Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 16 Apr 2020 21:52:29 +0000 (14:52 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 16 Apr 2020 21:52:29 +0000 (14:52 -0700)
Pull networking fixes from David Miller:

 1) Disable RISCV BPF JIT builds when !MMU, from Björn Töpel.

 2) nf_tables leaves dangling pointer after free, fix from Eric Dumazet.

 3) Out of boundary write in __xsk_rcv_memcpy(), fix from Li RongQing.

 4) Adjust icmp6 message source address selection when routes have a
    preferred source address set, from Tim Stallard.

 5) Be sure to validate HSR protocol version when creating new links,
    from Taehee Yoo.

 6) CAP_NET_ADMIN should be sufficient to manage l2tp tunnels even in
    non-initial namespaces, from Michael Weiß.

 7) Missing release firmware call in mlx5, from Eran Ben Elisha.

 8) Fix variable type in macsec_changelink(), caught by KASAN. Fix from
    Taehee Yoo.

 9) Fix pause frame negotiation in marvell phy driver, from Clemens
    Gruber.

10) Record RX queue early enough in tun packet paths such that XDP
    programs will see the correct RX queue index, from Gilberto Bertin.

11) Fix double unlock in mptcp, from Florian Westphal.

12) Fix offset overflow in ARM bpf JIT, from Luke Nelson.

13) marvell10g needs to soft reset PHY when coming out of low power
    mode, from Russell King.

14) Fix MTU setting regression in stmmac for some chip types, from
    Florian Fainelli.

* git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (101 commits)
  amd-xgbe: Use __napi_schedule() in BH context
  mISDN: make dmril and dmrim static
  net: stmmac: dwmac-sunxi: Provide TX and RX fifo sizes
  net: dsa: mt7530: fix tagged frames pass-through in VLAN-unaware mode
  tipc: fix incorrect increasing of link window
  Documentation: Fix tcp_challenge_ack_limit default value
  net: tulip: make early_486_chipsets static
  dt-bindings: net: ethernet-phy: add desciption for ethernet-phy-id1234.d400
  ipv6: remove redundant assignment to variable err
  net/rds: Use ERR_PTR for rds_message_alloc_sgs()
  net: mscc: ocelot: fix untagged packet drops when enslaving to vlan aware bridge
  selftests/bpf: Check for correct program attach/detach in xdp_attach test
  libbpf: Fix type of old_fd in bpf_xdp_set_link_opts
  libbpf: Always specify expected_attach_type on program load if supported
  xsk: Add missing check on user supplied headroom size
  mac80211: fix channel switch trigger from unknown mesh peer
  mac80211: fix race in ieee80211_register_hw()
  net: marvell10g: soft-reset the PHY when coming out of low power
  net: marvell10g: report firmware version
  net/cxgb4: Check the return from t4_query_params properly
  ...

972 files changed:
.mailmap
Documentation/ABI/testing/sysfs-platform-dell-laptop
Documentation/admin-guide/binderfs.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/sysctl/kernel.rst
Documentation/admin-guide/sysctl/user.rst
Documentation/admin-guide/sysrq.rst
Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt
Documentation/devicetree/bindings/display/panel/panel-dpi.yaml
Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
Documentation/devicetree/bindings/display/ti/ti,j721e-dss.yaml
Documentation/devicetree/bindings/display/ti/ti,k2g-dss.yaml
Documentation/devicetree/bindings/fpga/fpga-region.txt
Documentation/devicetree/bindings/input/iqs62x-keys.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt [deleted file]
Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/input/touchscreen/goodix.yaml
Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
Documentation/devicetree/bindings/mfd/iqs62x.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/rn5t618.txt
Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt [deleted file]
Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/rohm,bd71847-pmic.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml
Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.txt [deleted file]
Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/iqs620a-pwm.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.txt [deleted file]
Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/rohm,bd71847-regulator.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/cirrus,cs42l51.yaml
Documentation/devicetree/bindings/thermal/imx8mm-thermal.txt [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt
Documentation/devicetree/bindings/thermal/sprd-thermal.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/thermal.txt
Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml [new file with mode: 0644]
Documentation/driver-api/thermal/cpu-idle-cooling.rst
Documentation/driver-api/usb/writing_usb_driver.rst
Documentation/driver-api/w1.rst
Documentation/filesystems/9p.rst
Documentation/filesystems/ceph.rst
Documentation/filesystems/orangefs.rst
Documentation/filesystems/overlayfs.rst
Documentation/filesystems/qnx6.rst
Documentation/firmware-guide/acpi/namespace.rst
Documentation/kbuild/kbuild.rst
Documentation/kbuild/llvm.rst
Documentation/process/changes.rst
Documentation/x86/boot.rst
MAINTAINERS
Makefile
arch/alpha/include/asm/page.h
arch/alpha/include/asm/pgtable.h
arch/arc/include/asm/page.h
arch/arm/boot/compressed/head.S
arch/arm/include/asm/page.h
arch/arm/include/asm/pgtable-2level.h
arch/arm/include/asm/pgtable.h
arch/arm/mach-omap2/omap-secure.c
arch/arm/mach-omap2/omap-secure.h
arch/arm/mach-omap2/omap-smc.S
arch/arm/mach-pxa/cm-x300.c
arch/arm/mach-pxa/colibri-pxa270-income.c
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/ezx.c
arch/arm/mach-pxa/hx4700.c
arch/arm/mach-pxa/lpd270.c
arch/arm/mach-pxa/magician.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/mioa701.c
arch/arm/mach-pxa/palm27x.c
arch/arm/mach-pxa/palmtc.c
arch/arm/mach-pxa/palmte2.c
arch/arm/mach-pxa/pcm990-baseboard.c
arch/arm/mach-pxa/spitz.c
arch/arm/mach-pxa/tavorevb.c
arch/arm/mach-pxa/viper.c
arch/arm/mach-pxa/z2.c
arch/arm/mach-pxa/zylonite.c
arch/arm/mach-s3c24xx/mach-h1940.c
arch/arm/mach-s3c24xx/mach-rx1950.c
arch/arm/mach-s3c64xx/dev-backlight.c
arch/arm/mach-s3c64xx/mach-crag6410.c
arch/arm/mach-s3c64xx/mach-hmt.c
arch/arm/mach-s3c64xx/mach-smartq.c
arch/arm/mach-s3c64xx/mach-smdk6410.c
arch/arm/mm/fault.c
arch/arm/mm/mmu.c
arch/arm64/Kconfig
arch/arm64/Kconfig.debug
arch/arm64/Makefile
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/page.h
arch/arm64/kernel/armv8_deprecated.c
arch/arm64/kvm/Kconfig
arch/arm64/mm/fault.c
arch/arm64/mm/init.c
arch/arm64/mm/mmu.c
arch/c6x/include/asm/page.h
arch/csky/include/asm/page.h
arch/csky/include/asm/pgtable.h
arch/h8300/include/asm/page.h
arch/h8300/include/uapi/asm/bitsperlong.h [deleted file]
arch/h8300/include/uapi/asm/posix_types.h [new file with mode: 0644]
arch/hexagon/include/asm/page.h
arch/hexagon/include/asm/pgtable.h
arch/ia64/include/asm/page.h
arch/ia64/include/asm/pgtable.h
arch/ia64/mm/init.c
arch/m68k/68000/timers.c
arch/m68k/coldfire/pit.c
arch/m68k/coldfire/sltimers.c
arch/m68k/coldfire/timers.c
arch/m68k/include/asm/Kbuild
arch/m68k/include/asm/mcf_pgtable.h
arch/m68k/include/asm/motorola_pgtable.h
arch/m68k/include/asm/page.h
arch/m68k/include/asm/sun3_pgtable.h
arch/microblaze/include/asm/page.h
arch/microblaze/include/asm/pgtable.h
arch/mips/fw/arc/memory.c
arch/mips/include/asm/page.h
arch/mips/include/asm/pgtable.h
arch/mips/kvm/Kconfig
arch/nds32/include/asm/page.h
arch/nds32/include/asm/pgtable.h
arch/nds32/mm/fault.c
arch/nios2/Kconfig
arch/nios2/boot/dts/10m50_devboard.dts
arch/nios2/include/asm/page.h
arch/nios2/include/asm/pgtable.h
arch/nios2/platform/platform.c
arch/openrisc/include/asm/page.h
arch/openrisc/include/asm/pgtable.h
arch/parisc/include/asm/page.h
arch/parisc/include/asm/pgtable.h
arch/powerpc/Kconfig
arch/powerpc/configs/ps3_defconfig
arch/powerpc/include/asm/book3s/64/hash.h
arch/powerpc/include/asm/book3s/64/radix.h
arch/powerpc/include/asm/page.h
arch/powerpc/include/asm/page_64.h
arch/powerpc/include/asm/sparsemem.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/include/asm/unistd.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/ppc_save_regs.S
arch/powerpc/kernel/ptrace/Makefile
arch/powerpc/kernel/signal.c
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/syscall_64.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/vdso.c
arch/powerpc/kvm/Kconfig
arch/powerpc/mm/book3s64/hash_utils.c
arch/powerpc/mm/book3s64/pgtable.c
arch/powerpc/mm/book3s64/pkeys.c
arch/powerpc/mm/book3s64/radix_pgtable.c
arch/powerpc/mm/ioremap.c
arch/powerpc/mm/mem.c
arch/powerpc/perf/Makefile
arch/powerpc/perf/callchain.c
arch/powerpc/perf/callchain.h [new file with mode: 0644]
arch/powerpc/perf/callchain_32.c [new file with mode: 0644]
arch/powerpc/perf/callchain_64.c [new file with mode: 0644]
arch/powerpc/perf/imc-pmu.c
arch/powerpc/platforms/powernv/opal-imc.c
arch/powerpc/platforms/ps3/os-area.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/papr_scm.c
arch/powerpc/platforms/pseries/ras.c
arch/riscv/Kconfig
arch/riscv/Kconfig.socs
arch/riscv/Makefile
arch/riscv/boot/Makefile
arch/riscv/boot/dts/Makefile
arch/riscv/boot/dts/kendryte/Makefile [new file with mode: 0644]
arch/riscv/boot/dts/kendryte/k210.dts [new file with mode: 0644]
arch/riscv/boot/dts/kendryte/k210.dtsi [new file with mode: 0644]
arch/riscv/configs/defconfig
arch/riscv/configs/nommu_k210_defconfig [new file with mode: 0644]
arch/riscv/configs/rv32_defconfig
arch/riscv/include/asm/bug.h
arch/riscv/include/asm/cacheflush.h
arch/riscv/include/asm/cpu_ops.h [new file with mode: 0644]
arch/riscv/include/asm/current.h
arch/riscv/include/asm/fixmap.h
arch/riscv/include/asm/kasan.h
arch/riscv/include/asm/page.h
arch/riscv/include/asm/patch.h [new file with mode: 0644]
arch/riscv/include/asm/pgtable.h
arch/riscv/include/asm/ptdump.h [new file with mode: 0644]
arch/riscv/include/asm/sbi.h
arch/riscv/include/asm/set_memory.h [new file with mode: 0644]
arch/riscv/include/asm/smp.h
arch/riscv/include/asm/soc.h [new file with mode: 0644]
arch/riscv/kernel/Makefile
arch/riscv/kernel/cpu-hotplug.c [new file with mode: 0644]
arch/riscv/kernel/cpu_ops.c [new file with mode: 0644]
arch/riscv/kernel/cpu_ops_sbi.c [new file with mode: 0644]
arch/riscv/kernel/cpu_ops_spinwait.c [new file with mode: 0644]
arch/riscv/kernel/entry.S
arch/riscv/kernel/ftrace.c
arch/riscv/kernel/head.S
arch/riscv/kernel/patch.c [new file with mode: 0644]
arch/riscv/kernel/process.c
arch/riscv/kernel/sbi.c
arch/riscv/kernel/setup.c
arch/riscv/kernel/smpboot.c
arch/riscv/kernel/soc.c [new file with mode: 0644]
arch/riscv/kernel/stacktrace.c
arch/riscv/kernel/traps.c
arch/riscv/kernel/traps_misaligned.c [new file with mode: 0644]
arch/riscv/kernel/vmlinux.lds.S
arch/riscv/lib/uaccess.S
arch/riscv/mm/Makefile
arch/riscv/mm/hugetlbpage.c
arch/riscv/mm/init.c
arch/riscv/mm/pageattr.c [new file with mode: 0644]
arch/riscv/mm/ptdump.c [new file with mode: 0644]
arch/s390/include/asm/page.h
arch/s390/include/asm/qdio.h
arch/s390/kvm/Kconfig
arch/s390/kvm/vsie.c
arch/s390/mm/fault.c
arch/s390/mm/gmap.c
arch/s390/mm/init.c
arch/sh/include/asm/bitops-op32.h
arch/sh/include/asm/page.h
arch/sh/include/uapi/asm/setup.h [deleted file]
arch/sh/include/uapi/asm/types.h [deleted file]
arch/sh/mm/init.c
arch/sparc/include/asm/page_32.h
arch/sparc/include/asm/page_64.h
arch/sparc/include/asm/pgtable_32.h
arch/sparc/include/asm/pgtable_64.h
arch/um/include/asm/pgtable.h
arch/unicore32/include/asm/page.h
arch/unicore32/include/asm/pgtable.h
arch/unicore32/kernel/puv3-nb0916.c
arch/unicore32/mm/fault.c
arch/x86/Kconfig
arch/x86/Kconfig.assembler [new file with mode: 0644]
arch/x86/Makefile
arch/x86/crypto/Makefile
arch/x86/crypto/aesni-intel_avx-x86_64.S
arch/x86/crypto/aesni-intel_glue.c
arch/x86/crypto/blake2s-core.S
arch/x86/crypto/chacha_glue.c
arch/x86/crypto/poly1305-x86_64-cryptogams.pl
arch/x86/crypto/poly1305_glue.c
arch/x86/crypto/sha1_ssse3_asm.S
arch/x86/crypto/sha1_ssse3_glue.c
arch/x86/crypto/sha256-avx-asm.S
arch/x86/crypto/sha256-avx2-asm.S
arch/x86/crypto/sha256_ssse3_glue.c
arch/x86/crypto/sha512-avx-asm.S
arch/x86/crypto/sha512-avx2-asm.S
arch/x86/crypto/sha512_ssse3_glue.c
arch/x86/events/intel/uncore.c
arch/x86/events/intel/uncore.h
arch/x86/events/intel/uncore_snbep.c
arch/x86/hyperv/hv_init.c
arch/x86/include/asm/cpu.h
arch/x86/include/asm/dwarf2.h
arch/x86/include/asm/efi.h
arch/x86/include/asm/page_types.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/set_memory.h
arch/x86/include/asm/xor_avx.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/amd_gart_64.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kernel/setup.c
arch/x86/kvm/Kconfig
arch/x86/kvm/Makefile
arch/x86/kvm/lapic.c
arch/x86/kvm/lapic.h
arch/x86/kvm/svm/avic.c [new file with mode: 0644]
arch/x86/kvm/svm/nested.c [new file with mode: 0644]
arch/x86/kvm/svm/pmu.c [moved from arch/x86/kvm/pmu_amd.c with 100% similarity]
arch/x86/kvm/svm/sev.c [new file with mode: 0644]
arch/x86/kvm/svm/svm.c [moved from arch/x86/kvm/svm.c with 54% similarity]
arch/x86/kvm/svm/svm.h [new file with mode: 0644]
arch/x86/kvm/svm/vmenter.S [new file with mode: 0644]
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/vmenter.S
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/init.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/mm_internal.h
arch/x86/mm/numa.c
arch/x86/mm/pat/set_memory.c
arch/x86/mm/pkeys.c
arch/x86/platform/efi/efi_64.c
arch/x86/platform/uv/bios_uv.c
arch/x86/um/asm/vm-flags.h
arch/x86/xen/setup.c
arch/x86/xen/xen-head.S
arch/xtensa/Kconfig
arch/xtensa/boot/Makefile
arch/xtensa/include/asm/page.h
arch/xtensa/include/asm/pgtable.h
arch/xtensa/kernel/smp.c
arch/xtensa/kernel/time.c
block/blk-cgroup.c
block/blk-mq.c
block/partitions/core.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/arm64/iort.c
drivers/acpi/ec.c
drivers/acpi/nfit/core.c
drivers/acpi/nfit/nfit.h
drivers/acpi/numa/srat.c
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ahci_imx.c
drivers/ata/libata-pmp.c
drivers/block/loop.c
drivers/block/rbd.c
drivers/block/xen-blkfront.c
drivers/char/hw_random/omap3-rom-rng.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_ssif.c
drivers/char/ipmi/kcs_bmc_aspeed.c
drivers/cpuidle/cpuidle-haltpoll.c
drivers/crypto/hisilicon/Kconfig
drivers/crypto/marvell/octeontx/otx_cptvf_algs.c
drivers/dax/bus.c
drivers/dax/super.c
drivers/dma-buf/Kconfig
drivers/dma/tegra20-apb-dma.c
drivers/firmware/edd.c
drivers/firmware/efi/cper.c
drivers/firmware/efi/libstub/arm64-stub.c
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/libstub/file.c
drivers/firmware/efi/libstub/x86-stub.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_4.c
drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
drivers/gpu/drm/amd/amdkfd/kfd_device.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.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dc_hw_types.h
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
drivers/gpu/drm/amd/display/dc/dml/dc_features.h
drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
drivers/gpu/drm/amd/display/include/dal_asic_id.h
drivers/gpu/drm/amd/display/modules/freesync/freesync.c
drivers/gpu/drm/amd/display/modules/hdcp/hdcp.c
drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h
drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c
drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c
drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c
drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h
drivers/gpu/drm/amd/powerplay/amd_powerplay.c
drivers/gpu/drm/amd/powerplay/arcturus_ppt.c
drivers/gpu/drm/amd/powerplay/navi10_ppt.c
drivers/gpu/drm/amd/powerplay/renoir_ppt.c
drivers/gpu/drm/amd/powerplay/renoir_ppt.h
drivers/gpu/drm/amd/powerplay/smu_v11_0.c
drivers/gpu/drm/amd/powerplay/vega20_ppt.c
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/drm_prime.c
drivers/gpu/drm/exynos/exynos_dp.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/display/intel_ddi.c
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
drivers/gpu/drm/i915/gt/intel_ggtt.c
drivers/gpu/drm/i915/gvt/cmd_parser.c
drivers/gpu/drm/i915/gvt/display.c
drivers/gpu/drm/i915/gvt/handlers.c
drivers/gpu/drm/i915/gvt/scheduler.c
drivers/gpu/drm/i915/i915_memcpy.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
drivers/gpu/drm/nouveau/dispnv04/dac.c
drivers/gpu/drm/nouveau/dispnv04/hw.c
drivers/gpu/drm/nouveau/dispnv50/base507c.c
drivers/gpu/drm/nouveau/dispnv50/core507d.c
drivers/gpu/drm/nouveau/dispnv50/corec37d.c
drivers/gpu/drm/nouveau/dispnv50/curs507a.c
drivers/gpu/drm/nouveau/dispnv50/cursc37a.c
drivers/gpu/drm/nouveau/dispnv50/disp.c
drivers/gpu/drm/nouveau/dispnv50/ovly827e.c
drivers/gpu/drm/nouveau/dispnv50/wndw.h
drivers/gpu/drm/nouveau/include/nvif/device.h
drivers/gpu/drm/nouveau/include/nvif/timer.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/include/nvif/user.h
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_debugfs.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_svm.c
drivers/gpu/drm/nouveau/nvif/Kbuild
drivers/gpu/drm/nouveau/nvif/device.c
drivers/gpu/drm/nouveau/nvif/timer.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvif/userc361.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/vboxvideo/vbox_drv.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/virtio/virtgpu_object.c
drivers/gpu/drm/xen/xen_drm_front.c
drivers/hv/channel_mgmt.c
drivers/hv/hv_debugfs.c
drivers/hv/hyperv_vmbus.h
drivers/hv/vmbus_drv.c
drivers/hwmon/dell-smm-hwmon.c
drivers/iio/Kconfig
drivers/iio/Makefile
drivers/iio/accel/cros_ec_accel_legacy.c
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/rn5t618-adc.c [new file with mode: 0644]
drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c
drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
drivers/iio/industrialio-core.c
drivers/iio/light/Kconfig
drivers/iio/light/Makefile
drivers/iio/light/cros_ec_light_prox.c
drivers/iio/light/iqs621-als.c [new file with mode: 0644]
drivers/iio/position/Kconfig [new file with mode: 0644]
drivers/iio/position/Makefile [new file with mode: 0644]
drivers/iio/position/iqs624-pos.c [new file with mode: 0644]
drivers/iio/pressure/cros_ec_baro.c
drivers/iio/temperature/Kconfig
drivers/iio/temperature/Makefile
drivers/iio/temperature/iqs620at-temp.c [new file with mode: 0644]
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/iqs62x-keys.c [new file with mode: 0644]
drivers/input/serio/i8042-x86ia64io.h
drivers/input/touchscreen/elants_i2c.c
drivers/input/touchscreen/goodix.c
drivers/input/touchscreen/of_touchscreen.c
drivers/iommu/Kconfig
drivers/iommu/amd_iommu_types.h
drivers/iommu/arm-smmu-v3.c
drivers/iommu/arm-smmu.c
drivers/iommu/intel-iommu.c
drivers/iommu/intel-svm.c
drivers/iommu/iommu.c
drivers/iommu/ipmmu-vmsa.c
drivers/iommu/mtk_iommu.c
drivers/iommu/mtk_iommu_v1.c
drivers/iommu/omap-iommu.c
drivers/iommu/omap-iopgtable.h
drivers/iommu/qcom_iommu.c
drivers/iommu/tegra-gart.c
drivers/iommu/virtio-iommu.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/led-class.c
drivers/leds/leds-bd2802.c
drivers/leds/leds-ip30.c [new file with mode: 0644]
drivers/leds/leds-is31fl32xx.c
drivers/leds/leds-lm3532.c
drivers/leds/leds-lm3697.c
drivers/leds/leds-ns2.c
drivers/leds/leds-pwm.c
drivers/md/dm-linear.c
drivers/md/dm-log-writes.c
drivers/md/dm-stripe.c
drivers/md/dm.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/aat2870-core.c
drivers/mfd/cros_ec_dev.c
drivers/mfd/da9062-core.c
drivers/mfd/dln2.c
drivers/mfd/intel-lpss-pci.c
drivers/mfd/iqs62x.c [new file with mode: 0644]
drivers/mfd/omap-usb-host.c
drivers/mfd/omap-usb-tll.c
drivers/mfd/qcom-pm8xxx.c
drivers/mfd/rk808.c
drivers/mfd/rn5t618.c
drivers/mfd/sprd-sc27xx-spi.c
drivers/misc/mic/Kconfig
drivers/net/caif/Kconfig
drivers/nvdimm/bus.c
drivers/nvdimm/dimm.c
drivers/nvdimm/dimm_devs.c
drivers/nvdimm/e820.c
drivers/nvdimm/label.h
drivers/nvdimm/namespace_devs.c
drivers/nvdimm/nd.h
drivers/nvdimm/of_pmem.c
drivers/nvdimm/pfn.h
drivers/nvdimm/pfn_devs.c
drivers/nvdimm/pmem.c
drivers/nvdimm/region_devs.c
drivers/nvme/host/core.c
drivers/nvme/host/fc.c
drivers/nvme/host/multipath.c
drivers/nvme/host/rdma.c
drivers/nvme/host/tcp.c
drivers/nvme/target/configfs.c
drivers/nvme/target/fc.c
drivers/nvme/target/fcloop.c
drivers/nvme/target/rdma.c
drivers/pci/ats.c
drivers/platform/chrome/Kconfig
drivers/platform/chrome/Makefile
drivers/platform/chrome/chromeos_laptop.c
drivers/platform/chrome/cros_ec.c
drivers/platform/chrome/cros_ec_chardev.c
drivers/platform/chrome/cros_ec_lightbar.c
drivers/platform/chrome/cros_ec_proto.c
drivers/platform/chrome/cros_ec_rpmsg.c
drivers/platform/chrome/cros_ec_sensorhub.c
drivers/platform/chrome/cros_ec_sensorhub_ring.c [new file with mode: 0644]
drivers/platform/chrome/cros_ec_spi.c
drivers/platform/chrome/cros_ec_sysfs.c
drivers/platform/chrome/cros_ec_typec.c [new file with mode: 0644]
drivers/platform/chrome/cros_ec_vbc.c
drivers/platform/chrome/cros_usbpd_notify.c [new file with mode: 0644]
drivers/platform/chrome/wilco_ec/event.c
drivers/platform/chrome/wilco_ec/properties.c
drivers/platform/chrome/wilco_ec/sysfs.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/dell-rbtn.c
drivers/platform/x86/dell-rbtn.h
drivers/platform/x86/dell-smbios-base.c
drivers/platform/x86/dell-smbios-smm.c
drivers/platform/x86/dell-smbios.h
drivers/platform/x86/dell-smo8800.c
drivers/platform/x86/dell-wmi.c
drivers/power/supply/Kconfig
drivers/power/supply/bq2415x_charger.c
drivers/power/supply/bq27xxx_battery.c
drivers/power/supply/cros_usbpd-charger.c
drivers/power/supply/isp1704_charger.c
drivers/power/supply/rx51_battery.c
drivers/ps3/sys-manager-core.c
drivers/pwm/Kconfig
drivers/pwm/core.c
drivers/pwm/pwm-bcm2835.c
drivers/pwm/pwm-imx-tpm.c
drivers/pwm/pwm-imx27.c
drivers/pwm/pwm-jz4740.c
drivers/pwm/pwm-meson.c
drivers/pwm/pwm-mxs.c
drivers/pwm/pwm-omap-dmtimer.c
drivers/pwm/pwm-pca9685.c
drivers/pwm/pwm-rcar.c
drivers/pwm/pwm-renesas-tpu.c
drivers/pwm/pwm-sun4i.c
drivers/pwm/pwm-tegra.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-rc5t619.c [new file with mode: 0644]
drivers/s390/block/dcssblk.c
drivers/s390/cio/device.c
drivers/s390/cio/qdio.h
drivers/s390/cio/qdio_debug.c
drivers/s390/cio/qdio_debug.h
drivers/s390/cio/qdio_main.c
drivers/s390/cio/qdio_setup.c
drivers/s390/cio/qdio_thinint.c
drivers/s390/cio/vfio_ccw_drv.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_qdio.c
drivers/scsi/aacraid/commsup.c
drivers/scsi/aic7xxx/aic7xxx_core.c
drivers/scsi/bnx2fc/bnx2fc.h
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/bnx2fc/bnx2fc_hwi.c
drivers/scsi/bnx2fc/bnx2fc_io.c
drivers/scsi/constants.c
drivers/scsi/libfc/fc_rport.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/scsi/lpfc/lpfc_debugfs.h
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_nvme.c
drivers/scsi/lpfc/lpfc_nvmet.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/qla2xxx/qla_nvme.c
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/sr.c
drivers/scsi/ufs/ufs-mediatek.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h
drivers/soc/Kconfig
drivers/soc/Makefile
drivers/soc/kendryte/Kconfig [new file with mode: 0644]
drivers/soc/kendryte/Makefile [new file with mode: 0644]
drivers/soc/kendryte/k210-sysctl.c [new file with mode: 0644]
drivers/staging/gasket/gasket_core.c
drivers/target/target_core_xcopy.c
drivers/target/target_core_xcopy.h
drivers/thermal/Kconfig
drivers/thermal/Makefile
drivers/thermal/cpufreq_cooling.c
drivers/thermal/imx8mm_thermal.c [new file with mode: 0644]
drivers/thermal/imx_sc_thermal.c [new file with mode: 0644]
drivers/thermal/imx_thermal.c
drivers/thermal/intel/int340x_thermal/int3400_thermal.c
drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
drivers/thermal/of-thermal.c
drivers/thermal/qcom/tsens-8960.c
drivers/thermal/qcom/tsens-common.c
drivers/thermal/qcom/tsens-v0_1.c
drivers/thermal/qcom/tsens-v1.c
drivers/thermal/qcom/tsens-v2.c
drivers/thermal/qcom/tsens.c
drivers/thermal/qcom/tsens.h
drivers/thermal/qoriq_thermal.c
drivers/thermal/rcar_gen3_thermal.c
drivers/thermal/rcar_thermal.c
drivers/thermal/samsung/exynos_tmu.c
drivers/thermal/sprd_thermal.c [new file with mode: 0644]
drivers/thermal/st/stm_thermal.c
drivers/thermal/ti-soc-thermal/ti-bandgap.c
drivers/thermal/ti-soc-thermal/ti-bandgap.h
drivers/vdpa/Kconfig [new file with mode: 0644]
drivers/vdpa/Makefile [new file with mode: 0644]
drivers/vdpa/ifcvf/Makefile [new file with mode: 0644]
drivers/vdpa/ifcvf/ifcvf_base.c [new file with mode: 0644]
drivers/vdpa/ifcvf/ifcvf_base.h [new file with mode: 0644]
drivers/vdpa/ifcvf/ifcvf_main.c [new file with mode: 0644]
drivers/vdpa/vdpa.c [new file with mode: 0644]
drivers/vdpa/vdpa_sim/Makefile [new file with mode: 0644]
drivers/vdpa/vdpa_sim/vdpa_sim.c [new file with mode: 0644]
drivers/vhost/Kconfig
drivers/vhost/Kconfig.vringh [deleted file]
drivers/vhost/Makefile
drivers/vhost/iotlb.c [new file with mode: 0644]
drivers/vhost/net.c
drivers/vhost/scsi.c
drivers/vhost/vdpa.c [new file with mode: 0644]
drivers/vhost/vhost.c
drivers/vhost/vhost.h
drivers/vhost/vringh.c
drivers/vhost/vsock.c
drivers/video/backlight/corgi_lcd.c
drivers/video/backlight/pwm_bl.c
drivers/video/fbdev/core/fbcon.c
drivers/virtio/Kconfig
drivers/virtio/Makefile
drivers/virtio/virtio_vdpa.c [new file with mode: 0644]
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/imx2_wdt.c
drivers/watchdog/imx7ulp_wdt.c
drivers/watchdog/imx_sc_wdt.c
drivers/watchdog/npcm_wdt.c
drivers/watchdog/orion_wdt.c
drivers/watchdog/pm8916_wdt.c
drivers/watchdog/qcom-wdt.c
drivers/watchdog/rti_wdt.c [new file with mode: 0644]
drivers/watchdog/watchdog_core.c
drivers/watchdog/watchdog_dev.c
drivers/watchdog/wm831x_wdt.c
drivers/watchdog/ziirave_wdt.c
drivers/xen/events/events_2l.c
drivers/xen/events/events_base.c
drivers/xen/events/events_fifo.c
drivers/xen/events/events_internal.h
drivers/xen/evtchn.c
drivers/xen/gntdev-common.h
drivers/xen/gntdev.c
drivers/xen/pvcalls-back.c
drivers/xen/pvcalls-front.c
drivers/xen/xen-pciback/xenbus.c
drivers/xen/xen-scsiback.c
drivers/xen/xenbus/xenbus_client.c
fs/afs/dir.c
fs/afs/dir_silly.c
fs/afs/fsclient.c
fs/afs/yfsclient.c
fs/btrfs/block-group.c
fs/btrfs/file.c
fs/btrfs/reflink.c
fs/btrfs/relocation.c
fs/btrfs/space-info.c
fs/btrfs/tree-log.c
fs/ceph/addr.c
fs/ceph/cache.c
fs/ceph/caps.c
fs/ceph/debugfs.c
fs/ceph/dir.c
fs/ceph/export.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/ioctl.c
fs/ceph/locks.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/ceph/super.c
fs/ceph/super.h
fs/cifs/Kconfig
fs/cifs/cifs_debug.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/readdir.c
fs/cifs/smb2misc.c
fs/cifs/smb2proto.h
fs/cifs/smb2transport.c
fs/cifs/smbdirect.c
fs/cifs/smbdirect.h
fs/dax.c
fs/filesystems.c
fs/hfsplus/attributes.c
fs/io-wq.c
fs/io-wq.h
fs/io_uring.c
fs/iomap/buffered-io.c
fs/nfs/pnfs_nfs.c
fs/ocfs2/alloc.c
fs/orangefs/file.c
fs/orangefs/inode.c
fs/orangefs/orangefs-kernel.h
fs/overlayfs/copy_up.c
fs/overlayfs/dir.c
fs/overlayfs/export.c
fs/overlayfs/inode.c
fs/overlayfs/namei.c
fs/overlayfs/overlayfs.h
fs/overlayfs/ovl_entry.h
fs/overlayfs/readdir.c
fs/overlayfs/super.c
fs/overlayfs/util.c
fs/proc/base.c
fs/read_write.c
fs/seq_file.c
fs/udf/ecma_167.h
fs/udf/osta_udf.h
fs/xfs/libxfs/xfs_sb.c
fs/xfs/xfs_buf.c
fs/xfs/xfs_dquot.c
fs/xfs/xfs_dquot_item.c
fs/xfs/xfs_export.c
fs/xfs/xfs_file.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log.h
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_log_priv.h
fs/xfs/xfs_mount.h
fs/xfs/xfs_qm.c
fs/xfs/xfs_super.c
fs/xfs/xfs_symlink.c
fs/xfs/xfs_trace.h
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_priv.h
include/asm-generic/mshyperv.h
include/clocksource/timer-ti-dm.h
include/crypto/curve25519.h
include/drm/bridge/analogix_dp.h
include/drm/drm_legacy.h
include/dt-bindings/clock/k210-clk.h [new file with mode: 0644]
include/dt-bindings/leds/common.h
include/linux/acpi.h
include/linux/blk-cgroup.h
include/linux/ceph/ceph_fs.h
include/linux/ceph/debugfs.h
include/linux/ceph/libceph.h
include/linux/ceph/osd_client.h
include/linux/cma.h
include/linux/dax.h
include/linux/devfreq_cooling.h
include/linux/device-mapper.h
include/linux/device.h
include/linux/hugetlb.h
include/linux/iio/common/cros_ec_sensors_core.h
include/linux/iio/iio.h
include/linux/io.h
include/linux/iommu.h
include/linux/leds.h
include/linux/leds_pwm.h [deleted file]
include/linux/libnvdimm.h
include/linux/memblock.h
include/linux/memory_hotplug.h
include/linux/memremap.h
include/linux/mfd/iqs62x.h [new file with mode: 0644]
include/linux/mfd/rk808.h
include/linux/mfd/rn5t618.h
include/linux/mfd/sc27xx-pmic.h [new file with mode: 0644]
include/linux/mfd/wm831x/pdata.h
include/linux/mm.h
include/linux/mmzone.h
include/linux/numa.h
include/linux/nvme-fc-driver.h
include/linux/pid.h
include/linux/platform_data/cros_ec_proto.h
include/linux/platform_data/cros_ec_sensorhub.h
include/linux/platform_data/cros_usbpd_notify.h [new file with mode: 0644]
include/linux/platform_data/leds-kirkwood-ns2.h [deleted file]
include/linux/platform_data/pwm_omap_dmtimer.h [deleted file]
include/linux/platform_data/wilco-ec.h
include/linux/power/bq2415x_charger.h
include/linux/printk.h
include/linux/pwm.h
include/linux/pwm_backlight.h
include/linux/refcount.h
include/linux/slab.h
include/linux/spi/corgi_lcd.h
include/linux/thermal.h
include/linux/vdpa.h [new file with mode: 0644]
include/linux/vhost_iotlb.h [new file with mode: 0644]
include/linux/vringh.h
include/sound/soc-dai.h
include/uapi/linux/btrfs.h
include/uapi/linux/input-event-codes.h
include/uapi/linux/vhost.h
include/uapi/linux/vhost_types.h
include/uapi/linux/virtio_iommu.h
include/uapi/linux/virtio_net.h
include/xen/events.h
include/xen/interface/event_channel.h
include/xen/xenbus.h
init/Kconfig
init/Makefile
init/main.c
ipc/util.c
kernel/dma/debug.c
kernel/dma/direct.c
kernel/events/core.c
kernel/gcov/fs.c
kernel/kmod.c
kernel/locking/lockdep.c
kernel/locking/percpu-rwsem.c
kernel/module.c
kernel/pid.c
kernel/power/user.c
kernel/printk/internal.h
kernel/printk/printk.c
kernel/printk/printk_safe.c
kernel/sched/core.c
kernel/sched/debug.c
kernel/sched/fair.c
kernel/sched/sched.h
kernel/time/namespace.c
kernel/trace/trace_events_trigger.c
kernel/ucount.c
kernel/workqueue.c
lib/Kconfig
lib/raid6/algos.c
lib/raid6/avx2.c
lib/raid6/recov_avx2.c
lib/raid6/recov_ssse3.c
lib/raid6/test/Makefile
mm/Kconfig
mm/backing-dev.c
mm/cma.c
mm/gup.c
mm/hugetlb.c
mm/memblock.c
mm/memcontrol.c
mm/memory.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/memremap.c
mm/mmap.c
mm/mprotect.c
mm/page_alloc.c
mm/slab_common.c
net/ceph/debugfs.c
net/ceph/mon_client.c
net/ceph/osd_client.c
net/netfilter/Makefile
net/netfilter/nf_tables_api.c
net/netfilter/nft_set_pipapo.c
net/netfilter/nft_set_pipapo_avx2.h
scripts/Kconfig.include
scripts/Makefile
scripts/Makefile.build
scripts/Makefile.clean
scripts/Makefile.extrawarn
scripts/Makefile.host
scripts/dummy-tools/gcc [new file with mode: 0755]
scripts/dummy-tools/ld [new file with mode: 0755]
scripts/dummy-tools/nm [new symlink]
scripts/dummy-tools/objcopy [new symlink]
scripts/gcc-plugin.sh
scripts/gcc-plugins/Kconfig
scripts/gcc-plugins/Makefile
scripts/kconfig/qconf.cc
scripts/kconfig/qconf.h
scripts/mkcompile_h
security/keys/proc.c
security/selinux/ss/policydb.c
sound/core/oss/pcm_plugin.c
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c
sound/pci/ice1712/prodigy_hifi.c
sound/soc/amd/raven/acp3x-i2s.c
sound/soc/amd/raven/acp3x.h
sound/soc/bcm/bcm63xx-pcm-whistler.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5682.c
sound/soc/intel/atom/sst-atom-controls.c
sound/soc/intel/atom/sst/sst_pvt.c
sound/soc/intel/boards/bdw-rt5650.c
sound/soc/intel/boards/bdw-rt5677.c
sound/soc/intel/boards/broadwell.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/haswell.c
sound/soc/qcom/qdsp6/q6asm-dai.c
sound/soc/soc-dai.c
sound/soc/soc-dapm.c
sound/soc/soc-ops.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c
sound/soc/sof/loader.c
sound/soc/stm/stm32_sai_sub.c
sound/usb/mixer_maps.c
sound/usb/quirks-table.h
sound/usb/quirks.c
tools/laptop/freefall/freefall.c
tools/objtool/Makefile
tools/testing/nvdimm/Kbuild
tools/testing/nvdimm/test/Kbuild
tools/testing/nvdimm/test/nfit.c
tools/testing/selftests/kmod/kmod.sh
tools/testing/selftests/powerpc/eeh/eeh-basic.sh
tools/testing/selftests/powerpc/tm/Makefile
tools/thermal/tmon/tmon.c
tools/virtio/Makefile
usr/include/Makefile

index 9198a93..db3754a 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -210,6 +210,7 @@ Oleksij Rempel <linux@rempel-privat.de> <external.Oleksij.Rempel@de.bosch.com>
 Oleksij Rempel <linux@rempel-privat.de> <fixed-term.Oleksij.Rempel@de.bosch.com>
 Oleksij Rempel <linux@rempel-privat.de> <o.rempel@pengutronix.de>
 Oleksij Rempel <linux@rempel-privat.de> <ore@pengutronix.de>
+Pali Rohár <pali@kernel.org> <pali.rohar@gmail.com>
 Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
 Patrick Mochel <mochel@digitalimplant.org>
 Paul Burton <paulburton@kernel.org> <paul.burton@imgtec.com>
@@ -248,6 +249,7 @@ Sakari Ailus <sakari.ailus@linux.intel.com> <sakari.ailus@iki.fi>
 Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk>
 Sebastian Reichel <sre@kernel.org> <sre@debian.org>
 Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk>
+Sedat Dilek <sedat.dilek@gmail.com> <sedat.dilek@credativ.de>
 Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com>
 Shuah Khan <shuah@kernel.org> <shuahkhan@gmail.com>
 Shuah Khan <shuah@kernel.org> <shuah.khan@hp.com>
index 8c6a0b8..9b917c7 100644 (file)
@@ -2,7 +2,7 @@ What:           /sys/class/leds/dell::kbd_backlight/als_enabled
 Date:          December 2014
 KernelVersion: 3.19
 Contact:       Gabriele Mazzotta <gabriele.mzt@gmail.com>,
-               Pali Rohár <pali.rohar@gmail.com>
+               Pali Rohár <pali@kernel.org>
 Description:
                This file allows to control the automatic keyboard
                illumination mode on some systems that have an ambient
@@ -13,7 +13,7 @@ What:         /sys/class/leds/dell::kbd_backlight/als_setting
 Date:          December 2014
 KernelVersion: 3.19
 Contact:       Gabriele Mazzotta <gabriele.mzt@gmail.com>,
-               Pali Rohár <pali.rohar@gmail.com>
+               Pali Rohár <pali@kernel.org>
 Description:
                This file allows to specifiy the on/off threshold value,
                as reported by the ambient light sensor.
@@ -22,7 +22,7 @@ What:         /sys/class/leds/dell::kbd_backlight/start_triggers
 Date:          December 2014
 KernelVersion: 3.19
 Contact:       Gabriele Mazzotta <gabriele.mzt@gmail.com>,
-               Pali Rohár <pali.rohar@gmail.com>
+               Pali Rohár <pali@kernel.org>
 Description:
                This file allows to control the input triggers that
                turn on the keyboard backlight illumination that is
@@ -45,7 +45,7 @@ What:         /sys/class/leds/dell::kbd_backlight/stop_timeout
 Date:          December 2014
 KernelVersion: 3.19
 Contact:       Gabriele Mazzotta <gabriele.mzt@gmail.com>,
-               Pali Rohár <pali.rohar@gmail.com>
+               Pali Rohár <pali@kernel.org>
 Description:
                This file allows to specify the interval after which the
                keyboard illumination is disabled because of inactivity.
index c009671..8243af9 100644 (file)
@@ -33,6 +33,12 @@ max
   a per-instance limit. If ``max=<count>`` is set then only ``<count>`` number
   of binder devices can be allocated in this binderfs instance.
 
+stats
+  Using ``stats=global`` enables global binder statistics.
+  ``stats=global`` is only available for a binderfs instance mounted in the
+  initial user namespace. An attempt to use the option to mount a binderfs
+  instance in another user namespace will return a permission error.
+
 Allocating binder Devices
 -------------------------
 
index 86aae1f..f2a93c8 100644 (file)
        coredump_filter=
                        [KNL] Change the default value for
                        /proc/<pid>/coredump_filter.
-                       See also Documentation/filesystems/proc.txt.
+                       See also Documentation/filesystems/proc.rst.
 
        coresight_cpu_debug.enable
                        [ARM,ARM64]
                        edid/1680x1050.bin, or edid/1920x1080.bin is given
                        and no file with the same name exists. Details and
                        instructions how to build your own EDID data are
-                       available in Documentation/driver-api/edid.rst. An EDID
+                       available in Documentation/admin-guide/edid.rst. An EDID
                        data set will only be used for a particular connector,
                        if its name and a colon are prepended to the EDID
                        name. Each connector may use a unique EDID data
                        Documentation/admin-guide/dynamic-debug-howto.rst
                        for details.
 
-       nompx           [X86] Disables Intel Memory Protection Extensions.
-                       See Documentation/x86/intel_mpx.rst for more
-                       information about the feature.
-
        nopku           [X86] Disable Memory Protection Keys CPU feature found
                        in some Intel CPUs.
 
        hpet_mmap=      [X86, HPET_MMAP] Allow userspace to mmap HPET
                        registers.  Default set by CONFIG_HPET_MMAP_DEFAULT.
 
+       hugetlb_cma=    [HW] The size of a cma area used for allocation
+                       of gigantic hugepages.
+                       Format: nn[KMGTPE]
+
+                       Reserve a cma area of given size and allocate gigantic
+                       hugepages using the cma allocator. If enabled, the
+                       boot-time allocation of gigantic hugepages is skipped.
+
        hugepages=      [HW,X86-32,IA-64] HugeTLB pages to allocate at boot.
        hugepagesz=     [HW,IA-64,PPC,X86-64] The size of the HugeTLB pages.
                        On x86-64 and powerpc, this option can be specified
index 335696d..39c95c0 100644 (file)
@@ -446,6 +446,27 @@ Notes:
      successful IPC object allocation. If an IPC object allocation syscall
      fails, it is undefined if the value remains unmodified or is reset to -1.
 
+modprobe:
+=========
+
+The path to the usermode helper for autoloading kernel modules, by
+default "/sbin/modprobe".  This binary is executed when the kernel
+requests a module.  For example, if userspace passes an unknown
+filesystem type to mount(), then the kernel will automatically request
+the corresponding filesystem module by executing this usermode helper.
+This usermode helper should insert the needed module into the kernel.
+
+This sysctl only affects module autoloading.  It has no effect on the
+ability to explicitly insert modules.
+
+If this sysctl is set to the empty string, then module autoloading is
+completely disabled.  The kernel will not try to execute a usermode
+helper at all, nor will it call the kernel_module_request LSM hook.
+
+If CONFIG_STATIC_USERMODEHELPER=y is set in the kernel configuration,
+then the configured static usermode helper overrides this sysctl,
+except that the empty string is still accepted to completely disable
+module autoloading as described above.
 
 nmi_watchdog
 ============
index 650eaa0..c458245 100644 (file)
@@ -65,6 +65,12 @@ max_pid_namespaces
   The maximum number of pid namespaces that any user in the current
   user namespace may create.
 
+max_time_namespaces
+===================
+
+  The maximum number of time namespaces that any user in the current
+  user namespace may create.
+
 max_user_namespaces
 ===================
 
index 72b2cfb..a46209f 100644 (file)
@@ -48,9 +48,10 @@ always allowed (by a user with admin privileges).
 How do I use the magic SysRq key?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-On x86   - You press the key combo :kbd:`ALT-SysRq-<command key>`.
+On x86
+       You press the key combo :kbd:`ALT-SysRq-<command key>`.
 
-.. note::
+       .. note::
           Some
            keyboards may not have a key labeled 'SysRq'. The 'SysRq' key is
            also known as the 'Print Screen' key. Also some keyboards cannot
@@ -58,14 +59,15 @@ On x86   - You press the key combo :kbd:`ALT-SysRq-<command key>`.
           have better luck with press :kbd:`Alt`, press :kbd:`SysRq`,
           release :kbd:`SysRq`, press :kbd:`<command key>`, release everything.
 
-On SPARC - You press :kbd:`ALT-STOP-<command key>`, I believe.
+On SPARC
+       You press :kbd:`ALT-STOP-<command key>`, I believe.
 
 On the serial console (PC style standard serial ports only)
         You send a ``BREAK``, then within 5 seconds a command key. Sending
         ``BREAK`` twice is interpreted as a normal BREAK.
 
 On PowerPC
-       Press :kbd:`ALT - Print Screen` (or :kbd:`F13`) - :kbd:`<command key>`,
+       Press :kbd:`ALT - Print Screen` (or :kbd:`F13`) - :kbd:`<command key>`.
         :kbd:`Print Screen` (or :kbd:`F13`) - :kbd:`<command key>` may suffice.
 
 On other
@@ -73,7 +75,7 @@ On other
         let me know so I can add them to this section.
 
 On all
-       write a character to /proc/sysrq-trigger.  e.g.::
+       Write a character to /proc/sysrq-trigger.  e.g.::
 
                echo t > /proc/sysrq-trigger
 
@@ -282,7 +284,7 @@ Just ask them on the linux-kernel mailing list:
 Credits
 ~~~~~~~
 
-Written by Mydraal <vulpyne@vulpyne.net>
-Updated by Adam Sulmicki <adam@cfar.umd.edu>
-Updated by Jeremy M. Dolan <jmd@turbogeek.org> 2001/01/28 10:15:59
-Added to by Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+Written by Mydraal <vulpyne@vulpyne.net>
+Updated by Adam Sulmicki <adam@cfar.umd.edu>
+Updated by Jeremy M. Dolan <jmd@turbogeek.org> 2001/01/28 10:15:59
+Added to by Crutcher Dunnavant <crutcher+kernel@datastacks.com>
index 8cac6fa..623fedf 100644 (file)
@@ -166,6 +166,17 @@ Required properties:
               followed by "fsl,imx-sc-key";
 - linux,keycodes: See Documentation/devicetree/bindings/input/input.yaml
 
+Thermal bindings based on SCU Message Protocol
+------------------------------------------------------------
+
+Required properties:
+- compatible:                  Should be :
+                                 "fsl,imx8qxp-sc-thermal"
+                               followed by "fsl,imx-sc-thermal";
+
+- #thermal-sensor-cells:       See Documentation/devicetree/bindings/thermal/thermal.txt
+                               for a description.
+
 Example (imx8qxp):
 -------------
 aliases {
@@ -238,6 +249,11 @@ firmware {
                        compatible = "fsl,imx8qxp-sc-wdt", "fsl,imx-sc-wdt";
                        timeout-sec = <60>;
                };
+
+               tsens: thermal-sensor {
+                       compatible = "fsl,imx8qxp-sc-thermal", "fsl,imx-sc-thermal";
+                       #thermal-sensor-cells = <1>;
+               };
        };
 };
 
index f638703..0cd74c8 100644 (file)
@@ -21,15 +21,6 @@ properties:
       - {}
       - const: panel-dpi
 
-  data-mapping:
-    enum:
-      - rgb24
-      - rgb565
-      - bgr666
-    description: |
-      Describes the media format, how the display panel is connected
-      to the display interface.
-
   backlight: true
   enable-gpios: true
   height-mm: true
@@ -52,7 +43,6 @@ examples:
         compatible = "osddisplays,osd057T0559-34ts", "panel-dpi";
         label = "osddisplay";
         power-supply = <&vcc_supply>;
-        data-mapping = "rgb565";
         backlight = <&backlight>;
 
         port {
index cac61a9..eb04c23 100644 (file)
@@ -65,7 +65,7 @@ properties:
   ports:
     type: object
     description:
-      Ports as described in Documentation/devictree/bindings/graph.txt
+      Ports as described in Documentation/devicetree/bindings/graph.txt
     properties:
       "#address-cells":
         const: 1
@@ -121,7 +121,7 @@ examples:
     #include <dt-bindings/interrupt-controller/irq.h>
     #include <dt-bindings/soc/ti,sci_pm_domain.h>
 
-    dss: dss@04a00000 {
+    dss: dss@4a00000 {
             compatible = "ti,am65x-dss";
             reg =   <0x0 0x04a00000 0x0 0x1000>, /* common */
                     <0x0 0x04a02000 0x0 0x1000>, /* vidl1 */
index ade9b2f..eb4b1a2 100644 (file)
@@ -98,7 +98,7 @@ properties:
   ports:
     type: object
     description:
-      Ports as described in Documentation/devictree/bindings/graph.txt
+      Ports as described in Documentation/devicetree/bindings/graph.txt
     properties:
       "#address-cells":
         const: 1
@@ -154,7 +154,7 @@ examples:
     #include <dt-bindings/interrupt-controller/irq.h>
     #include <dt-bindings/soc/ti,sci_pm_domain.h>
 
-    dss: dss@04a00000 {
+    dss: dss@4a00000 {
             compatible = "ti,j721e-dss";
             reg =   <0x00 0x04a00000 0x00 0x10000>, /* common_m */
                     <0x00 0x04a10000 0x00 0x10000>, /* common_s0*/
index 385bd06..8f87b82 100644 (file)
@@ -56,7 +56,7 @@ properties:
   port:
     type: object
     description:
-      Port as described in Documentation/devictree/bindings/graph.txt.
+      Port as described in Documentation/devicetree/bindings/graph.txt.
       The DSS DPI output port node
 
   max-memory-bandwidth:
@@ -81,7 +81,7 @@ examples:
     #include <dt-bindings/interrupt-controller/arm-gic.h>
     #include <dt-bindings/interrupt-controller/irq.h>
 
-    dss: dss@02540000 {
+    dss: dss@2540000 {
             compatible = "ti,k2g-dss";
             reg =   <0x02540000 0x400>,
                     <0x02550000 0x1000>,
index 90c4469..8ab19d1 100644 (file)
@@ -263,7 +263,7 @@ Overlay contains:
                        gpio@10040 {
                                compatible = "altr,pio-1.0";
                                reg = <0x10040 0x20>;
-                               altr,gpio-bank-width = <4>;
+                               altr,ngpio = <4>;
                                #gpio-cells = <2>;
                                clocks = <2>;
                                gpio-controller;
@@ -468,8 +468,7 @@ programming is the FPGA based bridge of fpga_region1.
                                compatible = "altr,pio-1.0";
                                reg = <0x10040 0x20>;
                                clocks = <0x2>;
-                               altr,gpio-bank-width = <0x4>;
-                               resetvalue = <0x0>;
+                               altr,ngpio = <0x4>;
                                #gpio-cells = <0x2>;
                                gpio-controller;
                        };
diff --git a/Documentation/devicetree/bindings/input/iqs62x-keys.yaml b/Documentation/devicetree/bindings/input/iqs62x-keys.yaml
new file mode 100644 (file)
index 0000000..5625c22
--- /dev/null
@@ -0,0 +1,132 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/iqs62x-keys.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Azoteq IQS620A/621/622/624/625 Keys and Switches
+
+maintainers:
+  - Jeff LaBundy <jeff@labundy.com>
+
+description: |
+  The Azoteq IQS620A, IQS621, IQS622, IQS624 and IQS625 multi-function sensors
+  feature a variety of self-capacitive, mutual-inductive and Hall-effect sens-
+  ing capabilities that can facilitate a variety of contactless key and switch
+  applications.
+
+  These functions are collectively represented by a "keys" child node from the
+  parent MFD driver. See Documentation/devicetree/bindings/mfd/iqs62x.yaml for
+  further details and examples. Sensor hardware configuration (self-capacitive
+  vs. mutual-inductive, etc.) is selected based on the device's firmware.
+
+properties:
+  compatible:
+    enum:
+      - azoteq,iqs620a-keys
+      - azoteq,iqs621-keys
+      - azoteq,iqs622-keys
+      - azoteq,iqs624-keys
+      - azoteq,iqs625-keys
+
+  linux,keycodes:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32-array
+      - minItems: 1
+        maxItems: 16
+    description: |
+      Specifies the numeric keycodes associated with each available touch or
+      proximity event according to the following table. An 'x' indicates the
+      event is supported for a given device. Specify 0 for unused events.
+
+      -------------------------------------------------------------------------
+      | #  | Event              | IQS620A | IQS621 | IQS622 | IQS624 | IQS625 |
+      -------------------------------------------------------------------------
+      | 0  | CH0 Touch          |    x    |    x   |    x   |    x   |    x   |
+      |    | Antenna 1 Touch*   |    x    |        |        |        |        |
+      -------------------------------------------------------------------------
+      | 1  | CH0 Proximity      |    x    |    x   |    x   |    x   |    x   |
+      |    | Antenna 1 Prox.*   |    x    |        |        |        |        |
+      -------------------------------------------------------------------------
+      | 2  | CH1 Touch          |    x    |    x   |    x   |    x   |    x   |
+      |    | Ant. 1 Deep Touch* |    x    |        |        |        |        |
+      -------------------------------------------------------------------------
+      | 3  | CH1 Proximity      |    x    |    x   |    x   |    x   |    x   |
+      -------------------------------------------------------------------------
+      | 4  | CH2 Touch          |    x    |        |        |        |        |
+      -------------------------------------------------------------------------
+      | 5  | CH2 Proximity      |    x    |        |        |        |        |
+      |    | Antenna 2 Prox.*   |    x    |        |        |        |        |
+      -------------------------------------------------------------------------
+      | 6  | Metal (+) Touch**  |    x    |    x   |        |        |        |
+      |    | Ant. 2 Deep Touch* |    x    |        |        |        |        |
+      -------------------------------------------------------------------------
+      | 7  | Metal (+) Prox.**  |    x    |    x   |        |        |        |
+      |    | Antenna 2 Touch*   |    x    |        |        |        |        |
+      -------------------------------------------------------------------------
+      | 8  | Metal (-) Touch**  |    x    |    x   |        |        |        |
+      -------------------------------------------------------------------------
+      | 9  | Metal (-) Prox.**  |    x    |    x   |        |        |        |
+      -------------------------------------------------------------------------
+      | 10 | SAR Active***      |    x    |        |    x   |        |        |
+      -------------------------------------------------------------------------
+      | 11 | SAR Quick Rel.***  |    x    |        |    x   |        |        |
+      -------------------------------------------------------------------------
+      | 12 | SAR Movement***    |    x    |        |    x   |        |        |
+      -------------------------------------------------------------------------
+      | 13 | SAR Filter Halt*** |    x    |        |    x   |        |        |
+      -------------------------------------------------------------------------
+      | 14 | Wheel Up           |         |        |        |    x   |        |
+      -------------------------------------------------------------------------
+      | 15 | Wheel Down         |         |        |        |    x   |        |
+      -------------------------------------------------------------------------
+      *   Two-channel SAR. Replaces CH0-2 plus metal touch and proximity events
+          if enabled via firmware.
+      **  "+" and "-" refer to the polarity of a channel's delta (LTA - counts),
+          where "LTA" is defined as the channel's long-term average.
+      *** One-channel SAR. Replaces CH0-2 touch and proximity events if enabled
+          via firmware.
+
+patternProperties:
+  "^hall-switch-(north|south)$":
+    type: object
+    description:
+      Represents north/south-field Hall-effect sensor touch or proximity
+      events. Note that north/south-field orientation is reversed on the
+      IQS620AXzCSR device due to its flip-chip package.
+
+    properties:
+      linux,code:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: Numeric switch code associated with the event.
+
+      azoteq,use-prox:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          If present, specifies that Hall-effect sensor reporting should
+          use the device's wide-range proximity threshold instead of its
+          close-range touch threshold (default).
+
+    required:
+      - linux,code
+
+    additionalProperties: false
+
+if:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - azoteq,iqs624-keys
+          - azoteq,iqs625-keys
+then:
+  patternProperties:
+    "^hall-switch-(north|south)$": false
+
+required:
+  - compatible
+  - linux,keycodes
+
+additionalProperties: false
+
+...
diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
deleted file mode 100644 (file)
index 0e57315..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-FocalTech EDT-FT5x06 Polytouch driver
-=====================================
-
-There are 5 variants of the chip for various touch panel sizes
-FT5206GE1  2.8" .. 3.8"
-FT5306DE4  4.3" .. 7"
-FT5406EE8  7"   .. 8.9"
-FT5506EEG  7"   .. 8.9"
-FT5726NEI  5.7” .. 11.6"
-
-The software interface is identical for all those chips, so that
-currently there is no need for the driver to distinguish between the
-different chips. Nevertheless distinct compatible strings are used so
-that a distinction can be added if necessary without changing the DT
-bindings.
-
-
-Required properties:
- - compatible:  "edt,edt-ft5206"
-           or:  "edt,edt-ft5306"
-           or:  "edt,edt-ft5406"
-           or:  "edt,edt-ft5506"
-           or:  "evervision,ev-ft5726"
-           or:  "focaltech,ft6236"
-
- - reg:         I2C slave address of the chip (0x38)
- - interrupts:       interrupt specification for the touchdetect
-                     interrupt
-
-Optional properties:
- - reset-gpios: GPIO specification for the RESET input
- - wake-gpios:  GPIO specification for the WAKE input
- - vcc-supply:  Regulator that supplies the touchscreen
-
- - pinctrl-names: should be "default"
- - pinctrl-0:   a phandle pointing to the pin settings for the
-                control gpios
-
- - wakeup-source: If present the device will act as wakeup-source
-
- - threshold:   allows setting the "click"-threshold in the range
-                from 0 to 80.
-
- - gain:        allows setting the sensitivity in the range from 0 to
-                31. Note that lower values indicate higher
-                sensitivity.
-
- - offset:      allows setting the edge compensation in the range from
-                0 to 31.
-
- - offset-x:    Same as offset, but applies only to the horizontal position.
-                Range from 0 to 80, only supported by evervision,ev-ft5726
-                devices.
-
- - offset-y:    Same as offset, but applies only to the vertical position.
-                Range from 0 to 80, only supported by evervision,ev-ft5726
-                devices.
-
- - touchscreen-size-x     : See touchscreen.txt
- - touchscreen-size-y     : See touchscreen.txt
- - touchscreen-fuzz-x      : See touchscreen.txt
- - touchscreen-fuzz-y      : See touchscreen.txt
- - touchscreen-inverted-x  : See touchscreen.txt
- - touchscreen-inverted-y  : See touchscreen.txt
- - touchscreen-swapped-x-y : See touchscreen.txt
-
-Example:
-       polytouch: edt-ft5x06@38 {
-               compatible = "edt,edt-ft5406", "edt,edt-ft5x06";
-               reg = <0x38>;
-               pinctrl-names = "default";
-               pinctrl-0 = <&edt_ft5x06_pins>;
-               interrupt-parent = <&gpio2>;
-               interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
-               reset-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
-               wake-gpios = <&gpio4 9 GPIO_ACTIVE_HIGH>;
-       };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml
new file mode 100644 (file)
index 0000000..8d58709
--- /dev/null
@@ -0,0 +1,125 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/touchscreen/edt-ft5x06.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: FocalTech EDT-FT5x06 Polytouch Bindings
+
+description: |
+             There are 5 variants of the chip for various touch panel sizes
+              FT5206GE1  2.8" .. 3.8"
+              FT5306DE4  4.3" .. 7"
+              FT5406EE8  7"   .. 8.9"
+              FT5506EEG  7"   .. 8.9"
+              FT5726NEI  5.7” .. 11.6"
+
+maintainers:
+  - Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+allOf:
+  - $ref: touchscreen.yaml#
+  - if:
+     properties:
+       compatible:
+         contains:
+           enum:
+             - evervision,ev-ft5726
+
+    then:
+      properties:
+        offset-x: true
+        offset-y: true
+
+properties:
+  compatible:
+    enum:
+      - edt,edt-ft5206
+      - edt,edt-ft5306
+      - edt,edt-ft5406
+      - edt,edt-ft5506
+      - evervision,ev-ft5726
+      - focaltech,ft6236
+
+  reg:
+    const: 0x38
+
+  interrupts:
+    maxItems: 1
+
+  reset-gpios:
+    maxItems: 1
+
+  wake-gpios:
+    maxItems: 1
+
+  wakeup-source: true
+
+  vcc-supply:
+    maxItems: 1
+
+  gain:
+    description: Allows setting the sensitivity in the range from 0 to 31.
+                 Note that lower values indicate higher sensitivity.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - minimum: 0
+      - maximum: 31
+
+  offset:
+    description: Allows setting the edge compensation in the range from 0 to 31.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - minimum: 0
+      - maximum: 31
+
+  offset-x:
+    description: Same as offset, but applies only to the horizontal position.
+                 Range from 0 to 80, only supported by evervision,ev-ft5726 devices.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - minimum: 0
+      - maximum: 80
+
+  offset-y:
+    description: Same as offset, but applies only to the vertical position.
+                 Range from 0 to 80, only supported by evervision,ev-ft5726 devices.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - minimum: 0
+      - maximum: 80
+
+  touchscreen-size-x: true
+  touchscreen-size-y: true
+  touchscreen-fuzz-x: true
+  touchscreen-fuzz-y: true
+  touchscreen-inverted-x: true
+  touchscreen-inverted-y: true
+  touchscreen-swapped-x-y: true
+  interrupt-controller: true
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    i2c@00000000 {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      edt-ft5x06@38 {
+        compatible = "edt,edt-ft5406";
+        reg = <0x38>;
+        interrupt-parent = <&gpio2>;
+        interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
+        reset-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
+        wake-gpios = <&gpio4 9 GPIO_ACTIVE_HIGH>;
+      };
+    };
+
+...
index c99ed39..c8ea943 100644 (file)
@@ -21,6 +21,8 @@ properties:
       - goodix,gt911
       - goodix,gt9110
       - goodix,gt912
+      - goodix,gt9147
+      - goodix,gt917s
       - goodix,gt927
       - goodix,gt9271
       - goodix,gt928
index d98a9bf..193e71c 100644 (file)
@@ -1,9 +1,10 @@
-* Aspeed KCS (Keyboard Controller Style) IPMI interface
+# Aspeed KCS (Keyboard Controller Style) IPMI interface
 
 The Aspeed SOCs (AST2400 and AST2500) are commonly used as BMCs
 (Baseboard Management Controllers) and the KCS interface can be
 used to perform in-band IPMI communication with their host.
 
+## v1
 Required properties:
 - compatible : should be one of
     "aspeed,ast2400-kcs-bmc"
@@ -12,14 +13,21 @@ Required properties:
 - kcs_chan : The LPC channel number in the controller
 - kcs_addr : The host CPU IO map address
 
+## v2
+Required properties:
+- compatible : should be one of
+    "aspeed,ast2400-kcs-bmc-v2"
+    "aspeed,ast2500-kcs-bmc-v2"
+- reg : The address and size of the IDR, ODR and STR registers
+- interrupts : interrupt generated by the controller
+- aspeed,lpc-io-reg : The host CPU LPC IO address for the device
 
 Example:
 
-    kcs3: kcs3@0 {
-        compatible = "aspeed,ast2500-kcs-bmc";
-        reg = <0x0 0x80>;
+    kcs3: kcs@24 {
+        compatible = "aspeed,ast2500-kcs-bmc-v2";
+        reg = <0x24 0x1>, <0x30 0x1>, <0x3c 0x1>;
+        aspeed,lpc-reg = <0xca2>;
         interrupts = <8>;
-        kcs_chan = <3>;
-        kcs_addr = <0xCA2>;
         status = "okay";
     };
diff --git a/Documentation/devicetree/bindings/mfd/iqs62x.yaml b/Documentation/devicetree/bindings/mfd/iqs62x.yaml
new file mode 100644 (file)
index 0000000..541b06d
--- /dev/null
@@ -0,0 +1,179 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/iqs62x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Azoteq IQS620A/621/622/624/625 Multi-Function Sensors
+
+maintainers:
+  - Jeff LaBundy <jeff@labundy.com>
+
+description: |
+  The Azoteq IQS620A, IQS621, IQS622, IQS624 and IQS625 multi-function sensors
+  integrate multiple sensing technologies in a single package.
+
+  Link to datasheets: https://www.azoteq.com/
+
+properties:
+  compatible:
+    enum:
+      - azoteq,iqs620a
+      - azoteq,iqs621
+      - azoteq,iqs622
+      - azoteq,iqs624
+      - azoteq,iqs625
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  firmware-name:
+    $ref: /schemas/types.yaml#/definitions/string
+    description:
+      Specifies the name of the calibration and configuration file selected by
+      the driver. If this property is omitted, the name is chosen based on the
+      device name with ".bin" as the extension (e.g. iqs620a.bin for IQS620A).
+
+  keys:
+    $ref: ../input/iqs62x-keys.yaml
+
+  pwm:
+    $ref: ../pwm/iqs620a-pwm.yaml
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    /*
+     * Dual capacitive buttons with proximity-activated function, unipolar lid
+     * switch and panel-mounted LED.
+     */
+    #include <dt-bindings/input/input.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            iqs620a@44 {
+                    compatible = "azoteq,iqs620a";
+                    reg = <0x44>;
+                    interrupt-parent = <&gpio>;
+                    interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
+
+                    keys {
+                            compatible = "azoteq,iqs620a-keys";
+
+                            linux,keycodes = <KEY_SELECT>,
+                                             <KEY_MENU>,
+                                             <KEY_OK>,
+                                             <KEY_MENU>;
+
+                            hall-switch-south {
+                                    linux,code = <SW_LID>;
+                                    azoteq,use-prox;
+                            };
+                    };
+
+                    iqs620a_pwm: pwm {
+                            compatible = "azoteq,iqs620a-pwm";
+                            #pwm-cells = <2>;
+                    };
+            };
+    };
+
+    pwmleds {
+            compatible = "pwm-leds";
+
+            panel {
+                    pwms = <&iqs620a_pwm 0 1000000>;
+                    max-brightness = <255>;
+            };
+    };
+
+  - |
+    /* Single inductive button with bipolar dock/tablet-mode switch. */
+    #include <dt-bindings/input/input.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            iqs620a@44 {
+                    compatible = "azoteq,iqs620a";
+                    reg = <0x44>;
+                    interrupt-parent = <&gpio>;
+                    interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
+
+                    firmware-name = "iqs620a_coil.bin";
+
+                    keys {
+                            compatible = "azoteq,iqs620a-keys";
+
+                            linux,keycodes = <0>,
+                                             <0>,
+                                             <0>,
+                                             <0>,
+                                             <0>,
+                                             <0>,
+                                             <KEY_MUTE>;
+
+                            hall-switch-north {
+                                    linux,code = <SW_DOCK>;
+                            };
+
+                            hall-switch-south {
+                                    linux,code = <SW_TABLET_MODE>;
+                            };
+                    };
+            };
+    };
+
+  - |
+    /* Dual capacitive buttons with volume knob. */
+    #include <dt-bindings/input/input.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            iqs624@44 {
+                    compatible = "azoteq,iqs624";
+                    reg = <0x44>;
+                    interrupt-parent = <&gpio>;
+                    interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
+
+                    keys {
+                            compatible = "azoteq,iqs624-keys";
+
+                            linux,keycodes = <BTN_0>,
+                                             <0>,
+                                             <BTN_1>,
+                                             <0>,
+                                             <0>,
+                                             <0>,
+                                             <0>,
+                                             <0>,
+                                             <0>,
+                                             <0>,
+                                             <0>,
+                                             <0>,
+                                             <0>,
+                                             <0>,
+                                             <KEY_VOLUMEUP>,
+                                             <KEY_VOLUMEDOWN>;
+                    };
+            };
+    };
+
+...
index b74e5e9..16778ea 100644 (file)
@@ -15,6 +15,8 @@ Required properties:
  - reg: the I2C slave address of the device
 
 Optional properties:
+ - interrupts: interrupt mapping for IRQ
+   See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
  - system-power-controller:
    See Documentation/devicetree/bindings/power/power-controller.txt
 
@@ -32,6 +34,8 @@ Example:
        pmic@32 {
                compatible = "ricoh,rn5t618";
                reg = <0x32>;
+               interrupt-parent = <&gpio5>;
+               interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
                system-power-controller;
 
                regulators {
diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt b/Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt
deleted file mode 100644 (file)
index f22d74c..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-* ROHM BD71837 and BD71847 Power Management Integrated Circuit bindings
-
-BD71837MWV and BD71847MWV are programmable Power Management ICs for powering
-single-core, dual-core, and quad-core SoCs such as NXP-i.MX 8M. They are
-optimized for low BOM cost and compact solution footprint. BD71837MWV
-integrates 8 Buck regulators and 7 LDOs. BD71847MWV contains 6 Buck regulators
-and 6 LDOs.
-
-Datasheet for BD71837 is available at:
-https://www.rohm.com/datasheet/BD71837MWV/bd71837mwv-e
-Datasheet for BD71847 is available at:
-https://www.rohm.com/datasheet/BD71847AMWV/bd71847amwv-e
-
-Required properties:
- - compatible          : Should be "rohm,bd71837" for bd71837
-                                   "rohm,bd71847" for bd71847.
- - reg                 : I2C slave address.
- - interrupt-parent    : Phandle to the parent interrupt controller.
- - interrupts          : The interrupt line the device is connected to.
- - clocks              : The parent clock connected to PMIC. If this is missing
-                         32768 KHz clock is assumed.
- - #clock-cells                : Should be 0.
- - regulators:         : List of child nodes that specify the regulators.
-                         Please see ../regulator/rohm,bd71837-regulator.txt
-
-Optional properties:
-- clock-output-names   : Should contain name for output clock.
-- rohm,reset-snvs-powered : Transfer BD718x7 to SNVS state at reset.
-
-The BD718x7 supports two different HW states as reset target states. States
-are called as SNVS and READY. At READY state all the PMIC power outputs go
-down and OTP is reload. At the SNVS state all other logic and external
-devices apart from the SNVS power domain are shut off. Please refer to NXP
-i.MX8 documentation for further information regarding SNVS state. When a
-reset is done via SNVS state the PMIC OTP data is not reload. This causes
-power outputs that have been under SW control to stay down when reset has
-switched power state to SNVS. If reset is done via READY state the power
-outputs will be returned to HW control by OTP loading. Thus the reset
-target state is set to READY by default. If SNVS state is used the boot
-crucial regulators must have the regulator-always-on and regulator-boot-on
-properties set in regulator node.
-
-- rohm,short-press-ms  : Short press duration in milliseconds
-- rohm,long-press-ms   : Long press duration in milliseconds
-
-Configure the "short press" and "long press" timers for the power button.
-Values are rounded to what hardware supports (500ms multiple for short and
-1000ms multiple for long). If these properties are not present the existing
-configuration (from bootloader or OTP) is not touched.
-
-Example:
-
-       /* external oscillator node */
-       osc: oscillator {
-               compatible = "fixed-clock";
-               #clock-cells = <1>;
-               clock-frequency  = <32768>;
-               clock-output-names = "osc";
-       };
-
-       pmic: pmic@4b {
-               compatible = "rohm,bd71837";
-               reg = <0x4b>;
-               interrupt-parent = <&gpio1>;
-               interrupts = <29 GPIO_ACTIVE_LOW>;
-               interrupt-names = "irq";
-               #clock-cells = <0>;
-               clocks = <&osc 0>;
-               clock-output-names = "bd71837-32k-out";
-               rohm,reset-snvs-powered;
-
-               regulators {
-                       buck1: BUCK1 {
-                               regulator-name = "buck1";
-                               regulator-min-microvolt = <700000>;
-                               regulator-max-microvolt = <1300000>;
-                               regulator-boot-on;
-                               regulator-always-on;
-                               regulator-ramp-delay = <1250>;
-                       };
-                       // [...]
-               };
-       };
-
-       /* Clock consumer node */
-       rtc@0 {
-               compatible = "company,my-rtc";
-               clock-names = "my-clock";
-               clocks = <&pmic>;
-       };
diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.yaml
new file mode 100644 (file)
index 0000000..aa922c5
--- /dev/null
@@ -0,0 +1,236 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/rohm,bd71837-pmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BD71837 Power Management Integrated Circuit bindings
+
+maintainers:
+  - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
+
+description: |
+  BD71837MWV is programmable Power Management ICs for powering single-core,
+  dual-core, and quad-core SoCs such as NXP-i.MX 8M. It is optimized for low
+  BOM cost and compact solution footprint. BD71837MWV  integrates 8 Buck
+  regulators and 7 LDOs.
+  Datasheet for BD71837 is available at
+  https://www.rohm.com/products/power-management/power-management-ic-for-system/industrial-consumer-applications/nxp-imx/bd71837amwv-product
+
+properties:
+  compatible:
+    const: rohm,bd71837
+
+  reg:
+    description:
+      I2C slave address.
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  "#clock-cells":
+    const: 0
+
+# The BD718x7 supports two different HW states as reset target states. States
+# are called as SNVS and READY. At READY state all the PMIC power outputs go
+# down and OTP is reload. At the SNVS state all other logic and external
+# devices apart from the SNVS power domain are shut off. Please refer to NXP
+# i.MX8 documentation for further information regarding SNVS state. When a
+# reset is done via SNVS state the PMIC OTP data is not reload. This causes
+# power outputs that have been under SW control to stay down when reset has
+# switched power state to SNVS. If reset is done via READY state the power
+# outputs will be returned to HW control by OTP loading. Thus the reset
+# target state is set to READY by default. If SNVS state is used the boot
+# crucial regulators must have the regulator-always-on and regulator-boot-on
+# properties set in regulator node.
+
+  rohm,reset-snvs-powered:
+    description: |
+      Transfer PMIC to SNVS state at reset
+    type: boolean
+
+# Configure the "short press" and "long press" timers for the power button.
+# Values are rounded to what hardware supports
+# Short-press:
+#   Shortest being 10ms, next 500ms and then multiple of 500ms up to 7,5s
+# Long-press:
+#   Shortest being 10ms, next 1000ms and then multiple of 1000ms up to 15s
+# If these properties are not present the existing configuration (from
+# bootloader or OTP) is not touched.
+
+  rohm,short-press-ms:
+    description:
+      Short press duration in milliseconds
+    enum:
+      - 10
+      - 500
+      - 1000
+      - 1500
+      - 2000
+      - 2500
+      - 3000
+      - 3500
+      - 4000
+      - 4500
+      - 5000
+      - 5500
+      - 6000
+      - 6500
+      - 7000
+
+  rohm,long-press-ms:
+    description:
+      Long press duration in milliseconds
+    enum:
+      - 10
+      - 1000
+      - 2000
+      - 3000
+      - 4000
+      - 5000
+      - 6000
+      - 7000
+      - 8000
+      - 9000
+      - 10000
+      - 11000
+      - 12000
+      - 13000
+      - 14000
+
+  regulators:
+    $ref: ../regulator/rohm,bd71837-regulator.yaml
+    description:
+      List of child nodes that specify the regulators.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - "#clock-cells"
+  - regulators
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/leds/common.h>
+
+    i2c {
+      pmic: pmic@4b {
+            compatible = "rohm,bd71837";
+            reg = <0x4b>;
+            interrupt-parent = <&gpio1>;
+            interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+            #clock-cells = <0>;
+            clocks = <&osc 0>;
+            rohm,reset-snvs-powered;
+            rohm,short-press-ms = <10>;
+            rohm,long-press-ms = <2000>;
+
+            regulators {
+                buck1: BUCK1 {
+                    regulator-name = "buck1";
+                    regulator-min-microvolt = <700000>;
+                    regulator-max-microvolt = <1300000>;
+                    regulator-boot-on;
+                    regulator-always-on;
+                    regulator-ramp-delay = <1250>;
+                    rohm,dvs-run-voltage = <900000>;
+                    rohm,dvs-idle-voltage = <850000>;
+                    rohm,dvs-suspend-voltage = <800000>;
+                };
+                buck2: BUCK2 {
+                    regulator-name = "buck2";
+                    regulator-min-microvolt = <700000>;
+                    regulator-max-microvolt = <1300000>;
+                    regulator-boot-on;
+                    regulator-always-on;
+                    regulator-ramp-delay = <1250>;
+                    rohm,dvs-run-voltage = <1000000>;
+                    rohm,dvs-idle-voltage = <900000>;
+                };
+                buck3: BUCK3 {
+                    regulator-name = "buck3";
+                    regulator-min-microvolt = <700000>;
+                    regulator-max-microvolt = <1300000>;
+                    regulator-boot-on;
+                    rohm,dvs-run-voltage = <1000000>;
+                };
+                buck4: BUCK4 {
+                    regulator-name = "buck4";
+                    regulator-min-microvolt = <700000>;
+                    regulator-max-microvolt = <1300000>;
+                    regulator-boot-on;
+                    rohm,dvs-run-voltage = <1000000>;
+                };
+                buck5: BUCK5 {
+                    regulator-name = "buck5";
+                    regulator-min-microvolt = <700000>;
+                    regulator-max-microvolt = <1350000>;
+                    regulator-boot-on;
+                };
+                buck6: BUCK6 {
+                    regulator-name = "buck6";
+                    regulator-min-microvolt = <3000000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-boot-on;
+                };
+                buck7: BUCK7 {
+                    regulator-name = "buck7";
+                    regulator-min-microvolt = <1605000>;
+                    regulator-max-microvolt = <1995000>;
+                    regulator-boot-on;
+                };
+                buck8: BUCK8 {
+                    regulator-name = "buck8";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <1400000>;
+                };
+
+                ldo1: LDO1 {
+                    regulator-name = "ldo1";
+                    regulator-min-microvolt = <3000000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-boot-on;
+                };
+                ldo2: LDO2 {
+                    regulator-name = "ldo2";
+                    regulator-min-microvolt = <900000>;
+                    regulator-max-microvolt = <900000>;
+                    regulator-boot-on;
+                };
+                ldo3: LDO3 {
+                    regulator-name = "ldo3";
+                    regulator-min-microvolt = <1800000>;
+                    regulator-max-microvolt = <3300000>;
+                };
+                ldo4: LDO4 {
+                    regulator-name = "ldo4";
+                    regulator-min-microvolt = <900000>;
+                    regulator-max-microvolt = <1800000>;
+                };
+                ldo5: LDO5 {
+                    regulator-name = "ldo5";
+                    regulator-min-microvolt = <1800000>;
+                    regulator-max-microvolt = <3300000>;
+                };
+                ldo6: LDO6 {
+                    regulator-name = "ldo6";
+                    regulator-min-microvolt = <900000>;
+                    regulator-max-microvolt = <1800000>;
+                };
+                ldo7_reg: LDO7 {
+                    regulator-name = "ldo7";
+                    regulator-min-microvolt = <1800000>;
+                    regulator-max-microvolt = <3300000>;
+                };
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71847-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd71847-pmic.yaml
new file mode 100644 (file)
index 0000000..402e40d
--- /dev/null
@@ -0,0 +1,222 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/rohm,bd71847-pmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BD71847 and BD71850 Power Management Integrated Circuit bindings
+
+maintainers:
+  - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
+
+description: |
+  BD71847AMWV and BD71850MWV are programmable Power Management ICs for powering
+  single-core,  dual-core, and quad-core SoCs such as NXP-i.MX 8M. It is
+  optimized for low BOM cost and compact solution footprint. BD71847MWV and
+  BD71850MWV integrate 6 Buck regulators and 6 LDOs.
+  Datasheets are available at
+  https://www.rohm.com/products/power-management/power-management-ic-for-system/industrial-consumer-applications/nxp-imx/bd71847amwv-product
+  https://www.rohm.com/products/power-management/power-management-ic-for-system/industrial-consumer-applications/nxp-imx/bd71850mwv-product
+
+properties:
+  compatible:
+    enum:
+      - rohm,bd71847
+      - rohm,bd71850
+
+  reg:
+    description:
+      I2C slave address.
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  "#clock-cells":
+    const: 0
+
+# The BD71847 abd BD71850 support two different HW states as reset target
+# states. States are called as SNVS and READY. At READY state all the PMIC
+# power outputs go down and OTP is reload. At the SNVS state all other logic
+# and external devices apart from the SNVS power domain are shut off. Please
+# refer to NXP i.MX8 documentation for further information regarding SNVS
+# state. When a reset is done via SNVS state the PMIC OTP data is not reload.
+# This causes power outputs that have been under SW control to stay down when
+# reset has switched power state to SNVS. If reset is done via READY state the
+# power outputs will be returned to HW control by OTP loading. Thus the reset
+# target state is set to READY by default. If SNVS state is used the boot
+# crucial regulators must have the regulator-always-on and regulator-boot-on
+# properties set in regulator node.
+
+  rohm,reset-snvs-powered:
+    description:
+      Transfer PMIC to SNVS state at reset.
+    type: boolean
+
+# Configure the "short press" and "long press" timers for the power button.
+# Values are rounded to what hardware supports
+# Short-press:
+#   Shortest being 10ms, next 500ms and then multiple of 500ms up to 7,5s
+# Long-press:
+#   Shortest being 10ms, next 1000ms and then multiple of 1000ms up to 15s
+# If these properties are not present the existing # configuration (from
+# bootloader or OTP) is not touched.
+
+  rohm,short-press-ms:
+    description:
+      Short press duration in milliseconds
+    enum:
+      - 10
+      - 500
+      - 1000
+      - 1500
+      - 2000
+      - 2500
+      - 3000
+      - 3500
+      - 4000
+      - 4500
+      - 5000
+      - 5500
+      - 6000
+      - 6500
+      - 7000
+      - 7500
+
+  rohm,long-press-ms:
+    description:
+      Long press duration in milliseconds
+    enum:
+      - 10
+      - 1000
+      - 2000
+      - 3000
+      - 4000
+      - 5000
+      - 6000
+      - 7000
+      - 8000
+      - 9000
+      - 10000
+      - 11000
+      - 12000
+      - 13000
+      - 14000
+      - 15000
+
+  regulators:
+    $ref: ../regulator/rohm,bd71847-regulator.yaml
+    description:
+      List of child nodes that specify the regulators.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - "#clock-cells"
+  - regulators
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/leds/common.h>
+
+    i2c {
+      pmic: pmic@4b {
+            compatible = "rohm,bd71847";
+            reg = <0x4b>;
+            interrupt-parent = <&gpio1>;
+            interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+            #clock-cells = <0>;
+            clocks = <&osc 0>;
+            rohm,reset-snvs-powered;
+            rohm,short-press-ms = <10>;
+            rohm,long-press-ms = <2000>;
+
+            regulators {
+                buck1: BUCK1 {
+                    regulator-name = "buck1";
+                    regulator-min-microvolt = <700000>;
+                    regulator-max-microvolt = <1300000>;
+                    regulator-boot-on;
+                    regulator-always-on;
+                    regulator-ramp-delay = <1250>;
+                    rohm,dvs-run-voltage = <900000>;
+                    rohm,dvs-idle-voltage = <850000>;
+                    rohm,dvs-suspend-voltage = <800000>;
+                };
+                buck2: BUCK2 {
+                    regulator-name = "buck2";
+                    regulator-min-microvolt = <700000>;
+                    regulator-max-microvolt = <1300000>;
+                    regulator-boot-on;
+                    regulator-always-on;
+                    regulator-ramp-delay = <1250>;
+                    rohm,dvs-run-voltage = <1000000>;
+                    rohm,dvs-idle-voltage = <900000>;
+                };
+                buck3: BUCK3 {
+                    regulator-name = "buck3";
+                    regulator-min-microvolt = <550000>;
+                    regulator-max-microvolt = <1350000>;
+                    regulator-boot-on;
+                };
+                buck4: BUCK4 {
+                    regulator-name = "buck4";
+                    regulator-min-microvolt = <2600000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-boot-on;
+                };
+                buck5: BUCK5 {
+                    regulator-name = "buck5";
+                    regulator-min-microvolt = <1605000>;
+                    regulator-max-microvolt = <1995000>;
+                    regulator-boot-on;
+                };
+                buck8: BUCK6 {
+                    regulator-name = "buck6";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <1400000>;
+                };
+
+                ldo1: LDO1 {
+                    regulator-name = "ldo1";
+                    regulator-min-microvolt = <1600000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-boot-on;
+                };
+                ldo2: LDO2 {
+                    regulator-name = "ldo2";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <900000>;
+                    regulator-boot-on;
+                };
+                ldo3: LDO3 {
+                    regulator-name = "ldo3";
+                    regulator-min-microvolt = <1800000>;
+                    regulator-max-microvolt = <3300000>;
+                };
+                ldo4: LDO4 {
+                    regulator-name = "ldo4";
+                    regulator-min-microvolt = <900000>;
+                    regulator-max-microvolt = <1800000>;
+                };
+                ldo5: LDO5 {
+                    regulator-name = "ldo5";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <3300000>;
+                };
+                ldo6: LDO6 {
+                    regulator-name = "ldo6";
+                    regulator-min-microvolt = <900000>;
+                    regulator-max-microvolt = <1800000>;
+                };
+            };
+        };
+    };
index 1a4cc5f..ddf190c 100644 (file)
@@ -39,6 +39,8 @@ properties:
   "#size-cells":
     const: 0
 
+  wakeup-source: true
+
   pwm:
     type: object
 
@@ -81,6 +83,16 @@ patternProperties:
     required:
       - compatible
 
+  timer:
+    type: object
+
+    properties:
+      compatible:
+        const: st,stm32-lptimer-timer
+
+    required:
+      - compatible
+
 required:
   - "#address-cells"
   - "#size-cells"
@@ -115,6 +127,10 @@ examples:
       counter {
         compatible = "st,stm32-lptimer-counter";
       };
+
+      timer {
+        compatible = "st,stm32-lptimer-timer";
+      };
     };
 
 ...
diff --git a/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.txt b/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.txt
deleted file mode 100644 (file)
index 472bd46..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-* PWM controlled by ChromeOS EC
-
-Google's ChromeOS EC PWM is a simple PWM attached to the Embedded Controller
-(EC) and controlled via a host-command interface.
-
-An EC PWM node should be only found as a sub-node of the EC node (see
-Documentation/devicetree/bindings/mfd/cros-ec.txt).
-
-Required properties:
-- compatible: Must contain "google,cros-ec-pwm"
-- #pwm-cells: Should be 1. The cell specifies the PWM index.
-
-Example:
-       cros-ec@0 {
-               compatible = "google,cros-ec-spi";
-
-               ...
-
-               cros_ec_pwm: ec-pwm {
-                       compatible = "google,cros-ec-pwm";
-                       #pwm-cells = <1>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml b/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.yaml
new file mode 100644 (file)
index 0000000..24c217b
--- /dev/null
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/google,cros-ec-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PWM controlled by ChromeOS EC
+
+maintainers:
+  - Thierry Reding <thierry.reding@gmail.com>
+  - '"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>'
+
+description: |
+  Google's ChromeOS EC PWM is a simple PWM attached to the Embedded Controller
+  (EC) and controlled via a host-command interface.
+  An EC PWM node should be only found as a sub-node of the EC node (see
+  Documentation/devicetree/bindings/mfd/cros-ec.txt).
+
+properties:
+  compatible:
+    const: google,cros-ec-pwm
+  "#pwm-cells":
+    description: The cell specifies the PWM index.
+    const: 1
+
+required:
+  - compatible
+  - '#pwm-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    cros-ec@0 {
+        compatible = "google,cros-ec-spi";
+        cros_ec_pwm: ec-pwm {
+            compatible = "google,cros-ec-pwm";
+            #pwm-cells = <1>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/pwm/iqs620a-pwm.yaml b/Documentation/devicetree/bindings/pwm/iqs620a-pwm.yaml
new file mode 100644 (file)
index 0000000..1d7c27b
--- /dev/null
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/iqs620a-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Azoteq IQS620A PWM Generator
+
+maintainers:
+  - Jeff LaBundy <jeff@labundy.com>
+
+description: |
+  The Azoteq IQS620A multi-function sensor generates a fixed-frequency PWM
+  output represented by a "pwm" child node from the parent MFD driver. See
+  Documentation/devicetree/bindings/mfd/iqs62x.yaml for further details as
+  well as an example.
+
+properties:
+  compatible:
+    enum:
+      - azoteq,iqs620a-pwm
+
+  "#pwm-cells":
+    const: 2
+
+required:
+  - compatible
+  - "#pwm-cells"
+
+additionalProperties: false
+
+...
index 0a69ead..74c41e3 100644 (file)
@@ -9,6 +9,7 @@ Required properties:
   - "nvidia,tegra132-pwm", "nvidia,tegra20-pwm": for Tegra132
   - "nvidia,tegra210-pwm", "nvidia,tegra20-pwm": for Tegra210
   - "nvidia,tegra186-pwm": for Tegra186
+  - "nvidia,tegra194-pwm": for Tegra194
 - reg: physical base address and length of the controller's registers
 - #pwm-cells: should be 2. See pwm.yaml in this directory for a description of
   the cells format.
diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.txt b/Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.txt
deleted file mode 100644 (file)
index cbce62c..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-ROHM BD71837 and BD71847 Power Management Integrated Circuit regulator bindings
-
-Required properties:
- - regulator-name: should be "buck1", ..., "buck8" and "ldo1", ..., "ldo7" for
-                   BD71837. For BD71847 names should be "buck1", ..., "buck6"
-                  and "ldo1", ..., "ldo6"
-
-List of regulators provided by this controller. BD71837 regulators node
-should be sub node of the BD71837 MFD node. See BD71837 MFD bindings at
-Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt
-Regulator nodes should be named to BUCK_<number> and LDO_<number>. The
-definition for each of these nodes is defined using the standard
-binding for regulators at
-Documentation/devicetree/bindings/regulator/regulator.txt.
-Note that if BD71837 starts at RUN state you probably want to use
-regulator-boot-on at least for BUCK6 and BUCK7 so that those are not
-disabled by driver at startup. LDO5 and LDO6 are supplied by those and
-if they are disabled at startup the voltage monitoring for LDO5/LDO6 will
-cause PMIC to reset.
-
-The valid names for BD71837 regulator nodes are:
-BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, BUCK7, BUCK8
-LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7
-
-The valid names for BD71847 regulator nodes are:
-BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6
-LDO1, LDO2, LDO3, LDO4, LDO5, LDO6
-
-Optional properties:
-- rohm,dvs-run-voltage         : PMIC default "RUN" state voltage in uV.
-                                 See below table for bucks which support this.
-- rohm,dvs-idle-voltage                : PMIC default "IDLE" state voltage in uV.
-                                 See below table for bucks which support this.
-- rohm,dvs-suspend-voltage     : PMIC default "SUSPEND" state voltage in uV.
-                                 See below table for bucks which support this.
-- Any optional property defined in bindings/regulator/regulator.txt
-
-Supported default DVS states:
-
-BD71837:
-buck   | dvs-run-voltage       | dvs-idle-voltage      | dvs-suspend-voltage
------------------------------------------------------------------------------
-1      | supported             | supported             | supported
-----------------------------------------------------------------------------
-2      | supported             | supported             | not supported
-----------------------------------------------------------------------------
-3      | supported             | not supported         | not supported
-----------------------------------------------------------------------------
-4      | supported             | not supported         | not supported
-----------------------------------------------------------------------------
-rest   | not supported         | not supported         | not supported
-
-BD71847:
-buck   | dvs-run-voltage       | dvs-idle-voltage      | dvs-suspend-voltage
------------------------------------------------------------------------------
-1      | supported             | supported             | supported
-----------------------------------------------------------------------------
-2      | supported             | supported             | not supported
-----------------------------------------------------------------------------
-rest   | not supported         | not supported         | not supported
-
-Example:
-regulators {
-       buck1: BUCK1 {
-               regulator-name = "buck1";
-               regulator-min-microvolt = <700000>;
-               regulator-max-microvolt = <1300000>;
-               regulator-boot-on;
-               regulator-always-on;
-               regulator-ramp-delay = <1250>;
-               rohm,dvs-run-voltage = <900000>;
-               rohm,dvs-idle-voltage = <850000>;
-               rohm,dvs-suspend-voltage = <800000>;
-       };
-       buck2: BUCK2 {
-               regulator-name = "buck2";
-               regulator-min-microvolt = <700000>;
-               regulator-max-microvolt = <1300000>;
-               regulator-boot-on;
-               regulator-always-on;
-               regulator-ramp-delay = <1250>;
-               rohm,dvs-run-voltage = <1000000>;
-               rohm,dvs-idle-voltage = <900000>;
-       };
-       buck3: BUCK3 {
-               regulator-name = "buck3";
-               regulator-min-microvolt = <700000>;
-               regulator-max-microvolt = <1300000>;
-               regulator-boot-on;
-               rohm,dvs-run-voltage = <1000000>;
-       };
-       buck4: BUCK4 {
-               regulator-name = "buck4";
-               regulator-min-microvolt = <700000>;
-               regulator-max-microvolt = <1300000>;
-               regulator-boot-on;
-               rohm,dvs-run-voltage = <1000000>;
-       };
-       buck5: BUCK5 {
-               regulator-name = "buck5";
-               regulator-min-microvolt = <700000>;
-               regulator-max-microvolt = <1350000>;
-               regulator-boot-on;
-       };
-       buck6: BUCK6 {
-               regulator-name = "buck6";
-               regulator-min-microvolt = <3000000>;
-               regulator-max-microvolt = <3300000>;
-               regulator-boot-on;
-       };
-       buck7: BUCK7 {
-               regulator-name = "buck7";
-               regulator-min-microvolt = <1605000>;
-               regulator-max-microvolt = <1995000>;
-               regulator-boot-on;
-       };
-       buck8: BUCK8 {
-               regulator-name = "buck8";
-               regulator-min-microvolt = <800000>;
-               regulator-max-microvolt = <1400000>;
-       };
-
-       ldo1: LDO1 {
-               regulator-name = "ldo1";
-               regulator-min-microvolt = <3000000>;
-               regulator-max-microvolt = <3300000>;
-               regulator-boot-on;
-       };
-       ldo2: LDO2 {
-               regulator-name = "ldo2";
-               regulator-min-microvolt = <900000>;
-               regulator-max-microvolt = <900000>;
-               regulator-boot-on;
-       };
-       ldo3: LDO3 {
-               regulator-name = "ldo3";
-               regulator-min-microvolt = <1800000>;
-               regulator-max-microvolt = <3300000>;
-       };
-       ldo4: LDO4 {
-               regulator-name = "ldo4";
-               regulator-min-microvolt = <900000>;
-               regulator-max-microvolt = <1800000>;
-       };
-       ldo5: LDO5 {
-               regulator-name = "ldo5";
-               regulator-min-microvolt = <1800000>;
-               regulator-max-microvolt = <3300000>;
-       };
-       ldo6: LDO6 {
-               regulator-name = "ldo6";
-               regulator-min-microvolt = <900000>;
-               regulator-max-microvolt = <1800000>;
-       };
-       ldo7_reg: LDO7 {
-               regulator-name = "ldo7";
-               regulator-min-microvolt = <1800000>;
-               regulator-max-microvolt = <3300000>;
-       };
-};
-
-
diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.yaml b/Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.yaml
new file mode 100644 (file)
index 0000000..a323b16
--- /dev/null
@@ -0,0 +1,103 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/rohm,bd71837-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BD71837 Power Management Integrated Circuit regulators
+
+maintainers:
+  - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
+
+description: |
+  List of regulators provided by this controller. BD71837 regulators node
+  should be sub node of the BD71837 MFD node. See BD71837 MFD bindings at
+  Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.yaml
+  Regulator nodes should be named to BUCK_<number> and LDO_<number>. The
+  definition for each of these nodes is defined using the standard
+  binding for regulators at
+  Documentation/devicetree/bindings/regulator/regulator.txt.
+  Note that if BD71837 starts at RUN state you probably want to use
+  regulator-boot-on at least for BUCK6 and BUCK7 so that those are not
+  disabled by driver at startup. LDO5 and LDO6 are supplied by those and
+  if they are disabled at startup the voltage monitoring for LDO5/LDO6 will
+  cause PMIC to reset.
+
+#The valid names for BD71837 regulator nodes are:
+#BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, BUCK7, BUCK8
+#LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7
+
+patternProperties:
+  "^LDO[1-7]$":
+    type: object
+    allOf:
+      - $ref: regulator.yaml#
+    description:
+      Properties for single LDO regulator.
+
+    properties:
+      regulator-name:
+        pattern: "^ldo[1-7]$"
+        description:
+          should be "ldo1", ..., "ldo7"
+
+  "^BUCK[1-8]$":
+    type: object
+    allOf:
+      - $ref: regulator.yaml#
+    description:
+      Properties for single BUCK regulator.
+
+    properties:
+      regulator-name:
+        pattern: "^buck[1-8]$"
+        description:
+          should be "buck1", ..., "buck8"
+
+      rohm,dvs-run-voltage:
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/uint32"
+          - minimum: 0
+            maximum: 1300000
+        description:
+          PMIC default "RUN" state voltage in uV. See below table for
+          bucks which support this. 0 means disabled.
+
+      rohm,dvs-idle-voltage:
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/uint32"
+          - minimum: 0
+            maximum: 1300000
+        description:
+          PMIC default "IDLE" state voltage in uV. See below table for
+          bucks which support this. 0 means disabled.
+
+      rohm,dvs-suspend-voltage:
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/uint32"
+          - minimum: 0
+            maximum: 1300000
+        description:
+          PMIC default "SUSPEND" state voltage in uV. See below table for
+          bucks which support this. 0 means disabled.
+
+        # Supported default DVS states:
+        #
+        # BD71837:
+        # buck | dvs-run-voltage | dvs-idle-voltage | dvs-suspend-voltage
+        # ----------------------------------------------------------------
+        # 1    | supported       | supported        | supported
+        # ----------------------------------------------------------------
+        # 2    | supported       | supported        | not supported
+        # ----------------------------------------------------------------
+        # 3    | supported       | not supported    | not supported
+        # ----------------------------------------------------------------
+        # 4    | supported       | not supported    | not supported
+        # ----------------------------------------------------------------
+        # rest | not supported   | not supported    | not supported
+
+
+    required:
+      - regulator-name
+  additionalProperties: false
+additionalProperties: false
diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd71847-regulator.yaml b/Documentation/devicetree/bindings/regulator/rohm,bd71847-regulator.yaml
new file mode 100644 (file)
index 0000000..526fd00
--- /dev/null
@@ -0,0 +1,97 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/rohm,bd71847-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BD71847 and BD71850 Power Management Integrated Circuit regulators
+
+maintainers:
+  - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
+
+description: |
+  List of regulators provided by this controller. BD71847 regulators node
+  should be sub node of the BD71847 MFD node. See BD71847 MFD bindings at
+  Documentation/devicetree/bindings/mfd/rohm,bd71847-pmic.yaml
+  Regulator nodes should be named to BUCK_<number> and LDO_<number>. The
+  definition for each of these nodes is defined using the standard
+  binding for regulators at
+  Documentation/devicetree/bindings/regulator/regulator.txt.
+  Note that if BD71847 starts at RUN state you probably want to use
+  regulator-boot-on at least for BUCK5. LDO6 is supplied by it and it must
+  not be disabled by driver at startup. If BUCK5 is disabled at startup the
+  voltage monitoring for LDO5/LDO6 can cause PMIC to reset.
+
+#The valid names for BD71847 regulator nodes are:
+#BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6
+#LDO1, LDO2, LDO3, LDO4, LDO5, LDO6
+
+patternProperties:
+  "^LDO[1-6]$":
+    type: object
+    allOf:
+      - $ref: regulator.yaml#
+    description:
+      Properties for single LDO regulator.
+
+    properties:
+      regulator-name:
+        pattern: "^ldo[1-6]$"
+        description:
+          should be "ldo1", ..., "ldo6"
+
+  "^BUCK[1-6]$":
+    type: object
+    allOf:
+      - $ref: regulator.yaml#
+    description:
+      Properties for single BUCK regulator.
+
+    properties:
+      regulator-name:
+        pattern: "^buck[1-6]$"
+        description:
+          should be "buck1", ..., "buck6"
+
+      rohm,dvs-run-voltage:
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/uint32"
+          - minimum: 0
+            maximum: 1300000
+        description:
+          PMIC default "RUN" state voltage in uV. See below table for
+          bucks which support this. 0 means disabled.
+
+      rohm,dvs-idle-voltage:
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/uint32"
+          - minimum: 0
+            maximum: 1300000
+        description:
+          PMIC default "IDLE" state voltage in uV. See below table for
+          bucks which support this. 0 means disabled.
+
+      rohm,dvs-suspend-voltage:
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/uint32"
+          - minimum: 0
+            maximum: 1300000
+        description:
+          PMIC default "SUSPEND" state voltage in uV. See below table for
+          bucks which support this. 0 means disabled.
+
+        # Supported default DVS states:
+        #
+        # BD71847:
+        # buck | dvs-run-voltage | dvs-idle-voltage | dvs-suspend-voltage
+        # ----------------------------------------------------------------
+        # 1    | supported       | supported        | supported
+        # ----------------------------------------------------------------
+        # 2    | supported       | supported        | not supported
+        # ----------------------------------------------------------------
+        # rest | not supported   | not supported    | not supported
+
+    required:
+      - regulator-name
+  additionalProperties: false
+additionalProperties: false
index efce847..83f44f0 100644 (file)
@@ -49,7 +49,7 @@ required:
 examples:
   - |
     #include <dt-bindings/gpio/gpio.h>
-    i2c@0 {
+    i2c {
       #address-cells = <1>;
       #size-cells = <0>;
 
diff --git a/Documentation/devicetree/bindings/thermal/imx8mm-thermal.txt b/Documentation/devicetree/bindings/thermal/imx8mm-thermal.txt
new file mode 100644 (file)
index 0000000..3629d3c
--- /dev/null
@@ -0,0 +1,15 @@
+* Thermal Monitoring Unit (TMU) on Freescale i.MX8MM SoC
+
+Required properties:
+- compatible : Must be "fsl,imx8mm-tmu" or "fsl,imx8mp-tmu".
+- reg : Address range of TMU registers.
+- clocks : TMU's clock source.
+- #thermal-sensor-cells : Should be 0 or 1. See ./thermal.txt for a description.
+
+Example:
+tmu: tmu@30260000 {
+       compatible = "fsl,imx8mm-tmu";
+       reg = <0x30260000 0x10000>;
+       clocks = <&clk IMX8MM_CLK_TMU_ROOT>;
+       #thermal-sensor-cells = <0>;
+};
index a57b76a..2ddd39d 100644 (file)
@@ -38,11 +38,11 @@ properties:
           - enum:
               - qcom,msm8996-tsens
               - qcom,msm8998-tsens
+              - qcom,sc7180-tsens
               - qcom,sdm845-tsens
           - const: qcom,tsens-v2
 
   reg:
-    maxItems: 2
     items:
       - description: TM registers
       - description: SROT registers
index 12c740b..2993fa7 100644 (file)
@@ -11,6 +11,7 @@ Required properties:
                            - "renesas,r8a774b1-thermal" (RZ/G2N)
                            - "renesas,r8a7795-thermal" (R-Car H3)
                            - "renesas,r8a7796-thermal" (R-Car M3-W)
+                           - "renesas,r8a77961-thermal" (R-Car M3-W+)
                            - "renesas,r8a77965-thermal" (R-Car M3-N)
                            - "renesas,r8a77980-thermal" (R-Car V3H)
 - reg                  : Address ranges of the thermal registers. Each sensor
diff --git a/Documentation/devicetree/bindings/thermal/sprd-thermal.yaml b/Documentation/devicetree/bindings/thermal/sprd-thermal.yaml
new file mode 100644 (file)
index 0000000..058c4cc
--- /dev/null
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/thermal/sprd-thermal.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Spreadtrum thermal sensor controller bindings
+
+maintainers:
+  - Orson Zhai <orsonzhai@gmail.com>
+  - Baolin Wang <baolin.wang7@gmail.com>
+  - Chunyan Zhang <zhang.lyra@gmail.com>
+
+properties:
+  compatible:
+    const: sprd,ums512-thermal
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: enable
+
+  nvmem-cells:
+    maxItems: 2
+    description:
+      Reference to nvmem nodes for the calibration data.
+
+  nvmem-cell-names:
+    items:
+      - const: thm_sign_cal
+      - const: thm_ratio_cal
+
+  "#thermal-sensor-cells":
+    const: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^([a-z]*-)?sensor(-section)?@[0-9]+$":
+    type: object
+    description:
+      Represent one thermal sensor.
+
+    properties:
+      reg:
+        description: Specify the sensor id.
+        maxItems: 1
+
+      nvmem-cells:
+        maxItems: 1
+        description:
+          Reference to an nvmem node for the calibration data.
+
+      nvmem-cell-names:
+        const: sen_delta_cal
+
+    required:
+      - reg
+      - nvmem-cells
+      - nvmem-cell-names
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - nvmem-cells
+  - nvmem-cell-names
+  - "#thermal-sensor-cells"
+  - "#address-cells"
+  - "#size-cells"
+
+examples:
+  - |
+        ap_thm0: thermal@32200000 {
+                compatible = "sprd,ums512-thermal";
+                reg = <0 0x32200000 0 0x10000>;
+                clock-names = "enable";
+                clocks = <&aonapb_gate 32>;
+                #thermal-sensor-cells = <1>;
+                nvmem-cells = <&thm0_sign>, <&thm0_ratio>;
+                nvmem-cell-names = "thm_sign_cal", "thm_ratio_cal";
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                prometheus-sensor@0 {
+                        reg = <0>;
+                        nvmem-cells = <&thm0_sen0>;
+                        nvmem-cell-names = "sen_delta_cal";
+                };
+
+                ank-sensor@1 {
+                        reg = <1>;
+                        nvmem-cells = <&thm0_sen1>;
+                        nvmem-cell-names = "sen_delta_cal";
+                };
+        };
+...
index ca14ba9..f78bec1 100644 (file)
@@ -142,11 +142,11 @@ Required properties:
 - trips:               A sub-node which is a container of only trip point nodes
   Type: sub-node       required to describe the thermal zone.
 
+Optional property:
 - cooling-maps:                A sub-node which is a container of only cooling device
   Type: sub-node       map nodes, used to describe the relation between trips
                        and cooling devices.
 
-Optional property:
 - coefficients:                An array of integers (one signed cell) containing
   Type: array          coefficients to compose a linear relation between
   Elem size: one cell  the sensors listed in the thermal-sensors property.
diff --git a/Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml b/Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml
new file mode 100644 (file)
index 0000000..e83026f
--- /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/watchdog/ti,rti-wdt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments K3 SoC Watchdog Timer
+
+maintainers:
+  - Tero Kristo <t-kristo@ti.com>
+
+description:
+  The TI K3 SoC watchdog timer is implemented via the RTI (Real Time
+  Interrupt) IP module. This timer adds a support for windowed watchdog
+  mode, which will signal an error if it is pinged outside the watchdog
+  time window, meaning either too early or too late. The error signal
+  generated can be routed to either interrupt a safety controller or
+  to directly reset the SoC.
+
+allOf:
+  - $ref: "watchdog.yaml#"
+
+properties:
+  compatible:
+    enum:
+      - ti,j7-rti-wdt
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  assigned-clocks:
+    maxItems: 1
+
+  assigned-clocks-parents:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - power-domains
+
+examples:
+  - |
+    /*
+     * RTI WDT in main domain on J721e SoC. Assigned clocks are used to
+     * select the source clock for the watchdog, forcing it to tick with
+     * a 32kHz clock in this case.
+     */
+    #include <dt-bindings/soc/ti,sci_pm_domain.h>
+
+    watchdog0: rti@2200000 {
+        compatible = "ti,rti-wdt";
+        reg = <0x0 0x2200000 0x0 0x100>;
+        clocks = <&k3_clks 252 1>;
+        power-domains = <&k3_pds 252 TI_SCI_PD_EXCLUSIVE>;
+        assigned-clocks = <&k3_clks 252 1>;
+        assigned-clock-parents = <&k3_clks 252 5>;
+    };
index 9f0016e..a1c3ede 100644 (file)
@@ -105,8 +105,8 @@ and this variation will modulate the cooling effect.
        idle  <-------------->
                 running
 
-      <----------------------------->
-              duty cycle 33%
+      <--------------------->
+          duty cycle 33%
 
 
      ^
index 4fe1c06..0b3d9ff 100644 (file)
@@ -314,11 +314,8 @@ http://www.linux-usb.org/
 Linux Hotplug Project:
 http://linux-hotplug.sourceforge.net/
 
-Linux USB Working Devices List:
-http://www.qbik.ch/usb/devices/
-
-linux-usb-devel Mailing List Archives:
-http://marc.theaimsgroup.com/?l=linux-usb-devel
+linux-usb Mailing List Archives:
+https://lore.kernel.org/linux-usb/
 
 Programming Guide for Linux USB Device Drivers:
 http://lmu.web.psi.ch/docu/manuals/software_manuals/linux_sl/usb_linux_programming_guide.pdf
index 9963cca..bda3ad6 100644 (file)
@@ -7,9 +7,6 @@ W1: Dallas' 1-wire bus
 W1 API internal to the kernel
 =============================
 
-W1 API internal to the kernel
------------------------------
-
 include/linux/w1.h
 ~~~~~~~~~~~~~~~~~~
 
index f054d1c..671fef3 100644 (file)
@@ -158,6 +158,16 @@ Options
                /sys/fs/9p/caches. (applies only to cache=fscache)
   ============= ===============================================================
 
+Behavior
+========
+
+This section aims at describing 9p 'quirks' that can be different
+from a local filesystem behaviors.
+
+ - Setting O_NONBLOCK on a file will make client reads return as early
+   as the server returns some data instead of trying to fill the read
+   buffer with the requested amount of bytes or end of file is reached.
+
 Resources
 =========
 
index b46a721..0aa7075 100644 (file)
@@ -107,17 +107,17 @@ Mount Options
        address its connection to the monitor originates from.
 
   wsize=X
-       Specify the maximum write size in bytes.  Default: 16 MB.
+       Specify the maximum write size in bytes.  Default: 64 MB.
 
   rsize=X
-       Specify the maximum read size in bytes.  Default: 16 MB.
+       Specify the maximum read size in bytes.  Default: 64 MB.
 
   rasize=X
        Specify the maximum readahead size in bytes.  Default: 8 MB.
 
   mount_timeout=X
        Specify the timeout value for mount (in seconds), in the case
-       of a non-responsive Ceph file system.  The default is 30
+       of a non-responsive Ceph file system.  The default is 60
        seconds.
 
   caps_max=X
index 7d6d4ca..e413697 100644 (file)
@@ -41,16 +41,6 @@ Documentation
 
 http://www.orangefs.org/documentation/
 
-
-Userspace Filesystem Source
-===========================
-
-http://www.orangefs.org/download
-
-Orangefs versions prior to 2.9.3 would not be compatible with the
-upstream version of the kernel client.
-
-
 Running ORANGEFS On a Single Server
 ===================================
 
@@ -94,6 +84,14 @@ Mount the filesystem::
 
     mount -t pvfs2 tcp://localhost:3334/orangefs /pvfsmnt
 
+Userspace Filesystem Source
+===========================
+
+http://www.orangefs.org/download
+
+Orangefs versions prior to 2.9.3 would not be compatible with the
+upstream version of the kernel client.
+
 
 Building ORANGEFS on a Single Server
 ====================================
@@ -107,18 +105,24 @@ default, we will probably be changing the default to LMDB soon.
 
 ::
 
-    ./configure --prefix=/opt/ofs --with-db-backend=lmdb
+    ./configure --prefix=/opt/ofs --with-db-backend=lmdb --disable-usrint
 
     make
 
     make install
 
-Create an orangefs config file::
+Create an orangefs config file by running pvfs2-genconfig and
+specifying a target config file. Pvfs2-genconfig will prompt you
+through. Generally it works fine to take the defaults, but you
+should use your server's hostname, rather than "localhost" when
+it comes to that question::
 
     /opt/ofs/bin/pvfs2-genconfig /etc/pvfs2.conf
 
 Create an /etc/pvfs2tab file::
 
+Localhost is fine for your pvfs2tab file:
+
     echo tcp://localhost:3334/orangefs /pvfsmnt pvfs2 defaults,noauto 0 0 > \
        /etc/pvfs2tab
 
@@ -132,7 +136,7 @@ Bootstrap the server::
 
 Start the server::
 
-    /opt/osf/sbin/pvfs2-server /etc/pvfs2.conf
+    /opt/ofs/sbin/pvfs2-server /etc/pvfs2.conf
 
 Now the server should be running. Pvfs2-ls is a simple
 test to verify that the server is running::
@@ -142,11 +146,11 @@ test to verify that the server is running::
 If stuff seems to be working, load the kernel module and
 turn on the client core::
 
-    /opt/ofs/sbin/pvfs2-client -p /opt/osf/sbin/pvfs2-client-core
+    /opt/ofs/sbin/pvfs2-client -p /opt/ofs/sbin/pvfs2-client-core
 
 Mount your filesystem::
 
-    mount -t pvfs2 tcp://localhost:3334/orangefs /pvfsmnt
+    mount -t pvfs2 tcp://`hostname`:3334/orangefs /pvfsmnt
 
 
 Running xfstests
index e443be7..c9d2bf9 100644 (file)
@@ -40,13 +40,46 @@ On 64bit systems, even if all overlay layers are not on the same
 underlying filesystem, the same compliant behavior could be achieved
 with the "xino" feature.  The "xino" feature composes a unique object
 identifier from the real object st_ino and an underlying fsid index.
+
 If all underlying filesystems support NFS file handles and export file
 handles with 32bit inode number encoding (e.g. ext4), overlay filesystem
 will use the high inode number bits for fsid.  Even when the underlying
 filesystem uses 64bit inode numbers, users can still enable the "xino"
 feature with the "-o xino=on" overlay mount option.  That is useful for the
 case of underlying filesystems like xfs and tmpfs, which use 64bit inode
-numbers, but are very unlikely to use the high inode number bit.
+numbers, but are very unlikely to use the high inode number bits.  In case
+the underlying inode number does overflow into the high xino bits, overlay
+filesystem will fall back to the non xino behavior for that inode.
+
+The following table summarizes what can be expected in different overlay
+configurations.
+
+Inode properties
+````````````````
+
++--------------+------------+------------+-----------------+----------------+
+|Configuration | Persistent | Uniform    | st_ino == d_ino | d_ino == i_ino |
+|              | st_ino     | st_dev     |                 | [*]            |
++==============+=====+======+=====+======+========+========+========+=======+
+|              | dir | !dir | dir | !dir |  dir   +  !dir  |  dir   | !dir  |
++--------------+-----+------+-----+------+--------+--------+--------+-------+
+| All layers   |  Y  |  Y   |  Y  |  Y   |  Y     |   Y    |  Y     |  Y    |
+| on same fs   |     |      |     |      |        |        |        |       |
++--------------+-----+------+-----+------+--------+--------+--------+-------+
+| Layers not   |  N  |  Y   |  Y  |  N   |  N     |   Y    |  N     |  Y    |
+| on same fs,  |     |      |     |      |        |        |        |       |
+| xino=off     |     |      |     |      |        |        |        |       |
++--------------+-----+------+-----+------+--------+--------+--------+-------+
+| xino=on/auto |  Y  |  Y   |  Y  |  Y   |  Y     |   Y    |  Y     |  Y    |
+|              |     |      |     |      |        |        |        |       |
++--------------+-----+------+-----+------+--------+--------+--------+-------+
+| xino=on/auto,|  N  |  Y   |  Y  |  N   |  N     |   Y    |  N     |  Y    |
+| ino overflow |     |      |     |      |        |        |        |       |
++--------------+-----+------+-----+------+--------+--------+--------+-------+
+
+[*] nfsd v3 readdirplus verifies d_ino == i_ino. i_ino is exposed via several
+/proc files, such as /proc/locks and /proc/self/fdinfo/<fd> of an inotify
+file descriptor.
 
 
 Upper and Lower
@@ -248,6 +281,50 @@ overlay filesystem (though an operation on the name of the file such as
 rename or unlink will of course be noticed and handled).
 
 
+Permission model
+----------------
+
+Permission checking in the overlay filesystem follows these principles:
+
+ 1) permission check SHOULD return the same result before and after copy up
+
+ 2) task creating the overlay mount MUST NOT gain additional privileges
+
+ 3) non-mounting task MAY gain additional privileges through the overlay,
+ compared to direct access on underlying lower or upper filesystems
+
+This is achieved by performing two permission checks on each access
+
+ a) check if current task is allowed access based on local DAC (owner,
+    group, mode and posix acl), as well as MAC checks
+
+ b) check if mounting task would be allowed real operation on lower or
+    upper layer based on underlying filesystem permissions, again including
+    MAC checks
+
+Check (a) ensures consistency (1) since owner, group, mode and posix acls
+are copied up.  On the other hand it can result in server enforced
+permissions (used by NFS, for example) being ignored (3).
+
+Check (b) ensures that no task gains permissions to underlying layers that
+the mounting task does not have (2).  This also means that it is possible
+to create setups where the consistency rule (1) does not hold; normally,
+however, the mounting task will have sufficient privileges to perform all
+operations.
+
+Another way to demonstrate this model is drawing parallels between
+
+  mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,... /merged
+
+and
+
+  cp -a /lower /upper
+  mount --bind /upper /merged
+
+The resulting access permissions should be the same.  The difference is in
+the time of copy (on-demand vs. up-front).
+
+
 Multiple lower layers
 ---------------------
 
@@ -383,7 +460,8 @@ guarantee that the values of st_ino and st_dev returned by stat(2) and the
 value of d_ino returned by readdir(3) will act like on a normal filesystem.
 E.g. the value of st_dev may be different for two objects in the same
 overlay filesystem and the value of st_ino for directory objects may not be
-persistent and could change even while the overlay filesystem is mounted.
+persistent and could change even while the overlay filesystem is mounted, as
+summarized in the `Inode properties`_ table above.
 
 
 Changes to underlying filesystems
index b713083..fd13433 100644 (file)
@@ -185,7 +185,7 @@ tree structures are treated as system blocks.
 
 The rational behind that is that a write request can work on a new snapshot
 (system area of the inactive - resp. lower serial numbered superblock) while
-at the same time there is still a complete stable filesystem structer in the
+at the same time there is still a complete stable filesystem structure in the
 other half of the system area.
 
 When finished with writing (a sync write is completed, the maximum sync leap
index 3eb763d..6193582 100644 (file)
@@ -56,13 +56,13 @@ are illustrated in the following diagram::
                   +- - - -+                  |  +-------------------| |
                   | Entry | - - - - - - - -+ |  | Definition Blocks | |
                   +- - - -+                | |  +-------------------+ |
-                                          | |  +- - - - - - - - - -+ |
-                                          +-|->|       SSDT        | |
+                                           | |  +- - - - - - - - - -+ |
+                                           +-|->|       SSDT        | |
                                              |  +-------------------+ |
                                              |  | Definition Blocks | |
                                              |  +- - - - - - - - - -+ |
                                              +------------------------+
-                                                         |
+                                                          |
                                              OSPM Loading |
                                                          \|/
                                                    +----------------+
index 510f38d..2d1fc03 100644 (file)
@@ -262,3 +262,8 @@ KBUILD_BUILD_USER, KBUILD_BUILD_HOST
 These two variables allow to override the user@host string displayed during
 boot and in /proc/version. The default value is the output of the commands
 whoami and host, respectively.
+
+LLVM
+----
+If this variable is set to 1, Kbuild will use Clang and LLVM utilities instead
+of GCC and GNU binutils to build the kernel.
index d6c79eb..c776b6e 100644 (file)
@@ -47,14 +47,21 @@ example:
 LLVM Utilities
 --------------
 
-LLVM has substitutes for GNU binutils utilities. These can be invoked as
-additional parameters to `make`.
+LLVM has substitutes for GNU binutils utilities. Kbuild supports `LLVM=1`
+to enable them.
 
-       make CC=clang AS=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip \\
-         OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump OBJSIZE=llvm-objsize \\
+       make LLVM=1
+
+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 \\
          HOSTLD=ld.lld
 
+Currently, the integrated assembler is disabled by default. You can pass
+`LLVM_IAS=1` to enable it.
+
 Getting Help
 ------------
 
index e478635..91c5ff8 100644 (file)
@@ -31,7 +31,7 @@ you probably needn't concern yourself with pcmciautils.
 ====================== ===============  ========================================
 GNU C                  4.6              gcc --version
 GNU make               3.81             make --version
-binutils               2.21             ld -v
+binutils               2.23             ld -v
 flex                   2.5.35           flex --version
 bison                  2.0              bison --version
 util-linux             2.10o            fdformat --version
@@ -76,7 +76,7 @@ You will need GNU make 3.81 or later to build the kernel.
 Binutils
 --------
 
-Binutils 2.21 or newer is needed to build the kernel.
+Binutils 2.23 or newer is needed to build the kernel.
 
 pkg-config
 ----------
index fa7ddc0..5325c71 100644 (file)
@@ -1399,8 +1399,8 @@ must have read/write permission; CS must be __BOOT_CS and DS, ES, SS
 must be __BOOT_DS; interrupt must be disabled; %rsi must hold the base
 address of the struct boot_params.
 
-EFI Handover Protocol
-=====================
+EFI Handover Protocol (deprecated)
+==================================
 
 This protocol allows boot loaders to defer initialisation to the EFI
 boot stub. The boot loader is required to load the kernel/initrd(s)
@@ -1408,6 +1408,12 @@ from the boot media and jump to the EFI handover protocol entry point
 which is hdr->handover_offset bytes from the beginning of
 startup_{32,64}.
 
+The boot loader MUST respect the kernel's PE/COFF metadata when it comes
+to section alignment, the memory footprint of the executable image beyond
+the size of the file itself, and any other aspect of the PE/COFF header
+that may affect correct operation of the image as a PE/COFF binary in the
+execution context provided by the EFI firmware.
+
 The function prototype for the handover entry point looks like this::
 
     efi_main(void *handle, efi_system_table_t *table, struct boot_params *bp)
@@ -1419,9 +1425,18 @@ UEFI specification. 'bp' is the boot loader-allocated boot params.
 
 The boot loader *must* fill out the following fields in bp::
 
-  - hdr.code32_start
   - hdr.cmd_line_ptr
   - hdr.ramdisk_image (if applicable)
   - hdr.ramdisk_size  (if applicable)
 
 All other fields should be zero.
+
+NOTE: The EFI Handover Protocol is deprecated in favour of the ordinary PE/COFF
+      entry point, combined with the LINUX_EFI_INITRD_MEDIA_GUID based initrd
+      loading protocol (refer to [0] for an example of the bootloader side of
+      this), which removes the need for any knowledge on the part of the EFI
+      bootloader regarding the internal representation of boot_params or any
+      requirements/limitations regarding the placement of the command line
+      and ramdisk in memory, or the placement of the kernel image itself.
+
+[0] https://github.com/u-boot/u-boot/commit/ec80b4735a593961fe701cc3a5d717d4739b0fd0
index 46a3a01..6851ef7 100644 (file)
@@ -159,8 +159,8 @@ F:  drivers/net/ethernet/3com/typhoon*
 3WARE SAS/SATA-RAID SCSI DRIVERS (3W-XXXX, 3W-9XXX, 3W-SAS)
 M:     Adam Radford <aradford@gmail.com>
 L:     linux-scsi@vger.kernel.org
-W:     http://www.lsi.com
 S:     Supported
+W:     http://www.lsi.com
 F:     drivers/scsi/3w-*
 
 53C700 AND 53C700-66 SCSI DRIVER
@@ -175,9 +175,9 @@ M:  Jukka Rissanen <jukka.rissanen@linux.intel.com>
 L:     linux-bluetooth@vger.kernel.org
 L:     linux-wpan@vger.kernel.org
 S:     Maintained
-F:     net/6lowpan/
-F:     include/net/6lowpan.h
 F:     Documentation/networking/6lowpan.rst
+F:     include/net/6lowpan.h
+F:     net/6lowpan/
 
 6PACK NETWORK DRIVER FOR AX.25
 M:     Andreas Koensgen <ajk@comnets.uni-bremen.de>
@@ -185,6 +185,23 @@ L: linux-hams@vger.kernel.org
 S:     Maintained
 F:     drivers/net/hamradio/6pack.c
 
+802.11 (including CFG80211/NL80211)
+M:     Johannes Berg <johannes@sipsolutions.net>
+L:     linux-wireless@vger.kernel.org
+S:     Maintained
+W:     http://wireless.kernel.org/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
+F:     Documentation/driver-api/80211/cfg80211.rst
+F:     Documentation/networking/regulatory.txt
+F:     include/linux/ieee80211.h
+F:     include/net/cfg80211.h
+F:     include/net/ieee80211_radiotap.h
+F:     include/net/iw_handler.h
+F:     include/net/wext.h
+F:     include/uapi/linux/nl80211.h
+F:     net/wireless/
+
 8169 10/100/1000 GIGABIT ETHERNET DRIVER
 M:     Realtek linux nic maintainers <nic_swsd@realtek.com>
 M:     Heiner Kallweit <hkallweit1@gmail.com>
@@ -210,33 +227,33 @@ M:        Eric Van Hensbergen <ericvh@gmail.com>
 M:     Latchesar Ionkov <lucho@ionkov.net>
 M:     Dominique Martinet <asmadeus@codewreck.org>
 L:     v9fs-developer@lists.sourceforge.net
+S:     Maintained
 W:     http://swik.net/v9fs
 Q:     http://patchwork.kernel.org/project/v9fs-devel/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs.git
 T:     git git://github.com/martinetd/linux.git
-S:     Maintained
 F:     Documentation/filesystems/9p.rst
 F:     fs/9p/
-F:     net/9p/
 F:     include/net/9p/
-F:     include/uapi/linux/virtio_9p.h
 F:     include/trace/events/9p.h
+F:     include/uapi/linux/virtio_9p.h
+F:     net/9p/
 
 A8293 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/dvb-frontends/a8293*
 
 AACRAID SCSI RAID DRIVER
 M:     Adaptec OEM Raid Solutions <aacraid@microsemi.com>
 L:     linux-scsi@vger.kernel.org
-W:     http://www.adaptec.com/
 S:     Supported
+W:     http://www.adaptec.com/
 F:     Documentation/scsi/aacraid.rst
 F:     drivers/scsi/aacraid/
 
@@ -320,9 +337,9 @@ M:  Len Brown <lenb@kernel.org>
 L:     linux-acpi@vger.kernel.org
 S:     Supported
 W:     https://01.org/linux-acpi
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
 Q:     https://patchwork.kernel.org/project/linux-acpi/list/
 B:     https://bugzilla.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
 F:     Documentation/ABI/testing/configfs-acpi
 F:     Documentation/ABI/testing/sysfs-bus-acpi
 F:     Documentation/firmware-guide/acpi/
@@ -353,10 +370,10 @@ L:        devel@acpica.org
 S:     Supported
 W:     https://acpica.org/
 W:     https://github.com/acpica/acpica/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
 Q:     https://patchwork.kernel.org/project/linux-acpi/list/
 B:     https://bugzilla.kernel.org
 B:     https://bugs.acpica.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
 F:     drivers/acpi/acpica/
 F:     include/acpi/
 F:     tools/power/acpi/
@@ -391,9 +408,9 @@ R:  Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 R:     Mika Westerberg <mika.westerberg@linux.intel.com>
 L:     linux-acpi@vger.kernel.org
 S:     Supported
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
 Q:     https://patchwork.kernel.org/project/linux-acpi/list/
 B:     https://bugzilla.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
 F:     drivers/acpi/pmic/
 
 ACPI THERMAL DRIVER
@@ -419,44 +436,44 @@ F:        drivers/platform/x86/wmi.c
 F:     include/uapi/linux/wmi.h
 
 AD1889 ALSA SOUND DRIVER
-W:     https://parisc.wiki.kernel.org/index.php/AD1889
 L:     linux-parisc@vger.kernel.org
 S:     Maintained
+W:     https://parisc.wiki.kernel.org/index.php/AD1889
 F:     sound/pci/ad1889.*
 
 AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER
 M:     Michael Hennerich <michael.hennerich@analog.com>
+S:     Supported
 W:     http://wiki.analog.com/AD5254
 W:     http://ez.analog.com/community/linux-device-drivers
-S:     Supported
 F:     drivers/misc/ad525x_dpot.c
 
 AD5398 CURRENT REGULATOR DRIVER (AD5398/AD5821)
 M:     Michael Hennerich <michael.hennerich@analog.com>
+S:     Supported
 W:     http://wiki.analog.com/AD5398
 W:     http://ez.analog.com/community/linux-device-drivers
-S:     Supported
 F:     drivers/regulator/ad5398.c
 
 AD714X CAPACITANCE TOUCH SENSOR DRIVER (AD7142/3/7/8/7A)
 M:     Michael Hennerich <michael.hennerich@analog.com>
+S:     Supported
 W:     http://wiki.analog.com/AD7142
 W:     http://ez.analog.com/community/linux-device-drivers
-S:     Supported
 F:     drivers/input/misc/ad714x.c
 
 AD7877 TOUCHSCREEN DRIVER
 M:     Michael Hennerich <michael.hennerich@analog.com>
+S:     Supported
 W:     http://wiki.analog.com/AD7877
 W:     http://ez.analog.com/community/linux-device-drivers
-S:     Supported
 F:     drivers/input/touchscreen/ad7877.c
 
 AD7879 TOUCHSCREEN DRIVER (AD7879/AD7889)
 M:     Michael Hennerich <michael.hennerich@analog.com>
+S:     Supported
 W:     http://wiki.analog.com/AD7879
 W:     http://ez.analog.com/community/linux-device-drivers
-S:     Supported
 F:     drivers/input/touchscreen/ad7879.c
 
 ADDRESS SPACE LAYOUT RANDOMIZATION (ASLR)
@@ -465,12 +482,12 @@ S:        Maintained
 
 ADF7242 IEEE 802.15.4 RADIO DRIVER
 M:     Michael Hennerich <michael.hennerich@analog.com>
-W:     https://wiki.analog.com/ADF7242
-W:     http://ez.analog.com/community/linux-device-drivers
 L:     linux-wpan@vger.kernel.org
 S:     Supported
-F:     drivers/net/ieee802154/adf7242.c
+W:     https://wiki.analog.com/ADF7242
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
+F:     drivers/net/ieee802154/adf7242.c
 
 ADM1025 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
@@ -487,8 +504,8 @@ F:  drivers/hwmon/adm1029.c
 
 ADM8211 WIRELESS DRIVER
 L:     linux-wireless@vger.kernel.org
-W:     http://wireless.kernel.org/
 S:     Orphan
+W:     http://wireless.kernel.org/
 F:     drivers/net/wireless/admtek/adm8211.*
 
 ADP1653 FLASH CONTROLLER DRIVER
@@ -500,28 +517,28 @@ F:        include/media/i2c/adp1653.h
 
 ADP5520 BACKLIGHT DRIVER WITH IO EXPANDER (ADP5520/ADP5501)
 M:     Michael Hennerich <michael.hennerich@analog.com>
+S:     Supported
 W:     http://wiki.analog.com/ADP5520
 W:     http://ez.analog.com/community/linux-device-drivers
-S:     Supported
-F:     drivers/mfd/adp5520.c
-F:     drivers/video/backlight/adp5520_bl.c
-F:     drivers/leds/leds-adp5520.c
 F:     drivers/gpio/gpio-adp5520.c
 F:     drivers/input/keyboard/adp5520-keys.c
+F:     drivers/leds/leds-adp5520.c
+F:     drivers/mfd/adp5520.c
+F:     drivers/video/backlight/adp5520_bl.c
 
 ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587)
 M:     Michael Hennerich <michael.hennerich@analog.com>
+S:     Supported
 W:     http://wiki.analog.com/ADP5588
 W:     http://ez.analog.com/community/linux-device-drivers
-S:     Supported
-F:     drivers/input/keyboard/adp5588-keys.c
 F:     drivers/gpio/gpio-adp5588.c
+F:     drivers/input/keyboard/adp5588-keys.c
 
 ADP8860 BACKLIGHT DRIVER (ADP8860/ADP8861/ADP8863)
 M:     Michael Hennerich <michael.hennerich@analog.com>
+S:     Supported
 W:     http://wiki.analog.com/ADP8860
 W:     http://ez.analog.com/community/linux-device-drivers
-S:     Supported
 F:     drivers/video/backlight/adp8860_bl.c
 
 ADT746X FAN DRIVER
@@ -546,39 +563,39 @@ F:        drivers/scsi/advansys.c
 
 ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346)
 M:     Michael Hennerich <michael.hennerich@analog.com>
+S:     Supported
 W:     http://wiki.analog.com/ADXL345
 W:     http://ez.analog.com/community/linux-device-drivers
-S:     Supported
-F:     drivers/input/misc/adxl34x.c
 F:     Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml
+F:     drivers/input/misc/adxl34x.c
 
 ADXL372 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
 M:     Stefan Popa <stefan.popa@analog.com>
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
+W:     http://ez.analog.com/community/linux-device-drivers
+F:     Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml
 F:     drivers/iio/accel/adxl372.c
-F:     drivers/iio/accel/adxl372_spi.c
 F:     drivers/iio/accel/adxl372_i2c.c
-F:     Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml
+F:     drivers/iio/accel/adxl372_spi.c
 
 AF9013 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/dvb-frontends/af9013*
 
 AF9033 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/dvb-frontends/af9033*
 
 AFFS FILE SYSTEM
@@ -592,15 +609,15 @@ AFS FILESYSTEM
 M:     David Howells <dhowells@redhat.com>
 L:     linux-afs@lists.infradead.org
 S:     Supported
+W:     https://www.infradead.org/~dhowells/kafs/
+F:     Documentation/filesystems/afs.rst
 F:     fs/afs/
 F:     include/trace/events/afs.h
-F:     Documentation/filesystems/afs.rst
-W:     https://www.infradead.org/~dhowells/kafs/
 
 AGPGART DRIVER
 M:     David Airlie <airlied@linux.ie>
-T:     git git://anongit.freedesktop.org/drm/drm
 S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm
 F:     drivers/char/agp/
 F:     include/linux/agp*
 F:     include/uapi/linux/agp*
@@ -621,9 +638,9 @@ F:  drivers/scsi/aic7xxx/
 AIMSLAB FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/radio-aimslab*
 
 AIO
@@ -636,11 +653,11 @@ F:        include/linux/*aio*.h
 AIRSPY MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/usb/airspy/
 
 ALACRITECH GIGABIT ETHERNET DRIVER
@@ -648,18 +665,11 @@ M:        Lino Sanfilippo <LinoSanfilippo@gmx.de>
 S:     Maintained
 F:     drivers/net/ethernet/alacritech/*
 
-FORCEDETH GIGABIT ETHERNET DRIVER
-M:     Rain River <rain.1986.08.12@gmail.com>
-M:     Zhu Yanjun <zyjzyj2000@gmail.com>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     drivers/net/ethernet/nvidia/*
-
 ALCATEL SPEEDTOUCH USB DRIVER
 M:     Duncan Sands <duncan.sands@free.fr>
 L:     linux-usb@vger.kernel.org
-W:     http://www.linux-usb.org/SpeedTouch/
 S:     Maintained
+W:     http://www.linux-usb.org/SpeedTouch/
 F:     drivers/usb/atm/speedtch.c
 F:     drivers/usb/atm/usbatm.c
 
@@ -677,11 +687,11 @@ F:        drivers/i2c/busses/i2c-ali1563.c
 
 ALL SENSORS DLH SERIES PRESSURE SENSORS DRIVER
 M:     Tomislav Denis <tomislav.denis@avl.com>
-W:     http://www.allsensors.com/
-S:     Maintained
 L:     linux-iio@vger.kernel.org
-F:     drivers/iio/pressure/dlhl60d.c
+S:     Maintained
+W:     http://www.allsensors.com/
 F:     Documentation/devicetree/bindings/iio/pressure/asc,dlhl60d.yaml
+F:     drivers/iio/pressure/dlhl60d.c
 
 ALLEGRO DVT VIDEO IP CORE DRIVER
 M:     Michael Tretter <m.tretter@pengutronix.de>
@@ -690,6 +700,14 @@ L: linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/staging/media/allegro-dvt/
 
+ALLWINNER A10 CSI DRIVER
+M:     Maxime Ripard <mripard@kernel.org>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
+F:     Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml
+F:     drivers/media/platform/sunxi/sun4i-csi/
+
 ALLWINNER CPUFREQ DRIVER
 M:     Yangtao Li <tiny.windzz@gmail.com>
 L:     linux-pm@vger.kernel.org
@@ -722,12 +740,12 @@ ALPHA PORT
 M:     Richard Henderson <rth@twiddle.net>
 M:     Ivan Kokshaysky <ink@jurassic.park.msu.ru>
 M:     Matt Turner <mattst88@gmail.com>
-S:     Odd Fixes
 L:     linux-alpha@vger.kernel.org
+S:     Odd Fixes
 F:     arch/alpha/
 
 ALPS PS/2 TOUCHPAD DRIVER
-R:     Pali Rohár <pali.rohar@gmail.com>
+R:     Pali Rohár <pali@kernel.org>
 F:     drivers/input/mouse/alps.*
 
 ALTERA I2C CONTROLLER DRIVER
@@ -738,7 +756,6 @@ F:  drivers/i2c/busses/i2c-altera.c
 
 ALTERA MAILBOX DRIVER
 M:     Ley Foon Tan <ley.foon.tan@intel.com>
-L:     nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
 S:     Maintained
 F:     drivers/mailbox/mailbox-altera.c
 
@@ -760,25 +777,29 @@ S:        Maintained
 F:     drivers/gpio/gpio-altera-a10sr.c
 F:     drivers/mfd/altera-a10sr.c
 F:     drivers/reset/reset-a10sr.c
-F:     include/linux/mfd/altera-a10sr.h
 F:     include/dt-bindings/reset/altr,rst-mgr-a10sr.h
+F:     include/linux/mfd/altera-a10sr.h
 
 ALTERA TRIPLE SPEED ETHERNET DRIVER
 M:     Thor Thayer <thor.thayer@linux.intel.com>
 L:     netdev@vger.kernel.org
-L:     nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
 S:     Maintained
 F:     drivers/net/ethernet/altera/
 
 ALTERA UART/JTAG UART SERIAL DRIVERS
 M:     Tobias Klauser <tklauser@distanz.ch>
 L:     linux-serial@vger.kernel.org
-L:     nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
 S:     Maintained
-F:     drivers/tty/serial/altera_uart.c
 F:     drivers/tty/serial/altera_jtaguart.c
-F:     include/linux/altera_uart.h
+F:     drivers/tty/serial/altera_uart.c
 F:     include/linux/altera_jtaguart.h
+F:     include/linux/altera_uart.h
+
+AMAZON ANNAPURNA LABS FIC DRIVER
+M:     Talel Shenhar <talel@amazon.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/interrupt-controller/amazon,al-fic.txt
+F:     drivers/irqchip/irq-al-fic.c
 
 AMAZON ANNAPURNA LABS THERMAL MMIO DRIVER
 M:     Talel Shenhar <talel@amazon.com>
@@ -801,8 +822,8 @@ AMAZON RDMA EFA DRIVER
 M:     Gal Pressman <galpress@amazon.com>
 R:     Yossi Leybovich <sleybo@amazon.com>
 L:     linux-rdma@vger.kernel.org
-Q:     https://patchwork.kernel.org/project/linux-rdma/list/
 S:     Supported
+Q:     https://patchwork.kernel.org/project/linux-rdma/list/
 F:     drivers/infiniband/hw/efa/
 F:     include/uapi/rdma/efa-abi.h
 
@@ -817,8 +838,8 @@ AMD DISPLAY CORE
 M:     Harry Wentland <harry.wentland@amd.com>
 M:     Leo Li <sunpeng.li@amd.com>
 L:     amd-gfx@lists.freedesktop.org
-T:     git git://people.freedesktop.org/~agd5f/linux
 S:     Supported
+T:     git git://people.freedesktop.org/~agd5f/linux
 F:     drivers/gpu/drm/amd/display/
 
 AMD FAM15H PROCESSOR POWER MONITORING DRIVER
@@ -843,32 +864,32 @@ F:        drivers/usb/gadget/udc/amd5536udc.*
 AMD GEODE PROCESSOR/CHIPSET SUPPORT
 M:     Andres Salomon <dilinger@queued.net>
 L:     linux-geode@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
 S:     Supported
+W:     http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
+F:     arch/x86/include/asm/geode.h
 F:     drivers/char/hw_random/geode-rng.c
 F:     drivers/crypto/geode*
 F:     drivers/video/fbdev/geode/
-F:     arch/x86/include/asm/geode.h
 
 AMD IOMMU (AMD-VI)
 M:     Joerg Roedel <joro@8bytes.org>
 L:     iommu@lists.linux-foundation.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
 F:     drivers/iommu/amd_iommu*.[ch]
 F:     include/linux/amd-iommu.h
 
 AMD KFD
 M:     Felix Kuehling <Felix.Kuehling@amd.com>
 L:     amd-gfx@lists.freedesktop.org
-T:     git git://people.freedesktop.org/~agd5f/linux
 S:     Supported
+T:     git git://people.freedesktop.org/~agd5f/linux
 F:     drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd*.[ch]
 F:     drivers/gpu/drm/amd/amdkfd/
 F:     drivers/gpu/drm/amd/include/cik_structs.h
 F:     drivers/gpu/drm/amd/include/kgd_kfd_interface.h
-F:     drivers/gpu/drm/amd/include/vi_structs.h
 F:     drivers/gpu/drm/amd/include/v9_structs.h
+F:     drivers/gpu/drm/amd/include/vi_structs.h
 F:     include/uapi/linux/kfd_ioctl.h
 
 AMD MP2 I2C DRIVER
@@ -883,8 +904,8 @@ AMD POWERPLAY
 M:     Evan Quan <evan.quan@amd.com>
 L:     amd-gfx@lists.freedesktop.org
 S:     Supported
-F:     drivers/gpu/drm/amd/powerplay/
 T:     git git://people.freedesktop.org/~agd5f/linux
+F:     drivers/gpu/drm/amd/powerplay/
 
 AMD SEATTLE DEVICE TREE SUPPORT
 M:     Brijesh Singh <brijeshkumar.singh@amd.com>
@@ -897,82 +918,82 @@ AMD XGBE DRIVER
 M:     Tom Lendacky <thomas.lendacky@amd.com>
 L:     netdev@vger.kernel.org
 S:     Supported
-F:     drivers/net/ethernet/amd/xgbe/
 F:     arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi
+F:     drivers/net/ethernet/amd/xgbe/
 
 ANALOG DEVICES INC AD5686 DRIVER
 M:     Stefan Popa <stefan.popa@analog.com>
 L:     linux-pm@vger.kernel.org
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     drivers/iio/dac/ad5686*
 F:     drivers/iio/dac/ad5696*
 
 ANALOG DEVICES INC AD5758 DRIVER
 M:     Stefan Popa <stefan.popa@analog.com>
 L:     linux-iio@vger.kernel.org
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
-F:     drivers/iio/dac/ad5758.c
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/iio/dac/ad5758.txt
+F:     drivers/iio/dac/ad5758.c
 
 ANALOG DEVICES INC AD7091R5 DRIVER
 M:     Beniamin Bia <beniamin.bia@analog.com>
 L:     linux-iio@vger.kernel.org
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
-F:     drivers/iio/adc/ad7091r5.c
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml
+F:     drivers/iio/adc/ad7091r5.c
 
 ANALOG DEVICES INC AD7124 DRIVER
 M:     Stefan Popa <stefan.popa@analog.com>
 L:     linux-iio@vger.kernel.org
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
-F:     drivers/iio/adc/ad7124.c
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml
+F:     drivers/iio/adc/ad7124.c
 
 ANALOG DEVICES INC AD7192 DRIVER
 M:     Alexandru Tachici <alexandru.tachici@analog.com>
 L:     linux-iio@vger.kernel.org
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
-F:     drivers/iio/adc/ad7192.c
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml
+F:     drivers/iio/adc/ad7192.c
 
 ANALOG DEVICES INC AD7292 DRIVER
 M:     Marcelo Schmitt <marcelo.schmitt1@gmail.com>
 L:     linux-iio@vger.kernel.org
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
-F:     drivers/iio/adc/ad7292.c
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml
+F:     drivers/iio/adc/ad7292.c
 
 ANALOG DEVICES INC AD7606 DRIVER
 M:     Stefan Popa <stefan.popa@analog.com>
 M:     Beniamin Bia <beniamin.bia@analog.com>
 L:     linux-iio@vger.kernel.org
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
-F:     drivers/iio/adc/ad7606.c
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
+F:     drivers/iio/adc/ad7606.c
 
 ANALOG DEVICES INC AD7768-1 DRIVER
 M:     Stefan Popa <stefan.popa@analog.com>
 L:     linux-iio@vger.kernel.org
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
-F:     drivers/iio/adc/ad7768-1.c
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.txt
+F:     drivers/iio/adc/ad7768-1.c
 
 ANALOG DEVICES INC AD7780 DRIVER
 M:     Michael Hennerich <Michael.Hennerich@analog.com>
 M:     Renato Lui Geh <renatogeh@gmail.com>
 L:     linux-iio@vger.kernel.org
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
-F:     drivers/iio/adc/ad7780.c
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml
+F:     drivers/iio/adc/ad7780.c
 
 ANALOG DEVICES INC AD9389B DRIVER
 M:     Hans Verkuil <hverkuil-cisco@xs4all.nl>
@@ -983,53 +1004,53 @@ F:       drivers/media/i2c/ad9389b*
 ANALOG DEVICES INC ADGS1408 DRIVER
 M:     Mircea Caprioru <mircea.caprioru@analog.com>
 S:     Supported
-F:     drivers/mux/adgs1408.c
 F:     Documentation/devicetree/bindings/mux/adi,adgs1408.txt
+F:     drivers/mux/adgs1408.c
 
 ANALOG DEVICES INC ADIN DRIVER
 M:     Alexandru Ardelean <alexaundru.ardelean@analog.com>
 L:     netdev@vger.kernel.org
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
-F:     drivers/net/phy/adin.c
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/net/adi,adin.yaml
+F:     drivers/net/phy/adin.c
 
 ANALOG DEVICES INC ADIS DRIVER LIBRARY
 M:     Alexandru Ardelean <alexandru.ardelean@analog.com>
-S:     Supported
 L:     linux-iio@vger.kernel.org
-F:     include/linux/iio/imu/adis.h
+S:     Supported
 F:     drivers/iio/imu/adis.c
+F:     include/linux/iio/imu/adis.h
 
 ANALOG DEVICES INC ADIS16460 DRIVER
 M:     Dragos Bogdan <dragos.bogdan@analog.com>
-S:     Supported
 L:     linux-iio@vger.kernel.org
+S:     Supported
 W:     http://ez.analog.com/community/linux-device-drivers
-F:     drivers/iio/imu/adis16460.c
 F:     Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml
+F:     drivers/iio/imu/adis16460.c
 
 ANALOG DEVICES INC ADM1177 DRIVER
 M:     Beniamin Bia <beniamin.bia@analog.com>
 M:     Michael Hennerich <Michael.Hennerich@analog.com>
 L:     linux-hwmon@vger.kernel.org
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
-F:     drivers/hwmon/adm1177.c
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml
+F:     drivers/hwmon/adm1177.c
 
 ANALOG DEVICES INC ADP5061 DRIVER
 M:     Stefan Popa <stefan.popa@analog.com>
 L:     linux-pm@vger.kernel.org
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     drivers/power/supply/adp5061.c
 
 ANALOG DEVICES INC ADV7180 DRIVER
 M:     Lars-Peter Clausen <lars@metafoo.de>
 L:     linux-media@vger.kernel.org
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     drivers/media/i2c/adv7180.c
 
 ANALOG DEVICES INC ADV748X DRIVER
@@ -1060,44 +1081,44 @@ ANALOG DEVICES INC ASOC CODEC DRIVERS
 M:     Lars-Peter Clausen <lars@metafoo.de>
 M:     Nuno Sá <nuno.sa@analog.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Supported
 W:     http://wiki.analog.com/
 W:     http://ez.analog.com/community/linux-device-drivers
-S:     Supported
-F:     sound/soc/codecs/adau*
-F:     sound/soc/codecs/adav*
 F:     sound/soc/codecs/ad1*
 F:     sound/soc/codecs/ad7*
-F:     sound/soc/codecs/ssm*
+F:     sound/soc/codecs/adau*
+F:     sound/soc/codecs/adav*
 F:     sound/soc/codecs/sigmadsp.*
+F:     sound/soc/codecs/ssm*
 
 ANALOG DEVICES INC DMA DRIVERS
 M:     Lars-Peter Clausen <lars@metafoo.de>
-W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     drivers/dma/dma-axi-dmac.c
 
+ANALOG DEVICES INC HMC425A DRIVER
+M:     Beniamin Bia <beniamin.bia@analog.com>
+M:     Michael Hennerich <michael.hennerich@analog.com>
+L:     linux-iio@vger.kernel.org
+S:     Supported
+W:     http://ez.analog.com/community/linux-device-drivers
+F:     Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml
+F:     drivers/iio/amplifiers/hmc425a.c
+
 ANALOG DEVICES INC IIO DRIVERS
 M:     Lars-Peter Clausen <lars@metafoo.de>
 M:     Michael Hennerich <Michael.Hennerich@analog.com>
 M:     Stefan Popa <stefan.popa@analog.com>
+S:     Supported
 W:     http://wiki.analog.com/
 W:     http://ez.analog.com/community/linux-device-drivers
-S:     Supported
 F:     Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523
 F:     Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
 F:     drivers/iio/*/ad*
 F:     drivers/iio/adc/ltc249*
-X:     drivers/iio/*/adjd*
 F:     drivers/staging/iio/*/ad*
-
-ANALOG DEVICES INC HMC425A DRIVER
-M:     Beniamin Bia <beniamin.bia@analog.com>
-M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     linux-iio@vger.kernel.org
-S:     Supported
-W:     http://ez.analog.com/community/linux-device-drivers
-F:     Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml
-F:     drivers/iio/amplifiers/hmc425a.c
+X:     drivers/iio/*/adjd*
 
 ANALOGBITS PLL LIBRARIES
 M:     Paul Walmsley <paul.walmsley@sifive.com>
@@ -1109,13 +1130,13 @@ ANDES ARCHITECTURE
 M:     Nick Hu <nickhu@andestech.com>
 M:     Greentime Hu <green.hu@gmail.com>
 M:     Vincent Chen <deanbo422@gmail.com>
-T:     git https://git.kernel.org/pub/scm/linux/kernel/git/greentime/linux.git
 S:     Supported
-F:     arch/nds32/
+T:     git https://git.kernel.org/pub/scm/linux/kernel/git/greentime/linux.git
 F:     Documentation/devicetree/bindings/interrupt-controller/andestech,ativic32.txt
 F:     Documentation/devicetree/bindings/nds32/
-K:     nds32
+F:     arch/nds32/
 N:     nds32
+K:     nds32
 
 ANDROID CONFIG FRAGMENTS
 M:     Rob Herring <robh@kernel.org>
@@ -1129,9 +1150,9 @@ M:        Todd Kjos <tkjos@android.com>
 M:     Martijn Coenen <maco@android.com>
 M:     Joel Fernandes <joel@joelfernandes.org>
 M:     Christian Brauner <christian@brauner.io>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
 L:     devel@driverdev.osuosl.org
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
 F:     drivers/android/
 F:     drivers/staging/android/
 
@@ -1175,18 +1196,18 @@ M:      Jiri Kosina <jikos@kernel.org>
 S:     Odd fixes
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/apm.git
 F:     arch/x86/kernel/apm_32.c
+F:     drivers/char/apm-emulation.c
 F:     include/linux/apm_bios.h
 F:     include/uapi/linux/apm_bios.h
-F:     drivers/char/apm-emulation.c
 
 APPARMOR SECURITY MODULE
 M:     John Johansen <john.johansen@canonical.com>
 L:     apparmor@lists.ubuntu.com (subscribers-only, general discussion)
+S:     Supported
 W:     wiki.apparmor.net
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
-S:     Supported
-F:     security/apparmor/
 F:     Documentation/admin-guide/LSM/apparmor.rst
+F:     security/apparmor/
 
 APPLE BCM5974 MULTITOUCH DRIVER
 M:     Henrik Rydberg <rydberg@bitmath.org>
@@ -1204,9 +1225,9 @@ APPLETALK NETWORK LAYER
 L:     netdev@vger.kernel.org
 S:     Odd fixes
 F:     drivers/net/appletalk/
-F:     net/appletalk/
 F:     include/linux/atalk.h
 F:     include/uapi/linux/atalk.h
+F:     net/appletalk/
 
 APPLIED MICRO (APM) X-GENE DEVICE TREE SUPPORT
 M:     Khuong Dinh <khuong@os.amperecomputing.com>
@@ -1216,8 +1237,8 @@ F:        arch/arm64/boot/dts/apm/
 APPLIED MICRO (APM) X-GENE SOC EDAC
 M:     Khuong Dinh <khuong@os.amperecomputing.com>
 S:     Supported
-F:     drivers/edac/xgene_edac.c
 F:     Documentation/devicetree/bindings/edac/apm-xgene-edac.txt
+F:     drivers/edac/xgene_edac.c
 
 APPLIED MICRO (APM) X-GENE SOC ETHERNET (V2) DRIVER
 M:     Iyappan Subramanian <iyappan@os.amperecomputing.com>
@@ -1230,17 +1251,17 @@ M:      Iyappan Subramanian <iyappan@os.amperecomputing.com>
 M:     Keyur Chudgar <keyur@os.amperecomputing.com>
 M:     Quan Nguyen <quan@os.amperecomputing.com>
 S:     Supported
-F:     drivers/net/ethernet/apm/xgene/
-F:     drivers/net/phy/mdio-xgene.c
 F:     Documentation/devicetree/bindings/net/apm-xgene-enet.txt
 F:     Documentation/devicetree/bindings/net/apm-xgene-mdio.txt
+F:     drivers/net/ethernet/apm/xgene/
+F:     drivers/net/phy/mdio-xgene.c
 
 APPLIED MICRO (APM) X-GENE SOC PMU
 M:     Khuong Dinh <khuong@os.amperecomputing.com>
 S:     Supported
-F:     drivers/perf/xgene_pmu.c
 F:     Documentation/admin-guide/perf/xgene-pmu.rst
 F:     Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt
+F:     drivers/perf/xgene_pmu.c
 
 APTINA CAMERA SENSOR PLL
 M:     Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
@@ -1254,8 +1275,8 @@ L:        netdev@vger.kernel.org
 S:     Supported
 W:     https://www.marvell.com/
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
-F:     drivers/net/ethernet/aquantia/atlantic/
 F:     Documentation/networking/device_drivers/aquantia/atlantic.txt
+F:     drivers/net/ethernet/aquantia/atlantic/
 
 AQUANTIA ETHERNET DRIVER PTP SUBSYSTEM
 M:     Egor Pomozov <epomozov@marvell.com>
@@ -1273,8 +1294,8 @@ F:        drivers/video/fbdev/core/fb_defio.c
 ARC PGU DRM DRIVER
 M:     Alexey Brodkin <abrodkin@synopsys.com>
 S:     Supported
-F:     drivers/gpu/drm/arc/
 F:     Documentation/devicetree/bindings/display/snps,arcpgu.txt
+F:     drivers/gpu/drm/arc/
 
 ARCNET NETWORK LAYER
 M:     Michael Grzeschik <m.grzeschik@pengutronix.de>
@@ -1292,6 +1313,12 @@ F:       arch/arm/include/asm/arch_timer.h
 F:     arch/arm64/include/asm/arch_timer.h
 F:     drivers/clocksource/arm_arch_timer.c
 
+ARM HDLCD DRM DRIVER
+M:     Liviu Dudau <liviu.dudau@arm.com>
+S:     Supported
+F:     Documentation/devicetree/bindings/display/arm,hdlcd.txt
+F:     drivers/gpu/drm/arm/hdlcd_*
+
 ARM INTEGRATOR, VERSATILE AND REALVIEW SUPPORT
 M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1302,13 +1329,13 @@ F:      Documentation/devicetree/bindings/clock/arm,syscon-icst.yaml
 F:     Documentation/devicetree/bindings/i2c/i2c-versatile.txt
 F:     Documentation/devicetree/bindings/interrupt-controller/arm,versatile-fpga-irq.txt
 F:     Documentation/devicetree/bindings/mtd/arm-versatile.txt
+F:     arch/arm/boot/dts/arm-realview-*
+F:     arch/arm/boot/dts/integrator*
+F:     arch/arm/boot/dts/versatile*
 F:     arch/arm/mach-integrator/
 F:     arch/arm/mach-realview/
 F:     arch/arm/mach-versatile/
 F:     arch/arm/plat-versatile/
-F:     arch/arm/boot/dts/arm-realview-*
-F:     arch/arm/boot/dts/integrator*
-F:     arch/arm/boot/dts/versatile*
 F:     drivers/clk/versatile/
 F:     drivers/i2c/busses/i2c-versatile.c
 F:     drivers/irqchip/irq-versatile-fpga.c
@@ -1316,12 +1343,6 @@ F:       drivers/mtd/maps/physmap_of_versatile.c
 F:     drivers/power/reset/arm-versatile-reboot.c
 F:     drivers/soc/versatile/
 
-ARM HDLCD DRM DRIVER
-M:     Liviu Dudau <liviu.dudau@arm.com>
-S:     Supported
-F:     drivers/gpu/drm/arm/hdlcd_*
-F:     Documentation/devicetree/bindings/display/arm,hdlcd.txt
-
 ARM KOMEDA DRM-KMS DRIVER
 M:     James (Qian) Wang <james.qian.wang@arm.com>
 M:     Liviu Dudau <liviu.dudau@arm.com>
@@ -1329,20 +1350,10 @@ M:      Mihail Atanassov <mihail.atanassov@arm.com>
 L:     Mali DP Maintainers <malidp@foss.arm.com>
 S:     Supported
 T:     git git://anongit.freedesktop.org/drm/drm-misc
-F:     drivers/gpu/drm/arm/display/include/
-F:     drivers/gpu/drm/arm/display/komeda/
 F:     Documentation/devicetree/bindings/display/arm,komeda.txt
 F:     Documentation/gpu/komeda-kms.rst
-
-ARM MALI-DP DRM DRIVER
-M:     Liviu Dudau <liviu.dudau@arm.com>
-M:     Brian Starkey <brian.starkey@arm.com>
-L:     Mali DP Maintainers <malidp@foss.arm.com>
-S:     Supported
-T:     git git://anongit.freedesktop.org/drm/drm-misc
-F:     drivers/gpu/drm/arm/
-F:     Documentation/devicetree/bindings/display/arm,malidp.txt
-F:     Documentation/gpu/afbc.rst
+F:     drivers/gpu/drm/arm/display/include/
+F:     drivers/gpu/drm/arm/display/komeda/
 
 ARM MALI PANFROST DRM DRIVER
 M:     Rob Herring <robh@kernel.org>
@@ -1355,32 +1366,42 @@ T:      git git://anongit.freedesktop.org/drm/drm-misc
 F:     drivers/gpu/drm/panfrost/
 F:     include/uapi/drm/panfrost_drm.h
 
+ARM MALI-DP DRM DRIVER
+M:     Liviu Dudau <liviu.dudau@arm.com>
+M:     Brian Starkey <brian.starkey@arm.com>
+L:     Mali DP Maintainers <malidp@foss.arm.com>
+S:     Supported
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/devicetree/bindings/display/arm,malidp.txt
+F:     Documentation/gpu/afbc.rst
+F:     drivers/gpu/drm/arm/
+
 ARM MFM AND FLOPPY DRIVERS
 M:     Ian Molton <spyro@f2s.com>
 S:     Maintained
-F:     arch/arm/mach-rpc/floppydma.S
 F:     arch/arm/include/asm/floppy.h
+F:     arch/arm/mach-rpc/floppydma.S
 
 ARM PMU PROFILING AND DEBUGGING
 M:     Will Deacon <will@kernel.org>
 M:     Mark Rutland <mark.rutland@arm.com>
-S:     Maintained
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-F:     arch/arm*/kernel/perf_*
-F:     arch/arm/oprofile/common.c
-F:     arch/arm*/kernel/hw_breakpoint.c
+S:     Maintained
+F:     Documentation/devicetree/bindings/arm/pmu.yaml
+F:     Documentation/devicetree/bindings/perf/
 F:     arch/arm*/include/asm/hw_breakpoint.h
 F:     arch/arm*/include/asm/perf_event.h
+F:     arch/arm*/kernel/hw_breakpoint.c
+F:     arch/arm*/kernel/perf_*
+F:     arch/arm/oprofile/common.c
 F:     drivers/perf/*
 F:     include/linux/perf/arm_pmu.h
-F:     Documentation/devicetree/bindings/arm/pmu.yaml
-F:     Documentation/devicetree/bindings/perf/
 
 ARM PORT
 M:     Russell King <linux@armlinux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.armlinux.org.uk/
 S:     Odd Fixes
+W:     http://www.armlinux.org.uk/
 T:     git git://git.armlinux.org.uk/~rmk/linux-arm.git
 F:     arch/arm/
 X:     arch/arm/boot/dts/
@@ -1433,36 +1454,38 @@ S:      Maintained
 F:     Documentation/devicetree/bindings/interrupt-controller/arm,vic.txt
 F:     drivers/irqchip/irq-vic.c
 
-AMAZON ANNAPURNA LABS FIC DRIVER
-M:     Talel Shenhar <talel@amazon.com>
-S:     Maintained
-F:     Documentation/devicetree/bindings/interrupt-controller/amazon,al-fic.txt
-F:     drivers/irqchip/irq-al-fic.c
-
 ARM SMMU DRIVERS
 M:     Will Deacon <will@kernel.org>
 R:     Robin Murphy <robin.murphy@arm.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
+F:     Documentation/devicetree/bindings/iommu/arm,smmu*
 F:     drivers/iommu/arm-smmu*
-F:     drivers/iommu/io-pgtable-arm.c
 F:     drivers/iommu/io-pgtable-arm-v7s.c
+F:     drivers/iommu/io-pgtable-arm.c
 
 ARM SUB-ARCHITECTURES
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
 F:     arch/arm/mach-*/
 F:     arch/arm/plat-*/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
 
 ARM/ACTIONS SEMI ARCHITECTURE
 M:     Andreas Färber <afaerber@suse.de>
 M:     Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-N:     owl
-F:     arch/arm/mach-actions/
+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/mmc/owl-mmc.yaml
+F:     Documentation/devicetree/bindings/pinctrl/actions,s900-pinctrl.txt
+F:     Documentation/devicetree/bindings/power/actions,owl-sps.txt
+F:     Documentation/devicetree/bindings/timer/actions,owl-timer.txt
 F:     arch/arm/boot/dts/owl-*
+F:     arch/arm/mach-actions/
 F:     arch/arm64/boot/dts/actions/
 F:     drivers/clk/actions/
 F:     drivers/clocksource/timer-owl*
@@ -1473,14 +1496,7 @@ F:       drivers/pinctrl/actions/*
 F:     drivers/soc/actions/
 F:     include/dt-bindings/power/owl-*
 F:     include/linux/soc/actions/
-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/mmc/owl-mmc.yaml
-F:     Documentation/devicetree/bindings/pinctrl/actions,s900-pinctrl.txt
-F:     Documentation/devicetree/bindings/power/actions,owl-sps.txt
-F:     Documentation/devicetree/bindings/timer/actions,owl-timer.txt
+N:     owl
 
 ARM/ADS SPHERE MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
@@ -1507,85 +1523,77 @@ M:      Maxime Ripard <mripard@kernel.org>
 M:     Chen-Yu Tsai <wens@csie.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-N:     sun[x456789]i
-N:     sun50i
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git
 F:     arch/arm/mach-sunxi/
 F:     arch/arm64/boot/dts/allwinner/
 F:     drivers/clk/sunxi-ng/
 F:     drivers/pinctrl/sunxi/
 F:     drivers/soc/sunxi/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git
-
-Allwinner A10 CSI driver
-M:     Maxime Ripard <mripard@kernel.org>
-L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-F:     drivers/media/platform/sunxi/sun4i-csi/
-F:     Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml
-S:     Maintained
+N:     sun[x456789]i
+N:     sun50i
 
 ARM/Amlogic Meson SoC CLOCK FRAMEWORK
 M:     Neil Armstrong <narmstrong@baylibre.com>
 M:     Jerome Brunet <jbrunet@baylibre.com>
 L:     linux-amlogic@lists.infradead.org
 S:     Maintained
+F:     Documentation/devicetree/bindings/clock/amlogic*
 F:     drivers/clk/meson/
-F:     include/dt-bindings/clock/meson*
 F:     include/dt-bindings/clock/gxbb*
-F:     Documentation/devicetree/bindings/clock/amlogic*
-
-ARM/Amlogic Meson SoC support
-M:     Kevin Hilman <khilman@baylibre.com>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-L:     linux-amlogic@lists.infradead.org
-W:     http://linux-meson.com/
-S:     Maintained
-F:     arch/arm/mach-meson/
-F:     arch/arm/boot/dts/meson*
-F:     arch/arm64/boot/dts/amlogic/
-F:     drivers/pinctrl/meson/
-F:     drivers/mmc/host/meson*
-F:     drivers/soc/amlogic/
-F:     drivers/rtc/rtc-meson*
-N:     meson
+F:     include/dt-bindings/clock/meson*
 
 ARM/Amlogic Meson SoC Crypto Drivers
 M:     Corentin Labbe <clabbe@baylibre.com>
 L:     linux-crypto@vger.kernel.org
 L:     linux-amlogic@lists.infradead.org
 S:     Maintained
-F:     drivers/crypto/amlogic/
 F:     Documentation/devicetree/bindings/crypto/amlogic*
+F:     drivers/crypto/amlogic/
 
 ARM/Amlogic Meson SoC Sound Drivers
 M:     Jerome Brunet <jbrunet@baylibre.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Maintained
-F:     sound/soc/meson/
 F:     Documentation/devicetree/bindings/sound/amlogic*
+F:     sound/soc/meson/
+
+ARM/Amlogic Meson SoC support
+M:     Kevin Hilman <khilman@baylibre.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L:     linux-amlogic@lists.infradead.org
+S:     Maintained
+W:     http://linux-meson.com/
+F:     arch/arm/boot/dts/meson*
+F:     arch/arm/mach-meson/
+F:     arch/arm64/boot/dts/amlogic/
+F:     drivers/mmc/host/meson*
+F:     drivers/pinctrl/meson/
+F:     drivers/rtc/rtc-meson*
+F:     drivers/soc/amlogic/
+N:     meson
 
 ARM/Annapurna Labs ALPINE ARCHITECTURE
 M:     Tsahee Zidenberg <tsahee@annapurnalabs.com>
 M:     Antoine Tenart <antoine.tenart@bootlin.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm/mach-alpine/
 F:     arch/arm/boot/dts/alpine*
+F:     arch/arm/mach-alpine/
 F:     arch/arm64/boot/dts/al/
 F:     drivers/*/*alpine*
 
 ARM/ARTPEC MACHINE SUPPORT
 M:     Jesper Nilsson <jesper.nilsson@axis.com>
 M:     Lars Persson <lars.persson@axis.com>
-S:     Maintained
 L:     linux-arm-kernel@axis.com
-F:     arch/arm/mach-artpec
+S:     Maintained
+F:     Documentation/devicetree/bindings/pinctrl/axis,artpec6-pinctrl.txt
 F:     arch/arm/boot/dts/artpec6*
+F:     arch/arm/mach-artpec
 F:     drivers/clk/axis
 F:     drivers/crypto/axis
 F:     drivers/mmc/host/usdhi6rol0.c
 F:     drivers/pinctrl/pinctrl-artpec*
-F:     Documentation/devicetree/bindings/pinctrl/axis,artpec6-pinctrl.txt
 
 ARM/ASPEED I2C DRIVER
 M:     Brendan Higgins <brendanhiggins@google.com>
@@ -1594,41 +1602,41 @@ R:      Joel Stanley <joel@jms.id.au>
 L:     linux-i2c@vger.kernel.org
 L:     openbmc@lists.ozlabs.org (moderated for non-subscribers)
 S:     Maintained
-F:     drivers/irqchip/irq-aspeed-i2c-ic.c
-F:     drivers/i2c/busses/i2c-aspeed.c
-F:     Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2400-i2c-ic.txt
 F:     Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
+F:     Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2400-i2c-ic.txt
+F:     drivers/i2c/busses/i2c-aspeed.c
+F:     drivers/irqchip/irq-aspeed-i2c-ic.c
 
 ARM/ASPEED MACHINE SUPPORT
 M:     Joel Stanley <joel@jms.id.au>
 R:     Andrew Jeffery <andrew@aj.id.au>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
-Q:     https://patchwork.ozlabs.org/project/linux-aspeed/list/
 S:     Supported
+Q:     https://patchwork.ozlabs.org/project/linux-aspeed/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joel/aspeed.git
-F:     arch/arm/mach-aspeed/
 F:     arch/arm/boot/dts/aspeed-*
+F:     arch/arm/mach-aspeed/
 N:     aspeed
 
 ARM/BITMAIN ARCHITECTURE
 M:     Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm64/boot/dts/bitmain/
-F:     drivers/clk/clk-bm1880.c
-F:     drivers/pinctrl/pinctrl-bm1880.c
 F:     Documentation/devicetree/bindings/arm/bitmain.yaml
 F:     Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.yaml
 F:     Documentation/devicetree/bindings/pinctrl/bitmain,bm1880-pinctrl.txt
+F:     arch/arm64/boot/dts/bitmain/
+F:     drivers/clk/clk-bm1880.c
+F:     drivers/pinctrl/pinctrl-bm1880.c
 
 ARM/CALXEDA HIGHBANK ARCHITECTURE
 M:     Andre Przywara <andre.przywara@arm.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm/mach-highbank/
-F:     arch/arm/boot/dts/highbank.dts
 F:     arch/arm/boot/dts/ecx-*.dts*
+F:     arch/arm/boot/dts/highbank.dts
+F:     arch/arm/mach-highbank/
 
 ARM/CAVIUM NETWORKS CNS3XXX MACHINE SUPPORT
 M:     Krzysztof Halasa <khalasa@piap.pl>
@@ -1697,19 +1705,19 @@ R:      Suzuki K Poulose <suzuki.poulose@arm.com>
 R:     Mike Leach <mike.leach@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     drivers/hwtracing/coresight/*
-F:     include/dt-bindings/arm/coresight-cti-dt.h
-F:     Documentation/trace/coresight/*
-F:     Documentation/devicetree/bindings/arm/coresight.txt
+F:     Documentation/ABI/testing/sysfs-bus-coresight-devices-*
 F:     Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt
 F:     Documentation/devicetree/bindings/arm/coresight-cti.yaml
-F:     Documentation/ABI/testing/sysfs-bus-coresight-devices-*
-F:     tools/perf/arch/arm/util/pmu.c
+F:     Documentation/devicetree/bindings/arm/coresight.txt
+F:     Documentation/trace/coresight/*
+F:     drivers/hwtracing/coresight/*
+F:     include/dt-bindings/arm/coresight-cti-dt.h
 F:     tools/perf/arch/arm/util/auxtrace.c
 F:     tools/perf/arch/arm/util/cs-etm.c
 F:     tools/perf/arch/arm/util/cs-etm.h
-F:     tools/perf/util/cs-etm.*
+F:     tools/perf/arch/arm/util/pmu.c
 F:     tools/perf/util/cs-etm-decoder/*
+F:     tools/perf/util/cs-etm.*
 
 ARM/CORGI MACHINE SUPPORT
 M:     Richard Purdie <rpurdie@rpsys.net>
@@ -1719,11 +1727,11 @@ ARM/CORTINA SYSTEMS GEMINI ARM ARCHITECTURE
 M:     Hans Ulli Kroll <ulli.kroll@googlemail.com>
 M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://github.com/ulli-kroll/linux.git
 S:     Maintained
+T:     git git://github.com/ulli-kroll/linux.git
 F:     Documentation/devicetree/bindings/arm/gemini.txt
-F:     Documentation/devicetree/bindings/pinctrl/cortina,gemini-pinctrl.txt
 F:     Documentation/devicetree/bindings/net/cortina,gemini-ethernet.txt
+F:     Documentation/devicetree/bindings/pinctrl/cortina,gemini-pinctrl.txt
 F:     Documentation/devicetree/bindings/rtc/faraday,ftrtc010.txt
 F:     arch/arm/mach-gemini/
 F:     drivers/net/ethernet/cortina/
@@ -1733,36 +1741,36 @@ F:      drivers/rtc/rtc-ftrtc010.c
 ARM/CSR SIRFPRIMA2 MACHINE SUPPORT
 M:     Barry Song <baohua@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/baohua/linux.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/baohua/linux.git
 F:     arch/arm/boot/dts/prima2*
 F:     arch/arm/mach-prima2/
 F:     drivers/clk/sirf/
-F:     drivers/clocksource/timer-prima2.c
 F:     drivers/clocksource/timer-atlas7.c
-N:     [^a-z]sirf
+F:     drivers/clocksource/timer-prima2.c
 X:     drivers/gnss
+N:     [^a-z]sirf
 
 ARM/CZ.NIC TURRIS MOX SUPPORT
 M:     Marek Behun <marek.behun@nic.cz>
-W:     http://mox.turris.cz
 S:     Maintained
+W:     http://mox.turris.cz
 F:     Documentation/ABI/testing/debugfs-moxtet
 F:     Documentation/ABI/testing/sysfs-bus-moxtet-devices
 F:     Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm
 F:     Documentation/devicetree/bindings/bus/moxtet.txt
 F:     Documentation/devicetree/bindings/firmware/cznic,turris-mox-rwtm.txt
 F:     Documentation/devicetree/bindings/gpio/gpio-moxtet.txt
-F:     include/linux/moxtet.h
 F:     drivers/bus/moxtet.c
 F:     drivers/firmware/turris-mox-rwtm.c
 F:     drivers/gpio/gpio-moxtet.c
+F:     include/linux/moxtet.h
 
 ARM/EBSA110 MACHINE SUPPORT
 M:     Russell King <linux@armlinux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.armlinux.org.uk/
 S:     Maintained
+W:     http://www.armlinux.org.uk/
 F:     arch/arm/mach-ebsa110/
 F:     drivers/net/ethernet/amd/am79c961a.*
 
@@ -1789,8 +1797,8 @@ F:        arch/arm/mm/*-fa*
 ARM/FOOTBRIDGE ARCHITECTURE
 M:     Russell King <linux@armlinux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.armlinux.org.uk/
 S:     Maintained
+W:     http://www.armlinux.org.uk/
 F:     arch/arm/include/asm/hardware/dec21285.h
 F:     arch/arm/mach-footbridge/
 
@@ -1803,20 +1811,9 @@ R:       NXP Linux Team <linux-imx@nxp.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git
+X:     drivers/media/i2c/
 N:     imx
 N:     mxs
-X:     drivers/media/i2c/
-
-ARM/FREESCALE VYBRID ARM ARCHITECTURE
-M:     Shawn Guo <shawnguo@kernel.org>
-M:     Sascha Hauer <s.hauer@pengutronix.de>
-R:     Pengutronix Kernel Team <kernel@pengutronix.de>
-R:     Stefan Agner <stefan@agner.ch>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git
-F:     arch/arm/mach-imx/*vf610*
-F:     arch/arm/boot/dts/vf*
 
 ARM/FREESCALE LAYERSCAPE ARM ARCHITECTURE
 M:     Shawn Guo <shawnguo@kernel.org>
@@ -1828,6 +1825,17 @@ F:       arch/arm/boot/dts/ls1021a*
 F:     arch/arm64/boot/dts/freescale/fsl-*
 F:     arch/arm64/boot/dts/freescale/qoriq-*
 
+ARM/FREESCALE VYBRID ARM ARCHITECTURE
+M:     Shawn Guo <shawnguo@kernel.org>
+M:     Sascha Hauer <s.hauer@pengutronix.de>
+R:     Pengutronix Kernel Team <kernel@pengutronix.de>
+R:     Stefan Agner <stefan@agner.ch>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git
+F:     arch/arm/boot/dts/vf*
+F:     arch/arm/mach-imx/*vf610*
+
 ARM/GLOMATION GESBC9312SX MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1850,22 +1858,22 @@ F:      sound/soc/pxa/hx4700.c
 ARM/HISILICON SOC SUPPORT
 M:     Wei Xu <xuwei5@hisilicon.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.hisilicon.com
 S:     Supported
+W:     http://www.hisilicon.com
 T:     git git://github.com/hisilicon/linux-hisi.git
-F:     arch/arm/mach-hisi/
 F:     arch/arm/boot/dts/hi3*
 F:     arch/arm/boot/dts/hip*
 F:     arch/arm/boot/dts/hisi*
+F:     arch/arm/mach-hisi/
 F:     arch/arm64/boot/dts/hisilicon/
 
 ARM/HP JORNADA 7XX MACHINE SUPPORT
 M:     Kristoffer Ericson <kristoffer.ericson@gmail.com>
-W:     www.jlime.com
 S:     Maintained
+W:     www.jlime.com
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kristoffer/linux-hpc.git
-F:     arch/arm/mach-sa1100/jornada720.c
 F:     arch/arm/mach-sa1100/include/mach/jornada720.h
+F:     arch/arm/mach-sa1100/jornada720.c
 
 ARM/IGEP MACHINE SUPPORT
 M:     Enric Balletbo i Serra <eballetbo@gmail.com>
@@ -1957,8 +1965,8 @@ ARM/LPC32XX SOC SUPPORT
 M:     Vladimir Zapolskiy <vz@mleia.com>
 M:     Sylvain Lemieux <slemieux.tyco@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://github.com/vzapolskiy/linux-lpc32xx.git
 S:     Maintained
+T:     git git://github.com/vzapolskiy/linux-lpc32xx.git
 F:     Documentation/devicetree/bindings/i2c/i2c-pnx.txt
 F:     arch/arm/boot/dts/lpc32*
 F:     arch/arm/mach-lpc32xx/
@@ -1979,14 +1987,14 @@ M:      Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 M:     Gregory Clement <gregory.clement@bootlin.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
+T:     git git://git.infradead.org/linux-mvebu.git
 F:     Documentation/devicetree/bindings/soc/dove/
+F:     arch/arm/boot/dts/dove*
+F:     arch/arm/boot/dts/orion5x*
 F:     arch/arm/mach-dove/
 F:     arch/arm/mach-mv78xx0/
 F:     arch/arm/mach-orion5x/
 F:     arch/arm/plat-orion/
-F:     arch/arm/boot/dts/dove*
-F:     arch/arm/boot/dts/orion5x*
-T:     git git://git.infradead.org/linux-mvebu.git
 
 ARM/Marvell Kirkwood and Armada 370, 375, 38x, 39x, XP, 3700, 7K/8K, CN9130 SOC support
 M:     Jason Cooper <jason@lakedaemon.net>
@@ -1995,6 +2003,7 @@ M:        Gregory Clement <gregory.clement@bootlin.com>
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
+T:     git git://git.infradead.org/linux-mvebu.git
 F:     arch/arm/boot/dts/armada*
 F:     arch/arm/boot/dts/kirkwood*
 F:     arch/arm/configs/mvebu_*_defconfig
@@ -2008,7 +2017,6 @@ F:        drivers/irqchip/irq-armada-370-xp.c
 F:     drivers/irqchip/irq-mvebu-*
 F:     drivers/pinctrl/mvebu/
 F:     drivers/rtc/rtc-armada38x.c
-T:     git git://git.infradead.org/linux-mvebu.git
 
 ARM/Mediatek RTC DRIVER
 M:     Eddie Huang <eddie.huang@mediatek.com>
@@ -2026,9 +2034,9 @@ ARM/Mediatek SoC support
 M:     Matthias Brugger <matthias.bgg@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-mediatek@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
 W:     https://mtk.bcnfs.org/
 C:     irc://chat.freenode.net/linux-mediatek
-S:     Maintained
 F:     arch/arm/boot/dts/mt6*
 F:     arch/arm/boot/dts/mt7*
 F:     arch/arm/boot/dts/mt8*
@@ -2044,36 +2052,36 @@ M:      Chunfeng Yun <chunfeng.yun@mediatek.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-mediatek@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     drivers/phy/mediatek/
 F:     Documentation/devicetree/bindings/phy/phy-mtk-*
+F:     drivers/phy/mediatek/
 
 ARM/Microchip (AT91) SoC support
 M:     Nicolas Ferre <nicolas.ferre@microchip.com>
 M:     Alexandre Belloni <alexandre.belloni@bootlin.com>
 M:     Ludovic Desroches <ludovic.desroches@microchip.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Supported
 W:     http://www.linux4sam.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/at91/linux.git
-S:     Supported
-N:     at91
-N:     atmel
-F:     arch/arm/mach-at91/
-F:     include/soc/at91/
 F:     arch/arm/boot/dts/at91*.dts
 F:     arch/arm/boot/dts/at91*.dtsi
 F:     arch/arm/boot/dts/sama*.dts
 F:     arch/arm/boot/dts/sama*.dtsi
 F:     arch/arm/include/debug/at91.S
+F:     arch/arm/mach-at91/
 F:     drivers/memory/atmel*
 F:     drivers/watchdog/sama5d4_wdt.c
+F:     include/soc/at91/
 X:     drivers/input/touchscreen/atmel_mxt_ts.c
 X:     drivers/net/wireless/atmel/
+N:     at91
+N:     atmel
 
 ARM/MIOA701 MACHINE SUPPORT
 M:     Robert Jarzmik <robert.jarzmik@free.fr>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-F:     arch/arm/mach-pxa/mioa701.c
 S:     Maintained
+F:     arch/arm/mach-pxa/mioa701.c
 
 ARM/NEC MOBILEPRO 900/c MACHINE SUPPORT
 M:     Michael Petchkovsky <mkpetch@internode.on.net>
@@ -2083,13 +2091,16 @@ ARM/NOMADIK/U300/Ux500 ARCHITECTURES
 M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git
+F:     Documentation/devicetree/bindings/arm/ste-*
+F:     Documentation/devicetree/bindings/arm/ux500.yaml
+F:     Documentation/devicetree/bindings/arm/ux500/
 F:     Documentation/devicetree/bindings/i2c/i2c-nomadik.txt
 F:     Documentation/devicetree/bindings/i2c/i2c-stu300.txt
+F:     arch/arm/boot/dts/ste-*
 F:     arch/arm/mach-nomadik/
 F:     arch/arm/mach-u300/
 F:     arch/arm/mach-ux500/
-F:     drivers/soc/ux500/
-F:     arch/arm/boot/dts/ste-*
 F:     drivers/clk/clk-nomadik.c
 F:     drivers/clk/clk-u300.c
 F:     drivers/clocksource/clksrc-dbx500-prcmu.c
@@ -2103,8 +2114,8 @@ F:        drivers/iio/adc/ab8500-gpadc.c
 F:     drivers/mfd/ab3100*
 F:     drivers/mfd/ab8500*
 F:     drivers/mfd/abx500*
-F:     drivers/mfd/dbx500*
 F:     drivers/mfd/db8500*
+F:     drivers/mfd/dbx500*
 F:     drivers/pinctrl/nomadik/
 F:     drivers/pinctrl/pinctrl-coh901*
 F:     drivers/pinctrl/pinctrl-u300.c
@@ -2112,11 +2123,8 @@ F:       drivers/rtc/rtc-ab3100.c
 F:     drivers/rtc/rtc-ab8500.c
 F:     drivers/rtc/rtc-coh901331.c
 F:     drivers/rtc/rtc-pl031.c
+F:     drivers/soc/ux500/
 F:     drivers/watchdog/coh901327_wdt.c
-F:     Documentation/devicetree/bindings/arm/ste-*
-F:     Documentation/devicetree/bindings/arm/ux500/
-F:     Documentation/devicetree/bindings/arm/ux500.yaml
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git
 
 ARM/NUVOTON NPCM ARCHITECTURE
 M:     Avi Fishman <avifishman70@gmail.com>
@@ -2127,25 +2135,25 @@ R:      Nancy Yuen <yuenn@google.com>
 R:     Benjamin Fair <benjaminfair@google.com>
 L:     openbmc@lists.ozlabs.org (moderated for non-subscribers)
 S:     Supported
-F:     arch/arm/mach-npcm/
+F:     Documentation/devicetree/bindings/*/*/*npcm*
+F:     Documentation/devicetree/bindings/*/*npcm*
 F:     arch/arm/boot/dts/nuvoton-npcm*
-F:     include/dt-bindings/clock/nuvoton,npcm7xx-clock.h
+F:     arch/arm/mach-npcm/
 F:     drivers/*/*npcm*
-F:     Documentation/devicetree/bindings/*/*npcm*
-F:     Documentation/devicetree/bindings/*/*/*npcm*
+F:     include/dt-bindings/clock/nuvoton,npcm7xx-clock.h
 
 ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT
 L:     openmoko-kernel@lists.openmoko.org (subscribers-only)
-W:     http://wiki.openmoko.org/wiki/Neo_FreeRunner
 S:     Orphan
-F:     arch/arm/mach-s3c24xx/mach-gta02.c
+W:     http://wiki.openmoko.org/wiki/Neo_FreeRunner
 F:     arch/arm/mach-s3c24xx/gta02.h
+F:     arch/arm/mach-s3c24xx/mach-gta02.c
 
 ARM/Orion SoC/Technologic Systems TS-78xx platform support
 M:     Alexander Clouter <alex@digriz.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.digriz.org.uk/ts78xx/kernel
 S:     Maintained
+W:     http://www.digriz.org.uk/ts78xx/kernel
 F:     arch/arm/mach-orion5x/ts78xx-*
 
 ARM/OXNAS platform support
@@ -2153,71 +2161,72 @@ M:      Neil Armstrong <narmstrong@baylibre.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-oxnas@groups.io (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm/mach-oxnas/
 F:     arch/arm/boot/dts/ox8*.dts*
+F:     arch/arm/mach-oxnas/
 N:     oxnas
 
 ARM/PALM TREO SUPPORT
 M:     Tomas Cech <sleep_walker@suse.com>
 L:     linux-arm-kernel@lists.infradead.org
-W:     http://hackndev.com
 S:     Maintained
+W:     http://hackndev.com
 F:     arch/arm/mach-pxa/palmtreo.*
 
 ARM/PALMTX,PALMT5,PALMLD,PALMTE2,PALMTC SUPPORT
 M:     Marek Vasut <marek.vasut@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org
-W:     http://hackndev.com
 S:     Maintained
-F:     arch/arm/mach-pxa/include/mach/palmtx.h
-F:     arch/arm/mach-pxa/palmtx.c
-F:     arch/arm/mach-pxa/palmt5.*
+W:     http://hackndev.com
 F:     arch/arm/mach-pxa/include/mach/palmld.h
-F:     arch/arm/mach-pxa/palmld.c
-F:     arch/arm/mach-pxa/palmte2.*
 F:     arch/arm/mach-pxa/include/mach/palmtc.h
+F:     arch/arm/mach-pxa/include/mach/palmtx.h
+F:     arch/arm/mach-pxa/palmld.c
+F:     arch/arm/mach-pxa/palmt5.*
 F:     arch/arm/mach-pxa/palmtc.c
+F:     arch/arm/mach-pxa/palmte2.*
+F:     arch/arm/mach-pxa/palmtx.c
 
 ARM/PALMZ72 SUPPORT
 M:     Sergey Lapin <slapin@ossfans.org>
 L:     linux-arm-kernel@lists.infradead.org
-W:     http://hackndev.com
 S:     Maintained
+W:     http://hackndev.com
 F:     arch/arm/mach-pxa/palmz72.*
 
 ARM/PLEB SUPPORT
 M:     Peter Chubb <pleb@gelato.unsw.edu.au>
-W:     http://www.disy.cse.unsw.edu.au/Hardware/PLEB
 S:     Maintained
+W:     http://www.disy.cse.unsw.edu.au/Hardware/PLEB
 
 ARM/PT DIGITAL BOARD PORT
 M:     Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.armlinux.org.uk/
 S:     Maintained
+W:     http://www.armlinux.org.uk/
 
 ARM/QUALCOMM SUPPORT
 M:     Andy Gross <agross@kernel.org>
 M:     Bjorn Andersson <bjorn.andersson@linaro.org>
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/soc/qcom/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git
 F:     Documentation/devicetree/bindings/*/qcom*
+F:     Documentation/devicetree/bindings/soc/qcom/
 F:     arch/arm/boot/dts/qcom-*.dts
 F:     arch/arm/boot/dts/qcom-*.dtsi
 F:     arch/arm/mach-qcom/
 F:     arch/arm64/boot/dts/qcom/
-F:     drivers/*/qcom/
-F:     drivers/*/qcom*
-F:     drivers/*/*/qcom/
 F:     drivers/*/*/qcom*
+F:     drivers/*/*/qcom/
 F:     drivers/*/pm8???-*
+F:     drivers/*/qcom*
+F:     drivers/*/qcom/
 F:     drivers/bluetooth/btqcomsmd.c
 F:     drivers/clocksource/timer-qcom.c
 F:     drivers/extcon/extcon-qcom*
-F:     drivers/iommu/msm*
-F:     drivers/i2c/busses/i2c-qup.c
 F:     drivers/i2c/busses/i2c-qcom-geni.c
+F:     drivers/i2c/busses/i2c-qup.c
+F:     drivers/iommu/msm*
 F:     drivers/mfd/ssbi.c
 F:     drivers/mmc/host/mmci_qcom*
 F:     drivers/mmc/host/sdhci-msm.c
@@ -2226,14 +2235,13 @@ F:      drivers/phy/qualcomm/
 F:     drivers/power/*/msm*
 F:     drivers/reset/reset-qcom-*
 F:     drivers/scsi/ufs/ufs-qcom.*
-F:     drivers/spi/spi-qup.c
 F:     drivers/spi/spi-geni-qcom.c
 F:     drivers/spi/spi-qcom-qspi.c
+F:     drivers/spi/spi-qup.c
 F:     drivers/tty/serial/msm_serial.c
 F:     drivers/usb/dwc3/dwc3-qcom.c
 F:     include/dt-bindings/*/qcom*
 F:     include/linux/*/qcom*
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git
 
 ARM/RADISYS ENP2611 MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
@@ -2245,42 +2253,42 @@ M:      Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-unisoc@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm/boot/dts/rda8810pl-*
-F:     drivers/clocksource/timer-rda.c
-F:     drivers/gpio/gpio-rda.c
-F:     drivers/irqchip/irq-rda-intc.c
-F:     drivers/tty/serial/rda-uart.c
 F:     Documentation/devicetree/bindings/arm/rda.yaml
 F:     Documentation/devicetree/bindings/gpio/gpio-rda.yaml
 F:     Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.txt
 F:     Documentation/devicetree/bindings/serial/rda,8810pl-uart.txt
 F:     Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt
+F:     arch/arm/boot/dts/rda8810pl-*
+F:     drivers/clocksource/timer-rda.c
+F:     drivers/gpio/gpio-rda.c
+F:     drivers/irqchip/irq-rda-intc.c
+F:     drivers/tty/serial/rda-uart.c
 
 ARM/REALTEK ARCHITECTURE
 M:     Andreas Färber <afaerber@suse.de>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-realtek-soc@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm64/boot/dts/realtek/
 F:     Documentation/devicetree/bindings/arm/realtek.yaml
+F:     arch/arm64/boot/dts/realtek/
 
 ARM/RENESAS ARM64 ARCHITECTURE
 M:     Geert Uytterhoeven <geert+renesas@glider.be>
 M:     Magnus Damm <magnus.damm@gmail.com>
 L:     linux-renesas-soc@vger.kernel.org
+S:     Supported
 Q:     http://patchwork.kernel.org/project/linux-renesas-soc/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel.git next
-S:     Supported
-F:     arch/arm64/boot/dts/renesas/
 F:     Documentation/devicetree/bindings/arm/renesas.yaml
+F:     arch/arm64/boot/dts/renesas/
 F:     drivers/soc/renesas/
 F:     include/linux/soc/renesas/
 
 ARM/RISCPC ARCHITECTURE
 M:     Russell King <linux@armlinux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.armlinux.org.uk/
 S:     Maintained
+W:     http://www.armlinux.org.uk/
 F:     arch/arm/include/asm/hardware/entry-macro-iomd.S
 F:     arch/arm/include/asm/hardware/ioc.h
 F:     arch/arm/include/asm/hardware/iomd.h
@@ -2295,18 +2303,18 @@ ARM/Rockchip SoC support
 M:     Heiko Stuebner <heiko@sntech.de>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-rockchip@lists.infradead.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git
 F:     Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml
 F:     Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml
 F:     Documentation/devicetree/bindings/spi/spi-rockchip.yaml
 F:     arch/arm/boot/dts/rk3*
 F:     arch/arm/boot/dts/rv1108*
 F:     arch/arm/mach-rockchip/
+F:     drivers/*/*/*rockchip*
+F:     drivers/*/*rockchip*
 F:     drivers/clk/rockchip/
 F:     drivers/i2c/busses/i2c-rk3x.c
-F:     drivers/*/*rockchip*
-F:     drivers/*/*/*rockchip*
 F:     sound/soc/rockchip/
 N:     rockchip
 
@@ -2315,28 +2323,28 @@ M:      Kukjin Kim <kgene@kernel.org>
 M:     Krzysztof Kozlowski <krzk@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
-Q:     https://patchwork.kernel.org/project/linux-samsung-soc/list/
 S:     Maintained
+Q:     https://patchwork.kernel.org/project/linux-samsung-soc/list/
+F:     Documentation/arm/samsung/
+F:     Documentation/devicetree/bindings/arm/samsung/
+F:     Documentation/devicetree/bindings/power/pd-samsung.yaml
+F:     arch/arm/boot/dts/exynos*
 F:     arch/arm/boot/dts/s3c*
 F:     arch/arm/boot/dts/s5p*
-F:     arch/arm/boot/dts/exynos*
-F:     arch/arm64/boot/dts/exynos/
-F:     arch/arm/plat-samsung/
+F:     arch/arm/mach-exynos*/
 F:     arch/arm/mach-s3c24*/
 F:     arch/arm/mach-s3c64xx/
 F:     arch/arm/mach-s5p*/
-F:     arch/arm/mach-exynos*/
-F:     drivers/*/*s3c24*
+F:     arch/arm/plat-samsung/
+F:     arch/arm64/boot/dts/exynos/
 F:     drivers/*/*/*s3c24*
+F:     drivers/*/*s3c24*
 F:     drivers/*/*s3c64xx*
 F:     drivers/*/*s5pv210*
 F:     drivers/memory/samsung/
 F:     drivers/soc/samsung/
 F:     drivers/tty/serial/samsung*
 F:     include/linux/soc/samsung/
-F:     Documentation/arm/samsung/
-F:     Documentation/devicetree/bindings/arm/samsung/
-F:     Documentation/devicetree/bindings/power/pd-samsung.yaml
 N:     exynos
 
 ARM/SAMSUNG MOBILE MACHINE SUPPORT
@@ -2359,8 +2367,8 @@ M:        Marek Szyprowski <m.szyprowski@samsung.com>
 L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     drivers/media/platform/s5p-cec/
 F:     Documentation/devicetree/bindings/media/s5p-cec.txt
+F:     drivers/media/platform/s5p-cec/
 
 ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT
 M:     Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
@@ -2385,9 +2393,10 @@ ARM/SHMOBILE ARM ARCHITECTURE
 M:     Geert Uytterhoeven <geert+renesas@glider.be>
 M:     Magnus Damm <magnus.damm@gmail.com>
 L:     linux-renesas-soc@vger.kernel.org
+S:     Supported
 Q:     http://patchwork.kernel.org/project/linux-renesas-soc/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel.git next
-S:     Supported
+F:     Documentation/devicetree/bindings/arm/renesas.yaml
 F:     arch/arm/boot/dts/emev2*
 F:     arch/arm/boot/dts/gr-peach*
 F:     arch/arm/boot/dts/iwg20d-q7*
@@ -2398,20 +2407,19 @@ F:      arch/arm/boot/dts/sh*
 F:     arch/arm/configs/shmobile_defconfig
 F:     arch/arm/include/debug/renesas-scif.S
 F:     arch/arm/mach-shmobile/
-F:     Documentation/devicetree/bindings/arm/renesas.yaml
 F:     drivers/soc/renesas/
 F:     include/linux/soc/renesas/
 
 ARM/SOCFPGA ARCHITECTURE
 M:     Dinh Nguyen <dinguyen@kernel.org>
 S:     Maintained
-F:     arch/arm/mach-socfpga/
+W:     http://www.rocketboards.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git
 F:     arch/arm/boot/dts/socfpga*
 F:     arch/arm/configs/socfpga_defconfig
+F:     arch/arm/mach-socfpga/
 F:     arch/arm64/boot/dts/altera/
 F:     arch/arm64/boot/dts/intel/
-W:     http://www.rocketboards.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git
 
 ARM/SOCFPGA CLOCK FRAMEWORK SUPPORT
 M:     Dinh Nguyen <dinguyen@kernel.org>
@@ -2436,19 +2444,20 @@ N:      sc2731
 ARM/STI ARCHITECTURE
 M:     Patrice Chotard <patrice.chotard@st.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.stlinux.com
 S:     Maintained
+W:     http://www.stlinux.com
 F:     Documentation/devicetree/bindings/i2c/i2c-st.txt
-F:     arch/arm/mach-sti/
 F:     arch/arm/boot/dts/sti*
+F:     arch/arm/mach-sti/
+F:     drivers/ata/ahci_st.c
 F:     drivers/char/hw_random/st-rng.c
 F:     drivers/clocksource/arm_global_timer.c
 F:     drivers/clocksource/clksrc_st_lpc.c
 F:     drivers/cpufreq/sti-cpufreq.c
 F:     drivers/dma/st_fdma*
 F:     drivers/i2c/busses/i2c-st.c
-F:     drivers/media/rc/st_rc.c
 F:     drivers/media/platform/sti/c8sectpfe/
+F:     drivers/media/rc/st_rc.c
 F:     drivers/mmc/host/sdhci-st.c
 F:     drivers/phy/st/phy-miphy28lp.c
 F:     drivers/phy/st/phy-stih407-usb.c
@@ -2462,7 +2471,6 @@ F:        drivers/usb/dwc3/dwc3-st.c
 F:     drivers/usb/host/ehci-st.c
 F:     drivers/usb/host/ohci-st.c
 F:     drivers/watchdog/st_lpc_wdt.c
-F:     drivers/ata/ahci_st.c
 F:     include/linux/remoteproc/st_slim_rproc.h
 
 ARM/STM32 ARCHITECTURE
@@ -2472,19 +2480,19 @@ L:      linux-stm32@st-md-mailman.stormreply.com (moderated for non-subscribers)
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/atorgue/stm32.git stm32-next
-N:     stm32
-N:     stm
 F:     arch/arm/boot/dts/stm32*
 F:     arch/arm/mach-stm32/
 F:     drivers/clocksource/armv7m_systick.c
+N:     stm32
+N:     stm
 
 ARM/Synaptics SoC support
 M:     Jisheng Zhang <Jisheng.Zhang@synaptics.com>
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm/mach-berlin/
 F:     arch/arm/boot/dts/berlin*
+F:     arch/arm/mach-berlin/
 F:     arch/arm64/boot/dts/synaptics/
 
 ARM/TANGO ARCHITECTURE
@@ -2504,8 +2512,8 @@ M:        Hans Verkuil <hverkuil-cisco@xs4all.nl>
 L:     linux-tegra@vger.kernel.org
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     drivers/media/platform/tegra-cec/
 F:     Documentation/devicetree/bindings/media/tegra-cec.txt
+F:     drivers/media/platform/tegra-cec/
 
 ARM/TETON BGA MACHINE SUPPORT
 M:     "Mark F. Brown" <mark.brown314@gmail.com>
@@ -2518,23 +2526,13 @@ L:      linux-kernel@vger.kernel.org
 S:     Maintained
 F:     drivers/memory/*emif*
 
-ARM/TEXAS INSTRUMENTS K3 ARCHITECTURE
-M:     Tero Kristo <t-kristo@ti.com>
-M:     Nishanth Menon <nm@ti.com>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Supported
-F:     Documentation/devicetree/bindings/arm/ti/k3.txt
-F:     arch/arm64/boot/dts/ti/Makefile
-F:     arch/arm64/boot/dts/ti/k3-*
-F:     include/dt-bindings/pinctrl/k3.h
-
 ARM/TEXAS INSTRUMENT KEYSTONE ARCHITECTURE
 M:     Santosh Shilimkar <ssantosh@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm/mach-keystone/
-F:     arch/arm/boot/dts/keystone-*
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone.git
+F:     arch/arm/boot/dts/keystone-*
+F:     arch/arm/mach-keystone/
 
 ARM/TEXAS INSTRUMENT KEYSTONE CLOCK FRAMEWORK
 M:     Santosh Shilimkar <ssantosh@kernel.org>
@@ -2555,6 +2553,16 @@ L:       linux-kernel@vger.kernel.org
 S:     Maintained
 F:     drivers/power/reset/keystone-reset.c
 
+ARM/TEXAS INSTRUMENTS K3 ARCHITECTURE
+M:     Tero Kristo <t-kristo@ti.com>
+M:     Nishanth Menon <nm@ti.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Supported
+F:     Documentation/devicetree/bindings/arm/ti/k3.txt
+F:     arch/arm64/boot/dts/ti/Makefile
+F:     arch/arm64/boot/dts/ti/k3-*
+F:     include/dt-bindings/pinctrl/k3.h
+
 ARM/THECUS N2100 MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -2568,8 +2576,8 @@ S:        Maintained
 ARM/UNIPHIER ARCHITECTURE
 M:     Masahiro Yamada <yamada.masahiro@socionext.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-uniphier.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-uniphier.git
 F:     Documentation/devicetree/bindings/arm/socionext/uniphier.yaml
 F:     Documentation/devicetree/bindings/gpio/socionext,uniphier-gpio.yaml
 F:     Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.yaml
@@ -2590,24 +2598,17 @@ F:      drivers/reset/reset-uniphier.c
 F:     drivers/tty/serial/8250/8250_uniphier.c
 N:     uniphier
 
-Ux500 CLOCK DRIVERS
-M:     Ulf Hansson <ulf.hansson@linaro.org>
-L:     linux-clk@vger.kernel.org
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-F:     drivers/clk/ux500/
-
 ARM/VERSATILE EXPRESS PLATFORM
 M:     Liviu Dudau <liviu.dudau@arm.com>
 M:     Sudeep Holla <sudeep.holla@arm.com>
 M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
+F:     */*/*/vexpress*
+F:     */*/vexpress*
 F:     arch/arm/boot/dts/vexpress*
-F:     arch/arm64/boot/dts/arm/
 F:     arch/arm/mach-vexpress/
-F:     */*/vexpress*
-F:     */*/*/vexpress*
+F:     arch/arm64/boot/dts/arm/
 F:     drivers/clk/versatile/clk-vexpress-osc.c
 F:     drivers/clocksource/timer-versatile.c
 N:     mps2
@@ -2615,16 +2616,16 @@ N:      mps2
 ARM/VFP SUPPORT
 M:     Russell King <linux@armlinux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.armlinux.org.uk/
 S:     Maintained
+W:     http://www.armlinux.org.uk/
 F:     arch/arm/vfp/
 
 ARM/VOIPAC PXA270 SUPPORT
 M:     Marek Vasut <marek.vasut@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm/mach-pxa/vpac270.c
 F:     arch/arm/mach-pxa/include/mach/vpac270.h
+F:     arch/arm/mach-pxa/vpac270.c
 
 ARM/VT8500 ARM ARCHITECTURE
 M:     Tony Prisk <linux@prisktech.co.nz>
@@ -2648,26 +2649,14 @@ ARM/ZIPIT Z2 SUPPORT
 M:     Marek Vasut <marek.vasut@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm/mach-pxa/z2.c
 F:     arch/arm/mach-pxa/include/mach/z2.h
+F:     arch/arm/mach-pxa/z2.c
 
 ARM/ZTE ARCHITECTURE
 M:     Jun Nie <jun.nie@linaro.org>
 M:     Shawn Guo <shawnguo@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm/boot/dts/zx2967*
-F:     arch/arm/mach-zx/
-F:     arch/arm64/boot/dts/zte/
-F:     drivers/clk/zte/
-F:     drivers/dma/zx_dma.c
-F:     drivers/gpio/gpio-zx.c
-F:     drivers/i2c/busses/i2c-zx2967.c
-F:     drivers/mmc/host/dw_mmc-zx.*
-F:     drivers/pinctrl/zte/
-F:     drivers/soc/zte/
-F:     drivers/thermal/zx2967_thermal.c
-F:     drivers/watchdog/zx2967_wdt.c
 F:     Documentation/devicetree/bindings/arm/zte.yaml
 F:     Documentation/devicetree/bindings/clock/zx2967*.txt
 F:     Documentation/devicetree/bindings/dma/zxdma.txt
@@ -2680,6 +2669,18 @@ F:       Documentation/devicetree/bindings/soc/zte/
 F:     Documentation/devicetree/bindings/sound/zte,*.txt
 F:     Documentation/devicetree/bindings/thermal/zx2967-thermal.txt
 F:     Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt
+F:     arch/arm/boot/dts/zx2967*
+F:     arch/arm/mach-zx/
+F:     arch/arm64/boot/dts/zte/
+F:     drivers/clk/zte/
+F:     drivers/dma/zx_dma.c
+F:     drivers/gpio/gpio-zx.c
+F:     drivers/i2c/busses/i2c-zx2967.c
+F:     drivers/mmc/host/dw_mmc-zx.*
+F:     drivers/pinctrl/zte/
+F:     drivers/soc/zte/
+F:     drivers/thermal/zx2967_thermal.c
+F:     drivers/watchdog/zx2967_wdt.c
 F:     include/dt-bindings/clock/zx2967*.h
 F:     include/dt-bindings/soc/zte,*.h
 F:     sound/soc/codecs/zx_aud96p22.c
@@ -2688,32 +2689,32 @@ F:      sound/soc/zte/
 ARM/ZYNQ ARCHITECTURE
 M:     Michal Simek <michal.simek@xilinx.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Supported
 W:     http://wiki.xilinx.com
 T:     git https://github.com/Xilinx/linux-xlnx.git
-S:     Supported
-F:     arch/arm/mach-zynq/
-F:     drivers/cpuidle/cpuidle-zynq.c
-F:     drivers/block/xsysace.c
-N:     zynq
-N:     xilinx
 F:     Documentation/devicetree/bindings/i2c/i2c-cadence.txt
 F:     Documentation/devicetree/bindings/i2c/i2c-xiic.txt
+F:     arch/arm/mach-zynq/
+F:     drivers/block/xsysace.c
 F:     drivers/clocksource/timer-cadence-ttc.c
-F:     drivers/i2c/busses/i2c-cadence.c
-F:     drivers/mmc/host/sdhci-of-arasan.c
+F:     drivers/cpuidle/cpuidle-zynq.c
 F:     drivers/edac/synopsys_edac.c
+F:     drivers/i2c/busses/i2c-cadence.c
 F:     drivers/i2c/busses/i2c-xiic.c
+F:     drivers/mmc/host/sdhci-of-arasan.c
+N:     zynq
+N:     xilinx
 
 ARM64 PORT (AARCH64 ARCHITECTURE)
 M:     Catalin Marinas <catalin.marinas@arm.com>
 M:     Will Deacon <will@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git
 S:     Maintained
-F:     arch/arm64/
-X:     arch/arm64/boot/dts/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git
 F:     Documentation/arm64/
+F:     arch/arm64/
 F:     tools/testing/selftests/arm64/
+X:     arch/arm64/boot/dts/
 
 AS3645A LED FLASH CONTROLLER DRIVER
 M:     Sakari Ailus <sakari.ailus@iki.fi>
@@ -2724,16 +2725,16 @@ F:      drivers/leds/leds-as3645a.c
 ASAHI KASEI AK7375 LENS VOICE COIL DRIVER
 M:     Tianshu Qiu <tian.shu.qiu@intel.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/i2c/ak7375.c
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/ak7375.txt
+F:     drivers/media/i2c/ak7375.c
 
 ASAHI KASEI AK8974 DRIVER
 M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-iio@vger.kernel.org
-W:     http://www.akm.com/
 S:     Supported
+W:     http://www.akm.com/
 F:     drivers/iio/magnetometer/ak8974.c
 
 ASC7621 HARDWARE MONITOR DRIVER
@@ -2765,8 +2766,8 @@ M:        Eddie James <eajames@linux.ibm.com>
 L:     linux-media@vger.kernel.org
 L:     openbmc@lists.ozlabs.org (moderated for non-subscribers)
 S:     Maintained
-F:     drivers/media/platform/aspeed-video.c
 F:     Documentation/devicetree/bindings/media/aspeed-video.txt
+F:     drivers/media/platform/aspeed-video.c
 
 ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS
 M:     Corentin Chary <corentin.chary@gmail.com>
@@ -2788,33 +2789,33 @@ M:      David Howells <dhowells@redhat.com>
 L:     keyrings@vger.kernel.org
 S:     Maintained
 F:     Documentation/crypto/asymmetric-keys.txt
-F:     include/linux/verification.h
-F:     include/crypto/public_key.h
-F:     include/crypto/pkcs7.h
 F:     crypto/asymmetric_keys/
+F:     include/crypto/pkcs7.h
+F:     include/crypto/public_key.h
+F:     include/linux/verification.h
 
 ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
 R:     Dan Williams <dan.j.williams@intel.com>
-W:     http://sourceforge.net/projects/xscaleiop
 S:     Odd fixes
+W:     http://sourceforge.net/projects/xscaleiop
 F:     Documentation/crypto/async-tx-api.txt
 F:     crypto/async_tx/
 F:     drivers/dma/
-F:     include/linux/dmaengine.h
 F:     include/linux/async_tx.h
+F:     include/linux/dmaengine.h
 
 AT24 EEPROM DRIVER
 M:     Bartosz Golaszewski <bgolaszewski@baylibre.com>
 L:     linux-i2c@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
 F:     Documentation/devicetree/bindings/eeprom/at24.yaml
 F:     drivers/misc/eeprom/at24.c
 
 ATA OVER ETHERNET (AOE) DRIVER
 M:     "Justin Sanders" <justin@coraid.com>
-W:     http://www.openaoe.org/
 S:     Supported
+W:     http://www.openaoe.org/
 F:     Documentation/admin-guide/aoe/
 F:     drivers/block/aoe/
 
@@ -2828,11 +2829,11 @@ F:      drivers/gpio/gpio-ath79.c
 
 ATHEROS 71XX/9XXX USB PHY DRIVER
 M:     Alban Bedel <albeu@free.fr>
+S:     Maintained
 W:     https://github.com/AlbanBedel/linux
 T:     git git://github.com/AlbanBedel/linux
-S:     Maintained
-F:     drivers/phy/qualcomm/phy-ath79-usb.c
 F:     Documentation/devicetree/bindings/phy/phy-ath79-usb.txt
+F:     drivers/phy/qualcomm/phy-ath79-usb.c
 
 ATHEROS ATH GENERIC UTILITIES
 M:     Kalle Valo <kvalo@codeaurora.org>
@@ -2845,16 +2846,16 @@ M:      Jiri Slaby <jirislaby@gmail.com>
 M:     Nick Kossifidis <mickflemm@gmail.com>
 M:     Luis Chamberlain <mcgrof@kernel.org>
 L:     linux-wireless@vger.kernel.org
-W:     http://wireless.kernel.org/en/users/Drivers/ath5k
 S:     Maintained
+W:     http://wireless.kernel.org/en/users/Drivers/ath5k
 F:     drivers/net/wireless/ath/ath5k/
 
 ATHEROS ATH6KL WIRELESS DRIVER
 M:     Kalle Valo <kvalo@codeaurora.org>
 L:     linux-wireless@vger.kernel.org
+S:     Supported
 W:     http://wireless.kernel.org/en/users/Drivers/ath6kl
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
-S:     Supported
 F:     drivers/net/wireless/ath/ath6kl/
 
 ATI_REMOTE2 DRIVER
@@ -2872,17 +2873,17 @@ ATLX ETHERNET DRIVERS
 M:     Jay Cliburn <jcliburn@gmail.com>
 M:     Chris Snook <chris.snook@gmail.com>
 L:     netdev@vger.kernel.org
+S:     Maintained
 W:     http://sourceforge.net/projects/atl1
 W:     http://atl1.sourceforge.net
-S:     Maintained
 F:     drivers/net/ethernet/atheros/
 
 ATM
 M:     Chas Williams <3chas3@gmail.com>
 L:     linux-atm-general@lists.sourceforge.net (moderated for non-subscribers)
 L:     netdev@vger.kernel.org
-W:     http://linux-atm.sourceforge.net
 S:     Maintained
+W:     http://linux-atm.sourceforge.net
 F:     drivers/atm/
 F:     include/linux/atm*
 F:     include/uapi/linux/atm*
@@ -2894,17 +2895,17 @@ F:      drivers/net/ethernet/cadence/
 
 ATMEL MAXTOUCH DRIVER
 M:     Nick Dyer <nick@shmanahar.org>
-T:     git git://github.com/ndyer/linux.git
 S:     Maintained
+T:     git git://github.com/ndyer/linux.git
 F:     Documentation/devicetree/bindings/input/atmel,maxtouch.txt
 F:     drivers/input/touchscreen/atmel_mxt_ts.c
 
 ATMEL WIRELESS DRIVER
 M:     Simon Kelley <simon@thekelleys.org.uk>
 L:     linux-wireless@vger.kernel.org
+S:     Maintained
 W:     http://www.thekelleys.org.uk/atmel
 W:     http://atmelwlandriver.sourceforge.net/
-S:     Maintained
 F:     drivers/net/wireless/atmel/atmel*
 
 ATOMIC INFRASTRUCTURE
@@ -2920,25 +2921,25 @@ F:      scripts/atomic/
 ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER
 M:     Bradley Grove <linuxdrivers@attotech.com>
 L:     linux-scsi@vger.kernel.org
-W:     http://www.attotech.com
 S:     Supported
+W:     http://www.attotech.com
 F:     drivers/scsi/esas2r
 
 ATUSB IEEE 802.15.4 RADIO DRIVER
 M:     Stefan Schmidt <stefan@datenfreihafen.org>
 L:     linux-wpan@vger.kernel.org
 S:     Maintained
+F:     drivers/net/ieee802154/at86rf230.h
 F:     drivers/net/ieee802154/atusb.c
 F:     drivers/net/ieee802154/atusb.h
-F:     drivers/net/ieee802154/at86rf230.h
 
 AUDIT SUBSYSTEM
 M:     Paul Moore <paul@paul-moore.com>
 M:     Eric Paris <eparis@redhat.com>
 L:     linux-audit@redhat.com (moderated for non-subscribers)
+S:     Supported
 W:     https://github.com/linux-audit
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit.git
-S:     Supported
 F:     include/linux/audit.h
 F:     include/uapi/linux/audit.h
 F:     kernel/audit*
@@ -2959,10 +2960,10 @@ F:      drivers/iio/adc/hx711.c
 AX.25 NETWORK LAYER
 M:     Ralf Baechle <ralf@linux-mips.org>
 L:     linux-hams@vger.kernel.org
-W:     http://www.linux-ax25.org/
 S:     Maintained
-F:     include/uapi/linux/ax25.h
+W:     http://www.linux-ax25.org/
 F:     include/net/ax25.h
+F:     include/uapi/linux/ax25.h
 F:     net/ax25/
 
 AXENTIA ARM DEVICES
@@ -2983,11 +2984,11 @@ F:      sound/soc/atmel/tse850-pcm5142.c
 
 AXI-FAN-CONTROL HARDWARE MONITOR DRIVER
 M:     Nuno Sá <nuno.sa@analog.com>
-W:     http://ez.analog.com/community/linux-device-drivers
 L:     linux-hwmon@vger.kernel.org
 S:     Supported
-F:     drivers/hwmon/axi-fan-control.c
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml
+F:     drivers/hwmon/axi-fan-control.c
 
 AXXIA I2C CONTROLLER
 M:     Krzysztof Adamski <krzysztof.adamski@nokia.com>
@@ -2999,32 +3000,32 @@ F:      drivers/i2c/busses/i2c-axxia.c
 AZ6007 DVB DRIVER
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/az6007.c
 
 AZTECH FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/radio-aztech*
 
 B43 WIRELESS DRIVER
 L:     linux-wireless@vger.kernel.org
 L:     b43-dev@lists.infradead.org
-W:     http://wireless.kernel.org/en/users/Drivers/b43
 S:     Odd Fixes
+W:     http://wireless.kernel.org/en/users/Drivers/b43
 F:     drivers/net/wireless/broadcom/b43/
 
 B43LEGACY WIRELESS DRIVER
 M:     Larry Finger <Larry.Finger@lwfinger.net>
 L:     linux-wireless@vger.kernel.org
 L:     b43-dev@lists.infradead.org
-W:     http://wireless.kernel.org/en/users/Drivers/b43
 S:     Maintained
+W:     http://wireless.kernel.org/en/users/Drivers/b43
 F:     drivers/net/wireless/broadcom/b43legacy/
 
 BACKLIGHT CLASS/SUBSYSTEM
@@ -3032,14 +3033,14 @@ M:      Lee Jones <lee.jones@linaro.org>
 M:     Daniel Thompson <daniel.thompson@linaro.org>
 M:     Jingoo Han <jingoohan1@gmail.com>
 L:     dri-devel@lists.freedesktop.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight.git
+F:     Documentation/ABI/stable/sysfs-class-backlight
+F:     Documentation/ABI/testing/sysfs-class-backlight
+F:     Documentation/devicetree/bindings/leds/backlight
 F:     drivers/video/backlight/
 F:     include/linux/backlight.h
 F:     include/linux/pwm_backlight.h
-F:     Documentation/devicetree/bindings/leds/backlight
-F:     Documentation/ABI/stable/sysfs-class-backlight
-F:     Documentation/ABI/testing/sysfs-class-backlight
 
 BATMAN ADVANCED
 M:     Marek Lindner <mareklindner@neomailbox.ch>
@@ -3047,12 +3048,12 @@ M:      Simon Wunderlich <sw@simonwunderlich.de>
 M:     Antonio Quartulli <a@unstable.cc>
 M:     Sven Eckelmann <sven@narfation.org>
 L:     b.a.t.m.a.n@lists.open-mesh.org (moderated for non-subscribers)
+S:     Maintained
 W:     https://www.open-mesh.org/
+Q:     https://patchwork.open-mesh.org/project/batman/list/
 B:     https://www.open-mesh.org/projects/batman-adv/issues
 C:     irc://chat.freenode.net/batman
-Q:     https://patchwork.open-mesh.org/project/batman/list/
 T:     git https://git.open-mesh.org/linux-merge.git
-S:     Maintained
 F:     Documentation/ABI/obsolete/sysfs-class-net-batman-adv
 F:     Documentation/ABI/obsolete/sysfs-class-net-mesh
 F:     Documentation/networking/batman-adv.rst
@@ -3063,25 +3064,25 @@ F:      net/batman-adv/
 BAYCOM/HDLCDRV DRIVERS FOR AX.25
 M:     Thomas Sailer <t.sailer@alumni.ethz.ch>
 L:     linux-hams@vger.kernel.org
-W:     http://www.baycom.org/~tom/ham/ham.html
 S:     Maintained
+W:     http://www.baycom.org/~tom/ham/ham.html
 F:     drivers/net/hamradio/baycom*
 
 BCACHE (BLOCK LAYER CACHE)
 M:     Coly Li <colyli@suse.de>
 M:     Kent Overstreet <kent.overstreet@gmail.com>
 L:     linux-bcache@vger.kernel.org
+S:     Maintained
 W:     http://bcache.evilpiepirate.org
 C:     irc://irc.oftc.net/bcache
-S:     Maintained
 F:     drivers/md/bcache/
 
 BDISP ST MEDIA DRIVER
 M:     Fabien Dessenne <fabien.dessenne@st.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Supported
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/platform/sti/bdisp
 
 BECKHOFF CX5020 ETHERCAT MASTER DRIVER
@@ -3103,8 +3104,8 @@ M:        Paolo Valente <paolo.valente@linaro.org>
 M:     Jens Axboe <axboe@kernel.dk>
 L:     linux-block@vger.kernel.org
 S:     Maintained
-F:     block/bfq-*
 F:     Documentation/block/bfq-iosched.rst
+F:     block/bfq-*
 
 BFS FILE SYSTEM
 M:     "Tigran A. Aivazian" <aivazian.tigran@gmail.com>
@@ -3121,8 +3122,8 @@ F:        drivers/leds/leds-blinkm.c
 BLOCK LAYER
 M:     Jens Axboe <axboe@kernel.dk>
 L:     linux-block@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 F:     block/
 F:     drivers/block/
 F:     kernel/trace/blktrace.c
@@ -3138,30 +3139,30 @@ BLUETOOTH DRIVERS
 M:     Marcel Holtmann <marcel@holtmann.org>
 M:     Johan Hedberg <johan.hedberg@gmail.com>
 L:     linux-bluetooth@vger.kernel.org
+S:     Maintained
 W:     http://www.bluez.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
-S:     Maintained
 F:     drivers/bluetooth/
 
 BLUETOOTH SUBSYSTEM
 M:     Marcel Holtmann <marcel@holtmann.org>
 M:     Johan Hedberg <johan.hedberg@gmail.com>
 L:     linux-bluetooth@vger.kernel.org
+S:     Maintained
 W:     http://www.bluez.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
-S:     Maintained
-F:     net/bluetooth/
 F:     include/net/bluetooth/
+F:     net/bluetooth/
 
 BONDING DRIVER
 M:     Jay Vosburgh <j.vosburgh@gmail.com>
 M:     Veaceslav Falico <vfalico@gmail.com>
 M:     Andy Gospodarek <andy@greyhouse.net>
 L:     netdev@vger.kernel.org
-W:     http://sourceforge.net/projects/bonding/
 S:     Supported
+W:     http://sourceforge.net/projects/bonding/
 F:     drivers/net/bonding/
 F:     include/uapi/linux/if_bonding.h
 
@@ -3169,8 +3170,8 @@ BOSCH SENSORTEC BMA400 ACCELEROMETER IIO DRIVER
 M:     Dan Robertson <dan@dlrobertson.com>
 L:     linux-iio@vger.kernel.org
 S:     Maintained
-F:     drivers/iio/accel/bma400*
 F:     Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml
+F:     drivers/iio/accel/bma400*
 
 BPF (Safe dynamic programs and tools)
 M:     Alexei Starovoitov <ast@kernel.org>
@@ -3183,13 +3184,13 @@ R:      John Fastabend <john.fastabend@gmail.com>
 R:     KP Singh <kpsingh@chromium.org>
 L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
+S:     Supported
+Q:     https://patchwork.ozlabs.org/project/netdev/list/?delegate=77147
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git
-Q:     https://patchwork.ozlabs.org/project/netdev/list/?delegate=77147
-S:     Supported
-F:     arch/*/net/*
-F:     Documentation/networking/filter.txt
 F:     Documentation/bpf/
+F:     Documentation/networking/filter.txt
+F:     arch/*/net/*
 F:     include/linux/bpf*
 F:     include/linux/filter.h
 F:     include/trace/events/xdp.h
@@ -3206,8 +3207,8 @@ F:        samples/bpf/
 F:     tools/bpf/
 F:     tools/lib/bpf/
 F:     tools/testing/selftests/bpf/
-K:     bpf
 N:     bpf
+K:     bpf
 
 BPF JIT for ARM
 M:     Shubham Bansal <illusionist.neo@gmail.com>
@@ -3311,31 +3312,31 @@ S:      Supported
 F:     drivers/net/dsa/b53/*
 F:     include/linux/platform_data/b53.h
 
+BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE
+M:     Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+L:     bcm-kernel-feedback-list@broadcom.com
+L:     linux-rpi-kernel@lists.infradead.org (moderated for non-subscribers)
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+T:     git git://github.com/anholt/linux
+F:     Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
+F:     drivers/pci/controller/pcie-brcmstb.c
+F:     drivers/staging/vc04_services
+N:     bcm2711
+N:     bcm2835
+
 BROADCOM BCM281XX/BCM11XXX/BCM216XX ARM ARCHITECTURE
 M:     Florian Fainelli <f.fainelli@gmail.com>
 M:     Ray Jui <rjui@broadcom.com>
 M:     Scott Branden <sbranden@broadcom.com>
 M:     bcm-kernel-feedback-list@broadcom.com
-T:     git git://github.com/broadcom/mach-bcm
 S:     Maintained
+T:     git git://github.com/broadcom/mach-bcm
+F:     arch/arm/mach-bcm/
 N:     bcm281*
 N:     bcm113*
 N:     bcm216*
 N:     kona
-F:     arch/arm/mach-bcm/
-
-BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE
-M:     Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
-L:     bcm-kernel-feedback-list@broadcom.com
-L:     linux-rpi-kernel@lists.infradead.org (moderated for non-subscribers)
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://github.com/anholt/linux
-S:     Maintained
-N:     bcm2711
-N:     bcm2835
-F:     drivers/staging/vc04_services
-F:     Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
-F:     drivers/pci/controller/pcie-brcmstb.c
 
 BROADCOM BCM47XX MIPS ARCHITECTURE
 M:     Hauke Mehrtens <hauke@hauke-m.de>
@@ -3352,25 +3353,25 @@ M:      Rafał Miłecki <zajec5@gmail.com>
 M:     bcm-kernel-feedback-list@broadcom.com
 L:     linux-arm-kernel@lists.infradead.org
 S:     Maintained
-F:     arch/arm/mach-bcm/bcm_5301x.c
-F:     arch/arm/boot/dts/bcm5301x*.dtsi
 F:     arch/arm/boot/dts/bcm470*
+F:     arch/arm/boot/dts/bcm5301x*.dtsi
 F:     arch/arm/boot/dts/bcm953012*
+F:     arch/arm/mach-bcm/bcm_5301x.c
 
 BROADCOM BCM53573 ARM ARCHITECTURE
 M:     Rafał Miłecki <rafal@milecki.pl>
 L:     bcm-kernel-feedback-list@broadcom.com
 L:     linux-arm-kernel@lists.infradead.org
 S:     Maintained
-F:     arch/arm/boot/dts/bcm53573*
 F:     arch/arm/boot/dts/bcm47189*
+F:     arch/arm/boot/dts/bcm53573*
 
 BROADCOM BCM63XX ARM ARCHITECTURE
 M:     Florian Fainelli <f.fainelli@gmail.com>
 M:     bcm-kernel-feedback-list@broadcom.com
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://github.com/broadcom/stblinux.git
 S:     Maintained
+T:     git git://github.com/broadcom/stblinux.git
 N:     bcm63xx
 
 BROADCOM BCM63XX/BCM33XX UDC DRIVER
@@ -3383,16 +3384,16 @@ BROADCOM BCM7XXX ARM ARCHITECTURE
 M:     Florian Fainelli <f.fainelli@gmail.com>
 M:     bcm-kernel-feedback-list@broadcom.com
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://github.com/broadcom/stblinux.git
 S:     Maintained
-F:     arch/arm/mach-bcm/*brcmstb*
+T:     git git://github.com/broadcom/stblinux.git
+F:     Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
 F:     arch/arm/boot/dts/bcm7*.dts*
-F:     drivers/bus/brcmstb_gisb.c
-F:     arch/arm/mm/cache-b15-rac.c
 F:     arch/arm/include/asm/hardware/cache-b15-rac.h
-N:     brcmstb
-F:     Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
+F:     arch/arm/mach-bcm/*brcmstb*
+F:     arch/arm/mm/cache-b15-rac.c
+F:     drivers/bus/brcmstb_gisb.c
 F:     drivers/pci/controller/pcie-brcmstb.c
+N:     brcmstb
 
 BROADCOM BMIPS CPUFREQ DRIVER
 M:     Markus Mayer <mmayer@broadcom.com>
@@ -3405,12 +3406,12 @@ BROADCOM BMIPS MIPS ARCHITECTURE
 M:     Florian Fainelli <f.fainelli@gmail.com>
 L:     bcm-kernel-feedback-list@broadcom.com
 L:     linux-mips@vger.kernel.org
-T:     git git://github.com/broadcom/stblinux.git
 S:     Maintained
+T:     git git://github.com/broadcom/stblinux.git
 F:     arch/mips/bmips/*
+F:     arch/mips/boot/dts/brcm/bcm*.dts*
 F:     arch/mips/include/asm/mach-bmips/*
 F:     arch/mips/kernel/*bmips*
-F:     arch/mips/boot/dts/brcm/bcm*.dts*
 F:     drivers/irqchip/irq-bcm63*
 F:     drivers/irqchip/irq-bcm7*
 F:     drivers/irqchip/irq-brcmstb*
@@ -3475,8 +3476,8 @@ M:        Kamal Dasu <kdasu.kdev@gmail.com>
 L:     linux-i2c@vger.kernel.org
 L:     bcm-kernel-feedback-list@broadcom.com
 S:     Supported
-F:     drivers/i2c/busses/i2c-brcmstb.c
 F:     Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml
+F:     drivers/i2c/busses/i2c-brcmstb.c
 
 BROADCOM BRCMSTB USB2 and USB3 PHY DRIVER
 M:     Al Cooper <alcooperx@gmail.com>
@@ -3498,8 +3499,14 @@ M:       Ray Jui <rjui@broadcom.com>
 M:     Scott Branden <sbranden@broadcom.com>
 M:     bcm-kernel-feedback-list@broadcom.com
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://github.com/broadcom/cygnus-linux.git
 S:     Maintained
+T:     git git://github.com/broadcom/cygnus-linux.git
+F:     arch/arm64/boot/dts/broadcom/northstar2/*
+F:     arch/arm64/boot/dts/broadcom/stingray/*
+F:     drivers/clk/bcm/clk-ns*
+F:     drivers/clk/bcm/clk-sr*
+F:     drivers/pinctrl/bcm/pinctrl-ns*
+F:     include/dt-bindings/clock/bcm-sr*
 N:     iproc
 N:     cygnus
 N:     bcm[-_]nsp
@@ -3515,12 +3522,6 @@ N:       bcm586*
 N:     bcm88312
 N:     hr2
 N:     stingray
-F:     arch/arm64/boot/dts/broadcom/northstar2/*
-F:     arch/arm64/boot/dts/broadcom/stingray/*
-F:     drivers/clk/bcm/clk-ns*
-F:     drivers/clk/bcm/clk-sr*
-F:     drivers/pinctrl/bcm/pinctrl-ns*
-F:     include/dt-bindings/clock/bcm-sr*
 
 BROADCOM KONA GPIO DRIVER
 M:     Ray Jui <rjui@broadcom.com>
@@ -3535,8 +3536,8 @@ M:        Devesh Sharma <devesh.sharma@broadcom.com>
 M:     Somnath Kotur <somnath.kotur@broadcom.com>
 M:     Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
 L:     linux-rdma@vger.kernel.org
-W:     http://www.broadcom.com
 S:     Supported
+W:     http://www.broadcom.com
 F:     drivers/infiniband/hw/bnxt_re/
 F:     include/uapi/rdma/bnxt_re-abi.h
 
@@ -3553,6 +3554,15 @@ S:       Maintained
 F:     drivers/bcma/
 F:     include/linux/bcma/
 
+BROADCOM SPI DRIVER
+M:     Kamal Dasu <kdasu.kdev@gmail.com>
+M:     bcm-kernel-feedback-list@broadcom.com
+S:     Maintained
+F:     Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.txt
+F:     drivers/spi/spi-bcm-qspi.*
+F:     drivers/spi/spi-brcmstb-qspi.c
+F:     drivers/spi/spi-iproc-qspi.c
+
 BROADCOM STB AVS CPUFREQ DRIVER
 M:     Markus Mayer <mmayer@broadcom.com>
 M:     bcm-kernel-feedback-list@broadcom.com
@@ -3569,14 +3579,6 @@ S:       Maintained
 F:     Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
 F:     drivers/thermal/broadcom/brcmstb*
 
-BROADCOM STB NAND FLASH DRIVER
-M:     Brian Norris <computersforpeace@gmail.com>
-M:     Kamal Dasu <kdasu.kdev@gmail.com>
-L:     linux-mtd@lists.infradead.org
-L:     bcm-kernel-feedback-list@broadcom.com
-S:     Maintained
-F:     drivers/mtd/nand/raw/brcmnand/
-
 BROADCOM STB DPFE DRIVER
 M:     Markus Mayer <mmayer@broadcom.com>
 M:     bcm-kernel-feedback-list@broadcom.com
@@ -3585,14 +3587,13 @@ S:      Maintained
 F:     Documentation/devicetree/bindings/memory-controllers/brcm,dpfe-cpu.txt
 F:     drivers/memory/brcmstb_dpfe.c
 
-BROADCOM SPI DRIVER
+BROADCOM STB NAND FLASH DRIVER
+M:     Brian Norris <computersforpeace@gmail.com>
 M:     Kamal Dasu <kdasu.kdev@gmail.com>
-M:     bcm-kernel-feedback-list@broadcom.com
+L:     linux-mtd@lists.infradead.org
+L:     bcm-kernel-feedback-list@broadcom.com
 S:     Maintained
-F:     Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.txt
-F:     drivers/spi/spi-bcm-qspi.*
-F:     drivers/spi/spi-brcmstb-qspi.c
-F:     drivers/spi/spi-iproc-qspi.c
+F:     drivers/mtd/nand/raw/brcmnand/
 
 BROADCOM SYSTEMPORT ETHERNET DRIVER
 M:     Florian Fainelli <f.fainelli@gmail.com>
@@ -3635,8 +3636,8 @@ F:        include/uapi/linux/bsg.h
 BT87X AUDIO DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 F:     Documentation/sound/cards/bt87x.rst
 F:     sound/pci/bt87x.c
 
@@ -3651,10 +3652,10 @@ M:      Chris Mason <clm@fb.com>
 M:     Josef Bacik <josef@toxicpanda.com>
 M:     David Sterba <dsterba@suse.com>
 L:     linux-btrfs@vger.kernel.org
+S:     Maintained
 W:     http://btrfs.wiki.kernel.org/
 Q:     http://patchwork.kernel.org/project/linux-btrfs/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs.git
-S:     Maintained
 F:     Documentation/filesystems/btrfs.rst
 F:     fs/btrfs/
 F:     include/linux/btrfs*
@@ -3663,9 +3664,9 @@ F:        include/uapi/linux/btrfs*
 BTTV VIDEO4LINUX DRIVER
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-media@vger.kernel.org
+S:     Odd fixes
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Odd fixes
 F:     Documentation/media/v4l-drivers/bttv*
 F:     drivers/media/pci/bt8xx/bttv*
 
@@ -3673,10 +3674,10 @@ BUS FREQUENCY DRIVER FOR SAMSUNG EXYNOS
 M:     Chanwoo Choi <cw00.choi@samsung.com>
 L:     linux-pm@vger.kernel.org
 L:     linux-samsung-soc@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
 S:     Maintained
-F:     drivers/devfreq/exynos-bus.c
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
 F:     Documentation/devicetree/bindings/devfreq/exynos-bus.txt
+F:     drivers/devfreq/exynos-bus.c
 
 BUSLOGIC SCSI DRIVER
 M:     Khalid Aziz <khalid@gonehiking.org>
@@ -3688,40 +3689,40 @@ F:      drivers/scsi/FlashPoint.*
 C-MEDIA CMI8788 DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 F:     sound/pci/oxygen/
 
 C-SKY ARCHITECTURE
 M:     Guo Ren <guoren@kernel.org>
 L:     linux-csky@vger.kernel.org
-T:     git https://github.com/c-sky/csky-linux.git
 S:     Supported
-F:     arch/csky/
+T:     git https://github.com/c-sky/csky-linux.git
 F:     Documentation/devicetree/bindings/csky/
-F:     drivers/irqchip/irq-csky-*
 F:     Documentation/devicetree/bindings/interrupt-controller/csky,*
+F:     Documentation/devicetree/bindings/timer/csky,*
+F:     arch/csky/
 F:     drivers/clocksource/timer-gx6605s.c
 F:     drivers/clocksource/timer-mp-csky.c
-F:     Documentation/devicetree/bindings/timer/csky,*
-K:     csky
+F:     drivers/irqchip/irq-csky-*
 N:     csky
+K:     csky
 
 C6X ARCHITECTURE
 M:     Mark Salter <msalter@redhat.com>
 M:     Aurelien Jacquiot <jacquiot.aurelien@gmail.com>
 L:     linux-c6x-dev@linux-c6x.org
-W:     http://www.linux-c6x.org/wiki/index.php/Main_Page
 S:     Maintained
+W:     http://www.linux-c6x.org/wiki/index.php/Main_Page
 F:     arch/c6x/
 
 CA8210 IEEE-802.15.4 RADIO DRIVER
 M:     Harry Morris <h.morris@cascoda.com>
 L:     linux-wpan@vger.kernel.org
-W:     https://github.com/Cascoda/ca8210-linux.git
 S:     Maintained
-F:     drivers/net/ieee802154/ca8210.c
+W:     https://github.com/Cascoda/ca8210-linux.git
 F:     Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
+F:     drivers/net/ieee802154/ca8210.c
 
 CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS
 M:     David Howells <dhowells@redhat.com>
@@ -3741,22 +3742,22 @@ CADENCE NAND DRIVER
 M:     Piotr Sroka <piotrs@cadence.com>
 L:     linux-mtd@lists.infradead.org
 S:     Maintained
-F:     drivers/mtd/nand/raw/cadence-nand-controller.c
 F:     Documentation/devicetree/bindings/mtd/cadence-nand-controller.txt
+F:     drivers/mtd/nand/raw/cadence-nand-controller.c
 
 CADET FM/AM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/radio-cadet*
 
 CAFE CMOS INTEGRATED CAMERA CONTROLLER DRIVER
 M:     Jonathan Corbet <corbet@lwn.net>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/media/v4l-drivers/cafe_ccic*
 F:     drivers/media/platform/marvell-ccic/
 
@@ -3765,8 +3766,8 @@ L:        netdev@vger.kernel.org
 S:     Orphan
 F:     Documentation/networking/caif/
 F:     drivers/net/caif/
-F:     include/uapi/linux/caif/
 F:     include/net/caif/
+F:     include/uapi/linux/caif/
 F:     net/caif/
 
 CAKE QDISC
@@ -3779,16 +3780,16 @@ CAN NETWORK DRIVERS
 M:     Wolfgang Grandegger <wg@grandegger.com>
 M:     Marc Kleine-Budde <mkl@pengutronix.de>
 L:     linux-can@vger.kernel.org
+S:     Maintained
 W:     https://github.com/linux-can
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
-S:     Maintained
 F:     Documentation/devicetree/bindings/net/can/
 F:     drivers/net/can/
 F:     include/linux/can/dev.h
 F:     include/linux/can/led.h
-F:     include/linux/can/rx-offload.h
 F:     include/linux/can/platform/
+F:     include/linux/can/rx-offload.h
 F:     include/uapi/linux/can/error.h
 F:     include/uapi/linux/can/netlink.h
 F:     include/uapi/linux/can/vxcan.h
@@ -3797,19 +3798,19 @@ CAN NETWORK LAYER
 M:     Oliver Hartkopp <socketcan@hartkopp.net>
 M:     Marc Kleine-Budde <mkl@pengutronix.de>
 L:     linux-can@vger.kernel.org
+S:     Maintained
 W:     https://github.com/linux-can
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
-S:     Maintained
 F:     Documentation/networking/can.rst
-F:     net/can/
 F:     include/linux/can/core.h
 F:     include/linux/can/skb.h
 F:     include/net/netns/can.h
 F:     include/uapi/linux/can.h
 F:     include/uapi/linux/can/bcm.h
-F:     include/uapi/linux/can/raw.h
 F:     include/uapi/linux/can/gw.h
+F:     include/uapi/linux/can/raw.h
+F:     net/can/
 
 CAN-J1939 NETWORK LAYER
 M:     Robin van der Gracht <robin@protonic.nl>
@@ -3818,8 +3819,8 @@ R:        Pengutronix Kernel Team <kernel@pengutronix.de>
 L:     linux-can@vger.kernel.org
 S:     Maintained
 F:     Documentation/networking/j1939.rst
-F:     net/can/j1939/
 F:     include/uapi/linux/can/j1939.h
+F:     net/can/j1939/
 
 CAPABILITIES
 M:     Serge Hallyn <serge@hallyn.com>
@@ -3827,8 +3828,8 @@ L:        linux-security-module@vger.kernel.org
 S:     Supported
 F:     include/linux/capability.h
 F:     include/uapi/linux/capability.h
-F:     security/commoncap.c
 F:     kernel/capability.c
+F:     security/commoncap.c
 
 CAPELLA MICROSYSTEMS LIGHT SENSOR DRIVER
 M:     Kevin Tsai <ktsai@capellamicro.com>
@@ -3838,14 +3839,14 @@ F:      drivers/iio/light/cm*
 CARL9170 LINUX COMMUNITY WIRELESS DRIVER
 M:     Christian Lamparter <chunkeey@googlemail.com>
 L:     linux-wireless@vger.kernel.org
-W:     http://wireless.kernel.org/en/users/Drivers/carl9170
 S:     Maintained
+W:     http://wireless.kernel.org/en/users/Drivers/carl9170
 F:     drivers/net/wireless/ath/carl9170/
 
 CAVIUM I2C DRIVER
 M:     Robert Richter <rrichter@marvell.com>
-W:     http://www.marvell.com
 S:     Supported
+W:     http://www.marvell.com
 F:     drivers/i2c/busses/i2c-octeon*
 F:     drivers/i2c/busses/i2c-thunderx*
 
@@ -3854,76 +3855,76 @@ M:      Derek Chickles <dchickles@marvell.com>
 M:     Satanand Burla <sburla@marvell.com>
 M:     Felix Manlunas <fmanlunas@marvell.com>
 L:     netdev@vger.kernel.org
-W:     http://www.marvell.com
 S:     Supported
+W:     http://www.marvell.com
 F:     drivers/net/ethernet/cavium/liquidio/
 
 CAVIUM MMC DRIVER
 M:     Robert Richter <rrichter@marvell.com>
-W:     http://www.marvell.com
 S:     Supported
+W:     http://www.marvell.com
 F:     drivers/mmc/host/cavium*
 
 CAVIUM OCTEON-TX CRYPTO DRIVER
 M:     George Cherian <gcherian@marvell.com>
 L:     linux-crypto@vger.kernel.org
-W:     http://www.marvell.com
 S:     Supported
+W:     http://www.marvell.com
 F:     drivers/crypto/cavium/cpt/
 
 CAVIUM THUNDERX2 ARM64 SOC
 M:     Robert Richter <rrichter@marvell.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm64/boot/dts/cavium/thunder2-99xx*
 F:     Documentation/devicetree/bindings/arm/cavium-thunder2.txt
+F:     arch/arm64/boot/dts/cavium/thunder2-99xx*
 
 CC2520 IEEE-802.15.4 RADIO DRIVER
 M:     Varka Bhadram <varkabhadram@gmail.com>
 L:     linux-wpan@vger.kernel.org
 S:     Maintained
+F:     Documentation/devicetree/bindings/net/ieee802154/cc2520.txt
 F:     drivers/net/ieee802154/cc2520.c
 F:     include/linux/spi/cc2520.h
-F:     Documentation/devicetree/bindings/net/ieee802154/cc2520.txt
 
 CCREE ARM TRUSTZONE CRYPTOCELL REE DRIVER
 M:     Gilad Ben-Yossef <gilad@benyossef.com>
 L:     linux-crypto@vger.kernel.org
 S:     Supported
-F:     drivers/crypto/ccree/
 W:     https://developer.arm.com/products/system-ip/trustzone-cryptocell/cryptocell-700-family
+F:     drivers/crypto/ccree/
 
 CEC FRAMEWORK
 M:     Hans Verkuil <hverkuil-cisco@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
 S:     Supported
+W:     http://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
+F:     Documentation/ABI/testing/debugfs-cec-error-inj
+F:     Documentation/devicetree/bindings/media/cec.txt
 F:     Documentation/media/kapi/cec-core.rst
 F:     Documentation/media/uapi/cec
 F:     drivers/media/cec/
 F:     drivers/media/rc/keymaps/rc-cec.c
-F:     include/media/cec.h
 F:     include/media/cec-notifier.h
-F:     include/uapi/linux/cec.h
+F:     include/media/cec.h
 F:     include/uapi/linux/cec-funcs.h
-F:     Documentation/devicetree/bindings/media/cec.txt
-F:     Documentation/ABI/testing/debugfs-cec-error-inj
+F:     include/uapi/linux/cec.h
 
 CEC GPIO DRIVER
 M:     Hans Verkuil <hverkuil-cisco@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
 S:     Supported
-F:     drivers/media/platform/cec-gpio/
+W:     http://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/cec-gpio.txt
+F:     drivers/media/platform/cec-gpio/
 
 CELL BROADBAND ENGINE ARCHITECTURE
 M:     Arnd Bergmann <arnd@arndb.de>
 L:     linuxppc-dev@lists.ozlabs.org
-W:     http://www.ibm.com/developerworks/power/cell/
 S:     Supported
+W:     http://www.ibm.com/developerworks/power/cell/
 F:     arch/powerpc/include/asm/cell*.h
 F:     arch/powerpc/include/asm/spu*.h
 F:     arch/powerpc/include/uapi/asm/spu*.h
@@ -3935,23 +3936,23 @@ M:      Ilya Dryomov <idryomov@gmail.com>
 M:     Jeff Layton <jlayton@kernel.org>
 M:     Sage Weil <sage@redhat.com>
 L:     ceph-devel@vger.kernel.org
+S:     Supported
 W:     http://ceph.com/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
 T:     git git://github.com/ceph/ceph-client.git
-S:     Supported
-F:     net/ceph/
 F:     include/linux/ceph/
 F:     include/linux/crush/
+F:     net/ceph/
 
 CEPH DISTRIBUTED FILE SYSTEM CLIENT (CEPH)
 M:     Jeff Layton <jlayton@kernel.org>
 M:     Sage Weil <sage@redhat.com>
 M:     Ilya Dryomov <idryomov@gmail.com>
 L:     ceph-devel@vger.kernel.org
+S:     Supported
 W:     http://ceph.com/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
 T:     git git://github.com/ceph/ceph-client.git
-S:     Supported
 F:     Documentation/filesystems/ceph.rst
 F:     fs/ceph/
 
@@ -3962,8 +3963,8 @@ L:        keyrings@vger.kernel.org
 S:     Maintained
 F:     Documentation/admin-guide/module-signing.rst
 F:     certs/
-F:     scripts/sign-file.c
 F:     scripts/extract-cert.c
+F:     scripts/sign-file.c
 
 CFAG12864B LCD DRIVER
 M:     Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>
@@ -3977,28 +3978,11 @@ S:      Maintained
 F:     drivers/auxdisplay/cfag12864bfb.c
 F:     include/linux/cfag12864b.h
 
-802.11 (including CFG80211/NL80211)
-M:     Johannes Berg <johannes@sipsolutions.net>
-L:     linux-wireless@vger.kernel.org
-W:     http://wireless.kernel.org/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
-S:     Maintained
-F:     net/wireless/
-F:     include/uapi/linux/nl80211.h
-F:     include/linux/ieee80211.h
-F:     include/net/wext.h
-F:     include/net/cfg80211.h
-F:     include/net/iw_handler.h
-F:     include/net/ieee80211_radiotap.h
-F:     Documentation/driver-api/80211/cfg80211.rst
-F:     Documentation/networking/regulatory.txt
-
 CHAR and MISC DRIVERS
 M:     Arnd Bergmann <arnd@arndb.de>
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git
 F:     drivers/char/
 F:     drivers/misc/
 F:     include/linux/miscdevice.h
@@ -4018,9 +4002,9 @@ F:        Documentation/translations/zh_CN/
 
 CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER
 M:     Peter Chen <Peter.Chen@nxp.com>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
 L:     linux-usb@vger.kernel.org
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
 F:     drivers/usb/chipidea/
 
 CHIPONE ICN8318 I2C TOUCHSCREEN DRIVER
@@ -4043,22 +4027,22 @@ S:      Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git
 F:     drivers/platform/chrome/
 
+CHROMEOS EC CODEC DRIVER
+M:     Cheng-Yi Chiang <cychiang@chromium.org>
+R:     Enric Balletbo i Serra <enric.balletbo@collabora.com>
+R:     Guenter Roeck <groeck@chromium.org>
+S:     Maintained
+F:     Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml
+F:     sound/soc/codecs/cros_ec_codec.*
+
 CHROMEOS EC SUBDRIVERS
 M:     Benson Leung <bleung@chromium.org>
 M:     Enric Balletbo i Serra <enric.balletbo@collabora.com>
 R:     Guenter Roeck <groeck@chromium.org>
 S:     Maintained
+F:     drivers/power/supply/cros_usbpd-charger.c
 N:     cros_ec
 N:     cros-ec
-F:     drivers/power/supply/cros_usbpd-charger.c
-
-CHROMEOS EC CODEC DRIVER
-M:     Cheng-Yi Chiang <cychiang@chromium.org>
-S:     Maintained
-R:     Enric Balletbo i Serra <enric.balletbo@collabora.com>
-R:     Guenter Roeck <groeck@chromium.org>
-F:     Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml
-F:     sound/soc/codecs/cros_ec_codec.*
 
 CIRRUS LOGIC AUDIO CODEC DRIVERS
 M:     James Schulman <james.schulman@cirrus.com>
@@ -4078,22 +4062,45 @@ M:      Charles Keepax <ckeepax@opensource.cirrus.com>
 M:     Richard Fitzgerald <rf@opensource.cirrus.com>
 L:     patches@opensource.cirrus.com
 S:     Supported
+F:     Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt
+F:     Documentation/devicetree/bindings/hwmon/cirrus,lochnagar.txt
+F:     Documentation/devicetree/bindings/mfd/cirrus,lochnagar.txt
+F:     Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.txt
+F:     Documentation/devicetree/bindings/regulator/cirrus,lochnagar.txt
+F:     Documentation/devicetree/bindings/sound/cirrus,lochnagar.txt
+F:     Documentation/hwmon/lochnagar.rst
 F:     drivers/clk/clk-lochnagar.c
 F:     drivers/hwmon/lochnagar-hwmon.c
 F:     drivers/mfd/lochnagar-i2c.c
 F:     drivers/pinctrl/cirrus/pinctrl-lochnagar.c
 F:     drivers/regulator/lochnagar-regulator.c
-F:     sound/soc/codecs/lochnagar-sc.c
 F:     include/dt-bindings/clk/lochnagar.h
 F:     include/dt-bindings/pinctrl/lochnagar.h
 F:     include/linux/mfd/lochnagar*
-F:     Documentation/devicetree/bindings/mfd/cirrus,lochnagar.txt
-F:     Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt
-F:     Documentation/devicetree/bindings/hwmon/cirrus,lochnagar.txt
-F:     Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.txt
-F:     Documentation/devicetree/bindings/regulator/cirrus,lochnagar.txt
-F:     Documentation/devicetree/bindings/sound/cirrus,lochnagar.txt
-F:     Documentation/hwmon/lochnagar.rst
+F:     sound/soc/codecs/lochnagar-sc.c
+
+CIRRUS LOGIC MADERA CODEC DRIVERS
+M:     Charles Keepax <ckeepax@opensource.cirrus.com>
+M:     Richard Fitzgerald <rf@opensource.cirrus.com>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+L:     patches@opensource.cirrus.com
+S:     Supported
+W:     https://github.com/CirrusLogic/linux-drivers/wiki
+T:     git https://github.com/CirrusLogic/linux-drivers.git
+F:     Documentation/devicetree/bindings/mfd/madera.txt
+F:     Documentation/devicetree/bindings/pinctrl/cirrus,madera-pinctrl.txt
+F:     Documentation/devicetree/bindings/sound/madera.txt
+F:     drivers/gpio/gpio-madera*
+F:     drivers/irqchip/irq-madera*
+F:     drivers/mfd/cs47l*
+F:     drivers/mfd/madera*
+F:     drivers/pinctrl/cirrus/*
+F:     include/dt-bindings/sound/madera*
+F:     include/linux/irqchip/irq-madera*
+F:     include/linux/mfd/madera/*
+F:     include/sound/madera*
+F:     sound/soc/codecs/cs47l*
+F:     sound/soc/codecs/madera*
 
 CISCO FCOE HBA DRIVER
 M:     Satish Kharat <satishkh@cisco.com>
@@ -4123,29 +4130,6 @@ M:       Parvi Kaustubhi <pkaustub@cisco.com>
 S:     Supported
 F:     drivers/infiniband/hw/usnic/
 
-CIRRUS LOGIC MADERA CODEC DRIVERS
-M:     Charles Keepax <ckeepax@opensource.cirrus.com>
-M:     Richard Fitzgerald <rf@opensource.cirrus.com>
-L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-L:     patches@opensource.cirrus.com
-T:     git https://github.com/CirrusLogic/linux-drivers.git
-W:     https://github.com/CirrusLogic/linux-drivers/wiki
-S:     Supported
-F:     Documentation/devicetree/bindings/mfd/madera.txt
-F:     Documentation/devicetree/bindings/pinctrl/cirrus,madera-pinctrl.txt
-F:     Documentation/devicetree/bindings/sound/madera.txt
-F:     include/dt-bindings/sound/madera*
-F:     include/linux/irqchip/irq-madera*
-F:     include/linux/mfd/madera/*
-F:     include/sound/madera*
-F:     drivers/gpio/gpio-madera*
-F:     drivers/irqchip/irq-madera*
-F:     drivers/mfd/madera*
-F:     drivers/mfd/cs47l*
-F:     drivers/pinctrl/cirrus/*
-F:     sound/soc/codecs/cs47l*
-F:     sound/soc/codecs/madera*
-
 CLANG-FORMAT FILE
 M:     Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
 S:     Maintained
@@ -4153,19 +4137,19 @@ F:      .clang-format
 
 CLANG/LLVM BUILD SUPPORT
 L:     clang-built-linux@googlegroups.com
+S:     Supported
 W:     https://clangbuiltlinux.github.io/
 B:     https://github.com/ClangBuiltLinux/linux/issues
 C:     irc://chat.freenode.net/clangbuiltlinux
-S:     Supported
-K:     \b(?i:clang|llvm)\b
 F:     Documentation/kbuild/llvm.rst
+K:     \b(?i:clang|llvm)\b
 
 CLEANCACHE API
 M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
-F:     mm/cleancache.c
 F:     include/linux/cleancache.h
+F:     mm/cleancache.c
 
 CLK API
 M:     Russell King <linux@armlinux.org.uk>
@@ -4177,10 +4161,10 @@ CLOCKSOURCE, CLOCKEVENT DRIVERS
 M:     Daniel Lezcano <daniel.lezcano@linaro.org>
 M:     Thomas Gleixner <tglx@linutronix.de>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 S:     Supported
-F:     drivers/clocksource/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 F:     Documentation/devicetree/bindings/timer/
+F:     drivers/clocksource/
 
 CMPC ACPI DRIVER
 M:     Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
@@ -4192,9 +4176,9 @@ F:        drivers/platform/x86/classmate-laptop.c
 COBALT MEDIA DRIVER
 M:     Hans Verkuil <hverkuil-cisco@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Supported
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/pci/cobalt/
 
 COCCINELLE/Semantic Patches (SmPL)
@@ -4203,19 +4187,19 @@ M:      Gilles Muller <Gilles.Muller@lip6.fr>
 M:     Nicolas Palix <nicolas.palix@imag.fr>
 M:     Michal Marek <michal.lkml@markovi.net>
 L:     cocci@systeme.lip6.fr (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git misc
-W:     http://coccinelle.lip6.fr/
 S:     Supported
+W:     http://coccinelle.lip6.fr/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git misc
 F:     Documentation/dev-tools/coccinelle.rst
-F:     scripts/coccinelle/
 F:     scripts/coccicheck
+F:     scripts/coccinelle/
 
 CODA FILE SYSTEM
 M:     Jan Harkes <jaharkes@cs.cmu.edu>
 M:     coda@cs.cmu.edu
 L:     codalist@coda.cs.cmu.edu
-W:     http://www.coda.cs.cmu.edu/
 S:     Maintained
+W:     http://www.coda.cs.cmu.edu/
 F:     Documentation/filesystems/coda.txt
 F:     fs/coda/
 F:     include/linux/coda*.h
@@ -4231,30 +4215,30 @@ F:      drivers/media/platform/coda/
 CODE OF CONDUCT
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 S:     Supported
-F:     Documentation/process/code-of-conduct.rst
 F:     Documentation/process/code-of-conduct-interpretation.rst
+F:     Documentation/process/code-of-conduct.rst
 
 COMMON CLK FRAMEWORK
 M:     Michael Turquette <mturquette@baylibre.com>
 M:     Stephen Boyd <sboyd@kernel.org>
 L:     linux-clk@vger.kernel.org
+S:     Maintained
 Q:     http://patchwork.kernel.org/project/linux-clk/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git
-S:     Maintained
 F:     Documentation/devicetree/bindings/clock/
 F:     drivers/clk/
-X:     drivers/clk/clkdev.c
 F:     include/linux/clk-pr*
 F:     include/linux/clk/
 F:     include/linux/of_clk.h
+X:     drivers/clk/clkdev.c
 
 COMMON INTERNET FILE SYSTEM (CIFS)
 M:     Steve French <sfrench@samba.org>
 L:     linux-cifs@vger.kernel.org
 L:     samba-technical@lists.samba.org (moderated for non-subscribers)
+S:     Supported
 W:     http://linux-cifs.samba.org/
 T:     git git://git.samba.org/sfrench/cifs-2.6.git
-S:     Supported
 F:     Documentation/admin-guide/cifs/
 F:     fs/cifs/
 
@@ -4289,15 +4273,15 @@ F:      include/linux/compiler_attributes.h
 
 CONEXANT ACCESSRUNNER USB DRIVER
 L:     accessrunner-general@lists.sourceforge.net
-W:     http://accessrunner.sourceforge.net/
 S:     Orphan
+W:     http://accessrunner.sourceforge.net/
 F:     drivers/usb/atm/cxacru.c
 
 CONFIGFS
 M:     Joel Becker <jlbec@evilplan.org>
 M:     Christoph Hellwig <hch@lst.de>
-T:     git git://git.infradead.org/users/hch/configfs.git
 S:     Supported
+T:     git git://git.infradead.org/users/hch/configfs.git
 F:     fs/configfs/
 F:     include/linux/configfs.h
 
@@ -4312,20 +4296,33 @@ M:      Tejun Heo <tj@kernel.org>
 M:     Li Zefan <lizefan@huawei.com>
 M:     Johannes Weiner <hannes@cmpxchg.org>
 L:     cgroups@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
 S:     Maintained
-F:     Documentation/admin-guide/cgroup-v2.rst
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
 F:     Documentation/admin-guide/cgroup-v1/
+F:     Documentation/admin-guide/cgroup-v2.rst
 F:     include/linux/cgroup*
 F:     kernel/cgroup/
 
+CONTROL GROUP - BLOCK IO CONTROLLER (BLKIO)
+M:     Tejun Heo <tj@kernel.org>
+M:     Jens Axboe <axboe@kernel.dk>
+L:     cgroups@vger.kernel.org
+L:     linux-block@vger.kernel.org
+T:     git git://git.kernel.dk/linux-block
+F:     Documentation/admin-guide/cgroup-v1/blkio-controller.rst
+F:     block/bfq-cgroup.c
+F:     block/blk-cgroup.c
+F:     block/blk-iolatency.c
+F:     block/blk-throttle.c
+F:     include/linux/blk-cgroup.h
+
 CONTROL GROUP - CPUSET
 M:     Li Zefan <lizefan@huawei.com>
 L:     cgroups@vger.kernel.org
+S:     Maintained
 W:     http://www.bullopensource.org/cpuset/
 W:     http://oss.sgi.com/projects/cpusets/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
-S:     Maintained
 F:     Documentation/admin-guide/cgroup-v1/cpusets.rst
 F:     include/linux/cpuset.h
 F:     kernel/cgroup/cpuset.c
@@ -4340,19 +4337,6 @@ S:       Maintained
 F:     mm/memcontrol.c
 F:     mm/swap_cgroup.c
 
-CONTROL GROUP - BLOCK IO CONTROLLER (BLKIO)
-M:     Tejun Heo <tj@kernel.org>
-M:     Jens Axboe <axboe@kernel.dk>
-L:     cgroups@vger.kernel.org
-L:     linux-block@vger.kernel.org
-T:     git git://git.kernel.dk/linux-block
-F:     Documentation/admin-guide/cgroup-v1/blkio-controller.rst
-F:     block/blk-cgroup.c
-F:     include/linux/blk-cgroup.h
-F:     block/blk-throttle.c
-F:     block/blk-iolatency.c
-F:     block/bfq-cgroup.c
-
 CORETEMP HARDWARE MONITORING DRIVER
 M:     Fenghua Yu <fenghua.yu@intel.com>
 L:     linux-hwmon@vger.kernel.org
@@ -4362,8 +4346,8 @@ F:        drivers/hwmon/coretemp.c
 
 COSA/SRP SYNC SERIAL DRIVER
 M:     Jan "Yenya" Kasprzak <kas@fi.muni.cz>
-W:     http://www.fi.muni.cz/~kas/cosa/
 S:     Maintained
+W:     http://www.fi.muni.cz/~kas/cosa/
 F:     drivers/net/wan/cosa*
 
 COUNTER SUBSYSTEM
@@ -4382,31 +4366,43 @@ L:      netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/ti/cpmac.c
 
+CPU FREQUENCY DRIVERS - VEXPRESS SPC ARM BIG LITTLE
+M:     Viresh Kumar <viresh.kumar@linaro.org>
+M:     Sudeep Holla <sudeep.holla@arm.com>
+L:     linux-pm@vger.kernel.org
+S:     Maintained
+W:     http://www.arm.com/products/processors/technologies/biglittleprocessing.php
+F:     drivers/cpufreq/vexpress-spc-cpufreq.c
+
 CPU FREQUENCY SCALING FRAMEWORK
 M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
 M:     Viresh Kumar <viresh.kumar@linaro.org>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
+B:     https://bugzilla.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git (For ARM Updates)
-B:     https://bugzilla.kernel.org
 F:     Documentation/admin-guide/pm/cpufreq.rst
 F:     Documentation/admin-guide/pm/intel_pstate.rst
 F:     Documentation/cpu-freq/
 F:     Documentation/devicetree/bindings/cpufreq/
 F:     drivers/cpufreq/
-F:     kernel/sched/cpufreq*.c
 F:     include/linux/cpufreq.h
 F:     include/linux/sched/cpufreq.h
+F:     kernel/sched/cpufreq*.c
 F:     tools/testing/selftests/cpufreq/
 
-CPU FREQUENCY DRIVERS - VEXPRESS SPC ARM BIG LITTLE
-M:     Viresh Kumar <viresh.kumar@linaro.org>
-M:     Sudeep Holla <sudeep.holla@arm.com>
+CPU IDLE TIME MANAGEMENT FRAMEWORK
+M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
+M:     Daniel Lezcano <daniel.lezcano@linaro.org>
 L:     linux-pm@vger.kernel.org
-W:     http://www.arm.com/products/processors/technologies/biglittleprocessing.php
 S:     Maintained
-F:     drivers/cpufreq/vexpress-spc-cpufreq.c
+B:     https://bugzilla.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+F:     Documentation/admin-guide/pm/cpuidle.rst
+F:     Documentation/driver-api/pm/cpuidle.rst
+F:     drivers/cpuidle/*
+F:     include/linux/cpuidle.h
 
 CPU POWER MONITORING SUBSYSTEM
 M:     Thomas Renninger <trenn@suse.com>
@@ -4427,8 +4423,8 @@ M:        Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
 M:     Daniel Lezcano <daniel.lezcano@linaro.org>
 L:     linux-pm@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
 F:     drivers/cpuidle/cpuidle-big_little.c
 
 CPUIDLE DRIVER - ARM EXYNOS
@@ -4438,8 +4434,8 @@ M:        Kukjin Kim <kgene@kernel.org>
 L:     linux-pm@vger.kernel.org
 L:     linux-samsung-soc@vger.kernel.org
 S:     Supported
-F:     drivers/cpuidle/cpuidle-exynos.c
 F:     arch/arm/mach-exynos/pm.c
+F:     drivers/cpuidle/cpuidle-exynos.c
 
 CPUIDLE DRIVER - ARM PSCI
 M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
@@ -4449,18 +4445,6 @@ L:       linux-arm-kernel@lists.infradead.org
 S:     Supported
 F:     drivers/cpuidle/cpuidle-psci.c
 
-CPU IDLE TIME MANAGEMENT FRAMEWORK
-M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
-M:     Daniel Lezcano <daniel.lezcano@linaro.org>
-L:     linux-pm@vger.kernel.org
-S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
-B:     https://bugzilla.kernel.org
-F:     Documentation/admin-guide/pm/cpuidle.rst
-F:     Documentation/driver-api/pm/cpuidle.rst
-F:     drivers/cpuidle/*
-F:     include/linux/cpuidle.h
-
 CRAMFS FILESYSTEM
 M:     Nicolas Pitre <nico@fluxnic.net>
 S:     Maintained
@@ -4477,9 +4461,9 @@ CRYPTO API
 M:     Herbert Xu <herbert@gondor.apana.org.au>
 M:     "David S. Miller" <davem@davemloft.net>
 L:     linux-crypto@vger.kernel.org
+S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6.git
-S:     Maintained
 F:     Documentation/crypto/
 F:     Documentation/devicetree/bindings/crypto/
 F:     arch/*/crypto/
@@ -4499,9 +4483,9 @@ F:        crypto/rng.c
 CS3308 MEDIA DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
 S:     Odd Fixes
+W:     http://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/cs3308.c
 
 CS5535 Audio ALSA driver
@@ -4512,10 +4496,10 @@ F:      sound/pci/cs5535audio/
 CSI DRIVERS FOR ALLWINNER V3s
 M:     Yong Deng <yong.deng@magewell.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/platform/sunxi/sun6i-csi/
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml
+F:     drivers/media/platform/sunxi/sun6i-csi/
 
 CW1200 WLAN driver
 M:     Solomon Peachy <pizza@shaftnet.org>
@@ -4525,18 +4509,18 @@ F:      drivers/net/wireless/st/cw1200/
 CX18 VIDEO4LINUX DRIVER
 M:     Andy Walls <awalls@md.metrocast.net>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/pci/cx18/
 F:     include/uapi/linux/ivtv*
 
 CX2341X MPEG ENCODER HELPER MODULE
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/common/cx2341x*
 F:     include/media/drv-intf/cx2341x.h
 
@@ -4544,42 +4528,42 @@ CX24120 MEDIA DRIVER
 M:     Jemma Denson <jdenson@gmail.com>
 M:     Patrick Boettcher <patrick.boettcher@posteo.de>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-S:     Maintained
 F:     drivers/media/dvb-frontends/cx24120*
 
 CX88 VIDEO4LINUX DRIVER
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-media@vger.kernel.org
+S:     Odd fixes
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Odd fixes
 F:     Documentation/media/v4l-drivers/cx88*
 F:     drivers/media/pci/cx88/
 
 CXD2820R MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/dvb-frontends/cxd2820r*
 
 CXGB3 ETHERNET DRIVER (CXGB3)
 M:     Vishal Kulkarni <vishal@chelsio.com>
 L:     netdev@vger.kernel.org
-W:     http://www.chelsio.com
 S:     Supported
+W:     http://www.chelsio.com
 F:     drivers/net/ethernet/chelsio/cxgb3/
 
 CXGB3 ISCSI DRIVER (CXGB3I)
 M:     Karen Xie <kxie@chelsio.com>
 L:     linux-scsi@vger.kernel.org
-W:     http://www.chelsio.com
 S:     Supported
+W:     http://www.chelsio.com
 F:     drivers/scsi/cxgbi/cxgb3i
 
 CXGB4 CRYPTO DRIVER (chcr)
@@ -4587,37 +4571,37 @@ M:      Ayush Sawal <ayush.sawal@chelsio.com>
 M:     Vinay Kumar Yadav <vinay.yadav@chelsio.com>
 M:     Rohit Maheshwari <rohitm@chelsio.com>
 L:     linux-crypto@vger.kernel.org
-W:     http://www.chelsio.com
 S:     Supported
+W:     http://www.chelsio.com
 F:     drivers/crypto/chelsio
 
 CXGB4 ETHERNET DRIVER (CXGB4)
 M:     Vishal Kulkarni <vishal@chelsio.com>
 L:     netdev@vger.kernel.org
-W:     http://www.chelsio.com
 S:     Supported
+W:     http://www.chelsio.com
 F:     drivers/net/ethernet/chelsio/cxgb4/
 
 CXGB4 ISCSI DRIVER (CXGB4I)
 M:     Karen Xie <kxie@chelsio.com>
 L:     linux-scsi@vger.kernel.org
-W:     http://www.chelsio.com
 S:     Supported
+W:     http://www.chelsio.com
 F:     drivers/scsi/cxgbi/cxgb4i
 
 CXGB4 IWARP RNIC DRIVER (IW_CXGB4)
 M:     Potnuri Bharat Teja <bharat@chelsio.com>
 L:     linux-rdma@vger.kernel.org
-W:     http://www.openfabrics.org
 S:     Supported
+W:     http://www.openfabrics.org
 F:     drivers/infiniband/hw/cxgb4/
 F:     include/uapi/rdma/cxgb4-abi.h
 
 CXGB4VF ETHERNET DRIVER (CXGB4VF)
 M:     Vishal Kulkarni <vishal@gmail.com>
 L:     netdev@vger.kernel.org
-W:     http://www.chelsio.com
 S:     Supported
+W:     http://www.chelsio.com
 F:     drivers/net/ethernet/chelsio/cxgb4vf/
 
 CXL (IBM Coherent Accelerator Processor Interface CAPI) DRIVER
@@ -4625,12 +4609,12 @@ M:      Frederic Barrat <fbarrat@linux.ibm.com>
 M:     Andrew Donnellan <ajd@linux.ibm.com>
 L:     linuxppc-dev@lists.ozlabs.org
 S:     Supported
+F:     Documentation/ABI/testing/sysfs-class-cxl
+F:     Documentation/powerpc/cxl.rst
 F:     arch/powerpc/platforms/powernv/pci-cxl.c
 F:     drivers/misc/cxl/
 F:     include/misc/cxl*
 F:     include/uapi/misc/cxl.h
-F:     Documentation/powerpc/cxl.rst
-F:     Documentation/ABI/testing/sysfs-class-cxl
 
 CXLFLASH (IBM Coherent Accelerator Processor Interface CAPI Flash) SCSI DRIVER
 M:     Manoj N. Kumar <manoj@linux.ibm.com>
@@ -4638,37 +4622,37 @@ M:      Matthew R. Ochs <mrochs@linux.ibm.com>
 M:     Uma Krishnan <ukrishn@linux.ibm.com>
 L:     linux-scsi@vger.kernel.org
 S:     Supported
+F:     Documentation/powerpc/cxlflash.rst
 F:     drivers/scsi/cxlflash/
 F:     include/uapi/scsi/cxlflash_ioctl.h
-F:     Documentation/powerpc/cxlflash.rst
 
 CYBERPRO FB DRIVER
 M:     Russell King <linux@armlinux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.armlinux.org.uk/
 S:     Maintained
+W:     http://www.armlinux.org.uk/
 F:     drivers/video/fbdev/cyber2000fb.*
 
 CYCLADES ASYNC MUX DRIVER
-W:     http://www.cyclades.com/
 S:     Orphan
+W:     http://www.cyclades.com/
 F:     drivers/tty/cyclades.c
 F:     include/linux/cyclades.h
 F:     include/uapi/linux/cyclades.h
 
 CYCLADES PC300 DRIVER
-W:     http://www.cyclades.com/
 S:     Orphan
+W:     http://www.cyclades.com/
 F:     drivers/net/wan/pc300*
 
 CYPRESS_FIRMWARE MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/common/cypress_firmware*
 
 CYTTSP TOUCHSCREEN DRIVER
@@ -4692,10 +4676,10 @@ F:      include/linux/rtc/ds1685.h
 
 DAMA SLAVE for AX.25
 M:     Joerg Reuter <jreuter@yaina.de>
-W:     http://yaina.de/jreuter/
-W:     http://www.qsl.net/dl1bke/
 L:     linux-hams@vger.kernel.org
 S:     Maintained
+W:     http://yaina.de/jreuter/
+W:     http://www.qsl.net/dl1bke/
 F:     net/ax25/af_ax25.c
 F:     net/ax25/ax25_dev.c
 F:     net/ax25/ax25_ds_*
@@ -4721,34 +4705,34 @@ M:      Oliver Neukum <oliver@neukum.org>
 M:     Ali Akcaagac <aliakc@web.de>
 M:     Jamie Lenehan <lenehan@twibble.org>
 L:     dc395x@twibble.org
+S:     Maintained
 W:     http://twibble.org/dist/dc395x/
 W:     http://lists.twibble.org/mailman/listinfo/dc395x/
-S:     Maintained
 F:     Documentation/scsi/dc395x.rst
 F:     drivers/scsi/dc395x.*
 
 DCCP PROTOCOL
 M:     Gerrit Renker <gerrit@erg.abdn.ac.uk>
 L:     dccp@vger.kernel.org
-W:     http://www.linuxfoundation.org/collaborate/workgroups/networking/dccp
 S:     Maintained
+W:     http://www.linuxfoundation.org/collaborate/workgroups/networking/dccp
 F:     include/linux/dccp.h
-F:     include/uapi/linux/dccp.h
 F:     include/linux/tfrc.h
+F:     include/uapi/linux/dccp.h
 F:     net/dccp/
 
 DECnet NETWORK LAYER
-W:     http://linux-decnet.sourceforge.net
 L:     linux-decnet-user@lists.sourceforge.net
 S:     Orphan
+W:     http://linux-decnet.sourceforge.net
 F:     Documentation/networking/decnet.txt
 F:     net/decnet/
 
 DECSTATION PLATFORM SUPPORT
 M:     "Maciej W. Rozycki" <macro@linux-mips.org>
 L:     linux-mips@vger.kernel.org
-W:     http://www.linux-mips.org/wiki/DECstation
 S:     Maintained
+W:     http://www.linux-mips.org/wiki/DECstation
 F:     arch/mips/dec/
 F:     arch/mips/include/asm/dec/
 F:     arch/mips/include/asm/mach-dec/
@@ -4758,38 +4742,38 @@ M:      "Maciej W. Rozycki" <macro@linux-mips.org>
 S:     Maintained
 F:     drivers/net/fddi/defxx.*
 
+DEFZA FDDI NETWORK DRIVER
+M:     "Maciej W. Rozycki" <macro@linux-mips.org>
+S:     Maintained
+F:     drivers/net/fddi/defza.*
+
 DEINTERLACE DRIVERS FOR ALLWINNER H3
 M:     Jernej Skrabec <jernej.skrabec@siol.net>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/platform/sunxi/sun8i-di/
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/allwinner,sun8i-h3-deinterlace.yaml
-
-DEFZA FDDI NETWORK DRIVER
-M:     "Maciej W. Rozycki" <macro@linux-mips.org>
-S:     Maintained
-F:     drivers/net/fddi/defza.*
+F:     drivers/media/platform/sunxi/sun8i-di/
 
 DELL LAPTOP DRIVER
 M:     Matthew Garrett <mjg59@srcf.ucam.org>
-M:     Pali Rohár <pali.rohar@gmail.com>
+M:     Pali Rohár <pali@kernel.org>
 L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
 F:     drivers/platform/x86/dell-laptop.c
 
 DELL LAPTOP FREEFALL DRIVER
-M:     Pali Rohár <pali.rohar@gmail.com>
+M:     Pali Rohár <pali@kernel.org>
 S:     Maintained
 F:     drivers/platform/x86/dell-smo8800.c
 
 DELL LAPTOP RBTN DRIVER
-M:     Pali Rohár <pali.rohar@gmail.com>
+M:     Pali Rohár <pali@kernel.org>
 S:     Maintained
 F:     drivers/platform/x86/dell-rbtn.*
 
 DELL LAPTOP SMM DRIVER
-M:     Pali Rohár <pali.rohar@gmail.com>
+M:     Pali Rohár <pali@kernel.org>
 S:     Maintained
 F:     drivers/hwmon/dell-smm-hwmon.c
 F:     include/uapi/linux/i8k.h
@@ -4801,7 +4785,7 @@ S:        Maintained
 F:     drivers/platform/x86/dell_rbu.c
 
 DELL SMBIOS DRIVER
-M:     Pali Rohár <pali.rohar@gmail.com>
+M:     Pali Rohár <pali@kernel.org>
 M:     Mario Limonciello <mario.limonciello@dell.com>
 L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
@@ -4834,16 +4818,16 @@ F:      drivers/platform/x86/dell-wmi-descriptor.c
 
 DELL WMI NOTIFICATIONS DRIVER
 M:     Matthew Garrett <mjg59@srcf.ucam.org>
-M:     Pali Rohár <pali.rohar@gmail.com>
+M:     Pali Rohár <pali@kernel.org>
 S:     Maintained
 F:     drivers/platform/x86/dell-wmi.c
 
 DELTA ST MEDIA DRIVER
 M:     Hugues Fruchet <hugues.fruchet@st.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Supported
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/platform/sti/delta
 
 DENALI NAND DRIVER
@@ -4862,15 +4846,15 @@ F:      include/linux/dma/edma.h
 DESIGNWARE USB2 DRD IP DRIVER
 M:     Minas Harutyunyan <hminas@synopsys.com>
 L:     linux-usb@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 F:     drivers/usb/dwc2/
 
 DESIGNWARE USB3 DRD IP DRIVER
 M:     Felipe Balbi <balbi@kernel.org>
 L:     linux-usb@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 F:     drivers/usb/dwc3/
 
 DEVANTECH SRF ULTRASONIC RANGER IIO DRIVER
@@ -4887,47 +4871,55 @@ S:      Maintained
 F:     drivers/base/devcoredump.c
 F:     include/linux/devcoredump.h
 
+DEVICE DIRECT ACCESS (DAX)
+M:     Dan Williams <dan.j.williams@intel.com>
+M:     Vishal Verma <vishal.l.verma@intel.com>
+M:     Dave Jiang <dave.jiang@intel.com>
+L:     linux-nvdimm@lists.01.org
+S:     Supported
+F:     drivers/dax/
+
 DEVICE FREQUENCY (DEVFREQ)
 M:     MyungJoo Ham <myungjoo.ham@samsung.com>
 M:     Kyungmin Park <kyungmin.park@samsung.com>
 M:     Chanwoo Choi <cw00.choi@samsung.com>
 L:     linux-pm@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
+F:     Documentation/devicetree/bindings/devfreq/
 F:     drivers/devfreq/
 F:     include/linux/devfreq.h
-F:     Documentation/devicetree/bindings/devfreq/
 F:     include/trace/events/devfreq.h
 
 DEVICE FREQUENCY EVENT (DEVFREQ-EVENT)
 M:     Chanwoo Choi <cw00.choi@samsung.com>
 L:     linux-pm@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
 S:     Supported
-F:     drivers/devfreq/event/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
+F:     Documentation/devicetree/bindings/devfreq/event/
 F:     drivers/devfreq/devfreq-event.c
+F:     drivers/devfreq/event/
 F:     include/dt-bindings/pmu/exynos_ppmu.h
 F:     include/linux/devfreq-event.h
-F:     Documentation/devicetree/bindings/devfreq/event/
 
 DEVICE NUMBER REGISTRY
 M:     Torben Mathiasen <device@lanana.org>
-W:     http://lanana.org/docs/device-list/index.html
 S:     Maintained
+W:     http://lanana.org/docs/device-list/index.html
 
 DEVICE-MAPPER  (LVM)
 M:     Alasdair Kergon <agk@redhat.com>
 M:     Mike Snitzer <snitzer@redhat.com>
 M:     dm-devel@redhat.com
 L:     dm-devel@redhat.com
+S:     Maintained
 W:     http://sources.redhat.com/dm
 Q:     http://patchwork.kernel.org/project/dm-devel/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm.git
 T:     quilt http://people.redhat.com/agk/patches/linux/editing/
-S:     Maintained
 F:     Documentation/admin-guide/device-mapper/
-F:     drivers/md/Makefile
 F:     drivers/md/Kconfig
+F:     drivers/md/Makefile
 F:     drivers/md/dm*
 F:     drivers/md/persistent-data/
 F:     include/linux/device-mapper.h
@@ -4938,23 +4930,23 @@ DEVLINK
 M:     Jiri Pirko <jiri@mellanox.com>
 L:     netdev@vger.kernel.org
 S:     Supported
-F:     net/core/devlink.c
+F:     Documentation/networking/devlink
 F:     include/net/devlink.h
 F:     include/uapi/linux/devlink.h
-F:     Documentation/networking/devlink
+F:     net/core/devlink.c
 
 DIALOG SEMICONDUCTOR DRIVERS
 M:     Support Opensource <support.opensource@diasemi.com>
-W:     http://www.dialog-semiconductor.com/products
 S:     Supported
-F:     Documentation/hwmon/da90??.rst
-F:     Documentation/devicetree/bindings/mfd/da90*.txt
+W:     http://www.dialog-semiconductor.com/products
 F:     Documentation/devicetree/bindings/input/da90??-onkey.txt
-F:     Documentation/devicetree/bindings/thermal/da90??-thermal.txt
+F:     Documentation/devicetree/bindings/mfd/da90*.txt
 F:     Documentation/devicetree/bindings/regulator/da92*.txt
 F:     Documentation/devicetree/bindings/regulator/slg51000.txt
-F:     Documentation/devicetree/bindings/watchdog/da90??-wdt.txt
 F:     Documentation/devicetree/bindings/sound/da[79]*.txt
+F:     Documentation/devicetree/bindings/thermal/da90??-thermal.txt
+F:     Documentation/devicetree/bindings/watchdog/da90??-wdt.txt
+F:     Documentation/hwmon/da90??.rst
 F:     drivers/gpio/gpio-da90??.c
 F:     drivers/hwmon/da90??-hwmon.c
 F:     drivers/iio/adc/da91??-*.c
@@ -4970,8 +4962,8 @@ F:        drivers/power/supply/da91??-*.c
 F:     drivers/regulator/da903x.c
 F:     drivers/regulator/da9???-regulator.[ch]
 F:     drivers/regulator/slg51000-regulator.[ch]
-F:     drivers/thermal/da90??-thermal.c
 F:     drivers/rtc/rtc-da90??.c
+F:     drivers/thermal/da90??-thermal.c
 F:     drivers/video/backlight/da90??_bl.c
 F:     drivers/watchdog/da90??_wdt.c
 F:     include/linux/mfd/da903x.h
@@ -4996,25 +4988,6 @@ L:       linux-i2c@vger.kernel.org
 S:     Maintained
 F:     drivers/i2c/busses/i2c-diolan-u2c.c
 
-FILESYSTEM DIRECT ACCESS (DAX)
-M:     Dan Williams <dan.j.williams@intel.com>
-R:     Matthew Wilcox <willy@infradead.org>
-R:     Jan Kara <jack@suse.cz>
-L:     linux-fsdevel@vger.kernel.org
-L:     linux-nvdimm@lists.01.org
-S:     Supported
-F:     fs/dax.c
-F:     include/linux/dax.h
-F:     include/trace/events/fs_dax.h
-
-DEVICE DIRECT ACCESS (DAX)
-M:     Dan Williams <dan.j.williams@intel.com>
-M:     Vishal Verma <vishal.l.verma@intel.com>
-M:     Dave Jiang <dave.jiang@intel.com>
-L:     linux-nvdimm@lists.01.org
-S:     Supported
-F:     drivers/dax/
-
 DIRECTORY NOTIFICATION (DNOTIFY)
 M:     Jan Kara <jack@suse.cz>
 R:     Amir Goldstein <amir73il@gmail.com>
@@ -5026,10 +4999,10 @@ F:      include/linux/dnotify.h
 
 DISK GEOMETRY AND PARTITION HANDLING
 M:     Andries Brouwer <aeb@cwi.nl>
+S:     Maintained
 W:     http://www.win.tue.nl/~aeb/linux/Large-Disk.html
 W:     http://www.win.tue.nl/~aeb/linux/zip/zip-1.html
 W:     http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
-S:     Maintained
 
 DISKQUOTA
 M:     Jan Kara <jack@suse.com>
@@ -5044,84 +5017,84 @@ M:      Bernie Thompson <bernie@plugable.com>
 L:     linux-fbdev@vger.kernel.org
 S:     Maintained
 W:     http://plugable.com/category/projects/udlfb/
+F:     Documentation/fb/udlfb.rst
 F:     drivers/video/fbdev/udlfb.c
 F:     include/video/udlfb.h
-F:     Documentation/fb/udlfb.rst
 
 DISTRIBUTED LOCK MANAGER (DLM)
 M:     Christine Caulfield <ccaulfie@redhat.com>
 M:     David Teigland <teigland@redhat.com>
 L:     cluster-devel@redhat.com
+S:     Supported
 W:     http://sources.redhat.com/cluster/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm.git
-S:     Supported
 F:     fs/dlm/
 
 DMA BUFFER SHARING FRAMEWORK
 M:     Sumit Semwal <sumit.semwal@linaro.org>
-S:     Maintained
 L:     linux-media@vger.kernel.org
 L:     dri-devel@lists.freedesktop.org
 L:     linaro-mm-sig@lists.linaro.org (moderated for non-subscribers)
+S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/driver-api/dma-buf.rst
 F:     drivers/dma-buf/
+F:     include/linux/*fence.h
 F:     include/linux/dma-buf*
 F:     include/linux/dma-resv.h
-F:     include/linux/*fence.h
-F:     Documentation/driver-api/dma-buf.rst
 K:     dma_(buf|fence|resv)
-T:     git git://anongit.freedesktop.org/drm/drm-misc
-
-DMA-BUF HEAPS FRAMEWORK
-M:     Sumit Semwal <sumit.semwal@linaro.org>
-R:     Andrew F. Davis <afd@ti.com>
-R:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
-R:     Liam Mark <lmark@codeaurora.org>
-R:     Laura Abbott <labbott@redhat.com>
-R:     Brian Starkey <Brian.Starkey@arm.com>
-R:     John Stultz <john.stultz@linaro.org>
-S:     Maintained
-L:     linux-media@vger.kernel.org
-L:     dri-devel@lists.freedesktop.org
-L:     linaro-mm-sig@lists.linaro.org (moderated for non-subscribers)
-F:     include/uapi/linux/dma-heap.h
-F:     include/linux/dma-heap.h
-F:     drivers/dma-buf/dma-heap.c
-F:     drivers/dma-buf/heaps/*
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 
 DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
 M:     Vinod Koul <vkoul@kernel.org>
 L:     dmaengine@vger.kernel.org
-Q:     https://patchwork.kernel.org/project/linux-dmaengine/list/
 S:     Maintained
+Q:     https://patchwork.kernel.org/project/linux-dmaengine/list/
+T:     git git://git.infradead.org/users/vkoul/slave-dma.git
+F:     Documentation/devicetree/bindings/dma/
+F:     Documentation/driver-api/dmaengine/
 F:     drivers/dma/
 F:     include/linux/dmaengine.h
 F:     include/linux/of_dma.h
-F:     Documentation/devicetree/bindings/dma/
-F:     Documentation/driver-api/dmaengine/
-T:     git git://git.infradead.org/users/vkoul/slave-dma.git
 
 DMA MAPPING HELPERS
 M:     Christoph Hellwig <hch@lst.de>
 M:     Marek Szyprowski <m.szyprowski@samsung.com>
 R:     Robin Murphy <robin.murphy@arm.com>
 L:     iommu@lists.linux-foundation.org
-T:     git git://git.infradead.org/users/hch/dma-mapping.git
-W:     http://git.infradead.org/users/hch/dma-mapping.git
 S:     Supported
-F:     kernel/dma/
+W:     http://git.infradead.org/users/hch/dma-mapping.git
+T:     git git://git.infradead.org/users/hch/dma-mapping.git
 F:     include/asm-generic/dma-mapping.h
 F:     include/linux/dma-direct.h
 F:     include/linux/dma-mapping.h
 F:     include/linux/dma-noncoherent.h
+F:     kernel/dma/
+
+DMA-BUF HEAPS FRAMEWORK
+M:     Sumit Semwal <sumit.semwal@linaro.org>
+R:     Andrew F. Davis <afd@ti.com>
+R:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
+R:     Liam Mark <lmark@codeaurora.org>
+R:     Laura Abbott <labbott@redhat.com>
+R:     Brian Starkey <Brian.Starkey@arm.com>
+R:     John Stultz <john.stultz@linaro.org>
+L:     linux-media@vger.kernel.org
+L:     dri-devel@lists.freedesktop.org
+L:     linaro-mm-sig@lists.linaro.org (moderated for non-subscribers)
+S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     drivers/dma-buf/dma-heap.c
+F:     drivers/dma-buf/heaps/*
+F:     include/linux/dma-heap.h
+F:     include/uapi/linux/dma-heap.h
 
 DMC FREQUENCY DRIVER FOR SAMSUNG EXYNOS5422
 M:     Lukasz Luba <lukasz.luba@arm.com>
 L:     linux-pm@vger.kernel.org
 L:     linux-samsung-soc@vger.kernel.org
 S:     Maintained
-F:     drivers/memory/samsung/exynos5422-dmc.c
 F:     Documentation/devicetree/bindings/memory-controllers/exynos5422-dmc.txt
+F:     drivers/memory/samsung/exynos5422-dmc.c
 
 DME1737 HARDWARE MONITOR DRIVER
 M:     Juerg Haefliger <juergh@gmail.com>
@@ -5143,48 +5116,48 @@ DOCUMENTATION
 M:     Jonathan Corbet <corbet@lwn.net>
 L:     linux-doc@vger.kernel.org
 S:     Maintained
+T:     git git://git.lwn.net/linux.git docs-next
 F:     Documentation/
 F:     scripts/documentation-file-ref-check
 F:     scripts/kernel-doc
 F:     scripts/sphinx-pre-install
 X:     Documentation/ABI/
-X:     Documentation/firmware-guide/acpi/
 X:     Documentation/devicetree/
+X:     Documentation/firmware-guide/acpi/
 X:     Documentation/i2c/
 X:     Documentation/media/
 X:     Documentation/power/
 X:     Documentation/spi/
-T:     git git://git.lwn.net/linux.git docs-next
-
-DOCUMENTATION/ITALIAN
-M:     Federico Vaga <federico.vaga@vaga.pv.it>
-L:     linux-doc@vger.kernel.org
-S:     Maintained
-F:     Documentation/translations/it_IT
 
 DOCUMENTATION SCRIPTS
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-doc@vger.kernel.org
 S:     Maintained
+F:     Documentation/sphinx/parse-headers.pl
 F:     scripts/documentation-file-ref-check
 F:     scripts/sphinx-pre-install
-F:     Documentation/sphinx/parse-headers.pl
+
+DOCUMENTATION/ITALIAN
+M:     Federico Vaga <federico.vaga@vaga.pv.it>
+L:     linux-doc@vger.kernel.org
+S:     Maintained
+F:     Documentation/translations/it_IT
 
 DONGWOON DW9714 LENS VOICE COIL DRIVER
 M:     Sakari Ailus <sakari.ailus@linux.intel.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/i2c/dw9714.c
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.txt
+F:     drivers/media/i2c/dw9714.c
 
 DONGWOON DW9807 LENS VOICE COIL DRIVER
 M:     Sakari Ailus <sakari.ailus@linux.intel.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/i2c/dw9807-vcm.c
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/dongwoon,dw9807-vcm.txt
+F:     drivers/media/i2c/dw9807-vcm.c
 
 DOUBLETALK DRIVER
 M:     "James R. Van Zandt" <jrv@vanzandt.mv.com>
@@ -5203,15 +5176,15 @@ DPAA2 ETHERNET DRIVER
 M:     Ioana Radulescu <ruxandra.radulescu@nxp.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
+F:     Documentation/networking/device_drivers/freescale/dpaa2/ethernet-driver.rst
+F:     Documentation/networking/device_drivers/freescale/dpaa2/mac-phy-support.rst
+F:     drivers/net/ethernet/freescale/dpaa2/Kconfig
+F:     drivers/net/ethernet/freescale/dpaa2/Makefile
 F:     drivers/net/ethernet/freescale/dpaa2/dpaa2-eth*
 F:     drivers/net/ethernet/freescale/dpaa2/dpaa2-mac*
-F:     drivers/net/ethernet/freescale/dpaa2/dpni*
-F:     drivers/net/ethernet/freescale/dpaa2/dpmac*
 F:     drivers/net/ethernet/freescale/dpaa2/dpkg.h
-F:     drivers/net/ethernet/freescale/dpaa2/Makefile
-F:     drivers/net/ethernet/freescale/dpaa2/Kconfig
-F:     Documentation/networking/device_drivers/freescale/dpaa2/ethernet-driver.rst
-F:     Documentation/networking/device_drivers/freescale/dpaa2/mac-phy-support.rst
+F:     drivers/net/ethernet/freescale/dpaa2/dpmac*
+F:     drivers/net/ethernet/freescale/dpaa2/dpni*
 
 DPAA2 ETHERNET SWITCH DRIVER
 M:     Ioana Radulescu <ruxandra.radulescu@nxp.com>
@@ -5223,8 +5196,8 @@ F:        drivers/staging/fsl-dpaa2/ethsw
 DPT_I2O SCSI RAID DRIVER
 M:     Adaptec OEM Raid Solutions <aacraid@microsemi.com>
 L:     linux-scsi@vger.kernel.org
-W:     http://www.adaptec.com/
 S:     Maintained
+W:     http://www.adaptec.com/
 F:     drivers/scsi/dpt*
 F:     drivers/scsi/dpt/
 
@@ -5232,19 +5205,19 @@ DRBD DRIVER
 M:     Philipp Reisner <philipp.reisner@linbit.com>
 M:     Lars Ellenberg <lars.ellenberg@linbit.com>
 L:     drbd-dev@lists.linbit.com
+S:     Supported
 W:     http://www.drbd.org
 T:     git git://git.linbit.com/linux-drbd.git
 T:     git git://git.linbit.com/drbd-8.4.git
-S:     Supported
+F:     Documentation/admin-guide/blockdev/
 F:     drivers/block/drbd/
 F:     lib/lru_cache.c
-F:     Documentation/admin-guide/blockdev/
 
 DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 R:     "Rafael J. Wysocki" <rafael@kernel.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
 F:     Documentation/core-api/kobject.rst
 F:     drivers/base/
 F:     fs/debugfs/
@@ -5256,94 +5229,103 @@ F:     lib/kobj*
 DRIVERS FOR ADAPTIVE VOLTAGE SCALING (AVS)
 M:     Kevin Hilman <khilman@kernel.org>
 M:     Nishanth Menon <nm@ti.com>
+L:     linux-pm@vger.kernel.org
 S:     Maintained
 F:     drivers/power/avs/
 F:     include/linux/power/smartreflex.h
-L:     linux-pm@vger.kernel.org
+
+DRM DRIVER FOR ALLWINNER DE2 AND DE3 ENGINE
+M:     Maxime Ripard <mripard@kernel.org>
+M:     Chen-Yu Tsai <wens@csie.org>
+R:     Jernej Skrabec <jernej.skrabec@siol.net>
+L:     dri-devel@lists.freedesktop.org
+S:     Supported
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     drivers/gpu/drm/sun4i/sun8i*
 
 DRM DRIVER FOR ARM PL111 CLCD
 M:     Eric Anholt <eric@anholt.net>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Supported
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     drivers/gpu/drm/pl111/
 
 DRM DRIVER FOR ARM VERSATILE TFT PANELS
 M:     Linus Walleij <linus.walleij@linaro.org>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
-F:     drivers/gpu/drm/panel/panel-arm-versatile.c
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt
-
-DRM DRIVER FOR AST SERVER GRAPHICS CHIPS
-M:     Dave Airlie <airlied@redhat.com>
-S:     Odd Fixes
-F:     drivers/gpu/drm/ast/
+F:     drivers/gpu/drm/panel/panel-arm-versatile.c
 
 DRM DRIVER FOR ASPEED BMC GFX
 M:     Joel Stanley <joel@jms.id.au>
 L:     linux-aspeed@lists.ozlabs.org
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Supported
-F:     drivers/gpu/drm/aspeed/
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/gpu/aspeed-gfx.txt
+F:     drivers/gpu/drm/aspeed/
+
+DRM DRIVER FOR AST SERVER GRAPHICS CHIPS
+M:     Dave Airlie <airlied@redhat.com>
+S:     Odd Fixes
+F:     drivers/gpu/drm/ast/
 
 DRM DRIVER FOR BOCHS VIRTUAL GPU
 M:     Gerd Hoffmann <kraxel@redhat.com>
 L:     virtualization@lists.linux-foundation.org
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     drivers/gpu/drm/bochs/
 
 DRM DRIVER FOR BOE HIMAX8279D PANELS
 M:     Jerry Han <hanxu5@huaqin.corp-partner.google.com>
 S:     Maintained
-F:     drivers/gpu/drm/panel/panel-boe-himax8279d.c
 F:     Documentation/devicetree/bindings/display/panel/boe,himax8279d.txt
+F:     drivers/gpu/drm/panel/panel-boe-himax8279d.c
 
 DRM DRIVER FOR FARADAY TVE200 TV ENCODER
 M:     Linus Walleij <linus.walleij@linaro.org>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     drivers/gpu/drm/tve200/
 
 DRM DRIVER FOR FEIXIN K101 IM2BA02 MIPI-DSI LCD PANELS
 M:     Icenowy Zheng <icenowy@aosc.io>
 S:     Maintained
-F:     drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c
 F:     Documentation/devicetree/bindings/display/panel/feixin,k101-im2ba02.yaml
+F:     drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c
 
 DRM DRIVER FOR FEIYANG FY07024DI26A30-D MIPI-DSI LCD PANELS
 M:     Jagan Teki <jagan@amarulasolutions.com>
 S:     Maintained
-F:     drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
 F:     Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.txt
+F:     drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
 
 DRM DRIVER FOR GRAIN MEDIA GM12U320 PROJECTORS
 M:     Hans de Goede <hdegoede@redhat.com>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     drivers/gpu/drm/tiny/gm12u320.c
 
+DRM DRIVER FOR HX8357D PANELS
+M:     Eric Anholt <eric@anholt.net>
+S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/devicetree/bindings/display/himax,hx8357d.txt
+F:     drivers/gpu/drm/tiny/hx8357d.c
+
 DRM DRIVER FOR ILITEK ILI9225 PANELS
 M:     David Lechner <david@lechnology.com>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
-F:     drivers/gpu/drm/tiny/ili9225.c
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/ilitek,ili9225.txt
+F:     drivers/gpu/drm/tiny/ili9225.c
 
 DRM DRIVER FOR ILITEK ILI9486 PANELS
 M:     Kamlesh Gurudasani <kamlesh.gurudasani@gmail.com>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
-F:     drivers/gpu/drm/tiny/ili9486.c
-F:     Documentation/devicetree/bindings/display/ilitek,ili9486.yaml
-
-DRM DRIVER FOR HX8357D PANELS
-M:     Eric Anholt <eric@anholt.net>
 T:     git git://anongit.freedesktop.org/drm/drm-misc
-S:     Maintained
-F:     drivers/gpu/drm/tiny/hx8357d.c
-F:     Documentation/devicetree/bindings/display/himax,hx8357d.txt
+F:     Documentation/devicetree/bindings/display/ilitek,ili9486.yaml
+F:     drivers/gpu/drm/tiny/ili9486.c
 
 DRM DRIVER FOR INTEL I810 VIDEO CARDS
 S:     Orphan / Obsolete
@@ -5362,10 +5344,10 @@ F:      drivers/gpu/drm/mgag200/
 
 DRM DRIVER FOR MI0283QT
 M:     Noralf Trønnes <noralf@tronnes.org>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
-F:     drivers/gpu/drm/tiny/mi0283qt.c
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/multi-inno,mi0283qt.txt
+F:     drivers/gpu/drm/tiny/mi0283qt.c
 
 DRM DRIVER FOR MSM ADRENO GPU
 M:     Rob Clark <robdclark@gmail.com>
@@ -5373,48 +5355,48 @@ M:      Sean Paul <sean@poorly.run>
 L:     linux-arm-msm@vger.kernel.org
 L:     dri-devel@lists.freedesktop.org
 L:     freedreno@lists.freedesktop.org
-T:     git https://gitlab.freedesktop.org/drm/msm.git
 S:     Maintained
+T:     git https://gitlab.freedesktop.org/drm/msm.git
+F:     Documentation/devicetree/bindings/display/msm/
 F:     drivers/gpu/drm/msm/
 F:     include/uapi/drm/msm_drm.h
-F:     Documentation/devicetree/bindings/display/msm/
 
 DRM DRIVER FOR NOVATEK NT35510 PANELS
 M:     Linus Walleij <linus.walleij@linaro.org>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
-F:     drivers/gpu/drm/panel/panel-novatek-nt35510.c
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml
+F:     drivers/gpu/drm/panel/panel-novatek-nt35510.c
 
 DRM DRIVER FOR NVIDIA GEFORCE/QUADRO GPUS
 M:     Ben Skeggs <bskeggs@redhat.com>
 L:     dri-devel@lists.freedesktop.org
 L:     nouveau@lists.freedesktop.org
-T:     git git://github.com/skeggsb/linux
 S:     Supported
+T:     git git://github.com/skeggsb/linux
 F:     drivers/gpu/drm/nouveau/
 F:     include/uapi/drm/nouveau_drm.h
 
 DRM DRIVER FOR OLIMEX LCD-OLINUXINO PANELS
 M:     Stefan Mavrodiev <stefan@olimex.com>
 S:     Maintained
-F:     drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
 F:     Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino.txt
+F:     drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
 
 DRM DRIVER FOR PERVASIVE DISPLAYS REPAPER PANELS
 M:     Noralf Trønnes <noralf@tronnes.org>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
-F:     drivers/gpu/drm/tiny/repaper.c
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/repaper.txt
+F:     drivers/gpu/drm/tiny/repaper.c
 
 DRM DRIVER FOR QEMU'S CIRRUS DEVICE
 M:     Dave Airlie <airlied@redhat.com>
 M:     Gerd Hoffmann <kraxel@redhat.com>
 L:     virtualization@lists.linux-foundation.org
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Obsolete
 W:     https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     drivers/gpu/drm/cirrus/
 
 DRM DRIVER FOR QXL VIRTUAL GPU
@@ -5422,28 +5404,28 @@ M:      Dave Airlie <airlied@redhat.com>
 M:     Gerd Hoffmann <kraxel@redhat.com>
 L:     virtualization@lists.linux-foundation.org
 L:     spice-devel@lists.freedesktop.org
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     drivers/gpu/drm/qxl/
 F:     include/uapi/drm/qxl_drm.h
 
-DRM DRIVER FOR RAYDIUM RM67191 PANELS
-M:     Robert Chiras <robert.chiras@nxp.com>
-S:     Maintained
-F:     drivers/gpu/drm/panel/panel-raydium-rm67191.c
-F:     Documentation/devicetree/bindings/display/panel/raydium,rm67191.txt
-
 DRM DRIVER FOR RAGE 128 VIDEO CARDS
 S:     Orphan / Obsolete
 F:     drivers/gpu/drm/r128/
 F:     include/uapi/drm/r128_drm.h
 
+DRM DRIVER FOR RAYDIUM RM67191 PANELS
+M:     Robert Chiras <robert.chiras@nxp.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/display/panel/raydium,rm67191.txt
+F:     drivers/gpu/drm/panel/panel-raydium-rm67191.c
+
 DRM DRIVER FOR ROCKTECH JH057N00900 PANELS
 M:     Guido Günther <agx@sigxcpu.org>
 R:     Purism Kernel Team <kernel@puri.sm>
 S:     Maintained
-F:     drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c
 F:     Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.txt
+F:     drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c
 
 DRM DRIVER FOR SAVAGE VIDEO CARDS
 S:     Orphan / Obsolete
@@ -5455,38 +5437,38 @@ S:      Orphan / Obsolete
 F:     drivers/gpu/drm/sis/
 F:     include/uapi/drm/sis_drm.h
 
-DRM DRIVER FOR SITRONIX ST7701 PANELS
-M:     Jagan Teki <jagan@amarulasolutions.com>
-S:     Maintained
-F:     drivers/gpu/drm/panel/panel-sitronix-st7701.c
-F:     Documentation/devicetree/bindings/display/panel/sitronix,st7701.txt
-
 DRM DRIVER FOR SITRONIX ST7586 PANELS
 M:     David Lechner <david@lechnology.com>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
-F:     drivers/gpu/drm/tiny/st7586.c
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/sitronix,st7586.txt
+F:     drivers/gpu/drm/tiny/st7586.c
+
+DRM DRIVER FOR SITRONIX ST7701 PANELS
+M:     Jagan Teki <jagan@amarulasolutions.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/display/panel/sitronix,st7701.txt
+F:     drivers/gpu/drm/panel/panel-sitronix-st7701.c
 
 DRM DRIVER FOR SITRONIX ST7735R PANELS
 M:     David Lechner <david@lechnology.com>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
-F:     drivers/gpu/drm/tiny/st7735r.c
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/sitronix,st7735r.yaml
+F:     drivers/gpu/drm/tiny/st7735r.c
 
 DRM DRIVER FOR SONY ACX424AKP PANELS
 M:     Linus Walleij <linus.walleij@linaro.org>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     drivers/gpu/drm/panel/panel-sony-acx424akp.c
 
 DRM DRIVER FOR ST-ERICSSON MCDE
 M:     Linus Walleij <linus.walleij@linaro.org>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
-F:     drivers/gpu/drm/mcde/
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/ste,mcde.txt
+F:     drivers/gpu/drm/mcde/
 
 DRM DRIVER FOR TDFX VIDEO CARDS
 S:     Orphan / Obsolete
@@ -5494,42 +5476,42 @@ F:      drivers/gpu/drm/tdfx/
 
 DRM DRIVER FOR TPO TPG110 PANELS
 M:     Linus Walleij <linus.walleij@linaro.org>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
-F:     drivers/gpu/drm/panel/panel-tpo-tpg110.c
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/panel/tpo,tpg110.yaml
+F:     drivers/gpu/drm/panel/panel-tpo-tpg110.c
 
 DRM DRIVER FOR USB DISPLAYLINK VIDEO ADAPTERS
 M:     Dave Airlie <airlied@redhat.com>
 R:     Sean Paul <sean@poorly.run>
 L:     dri-devel@lists.freedesktop.org
 S:     Odd Fixes
-F:     drivers/gpu/drm/udl/
-T:     git git://anongit.freedesktop.org/drm/drm-misc
-
-DRM DRIVER FOR VIRTUALBOX VIRTUAL GPU
-M:     Hans de Goede <hdegoede@redhat.com>
-L:     dri-devel@lists.freedesktop.org
-S:     Maintained
-F:     drivers/gpu/drm/vboxvideo/
 T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     drivers/gpu/drm/udl/
 
 DRM DRIVER FOR VIRTUAL KERNEL MODESETTING (VKMS)
 M:     Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
 R:     Haneen Mohammed <hamohammed.sa@gmail.com>
 R:     Daniel Vetter <daniel@ffwll.ch>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
-S:     Maintained
 L:     dri-devel@lists.freedesktop.org
-F:     drivers/gpu/drm/vkms/
+S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/gpu/vkms.rst
+F:     drivers/gpu/drm/vkms/
+
+DRM DRIVER FOR VIRTUALBOX VIRTUAL GPU
+M:     Hans de Goede <hdegoede@redhat.com>
+L:     dri-devel@lists.freedesktop.org
+S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     drivers/gpu/drm/vboxvideo/
 
 DRM DRIVER FOR VMWARE VIRTUAL GPU
 M:     "VMware Graphics" <linux-graphics-maintainer@vmware.com>
 M:     Thomas Hellstrom <thellstrom@vmware.com>
 L:     dri-devel@lists.freedesktop.org
-T:     git git://people.freedesktop.org/~thomash/linux
 S:     Supported
+T:     git git://people.freedesktop.org/~thomash/linux
 F:     drivers/gpu/drm/vmwgfx/
 F:     include/uapi/drm/vmwgfx_drm.h
 
@@ -5537,71 +5519,62 @@ DRM DRIVERS
 M:     David Airlie <airlied@linux.ie>
 M:     Daniel Vetter <daniel@ffwll.ch>
 L:     dri-devel@lists.freedesktop.org
-T:     git git://anongit.freedesktop.org/drm/drm
+S:     Maintained
 B:     https://bugs.freedesktop.org/
 C:     irc://chat.freenode.net/dri-devel
-S:     Maintained
-F:     drivers/gpu/drm/
-F:     drivers/gpu/vga/
+T:     git git://anongit.freedesktop.org/drm/drm
 F:     Documentation/devicetree/bindings/display/
 F:     Documentation/devicetree/bindings/gpu/
 F:     Documentation/gpu/
+F:     drivers/gpu/drm/
+F:     drivers/gpu/vga/
 F:     include/drm/
-F:     include/uapi/drm/
 F:     include/linux/vga*
+F:     include/uapi/drm/
 
 DRM DRIVERS AND MISC GPU PATCHES
 M:     Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
 M:     Maxime Ripard <mripard@kernel.org>
 M:     Thomas Zimmermann <tzimmermann@suse.de>
-W:     https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html
 S:     Maintained
+W:     https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/gpu/
-F:     drivers/gpu/vga/
 F:     drivers/gpu/drm/*
+F:     drivers/gpu/vga/
 F:     include/drm/drm*
-F:     include/uapi/drm/drm*
 F:     include/linux/vga*
+F:     include/uapi/drm/drm*
 
 DRM DRIVERS FOR ALLWINNER A10
 M:     Maxime Ripard <mripard@kernel.org>
 M:     Chen-Yu Tsai <wens@csie.org>
 L:     dri-devel@lists.freedesktop.org
 S:     Supported
-F:     drivers/gpu/drm/sun4i/
-F:     Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
-T:     git git://anongit.freedesktop.org/drm/drm-misc
-
-DRM DRIVER FOR ALLWINNER DE2 AND DE3 ENGINE
-M:     Maxime Ripard <mripard@kernel.org>
-M:     Chen-Yu Tsai <wens@csie.org>
-R:     Jernej Skrabec <jernej.skrabec@siol.net>
-L:     dri-devel@lists.freedesktop.org
-S:     Supported
-F:     drivers/gpu/drm/sun4i/sun8i*
 T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
+F:     drivers/gpu/drm/sun4i/
 
 DRM DRIVERS FOR AMLOGIC SOCS
 M:     Neil Armstrong <narmstrong@baylibre.com>
 L:     dri-devel@lists.freedesktop.org
 L:     linux-amlogic@lists.infradead.org
-W:     http://linux-meson.com/
 S:     Supported
-F:     drivers/gpu/drm/meson/
-F:     Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
+W:     http://linux-meson.com/
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml
+F:     Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
 F:     Documentation/gpu/meson.rst
-T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     drivers/gpu/drm/meson/
 
 DRM DRIVERS FOR ATMEL HLCDC
 M:     Sam Ravnborg <sam@ravnborg.org>
 M:     Boris Brezillon <bbrezillon@kernel.org>
 L:     dri-devel@lists.freedesktop.org
 S:     Supported
-F:     drivers/gpu/drm/atmel-hlcdc/
-F:     Documentation/devicetree/bindings/display/atmel/
 T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/devicetree/bindings/display/atmel/
+F:     drivers/gpu/drm/atmel-hlcdc/
 
 DRM DRIVERS FOR BRIDGE CHIPS
 M:     Andrzej Hajda <a.hajda@samsung.com>
@@ -5619,35 +5592,35 @@ M:      Joonyoung Shim <jy0922.shim@samsung.com>
 M:     Seung-Woo Kim <sw0312.kim@samsung.com>
 M:     Kyungmin Park <kyungmin.park@samsung.com>
 L:     dri-devel@lists.freedesktop.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git
+F:     Documentation/devicetree/bindings/display/exynos/
 F:     drivers/gpu/drm/exynos/
 F:     include/uapi/drm/exynos_drm.h
-F:     Documentation/devicetree/bindings/display/exynos/
 
 DRM DRIVERS FOR FREESCALE DCU
 M:     Stefan Agner <stefan@agner.ch>
 M:     Alison Wang <alison.wang@nxp.com>
 L:     dri-devel@lists.freedesktop.org
 S:     Supported
-F:     drivers/gpu/drm/fsl-dcu/
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/fsl,dcu.txt
 F:     Documentation/devicetree/bindings/display/fsl,tcon.txt
-T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     drivers/gpu/drm/fsl-dcu/
 
 DRM DRIVERS FOR FREESCALE IMX
 M:     Philipp Zabel <p.zabel@pengutronix.de>
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
+F:     Documentation/devicetree/bindings/display/imx/
 F:     drivers/gpu/drm/imx/
 F:     drivers/gpu/ipu-v3/
-F:     Documentation/devicetree/bindings/display/imx/
 
 DRM DRIVERS FOR GMA500 (Poulsbo, Moorestown and derivative chipsets)
 M:     Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
 L:     dri-devel@lists.freedesktop.org
-T:     git git://github.com/patjak/drm-gma500
 S:     Maintained
+T:     git git://github.com/patjak/drm-gma500
 F:     drivers/gpu/drm/gma500/
 
 DRM DRIVERS FOR HISILICON
@@ -5657,71 +5630,71 @@ R:      John Stultz <john.stultz@linaro.org>
 R:     Xinwei Kong <kong.kongxinwei@hisilicon.com>
 R:     Chen Feng <puck.chen@hisilicon.com>
 L:     dri-devel@lists.freedesktop.org
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
-F:     drivers/gpu/drm/hisilicon/
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/hisilicon/
+F:     drivers/gpu/drm/hisilicon/
 
 DRM DRIVERS FOR LIMA
 M:     Qiang Yu <yuq825@gmail.com>
 L:     dri-devel@lists.freedesktop.org
 L:     lima@lists.freedesktop.org (moderated for non-subscribers)
 S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     drivers/gpu/drm/lima/
 F:     include/uapi/drm/lima_drm.h
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 
 DRM DRIVERS FOR MEDIATEK
 M:     Chun-Kuang Hu <chunkuang.hu@kernel.org>
 M:     Philipp Zabel <p.zabel@pengutronix.de>
 L:     dri-devel@lists.freedesktop.org
 S:     Supported
-F:     drivers/gpu/drm/mediatek/
 F:     Documentation/devicetree/bindings/display/mediatek/
+F:     drivers/gpu/drm/mediatek/
 
 DRM DRIVERS FOR NVIDIA TEGRA
 M:     Thierry Reding <thierry.reding@gmail.com>
 L:     dri-devel@lists.freedesktop.org
 L:     linux-tegra@vger.kernel.org
-T:     git git://anongit.freedesktop.org/tegra/linux.git
 S:     Supported
+T:     git git://anongit.freedesktop.org/tegra/linux.git
+F:     Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
 F:     drivers/gpu/drm/tegra/
 F:     drivers/gpu/host1x/
 F:     include/linux/host1x.h
 F:     include/uapi/drm/tegra_drm.h
-F:     Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
 
 DRM DRIVERS FOR RENESAS
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 M:     Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
 L:     dri-devel@lists.freedesktop.org
 L:     linux-renesas-soc@vger.kernel.org
-T:     git git://linuxtv.org/pinchartl/media drm/du/next
 S:     Supported
-F:     drivers/gpu/drm/rcar-du/
-F:     drivers/gpu/drm/shmobile/
-F:     include/linux/platform_data/shmob_drm.h
+T:     git git://linuxtv.org/pinchartl/media drm/du/next
 F:     Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.txt
 F:     Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt
 F:     Documentation/devicetree/bindings/display/renesas,du.txt
+F:     drivers/gpu/drm/rcar-du/
+F:     drivers/gpu/drm/shmobile/
+F:     include/linux/platform_data/shmob_drm.h
 
 DRM DRIVERS FOR ROCKCHIP
 M:     Sandy Huang <hjc@rock-chips.com>
 M:     Heiko Stübner <heiko@sntech.de>
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
-F:     drivers/gpu/drm/rockchip/
-F:     Documentation/devicetree/bindings/display/rockchip/
 T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/devicetree/bindings/display/rockchip/
+F:     drivers/gpu/drm/rockchip/
 
 DRM DRIVERS FOR STI
 M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
 M:     Vincent Abriou <vincent.abriou@st.com>
 L:     dri-devel@lists.freedesktop.org
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
-F:     drivers/gpu/drm/sti
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/st,stih4xx.txt
+F:     drivers/gpu/drm/sti
 
 DRM DRIVERS FOR STM
 M:     Yannick Fertre <yannick.fertre@st.com>
@@ -5729,53 +5702,53 @@ M:      Philippe Cornu <philippe.cornu@st.com>
 M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
 M:     Vincent Abriou <vincent.abriou@st.com>
 L:     dri-devel@lists.freedesktop.org
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
-F:     drivers/gpu/drm/stm
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/devicetree/bindings/display/st,stm32-ltdc.yaml
+F:     drivers/gpu/drm/stm
+
+DRM DRIVERS FOR TI KEYSTONE
+M:     Jyri Sarha <jsarha@ti.com>
+M:     Tomi Valkeinen <tomi.valkeinen@ti.com>
+L:     dri-devel@lists.freedesktop.org
+S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
+F:     Documentation/devicetree/bindings/display/ti/ti,j721e-dss.yaml
+F:     Documentation/devicetree/bindings/display/ti/ti,k2g-dss.yaml
+F:     drivers/gpu/drm/tidss/
 
 DRM DRIVERS FOR TI LCDC
 M:     Jyri Sarha <jsarha@ti.com>
 R:     Tomi Valkeinen <tomi.valkeinen@ti.com>
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
-F:     drivers/gpu/drm/tilcdc/
 F:     Documentation/devicetree/bindings/display/tilcdc/
+F:     drivers/gpu/drm/tilcdc/
 
 DRM DRIVERS FOR TI OMAP
 M:     Tomi Valkeinen <tomi.valkeinen@ti.com>
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
-F:     drivers/gpu/drm/omapdrm/
 F:     Documentation/devicetree/bindings/display/ti/
-
-DRM DRIVERS FOR TI KEYSTONE
-M:     Jyri Sarha <jsarha@ti.com>
-M:     Tomi Valkeinen <tomi.valkeinen@ti.com>
-L:     dri-devel@lists.freedesktop.org
-S:     Maintained
-F:     drivers/gpu/drm/tidss/
-F:     Documentation/devicetree/bindings/display/ti/ti,k2g-dss.yaml
-F:     Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
-F:     Documentation/devicetree/bindings/display/ti/ti,j721e-dss.yaml
-T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     drivers/gpu/drm/omapdrm/
 
 DRM DRIVERS FOR V3D
 M:     Eric Anholt <eric@anholt.net>
 S:     Supported
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.txt
 F:     drivers/gpu/drm/v3d/
 F:     include/uapi/drm/v3d_drm.h
-F:     Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.txt
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 
 DRM DRIVERS FOR VC4
 M:     Eric Anholt <eric@anholt.net>
-T:     git git://github.com/anholt/linux
 S:     Supported
+T:     git git://github.com/anholt/linux
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
 F:     drivers/gpu/drm/vc4/
 F:     include/uapi/drm/vc4_drm.h
-F:     Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 
 DRM DRIVERS FOR VIVANTE GPU IP
 M:     Lucas Stach <l.stach@pengutronix.de>
@@ -5784,177 +5757,177 @@ R:    Christian Gmeiner <christian.gmeiner@gmail.com>
 L:     etnaviv@lists.freedesktop.org (moderated for non-subscribers)
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
+F:     Documentation/devicetree/bindings/gpu/vivante,gc.yaml
 F:     drivers/gpu/drm/etnaviv/
 F:     include/uapi/drm/etnaviv_drm.h
-F:     Documentation/devicetree/bindings/gpu/vivante,gc.yaml
+
+DRM DRIVERS FOR XEN
+M:     Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
+L:     dri-devel@lists.freedesktop.org
+L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
+S:     Supported
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/gpu/xen-front.rst
+F:     drivers/gpu/drm/xen/
 
 DRM DRIVERS FOR ZTE ZX
 M:     Shawn Guo <shawnguo@kernel.org>
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
-F:     drivers/gpu/drm/zte/
-F:     Documentation/devicetree/bindings/display/zte,vou.txt
 T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/devicetree/bindings/display/zte,vou.txt
+F:     drivers/gpu/drm/zte/
 
 DRM PANEL DRIVERS
 M:     Thierry Reding <thierry.reding@gmail.com>
 R:     Sam Ravnborg <sam@ravnborg.org>
 L:     dri-devel@lists.freedesktop.org
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/devicetree/bindings/display/panel/
 F:     drivers/gpu/drm/drm_panel.c
 F:     drivers/gpu/drm/panel/
 F:     include/drm/drm_panel.h
-F:     Documentation/devicetree/bindings/display/panel/
-
-DRM DRIVERS FOR XEN
-M:     Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
-T:     git git://anongit.freedesktop.org/drm/drm-misc
-L:     dri-devel@lists.freedesktop.org
-L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
-S:     Supported
-F:     drivers/gpu/drm/xen/
-F:     Documentation/gpu/xen-front.rst
 
 DRM TTM SUBSYSTEM
 M:     Christian Koenig <christian.koenig@amd.com>
 M:     Huang Rui <ray.huang@amd.com>
-T:     git git://people.freedesktop.org/~agd5f/linux
-S:     Maintained
 L:     dri-devel@lists.freedesktop.org
-F:     include/drm/ttm/
+S:     Maintained
+T:     git git://people.freedesktop.org/~agd5f/linux
 F:     drivers/gpu/drm/ttm/
+F:     include/drm/ttm/
 
 DSBR100 USB FM RADIO DRIVER
 M:     Alexey Klimov <klimov.linux@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/dsbr100.c
 
 DT3155 MEDIA DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Odd Fixes
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/pci/dt3155/
 
 DVB_USB_AF9015 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/af9015*
 
 DVB_USB_AF9035 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/af9035*
 
 DVB_USB_ANYSEE MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/anysee*
 
 DVB_USB_AU6610 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/au6610*
 
 DVB_USB_CE6230 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/ce6230*
 
 DVB_USB_CXUSB MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
 F:     drivers/media/usb/dvb-usb/cxusb*
 
 DVB_USB_EC168 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/ec168*
 
 DVB_USB_GL861 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/gl861*
 
 DVB_USB_MXL111SF MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mkrufky/mxl111sf.git
-S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/mxl111sf*
 
 DVB_USB_RTL28XXU MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/rtl28xxu*
 
 DVB_USB_V2 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/dvb_usb*
 F:     drivers/media/usb/dvb-usb-v2/usb_urb.c
 
 DYNAMIC DEBUG
 M:     Jason Baron <jbaron@akamai.com>
 S:     Maintained
-F:     lib/dynamic_debug.c
 F:     include/linux/dynamic_debug.h
+F:     lib/dynamic_debug.c
 
 DYNAMIC INTERRUPT MODERATION
 M:     Tal Gilboa <talgi@mellanox.com>
@@ -5971,19 +5944,19 @@ F:      drivers/tty/serial/dz.*
 E3X0 POWER BUTTON DRIVER
 M:     Moritz Fischer <moritz.fischer@ettus.com>
 L:     usrp-users@lists.ettus.com
-W:     http://www.ettus.com
 S:     Supported
-F:     drivers/input/misc/e3x0-button.c
+W:     http://www.ettus.com
 F:     Documentation/devicetree/bindings/input/e3x0-button.txt
+F:     drivers/input/misc/e3x0-button.c
 
 E4000 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/tuners/e4000*
 
 EARTH_PT1 MEDIA DRIVER
@@ -6001,20 +5974,20 @@ F:      drivers/media/pci/pt3/
 EC100 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/dvb-frontends/ec100*
 
 ECRYPT FILE SYSTEM
 M:     Tyler Hicks <code@tyhicks.com>
 L:     ecryptfs@vger.kernel.org
+S:     Odd Fixes
 W:     http://ecryptfs.org
 W:     https://launchpad.net/ecryptfs
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs.git
-S:     Odd Fixes
 F:     Documentation/filesystems/ecryptfs.rst
 F:     fs/ecryptfs/
 
@@ -6033,8 +6006,8 @@ F:        drivers/edac/armada_xp_*
 EDAC-AST2500
 M:     Stefan Schaeckeler <sschaeck@cisco.com>
 S:     Supported
-F:     drivers/edac/aspeed_edac.c
 F:     Documentation/devicetree/bindings/edac/aspeed-sdram-edac.txt
+F:     drivers/edac/aspeed_edac.c
 
 EDAC-BLUEFIELD
 M:     Shravan Kumar Ramani <sramani@mellanox.com>
@@ -6068,8 +6041,8 @@ M:        Tony Luck <tony.luck@intel.com>
 R:     James Morse <james.morse@arm.com>
 R:     Robert Richter <rrichter@marvell.com>
 L:     linux-edac@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras.git edac-for-next
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras.git edac-for-next
 F:     Documentation/admin-guide/ras.rst
 F:     Documentation/driver-api/edac.rst
 F:     drivers/edac/
@@ -6174,6 +6147,14 @@ L:       linux-edac@vger.kernel.org
 S:     Maintained
 F:     drivers/edac/pnd2_edac.[ch]
 
+EDAC-QCOM
+M:     Channagoud Kadabi <ckadabi@codeaurora.org>
+M:     Venkata Narendra Kumar Gutta <vnkgutta@codeaurora.org>
+L:     linux-arm-msm@vger.kernel.org
+L:     linux-edac@vger.kernel.org
+S:     Maintained
+F:     drivers/edac/qcom_edac.c
+
 EDAC-R82600
 M:     Tim Small <tim@buttersideup.com>
 L:     linux-edac@vger.kernel.org
@@ -6206,25 +6187,17 @@ L:      linux-edac@vger.kernel.org
 S:     Maintained
 F:     drivers/edac/ti_edac.c
 
-EDAC-QCOM
-M:     Channagoud Kadabi <ckadabi@codeaurora.org>
-M:     Venkata Narendra Kumar Gutta <vnkgutta@codeaurora.org>
-L:     linux-arm-msm@vger.kernel.org
-L:     linux-edac@vger.kernel.org
-S:     Maintained
-F:     drivers/edac/qcom_edac.c
-
 EDIROL UA-101/UA-1000 DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 F:     sound/usb/misc/ua101.c
 
 EFI TEST DRIVER
-L:     linux-efi@vger.kernel.org
 M:     Ivan Hu <ivan.hu@canonical.com>
 M:     Ard Biesheuvel <ardb@kernel.org>
+L:     linux-efi@vger.kernel.org
 S:     Maintained
 F:     drivers/firmware/efi/test/
 
@@ -6232,20 +6205,20 @@ EFI VARIABLE FILESYSTEM
 M:     Matthew Garrett <matthew.garrett@nebula.com>
 M:     Jeremy Kerr <jk@ozlabs.org>
 M:     Ard Biesheuvel <ardb@kernel.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
 L:     linux-efi@vger.kernel.org
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
 F:     fs/efivarfs/
 
 EFIFB FRAMEBUFFER DRIVER
-L:     linux-fbdev@vger.kernel.org
 M:     Peter Jones <pjones@redhat.com>
+L:     linux-fbdev@vger.kernel.org
 S:     Maintained
 F:     drivers/video/fbdev/efifb.c
 
 EFS FILESYSTEM
-W:     http://aeschi.ch.eu.org/efs/
 S:     Orphan
+W:     http://aeschi.ch.eu.org/efs/
 F:     fs/efs/
 
 EHEA (IBM pSeries eHEA 10Gb ethernet adapter) DRIVER
@@ -6257,11 +6230,11 @@ F:      drivers/net/ethernet/ibm/ehea/
 EM28XX VIDEO4LINUX DRIVER
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
-F:     drivers/media/usb/em28xx/
 F:     Documentation/media/v4l-drivers/em28xx*
+F:     drivers/media/usb/em28xx/
 
 EMBEDDED LINUX
 M:     Paul Gortmaker <paul.gortmaker@windriver.com>
@@ -6270,30 +6243,38 @@ M:      David Woodhouse <dwmw2@infradead.org>
 L:     linux-embedded@vger.kernel.org
 S:     Maintained
 
-Emulex 10Gbps iSCSI - OneConnect DRIVER
+EMMC CMDQ HOST CONTROLLER INTERFACE (CQHCI) DRIVER
+M:     Adrian Hunter <adrian.hunter@intel.com>
+M:     Ritesh Harjani <riteshh@codeaurora.org>
+M:     Asutosh Das <asutoshd@codeaurora.org>
+L:     linux-mmc@vger.kernel.org
+S:     Maintained
+F:     drivers/mmc/host/cqhci*
+
+EMULEX 10Gbps iSCSI - OneConnect DRIVER
 M:     Subbu Seetharaman <subbu.seetharaman@broadcom.com>
 M:     Ketan Mukadam <ketan.mukadam@broadcom.com>
 M:     Jitendra Bhivare <jitendra.bhivare@broadcom.com>
 L:     linux-scsi@vger.kernel.org
-W:     http://www.broadcom.com
 S:     Supported
+W:     http://www.broadcom.com
 F:     drivers/scsi/be2iscsi/
 
-Emulex 10Gbps NIC BE2, BE3-R, Lancer, Skyhawk-R DRIVER (be2net)
+EMULEX 10Gbps NIC BE2, BE3-R, Lancer, Skyhawk-R DRIVER (be2net)
 M:     Ajit Khaparde <ajit.khaparde@broadcom.com>
 M:     Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
 M:     Somnath Kotur <somnath.kotur@broadcom.com>
 L:     netdev@vger.kernel.org
-W:     http://www.emulex.com
 S:     Supported
+W:     http://www.emulex.com
 F:     drivers/net/ethernet/emulex/benet/
 
 EMULEX ONECONNECT ROCE DRIVER
 M:     Selvin Xavier <selvin.xavier@broadcom.com>
 M:     Devesh Sharma <devesh.sharma@broadcom.com>
 L:     linux-rdma@vger.kernel.org
-W:     http://www.broadcom.com
 S:     Odd Fixes
+W:     http://www.broadcom.com
 F:     drivers/infiniband/hw/ocrdma/
 F:     include/uapi/rdma/ocrdma-abi.h
 
@@ -6301,8 +6282,8 @@ EMULEX/BROADCOM LPFC FC/FCOE SCSI DRIVER
 M:     James Smart <james.smart@broadcom.com>
 M:     Dick Kennedy <dick.kennedy@broadcom.com>
 L:     linux-scsi@vger.kernel.org
-W:     http://www.broadcom.com
 S:     Supported
+W:     http://www.broadcom.com
 F:     drivers/scsi/lpfc/
 
 ENE CB710 FLASH CARD READER DRIVER
@@ -6343,8 +6324,8 @@ F:        include/trace/events/erofs.h
 ERRSEQ ERROR TRACKING INFRASTRUCTURE
 M:     Jeff Layton <jlayton@kernel.org>
 S:     Maintained
-F:     lib/errseq.c
 F:     include/linux/errseq.h
+F:     lib/errseq.c
 
 ET131X NETWORK DRIVER
 M:     Mark Einon <mark.einon@gmail.com>
@@ -6356,8 +6337,8 @@ M:        Roopa Prabhu <roopa@cumulusnetworks.com>
 M:     Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
 L:     bridge@lists.linux-foundation.org (moderated for non-subscribers)
 L:     netdev@vger.kernel.org
-W:     http://www.linuxfoundation.org/en/Net:Bridge
 S:     Maintained
+W:     http://www.linuxfoundation.org/en/Net:Bridge
 F:     include/linux/netfilter_bridge/
 F:     net/bridge/
 
@@ -6406,10 +6387,10 @@ EXT4 FILE SYSTEM
 M:     "Theodore Ts'o" <tytso@mit.edu>
 M:     Andreas Dilger <adilger.kernel@dilger.ca>
 L:     linux-ext4@vger.kernel.org
+S:     Maintained
 W:     http://ext4.wiki.kernel.org
 Q:     http://patchwork.ozlabs.org/project/linux-ext4/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git
-S:     Maintained
 F:     Documentation/filesystems/ext4/
 F:     fs/ext4/
 
@@ -6422,28 +6403,37 @@ F:      security/integrity/evm/
 EXTENSIBLE FIRMWARE INTERFACE (EFI)
 M:     Ard Biesheuvel <ardb@kernel.org>
 L:     linux-efi@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
 F:     Documentation/admin-guide/efi-stub.rst
-F:     arch/*/kernel/efi.c
 F:     arch/*/include/asm/efi.h
+F:     arch/*/kernel/efi.c
+F:     arch/arm/boot/compressed/efi-header.S
+F:     arch/arm64/kernel/efi-entry.S
 F:     arch/x86/platform/efi/
 F:     drivers/firmware/efi/
 F:     include/linux/efi*.h
-F:     arch/arm/boot/compressed/efi-header.S
-F:     arch/arm64/kernel/efi-entry.S
 
 EXTERNAL CONNECTOR SUBSYSTEM (EXTCON)
 M:     MyungJoo Ham <myungjoo.ham@samsung.com>
 M:     Chanwoo Choi <cw00.choi@samsung.com>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon.git
+F:     Documentation/devicetree/bindings/extcon/
+F:     Documentation/firmware-guide/acpi/extcon-intel-int3496.rst
 F:     drivers/extcon/
-F:     include/linux/extcon/
 F:     include/linux/extcon.h
-F:     Documentation/firmware-guide/acpi/extcon-intel-int3496.rst
-F:     Documentation/devicetree/bindings/extcon/
+F:     include/linux/extcon/
+
+EXTRA BOOT CONFIG
+M:     Masami Hiramatsu <mhiramat@kernel.org>
+S:     Maintained
+F:     Documentation/admin-guide/bootconfig.rst
+F:     fs/proc/bootconfig.c
+F:     include/linux/bootconfig.h
+F:     lib/bootconfig.c
+F:     tools/bootconfig/*
 
 EXYNOS DP DRIVER
 M:     Jingoo Han <jingoohan1@gmail.com>
@@ -6461,18 +6451,18 @@ EZchip NPS platform support
 M:     Vineet Gupta <vgupta@synopsys.com>
 M:     Ofer Levi <oferle@mellanox.com>
 S:     Supported
-F:     arch/arc/plat-eznps
 F:     arch/arc/boot/dts/eznps.dts
+F:     arch/arc/plat-eznps
 
 F2FS FILE SYSTEM
 M:     Jaegeuk Kim <jaegeuk@kernel.org>
 M:     Chao Yu <yuchao0@huawei.com>
 L:     linux-f2fs-devel@lists.sourceforge.net
+S:     Maintained
 W:     https://f2fs.wiki.kernel.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
-S:     Maintained
-F:     Documentation/filesystems/f2fs.rst
 F:     Documentation/ABI/testing/sysfs-fs-f2fs
+F:     Documentation/filesystems/f2fs.rst
 F:     fs/f2fs/
 F:     include/linux/f2fs_fs.h
 F:     include/trace/events/f2fs.h
@@ -6493,9 +6483,9 @@ FAILOVER MODULE
 M:     Sridhar Samudrala <sridhar.samudrala@intel.com>
 L:     netdev@vger.kernel.org
 S:     Supported
-F:     net/core/failover.c
-F:     include/net/failover.h
 F:     Documentation/networking/failover.rst
+F:     include/net/failover.h
+F:     net/core/failover.c
 
 FANOTIFY
 M:     Jan Kara <jack@suse.cz>
@@ -6508,8 +6498,8 @@ F:        include/uapi/linux/fanotify.h
 
 FARSYNC SYNCHRONOUS DRIVER
 M:     Kevin Curtis <kevin.curtis@farsite.co.uk>
-W:     http://www.farsite.co.uk/
 S:     Supported
+W:     http://www.farsite.co.uk/
 F:     drivers/net/wan/farsync.*
 
 FAULT INJECTION SUPPORT
@@ -6519,35 +6509,35 @@ F:      Documentation/fault-injection/
 F:     lib/fault-inject.c
 
 FBTFT Framebuffer drivers
-S:     Orphan
 L:     dri-devel@lists.freedesktop.org
 L:     linux-fbdev@vger.kernel.org
+S:     Orphan
 F:     drivers/staging/fbtft/
 
 FC0011 TUNER DRIVER
 M:     Michael Buesch <m@bues.ch>
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     drivers/media/tuners/fc0011.h
 F:     drivers/media/tuners/fc0011.c
+F:     drivers/media/tuners/fc0011.h
 
 FC2580 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/tuners/fc2580*
 
 FCOE SUBSYSTEM (libfc, libfcoe, fcoe)
 M:     Hannes Reinecke <hare@suse.de>
 L:     linux-scsi@vger.kernel.org
-W:     www.Open-FCoE.org
 S:     Supported
-F:     drivers/scsi/libfc/
+W:     www.Open-FCoE.org
 F:     drivers/scsi/fcoe/
+F:     drivers/scsi/libfc/
 F:     include/scsi/fc/
 F:     include/scsi/libfc.h
 F:     include/scsi/libfcoe.h
@@ -6558,10 +6548,21 @@ M:      Jeff Layton <jlayton@kernel.org>
 M:     "J. Bruce Fields" <bfields@fieldses.org>
 L:     linux-fsdevel@vger.kernel.org
 S:     Maintained
-F:     include/linux/fcntl.h
-F:     include/uapi/linux/fcntl.h
 F:     fs/fcntl.c
 F:     fs/locks.c
+F:     include/linux/fcntl.h
+F:     include/uapi/linux/fcntl.h
+
+FILESYSTEM DIRECT ACCESS (DAX)
+M:     Dan Williams <dan.j.williams@intel.com>
+R:     Matthew Wilcox <willy@infradead.org>
+R:     Jan Kara <jack@suse.cz>
+L:     linux-fsdevel@vger.kernel.org
+L:     linux-nvdimm@lists.01.org
+S:     Supported
+F:     fs/dax.c
+F:     include/linux/dax.h
+F:     include/trace/events/fs_dax.h
 
 FILESYSTEMS (VFS and infrastructure)
 M:     Alexander Viro <viro@zeniv.linux.org.uk>
@@ -6584,17 +6585,17 @@ FIREWIRE AUDIO DRIVERS and IEC 61883-1/6 PACKET STREAMING ENGINE
 M:     Clemens Ladisch <clemens@ladisch.de>
 M:     Takashi Sakamoto <o-takashi@sakamocchi.jp>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:     Maintained
-F:     sound/firewire/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 F:     include/uapi/sound/firewire.h
+F:     sound/firewire/
 
 FIREWIRE MEDIA DRIVERS (firedtv)
 M:     Stefan Richter <stefanr@s5r6.in-berlin.de>
 L:     linux-media@vger.kernel.org
 L:     linux1394-devel@lists.sourceforge.net
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 F:     drivers/media/firewire/
 
 FIREWIRE SBP-2 TARGET
@@ -6602,16 +6603,16 @@ M:      Chris Boot <bootc@bootc.net>
 L:     linux-scsi@vger.kernel.org
 L:     target-devel@vger.kernel.org
 L:     linux1394-devel@lists.sourceforge.net
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master
 F:     drivers/target/sbp/
 
 FIREWIRE SUBSYSTEM
 M:     Stefan Richter <stefanr@s5r6.in-berlin.de>
 L:     linux1394-devel@lists.sourceforge.net
+S:     Maintained
 W:     http://ieee1394.wiki.kernel.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394.git
-S:     Maintained
 F:     drivers/firewire/
 F:     include/linux/firewire.h
 F:     include/uapi/linux/firewire*.h
@@ -6641,35 +6642,48 @@ F:      drivers/counter/ftm-quaddec.c
 
 FLOPPY DRIVER
 M:     Denis Efremov <efremov@linux.com>
-S:     Odd Fixes
 L:     linux-block@vger.kernel.org
+S:     Odd Fixes
 F:     drivers/block/floppy.c
 
-FPGA MANAGER FRAMEWORK
-M:     Moritz Fischer <mdf@kernel.org>
-L:     linux-fpga@vger.kernel.org
+FLYSKY FSIA6B RC RECEIVER
+M:     Markus Koch <markus@notsyncing.net>
+L:     linux-input@vger.kernel.org
 S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mdf/linux-fpga.git
-Q:     http://patchwork.kernel.org/project/linux-fpga/list/
-F:     Documentation/fpga/
-F:     Documentation/driver-api/fpga/
-F:     Documentation/devicetree/bindings/fpga/
-F:     drivers/fpga/
-F:     include/linux/fpga/
-W:     http://www.rocketboards.org
+F:     drivers/input/joystick/fsia6b.c
+
+FORCEDETH GIGABIT ETHERNET DRIVER
+M:     Rain River <rain.1986.08.12@gmail.com>
+M:     Zhu Yanjun <zyjzyj2000@gmail.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/ethernet/nvidia/*
 
 FPGA DFL DRIVERS
 M:     Wu Hao <hao.wu@intel.com>
 L:     linux-fpga@vger.kernel.org
 S:     Maintained
 F:     Documentation/fpga/dfl.rst
-F:     include/uapi/linux/fpga-dfl.h
 F:     drivers/fpga/dfl*
+F:     include/uapi/linux/fpga-dfl.h
+
+FPGA MANAGER FRAMEWORK
+M:     Moritz Fischer <mdf@kernel.org>
+L:     linux-fpga@vger.kernel.org
+S:     Maintained
+W:     http://www.rocketboards.org
+Q:     http://patchwork.kernel.org/project/linux-fpga/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mdf/linux-fpga.git
+F:     Documentation/devicetree/bindings/fpga/
+F:     Documentation/driver-api/fpga/
+F:     Documentation/fpga/
+F:     drivers/fpga/
+F:     include/linux/fpga/
 
 FPU EMULATOR
 M:     Bill Metzenthen <billm@melbpc.org.au>
-W:     http://floatingpoint.sourceforge.net/emulator/index.html
 S:     Maintained
+W:     http://floatingpoint.sourceforge.net/emulator/index.html
 F:     arch/x86/math-emu/
 
 FRAME RELAY DLCI/FRAD (Sangoma drivers too)
@@ -6682,23 +6696,23 @@ FRAMEBUFFER LAYER
 M:     Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
 L:     dri-devel@lists.freedesktop.org
 L:     linux-fbdev@vger.kernel.org
-T:     git git://anongit.freedesktop.org/drm/drm-misc
-Q:     http://patchwork.kernel.org/project/linux-fbdev/list/
 S:     Maintained
+Q:     http://patchwork.kernel.org/project/linux-fbdev/list/
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/fb/
 F:     drivers/video/
-F:     include/video/
 F:     include/linux/fb.h
-F:     include/uapi/video/
 F:     include/uapi/linux/fb.h
+F:     include/uapi/video/
+F:     include/video/
 
 FREESCALE CAAM (Cryptographic Acceleration and Assurance Module) DRIVER
 M:     Horia Geantă <horia.geanta@nxp.com>
 M:     Aymen Sghaier <aymen.sghaier@nxp.com>
 L:     linux-crypto@vger.kernel.org
 S:     Maintained
-F:     drivers/crypto/caam/
 F:     Documentation/devicetree/bindings/crypto/fsl-sec4.txt
+F:     drivers/crypto/caam/
 
 FREESCALE DIU FRAMEBUFFER DRIVER
 M:     Timur Tabi <timur@kernel.org>
@@ -6723,8 +6737,8 @@ FREESCALE eTSEC ETHERNET DRIVER (GIANFAR)
 M:     Claudiu Manoil <claudiu.manoil@nxp.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/ethernet/freescale/gianfar*
 F:     Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
+F:     drivers/net/ethernet/freescale/gianfar*
 
 FREESCALE GPMI NAND DRIVER
 M:     Han Xu <han.xu@nxp.com>
@@ -6737,49 +6751,49 @@ M:      Jochen Friedrich <jochen@scram.de>
 L:     linuxppc-dev@lists.ozlabs.org
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
-F:     drivers/i2c/busses/i2c-cpm.c
+F:     drivers/i2c/busses/i2c-cpm.c
+
+FREESCALE IMX / MXC FEC DRIVER
+M:     Fugang Duan <fugang.duan@nxp.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/net/fsl-fec.txt
+F:     drivers/net/ethernet/freescale/fec.h
+F:     drivers/net/ethernet/freescale/fec_main.c
+F:     drivers/net/ethernet/freescale/fec_ptp.c
+
+FREESCALE IMX / MXC FRAMEBUFFER DRIVER
+M:     Sascha Hauer <s.hauer@pengutronix.de>
+R:     Pengutronix Kernel Team <kernel@pengutronix.de>
+L:     linux-fbdev@vger.kernel.org
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     drivers/video/fbdev/imxfb.c
+F:     include/linux/platform_data/video-imxfb.h
 
 FREESCALE IMX DDR PMU DRIVER
 M:     Frank Li <Frank.li@nxp.com>
 L:     linux-arm-kernel@lists.infradead.org
 S:     Maintained
-F:     drivers/perf/fsl_imx8_ddr_perf.c
 F:     Documentation/admin-guide/perf/imx-ddr.rst
 F:     Documentation/devicetree/bindings/perf/fsl-imx-ddr.txt
+F:     drivers/perf/fsl_imx8_ddr_perf.c
 
 FREESCALE IMX I2C DRIVER
 M:     Oleksij Rempel <o.rempel@pengutronix.de>
 R:     Pengutronix Kernel Team <kernel@pengutronix.de>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
-F:     drivers/i2c/busses/i2c-imx.c
 F:     Documentation/devicetree/bindings/i2c/i2c-imx.txt
+F:     drivers/i2c/busses/i2c-imx.c
 
 FREESCALE IMX LPI2C DRIVER
 M:     Dong Aisheng <aisheng.dong@nxp.com>
 L:     linux-i2c@vger.kernel.org
 L:     linux-imx@nxp.com
 S:     Maintained
-F:     drivers/i2c/busses/i2c-imx-lpi2c.c
 F:     Documentation/devicetree/bindings/i2c/i2c-imx-lpi2c.txt
-
-FREESCALE IMX / MXC FEC DRIVER
-M:     Fugang Duan <fugang.duan@nxp.com>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     drivers/net/ethernet/freescale/fec_main.c
-F:     drivers/net/ethernet/freescale/fec_ptp.c
-F:     drivers/net/ethernet/freescale/fec.h
-F:     Documentation/devicetree/bindings/net/fsl-fec.txt
-
-FREESCALE IMX / MXC FRAMEBUFFER DRIVER
-M:     Sascha Hauer <s.hauer@pengutronix.de>
-R:     Pengutronix Kernel Team <kernel@pengutronix.de>
-L:     linux-fbdev@vger.kernel.org
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-F:     include/linux/platform_data/video-imxfb.h
-F:     drivers/video/fbdev/imxfb.c
+F:     drivers/i2c/busses/i2c-imx-lpi2c.c
 
 FREESCALE QORIQ DPAA ETHERNET DRIVER
 M:     Madalin Bucur <madalin.bucur@nxp.com>
@@ -6791,20 +6805,20 @@ FREESCALE QORIQ DPAA FMAN DRIVER
 M:     Madalin Bucur <madalin.bucur@nxp.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/ethernet/freescale/fman
 F:     Documentation/devicetree/bindings/net/fsl-fman.txt
+F:     drivers/net/ethernet/freescale/fman
 
 FREESCALE QORIQ PTP CLOCK DRIVER
 M:     Yangbo Lu <yangbo.lu@nxp.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
+F:     Documentation/devicetree/bindings/ptp/ptp-qoriq.txt
 F:     drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp*
 F:     drivers/net/ethernet/freescale/dpaa2/dprtc*
 F:     drivers/net/ethernet/freescale/enetc/enetc_ptp.c
 F:     drivers/ptp/ptp_qoriq.c
 F:     drivers/ptp/ptp_qoriq_debugfs.c
 F:     include/linux/fsl/ptp_qoriq.h
-F:     Documentation/devicetree/bindings/ptp/ptp-qoriq.txt
 
 FREESCALE QUAD SPI DRIVER
 M:     Han Xu <han.xu@nxp.com>
@@ -6879,8 +6893,8 @@ F:        drivers/usb/gadget/udc/fsl*
 
 FREEVXFS FILESYSTEM
 M:     Christoph Hellwig <hch@infradead.org>
-W:     ftp://ftp.openlinux.org/pub/people/hch/vxfs
 S:     Maintained
+W:     ftp://ftp.openlinux.org/pub/people/hch/vxfs
 F:     fs/freevxfs/
 
 FREEZER
@@ -6896,8 +6910,8 @@ FRONTSWAP API
 M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
-F:     mm/frontswap.c
 F:     include/linux/frontswap.h
+F:     mm/frontswap.c
 
 FS-CACHE: LOCAL CACHING FOR NETWORK FILESYSTEMS
 M:     David Howells <dhowells@redhat.com>
@@ -6912,13 +6926,13 @@ M:      Theodore Y. Ts'o <tytso@mit.edu>
 M:     Jaegeuk Kim <jaegeuk@kernel.org>
 M:     Eric Biggers <ebiggers@kernel.org>
 L:     linux-fscrypt@vger.kernel.org
+S:     Supported
 Q:     https://patchwork.kernel.org/project/linux-fscrypt/list/
 T:     git git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git
-S:     Supported
+F:     Documentation/filesystems/fscrypt.rst
 F:     fs/crypto/
 F:     include/linux/fscrypt*.h
 F:     include/uapi/linux/fscrypt.h
-F:     Documentation/filesystems/fscrypt.rst
 
 FSI SUBSYSTEM
 M:     Jeremy Kerr <jk@ozlabs.org>
@@ -6926,9 +6940,9 @@ M:        Joel Stanley <joel@jms.id.au>
 R:     Alistar Popple <alistair@popple.id.au>
 R:     Eddie James <eajames@linux.ibm.com>
 L:     linux-fsi@lists.ozlabs.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joel/fsi.git
-Q:     http://patchwork.ozlabs.org/project/linux-fsi/list/
 S:     Supported
+Q:     http://patchwork.ozlabs.org/project/linux-fsi/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joel/fsi.git
 F:     drivers/fsi/
 F:     include/linux/fsi*.h
 F:     include/trace/events/fsi*.h
@@ -6938,22 +6952,22 @@ M:      Eddie James <eajames@linux.ibm.com>
 L:     linux-i2c@vger.kernel.org
 L:     openbmc@lists.ozlabs.org (moderated for non-subscribers)
 S:     Maintained
-F:     drivers/i2c/busses/i2c-fsi.c
 F:     Documentation/devicetree/bindings/i2c/i2c-fsi.txt
+F:     drivers/i2c/busses/i2c-fsi.c
 
 FSI-ATTACHED SPI DRIVER
 M:     Eddie James <eajames@linux.ibm.com>
 L:     linux-spi@vger.kernel.org
 S:     Maintained
-F:     drivers/spi/spi-fsi.c
 F:     Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml
+F:     drivers/spi/spi-fsi.c
 
 FSNOTIFY: FILESYSTEM NOTIFICATION INFRASTRUCTURE
 M:     Jan Kara <jack@suse.cz>
 R:     Amir Goldstein <amir73il@gmail.com>
 L:     linux-fsdevel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git fsnotify
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git fsnotify
 F:     fs/notify/
 F:     include/linux/fsnotify*.h
 
@@ -6961,13 +6975,13 @@ FSVERITY: READ-ONLY FILE-BASED AUTHENTICITY PROTECTION
 M:     Eric Biggers <ebiggers@kernel.org>
 M:     Theodore Y. Ts'o <tytso@mit.edu>
 L:     linux-fscrypt@vger.kernel.org
+S:     Supported
 Q:     https://patchwork.kernel.org/project/linux-fscrypt/list/
 T:     git git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git fsverity
-S:     Supported
+F:     Documentation/filesystems/fsverity.rst
 F:     fs/verity/
 F:     include/linux/fsverity.h
 F:     include/uapi/linux/fsverity.h
-F:     Documentation/filesystems/fsverity.rst
 
 FUJITSU LAPTOP EXTRAS
 M:     Jonathan Woithe <jwoithe@just42.net>
@@ -6992,12 +7006,12 @@ F:      drivers/platform/x86/fujitsu-tablet.c
 FUSE: FILESYSTEM IN USERSPACE
 M:     Miklos Szeredi <miklos@szeredi.hu>
 L:     linux-fsdevel@vger.kernel.org
+S:     Maintained
 W:     http://fuse.sourceforge.net/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git
-S:     Maintained
+F:     Documentation/filesystems/fuse.rst
 F:     fs/fuse/
 F:     include/uapi/linux/fuse.h
-F:     Documentation/filesystems/fuse.rst
 
 FUTEX SUBSYSTEM
 M:     Thomas Gleixner <tglx@linutronix.de>
@@ -7005,25 +7019,15 @@ M:      Ingo Molnar <mingo@redhat.com>
 R:     Peter Zijlstra <peterz@infradead.org>
 R:     Darren Hart <dvhart@infradead.org>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core
 S:     Maintained
-F:     kernel/futex.c
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core
+F:     Documentation/*futex*
 F:     include/asm-generic/futex.h
 F:     include/linux/futex.h
 F:     include/uapi/linux/futex.h
-F:     tools/testing/selftests/futex/
+F:     kernel/futex.c
 F:     tools/perf/bench/futex*
-F:     Documentation/*futex*
-
-GCC PLUGINS
-M:     Kees Cook <keescook@chromium.org>
-R:     Emese Revfy <re.emese@gmail.com>
-L:     kernel-hardening@lists.openwall.com
-S:     Maintained
-F:     scripts/gcc-plugins/
-F:     scripts/gcc-plugin.sh
-F:     scripts/Makefile.gcc-plugins
-F:     Documentation/kbuild/gcc-plugins.rst
+F:     tools/testing/selftests/futex/
 
 GASKET DRIVER FRAMEWORK
 M:     Rob Springer <rspringer@google.com>
@@ -7032,11 +7036,21 @@ M:      Ben Chan <benchan@chromium.org>
 S:     Maintained
 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
+S:     Maintained
+F:     Documentation/kbuild/gcc-plugins.rst
+F:     scripts/Makefile.gcc-plugins
+F:     scripts/gcc-plugin.sh
+F:     scripts/gcc-plugins/
+
 GCOV BASED KERNEL PROFILING
 M:     Peter Oberparleiter <oberpar@linux.ibm.com>
 S:     Maintained
-F:     kernel/gcov/
 F:     Documentation/dev-tools/gcov.rst
+F:     kernel/gcov/
 
 GDB KERNEL DEBUGGING HELPER SCRIPTS
 M:     Jan Kiszka <jan.kiszka@siemens.com>
@@ -7047,16 +7061,16 @@ F:      scripts/gdb/
 GDT SCSI DISK ARRAY CONTROLLER DRIVER
 M:     Achim Leubner <achim_leubner@adaptec.com>
 L:     linux-scsi@vger.kernel.org
-W:     http://www.icp-vortex.com/
 S:     Supported
+W:     http://www.icp-vortex.com/
 F:     drivers/scsi/gdt*
 
 GEMTEK FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/radio-gemtek*
 
 GENERIC ARCHITECTURE TOPOLOGY
@@ -7076,14 +7090,14 @@ GENERIC GPIO I2C MULTIPLEXER DRIVER
 M:     Peter Korsgaard <peter.korsgaard@barco.com>
 L:     linux-i2c@vger.kernel.org
 S:     Supported
+F:     Documentation/i2c/muxes/i2c-mux-gpio.rst
 F:     drivers/i2c/muxes/i2c-mux-gpio.c
 F:     include/linux/platform_data/i2c-mux-gpio.h
-F:     Documentation/i2c/muxes/i2c-mux-gpio.rst
 
 GENERIC HDLC (WAN) DRIVERS
 M:     Krzysztof Halasa <khc@pm.waw.pl>
-W:     http://www.kernel.org/pub/linux/utils/net/hdlc/
 S:     Maintained
+W:     http://www.kernel.org/pub/linux/utils/net/hdlc/
 F:     drivers/net/wan/c101.c
 F:     drivers/net/wan/hd6457*
 F:     drivers/net/wan/hdlc*
@@ -7095,19 +7109,19 @@ F:      drivers/net/wan/wanxl*
 GENERIC INCLUDE/ASM HEADER FILES
 M:     Arnd Bergmann <arnd@arndb.de>
 L:     linux-arch@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git
 F:     include/asm-generic/
 F:     include/uapi/asm-generic/
 
 GENERIC PHY FRAMEWORK
 M:     Kishon Vijay Abraham I <kishon@ti.com>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy.git
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy.git
+F:     Documentation/devicetree/bindings/phy/
 F:     drivers/phy/
 F:     include/linux/phy/
-F:     Documentation/devicetree/bindings/phy/
 
 GENERIC PINCTRL I2C DEMULTIPLEXER DRIVER
 M:     Wolfram Sang <wsa+renesas@sang-engineering.com>
@@ -7120,9 +7134,9 @@ M:        Kevin Hilman <khilman@kernel.org>
 M:     Ulf Hansson <ulf.hansson@linaro.org>
 L:     linux-pm@vger.kernel.org
 S:     Supported
+F:     Documentation/devicetree/bindings/power/power?domain*
 F:     drivers/base/power/domain*.c
 F:     include/linux/pm_domain.h
-F:     Documentation/devicetree/bindings/power/power?domain*
 
 GENERIC RESISTIVE TOUCHSCREEN ADC DRIVER
 M:     Eugen Hristev <eugen.hristev@microchip.com>
@@ -7141,12 +7155,12 @@ M:      Andy Lutomirski <luto@kernel.org>
 M:     Thomas Gleixner <tglx@linutronix.de>
 M:     Vincenzo Frascino <vincenzo.frascino@arm.com>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/vdso
 S:     Maintained
-F:     lib/vdso/
-F:     kernel/time/vsyscall.c
-F:     include/vdso/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/vdso
 F:     include/asm-generic/vdso/vsyscall.h
+F:     include/vdso/
+F:     kernel/time/vsyscall.c
+F:     lib/vdso/
 
 GENWQE (IBM Generic Workqueue Card)
 M:     Frank Haverkamp <haver@linux.ibm.com>
@@ -7162,17 +7176,17 @@ GFS2 FILE SYSTEM
 M:     Bob Peterson <rpeterso@redhat.com>
 M:     Andreas Gruenbacher <agruenba@redhat.com>
 L:     cluster-devel@redhat.com
+S:     Supported
 W:     http://sources.redhat.com/cluster/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2.git
-S:     Supported
 F:     Documentation/filesystems/gfs2*.txt
 F:     fs/gfs2/
 F:     include/uapi/linux/gfs2_ondisk.h
 
 GNSS SUBSYSTEM
 M:     Johan Hovold <johan@kernel.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/johan/gnss.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/johan/gnss.git
 F:     Documentation/ABI/testing/sysfs-class-gnss
 F:     Documentation/devicetree/bindings/gnss/
 F:     drivers/gnss/
@@ -7241,8 +7255,8 @@ F:        Documentation/devicetree/bindings/gpio/
 F:     Documentation/driver-api/gpio/
 F:     drivers/gpio/
 F:     include/asm-generic/gpio.h
-F:     include/linux/gpio/
 F:     include/linux/gpio.h
+F:     include/linux/gpio/
 F:     include/linux/of_gpio.h
 F:     include/uapi/linux/gpio.h
 F:     tools/gpio/
@@ -7251,9 +7265,9 @@ GRE DEMULTIPLEXER DRIVER
 M:     Dmitry Kozlov <xeb@mail.ru>
 L:     netdev@vger.kernel.org
 S:     Maintained
+F:     include/net/gre.h
 F:     net/ipv4/gre_demux.c
 F:     net/ipv4/gre_offload.c
-F:     include/net/gre.h
 
 GRETH 10/100/1G Ethernet MAC device driver
 M:     Andreas Larsson <andreas@gaisler.com>
@@ -7303,17 +7317,17 @@ F:      drivers/staging/greybus/loopback.c
 GREYBUS PLATFORM DRIVERS
 M:     Vaibhav Hiremath <hvaibhav.linux@gmail.com>
 S:     Maintained
-F:     drivers/staging/greybus/arche-platform.c
 F:     drivers/staging/greybus/arche-apb-ctrl.c
+F:     drivers/staging/greybus/arche-platform.c
 F:     drivers/staging/greybus/arche_platform.h
 
 GREYBUS SDIO/GPIO/SPI PROTOCOLS DRIVERS
 M:     Rui Miguel Silva <rmfrfs@gmail.com>
 S:     Maintained
-F:     drivers/staging/greybus/sdio.c
-F:     drivers/staging/greybus/light.c
 F:     drivers/staging/greybus/gpio.c
+F:     drivers/staging/greybus/light.c
 F:     drivers/staging/greybus/power_supply.c
+F:     drivers/staging/greybus/sdio.c
 F:     drivers/staging/greybus/spi.c
 F:     drivers/staging/greybus/spilib.c
 
@@ -7321,81 +7335,81 @@ GREYBUS SUBSYSTEM
 M:     Johan Hovold <johan@kernel.org>
 M:     Alex Elder <elder@kernel.org>
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+L:     greybus-dev@lists.linaro.org (moderated for non-subscribers)
 S:     Maintained
-F:     drivers/staging/greybus/
 F:     drivers/greybus/
+F:     drivers/staging/greybus/
 F:     include/linux/greybus.h
 F:     include/linux/greybus/
-L:     greybus-dev@lists.linaro.org (moderated for non-subscribers)
 
 GREYBUS UART PROTOCOLS DRIVERS
 M:     David Lin <dtwlin@gmail.com>
 S:     Maintained
-F:     drivers/staging/greybus/uart.c
 F:     drivers/staging/greybus/log.c
+F:     drivers/staging/greybus/uart.c
 
 GS1662 VIDEO SERIALIZER
 M:     Charles-Antoine Couret <charles-antoine.couret@nexvision.fr>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/spi/gs1662.c
 
 GSPCA FINEPIX SUBDRIVER
 M:     Frank Zago <frank@zago.net>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/usb/gspca/finepix.c
 
 GSPCA GL860 SUBDRIVER
 M:     Olivier Lorin <o.lorin@laposte.net>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/usb/gspca/gl860/
 
 GSPCA M5602 SUBDRIVER
 M:     Erik Andren <erik.andren@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/usb/gspca/m5602/
 
 GSPCA PAC207 SONIXB SUBDRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Odd Fixes
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/usb/gspca/pac207.c
 
 GSPCA SN9C20X SUBDRIVER
 M:     Brian Johnson <brijohn@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/usb/gspca/sn9c20x.c
 
 GSPCA T613 SUBDRIVER
 M:     Leandro Costantino <lcostantino@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/usb/gspca/t613.c
 
 GSPCA USB WEBCAM DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Odd Fixes
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/usb/gspca/
 
 GTP (GPRS Tunneling Protocol)
 M:     Pablo Neira Ayuso <pablo@netfilter.org>
 M:     Harald Welte <laforge@gnumonks.org>
 L:     osmocom-net-gprs@lists.osmocom.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/gtp.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/gtp.git
 F:     drivers/net/gtp.c
 
 GUID PARTITION TABLE (GPT)
@@ -7407,33 +7421,43 @@ F:      block/partitions/efi.*
 H8/300 ARCHITECTURE
 M:     Yoshinori Sato <ysato@users.sourceforge.jp>
 L:     uclinux-h8-devel@lists.sourceforge.jp (moderated for non-subscribers)
+S:     Maintained
 W:     http://uclinux-h8.sourceforge.jp
 T:     git git://git.sourceforge.jp/gitroot/uclinux-h8/linux.git
-S:     Maintained
 F:     arch/h8300/
-F:     drivers/clocksource/h8300_*.c
 F:     drivers/clk/h8300/
+F:     drivers/clocksource/h8300_*.c
 F:     drivers/irqchip/irq-renesas-h8*.c
 
 HABANALABS PCI DRIVER
 M:     Oded Gabbay <oded.gabbay@gmail.com>
-T:     git https://github.com/HabanaAI/linux.git
 S:     Supported
+T:     git https://github.com/HabanaAI/linux.git
+F:     Documentation/ABI/testing/debugfs-driver-habanalabs
+F:     Documentation/ABI/testing/sysfs-driver-habanalabs
 F:     drivers/misc/habanalabs/
 F:     include/uapi/misc/habanalabs.h
-F:     Documentation/ABI/testing/sysfs-driver-habanalabs
-F:     Documentation/ABI/testing/debugfs-driver-habanalabs
 
 HACKRF MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/usb/hackrf/
 
+HANTRO VPU CODEC DRIVER
+M:     Ezequiel Garcia <ezequiel@collabora.com>
+M:     Philipp Zabel <p.zabel@pengutronix.de>
+L:     linux-media@vger.kernel.org
+L:     linux-rockchip@lists.infradead.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/media/nxp,imx8mq-vpu.yaml
+F:     Documentation/devicetree/bindings/media/rockchip-vpu.txt
+F:     drivers/staging/media/hantro/
+
 HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
 M:     Frank Seidel <frank@f-seidel.de>
 L:     platform-driver-x86@vger.kernel.org
@@ -7445,9 +7469,9 @@ HARDWARE MONITORING
 M:     Jean Delvare <jdelvare@suse.com>
 M:     Guenter Roeck <linux@roeck-us.net>
 L:     linux-hwmon@vger.kernel.org
+S:     Maintained
 W:     http://hwmon.wiki.kernel.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
-S:     Maintained
 F:     Documentation/devicetree/bindings/hwmon/
 F:     Documentation/hwmon/
 F:     drivers/hwmon/
@@ -7459,16 +7483,11 @@ M:      Matt Mackall <mpm@selenic.com>
 M:     Herbert Xu <herbert@gondor.apana.org.au>
 L:     linux-crypto@vger.kernel.org
 S:     Odd fixes
-F:     Documentation/devicetree/bindings/rng/
 F:     Documentation/admin-guide/hw_random.rst
+F:     Documentation/devicetree/bindings/rng/
 F:     drivers/char/hw_random/
 F:     include/linux/hw_random.h
 
-HARDWARE TRACING FACILITIES
-M:     Alexander Shishkin <alexander.shishkin@linux.intel.com>
-S:     Maintained
-F:     drivers/hwtracing/
-
 HARDWARE SPINLOCK CORE
 M:     Ohad Ben-Cohen <ohad@wizery.com>
 M:     Bjorn Andersson <bjorn.andersson@linaro.org>
@@ -7481,6 +7500,11 @@ F:       Documentation/hwspinlock.txt
 F:     drivers/hwspinlock/
 F:     include/linux/hwspinlock.h
 
+HARDWARE TRACING FACILITIES
+M:     Alexander Shishkin <alexander.shishkin@linux.intel.com>
+S:     Maintained
+F:     drivers/hwtracing/
+
 HARMONY SOUND DRIVER
 L:     linux-parisc@vger.kernel.org
 S:     Maintained
@@ -7489,9 +7513,9 @@ F:        sound/parisc/harmony.*
 HDPVR USB VIDEO ENCODER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Odd Fixes
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/usb/hdpvr/
 
 HEWLETT PACKARD ENTERPRISE ILO NMI WATCHDOG DRIVER
@@ -7532,30 +7556,30 @@ F:      fs/hfsplus/
 HGA FRAMEBUFFER DRIVER
 M:     Ferenc Bakonyi <fero@drama.obuda.kando.hu>
 L:     linux-nvidia@lists.surfsouth.com
-W:     http://drama.obuda.kando.hu/~fero/cgi-bin/hgafb.shtml
 S:     Maintained
+W:     http://drama.obuda.kando.hu/~fero/cgi-bin/hgafb.shtml
 F:     drivers/video/fbdev/hgafb.c
 
 HIBERNATION (aka Software Suspend, aka swsusp)
 M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
 M:     Pavel Machek <pavel@ucw.cz>
 L:     linux-pm@vger.kernel.org
-B:     https://bugzilla.kernel.org
 S:     Supported
+B:     https://bugzilla.kernel.org
+F:     arch/*/include/asm/suspend*.h
 F:     arch/x86/power/
 F:     drivers/base/power/
-F:     kernel/power/
-F:     include/linux/suspend.h
 F:     include/linux/freezer.h
 F:     include/linux/pm.h
-F:     arch/*/include/asm/suspend*.h
+F:     include/linux/suspend.h
+F:     kernel/power/
 
 HID CORE LAYER
 M:     Jiri Kosina <jikos@kernel.org>
 M:     Benjamin Tissoires <benjamin.tissoires@redhat.com>
 L:     linux-input@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
 F:     drivers/hid/
 F:     include/linux/hid*
 F:     include/uapi/linux/hid*
@@ -7575,14 +7599,14 @@ F:      include/linux/hid-sensor-*
 HIGH-RESOLUTION TIMERS, CLOCKEVENTS
 M:     Thomas Gleixner <tglx@linutronix.de>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 F:     Documentation/timers/
-F:     kernel/time/hrtimer.c
-F:     kernel/time/clockevents.c
-F:     kernel/time/timer_*.c
 F:     include/linux/clockchips.h
 F:     include/linux/hrtimer.h
+F:     kernel/time/clockevents.c
+F:     kernel/time/hrtimer.c
+F:     kernel/time/timer_*.c
 
 HIGH-SPEED SCC DRIVER FOR AX.25
 L:     linux-hams@vger.kernel.org
@@ -7592,8 +7616,8 @@ F:        drivers/net/hamradio/scc.c
 
 HIGHPOINT ROCKETRAID 3xxx RAID DRIVER
 M:     HighPoint Linux Team <linux@highpoint-tech.com>
-W:     http://www.highpoint-tech.com
 S:     Supported
+W:     http://www.highpoint-tech.com
 F:     Documentation/scsi/hptiop.rst
 F:     drivers/scsi/hptiop.c
 
@@ -7601,10 +7625,10 @@ HIPPI
 M:     Jes Sorensen <jes@trained-monkey.org>
 L:     linux-hippi@sunsite.dk
 S:     Maintained
+F:     drivers/net/hippi/
 F:     include/linux/hippidevice.h
 F:     include/uapi/linux/if_hippi.h
 F:     net/802/hippi.c
-F:     drivers/net/hippi/
 
 HISILICON DMA DRIVER
 M:     Zhou Wang <wangzhou1@hisilicon.com>
@@ -7612,60 +7636,55 @@ L:      dmaengine@vger.kernel.org
 S:     Maintained
 F:     drivers/dma/hisi_dma.c
 
-HISILICON SECURITY ENGINE V2 DRIVER (SEC2)
-M:     Zaibo Xu <xuzaibo@huawei.com>
-L:     linux-crypto@vger.kernel.org
-S:     Maintained
-F:     drivers/crypto/hisilicon/sec2/sec_crypto.c
-F:     drivers/crypto/hisilicon/sec2/sec_main.c
-F:     drivers/crypto/hisilicon/sec2/sec_crypto.h
-F:     drivers/crypto/hisilicon/sec2/sec.h
-F:     Documentation/ABI/testing/debugfs-hisi-sec
-
 HISILICON HIGH PERFORMANCE RSA ENGINE DRIVER (HPRE)
 M:     Zaibo Xu <xuzaibo@huawei.com>
 L:     linux-crypto@vger.kernel.org
 S:     Maintained
+F:     Documentation/ABI/testing/debugfs-hisi-hpre
+F:     drivers/crypto/hisilicon/hpre/hpre.h
 F:     drivers/crypto/hisilicon/hpre/hpre_crypto.c
 F:     drivers/crypto/hisilicon/hpre/hpre_main.c
-F:     drivers/crypto/hisilicon/hpre/hpre.h
-F:     Documentation/ABI/testing/debugfs-hisi-hpre
-
-HISILICON NETWORK SUBSYSTEM 3 DRIVER (HNS3)
-M:     Yisen Zhuang <yisen.zhuang@huawei.com>
-M:     Salil Mehta <salil.mehta@huawei.com>
-L:     netdev@vger.kernel.org
-W:     http://www.hisilicon.com
-S:     Maintained
-F:     drivers/net/ethernet/hisilicon/hns3/
-
-HISILICON TRUE RANDOM NUMBER GENERATOR V2 SUPPORT
-M:     Zaibo Xu <xuzaibo@huawei.com>
-S:     Maintained
-F:     drivers/char/hw_random/hisi-trng-v2.c
 
 HISILICON LPC BUS DRIVER
 M:     john.garry@huawei.com
+S:     Maintained
 W:     http://www.hisilicon.com
+F:     Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
+F:     drivers/bus/hisi_lpc.c
+
+HISILICON NETWORK SUBSYSTEM 3 DRIVER (HNS3)
+M:     Yisen Zhuang <yisen.zhuang@huawei.com>
+M:     Salil Mehta <salil.mehta@huawei.com>
+L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/bus/hisi_lpc.c
-F:     Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
+W:     http://www.hisilicon.com
+F:     drivers/net/ethernet/hisilicon/hns3/
 
 HISILICON NETWORK SUBSYSTEM DRIVER
 M:     Yisen Zhuang <yisen.zhuang@huawei.com>
 M:     Salil Mehta <salil.mehta@huawei.com>
 L:     netdev@vger.kernel.org
-W:     http://www.hisilicon.com
 S:     Maintained
-F:     drivers/net/ethernet/hisilicon/
+W:     http://www.hisilicon.com
 F:     Documentation/devicetree/bindings/net/hisilicon*.txt
+F:     drivers/net/ethernet/hisilicon/
 
 HISILICON PMU DRIVER
 M:     Shaokun Zhang <zhangshaokun@hisilicon.com>
-W:     http://www.hisilicon.com
 S:     Supported
-F:     drivers/perf/hisilicon
+W:     http://www.hisilicon.com
 F:     Documentation/admin-guide/perf/hisi-pmu.rst
+F:     drivers/perf/hisilicon
+
+HISILICON QM AND ZIP Controller DRIVER
+M:     Zhou Wang <wangzhou1@hisilicon.com>
+L:     linux-crypto@vger.kernel.org
+S:     Maintained
+F:     Documentation/ABI/testing/debugfs-hisi-zip
+F:     drivers/crypto/hisilicon/qm.c
+F:     drivers/crypto/hisilicon/qm.h
+F:     drivers/crypto/hisilicon/sgl.c
+F:     drivers/crypto/hisilicon/zip/
 
 HISILICON ROCE DRIVER
 M:     Lijun Ou <oulijun@huawei.com>
@@ -7673,45 +7692,50 @@ M:      Wei Hu(Xavier) <huwei87@hisilicon.com>
 M:     Weihang Li <liweihang@huawei.com>
 L:     linux-rdma@vger.kernel.org
 S:     Maintained
-F:     drivers/infiniband/hw/hns/
 F:     Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt
+F:     drivers/infiniband/hw/hns/
 
 HISILICON SAS Controller
 M:     John Garry <john.garry@huawei.com>
-W:     http://www.hisilicon.com
 S:     Supported
-F:     drivers/scsi/hisi_sas/
+W:     http://www.hisilicon.com
 F:     Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
+F:     drivers/scsi/hisi_sas/
+
+HISILICON SECURITY ENGINE V2 DRIVER (SEC2)
+M:     Zaibo Xu <xuzaibo@huawei.com>
+L:     linux-crypto@vger.kernel.org
+S:     Maintained
+F:     Documentation/ABI/testing/debugfs-hisi-sec
+F:     drivers/crypto/hisilicon/sec2/sec.h
+F:     drivers/crypto/hisilicon/sec2/sec_crypto.c
+F:     drivers/crypto/hisilicon/sec2/sec_crypto.h
+F:     drivers/crypto/hisilicon/sec2/sec_main.c
+
+HISILICON TRUE RANDOM NUMBER GENERATOR V2 SUPPORT
+M:     Zaibo Xu <xuzaibo@huawei.com>
+S:     Maintained
+F:     drivers/char/hw_random/hisi-trng-v2.c
 
 HISILICON V3XX SPI NOR FLASH Controller Driver
 M:     John Garry <john.garry@huawei.com>
-W:     http://www.hisilicon.com
 S:     Maintained
+W:     http://www.hisilicon.com
 F:     drivers/spi/spi-hisi-sfc-v3xx.c
 
-HISILICON QM AND ZIP Controller DRIVER
-M:     Zhou Wang <wangzhou1@hisilicon.com>
-L:     linux-crypto@vger.kernel.org
-S:     Maintained
-F:     drivers/crypto/hisilicon/qm.c
-F:     drivers/crypto/hisilicon/qm.h
-F:     drivers/crypto/hisilicon/sgl.c
-F:     drivers/crypto/hisilicon/zip/
-F:     Documentation/ABI/testing/debugfs-hisi-zip
-
 HMM - Heterogeneous Memory Management
 M:     Jérôme Glisse <jglisse@redhat.com>
 L:     linux-mm@kvack.org
 S:     Maintained
-F:     mm/hmm*
-F:     include/linux/hmm*
 F:     Documentation/vm/hmm.rst
+F:     include/linux/hmm*
+F:     mm/hmm*
 
 HOST AP DRIVER
 M:     Jouni Malinen <j@w1.fi>
 L:     linux-wireless@vger.kernel.org
-W:     http://w1.fi/hostap-driver.html
 S:     Obsolete
+W:     http://w1.fi/hostap-driver.html
 F:     drivers/net/wireless/intersil/hostap/
 
 HP COMPAQ TC1100 TABLET WMI EXTRAS DRIVER
@@ -7734,19 +7758,19 @@ F:      include/uapi/linux/hpet.h
 
 HPET:  x86
 S:     Orphan
-F:     arch/x86/kernel/hpet.c
 F:     arch/x86/include/asm/hpet.h
+F:     arch/x86/kernel/hpet.c
 
 HPFS FILESYSTEM
 M:     Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>
-W:     http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
 S:     Maintained
+W:     http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
 F:     fs/hpfs/
 
 HSI SUBSYSTEM
 M:     Sebastian Reichel <sre@kernel.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi.git
 F:     Documentation/ABI/testing/sysfs-bus-hsi
 F:     Documentation/driver-api/hsi.rst
 F:     drivers/hsi/
@@ -7766,8 +7790,8 @@ F:        net/hsr/
 HT16K33 LED CONTROLLER DRIVER
 M:     Robin van der Gracht <robin@protonic.nl>
 S:     Maintained
-F:     drivers/auxdisplay/ht16k33.c
 F:     Documentation/devicetree/bindings/display/ht16k33.txt
+F:     drivers/auxdisplay/ht16k33.c
 
 HTCPEN TOUCHSCREEN DRIVER
 M:     Pau Oliva Fora <pof@eslack.org>
@@ -7778,10 +7802,10 @@ F:      drivers/input/touchscreen/htcpen.c
 HTS221 TEMPERATURE-HUMIDITY IIO DRIVER
 M:     Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
 L:     linux-iio@vger.kernel.org
-W:     http://www.st.com/
 S:     Maintained
-F:     drivers/iio/humidity/hts221*
+W:     http://www.st.com/
 F:     Documentation/devicetree/bindings/iio/humidity/hts221.txt
+F:     drivers/iio/humidity/hts221*
 
 HUAWEI ETHERNET DRIVER
 M:     Aviad Krawczyk <aviad.krawczyk@huawei.com>
@@ -7794,27 +7818,27 @@ HUGETLB FILESYSTEM
 M:     Mike Kravetz <mike.kravetz@oracle.com>
 L:     linux-mm@kvack.org
 S:     Maintained
-F:     fs/hugetlbfs/
-F:     mm/hugetlb.c
-F:     include/linux/hugetlb.h
+F:     Documentation/ABI/testing/sysfs-kernel-mm-hugepages
 F:     Documentation/admin-guide/mm/hugetlbpage.rst
 F:     Documentation/vm/hugetlbfs_reserv.rst
-F:     Documentation/ABI/testing/sysfs-kernel-mm-hugepages
+F:     fs/hugetlbfs/
+F:     include/linux/hugetlb.h
+F:     mm/hugetlb.c
 
 HVA ST MEDIA DRIVER
 M:     Jean-Christophe Trotin <jean-christophe.trotin@st.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Supported
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/platform/sti/hva
 
 HWPOISON MEMORY FAILURE HANDLING
 M:     Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
 L:     linux-mm@kvack.org
 S:     Maintained
-F:     mm/memory-failure.c
 F:     mm/hwpoison-inject.c
+F:     mm/memory-failure.c
 
 HYGON PROCESSOR SUPPORT
 M:     Pu Wen <puwen@hygon.cn>
@@ -7825,8 +7849,8 @@ F:        arch/x86/kernel/cpu/hygon.c
 HYNIX HI556 SENSOR DRIVER
 M:     Shawn Tu <shawnx.tu@intel.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/hi556.c
 
 Hyper-V CORE AND DRIVERS
@@ -7834,46 +7858,46 @@ M:      "K. Y. Srinivasan" <kys@microsoft.com>
 M:     Haiyang Zhang <haiyangz@microsoft.com>
 M:     Stephen Hemminger <sthemmin@microsoft.com>
 M:     Wei Liu <wei.liu@kernel.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
 L:     linux-hyperv@vger.kernel.org
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
+F:     Documentation/ABI/stable/sysfs-bus-vmbus
+F:     Documentation/ABI/testing/debugfs-hyperv
 F:     Documentation/networking/device_drivers/microsoft/netvsc.txt
+F:     arch/x86/hyperv
+F:     arch/x86/include/asm/hyperv-tlfs.h
 F:     arch/x86/include/asm/mshyperv.h
 F:     arch/x86/include/asm/trace/hyperv.h
-F:     arch/x86/include/asm/hyperv-tlfs.h
 F:     arch/x86/kernel/cpu/mshyperv.c
-F:     arch/x86/hyperv
 F:     drivers/clocksource/hyperv_timer.c
 F:     drivers/hid/hid-hyperv.c
 F:     drivers/hv/
 F:     drivers/input/serio/hyperv-keyboard.c
-F:     drivers/pci/controller/pci-hyperv.c
-F:     drivers/pci/controller/pci-hyperv-intf.c
+F:     drivers/iommu/hyperv-iommu.c
 F:     drivers/net/hyperv/
+F:     drivers/pci/controller/pci-hyperv-intf.c
+F:     drivers/pci/controller/pci-hyperv.c
 F:     drivers/scsi/storvsc_drv.c
 F:     drivers/uio/uio_hv_generic.c
 F:     drivers/video/fbdev/hyperv_fb.c
-F:     drivers/iommu/hyperv-iommu.c
-F:     net/vmw_vsock/hyperv_transport.c
+F:     include/asm-generic/mshyperv.h
 F:     include/clocksource/hyperv_timer.h
 F:     include/linux/hyperv.h
 F:     include/uapi/linux/hyperv.h
-F:     include/asm-generic/mshyperv.h
+F:     net/vmw_vsock/hyperv_transport.c
 F:     tools/hv/
-F:     Documentation/ABI/stable/sysfs-bus-vmbus
-F:     Documentation/ABI/testing/debugfs-hyperv
 
 HYPERBUS SUPPORT
 M:     Vignesh Raghavendra <vigneshr@ti.com>
 L:     linux-mtd@lists.infradead.org
+S:     Supported
 Q:     http://patchwork.ozlabs.org/project/linux-mtd/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git cfi/next
 C:     irc://irc.oftc.net/mtd
-S:     Supported
-F:     drivers/mtd/hyperbus/
-F:     include/linux/mtd/hyperbus.h
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git cfi/next
 F:     Documentation/devicetree/bindings/mtd/cypress,hyperflash.txt
 F:     Documentation/devicetree/bindings/mtd/ti,am654-hbmc.txt
+F:     drivers/mtd/hyperbus/
+F:     include/linux/mtd/hyperbus.h
 
 HYPERVISOR VIRTUAL CONSOLE DRIVER
 L:     linuxppc-dev@lists.ozlabs.org
@@ -7898,11 +7922,11 @@ I2C MUXES
 M:     Peter Rosin <peda@axentia.se>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
-F:     Documentation/i2c/i2c-topology.rst
-F:     Documentation/i2c/muxes/
-F:     Documentation/devicetree/bindings/i2c/i2c-mux*
 F:     Documentation/devicetree/bindings/i2c/i2c-arb*
 F:     Documentation/devicetree/bindings/i2c/i2c-gate*
+F:     Documentation/devicetree/bindings/i2c/i2c-mux*
+F:     Documentation/i2c/i2c-topology.rst
+F:     Documentation/i2c/muxes/
 F:     drivers/i2c/i2c-mux.c
 F:     drivers/i2c/muxes/
 F:     include/linux/i2c-mux.h
@@ -7924,25 +7948,25 @@ F:      drivers/i2c/busses/i2c-parport.c
 I2C SUBSYSTEM
 M:     Wolfram Sang <wsa@the-dreams.de>
 L:     linux-i2c@vger.kernel.org
+S:     Maintained
 W:     https://i2c.wiki.kernel.org/
 Q:     https://patchwork.ozlabs.org/project/linux-i2c/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
-S:     Maintained
 F:     Documentation/devicetree/bindings/i2c/i2c.txt
 F:     Documentation/i2c/
 F:     drivers/i2c/*
-F:     include/linux/i2c.h
 F:     include/linux/i2c-dev.h
 F:     include/linux/i2c-smbus.h
-F:     include/uapi/linux/i2c.h
+F:     include/linux/i2c.h
 F:     include/uapi/linux/i2c-*.h
+F:     include/uapi/linux/i2c.h
 
 I2C SUBSYSTEM HOST DRIVERS
 L:     linux-i2c@vger.kernel.org
+S:     Odd Fixes
 W:     https://i2c.wiki.kernel.org/
 Q:     https://patchwork.ozlabs.org/project/linux-i2c/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
-S:     Odd Fixes
 F:     Documentation/devicetree/bindings/i2c/
 F:     drivers/i2c/algos/
 F:     drivers/i2c/busses/
@@ -7957,8 +7981,8 @@ F:        drivers/i2c/busses/i2c-taos-evm.c
 I2C-TINY-USB DRIVER
 M:     Till Harbaum <till@harbaum.org>
 L:     linux-i2c@vger.kernel.org
-W:     http://www.harbaum.org/till/i2c_tiny_usb
 S:     Maintained
+W:     http://www.harbaum.org/till/i2c_tiny_usb
 F:     drivers/i2c/busses/i2c-tiny-usb.c
 
 I2C/SMBUS CONTROLLER DRIVERS FOR PC
@@ -7981,13 +8005,13 @@ F:      Documentation/i2c/busses/i2c-viapro.rst
 F:     drivers/i2c/busses/i2c-ali1535.c
 F:     drivers/i2c/busses/i2c-ali1563.c
 F:     drivers/i2c/busses/i2c-ali15x3.c
-F:     drivers/i2c/busses/i2c-amd756.c
 F:     drivers/i2c/busses/i2c-amd756-s4882.c
+F:     drivers/i2c/busses/i2c-amd756.c
 F:     drivers/i2c/busses/i2c-amd8111.c
 F:     drivers/i2c/busses/i2c-i801.c
 F:     drivers/i2c/busses/i2c-isch.c
-F:     drivers/i2c/busses/i2c-nforce2.c
 F:     drivers/i2c/busses/i2c-nforce2-s4985.c
+F:     drivers/i2c/busses/i2c-nforce2.c
 F:     drivers/i2c/busses/i2c-piix4.c
 F:     drivers/i2c/busses/i2c-sis5595.c
 F:     drivers/i2c/busses/i2c-sis630.c
@@ -8005,8 +8029,8 @@ I2C/SMBUS ISMT DRIVER
 M:     Seth Heasley <seth.heasley@intel.com>
 M:     Neil Horman <nhorman@tuxdriver.com>
 L:     linux-i2c@vger.kernel.org
-F:     drivers/i2c/busses/i2c-ismt.c
 F:     Documentation/i2c/busses/i2c-ismt.rst
+F:     drivers/i2c/busses/i2c-ismt.c
 
 I2C/SMBUS STUB DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
@@ -8014,47 +8038,47 @@ L:      linux-i2c@vger.kernel.org
 S:     Maintained
 F:     drivers/i2c/i2c-stub.c
 
+I3C DRIVER FOR CADENCE I3C MASTER IP
+M:     Przemysław Gaj <pgaj@cadence.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/i3c/cdns,i3c-master.txt
+F:     drivers/i3c/master/i3c-master-cdns.c
+
+I3C DRIVER FOR SYNOPSYS DESIGNWARE
+M:     Vitor Soares <vitor.soares@synopsys.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.txt
+F:     drivers/i3c/master/dw*
+
 I3C SUBSYSTEM
 M:     Boris Brezillon <bbrezillon@kernel.org>
 L:     linux-i3c@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
 C:     irc://chat.freenode.net/linux-i3c
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux.git
-S:     Maintained
 F:     Documentation/ABI/testing/sysfs-bus-i3c
 F:     Documentation/devicetree/bindings/i3c/
 F:     Documentation/driver-api/i3c
 F:     drivers/i3c/
 F:     include/linux/i3c/
 
-I3C DRIVER FOR SYNOPSYS DESIGNWARE
-M:     Vitor Soares <vitor.soares@synopsys.com>
-S:     Maintained
-F:     Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.txt
-F:     drivers/i3c/master/dw*
-
-I3C DRIVER FOR CADENCE I3C MASTER IP
-M:     Przemysław Gaj <pgaj@cadence.com>
-S:     Maintained
-F:     Documentation/devicetree/bindings/i3c/cdns,i3c-master.txt
-F:     drivers/i3c/master/i3c-master-cdns.c
-
 IA64 (Itanium) PLATFORM
 M:     Tony Luck <tony.luck@intel.com>
 M:     Fenghua Yu <fenghua.yu@intel.com>
 L:     linux-ia64@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git
 S:     Maintained
-F:     arch/ia64/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git
 F:     Documentation/ia64/
+F:     arch/ia64/
 
 IBM Power 842 compression accelerator
 M:     Haren Myneni <haren@us.ibm.com>
 S:     Supported
-F:     drivers/crypto/nx/Makefile
+F:     crypto/842.c
 F:     drivers/crypto/nx/Kconfig
+F:     drivers/crypto/nx/Makefile
 F:     drivers/crypto/nx/nx-842*
 F:     include/linux/sw842.h
-F:     crypto/842.c
 F:     lib/842/
 
 IBM Power in-Nest Crypto Acceleration
@@ -8063,19 +8087,33 @@ M:      Nayna Jain <nayna@linux.ibm.com>
 M:     Paulo Flabiano Smorigo <pfsmorigo@gmail.com>
 L:     linux-crypto@vger.kernel.org
 S:     Supported
-F:     drivers/crypto/nx/Makefile
 F:     drivers/crypto/nx/Kconfig
+F:     drivers/crypto/nx/Makefile
 F:     drivers/crypto/nx/nx-aes*
 F:     drivers/crypto/nx/nx-sha*
 F:     drivers/crypto/nx/nx.*
 F:     drivers/crypto/nx/nx_csbcpb.h
 F:     drivers/crypto/nx/nx_debugfs.c
 
+IBM Power IO DLPAR Driver for RPA-compliant PPC64 platform
+M:     Tyrel Datwyler <tyreld@linux.ibm.com>
+L:     linux-pci@vger.kernel.org
+L:     linuxppc-dev@lists.ozlabs.org
+S:     Supported
+F:     drivers/pci/hotplug/rpadlpar*
+
 IBM Power Linux RAID adapter
 M:     Brian King <brking@us.ibm.com>
 S:     Supported
 F:     drivers/scsi/ipr.*
 
+IBM Power PCI Hotplug Driver for RPA-compliant PPC64 platform
+M:     Tyrel Datwyler <tyreld@linux.ibm.com>
+L:     linux-pci@vger.kernel.org
+L:     linuxppc-dev@lists.ozlabs.org
+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>
@@ -8087,9 +8125,9 @@ IBM Power Virtual Accelerator Switchboard
 M:     Sukadev Bhattiprolu <sukadev@linux.ibm.com>
 L:     linuxppc-dev@lists.ozlabs.org
 S:     Supported
-F:     arch/powerpc/platforms/powernv/vas*
-F:     arch/powerpc/platforms/powernv/copy-paste.h
 F:     arch/powerpc/include/asm/vas.h
+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>
@@ -8128,26 +8166,12 @@ M:      Nayna Jain <nayna@linux.ibm.com>
 M:     Paulo Flabiano Smorigo <pfsmorigo@gmail.com>
 L:     linux-crypto@vger.kernel.org
 S:     Supported
-F:     drivers/crypto/vmx/Makefile
 F:     drivers/crypto/vmx/Kconfig
-F:     drivers/crypto/vmx/vmx.c
+F:     drivers/crypto/vmx/Makefile
 F:     drivers/crypto/vmx/aes*
 F:     drivers/crypto/vmx/ghash*
 F:     drivers/crypto/vmx/ppc-xlate.pl
-
-IBM Power PCI Hotplug Driver for RPA-compliant PPC64 platform
-M:     Tyrel Datwyler <tyreld@linux.ibm.com>
-L:     linux-pci@vger.kernel.org
-L:     linuxppc-dev@lists.ozlabs.org
-S:     Supported
-F:     drivers/pci/hotplug/rpaphp*
-
-IBM Power IO DLPAR Driver for RPA-compliant PPC64 platform
-M:     Tyrel Datwyler <tyreld@linux.ibm.com>
-L:     linux-pci@vger.kernel.org
-L:     linuxppc-dev@lists.ozlabs.org
-S:     Supported
-F:     drivers/pci/hotplug/rpadlpar*
+F:     drivers/crypto/vmx/vmx.c
 
 IBM ServeRAID RAID DRIVER
 S:     Orphan
@@ -8168,9 +8192,9 @@ F:        drivers/i2c/busses/i2c-icy.c
 IDE SUBSYSTEM
 M:     "David S. Miller" <davem@davemloft.net>
 L:     linux-ide@vger.kernel.org
+S:     Maintained
 Q:     http://patchwork.ozlabs.org/project/linux-ide/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide.git
-S:     Maintained
 F:     Documentation/ide/
 F:     drivers/ide/
 F:     include/linux/ide.h
@@ -8205,28 +8229,28 @@ IEEE 802.15.4 SUBSYSTEM
 M:     Alexander Aring <alex.aring@gmail.com>
 M:     Stefan Schmidt <stefan@datenfreihafen.org>
 L:     linux-wpan@vger.kernel.org
+S:     Maintained
 W:     http://wpan.cakelab.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sschmidt/wpan.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sschmidt/wpan-next.git
-S:     Maintained
-F:     net/ieee802154/
-F:     net/mac802154/
+F:     Documentation/networking/ieee802154.rst
 F:     drivers/net/ieee802154/
-F:     include/linux/nl802154.h
 F:     include/linux/ieee802154.h
-F:     include/net/nl802154.h
-F:     include/net/mac802154.h
+F:     include/linux/nl802154.h
 F:     include/net/af_ieee802154.h
 F:     include/net/cfg802154.h
 F:     include/net/ieee802154_netdev.h
-F:     Documentation/networking/ieee802154.rst
+F:     include/net/mac802154.h
+F:     include/net/nl802154.h
+F:     net/ieee802154/
+F:     net/mac802154/
 
 IFE PROTOCOL
 M:     Yotam Gigi <yotam.gi@gmail.com>
 M:     Jamal Hadi Salim <jhs@mojatatu.com>
-F:     net/ife
 F:     include/net/ife.h
 F:     include/uapi/linux/ife.h
+F:     net/ife
 
 IGORPLUG-USB IR RECEIVER
 M:     Sean Young <sean@mess.org>
@@ -8269,8 +8293,8 @@ R:        Hartmut Knaack <knaack.h@gmx.de>
 R:     Lars-Peter Clausen <lars@metafoo.de>
 R:     Peter Meerwald-Stadler <pmeerw@pmeerw.net>
 L:     linux-iio@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
 F:     Documentation/ABI/testing/configfs-iio*
 F:     Documentation/ABI/testing/sysfs-bus-iio*
 F:     Documentation/devicetree/bindings/iio/
@@ -8308,8 +8332,8 @@ IMON SOUNDGRAPH USB IR RECEIVER
 M:     Sean Young <sean@mess.org>
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     drivers/media/rc/imon_raw.c
 F:     drivers/media/rc/imon.c
+F:     drivers/media/rc/imon_raw.c
 
 IMS TWINTURBO FRAMEBUFFER DRIVER
 L:     linux-fbdev@vger.kernel.org
@@ -8320,8 +8344,8 @@ INA209 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
 L:     linux-hwmon@vger.kernel.org
 S:     Maintained
-F:     Documentation/hwmon/ina209.rst
 F:     Documentation/devicetree/bindings/hwmon/ina2xx.txt
+F:     Documentation/hwmon/ina209.rst
 F:     drivers/hwmon/ina209.c
 
 INA2XX HARDWARE MONITOR DRIVER
@@ -8337,32 +8361,32 @@ M:      Samuel Iglesias Gonsalvez <siglesias@igalia.com>
 M:     Jens Taprogge <jens.taprogge@taprogge.org>
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 L:     industrypack-devel@lists.sourceforge.net
-W:     http://industrypack.sourceforge.net
 S:     Maintained
+W:     http://industrypack.sourceforge.net
 F:     drivers/ipack/
 
 INFINEON DPS310 Driver
 M:     Eddie James <eajames@linux.ibm.com>
 L:     linux-iio@vger.kernel.org
-F:     drivers/iio/pressure/dps310.c
 S:     Maintained
+F:     drivers/iio/pressure/dps310.c
 
 INFINIBAND SUBSYSTEM
 M:     Doug Ledford <dledford@redhat.com>
 M:     Jason Gunthorpe <jgg@mellanox.com>
 L:     linux-rdma@vger.kernel.org
+S:     Supported
 W:     https://github.com/linux-rdma/rdma-core
 Q:     http://patchwork.kernel.org/project/linux-rdma/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git
-S:     Supported
 F:     Documentation/devicetree/bindings/infiniband/
 F:     Documentation/infiniband/
 F:     drivers/infiniband/
-F:     include/uapi/linux/if_infiniband.h
-F:     include/uapi/rdma/
 F:     include/rdma/
 F:     include/trace/events/ib_mad.h
 F:     include/trace/events/ib_umad.h
+F:     include/uapi/linux/if_infiniband.h
+F:     include/uapi/rdma/
 F:     samples/bpf/ibumad_kern.c
 F:     samples/bpf/ibumad_user.c
 
@@ -8401,8 +8425,8 @@ F:        drivers/usb/musb/jz4740.c
 F:     drivers/watchdog/jz4740_wdt.c
 F:     include/dt-bindings/iio/adc/ingenic,adc.h
 F:     include/linux/mfd/ingenic-tcu.h
-F:     sound/soc/jz4740/
 F:     sound/soc/codecs/jz47*
+F:     sound/soc/jz4740/
 
 INOTIFY
 M:     Jan Kara <jack@suse.cz>
@@ -8417,17 +8441,17 @@ F:      include/uapi/linux/inotify.h
 INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
 M:     Dmitry Torokhov <dmitry.torokhov@gmail.com>
 L:     linux-input@vger.kernel.org
+S:     Maintained
 Q:     http://patchwork.kernel.org/project/linux-input/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git
-S:     Maintained
-F:     drivers/input/
-F:     include/linux/input.h
-F:     include/uapi/linux/input.h
-F:     include/uapi/linux/input-event-codes.h
-F:     include/linux/input/
 F:     Documentation/devicetree/bindings/input/
 F:     Documentation/devicetree/bindings/serio/
 F:     Documentation/input/
+F:     drivers/input/
+F:     include/linux/input.h
+F:     include/linux/input/
+F:     include/uapi/linux/input-event-codes.h
+F:     include/uapi/linux/input.h
 
 INPUT MULTITOUCH (MT) PROTOCOL
 M:     Henrik Rydberg <rydberg@bitmath.org>
@@ -8439,16 +8463,16 @@ K:      \b(ABS|SYN)_MT_
 
 INSIDE SECURE CRYPTO DRIVER
 M:     Antoine Tenart <antoine.tenart@bootlin.com>
-F:     drivers/crypto/inside-secure/
-S:     Maintained
 L:     linux-crypto@vger.kernel.org
+S:     Maintained
+F:     drivers/crypto/inside-secure/
 
 INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
 M:     Mimi Zohar <zohar@linux.ibm.com>
 M:     Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
 L:     linux-integrity@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
 F:     security/integrity/ima/
 
 INTEL 810/815 FRAMEBUFFER DRIVER
@@ -8476,8 +8500,8 @@ INTEL C600 SERIES SAS CONTROLLER DRIVER
 M:     Intel SCU Linux support <intel-linux-scu@intel.com>
 M:     Artur Paszkiewicz <artur.paszkiewicz@intel.com>
 L:     linux-scsi@vger.kernel.org
-T:     git git://git.code.sf.net/p/intel-sas/isci
 S:     Supported
+T:     git git://git.code.sf.net/p/intel-sas/isci
 F:     drivers/scsi/isci/
 
 INTEL CPU family model numbers
@@ -8492,38 +8516,38 @@ M:      Jani Nikula <jani.nikula@linux.intel.com>
 M:     Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
 M:     Rodrigo Vivi <rodrigo.vivi@intel.com>
 L:     intel-gfx@lists.freedesktop.org
+S:     Supported
 W:     https://01.org/linuxgraphics/
+Q:     http://patchwork.freedesktop.org/project/intel-gfx/
 B:     https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs
 C:     irc://chat.freenode.net/intel-gfx
-Q:     http://patchwork.freedesktop.org/project/intel-gfx/
 T:     git git://anongit.freedesktop.org/drm-intel
-S:     Supported
+F:     Documentation/gpu/i915.rst
 F:     drivers/gpu/drm/i915/
 F:     include/drm/i915*
 F:     include/uapi/drm/i915_drm.h
-F:     Documentation/gpu/i915.rst
 
 INTEL ETHERNET DRIVERS
 M:     Jeff Kirsher <jeffrey.t.kirsher@intel.com>
 L:     intel-wired-lan@lists.osuosl.org (moderated for non-subscribers)
+S:     Supported
 W:     http://www.intel.com/support/feedback.htm
 W:     http://e1000.sourceforge.net/
 Q:     http://patchwork.ozlabs.org/project/intel-wired-lan/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-queue.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue.git
-S:     Supported
 F:     Documentation/networking/device_drivers/intel/e100.rst
 F:     Documentation/networking/device_drivers/intel/e1000.rst
 F:     Documentation/networking/device_drivers/intel/e1000e.rst
 F:     Documentation/networking/device_drivers/intel/fm10k.rst
+F:     Documentation/networking/device_drivers/intel/i40e.rst
+F:     Documentation/networking/device_drivers/intel/iavf.rst
+F:     Documentation/networking/device_drivers/intel/ice.rst
 F:     Documentation/networking/device_drivers/intel/igb.rst
 F:     Documentation/networking/device_drivers/intel/igbvf.rst
 F:     Documentation/networking/device_drivers/intel/ixgb.rst
 F:     Documentation/networking/device_drivers/intel/ixgbe.rst
 F:     Documentation/networking/device_drivers/intel/ixgbevf.rst
-F:     Documentation/networking/device_drivers/intel/i40e.rst
-F:     Documentation/networking/device_drivers/intel/iavf.rst
-F:     Documentation/networking/device_drivers/intel/ice.rst
 F:     drivers/net/ethernet/intel/
 F:     drivers/net/ethernet/intel/*/
 F:     include/linux/avf/virtchnl.h
@@ -8553,9 +8577,9 @@ M:        Zhenyu Wang <zhenyuw@linux.intel.com>
 M:     Zhi Wang <zhi.a.wang@intel.com>
 L:     intel-gvt-dev@lists.freedesktop.org
 L:     intel-gfx@lists.freedesktop.org
+S:     Supported
 W:     https://01.org/igvt-g
 T:     git https://github.com/intel/gvt-linux.git
-S:     Supported
 F:     drivers/gpu/drm/i915/gvt/
 
 INTEL HID EVENT DRIVER
@@ -8568,8 +8592,8 @@ INTEL I/OAT DMA DRIVER
 M:     Dave Jiang <dave.jiang@intel.com>
 R:     Dan Williams <dan.j.williams@intel.com>
 L:     dmaengine@vger.kernel.org
-Q:     https://patchwork.kernel.org/project/linux-dmaengine/list/
 S:     Supported
+Q:     https://patchwork.kernel.org/project/linux-dmaengine/list/
 F:     drivers/dma/ioat*
 
 INTEL IADX DRIVER
@@ -8583,9 +8607,9 @@ INTEL IDLE DRIVER
 M:     Jacob Pan <jacob.jun.pan@linux.intel.com>
 M:     Len Brown <lenb@kernel.org>
 L:     linux-pm@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git
-B:     https://bugzilla.kernel.org
 S:     Supported
+B:     https://bugzilla.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git
 F:     drivers/idle/intel_idle.c
 
 INTEL INTEGRATED SENSOR HUB DRIVER
@@ -8599,8 +8623,8 @@ INTEL IOMMU (VT-d)
 M:     David Woodhouse <dwmw2@infradead.org>
 M:     Lu Baolu <baolu.lu@linux.intel.com>
 L:     iommu@lists.linux-foundation.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
 F:     drivers/iommu/dmar.c
 F:     drivers/iommu/intel*.[ch]
 F:     include/linux/intel-iommu.h
@@ -8618,27 +8642,27 @@ M:      Bingbu Cao <bingbu.cao@intel.com>
 R:     Tian Shu Qiu <tian.shu.qiu@intel.com>
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     drivers/media/pci/intel/ipu3/
 F:     Documentation/media/uapi/v4l/pixfmt-srggb10-ipu3.rst
+F:     drivers/media/pci/intel/ipu3/
 
 INTEL IPU3 CSI-2 IMGU DRIVER
 M:     Sakari Ailus <sakari.ailus@linux.intel.com>
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     drivers/staging/media/ipu3/
 F:     Documentation/media/uapi/v4l/pixfmt-meta-intel-ipu3.rst
 F:     Documentation/media/v4l-drivers/ipu3.rst
 F:     Documentation/media/v4l-drivers/ipu3_rcb.svg
+F:     drivers/staging/media/ipu3/
 
 INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
 M:     Krzysztof Halasa <khalasa@piap.pl>
 S:     Maintained
-F:     include/linux/soc/ixp4xx/qmgr.h
-F:     include/linux/soc/ixp4xx/npe.h
-F:     drivers/soc/ixp4xx/ixp4xx-qmgr.c
-F:     drivers/soc/ixp4xx/ixp4xx-npe.c
 F:     drivers/net/ethernet/xscale/ixp4xx_eth.c
 F:     drivers/net/wan/ixp4xx_hss.c
+F:     drivers/soc/ixp4xx/ixp4xx-npe.c
+F:     drivers/soc/ixp4xx/ixp4xx-qmgr.c
+F:     include/linux/soc/ixp4xx/npe.h
+F:     include/linux/soc/ixp4xx/qmgr.h
 
 INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT
 M:     Deepak Saxena <dsaxena@plexity.net>
@@ -8649,11 +8673,11 @@ INTEL MANAGEMENT ENGINE (mei)
 M:     Tomas Winkler <tomas.winkler@intel.com>
 L:     linux-kernel@vger.kernel.org
 S:     Supported
-F:     include/uapi/linux/mei.h
-F:     include/linux/mei_cl_bus.h
+F:     Documentation/driver-api/mei/*
 F:     drivers/misc/mei/*
 F:     drivers/watchdog/mei_wdt.c
-F:     Documentation/driver-api/mei/*
+F:     include/linux/mei_cl_bus.h
+F:     include/uapi/linux/mei.h
 F:     samples/mei/*
 
 INTEL MENLOW THERMAL DRIVER
@@ -8745,12 +8769,12 @@ INTEL STRATIX10 FIRMWARE DRIVERS
 M:     Richard Gong <richard.gong@linux.intel.com>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
+F:     Documentation/ABI/testing/sysfs-devices-platform-stratix10-rsu
+F:     Documentation/devicetree/bindings/firmware/intel,stratix10-svc.txt
 F:     drivers/firmware/stratix10-rsu.c
 F:     drivers/firmware/stratix10-svc.c
 F:     include/linux/firmware/intel/stratix10-smc.h
 F:     include/linux/firmware/intel/stratix10-svc-client.h
-F:     Documentation/ABI/testing/sysfs-devices-platform-stratix10-rsu
-F:     Documentation/devicetree/bindings/firmware/intel,stratix10-svc.txt
 
 INTEL TELEMETRY DRIVER
 M:     Rajneesh Bhardwaj <rajneesh.bhardwaj@linux.intel.com>
@@ -8784,9 +8808,9 @@ M:        Emmanuel Grumbach <emmanuel.grumbach@intel.com>
 M:     Luca Coelho <luciano.coelho@intel.com>
 M:     Intel Linux Wireless <linuxwifi@intel.com>
 L:     linux-wireless@vger.kernel.org
+S:     Supported
 W:     https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
-S:     Supported
 F:     drivers/net/wireless/intel/iwlwifi/
 
 INTEL WIRELESS WIMAX CONNECTION 2400
@@ -8814,19 +8838,19 @@ F:      include/linux/intel_th.h
 INTEL(R) TRUSTED EXECUTION TECHNOLOGY (TXT)
 M:     Ning Sun <ning.sun@intel.com>
 L:     tboot-devel@lists.sourceforge.net
+S:     Supported
 W:     http://tboot.sourceforge.net
 T:     hg http://tboot.hg.sourceforge.net:8000/hgroot/tboot/tboot
-S:     Supported
 F:     Documentation/x86/intel_txt.rst
-F:     include/linux/tboot.h
 F:     arch/x86/kernel/tboot.c
+F:     include/linux/tboot.h
 
 INTERCONNECT API
 M:     Georgi Djakov <georgi.djakov@linaro.org>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
-F:     Documentation/driver-api/interconnect.rst
 F:     Documentation/devicetree/bindings/interconnect/
+F:     Documentation/driver-api/interconnect.rst
 F:     drivers/interconnect/
 F:     include/dt-bindings/interconnect/
 F:     include/linux/interconnect-provider.h
@@ -8836,8 +8860,8 @@ INVENSENSE MPU-3050 GYROSCOPE DRIVER
 M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-iio@vger.kernel.org
 S:     Maintained
-F:     drivers/iio/gyro/mpu3050*
 F:     Documentation/devicetree/bindings/iio/gyroscope/invensense,mpu3050.txt
+F:     drivers/iio/gyro/mpu3050*
 
 IOC3 ETHERNET DRIVER
 M:     Ralf Baechle <ralf@linux-mips.org>
@@ -8852,40 +8876,40 @@ M:      linux-xfs@vger.kernel.org
 M:     linux-fsdevel@vger.kernel.org
 L:     linux-xfs@vger.kernel.org
 L:     linux-fsdevel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git
 F:     fs/iomap/
 F:     include/linux/iomap.h
 
 IOMMU DRIVERS
 M:     Joerg Roedel <joro@8bytes.org>
 L:     iommu@lists.linux-foundation.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
 F:     Documentation/devicetree/bindings/iommu/
 F:     drivers/iommu/
 F:     include/linux/iommu.h
-F:     include/linux/of_iommu.h
 F:     include/linux/iova.h
+F:     include/linux/of_iommu.h
 
 IO_URING
 M:     Jens Axboe <axboe@kernel.dk>
 L:     io-uring@vger.kernel.org
+S:     Maintained
 T:     git git://git.kernel.dk/linux-block
 T:     git git://git.kernel.dk/liburing
-S:     Maintained
-F:     fs/io_uring.c
 F:     fs/io-wq.c
 F:     fs/io-wq.h
+F:     fs/io_uring.c
 F:     include/uapi/linux/io_uring.h
 
 IPMI SUBSYSTEM
 M:     Corey Minyard <minyard@acm.org>
 L:     openipmi-developer@lists.sourceforge.net (moderated for non-subscribers)
-W:     http://openipmi.sourceforge.net/
 S:     Supported
-F:     Documentation/devicetree/bindings/ipmi/
+W:     http://openipmi.sourceforge.net/
 F:     Documentation/IPMI.txt
+F:     Documentation/devicetree/bindings/ipmi/
 F:     drivers/char/ipmi/
 F:     include/linux/ipmi*
 F:     include/uapi/linux/ipmi*
@@ -8893,8 +8917,8 @@ F:        include/uapi/linux/ipmi*
 IPS SCSI RAID DRIVER
 M:     Adaptec OEM Raid Solutions <aacraid@microsemi.com>
 L:     linux-scsi@vger.kernel.org
-W:     http://www.adaptec.com/
 S:     Maintained
+W:     http://www.adaptec.com/
 F:     drivers/scsi/ips*
 
 IPVS
@@ -8958,9 +8982,9 @@ F:        include/linux/isa.h
 ISA RADIO MODULE
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/radio-isa*
 
 ISAPNP
@@ -8975,8 +8999,8 @@ M:        Lee Duncan <lduncan@suse.com>
 M:     Chris Leech <cleech@redhat.com>
 L:     open-iscsi@googlegroups.com
 L:     linux-scsi@vger.kernel.org
-W:     www.open-iscsi.com
 S:     Maintained
+W:     www.open-iscsi.com
 F:     drivers/scsi/*iscsi*
 F:     include/scsi/*iscsi*
 
@@ -8998,35 +9022,35 @@ F:      drivers/infiniband/ulp/iser/
 
 ISCSI EXTENSIONS FOR RDMA (ISER) TARGET
 M:     Sagi Grimberg <sagi@grimberg.me>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master
 L:     linux-rdma@vger.kernel.org
 L:     target-devel@vger.kernel.org
 S:     Supported
 W:     http://www.linux-iscsi.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master
 F:     drivers/infiniband/ulp/isert
 
-ISDN/mISDN SUBSYSTEM
-M:     Karsten Keil <isdn@linux-pingi.de>
-L:     isdn4linux@listserv.isdn4linux.de (subscribers-only)
-L:     netdev@vger.kernel.org
-W:     http://www.isdn4linux.de
-S:     Maintained
-F:     drivers/isdn/mISDN/
-F:     drivers/isdn/hardware/
-F:     drivers/isdn/Kconfig
-F:     drivers/isdn/Makefile
-
 ISDN/CMTP OVER BLUETOOTH
 M:     Karsten Keil <isdn@linux-pingi.de>
 L:     isdn4linux@listserv.isdn4linux.de (subscribers-only)
 L:     netdev@vger.kernel.org
-W:     http://www.isdn4linux.de
 S:     Odd Fixes
+W:     http://www.isdn4linux.de
 F:     Documentation/isdn/
 F:     drivers/isdn/capi/
-F:     net/bluetooth/cmtp/
 F:     include/linux/isdn/
 F:     include/uapi/linux/isdn/
+F:     net/bluetooth/cmtp/
+
+ISDN/mISDN SUBSYSTEM
+M:     Karsten Keil <isdn@linux-pingi.de>
+L:     isdn4linux@listserv.isdn4linux.de (subscribers-only)
+L:     netdev@vger.kernel.org
+S:     Maintained
+W:     http://www.isdn4linux.de
+F:     drivers/isdn/Kconfig
+F:     drivers/isdn/Makefile
+F:     drivers/isdn/hardware/
+F:     drivers/isdn/mISDN/
 
 IT87 HARDWARE MONITORING DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
@@ -9038,19 +9062,19 @@ F:      drivers/hwmon/it87.c
 IT913X MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/tuners/it913x*
 
 IVTV VIDEO4LINUX DRIVER
 M:     Andy Walls <awalls@md.metrocast.net>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/media/v4l-drivers/ivtv*
 F:     drivers/media/pci/ivtv/
 F:     include/uapi/linux/ivtv*
@@ -9058,31 +9082,31 @@ F:      include/uapi/linux/ivtv*
 IX2505V MEDIA DRIVER
 M:     Malcolm Priestley <tvboxspy@gmail.com>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-S:     Maintained
 F:     drivers/media/dvb-frontends/ix2505v*
 
 JAILHOUSE HYPERVISOR INTERFACE
 M:     Jan Kiszka <jan.kiszka@siemens.com>
 L:     jailhouse-dev@googlegroups.com
 S:     Maintained
-F:     arch/x86/kernel/jailhouse.c
 F:     arch/x86/include/asm/jailhouse_para.h
+F:     arch/x86/kernel/jailhouse.c
 
 JC42.4 TEMPERATURE SENSOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
 L:     linux-hwmon@vger.kernel.org
 S:     Maintained
-F:     drivers/hwmon/jc42.c
 F:     Documentation/hwmon/jc42.rst
+F:     drivers/hwmon/jc42.c
 
 JFS FILESYSTEM
 M:     Dave Kleikamp <shaggy@kernel.org>
 L:     jfs-discussion@lists.sourceforge.net
+S:     Maintained
 W:     http://jfs.sourceforge.net/
 T:     git git://github.com/kleikamp/linux-shaggy.git
-S:     Maintained
 F:     Documentation/admin-guide/jfs.rst
 F:     fs/jfs/
 
@@ -9096,9 +9120,9 @@ JOURNALLING FLASH FILE SYSTEM V2 (JFFS2)
 M:     David Woodhouse <dwmw2@infradead.org>
 M:     Richard Weinberger <richard@nod.at>
 L:     linux-mtd@lists.infradead.org
+S:     Odd Fixes
 W:     http://www.linux-mtd.infradead.org/doc/jffs2.html
 T:     git git://git.infradead.org/ubifs-2.6.git
-S:     Odd Fixes
 F:     fs/jffs2/
 F:     include/uapi/linux/jffs2.h
 
@@ -9141,9 +9165,9 @@ R:        Alexander Potapenko <glider@google.com>
 R:     Dmitry Vyukov <dvyukov@google.com>
 L:     kasan-dev@googlegroups.com
 S:     Maintained
+F:     Documentation/dev-tools/kasan.rst
 F:     arch/*/include/asm/kasan.h
 F:     arch/*/mm/kasan_init*
-F:     Documentation/dev-tools/kasan.rst
 F:     include/linux/kasan*.h
 F:     lib/test_kasan.c
 F:     mm/kasan/
@@ -9151,28 +9175,28 @@ F:      scripts/Makefile.kasan
 
 KCONFIG
 M:     Masahiro Yamada <masahiroy@kernel.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git kconfig
 L:     linux-kbuild@vger.kernel.org
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git kconfig
 F:     Documentation/kbuild/kconfig*
-F:     scripts/kconfig/
 F:     scripts/Kconfig.include
+F:     scripts/kconfig/
 
 KDUMP
 M:     Dave Young <dyoung@redhat.com>
 M:     Baoquan He <bhe@redhat.com>
 R:     Vivek Goyal <vgoyal@redhat.com>
 L:     kexec@lists.infradead.org
-W:     http://lse.sourceforge.net/kdump/
 S:     Maintained
+W:     http://lse.sourceforge.net/kdump/
 F:     Documentation/admin-guide/kdump/
 
 KEENE FM RADIO TRANSMITTER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/radio-keene*
 
 KERNEL AUTOMOUNTER
@@ -9184,56 +9208,56 @@ F:      fs/autofs/
 KERNEL BUILD + files below scripts/ (unless maintained elsewhere)
 M:     Masahiro Yamada <masahiroy@kernel.org>
 M:     Michal Marek <michal.lkml@markovi.net>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git
 L:     linux-kbuild@vger.kernel.org
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git
 F:     Documentation/kbuild/
 F:     Makefile
+F:     scripts/*vmlinux*
 F:     scripts/Kbuild*
 F:     scripts/Makefile*
 F:     scripts/basic/
 F:     scripts/mk*
-F:     scripts/*vmlinux*
 F:     scripts/mod/
 F:     scripts/package/
 
 KERNEL JANITORS
 L:     kernel-janitors@vger.kernel.org
-W:     http://kernelnewbies.org/KernelJanitors
 S:     Odd Fixes
+W:     http://kernelnewbies.org/KernelJanitors
 
 KERNEL NFSD, SUNRPC, AND LOCKD SERVERS
 M:     "J. Bruce Fields" <bfields@fieldses.org>
 M:     Chuck Lever <chuck.lever@oracle.com>
 L:     linux-nfs@vger.kernel.org
+S:     Supported
 W:     http://nfs.sourceforge.net/
 T:     git git://linux-nfs.org/~bfields/linux.git
-S:     Supported
-F:     fs/nfsd/
-F:     include/uapi/linux/nfsd/
 F:     fs/lockd/
 F:     fs/nfs_common/
-F:     net/sunrpc/
+F:     fs/nfsd/
 F:     include/linux/lockd/
 F:     include/linux/sunrpc/
+F:     include/uapi/linux/nfsd/
 F:     include/uapi/linux/sunrpc/
+F:     net/sunrpc/
 
 KERNEL SELFTEST FRAMEWORK
 M:     Shuah Khan <shuah@kernel.org>
 M:     Shuah Khan <skhan@linuxfoundation.org>
 L:     linux-kselftest@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git
-Q:     https://patchwork.kernel.org/project/linux-kselftest/list/
 S:     Maintained
-F:     tools/testing/selftests/
+Q:     https://patchwork.kernel.org/project/linux-kselftest/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git
 F:     Documentation/dev-tools/kselftest*
+F:     tools/testing/selftests/
 
 KERNEL UNIT TESTING FRAMEWORK (KUnit)
 M:     Brendan Higgins <brendanhiggins@google.com>
 L:     linux-kselftest@vger.kernel.org
 L:     kunit-dev@googlegroups.com
-W:     https://google.github.io/kunit-docs/third_party/kernel/docs/
 S:     Maintained
+W:     https://google.github.io/kunit-docs/third_party/kernel/docs/
 F:     Documentation/dev-tools/kunit/
 F:     include/kunit/
 F:     lib/kunit/
@@ -9243,25 +9267,25 @@ KERNEL USERMODE HELPER
 M:     Luis Chamberlain <mcgrof@kernel.org>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
-F:     kernel/umh.c
 F:     include/linux/umh.h
+F:     kernel/umh.c
 
 KERNEL VIRTUAL MACHINE (KVM)
 M:     Paolo Bonzini <pbonzini@redhat.com>
 L:     kvm@vger.kernel.org
+S:     Supported
 W:     http://www.linux-kvm.org
 T:     git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
-S:     Supported
 F:     Documentation/virt/kvm/
+F:     include/asm-generic/kvm*
+F:     include/kvm/iodev.h
+F:     include/linux/kvm*
 F:     include/trace/events/kvm.h
 F:     include/uapi/asm-generic/kvm*
 F:     include/uapi/linux/kvm*
-F:     include/asm-generic/kvm*
-F:     include/linux/kvm*
-F:     include/kvm/iodev.h
-F:     virt/kvm/*
 F:     tools/kvm/
 F:     tools/testing/selftests/kvm/
+F:     virt/kvm/*
 
 KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
 M:     Marc Zyngier <maz@kernel.org>
@@ -9270,32 +9294,32 @@ R:      Julien Thierry <julien.thierry.kdev@gmail.com>
 R:     Suzuki K Poulose <suzuki.poulose@arm.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     kvmarm@lists.cs.columbia.edu
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git
 S:     Maintained
-F:     arch/arm64/include/uapi/asm/kvm*
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git
 F:     arch/arm64/include/asm/kvm*
+F:     arch/arm64/include/uapi/asm/kvm*
 F:     arch/arm64/kvm/
-F:     virt/kvm/arm/
 F:     include/kvm/arm_*
+F:     virt/kvm/arm/
 
 KERNEL VIRTUAL MACHINE FOR MIPS (KVM/mips)
 L:     linux-mips@vger.kernel.org
 L:     kvm@vger.kernel.org
 S:     Orphan
-F:     arch/mips/include/uapi/asm/kvm*
 F:     arch/mips/include/asm/kvm*
+F:     arch/mips/include/uapi/asm/kvm*
 F:     arch/mips/kvm/
 
 KERNEL VIRTUAL MACHINE FOR POWERPC (KVM/powerpc)
 M:     Paul Mackerras <paulus@ozlabs.org>
 L:     kvm-ppc@vger.kernel.org
+S:     Supported
 W:     http://www.linux-kvm.org/
 T:     git git://github.com/agraf/linux-2.6.git
-S:     Supported
-F:     arch/powerpc/include/uapi/asm/kvm*
 F:     arch/powerpc/include/asm/kvm*
-F:     arch/powerpc/kvm/
+F:     arch/powerpc/include/uapi/asm/kvm*
 F:     arch/powerpc/kernel/kvm*
+F:     arch/powerpc/kvm/
 
 KERNEL VIRTUAL MACHINE for s390 (KVM/s390)
 M:     Christian Borntraeger <borntraeger@de.ibm.com>
@@ -9303,17 +9327,17 @@ M:      Janosch Frank <frankja@linux.ibm.com>
 R:     David Hildenbrand <david@redhat.com>
 R:     Cornelia Huck <cohuck@redhat.com>
 L:     kvm@vger.kernel.org
+S:     Supported
 W:     http://www.ibm.com/developerworks/linux/linux390/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git
-S:     Supported
 F:     Documentation/virt/kvm/s390*
-F:     arch/s390/include/uapi/asm/kvm*
 F:     arch/s390/include/asm/gmap.h
 F:     arch/s390/include/asm/kvm*
+F:     arch/s390/include/uapi/asm/kvm*
 F:     arch/s390/kvm/
 F:     arch/s390/mm/gmap.c
-F:     tools/testing/selftests/kvm/s390x/
 F:     tools/testing/selftests/kvm/*/s390x/
+F:     tools/testing/selftests/kvm/s390x/
 
 KERNEL VIRTUAL MACHINE FOR X86 (KVM/x86)
 M:     Paolo Bonzini <pbonzini@redhat.com>
@@ -9323,34 +9347,34 @@ R:      Wanpeng Li <wanpengli@tencent.com>
 R:     Jim Mattson <jmattson@google.com>
 R:     Joerg Roedel <joro@8bytes.org>
 L:     kvm@vger.kernel.org
+S:     Supported
 W:     http://www.linux-kvm.org
 T:     git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
-S:     Supported
-F:     arch/x86/kvm/
-F:     arch/x86/kvm/*/
-F:     arch/x86/include/uapi/asm/kvm*
-F:     arch/x86/include/uapi/asm/vmx.h
-F:     arch/x86/include/uapi/asm/svm.h
 F:     arch/x86/include/asm/kvm*
 F:     arch/x86/include/asm/pvclock-abi.h
 F:     arch/x86/include/asm/svm.h
 F:     arch/x86/include/asm/vmx*.h
+F:     arch/x86/include/uapi/asm/kvm*
+F:     arch/x86/include/uapi/asm/svm.h
+F:     arch/x86/include/uapi/asm/vmx.h
 F:     arch/x86/kernel/kvm.c
 F:     arch/x86/kernel/kvmclock.c
+F:     arch/x86/kvm/
+F:     arch/x86/kvm/*/
 
 KERNFS
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 M:     Tejun Heo <tj@kernel.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
 S:     Supported
-F:     include/linux/kernfs.h
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
 F:     fs/kernfs/
+F:     include/linux/kernfs.h
 
 KEXEC
 M:     Eric Biederman <ebiederm@xmission.com>
-W:     http://kernel.org/pub/linux/utils/kernel/kexec/
 L:     kexec@lists.infradead.org
 S:     Maintained
+W:     http://kernel.org/pub/linux/utils/kernel/kexec/
 F:     include/linux/kexec.h
 F:     include/uapi/linux/kexec.h
 F:     kernel/kexec*
@@ -9382,21 +9406,21 @@ M:      Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
 L:     keyrings@vger.kernel.org
 S:     Maintained
 F:     Documentation/security/keys/core.rst
-F:     include/linux/key.h
+F:     include/keys/
 F:     include/linux/key-type.h
+F:     include/linux/key.h
 F:     include/linux/keyctl.h
 F:     include/uapi/linux/keyctl.h
-F:     include/keys/
 F:     security/keys/
 
 KGDB / KDB /debug_core
 M:     Jason Wessel <jason.wessel@windriver.com>
 M:     Daniel Thompson <daniel.thompson@linaro.org>
 R:     Douglas Anderson <dianders@chromium.org>
-W:     http://kgdb.wiki.kernel.org/
 L:     kgdb-bugreport@lists.sourceforge.net
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb.git
 S:     Maintained
+W:     http://kgdb.wiki.kernel.org/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb.git
 F:     Documentation/dev-tools/kgdb.rst
 F:     drivers/misc/kgdbts.c
 F:     drivers/tty/serial/kgdboc.c
@@ -9409,15 +9433,15 @@ M:      Catalin Marinas <catalin.marinas@arm.com>
 S:     Maintained
 F:     Documentation/dev-tools/kmemleak.rst
 F:     include/linux/kmemleak.h
-F:     mm/kmemleak.c
 F:     mm/kmemleak-test.c
+F:     mm/kmemleak.c
 
 KMOD KERNEL MODULE LOADER - USERMODE HELPER
 M:     Luis Chamberlain <mcgrof@kernel.org>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
-F:     kernel/kmod.c
 F:     include/linux/kmod.h
+F:     kernel/kmod.c
 F:     lib/test_kmod.c
 F:     tools/testing/selftests/kmod/
 
@@ -9428,8 +9452,8 @@ M:        "David S. Miller" <davem@davemloft.net>
 M:     Masami Hiramatsu <mhiramat@kernel.org>
 S:     Maintained
 F:     Documentation/kprobes.txt
-F:     include/linux/kprobes.h
 F:     include/asm-generic/kprobes.h
+F:     include/linux/kprobes.h
 F:     kernel/kprobes.c
 
 KS0108 LCD CONTROLLER DRIVER
@@ -9443,8 +9467,8 @@ L3MDEV
 M:     David Ahern <dsahern@kernel.org>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     net/l3mdev
 F:     include/net/l3mdev.h
+F:     net/l3mdev
 
 L7 BPF FRAMEWORK
 M:     John Fastabend <john.fastabend@gmail.com>
@@ -9464,10 +9488,10 @@ LANTIQ / INTEL Ethernet drivers
 M:     Hauke Mehrtens <hauke@hauke-m.de>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     net/dsa/tag_gswip.c
-F:     drivers/net/ethernet/lantiq_xrx200.c
-F:     drivers/net/dsa/lantiq_pce.h
 F:     drivers/net/dsa/lantiq_gswip.c
+F:     drivers/net/dsa/lantiq_pce.h
+F:     drivers/net/ethernet/lantiq_xrx200.c
+F:     net/dsa/tag_gswip.c
 
 LANTIQ MIPS ARCHITECTURE
 M:     John Crispin <john@phrozen.org>
@@ -9503,9 +9527,9 @@ M:        Jacek Anaszewski <jacek.anaszewski@gmail.com>
 M:     Pavel Machek <pavel@ucw.cz>
 R:     Dan Murphy <dmurphy@ti.com>
 L:     linux-leds@vger.kernel.org
+S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds.git
-S:     Maintained
 F:     Documentation/devicetree/bindings/leds/
 F:     drivers/leds/
 F:     include/linux/leds.h
@@ -9519,15 +9543,15 @@ F:      drivers/misc/eeprom/eeprom.c
 LEGO MINDSTORMS EV3
 R:     David Lechner <david@lechnology.com>
 S:     Maintained
-F:     arch/arm/boot/dts/da850-lego-ev3.dts
 F:     Documentation/devicetree/bindings/power/supply/lego_ev3_battery.txt
+F:     arch/arm/boot/dts/da850-lego-ev3.dts
 F:     drivers/power/supply/lego_ev3_battery.c
 
 LEGO USB Tower driver
 M:     Juergen Stuber <starblue@users.sourceforge.net>
 L:     legousb-devel@lists.sourceforge.net
-W:     http://legousb.sourceforge.net/
 S:     Maintained
+W:     http://legousb.sourceforge.net/
 F:     drivers/usb/misc/legousbtower.c
 
 LG LAPTOP EXTRAS
@@ -9541,45 +9565,45 @@ F:      drivers/platform/x86/lg-laptop.c
 LG2160 MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mkrufky/tuners.git
-S:     Maintained
 F:     drivers/media/dvb-frontends/lg2160.*
 
 LGDT3305 MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mkrufky/tuners.git
-S:     Maintained
 F:     drivers/media/dvb-frontends/lgdt3305.*
 
 LIBATA PATA ARASAN COMPACT FLASH CONTROLLER
 M:     Viresh Kumar <vireshk@kernel.org>
 L:     linux-ide@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 S:     Maintained
-F:     include/linux/pata_arasan_cf_data.h
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 F:     drivers/ata/pata_arasan_cf.c
+F:     include/linux/pata_arasan_cf_data.h
 
 LIBATA PATA DRIVERS
 M:     Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
 M:     Jens Axboe <axboe@kernel.dk>
 L:     linux-ide@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 S:     Maintained
-F:     drivers/ata/pata_*.c
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 F:     drivers/ata/ata_generic.c
+F:     drivers/ata/pata_*.c
 
 LIBATA PATA FARADAY FTIDE010 AND GEMINI SATA BRIDGE DRIVERS
 M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-ide@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 F:     drivers/ata/pata_ftide010.c
 F:     drivers/ata/sata_gemini.c
 F:     drivers/ata/sata_gemini.h
@@ -9588,8 +9612,8 @@ LIBATA SATA AHCI PLATFORM devices support
 M:     Hans de Goede <hdegoede@redhat.com>
 M:     Jens Axboe <axboe@kernel.dk>
 L:     linux-ide@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 F:     drivers/ata/ahci_platform.c
 F:     drivers/ata/libahci_platform.c
 F:     include/linux/ahci_platform.h
@@ -9597,19 +9621,19 @@ F:      include/linux/ahci_platform.h
 LIBATA SATA PROMISE TX2/TX4 CONTROLLER DRIVER
 M:     Mikael Pettersson <mikpelinux@gmail.com>
 L:     linux-ide@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 F:     drivers/ata/sata_promise.*
 
 LIBATA SUBSYSTEM (Serial and Parallel ATA drivers)
 M:     Jens Axboe <axboe@kernel.dk>
 L:     linux-ide@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
+F:     Documentation/devicetree/bindings/ata/
 F:     drivers/ata/
 F:     include/linux/ata.h
 F:     include/linux/libata.h
-F:     Documentation/devicetree/bindings/ata/
 
 LIBLOCKDEP
 M:     Sasha Levin <alexander.levin@microsoft.com>
@@ -9621,9 +9645,9 @@ M:        Dan Williams <dan.j.williams@intel.com>
 M:     Vishal Verma <vishal.l.verma@intel.com>
 M:     Dave Jiang <dave.jiang@intel.com>
 L:     linux-nvdimm@lists.01.org
-P:     Documentation/nvdimm/maintainer-entry-profile.rst
-Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
 S:     Supported
+Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
+P:     Documentation/nvdimm/maintainer-entry-profile.rst
 F:     drivers/nvdimm/blk.c
 F:     drivers/nvdimm/region_devs.c
 
@@ -9632,9 +9656,9 @@ M:        Vishal Verma <vishal.l.verma@intel.com>
 M:     Dan Williams <dan.j.williams@intel.com>
 M:     Dave Jiang <dave.jiang@intel.com>
 L:     linux-nvdimm@lists.01.org
-P:     Documentation/nvdimm/maintainer-entry-profile.rst
-Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
 S:     Supported
+Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
+P:     Documentation/nvdimm/maintainer-entry-profile.rst
 F:     drivers/nvdimm/btt*
 
 LIBNVDIMM PMEM: PERSISTENT MEMORY DRIVER
@@ -9642,18 +9666,18 @@ M:      Dan Williams <dan.j.williams@intel.com>
 M:     Vishal Verma <vishal.l.verma@intel.com>
 M:     Dave Jiang <dave.jiang@intel.com>
 L:     linux-nvdimm@lists.01.org
-P:     Documentation/nvdimm/maintainer-entry-profile.rst
-Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
 S:     Supported
+Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
+P:     Documentation/nvdimm/maintainer-entry-profile.rst
 F:     drivers/nvdimm/pmem*
 
 LIBNVDIMM: DEVICETREE BINDINGS
 M:     Oliver O'Halloran <oohall@gmail.com>
 L:     linux-nvdimm@lists.01.org
-Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
 S:     Supported
-F:     drivers/nvdimm/of_pmem.c
+Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
 F:     Documentation/devicetree/bindings/pmem/pmem-region.txt
+F:     drivers/nvdimm/of_pmem.c
 
 LIBNVDIMM: NON-VOLATILE MEMORY DEVICE SUBSYSTEM
 M:     Dan Williams <dan.j.williams@intel.com>
@@ -9661,15 +9685,16 @@ M:      Vishal Verma <vishal.l.verma@intel.com>
 M:     Dave Jiang <dave.jiang@intel.com>
 M:     Ira Weiny <ira.weiny@intel.com>
 L:     linux-nvdimm@lists.01.org
-P:     Documentation/nvdimm/maintainer-entry-profile.rst
+S:     Supported
 Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
+P:     Documentation/nvdimm/maintainer-entry-profile.rst
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git
-S:     Supported
-F:     drivers/nvdimm/*
 F:     drivers/acpi/nfit/*
-F:     include/linux/nd.h
+F:     drivers/nvdimm/*
 F:     include/linux/libnvdimm.h
+F:     include/linux/nd.h
 F:     include/uapi/linux/ndctl.h
+F:     tools/testing/nvdimm/
 
 LICENSES and SPDX stuff
 M:     Thomas Gleixner <tglx@linutronix.de>
@@ -9685,9 +9710,9 @@ F:        scripts/spdxcheck.py
 
 LIGHTNVM PLATFORM SUPPORT
 M:     Matias Bjorling <mb@lightnvm.io>
-W:     http://github/OpenChannelSSD
 L:     linux-block@vger.kernel.org
 S:     Maintained
+W:     http://github/OpenChannelSSD
 F:     drivers/lightnvm/
 F:     include/linux/lightnvm.h
 F:     include/uapi/linux/lightnvm.h
@@ -9703,25 +9728,25 @@ LINUX FOR POWERPC (32-BIT AND 64-BIT)
 M:     Michael Ellerman <mpe@ellerman.id.au>
 R:     Benjamin Herrenschmidt <benh@kernel.crashing.org>
 R:     Paul Mackerras <paulus@samba.org>
-W:     https://github.com/linuxppc/wiki/wiki
 L:     linuxppc-dev@lists.ozlabs.org
+S:     Supported
+W:     https://github.com/linuxppc/wiki/wiki
 Q:     http://patchwork.ozlabs.org/project/linuxppc-dev/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git
-S:     Supported
 F:     Documentation/ABI/stable/sysfs-firmware-opal-*
+F:     Documentation/devicetree/bindings/i2c/i2c-opal.txt
 F:     Documentation/devicetree/bindings/powerpc/
 F:     Documentation/devicetree/bindings/rtc/rtc-opal.txt
-F:     Documentation/devicetree/bindings/i2c/i2c-opal.txt
 F:     Documentation/powerpc/
 F:     arch/powerpc/
+F:     drivers/*/*/*pasemi*
+F:     drivers/*/*pasemi*
 F:     drivers/char/tpm/tpm_ibmvtpm*
 F:     drivers/crypto/nx/
 F:     drivers/crypto/vmx/
 F:     drivers/i2c/busses/i2c-opal.c
 F:     drivers/net/ethernet/ibm/ibmveth.*
 F:     drivers/net/ethernet/ibm/ibmvnic.*
-F:     drivers/*/*/*pasemi*
-F:     drivers/*/*pasemi*
 F:     drivers/pci/hotplug/pnv_php.c
 F:     drivers/pci/hotplug/rpa*
 F:     drivers/rtc/rtc-opal.c
@@ -9751,11 +9776,11 @@ F:      arch/powerpc/platforms/44x/
 LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX
 M:     Scott Wood <oss@buserror.net>
 L:     linuxppc-dev@lists.ozlabs.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/scottwood/linux.git
 S:     Odd fixes
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/scottwood/linux.git
+F:     Documentation/devicetree/bindings/powerpc/fsl/
 F:     arch/powerpc/platforms/83xx/
 F:     arch/powerpc/platforms/85xx/
-F:     Documentation/devicetree/bindings/powerpc/fsl/
 
 LINUX FOR POWERPC EMBEDDED PPC8XX
 M:     Christophe Leroy <christophe.leroy@c-s.fr>
@@ -9786,12 +9811,12 @@ L:      linux-kernel@vger.kernel.org
 L:     linux-arch@vger.kernel.org
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev
-F:     tools/memory-model/
 F:     Documentation/atomic_bitops.txt
 F:     Documentation/atomic_t.txt
 F:     Documentation/core-api/atomic_ops.rst
 F:     Documentation/core-api/refcount-vs-atomic.rst
 F:     Documentation/memory-barriers.txt
+F:     tools/memory-model/
 
 LIS3LV02D ACCELEROMETER DRIVER
 M:     Eric Piel <eric.piel@tremplin-utc.net>
@@ -9813,24 +9838,24 @@ M:      Jiri Kosina <jikos@kernel.org>
 M:     Miroslav Benes <mbenes@suse.cz>
 M:     Petr Mladek <pmladek@suse.com>
 R:     Joe Lawrence <joe.lawrence@redhat.com>
+L:     live-patching@vger.kernel.org
 S:     Maintained
-F:     kernel/livepatch/
-F:     include/linux/livepatch.h
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching.git
+F:     Documentation/ABI/testing/sysfs-kernel-livepatch
+F:     Documentation/livepatch/
 F:     arch/x86/include/asm/livepatch.h
 F:     arch/x86/kernel/livepatch.c
-F:     Documentation/livepatch/
-F:     Documentation/ABI/testing/sysfs-kernel-livepatch
+F:     include/linux/livepatch.h
+F:     kernel/livepatch/
 F:     samples/livepatch/
 F:     tools/testing/selftests/livepatch/
-L:     live-patching@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching.git
 
 LLC (802.2)
 L:     netdev@vger.kernel.org
 S:     Odd fixes
 F:     include/linux/llc.h
-F:     include/uapi/linux/llc.h
 F:     include/net/llc*
+F:     include/uapi/linux/llc.h
 F:     net/llc/
 
 LM73 HARDWARE MONITOR DRIVER
@@ -9857,8 +9882,8 @@ LM90 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
 L:     linux-hwmon@vger.kernel.org
 S:     Maintained
-F:     Documentation/hwmon/lm90.rst
 F:     Documentation/devicetree/bindings/hwmon/lm90.txt
+F:     Documentation/hwmon/lm90.rst
 F:     drivers/hwmon/lm90.c
 F:     include/dt-bindings/thermal/lm90.h
 
@@ -9872,50 +9897,50 @@ F:      drivers/hwmon/lm95234.c
 LME2510 MEDIA DRIVER
 M:     Malcolm Priestley <tvboxspy@gmail.com>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/lmedm04*
 
 LOADPIN SECURITY MODULE
 M:     Kees Cook <keescook@chromium.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git lsm/loadpin
 S:     Supported
-F:     security/loadpin/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git lsm/loadpin
 F:     Documentation/admin-guide/LSM/LoadPin.rst
+F:     security/loadpin/
 
 LOCKING PRIMITIVES
 M:     Peter Zijlstra <peterz@infradead.org>
 M:     Ingo Molnar <mingo@redhat.com>
 M:     Will Deacon <will@kernel.org>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core
 F:     Documentation/locking/
-F:     include/linux/lockdep.h
-F:     include/linux/spinlock*.h
 F:     arch/*/include/asm/spinlock*.h
-F:     include/linux/rwlock*.h
+F:     include/linux/lockdep.h
 F:     include/linux/mutex*.h
+F:     include/linux/rwlock*.h
 F:     include/linux/rwsem*.h
 F:     include/linux/seqlock.h
-F:     lib/locking*.[ch]
+F:     include/linux/spinlock*.h
 F:     kernel/locking/
+F:     lib/locking*.[ch]
 X:     kernel/locking/locktorture.c
 
 LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP/Vista Dynamic Disks)
 M:     "Richard Russon (FlatCap)" <ldm@flatcap.org>
 L:     linux-ntfs-dev@lists.sourceforge.net
-W:     http://www.linux-ntfs.org/content/view/19/37/
 S:     Maintained
+W:     http://www.linux-ntfs.org/content/view/19/37/
 F:     Documentation/admin-guide/ldm.rst
 F:     block/partitions/ldm.*
 
 LOGITECH HID GAMING KEYBOARDS
 M:     Hans de Goede <hdegoede@redhat.com>
 L:     linux-input@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
 F:     drivers/hid/hid-lg-g15.c
 
 LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
@@ -9924,8 +9949,8 @@ M:        Chaitra P B <chaitra.basappa@broadcom.com>
 M:     Suganath Prabu Subramani <suganath-prabu.subramani@broadcom.com>
 L:     MPT-FusionLinux.pdl@broadcom.com
 L:     linux-scsi@vger.kernel.org
-W:     http://www.avagotech.com/support/
 S:     Supported
+W:     http://www.avagotech.com/support/
 F:     drivers/message/fusion/
 F:     drivers/scsi/mpt3sas/
 
@@ -9942,13 +9967,24 @@ S:      Maintained
 F:     Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml
 F:     drivers/iio/dac/ltc1660.c
 
-LTC2983 IIO TEMPERATURE DRIVER
+LTC2947 HARDWARE MONITOR DRIVER
 M:     Nuno Sá <nuno.sa@analog.com>
+L:     linux-hwmon@vger.kernel.org
+S:     Supported
 W:     http://ez.analog.com/community/linux-device-drivers
+F:     Documentation/devicetree/bindings/hwmon/adi,ltc2947.yaml
+F:     drivers/hwmon/ltc2947-core.c
+F:     drivers/hwmon/ltc2947-i2c.c
+F:     drivers/hwmon/ltc2947-spi.c
+F:     drivers/hwmon/ltc2947.h
+
+LTC2983 IIO TEMPERATURE DRIVER
+M:     Nuno Sá <nuno.sa@analog.com>
 L:     linux-iio@vger.kernel.org
 S:     Supported
-F:     drivers/iio/temperature/ltc2983.c
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml
+F:     drivers/iio/temperature/ltc2983.c
 
 LTC4261 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
@@ -9957,24 +9993,13 @@ S:      Maintained
 F:     Documentation/hwmon/ltc4261.rst
 F:     drivers/hwmon/ltc4261.c
 
-LTC2947 HARDWARE MONITOR DRIVER
-M:     Nuno Sá <nuno.sa@analog.com>
-W:     http://ez.analog.com/community/linux-device-drivers
-L:     linux-hwmon@vger.kernel.org
-S:     Supported
-F:     drivers/hwmon/ltc2947-core.c
-F:     drivers/hwmon/ltc2947-spi.c
-F:     drivers/hwmon/ltc2947-i2c.c
-F:     drivers/hwmon/ltc2947.h
-F:     Documentation/devicetree/bindings/hwmon/adi,ltc2947.yaml
-
 LTC4306 I2C MULTIPLEXER DRIVER
 M:     Michael Hennerich <michael.hennerich@analog.com>
-W:     http://ez.analog.com/community/linux-device-drivers
 L:     linux-i2c@vger.kernel.org
 S:     Supported
-F:     drivers/i2c/muxes/i2c-mux-ltc4306.c
+W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
+F:     drivers/i2c/muxes/i2c-mux-ltc4306.c
 
 LTP (Linux Test Project)
 M:     Mike Frysinger <vapier@gentoo.org>
@@ -9984,69 +10009,69 @@ M:     Jan Stancek <jstancek@redhat.com>
 M:     Stanislav Kholmanskikh <stanislav.kholmanskikh@oracle.com>
 M:     Alexey Kodanev <alexey.kodanev@oracle.com>
 L:     ltp@lists.linux.it (subscribers-only)
+S:     Maintained
 W:     http://linux-test-project.github.io/
 T:     git git://github.com/linux-test-project/ltp.git
-S:     Maintained
 
 M68K ARCHITECTURE
 M:     Geert Uytterhoeven <geert@linux-m68k.org>
 L:     linux-m68k@lists.linux-m68k.org
+S:     Maintained
 W:     http://www.linux-m68k.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git
-S:     Maintained
 F:     arch/m68k/
 F:     drivers/zorro/
 
 M68K ON APPLE MACINTOSH
 M:     Joshua Thompson <funaho@jurai.org>
-W:     http://www.mac.linux-m68k.org/
 L:     linux-m68k@lists.linux-m68k.org
 S:     Maintained
+W:     http://www.mac.linux-m68k.org/
 F:     arch/m68k/mac/
 
 M68K ON HP9000/300
 M:     Philip Blundell <philb@gnu.org>
-W:     http://www.tazenda.demon.co.uk/phil/linux-hp
 S:     Maintained
+W:     http://www.tazenda.demon.co.uk/phil/linux-hp
 F:     arch/m68k/hp300/
 
 M88DS3103 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/dvb-frontends/m88ds3103*
 
 M88RS2000 MEDIA DRIVER
 M:     Malcolm Priestley <tvboxspy@gmail.com>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-S:     Maintained
 F:     drivers/media/dvb-frontends/m88rs2000*
 
 MA901 MASTERKIT USB FM RADIO DRIVER
 M:     Alexey Klimov <klimov.linux@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/radio-ma901.c
 
 MAC80211
 M:     Johannes Berg <johannes@sipsolutions.net>
 L:     linux-wireless@vger.kernel.org
+S:     Maintained
 W:     http://wireless.kernel.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
-S:     Maintained
 F:     Documentation/networking/mac80211-injection.txt
+F:     Documentation/networking/mac80211_hwsim/mac80211_hwsim.rst
+F:     drivers/net/wireless/mac80211_hwsim.[ch]
 F:     include/net/mac80211.h
 F:     net/mac80211/
-F:     drivers/net/wireless/mac80211_hwsim.[ch]
-F:     Documentation/networking/mac80211_hwsim/mac80211_hwsim.rst
 
 MAILBOX API
 M:     Jassi Brar <jassisinghbrar@gmail.com>
@@ -10058,9 +10083,9 @@ F:      include/linux/mailbox_controller.h
 
 MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
 M:     Michael Kerrisk <mtk.manpages@gmail.com>
-W:     http://www.kernel.org/doc/man-pages
 L:     linux-man@vger.kernel.org
 S:     Maintained
+W:     http://www.kernel.org/doc/man-pages
 
 MARDUK (CREATOR CI40) DEVICE TREE SUPPORT
 M:     Rahul Bedarkar <rahulbedarkar89@gmail.com>
@@ -10073,35 +10098,35 @@ M:    Andrew Lunn <andrew@lunn.ch>
 M:     Vivien Didelot <vivien.didelot@gmail.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/dsa/mv88e6xxx/
-F:     include/linux/platform_data/mv88e6xxx.h
 F:     Documentation/devicetree/bindings/net/dsa/marvell.txt
 F:     Documentation/networking/devlink/mv88e6xxx.rst
+F:     drivers/net/dsa/mv88e6xxx/
+F:     include/linux/platform_data/mv88e6xxx.h
+
+MARVELL ARMADA 3700 PHY DRIVERS
+M:     Miquel Raynal <miquel.raynal@bootlin.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt
+F:     Documentation/devicetree/bindings/phy/phy-mvebu-utmi.txt
+F:     drivers/phy/marvell/phy-mvebu-a3700-comphy.c
+F:     drivers/phy/marvell/phy-mvebu-a3700-utmi.c
 
 MARVELL ARMADA DRM SUPPORT
 M:     Russell King <linux@armlinux.org.uk>
 S:     Maintained
 T:     git git://git.armlinux.org.uk/~rmk/linux-arm.git drm-armada-devel
 T:     git git://git.armlinux.org.uk/~rmk/linux-arm.git drm-armada-fixes
+F:     Documentation/devicetree/bindings/display/armada/
 F:     drivers/gpu/drm/armada/
 F:     include/uapi/drm/armada_drm.h
-F:     Documentation/devicetree/bindings/display/armada/
-
-MARVELL ARMADA 3700 PHY DRIVERS
-M:     Miquel Raynal <miquel.raynal@bootlin.com>
-S:     Maintained
-F:     drivers/phy/marvell/phy-mvebu-a3700-comphy.c
-F:     drivers/phy/marvell/phy-mvebu-a3700-utmi.c
-F:     Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt
-F:     Documentation/devicetree/bindings/phy/phy-mvebu-utmi.txt
 
 MARVELL CRYPTO DRIVER
 M:     Boris Brezillon <bbrezillon@kernel.org>
 M:     Arnaud Ebalard <arno@natisbad.org>
 M:     Srujana Challa <schalla@marvell.com>
-F:     drivers/crypto/marvell/
-S:     Maintained
 L:     linux-crypto@vger.kernel.org
+S:     Maintained
+F:     drivers/crypto/marvell/
 
 MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
 M:     Mirko Lindner <mlindner@marvell.com>
@@ -10163,8 +10188,27 @@ MARVELL NAND CONTROLLER DRIVER
 M:     Miquel Raynal <miquel.raynal@bootlin.com>
 L:     linux-mtd@lists.infradead.org
 S:     Maintained
-F:     drivers/mtd/nand/raw/marvell_nand.c
 F:     Documentation/devicetree/bindings/mtd/marvell-nand.txt
+F:     drivers/mtd/nand/raw/marvell_nand.c
+
+MARVELL OCTEONTX2 PHYSICAL FUNCTION DRIVER
+M:     Sunil Goutham <sgoutham@marvell.com>
+M:     Geetha sowjanya <gakula@marvell.com>
+M:     Subbaraya Sundeep <sbhatta@marvell.com>
+M:     hariprasad <hkelam@marvell.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     drivers/net/ethernet/marvell/octeontx2/nic/
+
+MARVELL OCTEONTX2 RVU ADMIN FUNCTION DRIVER
+M:     Sunil Goutham <sgoutham@marvell.com>
+M:     Linu Cherian <lcherian@marvell.com>
+M:     Geetha sowjanya <gakula@marvell.com>
+M:     Jerin Jacob <jerinj@marvell.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     Documentation/networking/device_drivers/marvell/octeontx2.rst
+F:     drivers/net/ethernet/marvell/octeontx2/af/
 
 MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
 M:     Nicolas Pitre <nico@fluxnic.net>
@@ -10175,34 +10219,15 @@ MARVELL USB MDIO CONTROLLER DRIVER
 M:     Tobias Waldekranz <tobias@waldekranz.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/phy/mdio-mvusb.c
 F:     Documentation/devicetree/bindings/net/marvell,mvusb.yaml
+F:     drivers/net/phy/mdio-mvusb.c
 
 MARVELL XENON MMC/SD/SDIO HOST CONTROLLER DRIVER
 M:     Hu Ziji <huziji@marvell.com>
 L:     linux-mmc@vger.kernel.org
 S:     Supported
-F:     drivers/mmc/host/sdhci-xenon*
 F:     Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
-
-MARVELL OCTEONTX2 RVU ADMIN FUNCTION DRIVER
-M:     Sunil Goutham <sgoutham@marvell.com>
-M:     Linu Cherian <lcherian@marvell.com>
-M:     Geetha sowjanya <gakula@marvell.com>
-M:     Jerin Jacob <jerinj@marvell.com>
-L:     netdev@vger.kernel.org
-S:     Supported
-F:     drivers/net/ethernet/marvell/octeontx2/af/
-F:     Documentation/networking/device_drivers/marvell/octeontx2.rst
-
-MARVELL OCTEONTX2 PHYSICAL FUNCTION DRIVER
-M:     Sunil Goutham <sgoutham@marvell.com>
-M:     Geetha sowjanya <gakula@marvell.com>
-M:     Subbaraya Sundeep <sbhatta@marvell.com>
-M:     hariprasad <hkelam@marvell.com>
-L:     netdev@vger.kernel.org
-S:     Supported
-F:     drivers/net/ethernet/marvell/octeontx2/nic/
+F:     drivers/mmc/host/sdhci-xenon*
 
 MATROX FRAMEBUFFER DRIVER
 L:     linux-fbdev@vger.kernel.org
@@ -10220,8 +10245,8 @@ F:      drivers/hwmon/max16065.c
 MAX2175 SDR TUNER DRIVER
 M:     Ramesh Shanmugasundaram <rashanmu@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/max2175.txt
 F:     Documentation/media/v4l-drivers/max2175.rst
 F:     drivers/media/i2c/max2175*
@@ -10237,8 +10262,8 @@ MAX6697 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
 L:     linux-hwmon@vger.kernel.org
 S:     Maintained
-F:     Documentation/hwmon/max6697.rst
 F:     Documentation/devicetree/bindings/hwmon/max6697.txt
+F:     Documentation/hwmon/max6697.rst
 F:     drivers/hwmon/max6697.c
 F:     include/linux/platform_data/max6697.h
 
@@ -10262,20 +10287,20 @@ L:    linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/*/*max77650.yaml
 F:     Documentation/devicetree/bindings/*/max77650*.yaml
-F:     include/linux/mfd/max77650.h
-F:     drivers/mfd/max77650.c
-F:     drivers/regulator/max77650-regulator.c
-F:     drivers/power/supply/max77650-charger.c
+F:     drivers/gpio/gpio-max77650.c
 F:     drivers/input/misc/max77650-onkey.c
 F:     drivers/leds/leds-max77650.c
-F:     drivers/gpio/gpio-max77650.c
+F:     drivers/mfd/max77650.c
+F:     drivers/power/supply/max77650-charger.c
+F:     drivers/regulator/max77650-regulator.c
+F:     include/linux/mfd/max77650.h
 
 MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER
 M:     Javier Martinez Canillas <javier@dowhile0.org>
 L:     linux-kernel@vger.kernel.org
 S:     Supported
-F:     drivers/regulator/max77802-regulator.c
 F:     Documentation/devicetree/bindings/*/*max77802.txt
+F:     drivers/regulator/max77802-regulator.c
 F:     include/dt-bindings/*/*max77802.h
 
 MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS
@@ -10292,17 +10317,17 @@ M:    Krzysztof Kozlowski <krzk@kernel.org>
 M:     Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
 L:     linux-kernel@vger.kernel.org
 S:     Supported
+F:     Documentation/devicetree/bindings/*/max77686.txt
+F:     Documentation/devicetree/bindings/clock/maxim,max77686.txt
+F:     Documentation/devicetree/bindings/mfd/max14577.txt
+F:     Documentation/devicetree/bindings/mfd/max77693.txt
 F:     drivers/*/max14577*.c
 F:     drivers/*/max77686*.c
 F:     drivers/*/max77693*.c
+F:     drivers/clk/clk-max77686.c
 F:     drivers/extcon/extcon-max14577.c
 F:     drivers/extcon/extcon-max77693.c
 F:     drivers/rtc/rtc-max77686.c
-F:     drivers/clk/clk-max77686.c
-F:     Documentation/devicetree/bindings/mfd/max14577.txt
-F:     Documentation/devicetree/bindings/*/max77686.txt
-F:     Documentation/devicetree/bindings/mfd/max77693.txt
-F:     Documentation/devicetree/bindings/clock/maxim,max77686.txt
 F:     include/linux/mfd/max14577*.h
 F:     include/linux/mfd/max77686*.h
 F:     include/linux/mfd/max77693*.h
@@ -10310,9 +10335,9 @@ F:      include/linux/mfd/max77693*.h
 MAXIRADIO FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/radio-maxiradio*
 
 MCAN MMIO DEVICE DRIVER
@@ -10343,11 +10368,11 @@ F:    drivers/iio/potentiometer/mcp4531.c
 MCR20A IEEE-802.15.4 RADIO DRIVER
 M:     Xue Liu <liuxuenetmail@gmail.com>
 L:     linux-wpan@vger.kernel.org
-W:     https://github.com/xueliu/mcr20a-linux
 S:     Maintained
+W:     https://github.com/xueliu/mcr20a-linux
+F:     Documentation/devicetree/bindings/net/ieee802154/mcr20a.txt
 F:     drivers/net/ieee802154/mcr20a.c
 F:     drivers/net/ieee802154/mcr20a.h
-F:     Documentation/devicetree/bindings/net/ieee802154/mcr20a.txt
 
 MEASUREMENT COMPUTING CIO-DAC IIO DRIVER
 M:     William Breathitt Gray <vilhelm.gray@gmail.com>
@@ -10359,81 +10384,81 @@ MEDIA CONTROLLER FRAMEWORK
 M:     Sakari Ailus <sakari.ailus@linux.intel.com>
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-media@vger.kernel.org
+S:     Supported
 W:     https://www.linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Supported
 F:     drivers/media/mc/
 F:     include/media/media-*.h
 F:     include/uapi/linux/media.h
 
+MEDIA DRIVER FOR FREESCALE IMX PXP
+M:     Philipp Zabel <p.zabel@pengutronix.de>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
+F:     drivers/media/platform/imx-pxp.[ch]
+
 MEDIA DRIVERS FOR ASCOT2E
 M:     Sergey Kozlov <serjk@netup.ru>
 M:     Abylay Ospan <aospan@netup.ru>
 L:     linux-media@vger.kernel.org
+S:     Supported
 W:     https://linuxtv.org
 W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
-S:     Supported
 F:     drivers/media/dvb-frontends/ascot2e*
 
 MEDIA DRIVERS FOR CXD2099AR CI CONTROLLERS
 M:     Jasmin Jessich <jasmin@anw.at>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
 F:     drivers/media/dvb-frontends/cxd2099*
 
 MEDIA DRIVERS FOR CXD2841ER
 M:     Sergey Kozlov <serjk@netup.ru>
 M:     Abylay Ospan <aospan@netup.ru>
 L:     linux-media@vger.kernel.org
+S:     Supported
 W:     https://linuxtv.org
 W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
-S:     Supported
 F:     drivers/media/dvb-frontends/cxd2841er*
 
 MEDIA DRIVERS FOR CXD2880
 M:     Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
 L:     linux-media@vger.kernel.org
+S:     Supported
 W:     http://linuxtv.org/
 T:     git git://linuxtv.org/media_tree.git
-S:     Supported
 F:     drivers/media/dvb-frontends/cxd2880/*
 F:     drivers/media/spi/cxd2880*
 
 MEDIA DRIVERS FOR DIGITAL DEVICES PCIE DEVICES
 L:     linux-media@vger.kernel.org
+S:     Orphan
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Orphan
 F:     drivers/media/pci/ddbridge/*
 
 MEDIA DRIVERS FOR FREESCALE IMX
 M:     Steve Longerbeam <slongerbeam@gmail.com>
 M:     Philipp Zabel <p.zabel@pengutronix.de>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/imx.txt
 F:     Documentation/media/v4l-drivers/imx.rst
 F:     drivers/staging/media/imx/
 F:     include/linux/imx-media.h
 F:     include/media/imx.h
 
-MEDIA DRIVER FOR FREESCALE IMX PXP
-M:     Philipp Zabel <p.zabel@pengutronix.de>
-L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
-F:     drivers/media/platform/imx-pxp.[ch]
-
 MEDIA DRIVERS FOR FREESCALE IMX7
 M:     Rui Miguel Silva <rmfrfs@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/imx7-csi.txt
 F:     Documentation/devicetree/bindings/media/imx7-mipi-csi2.txt
 F:     Documentation/media/v4l-drivers/imx7.rst
@@ -10443,55 +10468,64 @@ F:    drivers/staging/media/imx/imx7-mipi-csis.c
 MEDIA DRIVERS FOR HELENE
 M:     Abylay Ospan <aospan@netup.ru>
 L:     linux-media@vger.kernel.org
+S:     Supported
 W:     https://linuxtv.org
 W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
-S:     Supported
 F:     drivers/media/dvb-frontends/helene*
 
 MEDIA DRIVERS FOR HORUS3A
 M:     Sergey Kozlov <serjk@netup.ru>
 M:     Abylay Ospan <aospan@netup.ru>
 L:     linux-media@vger.kernel.org
+S:     Supported
 W:     https://linuxtv.org
 W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
-S:     Supported
 F:     drivers/media/dvb-frontends/horus3a*
 
 MEDIA DRIVERS FOR LNBH25
 M:     Sergey Kozlov <serjk@netup.ru>
 M:     Abylay Ospan <aospan@netup.ru>
 L:     linux-media@vger.kernel.org
+S:     Supported
 W:     https://linuxtv.org
 W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
-S:     Supported
 F:     drivers/media/dvb-frontends/lnbh25*
 
 MEDIA DRIVERS FOR MXL5XX TUNER DEMODULATORS
 L:     linux-media@vger.kernel.org
+S:     Orphan
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Orphan
 F:     drivers/media/dvb-frontends/mxl5xx*
 
 MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices
 M:     Sergey Kozlov <serjk@netup.ru>
 M:     Abylay Ospan <aospan@netup.ru>
 L:     linux-media@vger.kernel.org
+S:     Supported
 W:     https://linuxtv.org
 W:     http://netup.tv/
 T:     git git://linuxtv.org/media_tree.git
-S:     Supported
 F:     drivers/media/pci/netup_unidvb/*
 
+MEDIA DRIVERS FOR NVIDIA TEGRA - VDE
+M:     Dmitry Osipenko <digetx@gmail.com>
+L:     linux-media@vger.kernel.org
+L:     linux-tegra@vger.kernel.org
+S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
+F:     Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt
+F:     drivers/staging/media/tegra-vde/
+
 MEDIA DRIVERS FOR RENESAS - CEU
 M:     Jacopo Mondi <jacopo@jmondi.org>
 L:     linux-media@vger.kernel.org
 L:     linux-renesas-soc@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Supported
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/renesas,ceu.yaml
 F:     drivers/media/platform/renesas-ceu.c
 F:     include/media/drv-intf/renesas-ceu.h
@@ -10500,8 +10534,8 @@ MEDIA DRIVERS FOR RENESAS - DRIF
 M:     Ramesh Shanmugasundaram <rashanmu@gmail.com>
 L:     linux-media@vger.kernel.org
 L:     linux-renesas-soc@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Supported
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/renesas,drif.txt
 F:     drivers/media/platform/rcar_drif.c
 
@@ -10509,8 +10543,8 @@ MEDIA DRIVERS FOR RENESAS - FCP
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-media@vger.kernel.org
 L:     linux-renesas-soc@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Supported
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/renesas,fcp.txt
 F:     drivers/media/platform/rcar-fcp.c
 F:     include/media/rcar-fcp.h
@@ -10519,8 +10553,8 @@ MEDIA DRIVERS FOR RENESAS - FDP1
 M:     Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
 L:     linux-media@vger.kernel.org
 L:     linux-renesas-soc@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Supported
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/renesas,fdp1.txt
 F:     drivers/media/platform/rcar_fdp1.c
 
@@ -10528,8 +10562,8 @@ MEDIA DRIVERS FOR RENESAS - VIN
 M:     Niklas Söderlund <niklas.soderlund@ragnatech.se>
 L:     linux-media@vger.kernel.org
 L:     linux-renesas-soc@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Supported
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/renesas,csi2.yaml
 F:     Documentation/devicetree/bindings/media/renesas,vin.yaml
 F:     drivers/media/platform/rcar-vin/
@@ -10539,49 +10573,40 @@ M:    Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 M:     Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
 L:     linux-media@vger.kernel.org
 L:     linux-renesas-soc@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Supported
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/renesas,vsp1.txt
 F:     drivers/media/platform/vsp1/
 
 MEDIA DRIVERS FOR ST STV0910 DEMODULATOR ICs
 L:     linux-media@vger.kernel.org
+S:     Orphan
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Orphan
 F:     drivers/media/dvb-frontends/stv0910*
 
 MEDIA DRIVERS FOR ST STV6111 TUNER ICs
 L:     linux-media@vger.kernel.org
+S:     Orphan
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Orphan
 F:     drivers/media/dvb-frontends/stv6111*
 
 MEDIA DRIVERS FOR STM32 - DCMI
 M:     Hugues Fruchet <hugues.fruchet@st.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Supported
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
 F:     drivers/media/platform/stm32/stm32-dcmi.c
 
-MEDIA DRIVERS FOR NVIDIA TEGRA - VDE
-M:     Dmitry Osipenko <digetx@gmail.com>
-L:     linux-media@vger.kernel.org
-L:     linux-tegra@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
-F:     Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt
-F:     drivers/staging/media/tegra-vde/
-
 MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 Q:     http://patchwork.kernel.org/project/linux-media/list/
 T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
 F:     Documentation/devicetree/bindings/media/
 F:     Documentation/media/
 F:     drivers/media/
@@ -10589,12 +10614,12 @@ F:    drivers/staging/media/
 F:     include/linux/platform_data/media/
 F:     include/media/
 F:     include/uapi/linux/dvb/
-F:     include/uapi/linux/videodev2.h
+F:     include/uapi/linux/ivtv*
 F:     include/uapi/linux/media.h
-F:     include/uapi/linux/v4l2-*
 F:     include/uapi/linux/meye.h
-F:     include/uapi/linux/ivtv*
 F:     include/uapi/linux/uvcvideo.h
+F:     include/uapi/linux/v4l2-*
+F:     include/uapi/linux/videodev2.h
 
 MEDIATEK BLUETOOTH DRIVER
 M:     Sean Wang <sean.wang@mediatek.com>
@@ -10604,6 +10629,13 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/net/mediatek-bluetooth.txt
 F:     drivers/bluetooth/btmtkuart.c
 
+MEDIATEK BOARD LEVEL SHUTDOWN DRIVERS
+M:     Sean Wang <sean.wang@mediatek.com>
+L:     linux-pm@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/power/reset/mt6323-poweroff.txt
+F:     drivers/power/reset/mt6323-poweroff.c
+
 MEDIATEK CIR DRIVER
 M:     Sean Wang <sean.wang@mediatek.com>
 S:     Maintained
@@ -10618,12 +10650,6 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/dma/mtk-*
 F:     drivers/dma/mediatek/
 
-MEDIATEK PMIC LED DRIVER
-M:     Sean Wang <sean.wang@mediatek.com>
-S:     Maintained
-F:     drivers/leds/leds-mt6323.c
-F:     Documentation/devicetree/bindings/leds/leds-mt6323.txt
-
 MEDIATEK ETHERNET DRIVER
 M:     Felix Fietkau <nbd@openwrt.org>
 M:     John Crispin <john@phrozen.org>
@@ -10633,50 +10659,36 @@ L:    netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/mediatek/
 
-MEDIATEK SWITCH DRIVER
-M:     Sean Wang <sean.wang@mediatek.com>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     drivers/net/dsa/mt7530.*
-F:     net/dsa/tag_mtk.c
-
-MEDIATEK BOARD LEVEL SHUTDOWN DRIVERS
-M:     Sean Wang <sean.wang@mediatek.com>
-L:     linux-pm@vger.kernel.org
-S:     Maintained
-F:     Documentation/devicetree/bindings/power/reset/mt6323-poweroff.txt
-F:     drivers/power/reset/mt6323-poweroff.c
-
 MEDIATEK JPEG DRIVER
 M:     Rick Chang <rick.chang@mediatek.com>
 M:     Bin Liu <bin.liu@mediatek.com>
 S:     Supported
-F:     drivers/media/platform/mtk-jpeg/
 F:     Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt
+F:     drivers/media/platform/mtk-jpeg/
 
 MEDIATEK MDP DRIVER
 M:     Minghsiu Tsai <minghsiu.tsai@mediatek.com>
 M:     Houlong Wei <houlong.wei@mediatek.com>
 M:     Andrew-CT Chen <andrew-ct.chen@mediatek.com>
 S:     Supported
+F:     Documentation/devicetree/bindings/media/mediatek-mdp.txt
 F:     drivers/media/platform/mtk-mdp/
 F:     drivers/media/platform/mtk-vpu/
-F:     Documentation/devicetree/bindings/media/mediatek-mdp.txt
 
 MEDIATEK MEDIA DRIVER
 M:     Tiffany Lin <tiffany.lin@mediatek.com>
 M:     Andrew-CT Chen <andrew-ct.chen@mediatek.com>
 S:     Supported
-F:     drivers/media/platform/mtk-vcodec/
-F:     drivers/media/platform/mtk-vpu/
 F:     Documentation/devicetree/bindings/media/mediatek-vcodec.txt
 F:     Documentation/devicetree/bindings/media/mediatek-vpu.txt
+F:     drivers/media/platform/mtk-vcodec/
+F:     drivers/media/platform/mtk-vpu/
 
 MEDIATEK MMC/SD/SDIO DRIVER
 M:     Chaotian Jing <chaotian.jing@mediatek.com>
 S:     Maintained
-F:     drivers/mmc/host/mtk-sd.c
 F:     Documentation/devicetree/bindings/mmc/mtk-sd.txt
+F:     drivers/mmc/host/mtk-sd.c
 
 MEDIATEK MT76 WIRELESS LAN DRIVER
 M:     Felix Fietkau <nbd@nbd.name>
@@ -10697,21 +10709,34 @@ MEDIATEK MT7621/28/88 I2C DRIVER
 M:     Stefan Roese <sr@denx.de>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
-F:     drivers/i2c/busses/i2c-mt7621.c
 F:     Documentation/devicetree/bindings/i2c/i2c-mt7621.txt
+F:     drivers/i2c/busses/i2c-mt7621.c
 
 MEDIATEK NAND CONTROLLER DRIVER
 M:     Xiaolei Li <xiaolei.li@mediatek.com>
 L:     linux-mtd@lists.infradead.org
 S:     Maintained
-F:     drivers/mtd/nand/raw/mtk_*
 F:     Documentation/devicetree/bindings/mtd/mtk-nand.txt
+F:     drivers/mtd/nand/raw/mtk_*
+
+MEDIATEK PMIC LED DRIVER
+M:     Sean Wang <sean.wang@mediatek.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/leds/leds-mt6323.txt
+F:     drivers/leds/leds-mt6323.c
 
 MEDIATEK RANDOM NUMBER GENERATOR SUPPORT
 M:     Sean Wang <sean.wang@mediatek.com>
 S:     Maintained
 F:     drivers/char/hw_random/mtk-rng.c
 
+MEDIATEK SWITCH DRIVER
+M:     Sean Wang <sean.wang@mediatek.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/dsa/mt7530.*
+F:     net/dsa/tag_mtk.c
+
 MEDIATEK USB3 DRD IP DRIVER
 M:     Chunfeng Yun <chunfeng.yun@mediatek.com>
 L:     linux-usb@vger.kernel.org (moderated for non-subscribers)
@@ -10725,8 +10750,8 @@ M:      Peter Senna Tschudin <peter.senna@gmail.com>
 M:     Martin Donnelly <martin.donnelly@ge.com>
 M:     Martyn Welch <martyn.welch@collabora.co.uk>
 S:     Maintained
-F:     drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
 F:     Documentation/devicetree/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt
+F:     drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
 
 MEGARAID SCSI/SAS DRIVERS
 M:     Kashyap Desai <kashyap.desai@broadcom.com>
@@ -10734,8 +10759,8 @@ M:      Sumit Saxena <sumit.saxena@broadcom.com>
 M:     Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
 L:     megaraidlinux.pdl@broadcom.com
 L:     linux-scsi@vger.kernel.org
-W:     http://www.avagotech.com/support/
 S:     Maintained
+W:     http://www.avagotech.com/support/
 F:     Documentation/scsi/megaraid.rst
 F:     drivers/scsi/megaraid.*
 F:     drivers/scsi/megaraid/
@@ -10743,23 +10768,23 @@ F:    drivers/scsi/megaraid/
 MELEXIS MLX90614 DRIVER
 M:     Crt Mori <cmo@melexis.com>
 L:     linux-iio@vger.kernel.org
-W:     http://www.melexis.com
 S:     Supported
+W:     http://www.melexis.com
 F:     drivers/iio/temperature/mlx90614.c
 
 MELEXIS MLX90632 DRIVER
 M:     Crt Mori <cmo@melexis.com>
 L:     linux-iio@vger.kernel.org
-W:     http://www.melexis.com
 S:     Supported
+W:     http://www.melexis.com
 F:     drivers/iio/temperature/mlx90632.c
 
 MELFAS MIP4 TOUCHSCREEN DRIVER
 M:     Sangwon Jee <jeesw@melfas.com>
-W:     http://www.melfas.com
 S:     Supported
-F:     drivers/input/touchscreen/melfas_mip4.c
+W:     http://www.melfas.com
 F:     Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt
+F:     drivers/input/touchscreen/melfas_mip4.c
 
 MELLANOX ETHERNET DRIVER (mlx4_en)
 M:     Tariq Toukan <tariqt@mellanox.com>
@@ -10783,8 +10808,8 @@ L:      netdev@vger.kernel.org
 S:     Supported
 W:     http://www.mellanox.com
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
-F:     drivers/net/ethernet/mellanox/mlx5/core/en_accel/*
 F:     drivers/net/ethernet/mellanox/mlx5/core/accel/*
+F:     drivers/net/ethernet/mellanox/mlx5/core/en_accel/*
 F:     drivers/net/ethernet/mellanox/mlx5/core/fpga/*
 F:     include/linux/mlx5/mlx5_ifc_fpga.h
 
@@ -10820,18 +10845,18 @@ MELLANOX MLX4 core VPI driver
 M:     Tariq Toukan <tariqt@mellanox.com>
 L:     netdev@vger.kernel.org
 L:     linux-rdma@vger.kernel.org
+S:     Supported
 W:     http://www.mellanox.com
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
-S:     Supported
 F:     drivers/net/ethernet/mellanox/mlx4/
 F:     include/linux/mlx4/
 
 MELLANOX MLX4 IB driver
 M:     Yishai Hadas <yishaih@mellanox.com>
 L:     linux-rdma@vger.kernel.org
+S:     Supported
 W:     http://www.mellanox.com
 Q:     http://patchwork.kernel.org/project/linux-rdma/list/
-S:     Supported
 F:     drivers/infiniband/hw/mlx4/
 F:     include/linux/mlx4/
 F:     include/uapi/rdma/mlx4-abi.h
@@ -10841,19 +10866,19 @@ M:    Saeed Mahameed <saeedm@mellanox.com>
 M:     Leon Romanovsky <leonro@mellanox.com>
 L:     netdev@vger.kernel.org
 L:     linux-rdma@vger.kernel.org
+S:     Supported
 W:     http://www.mellanox.com
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
-S:     Supported
+F:     Documentation/networking/device_drivers/mellanox/
 F:     drivers/net/ethernet/mellanox/mlx5/core/
 F:     include/linux/mlx5/
-F:     Documentation/networking/device_drivers/mellanox/
 
 MELLANOX MLX5 IB driver
 M:     Leon Romanovsky <leonro@mellanox.com>
 L:     linux-rdma@vger.kernel.org
+S:     Supported
 W:     http://www.mellanox.com
 Q:     http://patchwork.kernel.org/project/linux-rdma/list/
-S:     Supported
 F:     drivers/infiniband/hw/mlx5/
 F:     include/linux/mlx5/
 F:     include/uapi/rdma/mlx5-abi.h
@@ -10863,17 +10888,17 @@ M:    Vadim Pasternak <vadimp@mellanox.com>
 M:     Michael Shych <michaelsh@mellanox.com>
 L:     linux-i2c@vger.kernel.org
 S:     Supported
+F:     Documentation/i2c/busses/i2c-mlxcpld.rst
 F:     drivers/i2c/busses/i2c-mlxcpld.c
 F:     drivers/i2c/muxes/i2c-mux-mlxcpld.c
-F:     Documentation/i2c/busses/i2c-mlxcpld.rst
 
 MELLANOX MLXCPLD LED DRIVER
 M:     Vadim Pasternak <vadimp@mellanox.com>
 L:     linux-leds@vger.kernel.org
 S:     Supported
+F:     Documentation/leds/leds-mlxcpld.rst
 F:     drivers/leds/leds-mlxcpld.c
 F:     drivers/leds/leds-mlxreg.c
-F:     Documentation/leds/leds-mlxcpld.rst
 
 MELLANOX PLATFORM DRIVER
 M:     Vadim Pasternak <vadimp@mellanox.com>
@@ -10886,30 +10911,30 @@ M:    Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
 M:     "Paul E. McKenney" <paulmck@kernel.org>
 L:     linux-kernel@vger.kernel.org
 S:     Supported
-F:     kernel/sched/membarrier.c
-F:     include/uapi/linux/membarrier.h
 F:     arch/powerpc/include/asm/membarrier.h
+F:     include/uapi/linux/membarrier.h
+F:     kernel/sched/membarrier.c
 
 MEMBLOCK
 M:     Mike Rapoport <rppt@linux.ibm.com>
 L:     linux-mm@kvack.org
 S:     Maintained
+F:     Documentation/core-api/boot-time-mm.rst
 F:     include/linux/memblock.h
 F:     mm/memblock.c
-F:     Documentation/core-api/boot-time-mm.rst
 
 MEMORY MANAGEMENT
 M:     Andrew Morton <akpm@linux-foundation.org>
 L:     linux-mm@kvack.org
+S:     Maintained
 W:     http://www.linux-mm.org
 T:     quilt https://ozlabs.org/~akpm/mmotm/
 T:     quilt https://ozlabs.org/~akpm/mmots/
 T:     git git://github.com/hnaz/linux-mm.git
-S:     Maintained
-F:     include/linux/mm.h
 F:     include/linux/gfp.h
-F:     include/linux/mmzone.h
 F:     include/linux/memory_hotplug.h
+F:     include/linux/mm.h
+F:     include/linux/mmzone.h
 F:     include/linux/vmalloc.h
 F:     mm/
 
@@ -10918,12 +10943,12 @@ M:    Miquel Raynal <miquel.raynal@bootlin.com>
 M:     Richard Weinberger <richard@nod.at>
 M:     Vignesh Raghavendra <vigneshr@ti.com>
 L:     linux-mtd@lists.infradead.org
+S:     Maintained
 W:     http://www.linux-mtd.infradead.org/
 Q:     http://patchwork.ozlabs.org/project/linux-mtd/list/
 C:     irc://irc.oftc.net/mtd
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git mtd/fixes
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git mtd/next
-S:     Maintained
 F:     Documentation/devicetree/bindings/mtd/
 F:     drivers/mtd/
 F:     include/linux/mtd/
@@ -10938,18 +10963,18 @@ F:    drivers/watchdog/mena21_wdt.c
 MEN CHAMELEON BUS (mcb)
 M:     Johannes Thumshirn <morbidrsa@gmail.com>
 S:     Maintained
+F:     Documentation/driver-api/men-chameleon-bus.rst
 F:     drivers/mcb/
 F:     include/linux/mcb.h
-F:     Documentation/driver-api/men-chameleon-bus.rst
 
 MEN F21BMC (Board Management Controller)
 M:     Andreas Werner <andreas.werner@men.de>
 S:     Supported
+F:     Documentation/hwmon/menf21bmc.rst
+F:     drivers/hwmon/menf21bmc_hwmon.c
+F:     drivers/leds/leds-menf21bmc.c
 F:     drivers/mfd/menf21bmc.c
 F:     drivers/watchdog/menf21bmc_wdt.c
-F:     drivers/leds/leds-menf21bmc.c
-F:     drivers/hwmon/menf21bmc_hwmon.c
-F:     Documentation/hwmon/menf21bmc.rst
 
 MEN Z069 WATCHDOG DRIVER
 M:     Johannes Thumshirn <jth@kernel.org>
@@ -10961,27 +10986,27 @@ MESON AO CEC DRIVER FOR AMLOGIC SOCS
 M:     Neil Armstrong <narmstrong@baylibre.com>
 L:     linux-media@vger.kernel.org
 L:     linux-amlogic@lists.infradead.org
-W:     http://linux-meson.com/
 S:     Supported
-F:     drivers/media/platform/meson/ao-cec.c
-F:     drivers/media/platform/meson/ao-cec-g12a.c
-F:     Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml
+W:     http://linux-meson.com/
 T:     git git://linuxtv.org/media_tree.git
+F:     Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml
+F:     drivers/media/platform/meson/ao-cec-g12a.c
+F:     drivers/media/platform/meson/ao-cec.c
 
 MESON NAND CONTROLLER DRIVER FOR AMLOGIC SOCS
 M:     Liang Yang <liang.yang@amlogic.com>
 L:     linux-mtd@lists.infradead.org
 S:     Maintained
-F:     drivers/mtd/nand/raw/meson_*
 F:     Documentation/devicetree/bindings/mtd/amlogic,meson-nand.txt
+F:     drivers/mtd/nand/raw/meson_*
 
 MESON VIDEO DECODER DRIVER FOR AMLOGIC SOCS
 M:     Maxime Jourdan <mjourdan@baylibre.com>
 L:     linux-media@vger.kernel.org
 L:     linux-amlogic@lists.infradead.org
 S:     Supported
-F:     drivers/staging/media/meson/vdec/
 T:     git git://linuxtv.org/media_tree.git
+F:     drivers/staging/media/meson/vdec/
 
 METHODE UDPU SUPPORT
 M:     Vladimir Vid <vladimir.vid@sartura.hr>
@@ -11000,17 +11025,32 @@ F:    include/linux/mhi.h
 
 MICROBLAZE ARCHITECTURE
 M:     Michal Simek <monstr@monstr.eu>
+S:     Supported
 W:     http://www.monstr.eu/fdt/
 T:     git git://git.monstr.eu/linux-2.6-microblaze.git
-S:     Supported
 F:     arch/microblaze/
 
 MICROCHIP AT91 SERIAL DRIVER
 M:     Richard Genoud <richard.genoud@gmail.com>
 S:     Maintained
+F:     Documentation/devicetree/bindings/mfd/atmel-usart.txt
 F:     drivers/tty/serial/atmel_serial.c
 F:     drivers/tty/serial/atmel_serial.h
+
+MICROCHIP AT91 USART MFD DRIVER
+M:     Radu Pirea <radu_nicolae.pirea@upb.ro>
+L:     linux-kernel@vger.kernel.org
+S:     Supported
+F:     Documentation/devicetree/bindings/mfd/atmel-usart.txt
+F:     drivers/mfd/at91-usart.c
+F:     include/dt-bindings/mfd/at91-usart.h
+
+MICROCHIP AT91 USART SPI DRIVER
+M:     Radu Pirea <radu_nicolae.pirea@upb.ro>
+L:     linux-spi@vger.kernel.org
+S:     Supported
 F:     Documentation/devicetree/bindings/mfd/atmel-usart.txt
+F:     drivers/spi/spi-at91-usart.c
 
 MICROCHIP AUDIO ASOC DRIVERS
 M:     Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
@@ -11023,11 +11063,11 @@ M:    Ludovic Desroches <ludovic.desroches@microchip.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     dmaengine@vger.kernel.org
 S:     Supported
+F:     Documentation/devicetree/bindings/dma/atmel-dma.txt
 F:     drivers/dma/at_hdmac.c
 F:     drivers/dma/at_hdmac_regs.h
-F:     include/linux/platform_data/dma-atmel.h
-F:     Documentation/devicetree/bindings/dma/atmel-dma.txt
 F:     include/dt-bindings/dma/at91.h
+F:     include/linux/platform_data/dma-atmel.h
 
 MICROCHIP ECC DRIVER
 M:     Tudor Ambarus <tudor.ambarus@microchip.com>
@@ -11039,18 +11079,18 @@ MICROCHIP I2C DRIVER
 M:     Ludovic Desroches <ludovic.desroches@microchip.com>
 L:     linux-i2c@vger.kernel.org
 S:     Supported
-F:     drivers/i2c/busses/i2c-at91.h
 F:     drivers/i2c/busses/i2c-at91-*.c
+F:     drivers/i2c/busses/i2c-at91.h
 
 MICROCHIP ISC DRIVER
 M:     Eugen Hristev <eugen.hristev@microchip.com>
 L:     linux-media@vger.kernel.org
 S:     Supported
-F:     drivers/media/platform/atmel/atmel-sama5d2-isc.c
-F:     drivers/media/platform/atmel/atmel-isc.h
+F:     Documentation/devicetree/bindings/media/atmel-isc.txt
 F:     drivers/media/platform/atmel/atmel-isc-base.c
 F:     drivers/media/platform/atmel/atmel-isc-regs.h
-F:     Documentation/devicetree/bindings/media/atmel-isc.txt
+F:     drivers/media/platform/atmel/atmel-isc.h
+F:     drivers/media/platform/atmel/atmel-sama5d2-isc.c
 F:     include/linux/atmel-isc-media.h
 
 MICROCHIP ISI DRIVER
@@ -11060,30 +11100,15 @@ S:    Supported
 F:     drivers/media/platform/atmel/atmel-isi.c
 F:     drivers/media/platform/atmel/atmel-isi.h
 
-MICROCHIP AT91 USART MFD DRIVER
-M:     Radu Pirea <radu_nicolae.pirea@upb.ro>
-L:     linux-kernel@vger.kernel.org
-S:     Supported
-F:     drivers/mfd/at91-usart.c
-F:     include/dt-bindings/mfd/at91-usart.h
-F:     Documentation/devicetree/bindings/mfd/atmel-usart.txt
-
-MICROCHIP AT91 USART SPI DRIVER
-M:     Radu Pirea <radu_nicolae.pirea@upb.ro>
-L:     linux-spi@vger.kernel.org
-S:     Supported
-F:     drivers/spi/spi-at91-usart.c
-F:     Documentation/devicetree/bindings/mfd/atmel-usart.txt
-
 MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER
 M:     Woojung Huh <woojung.huh@microchip.com>
 M:     Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     net/dsa/tag_ksz.c
+F:     Documentation/devicetree/bindings/net/dsa/ksz.txt
 F:     drivers/net/dsa/microchip/*
 F:     include/linux/platform_data/microchip-ksz.h
-F:     Documentation/devicetree/bindings/net/dsa/ksz.txt
+F:     net/dsa/tag_ksz.c
 
 MICROCHIP LAN743X ETHERNET DRIVER
 M:     Bryan Whitehead <bryan.whitehead@microchip.com>
@@ -11099,11 +11124,6 @@ S:     Maintained
 F:     drivers/video/fbdev/atmel_lcdfb.c
 F:     include/video/atmel_lcdc.h
 
-MICROCHIP MMC/SD/SDIO MCI DRIVER
-M:     Ludovic Desroches <ludovic.desroches@microchip.com>
-S:     Maintained
-F:     drivers/mmc/host/atmel-mci.c
-
 MICROCHIP MCP16502 PMIC DRIVER
 M:     Andrei Stefanescu <andrei.stefanescu@microchip.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -11116,31 +11136,36 @@ M:    Marcus Folkesson <marcus.folkesson@gmail.com>
 M:     Kent Gustavsson <kent@minoris.se>
 L:     linux-iio@vger.kernel.org
 S:     Supported
-F:     drivers/iio/adc/mcp3911.c
 F:     Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml
+F:     drivers/iio/adc/mcp3911.c
+
+MICROCHIP MMC/SD/SDIO MCI DRIVER
+M:     Ludovic Desroches <ludovic.desroches@microchip.com>
+S:     Maintained
+F:     drivers/mmc/host/atmel-mci.c
 
 MICROCHIP NAND DRIVER
 M:     Tudor Ambarus <tudor.ambarus@microchip.com>
 L:     linux-mtd@lists.infradead.org
 S:     Supported
-F:     drivers/mtd/nand/raw/atmel/*
 F:     Documentation/devicetree/bindings/mtd/atmel-nand.txt
+F:     drivers/mtd/nand/raw/atmel/*
 
 MICROCHIP PWM DRIVER
 M:     Claudiu Beznea <claudiu.beznea@microchip.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-pwm@vger.kernel.org
 S:     Supported
-F:     drivers/pwm/pwm-atmel.c
 F:     Documentation/devicetree/bindings/pwm/atmel-pwm.txt
+F:     drivers/pwm/pwm-atmel.c
 
 MICROCHIP SAMA5D2-COMPATIBLE ADC DRIVER
 M:     Ludovic Desroches <ludovic.desroches@microchip.com>
 M:     Eugen Hristev <eugen.hristev@microchip.com>
 L:     linux-iio@vger.kernel.org
 S:     Supported
-F:     drivers/iio/adc/at91-sama5d2_adc.c
 F:     Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt
+F:     drivers/iio/adc/at91-sama5d2_adc.c
 F:     include/dt-bindings/iio/adc/at91-sama5d2_adc.h
 
 MICROCHIP SAMA5D2-COMPATIBLE SHUTDOWN CONTROLLER
@@ -11160,18 +11185,18 @@ S:    Supported
 F:     drivers/misc/atmel-ssc.c
 F:     include/linux/atmel-ssc.h
 
-MICROCHIP USBA UDC DRIVER
-M:     Cristian Birsan <cristian.birsan@microchip.com>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Supported
-F:     drivers/usb/gadget/udc/atmel_usba_udc.*
-
 MICROCHIP USB251XB DRIVER
 M:     Richard Leitner <richard.leitner@skidata.com>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
-F:     drivers/usb/misc/usb251xb.c
 F:     Documentation/devicetree/bindings/usb/usb251xb.txt
+F:     drivers/usb/misc/usb251xb.c
+
+MICROCHIP USBA UDC DRIVER
+M:     Cristian Birsan <cristian.birsan@microchip.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Supported
+F:     drivers/usb/gadget/udc/atmel_usba_udc.*
 
 MICROCHIP XDMA DRIVER
 M:     Ludovic Desroches <ludovic.desroches@microchip.com>
@@ -11180,35 +11205,35 @@ L:    dmaengine@vger.kernel.org
 S:     Supported
 F:     drivers/dma/at_xdmac.c
 
+MICROSEMI ETHERNET SWITCH DRIVER
+M:     Alexandre Belloni <alexandre.belloni@bootlin.com>
+M:     Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     drivers/net/ethernet/mscc/
+F:     include/soc/mscc/ocelot*
+
 MICROSEMI MIPS SOCS
 M:     Alexandre Belloni <alexandre.belloni@bootlin.com>
 M:     Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
 L:     linux-mips@vger.kernel.org
 S:     Supported
-F:     arch/mips/generic/board-ocelot.c
-F:     arch/mips/configs/generic/board-ocelot.config
-F:     arch/mips/boot/dts/mscc/
 F:     Documentation/devicetree/bindings/mips/mscc.txt
+F:     arch/mips/boot/dts/mscc/
+F:     arch/mips/configs/generic/board-ocelot.config
+F:     arch/mips/generic/board-ocelot.c
 
 MICROSEMI SMART ARRAY SMARTPQI DRIVER (smartpqi)
 M:     Don Brace <don.brace@microsemi.com>
 L:     esc.storagedev@microsemi.com
 L:     linux-scsi@vger.kernel.org
 S:     Supported
-F:     drivers/scsi/smartpqi/smartpqi*.[ch]
+F:     Documentation/scsi/smartpqi.rst
 F:     drivers/scsi/smartpqi/Kconfig
 F:     drivers/scsi/smartpqi/Makefile
+F:     drivers/scsi/smartpqi/smartpqi*.[ch]
 F:     include/linux/cciss*.h
 F:     include/uapi/linux/cciss*.h
-F:     Documentation/scsi/smartpqi.rst
-
-MICROSEMI ETHERNET SWITCH DRIVER
-M:     Alexandre Belloni <alexandre.belloni@bootlin.com>
-M:     Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
-L:     netdev@vger.kernel.org
-S:     Supported
-F:     drivers/net/ethernet/mscc/
-F:     include/soc/mscc/ocelot*
 
 MICROSOFT SURFACE PRO 3 BUTTON DRIVER
 M:     Chen Yu <yu.c.chen@intel.com>
@@ -11224,10 +11249,10 @@ F:    drivers/usb/image/microtek.*
 MIPS
 M:     Thomas Bogendoerfer <tsbogend@alpha.franken.de>
 L:     linux-mips@vger.kernel.org
+S:     Maintained
 W:     http://www.linux-mips.org/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git
 Q:     https://patchwork.kernel.org/project/linux-mips/list/
-S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git
 F:     Documentation/devicetree/bindings/mips/
 F:     Documentation/mips/
 F:     arch/mips/
@@ -11251,56 +11276,56 @@ F:    Documentation/devicetree/bindings/power/mti,mips-cpc.txt
 F:     arch/mips/generic/
 F:     arch/mips/tools/generic-board-config.sh
 
+MIPS RINT INSTRUCTION EMULATION
+M:     Aleksandar Markovic <aleksandar.markovic@mips.com>
+L:     linux-mips@vger.kernel.org
+S:     Supported
+F:     arch/mips/math-emu/dp_rint.c
+F:     arch/mips/math-emu/sp_rint.c
+
 MIPS/LOONGSON1 ARCHITECTURE
 M:     Keguang Zhang <keguang.zhang@gmail.com>
 L:     linux-mips@vger.kernel.org
 S:     Maintained
-F:     arch/mips/loongson32/
 F:     arch/mips/include/asm/mach-loongson32/
-F:     drivers/*/*loongson1*
+F:     arch/mips/loongson32/
 F:     drivers/*/*/*loongson1*
+F:     drivers/*/*loongson1*
 
 MIPS/LOONGSON2EF ARCHITECTURE
 M:     Jiaxun Yang <jiaxun.yang@flygoat.com>
 L:     linux-mips@vger.kernel.org
 S:     Maintained
-F:     arch/mips/loongson2ef/
 F:     arch/mips/include/asm/mach-loongson2ef/
-F:     drivers/*/*loongson2*
+F:     arch/mips/loongson2ef/
 F:     drivers/*/*/*loongson2*
+F:     drivers/*/*loongson2*
 
 MIPS/LOONGSON64 ARCHITECTURE
 M:     Huacai Chen <chenhc@lemote.com>
 M:     Jiaxun Yang <jiaxun.yang@flygoat.com>
 L:     linux-mips@vger.kernel.org
 S:     Maintained
-F:     arch/mips/loongson64/
 F:     arch/mips/include/asm/mach-loongson64/
-F:     drivers/platform/mips/cpu_hwmon.c
-F:     drivers/irqchip/irq-loongson*
-F:     drivers/*/*loongson3*
+F:     arch/mips/loongson64/
 F:     drivers/*/*/*loongson3*
-
-MIPS RINT INSTRUCTION EMULATION
-M:     Aleksandar Markovic <aleksandar.markovic@mips.com>
-L:     linux-mips@vger.kernel.org
-S:     Supported
-F:     arch/mips/math-emu/sp_rint.c
-F:     arch/mips/math-emu/dp_rint.c
+F:     drivers/*/*loongson3*
+F:     drivers/irqchip/irq-loongson*
+F:     drivers/platform/mips/cpu_hwmon.c
 
 MIROSOUND PCM20 FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Odd Fixes
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/radio-miropcm20*
 
 MMP SUPPORT
 R:     Lubomir Rintel <lkundrak@v3.sk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/linux-mmp.git
 S:     Odd Fixes
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/linux-mmp.git
 F:     arch/arm/boot/dts/mmp*
 F:     arch/arm/mach-mmp/
 F:     linux/soc/mmp/
@@ -11328,31 +11353,39 @@ F:    mm/mmu_gather.c
 MN88472 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-S:     Maintained
 F:     drivers/media/dvb-frontends/mn88472*
 
 MN88473 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-S:     Maintained
 F:     drivers/media/dvb-frontends/mn88473*
 
 MODULE SUPPORT
 M:     Jessica Yu <jeyu@kernel.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux.git modules-next
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux.git modules-next
 F:     include/linux/module.h
 F:     kernel/module.c
 
+MONOLITHIC POWER SYSTEM PMIC DRIVER
+M:     Saravanan Sekar <sravanhome@gmail.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/regulator/mps,mp*.yaml
+F:     drivers/regulator/mp5416.c
+F:     drivers/regulator/mpq7920.c
+F:     drivers/regulator/mpq7920.h
+
 MOTION EYE VAIO PICTUREBOOK CAMERA DRIVER
-W:     http://popies.net/meye/
 S:     Orphan
+W:     http://popies.net/meye/
 F:     Documentation/media/v4l-drivers/meye*
 F:     drivers/media/pci/meye/
 F:     include/uapi/linux/meye.h
@@ -11363,27 +11396,19 @@ S:    Maintained
 F:     Documentation/driver-api/serial/moxa-smartio.rst
 F:     drivers/tty/mxser.*
 
-MONOLITHIC POWER SYSTEM PMIC DRIVER
-M:     Saravanan Sekar <sravanhome@gmail.com>
-S:     Maintained
-F:     Documentation/devicetree/bindings/regulator/mps,mp*.yaml
-F:     drivers/regulator/mp5416.c
-F:     drivers/regulator/mpq7920.c
-F:     drivers/regulator/mpq7920.h
-
 MR800 AVERMEDIA USB FM RADIO DRIVER
 M:     Alexey Klimov <klimov.linux@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/radio-mr800.c
 
 MRF24J40 IEEE 802.15.4 RADIO DRIVER
 M:     Alan Ott <alan@signal11.us>
 L:     linux-wpan@vger.kernel.org
 S:     Maintained
-F:     drivers/net/ieee802154/mrf24j40.c
 F:     Documentation/devicetree/bindings/net/ieee802154/mrf24j40.txt
+F:     drivers/net/ieee802154/mrf24j40.c
 
 MSI LAPTOP SUPPORT
 M:     "Lee, Chun-Yi" <jlee@suse.com>
@@ -11399,21 +11424,21 @@ F:    drivers/platform/x86/msi-wmi.c
 MSI001 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/tuners/msi001*
 
 MSI2500 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/usb/msi2500/
 
 MSYSTEMS DISKONCHIP G3 MTD DRIVER
@@ -11425,40 +11450,40 @@ F:    drivers/mtd/devices/docg3*
 MT9M032 APTINA SENSOR DRIVER
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/mt9m032.c
 F:     include/media/i2c/mt9m032.h
 
 MT9P031 APTINA CAMERA SENSOR
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/mt9p031.c
 F:     include/media/i2c/mt9p031.h
 
 MT9T001 APTINA CAMERA SENSOR
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/mt9t001.c
 F:     include/media/i2c/mt9t001.h
 
 MT9T112 APTINA CAMERA SENSOR
 M:     Jacopo Mondi <jacopo@jmondi.org>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Odd Fixes
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/mt9t112.c
 F:     include/media/i2c/mt9t112.h
 
 MT9V032 APTINA CAMERA SENSOR
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/mt9v032.txt
 F:     drivers/media/i2c/mt9v032.c
 F:     include/media/i2c/mt9v032.h
@@ -11466,19 +11491,19 @@ F:    include/media/i2c/mt9v032.h
 MT9V111 APTINA CAMERA SENSOR
 M:     Jacopo Mondi <jacopo@jmondi.org>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.txt
 F:     drivers/media/i2c/mt9v111.c
 
 MULTIFUNCTION DEVICES (MFD)
 M:     Lee Jones <lee.jones@linaro.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git
 F:     Documentation/devicetree/bindings/mfd/
 F:     drivers/mfd/
-F:     include/linux/mfd/
 F:     include/dt-bindings/mfd/
+F:     include/linux/mfd/
 
 MULTIMEDIA CARD (MMC) ETC. OVER SPI
 S:     Orphan
@@ -11488,8 +11513,8 @@ F:      include/linux/spi/mmc_spi.h
 MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
 M:     Ulf Hansson <ulf.hansson@linaro.org>
 L:     linux-mmc@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git
 F:     Documentation/devicetree/bindings/mmc/
 F:     drivers/mmc/
 F:     include/linux/mmc/
@@ -11500,9 +11525,9 @@ M:      Peter Rosin <peda@axentia.se>
 S:     Maintained
 F:     Documentation/ABI/testing/sysfs-class-mux*
 F:     Documentation/devicetree/bindings/mux/
+F:     drivers/mux/
 F:     include/dt-bindings/mux/
 F:     include/linux/mux/
-F:     drivers/mux/
 
 MULTITECH MULTIPORT CARD (ISICOM)
 S:     Orphan
@@ -11524,11 +11549,11 @@ F:    drivers/media/tuners/mxl301rf*
 MXL5007T MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mkrufky/tuners.git
-S:     Maintained
 F:     drivers/media/tuners/mxl5007t.*
 
 MXSFB DRM DRIVER
@@ -11536,9 +11561,9 @@ M:      Marek Vasut <marex@denx.de>
 M:     Stefan Agner <stefan@agner.ch>
 L:     dri-devel@lists.freedesktop.org
 S:     Supported
-F:     drivers/gpu/drm/mxsfb/
-F:     Documentation/devicetree/bindings/display/mxsfb.txt
 T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/devicetree/bindings/display/mxsfb.txt
+F:     drivers/gpu/drm/mxsfb/
 
 MYLEX DAC960 PCI RAID Controller
 M:     Hannes Reinecke <hare@kernel.org>
@@ -11550,26 +11575,26 @@ F:    drivers/scsi/myrs.*
 MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
 M:     Chris Lee <christopher.lee@cspi.com>
 L:     netdev@vger.kernel.org
-W:     https://www.cspi.com/ethernet-products/support/downloads/
 S:     Supported
+W:     https://www.cspi.com/ethernet-products/support/downloads/
 F:     drivers/net/ethernet/myricom/myri10ge/
 
 NAND FLASH SUBSYSTEM
 M:     Miquel Raynal <miquel.raynal@bootlin.com>
 R:     Richard Weinberger <richard@nod.at>
 L:     linux-mtd@lists.infradead.org
+S:     Maintained
 W:     http://www.linux-mtd.infradead.org/
 Q:     http://patchwork.ozlabs.org/project/linux-mtd/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next
 C:     irc://irc.oftc.net/mtd
-S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next
 F:     drivers/mtd/nand/
 F:     include/linux/mtd/*nand*.h
 
 NATIVE INSTRUMENTS USB SOUND INTERFACE DRIVER
 M:     Daniel Mack <zonque@gmail.com>
-S:     Maintained
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
 W:     http://www.native-instruments.com
 F:     sound/usb/caiaq/
 
@@ -11605,13 +11630,10 @@ S:    Maintained
 F:     Documentation/hwmon/nct6775.rst
 F:     drivers/hwmon/nct6775.c
 
-NET_FAILOVER MODULE
-M:     Sridhar Samudrala <sridhar.samudrala@intel.com>
-L:     netdev@vger.kernel.org
-S:     Supported
-F:     drivers/net/net_failover.c
-F:     include/net/net_failover.h
-F:     Documentation/networking/net_failover.rst
+NETDEVSIM
+M:     Jakub Kicinski <kuba@kernel.org>
+S:     Maintained
+F:     drivers/net/netdevsim/*
 
 NETEM NETWORK EMULATOR
 M:     Stephen Hemminger <stephen@networkplumber.org>
@@ -11633,13 +11655,13 @@ M:    Jozsef Kadlecsik <kadlec@netfilter.org>
 M:     Florian Westphal <fw@strlen.de>
 L:     netfilter-devel@vger.kernel.org
 L:     coreteam@netfilter.org
+S:     Maintained
 W:     http://www.netfilter.org/
 W:     http://www.iptables.org/
 W:     http://www.nftables.org/
 Q:     http://patchwork.ozlabs.org/project/netfilter-devel/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next.git
-S:     Maintained
 F:     include/linux/netfilter*
 F:     include/linux/netfilter/
 F:     include/net/netfilter/
@@ -11647,14 +11669,14 @@ F:    include/uapi/linux/netfilter*
 F:     include/uapi/linux/netfilter/
 F:     net/*/netfilter.c
 F:     net/*/netfilter/
-F:     net/netfilter/
 F:     net/bridge/br_netfilter*.c
+F:     net/netfilter/
 
 NETROM NETWORK LAYER
 M:     Ralf Baechle <ralf@linux-mips.org>
 L:     linux-hams@vger.kernel.org
-W:     http://www.linux-ax25.org/
 S:     Maintained
+W:     http://www.linux-ax25.org/
 F:     include/net/netrom.h
 F:     include/uapi/linux/netrom.h
 F:     net/netrom/
@@ -11667,9 +11689,9 @@ F:      drivers/net/ethernet/netronome/
 
 NETWORK BLOCK DEVICE (NBD)
 M:     Josef Bacik <josef@toxicpanda.com>
-S:     Maintained
 L:     linux-block@vger.kernel.org
 L:     nbd@other.debian.org
+S:     Maintained
 F:     Documentation/admin-guide/blockdev/nbd.rst
 F:     drivers/block/nbd.c
 F:     include/trace/events/nbd.h
@@ -11680,37 +11702,37 @@ M:    Neil Horman <nhorman@tuxdriver.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 W:     https://fedorahosted.org/dropwatch/
-F:     net/core/drop_monitor.c
-F:     include/uapi/linux/net_dropmon.h
 F:     include/net/drop_monitor.h
+F:     include/uapi/linux/net_dropmon.h
+F:     net/core/drop_monitor.c
 
 NETWORKING DRIVERS
 M:     "David S. Miller" <davem@davemloft.net>
 L:     netdev@vger.kernel.org
+S:     Odd Fixes
 W:     http://www.linuxfoundation.org/en/Net
 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
-S:     Odd Fixes
 F:     Documentation/devicetree/bindings/net/
 F:     drivers/net/
-F:     include/linux/if_*
-F:     include/linux/netdevice.h
 F:     include/linux/etherdevice.h
 F:     include/linux/fcdevice.h
 F:     include/linux/fddidevice.h
 F:     include/linux/hippidevice.h
+F:     include/linux/if_*
 F:     include/linux/inetdevice.h
+F:     include/linux/netdevice.h
 F:     include/uapi/linux/if_*
 F:     include/uapi/linux/netdevice.h
 
 NETWORKING DRIVERS (WIRELESS)
 M:     Kalle Valo <kvalo@codeaurora.org>
 L:     linux-wireless@vger.kernel.org
+S:     Maintained
 Q:     http://patchwork.kernel.org/project/linux-wireless/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git
-S:     Maintained
 F:     Documentation/devicetree/bindings/net/wireless/
 F:     drivers/net/wireless/
 
@@ -11720,97 +11742,97 @@ M:    Vivien Didelot <vivien.didelot@gmail.com>
 M:     Florian Fainelli <f.fainelli@gmail.com>
 S:     Maintained
 F:     Documentation/devicetree/bindings/net/dsa/
-F:     net/dsa/
-F:     include/net/dsa.h
+F:     drivers/net/dsa/
 F:     include/linux/dsa/
 F:     include/linux/platform_data/dsa.h
-F:     drivers/net/dsa/
+F:     include/net/dsa.h
+F:     net/dsa/
 
 NETWORKING [GENERAL]
 M:     "David S. Miller" <davem@davemloft.net>
 M:     Jakub Kicinski <kuba@kernel.org>
 L:     netdev@vger.kernel.org
+S:     Maintained
 W:     http://www.linuxfoundation.org/en/Net
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
+B:     mailto:netdev@vger.kernel.org
 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
-B:     mailto:netdev@vger.kernel.org
-S:     Maintained
-F:     net/
-F:     include/net/
+F:     Documentation/networking/
 F:     include/linux/in.h
 F:     include/linux/net.h
 F:     include/linux/netdevice.h
+F:     include/net/
 F:     include/uapi/linux/in.h
 F:     include/uapi/linux/net.h
-F:     include/uapi/linux/netdevice.h
 F:     include/uapi/linux/net_namespace.h
-F:     tools/testing/selftests/net/
+F:     include/uapi/linux/netdevice.h
 F:     lib/net_utils.c
 F:     lib/random32.c
-F:     Documentation/networking/
+F:     net/
+F:     tools/testing/selftests/net/
 
 NETWORKING [IPSEC]
 M:     Steffen Klassert <steffen.klassert@secunet.com>
 M:     Herbert Xu <herbert@gondor.apana.org.au>
 M:     "David S. Miller" <davem@davemloft.net>
 L:     netdev@vger.kernel.org
+S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next.git
-S:     Maintained
-F:     net/xfrm/
-F:     net/key/
-F:     net/ipv4/xfrm*
-F:     net/ipv4/esp4*
+F:     include/net/xfrm.h
+F:     include/uapi/linux/xfrm.h
 F:     net/ipv4/ah4.c
-F:     net/ipv4/ipcomp.c
+F:     net/ipv4/esp4*
 F:     net/ipv4/ip_vti.c
-F:     net/ipv6/xfrm*
-F:     net/ipv6/esp6*
+F:     net/ipv4/ipcomp.c
+F:     net/ipv4/xfrm*
 F:     net/ipv6/ah6.c
-F:     net/ipv6/ipcomp6.c
+F:     net/ipv6/esp6*
 F:     net/ipv6/ip6_vti.c
-F:     include/uapi/linux/xfrm.h
-F:     include/net/xfrm.h
+F:     net/ipv6/ipcomp6.c
+F:     net/ipv6/xfrm*
+F:     net/key/
+F:     net/xfrm/
 
 NETWORKING [IPv4/IPv6]
 M:     "David S. Miller" <davem@davemloft.net>
 M:     Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
 M:     Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
 L:     netdev@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
+F:     arch/x86/net/*
+F:     include/net/ip*
 F:     net/ipv4/
 F:     net/ipv6/
-F:     include/net/ip*
-F:     arch/x86/net/*
 
 NETWORKING [LABELED] (NetLabel, Labeled IPsec, SECMARK)
 M:     Paul Moore <paul@paul-moore.com>
-W:     https://github.com/netlabel
 L:     netdev@vger.kernel.org
 L:     linux-security-module@vger.kernel.org
 S:     Maintained
+W:     https://github.com/netlabel
 F:     Documentation/netlabel/
 F:     include/net/calipso.h
 F:     include/net/cipso_ipv4.h
 F:     include/net/netlabel.h
-F:     include/uapi/linux/netfilter/xt_SECMARK.h
 F:     include/uapi/linux/netfilter/xt_CONNSECMARK.h
-F:     net/netlabel/
+F:     include/uapi/linux/netfilter/xt_SECMARK.h
 F:     net/ipv4/cipso_ipv4.c
 F:     net/ipv6/calipso.c
 F:     net/netfilter/xt_CONNSECMARK.c
 F:     net/netfilter/xt_SECMARK.c
+F:     net/netlabel/
 
 NETWORKING [MPTCP]
 M:     Mat Martineau <mathew.j.martineau@linux.intel.com>
 M:     Matthieu Baerts <matthieu.baerts@tessares.net>
 L:     netdev@vger.kernel.org
 L:     mptcp@lists.01.org
+S:     Maintained
 W:     https://github.com/multipath-tcp/mptcp_net-next/wiki
 B:     https://github.com/multipath-tcp/mptcp_net-next/issues
-S:     Maintained
 F:     include/net/mptcp.h
 F:     include/uapi/linux/mptcp.h
 F:     net/mptcp/
@@ -11820,14 +11842,14 @@ NETWORKING [TCP]
 M:     Eric Dumazet <edumazet@google.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     net/ipv4/tcp*.c
-F:     net/ipv4/syncookies.c
-F:     net/ipv6/tcp*.c
-F:     net/ipv6/syncookies.c
-F:     include/uapi/linux/tcp.h
-F:     include/net/tcp.h
 F:     include/linux/tcp.h
+F:     include/net/tcp.h
 F:     include/trace/events/tcp.h
+F:     include/uapi/linux/tcp.h
+F:     net/ipv4/syncookies.c
+F:     net/ipv4/tcp*.c
+F:     net/ipv6/syncookies.c
+F:     net/ipv6/tcp*.c
 
 NETWORKING [TLS]
 M:     Boris Pismenny <borisp@mellanox.com>
@@ -11837,19 +11859,14 @@ M:    Daniel Borkmann <daniel@iogearbox.net>
 M:     Jakub Kicinski <kuba@kernel.org>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     net/tls/*
-F:     include/uapi/linux/tls.h
 F:     include/net/tls.h
+F:     include/uapi/linux/tls.h
+F:     net/tls/*
 
 NETWORKING [WIRELESS]
 L:     linux-wireless@vger.kernel.org
 Q:     http://patchwork.kernel.org/project/linux-wireless/list/
 
-NETDEVSIM
-M:     Jakub Kicinski <kuba@kernel.org>
-S:     Maintained
-F:     drivers/net/netdevsim/*
-
 NETXEN (1/10) GbE SUPPORT
 M:     Manish Chopra <manishc@marvell.com>
 M:     Rahul Verma <rahulv@marvell.com>
@@ -11858,49 +11875,57 @@ L:    netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/qlogic/netxen/
 
+NET_FAILOVER MODULE
+M:     Sridhar Samudrala <sridhar.samudrala@intel.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     Documentation/networking/net_failover.rst
+F:     drivers/net/net_failover.c
+F:     include/net/net_failover.h
+
 NEXTHOP
 M:     David Ahern <dsahern@kernel.org>
 L:     netdev@vger.kernel.org
 S:     Maintained
+F:     include/net/netns/nexthop.h
 F:     include/net/nexthop.h
 F:     include/uapi/linux/nexthop.h
-F:     include/net/netns/nexthop.h
 F:     net/ipv4/nexthop.c
 
 NFC SUBSYSTEM
 L:     netdev@vger.kernel.org
 S:     Orphan
-F:     net/nfc/
-F:     include/net/nfc/
-F:     include/uapi/linux/nfc.h
+F:     Documentation/devicetree/bindings/net/nfc/
 F:     drivers/nfc/
 F:     include/linux/platform_data/nfcmrvl.h
-F:     Documentation/devicetree/bindings/net/nfc/
+F:     include/net/nfc/
+F:     include/uapi/linux/nfc.h
+F:     net/nfc/
 
 NFS, SUNRPC, AND LOCKD CLIENTS
 M:     Trond Myklebust <trond.myklebust@hammerspace.com>
 M:     Anna Schumaker <anna.schumaker@netapp.com>
 L:     linux-nfs@vger.kernel.org
+S:     Maintained
 W:     http://client.linux-nfs.org
 T:     git git://git.linux-nfs.org/projects/trondmy/linux-nfs.git
-S:     Maintained
 F:     fs/lockd/
 F:     fs/nfs/
 F:     fs/nfs_common/
-F:     net/sunrpc/
 F:     include/linux/lockd/
 F:     include/linux/nfs*
 F:     include/linux/sunrpc/
 F:     include/uapi/linux/nfs*
 F:     include/uapi/linux/sunrpc/
+F:     net/sunrpc/
 
 NILFS2 FILESYSTEM
 M:     Ryusuke Konishi <konishi.ryusuke@gmail.com>
 L:     linux-nilfs@vger.kernel.org
+S:     Supported
 W:     https://nilfs.sourceforge.io/
 W:     https://nilfs.osdn.jp/
 T:     git git://github.com/konis/nilfs2.git
-S:     Supported
 F:     Documentation/filesystems/nilfs2.rst
 F:     fs/nilfs2/
 F:     include/trace/events/nilfs2.h
@@ -11909,24 +11934,23 @@ F:    include/uapi/linux/nilfs2_ondisk.h
 
 NINJA SCSI-3 / NINJA SCSI-32Bi (16bit/CardBus) PCMCIA SCSI HOST ADAPTER DRIVER
 M:     YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
-W:     http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
 S:     Maintained
+W:     http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
 F:     Documentation/scsi/NinjaSCSI.rst
 F:     drivers/scsi/pcmcia/nsp_*
 
 NINJA SCSI-32Bi/UDE PCI/CARDBUS SCSI HOST ADAPTER DRIVER
 M:     GOTO Masanori <gotom@debian.or.jp>
 M:     YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
-W:     http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
 S:     Maintained
+W:     http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
 F:     Documentation/scsi/NinjaSCSI.rst
 F:     drivers/scsi/nsp32*
 
 NIOS2 ARCHITECTURE
 M:     Ley Foon Tan <ley.foon.tan@intel.com>
-L:     nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lftan/nios2.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lftan/nios2.git
 F:     arch/nios2/
 
 NOHZ, DYNTICKS SUPPORT
@@ -11934,29 +11958,29 @@ M:    Frederic Weisbecker <fweisbec@gmail.com>
 M:     Thomas Gleixner <tglx@linutronix.de>
 M:     Ingo Molnar <mingo@kernel.org>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/nohz
 S:     Maintained
-F:     kernel/time/tick*.*
-F:     include/linux/tick.h
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/nohz
 F:     include/linux/sched/nohz.h
+F:     include/linux/tick.h
+F:     kernel/time/tick*.*
 
 NOKIA N900 CAMERA SUPPORT (ET8EK8 SENSOR, AD5820 FOCUS)
 M:     Pavel Machek <pavel@ucw.cz>
 M:     Sakari Ailus <sakari.ailus@iki.fi>
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     drivers/media/i2c/et8ek8
 F:     drivers/media/i2c/ad5820.c
+F:     drivers/media/i2c/et8ek8
 
 NOKIA N900 POWER SUPPLY DRIVERS
-R:     Pali Rohár <pali.rohar@gmail.com>
-F:     include/linux/power/bq2415x_charger.h
-F:     include/linux/power/bq27xxx_battery.h
+R:     Pali Rohár <pali@kernel.org>
 F:     drivers/power/supply/bq2415x_charger.c
 F:     drivers/power/supply/bq27xxx_battery.c
 F:     drivers/power/supply/bq27xxx_battery_i2c.c
 F:     drivers/power/supply/isp1704_charger.c
 F:     drivers/power/supply/rx51_battery.c
+F:     include/linux/power/bq2415x_charger.h
+F:     include/linux/power/bq27xxx_battery.h
 
 NOLIBC HEADER FILE
 M:     Willy Tarreau <w@1wt.eu>
@@ -11967,8 +11991,8 @@ F:      tools/include/nolibc/
 NSDEPS
 M:     Matthias Maennich <maennich@google.com>
 S:     Maintained
-F:     scripts/nsdeps
 F:     Documentation/core-api/symbol-namespaces.rst
+F:     scripts/nsdeps
 
 NTB AMD DRIVER
 M:     Sanjay R Mehta <sanju.mehta@amd.com>
@@ -11985,8 +12009,8 @@ L:      linux-ntb@googlegroups.com
 S:     Supported
 W:     https://github.com/jonmason/ntb/wiki
 T:     git git://github.com/jonmason/ntb.git
-F:     drivers/ntb/
 F:     drivers/net/ntb_netdev.c
+F:     drivers/ntb/
 F:     include/linux/ntb.h
 F:     include/linux/ntb_transport.h
 F:     tools/testing/selftests/ntb/
@@ -12008,9 +12032,9 @@ F:      drivers/ntb/hw/intel/
 NTFS FILESYSTEM
 M:     Anton Altaparmakov <anton@tuxera.com>
 L:     linux-ntfs-dev@lists.sourceforge.net
+S:     Supported
 W:     http://www.tuxera.com/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs.git
-S:     Supported
 F:     Documentation/filesystems/ntfs.rst
 F:     fs/ntfs/
 
@@ -12027,8 +12051,8 @@ NVIDIA (rivafb and nvidiafb) FRAMEBUFFER DRIVER
 M:     Antonino Daplas <adaplas@gmail.com>
 L:     linux-fbdev@vger.kernel.org
 S:     Maintained
-F:     drivers/video/fbdev/riva/
 F:     drivers/video/fbdev/nvidia/
+F:     drivers/video/fbdev/riva/
 
 NVM EXPRESS DRIVER
 M:     Keith Busch <kbusch@kernel.org>
@@ -12036,9 +12060,9 @@ M:      Jens Axboe <axboe@fb.com>
 M:     Christoph Hellwig <hch@lst.de>
 M:     Sagi Grimberg <sagi@grimberg.me>
 L:     linux-nvme@lists.infradead.org
-T:     git://git.infradead.org/nvme.git
-W:     http://git.infradead.org/nvme.git
 S:     Supported
+W:     http://git.infradead.org/nvme.git
+T:     git://git.infradead.org/nvme.git
 F:     drivers/nvme/host/
 F:     include/linux/nvme.h
 F:     include/uapi/linux/nvme_ioctl.h
@@ -12047,38 +12071,46 @@ NVM EXPRESS FC TRANSPORT DRIVERS
 M:     James Smart <james.smart@broadcom.com>
 L:     linux-nvme@lists.infradead.org
 S:     Supported
-F:     include/linux/nvme-fc.h
-F:     include/linux/nvme-fc-driver.h
 F:     drivers/nvme/host/fc.c
 F:     drivers/nvme/target/fc.c
 F:     drivers/nvme/target/fcloop.c
+F:     include/linux/nvme-fc-driver.h
+F:     include/linux/nvme-fc.h
 
 NVM EXPRESS TARGET DRIVER
 M:     Christoph Hellwig <hch@lst.de>
 M:     Sagi Grimberg <sagi@grimberg.me>
 M:     Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
 L:     linux-nvme@lists.infradead.org
-T:     git://git.infradead.org/nvme.git
-W:     http://git.infradead.org/nvme.git
 S:     Supported
+W:     http://git.infradead.org/nvme.git
+T:     git://git.infradead.org/nvme.git
 F:     drivers/nvme/target/
 
 NVMEM FRAMEWORK
 M:     Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
 S:     Maintained
-F:     drivers/nvmem/
-F:     Documentation/devicetree/bindings/nvmem/
 F:     Documentation/ABI/stable/sysfs-bus-nvmem
+F:     Documentation/devicetree/bindings/nvmem/
+F:     drivers/nvmem/
 F:     include/linux/nvmem-consumer.h
 F:     include/linux/nvmem-provider.h
 
+NXP FSPI DRIVER
+M:     Ashish Kumar <ashish.kumar@nxp.com>
+R:     Yogesh Gaur <yogeshgaur.83@gmail.com>
+L:     linux-spi@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt
+F:     drivers/spi/spi-nxp-fspi.c
+
 NXP FXAS21002C DRIVER
 M:     Rui Miguel Silva <rmfrfs@gmail.com>
 L:     linux-iio@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/iio/gyroscope/nxp,fxas21002c.txt
-F:     drivers/iio/gyro/fxas21002c_core.c
 F:     drivers/iio/gyro/fxas21002c.h
+F:     drivers/iio/gyro/fxas21002c_core.c
 F:     drivers/iio/gyro/fxas21002c_i2c.c
 F:     drivers/iio/gyro/fxas21002c_spi.c
 
@@ -12123,17 +12155,9 @@ OBJAGG
 M:     Jiri Pirko <jiri@mellanox.com>
 L:     netdev@vger.kernel.org
 S:     Supported
+F:     include/linux/objagg.h
 F:     lib/objagg.c
 F:     lib/test_objagg.c
-F:     include/linux/objagg.h
-
-NXP FSPI DRIVER
-R:     Yogesh Gaur <yogeshgaur.83@gmail.com>
-M:     Ashish Kumar <ashish.kumar@nxp.com>
-L:     linux-spi@vger.kernel.org
-S:     Maintained
-F:     drivers/spi/spi-nxp-fspi.c
-F:     Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt
 
 OBJTOOL
 M:     Josh Poimboeuf <jpoimboe@redhat.com>
@@ -12146,12 +12170,12 @@ M:    Frederic Barrat <fbarrat@linux.ibm.com>
 M:     Andrew Donnellan <ajd@linux.ibm.com>
 L:     linuxppc-dev@lists.ozlabs.org
 S:     Supported
-F:     arch/powerpc/platforms/powernv/ocxl.c
+F:     Documentation/userspace-api/accelerators/ocxl.rst
 F:     arch/powerpc/include/asm/pnv-ocxl.h
+F:     arch/powerpc/platforms/powernv/ocxl.c
 F:     drivers/misc/ocxl/
 F:     include/misc/ocxl*
 F:     include/uapi/misc/ocxl.h
-F:     Documentation/userspace-api/accelerators/ocxl.rst
 
 OMAP AUDIO SUPPORT
 M:     Peter Ujfalusi <peter.ujfalusi@ti.com>
@@ -12159,9 +12183,9 @@ M:      Jarkko Nikula <jarkko.nikula@bitmer.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 L:     linux-omap@vger.kernel.org
 S:     Maintained
+F:     sound/soc/ti/n810.c
 F:     sound/soc/ti/omap*
 F:     sound/soc/ti/rx51.c
-F:     sound/soc/ti/n810.c
 F:     sound/soc/ti/sdma-pcm.*
 
 OMAP CLOCK FRAMEWORK SUPPORT
@@ -12176,11 +12200,11 @@ M:    Tony Lindgren <tony@atomide.com>
 L:     linux-omap@vger.kernel.org
 L:     devicetree@vger.kernel.org
 S:     Maintained
-F:     arch/arm/boot/dts/*omap*
 F:     arch/arm/boot/dts/*am3*
 F:     arch/arm/boot/dts/*am4*
 F:     arch/arm/boot/dts/*am5*
 F:     arch/arm/boot/dts/*dra7*
+F:     arch/arm/boot/dts/*omap*
 F:     arch/arm/boot/dts/logicpd-som-lv*
 F:     arch/arm/boot/dts/logicpd-torpedo*
 
@@ -12188,8 +12212,8 @@ OMAP DISPLAY SUBSYSTEM and FRAMEBUFFER SUPPORT (DSS2)
 L:     linux-omap@vger.kernel.org
 L:     linux-fbdev@vger.kernel.org
 S:     Orphan
-F:     drivers/video/fbdev/omap2/
 F:     Documentation/arm/omap/dss.rst
+F:     drivers/video/fbdev/omap2/
 
 OMAP FRAMEBUFFER SUPPORT
 L:     linux-fbdev@vger.kernel.org
@@ -12202,8 +12226,8 @@ M:      Roger Quadros <rogerq@ti.com>
 M:     Tony Lindgren <tony@atomide.com>
 L:     linux-omap@vger.kernel.org
 S:     Maintained
-F:     drivers/memory/omap-gpmc.c
 F:     arch/arm/mach-omap2/*gpmc*
+F:     drivers/memory/omap-gpmc.c
 
 OMAP GPIO DRIVER
 M:     Grygorii Strashko <grygorii.strashko@ti.com>
@@ -12290,8 +12314,8 @@ OMAP USB SUPPORT
 L:     linux-usb@vger.kernel.org
 L:     linux-omap@vger.kernel.org
 S:     Orphan
-F:     drivers/usb/*/*omap*
 F:     arch/arm/*omap*/usb*
+F:     drivers/usb/*/*omap*
 
 OMAP/NEWFLOW NANOBONE MACHINE SUPPORT
 M:     Mark Jackson <mpfj@newflow.co.uk>
@@ -12303,27 +12327,27 @@ OMAP1 SUPPORT
 M:     Aaro Koskinen <aaro.koskinen@iki.fi>
 M:     Tony Lindgren <tony@atomide.com>
 L:     linux-omap@vger.kernel.org
+S:     Maintained
 Q:     http://patchwork.kernel.org/project/linux-omap/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git
-S:     Maintained
+F:     arch/arm/configs/omap1_defconfig
 F:     arch/arm/mach-omap1/
 F:     arch/arm/plat-omap/
-F:     arch/arm/configs/omap1_defconfig
 F:     drivers/i2c/busses/i2c-omap.c
-F:     include/linux/platform_data/i2c-omap.h
 F:     include/linux/platform_data/ams-delta-fiq.h
+F:     include/linux/platform_data/i2c-omap.h
 
 OMAP2+ SUPPORT
 M:     Tony Lindgren <tony@atomide.com>
 L:     linux-omap@vger.kernel.org
+S:     Maintained
 W:     http://www.muru.com/linux/omap/
 W:     http://linux.omap.com/
 Q:     http://patchwork.kernel.org/project/linux-omap/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git
-S:     Maintained
+F:     arch/arm/configs/omap2plus_defconfig
 F:     arch/arm/mach-omap2/
 F:     arch/arm/plat-omap/
-F:     arch/arm/configs/omap2plus_defconfig
 F:     drivers/bus/ti-sysc.c
 F:     drivers/i2c/busses/i2c-omap.c
 F:     drivers/irqchip/irq-omap-intc.c
@@ -12347,12 +12371,6 @@ F:     drivers/regulator/twl6030-regulator.c
 F:     include/linux/platform_data/i2c-omap.h
 F:     include/linux/platform_data/ti-sysc.h
 
-ONION OMEGA2+ BOARD
-M:     Harvey Hunt <harveyhuntnexus@gmail.com>
-L:     linux-mips@vger.kernel.org
-S:     Maintained
-F:     arch/mips/boot/dts/ralink/omega2p.dts
-
 OMFS FILESYSTEM
 M:     Bob Copeland <me@bobcopeland.com>
 L:     linux-karma-devel@lists.sourceforge.net
@@ -12375,108 +12393,108 @@ F:  drivers/char/pcmcia/cm4040_cs.*
 OMNIVISION OV13858 SENSOR DRIVER
 M:     Sakari Ailus <sakari.ailus@linux.intel.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/ov13858.c
 
 OMNIVISION OV2680 SENSOR DRIVER
 M:     Rui Miguel Silva <rmfrfs@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/i2c/ov2680.c
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/ov2680.txt
+F:     drivers/media/i2c/ov2680.c
 
 OMNIVISION OV2685 SENSOR DRIVER
 M:     Shunqian Zheng <zhengsq@rock-chips.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/ov2685.c
 
 OMNIVISION OV5640 SENSOR DRIVER
 M:     Steve Longerbeam <slongerbeam@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/ov5640.c
 
 OMNIVISION OV5647 SENSOR DRIVER
 M:     Luis Oliveira <lolivei@synopsys.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/ov5647.c
 
 OMNIVISION OV5670 SENSOR DRIVER
 M:     Chiranjeevi Rapolu <chiranjeevi.rapolu@intel.com>
 M:     Hyungwoo Yang <hyungwoo.yang@intel.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/ov5670.c
 
 OMNIVISION OV5675 SENSOR DRIVER
 M:     Shawn Tu <shawnx.tu@intel.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/ov5675.c
 
 OMNIVISION OV5695 SENSOR DRIVER
 M:     Shunqian Zheng <zhengsq@rock-chips.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/ov5695.c
 
 OMNIVISION OV7670 SENSOR DRIVER
 M:     Jonathan Corbet <corbet@lwn.net>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/i2c/ov7670.c
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/ov7670.txt
+F:     drivers/media/i2c/ov7670.c
 
 OMNIVISION OV772x SENSOR DRIVER
 M:     Jacopo Mondi <jacopo@jmondi.org>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Odd fixes
+T:     git git://linuxtv.org/media_tree.git
+F:     Documentation/devicetree/bindings/media/i2c/ov772x.txt
 F:     drivers/media/i2c/ov772x.c
 F:     include/media/i2c/ov772x.h
-F:     Documentation/devicetree/bindings/media/i2c/ov772x.txt
 
 OMNIVISION OV7740 SENSOR DRIVER
 M:     Wenyou Yang <wenyou.yang@microchip.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/i2c/ov7740.c
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/ov7740.txt
-
-OMNIVISION OV9640 SENSOR DRIVER
-M:     Petr Cvek <petrcvekcz@gmail.com>
-L:     linux-media@vger.kernel.org
-S:     Maintained
-F:     drivers/media/i2c/ov9640.*
+F:     drivers/media/i2c/ov7740.c
 
 OMNIVISION OV8856 SENSOR DRIVER
 M:     Ben Kao <ben.kao@intel.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/ov8856.c
 
+OMNIVISION OV9640 SENSOR DRIVER
+M:     Petr Cvek <petrcvekcz@gmail.com>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     drivers/media/i2c/ov9640.*
+
 OMNIVISION OV9650 SENSOR DRIVER
 M:     Sakari Ailus <sakari.ailus@linux.intel.com>
 R:     Akinobu Mita <akinobu.mita@gmail.com>
 R:     Sylwester Nawrocki <s.nawrocki@samsung.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/i2c/ov9650.c
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/ov9650.txt
+F:     drivers/media/i2c/ov9650.c
 
 ONENAND FLASH DRIVER
 M:     Kyungmin Park <kyungmin.park@samsung.com>
@@ -12485,6 +12503,12 @@ S:     Maintained
 F:     drivers/mtd/nand/onenand/
 F:     include/linux/mtd/onenand*.h
 
+ONION OMEGA2+ BOARD
+M:     Harvey Hunt <harveyhuntnexus@gmail.com>
+L:     linux-mips@vger.kernel.org
+S:     Maintained
+F:     arch/mips/boot/dts/ralink/omega2p.dts
+
 OP-TEE DRIVER
 M:     Jens Wiklander <jens.wiklander@linaro.org>
 L:     tee-dev@lists.linaro.org
@@ -12519,20 +12543,20 @@ OPEN FIRMWARE AND FLATTENED DEVICE TREE
 M:     Rob Herring <robh+dt@kernel.org>
 M:     Frank Rowand <frowand.list@gmail.com>
 L:     devicetree@vger.kernel.org
+S:     Maintained
 W:     http://www.devicetree.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
-S:     Maintained
+F:     Documentation/ABI/testing/sysfs-firmware-ofw
 F:     drivers/of/
 F:     include/linux/of*.h
 F:     scripts/dtc/
-F:     Documentation/ABI/testing/sysfs-firmware-ofw
 
 OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
 M:     Rob Herring <robh+dt@kernel.org>
 L:     devicetree@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
-Q:     http://patchwork.ozlabs.org/project/devicetree-bindings/list/
 S:     Maintained
+Q:     http://patchwork.ozlabs.org/project/devicetree-bindings/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
 F:     Documentation/devicetree/
 F:     arch/*/boot/dts/
 F:     include/dt-bindings/
@@ -12551,10 +12575,10 @@ OPENRISC ARCHITECTURE
 M:     Jonas Bonn <jonas@southpole.se>
 M:     Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
 M:     Stafford Horne <shorne@gmail.com>
-T:     git git://github.com/openrisc/linux.git
 L:     openrisc@lists.librecores.org
-W:     http://openrisc.io
 S:     Maintained
+W:     http://openrisc.io
+T:     git git://github.com/openrisc/linux.git
 F:     Documentation/devicetree/bindings/openrisc/
 F:     Documentation/openrisc/
 F:     arch/openrisc/
@@ -12565,10 +12589,10 @@ OPENVSWITCH
 M:     Pravin B Shelar <pshelar@ovn.org>
 L:     netdev@vger.kernel.org
 L:     dev@openvswitch.org
-W:     http://openvswitch.org
 S:     Maintained
-F:     net/openvswitch/
+W:     http://openvswitch.org
 F:     include/uapi/linux/openvswitch.h
+F:     net/openvswitch/
 
 OPERATING PERFORMANCE POINTS (OPP)
 M:     Viresh Kumar <vireshk@kernel.org>
@@ -12577,16 +12601,16 @@ M:    Stephen Boyd <sboyd@kernel.org>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git
+F:     Documentation/devicetree/bindings/opp/
+F:     Documentation/power/opp.rst
 F:     drivers/opp/
 F:     include/linux/pm_opp.h
-F:     Documentation/power/opp.rst
-F:     Documentation/devicetree/bindings/opp/
 
 OPL4 DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 F:     sound/drivers/opl4/
 
 OPROFILE
@@ -12603,76 +12627,76 @@ M:    Mark Fasheh <mark@fasheh.com>
 M:     Joel Becker <jlbec@evilplan.org>
 M:     Joseph Qi <joseph.qi@linux.alibaba.com>
 L:     ocfs2-devel@oss.oracle.com (moderated for non-subscribers)
-W:     http://ocfs2.wiki.kernel.org
 S:     Supported
-F:     Documentation/filesystems/ocfs2.rst
+W:     http://ocfs2.wiki.kernel.org
 F:     Documentation/filesystems/dlmfs.rst
+F:     Documentation/filesystems/ocfs2.rst
 F:     fs/ocfs2/
 
 ORANGEFS FILESYSTEM
 M:     Mike Marshall <hubcap@omnibond.com>
 R:     Martin Brandenburg <martin@omnibond.com>
 L:     devel@lists.orangefs.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git
 S:     Supported
-F:     fs/orangefs/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git
 F:     Documentation/filesystems/orangefs.rst
+F:     fs/orangefs/
 
 ORINOCO DRIVER
 L:     linux-wireless@vger.kernel.org
+S:     Orphan
 W:     http://wireless.kernel.org/en/users/Drivers/orinoco
 W:     http://www.nongnu.org/orinoco/
-S:     Orphan
 F:     drivers/net/wireless/intersil/orinoco/
 
 OV2659 OMNIVISION SENSOR DRIVER
 M:     "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
-S:     Maintained
 F:     drivers/media/i2c/ov2659.c
 F:     include/media/i2c/ov2659.h
 
 OVERLAY FILESYSTEM
 M:     Miklos Szeredi <miklos@szeredi.hu>
 L:     linux-unionfs@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git
 S:     Supported
-F:     fs/overlayfs/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git
 F:     Documentation/filesystems/overlayfs.rst
+F:     fs/overlayfs/
 
 P54 WIRELESS DRIVER
 M:     Christian Lamparter <chunkeey@googlemail.com>
 L:     linux-wireless@vger.kernel.org
-W:     http://wireless.kernel.org/en/users/Drivers/p54
 S:     Maintained
+W:     http://wireless.kernel.org/en/users/Drivers/p54
 F:     drivers/net/wireless/intersil/p54/
 
 PACKING
 M:     Vladimir Oltean <olteanv@gmail.com>
 L:     netdev@vger.kernel.org
 S:     Supported
-F:     lib/packing.c
-F:     include/linux/packing.h
 F:     Documentation/core-api/packing.rst
+F:     include/linux/packing.h
+F:     lib/packing.c
 
 PADATA PARALLEL EXECUTION MECHANISM
 M:     Steffen Klassert <steffen.klassert@secunet.com>
 L:     linux-crypto@vger.kernel.org
 S:     Maintained
-F:     kernel/padata.c
-F:     include/linux/padata.h
 F:     Documentation/core-api/padata.rst
+F:     include/linux/padata.h
+F:     kernel/padata.c
 
 PAGE POOL
 M:     Jesper Dangaard Brouer <hawk@kernel.org>
 M:     Ilias Apalodimas <ilias.apalodimas@linaro.org>
 L:     netdev@vger.kernel.org
 S:     Supported
-F:     net/core/page_pool.c
 F:     include/net/page_pool.h
+F:     net/core/page_pool.c
 
 PANASONIC LAPTOP ACPI EXTRAS DRIVER
 M:     Harald Welte <laforge@gnumonks.org>
@@ -12699,11 +12723,11 @@ M:    Sudip Mukherjee <sudipm.mukherjee@gmail.com>
 M:     Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
 L:     linux-parport@lists.infradead.org (subscribers-only)
 S:     Maintained
+F:     Documentation/driver-api/parport*.rst
+F:     drivers/char/ppdev.c
 F:     drivers/parport/
 F:     include/linux/parport*.h
-F:     drivers/char/ppdev.c
 F:     include/uapi/linux/ppdev.h
-F:     Documentation/driver-api/parport*.rst
 
 PARAVIRT_OPS INTERFACE
 M:     Juergen Gross <jgross@suse.com>
@@ -12712,8 +12736,8 @@ M:      "VMware, Inc." <pv-drivers@vmware.com>
 L:     virtualization@lists.linux-foundation.org
 S:     Supported
 F:     Documentation/virt/paravirt_ops.rst
-F:     arch/*/kernel/paravirt*
 F:     arch/*/include/asm/paravirt*.h
+F:     arch/*/kernel/paravirt*
 F:     include/linux/hypervisor.h
 
 PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES
@@ -12727,22 +12751,22 @@ PARISC ARCHITECTURE
 M:     "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
 M:     Helge Deller <deller@gmx.de>
 L:     linux-parisc@vger.kernel.org
+S:     Maintained
 W:     http://www.parisc-linux.org/
 Q:     http://patchwork.kernel.org/project/linux-parisc/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/parisc-2.6.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git
-S:     Maintained
-F:     arch/parisc/
 F:     Documentation/parisc/
-F:     drivers/parisc/
+F:     arch/parisc/
 F:     drivers/char/agp/parisc-agp.c
 F:     drivers/input/misc/hp_sdc_rtc.c
 F:     drivers/input/serio/gscps2.c
 F:     drivers/input/serio/hp_sdc*
+F:     drivers/parisc/
 F:     drivers/parport/parport_gsc.*
 F:     drivers/tty/serial/8250/8250_gsc.c
-F:     drivers/video/fbdev/sti*
 F:     drivers/video/console/sti*
+F:     drivers/video/fbdev/sti*
 F:     drivers/video/logo/logo_parisc*
 F:     include/linux/hp_sdc.h
 
@@ -12750,9 +12774,9 @@ PARMAN
 M:     Jiri Pirko <jiri@mellanox.com>
 L:     netdev@vger.kernel.org
 S:     Supported
+F:     include/linux/parman.h
 F:     lib/parman.c
 F:     lib/test_parman.c
-F:     include/linux/parman.h
 
 PC ENGINES APU BOARD DRIVER
 M:     Enrico Weigelt, metux IT consult <info@metux.net>
@@ -12852,14 +12876,6 @@ L:     linux-arm-kernel@lists.infradead.org
 S:     Maintained
 F:     drivers/pci/controller/dwc/*layerscape*
 
-PCI DRIVER FOR NXP LAYERSCAPE GEN4 CONTROLLER
-M:     Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
-L:     linux-pci@vger.kernel.org
-L:     linux-arm-kernel@lists.infradead.org
-S:     Maintained
-F:     Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
-F:     drivers/pci/controller/mobibeil/pcie-layerscape-gen4.c
-
 PCI DRIVER FOR GENERIC OF HOSTS
 M:     Will Deacon <will@kernel.org>
 L:     linux-pci@vger.kernel.org
@@ -12889,12 +12905,12 @@ M:    Kurt Schwemmer <kurt.schwemmer@microsemi.com>
 M:     Logan Gunthorpe <logang@deltatee.com>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
-F:     Documentation/driver-api/switchtec.rst
 F:     Documentation/ABI/testing/sysfs-class-switchtec
+F:     Documentation/driver-api/switchtec.rst
+F:     drivers/ntb/hw/mscc/
 F:     drivers/pci/switch/switchtec*
-F:     include/uapi/linux/switchtec_ioctl.h
 F:     include/linux/switchtec.h
-F:     drivers/ntb/hw/mscc/
+F:     include/uapi/linux/switchtec_ioctl.h
 
 PCI DRIVER FOR MOBIVEIL PCIE IP
 M:     Karthikeyan Mitran <m.karthikeyan@mobiveil.co.in>
@@ -12920,6 +12936,14 @@ S:     Supported
 F:     Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
 F:     drivers/pci/controller/pci-tegra.c
 
+PCI DRIVER FOR NXP LAYERSCAPE GEN4 CONTROLLER
+M:     Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+L:     linux-pci@vger.kernel.org
+L:     linux-arm-kernel@lists.infradead.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
+F:     drivers/pci/controller/mobibeil/pcie-layerscape-gen4.c
+
 PCI DRIVER FOR RENESAS R-CAR
 M:     Marek Vasut <marek.vasut+renesas@gmail.com>
 M:     Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
@@ -12959,14 +12983,21 @@ L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     drivers/pci/controller/dwc/pci-keystone.c
 
+PCI DRIVER FOR V3 SEMICONDUCTOR V360EPC
+M:     Linus Walleij <linus.walleij@linaro.org>
+L:     linux-pci@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/pci/v3-v360epc-pci.txt
+F:     drivers/pci/controller/pci-v3-semi.c
+
 PCI ENDPOINT SUBSYSTEM
 M:     Kishon Vijay Abraham I <kishon@ti.com>
 M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
 L:     linux-pci@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/pci-endpoint.git
 S:     Supported
-F:     drivers/pci/endpoint/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/pci-endpoint.git
 F:     drivers/misc/pci_endpoint_test.c
+F:     drivers/pci/endpoint/
 F:     tools/pci/
 
 PCI ENHANCED ERROR HANDLING (EEH) FOR POWERPC
@@ -12976,13 +13007,13 @@ M:    Oliver O'Halloran <oohall@gmail.com>
 L:     linuxppc-dev@lists.ozlabs.org
 S:     Supported
 F:     Documentation/PCI/pci-error-recovery.rst
-F:     drivers/pci/pcie/aer.c
-F:     drivers/pci/pcie/dpc.c
-F:     drivers/pci/pcie/err.c
 F:     Documentation/powerpc/eeh-pci-error-recovery.rst
+F:     arch/powerpc/include/*/eeh*.h
 F:     arch/powerpc/kernel/eeh*.c
 F:     arch/powerpc/platforms/*/eeh*.c
-F:     arch/powerpc/include/*/eeh*.h
+F:     drivers/pci/pcie/aer.c
+F:     drivers/pci/pcie/dpc.c
+F:     drivers/pci/pcie/err.c
 
 PCI ERROR RECOVERY
 M:     Linas Vepstas <linasvepstas@gmail.com>
@@ -13006,33 +13037,33 @@ S:    Maintained
 F:     Documentation/devicetree/bindings/pci/xgene-pci-msi.txt
 F:     drivers/pci/controller/pci-xgene-msi.c
 
+PCI NATIVE HOST BRIDGE AND ENDPOINT DRIVERS
+M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+R:     Andrew Murray <amurray@thegoodpenguin.co.uk>
+L:     linux-pci@vger.kernel.org
+S:     Supported
+Q:     http://patchwork.ozlabs.org/project/linux-pci/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git/
+F:     drivers/pci/controller/
+
 PCI SUBSYSTEM
 M:     Bjorn Helgaas <bhelgaas@google.com>
 L:     linux-pci@vger.kernel.org
+S:     Supported
 Q:     http://patchwork.ozlabs.org/project/linux-pci/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
-S:     Supported
-F:     Documentation/devicetree/bindings/pci/
 F:     Documentation/PCI/
+F:     Documentation/devicetree/bindings/pci/
+F:     arch/x86/kernel/early-quirks.c
+F:     arch/x86/kernel/quirks.c
+F:     arch/x86/pci/
 F:     drivers/acpi/pci*
 F:     drivers/pci/
 F:     include/asm-generic/pci*
-F:     include/linux/pci*
 F:     include/linux/of_pci.h
+F:     include/linux/pci*
 F:     include/uapi/linux/pci*
 F:     lib/pci*
-F:     arch/x86/pci/
-F:     arch/x86/kernel/quirks.c
-F:     arch/x86/kernel/early-quirks.c
-
-PCI NATIVE HOST BRIDGE AND ENDPOINT DRIVERS
-M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
-R:     Andrew Murray <amurray@thegoodpenguin.co.uk>
-L:     linux-pci@vger.kernel.org
-Q:     http://patchwork.ozlabs.org/project/linux-pci/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git/
-S:     Supported
-F:     drivers/pci/controller/
 
 PCIE DRIVER FOR AMAZON ANNAPURNA LABS
 M:     Jonathan Chocron <jonnyc@amazon.com>
@@ -13108,13 +13139,6 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/pci/rockchip-pcie*
 F:     drivers/pci/controller/pcie-rockchip*
 
-PCI DRIVER FOR V3 SEMICONDUCTOR V360EPC
-M:     Linus Walleij <linus.walleij@linaro.org>
-L:     linux-pci@vger.kernel.org
-S:     Maintained
-F:     Documentation/devicetree/bindings/pci/v3-v360epc-pci.txt
-F:     drivers/pci/controller/pci-v3-semi.c
-
 PCIE DRIVER FOR SOCIONEXT UNIPHIER
 M:     Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
 L:     linux-pci@vger.kernel.org
@@ -13130,12 +13154,12 @@ F:    drivers/pci/controller/dwc/*spear*
 
 PCMCIA SUBSYSTEM
 M:     Dominik Brodowski <linux@dominikbrodowski.net>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia.git
 S:     Odd Fixes
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia.git
 F:     Documentation/pcmcia/
-F:     tools/pcmcia/
 F:     drivers/pcmcia/
 F:     include/pcmcia/
+F:     tools/pcmcia/
 
 PCNET32 NETWORK DRIVER
 M:     Don Fry <pcnet32@frontier.com>
@@ -13168,11 +13192,11 @@ PER-CPU MEMORY ALLOCATOR
 M:     Dennis Zhou <dennis@kernel.org>
 M:     Tejun Heo <tj@kernel.org>
 M:     Christoph Lameter <cl@linux.com>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dennis/percpu.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dennis/percpu.git
+F:     arch/*/include/asm/percpu.h
 F:     include/linux/percpu*.h
 F:     mm/percpu*.c
-F:     arch/*/include/asm/percpu.h
 
 PER-TASK DELAY ACCOUNTING
 M:     Balbir Singh <bsingharora@gmail.com>
@@ -13189,18 +13213,18 @@ R:    Alexander Shishkin <alexander.shishkin@linux.intel.com>
 R:     Jiri Olsa <jolsa@redhat.com>
 R:     Namhyung Kim <namhyung@kernel.org>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core
 S:     Supported
-F:     kernel/events/*
-F:     include/linux/perf_event.h
-F:     include/uapi/linux/perf_event.h
-F:     arch/*/kernel/perf_event*.c
-F:     arch/*/kernel/*/perf_event*.c
-F:     arch/*/kernel/*/*/perf_event*.c
-F:     arch/*/include/asm/perf_event.h
-F:     arch/*/kernel/perf_callchain.c
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core
 F:     arch/*/events/*
 F:     arch/*/events/*/*
+F:     arch/*/include/asm/perf_event.h
+F:     arch/*/kernel/*/*/perf_event*.c
+F:     arch/*/kernel/*/perf_event*.c
+F:     arch/*/kernel/perf_callchain.c
+F:     arch/*/kernel/perf_event*.c
+F:     include/linux/perf_event.h
+F:     include/uapi/linux/perf_event.h
+F:     kernel/events/*
 F:     tools/perf/
 
 PERFORMANCE EVENTS SUBSYSTEM ARM64 PMU EVENTS
@@ -13224,12 +13248,6 @@ S:     Maintained
 F:     Documentation/input/devices/pxrc.rst
 F:     drivers/input/joystick/pxrc.c
 
-FLYSKY FSIA6B RC RECEIVER
-M:     Markus Koch <markus@notsyncing.net>
-L:     linux-input@vger.kernel.org
-S:     Maintained
-F:     drivers/input/joystick/fsia6b.c
-
 PHONET PROTOCOL
 M:     Remi Denis-Courmont <courmisch@gmail.com>
 S:     Supported
@@ -13254,8 +13272,8 @@ F:      drivers/hid/hid-picolcd*
 PICOXCELL SUPPORT
 M:     Jamie Iles <jamie@jamieiles.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://github.com/jamieiles/linux-2.6-ji.git
 S:     Supported
+T:     git git://github.com/jamieiles/linux-2.6-ji.git
 F:     arch/arm/boot/dts/picoxcell*
 F:     arch/arm/mach-picoxcell/
 F:     drivers/crypto/picoxcell*
@@ -13266,9 +13284,9 @@ L:      linux-kernel@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git
 F:     samples/pidfd/
-F:     tools/testing/selftests/pidfd/
-F:     tools/testing/selftests/pid_namespace/
 F:     tools/testing/selftests/clone3/
+F:     tools/testing/selftests/pid_namespace/
+F:     tools/testing/selftests/pidfd/
 K:     (?i)pidfd
 K:     (?i)clone3
 K:     \b(clone_args|kernel_clone_args)\b
@@ -13339,8 +13357,8 @@ M:      Sylwester Nawrocki <s.nawrocki@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
 S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git
 Q:     https://patchwork.kernel.org/project/linux-samsung-soc/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git
 F:     Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
 F:     drivers/pinctrl/samsung/
 F:     include/dt-bindings/pinctrl/samsung.h
@@ -13364,49 +13382,58 @@ PISTACHIO SOC SUPPORT
 M:     James Hartley <james.hartley@sondrel.com>
 L:     linux-mips@vger.kernel.org
 S:     Odd Fixes
-F:     arch/mips/pistachio/
-F:     arch/mips/include/asm/mach-pistachio/
 F:     arch/mips/boot/dts/img/pistachio*
 F:     arch/mips/configs/pistachio*_defconfig
+F:     arch/mips/include/asm/mach-pistachio/
+F:     arch/mips/pistachio/
 
 PKTCDVD DRIVER
-S:     Orphan
 M:     linux-block@vger.kernel.org
+S:     Orphan
 F:     drivers/block/pktcdvd.c
 F:     include/linux/pktcdvd.h
 F:     include/uapi/linux/pktcdvd.h
 
 PKUNITY SOC DRIVERS
 M:     Guan Xuetao <gxt@pku.edu.cn>
-W:     http://mprc.pku.edu.cn/~guanxuetao/linux
 S:     Maintained
+W:     http://mprc.pku.edu.cn/~guanxuetao/linux
 T:     git git://github.com/gxt/linux.git
-F:     drivers/input/serio/i8042-unicore32io.h
 F:     drivers/i2c/busses/i2c-puv3.c
-F:     drivers/video/fbdev/fb-puv3.c
+F:     drivers/input/serio/i8042-unicore32io.h
 F:     drivers/rtc/rtc-puv3.c
+F:     drivers/video/fbdev/fb-puv3.c
 
 PLANTOWER PMS7003 AIR POLLUTION SENSOR DRIVER
 M:     Tomasz Duszynski <tduszyns@gmail.com>
 S:     Maintained
-F:     drivers/iio/chemical/pms7003.c
 F:     Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml
+F:     drivers/iio/chemical/pms7003.c
 
 PLX DMA DRIVER
 M:     Logan Gunthorpe <logang@deltatee.com>
 S:     Maintained
 F:     drivers/dma/plx_dma.c
 
+PM-GRAPH UTILITY
+M:     "Todd E Brandt" <todd.e.brandt@linux.intel.com>
+L:     linux-pm@vger.kernel.org
+S:     Supported
+W:     https://01.org/pm-graph
+B:     https://bugzilla.kernel.org/buglist.cgi?component=pm-graph&product=Tools
+T:     git git://github.com/intel/pm-graph
+F:     tools/power/pm-graph
+
 PMBUS HARDWARE MONITORING DRIVERS
 M:     Guenter Roeck <linux@roeck-us.net>
 L:     linux-hwmon@vger.kernel.org
+S:     Maintained
 W:     http://hwmon.wiki.kernel.org/
 W:     http://www.roeck-us.net/linux/drivers/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
-S:     Maintained
 F:     Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt
-F:     Documentation/devicetree/bindings/hwmon/max31785.txt
 F:     Documentation/devicetree/bindings/hwmon/ltc2978.txt
+F:     Documentation/devicetree/bindings/hwmon/max31785.txt
 F:     Documentation/hwmon/adm1275.rst
 F:     Documentation/hwmon/ibm-cffps.rst
 F:     Documentation/hwmon/ir35221.rst
@@ -13418,8 +13445,8 @@ F:      Documentation/hwmon/max20751.rst
 F:     Documentation/hwmon/max31785.rst
 F:     Documentation/hwmon/max34440.rst
 F:     Documentation/hwmon/max8688.rst
-F:     Documentation/hwmon/pmbus.rst
 F:     Documentation/hwmon/pmbus-core.rst
+F:     Documentation/hwmon/pmbus.rst
 F:     Documentation/hwmon/tps40422.rst
 F:     Documentation/hwmon/ucd9000.rst
 F:     Documentation/hwmon/ucd9200.rst
@@ -13429,8 +13456,8 @@ F:      include/linux/pmbus.h
 
 PMC SIERRA MaxRAID DRIVER
 L:     linux-scsi@vger.kernel.org
-W:     http://www.pmc-sierra.com/
 S:     Orphan
+W:     http://www.pmc-sierra.com/
 F:     drivers/scsi/pmcraid.*
 
 PMC SIERRA PM8001 DRIVER
@@ -13439,52 +13466,43 @@ L:    linux-scsi@vger.kernel.org
 S:     Supported
 F:     drivers/scsi/pm8001/
 
-PM-GRAPH UTILITY
-M:     "Todd E Brandt" <todd.e.brandt@linux.intel.com>
-L:     linux-pm@vger.kernel.org
-W:     https://01.org/pm-graph
-B:     https://bugzilla.kernel.org/buglist.cgi?component=pm-graph&product=Tools
-T:     git git://github.com/intel/pm-graph
-S:     Supported
-F:     tools/power/pm-graph
-
 PNI RM3100 IIO DRIVER
 M:     Song Qiang <songqiang1304521@gmail.com>
 L:     linux-iio@vger.kernel.org
 S:     Maintained
-F:     drivers/iio/magnetometer/rm3100*
 F:     Documentation/devicetree/bindings/iio/magnetometer/pni,rm3100.txt
+F:     drivers/iio/magnetometer/rm3100*
 
 PNP SUPPORT
 M:     "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
 L:     linux-acpi@vger.kernel.org
 S:     Maintained
-F:     include/linux/pnp.h
 F:     drivers/pnp/
+F:     include/linux/pnp.h
 
 POSIX CLOCKS and TIMERS
 M:     Thomas Gleixner <tglx@linutronix.de>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 F:     fs/timerfd.c
-F:     include/linux/timer*
 F:     include/linux/time_namespace.h
-F:     kernel/time/namespace.c
+F:     include/linux/timer*
 F:     kernel/time/*timer*
+F:     kernel/time/namespace.c
 
 POWER MANAGEMENT CORE
 M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
 L:     linux-pm@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
-B:     https://bugzilla.kernel.org
 S:     Supported
+B:     https://bugzilla.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
 F:     drivers/base/power/
+F:     drivers/powercap/
+F:     include/linux/intel_rapl.h
 F:     include/linux/pm.h
 F:     include/linux/pm_*
 F:     include/linux/powercap.h
-F:     include/linux/intel_rapl.h
-F:     drivers/powercap/
 F:     kernel/configs/nopm.config
 
 POWER STATE COORDINATION INTERFACE (PSCI)
@@ -13499,12 +13517,12 @@ F:    include/uapi/linux/psci.h
 POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
 M:     Sebastian Reichel <sre@kernel.org>
 L:     linux-pm@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git
 F:     Documentation/ABI/testing/sysfs-class-power
 F:     Documentation/devicetree/bindings/power/supply/
-F:     include/linux/power_supply.h
 F:     drivers/power/supply/
+F:     include/linux/power_supply.h
 
 POWERNV OPERATOR PANEL LCD DISPLAY DRIVER
 M:     Suraj Jitindar Singh <sjitindarsingh@gmail.com>
@@ -13515,8 +13533,8 @@ F:      drivers/char/powernv-op-panel.c
 PPP OVER ATM (RFC 2364)
 M:     Mitchell Blank Jr <mitch@sfgoth.com>
 S:     Maintained
-F:     net/atm/pppoatm.c
 F:     include/uapi/linux/atmppp.h
+F:     net/atm/pppoatm.c
 
 PPP OVER ETHERNET
 M:     Michal Ostrowski <mostrows@earthlink.net>
@@ -13527,9 +13545,9 @@ F:      drivers/net/ppp/pppox.c
 PPP OVER L2TP
 M:     James Chapman <jchapman@katalix.com>
 S:     Maintained
-F:     net/l2tp/l2tp_ppp.c
 F:     include/linux/if_pppol2tp.h
 F:     include/uapi/linux/if_pppol2tp.h
+F:     net/l2tp/l2tp_ppp.c
 
 PPP PROTOCOL DRIVERS AND COMPRESSORS
 M:     Paul Mackerras <paulus@samba.org>
@@ -13539,12 +13557,12 @@ F:    drivers/net/ppp/ppp_*
 
 PPS SUPPORT
 M:     Rodolfo Giometti <giometti@enneenne.com>
-W:     http://wiki.enneenne.com/index.php/LinuxPPS_support
 L:     linuxpps@ml.enneenne.com (subscribers-only)
 S:     Maintained
-F:     Documentation/driver-api/pps.rst
-F:     Documentation/devicetree/bindings/pps/pps-gpio.txt
+W:     http://wiki.enneenne.com/index.php/LinuxPPS_support
 F:     Documentation/ABI/testing/sysfs-pps
+F:     Documentation/devicetree/bindings/pps/pps-gpio.txt
+F:     Documentation/driver-api/pps.rst
 F:     drivers/pps/
 F:     include/linux/pps*.h
 F:     include/uapi/linux/pps.h
@@ -13553,22 +13571,28 @@ PPTP DRIVER
 M:     Dmitry Kozlov <xeb@mail.ru>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/ppp/pptp.c
 W:     http://sourceforge.net/projects/accel-pptp
+F:     drivers/net/ppp/pptp.c
+
+PRESSURE STALL INFORMATION (PSI)
+M:     Johannes Weiner <hannes@cmpxchg.org>
+S:     Maintained
+F:     include/linux/psi*
+F:     kernel/sched/psi.c
 
 PRINTK
 M:     Petr Mladek <pmladek@suse.com>
 M:     Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
 R:     Steven Rostedt <rostedt@goodmis.org>
 S:     Maintained
-F:     kernel/printk/
 F:     include/linux/printk.h
+F:     kernel/printk/
 
 PRISM54 WIRELESS DRIVER
 M:     Luis Chamberlain <mcgrof@kernel.org>
 L:     linux-wireless@vger.kernel.org
-W:     http://wireless.kernel.org/en/users/Drivers/p54
 S:     Obsolete
+W:     http://wireless.kernel.org/en/users/Drivers/p54
 F:     drivers/net/wireless/intersil/prism54/
 
 PROC FILESYSTEM
@@ -13576,10 +13600,10 @@ R:    Alexey Dobriyan <adobriyan@gmail.com>
 L:     linux-kernel@vger.kernel.org
 L:     linux-fsdevel@vger.kernel.org
 S:     Maintained
+F:     Documentation/filesystems/proc.rst
 F:     fs/proc/
 F:     include/linux/proc_fs.h
 F:     tools/testing/selftests/proc/
-F:     Documentation/filesystems/proc.rst
 
 PROC SYSCTL
 M:     Luis Chamberlain <mcgrof@kernel.org>
@@ -13590,8 +13614,8 @@ L:      linux-fsdevel@vger.kernel.org
 S:     Maintained
 F:     fs/proc/proc_sysctl.c
 F:     include/linux/sysctl.h
-F:     kernel/sysctl.c
 F:     kernel/sysctl-test.c
+F:     kernel/sysctl.c
 F:     tools/testing/selftests/sysctl/
 
 PS3 NETWORK SUPPORT
@@ -13625,15 +13649,9 @@ F:     drivers/block/ps3vram.c
 PSAMPLE PACKET SAMPLING SUPPORT
 M:     Yotam Gigi <yotam.gi@gmail.com>
 S:     Maintained
-F:     net/psample
 F:     include/net/psample.h
 F:     include/uapi/linux/psample.h
-
-PRESSURE STALL INFORMATION (PSI)
-M:     Johannes Weiner <hannes@cmpxchg.org>
-S:     Maintained
-F:     kernel/sched/psi.c
-F:     include/linux/psi*
+F:     net/psample
 
 PSTORE FILESYSTEM
 M:     Kees Cook <keescook@chromium.org>
@@ -13642,12 +13660,12 @@ M:    Colin Cross <ccross@android.com>
 M:     Tony Luck <tony.luck@intel.com>
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/pstore
-F:     fs/pstore/
-F:     include/linux/pstore*
-F:     drivers/firmware/efi/efi-pstore.c
-F:     drivers/acpi/apei/erst.c
 F:     Documentation/admin-guide/ramoops.rst
 F:     Documentation/devicetree/bindings/reserved-memory/ramoops.txt
+F:     drivers/acpi/apei/erst.c
+F:     drivers/firmware/efi/efi-pstore.c
+F:     fs/pstore/
+F:     include/linux/pstore*
 K:     \b(pstore|ramoops)
 
 PTP HARDWARE CLOCK SUPPORT
@@ -13664,6 +13682,9 @@ F:      include/linux/ptp_cl*
 PTRACE SUPPORT
 M:     Oleg Nesterov <oleg@redhat.com>
 S:     Maintained
+F:     arch/*/*/ptrace*.c
+F:     arch/*/include/asm/ptrace*.h
+F:     arch/*/ptrace*.c
 F:     include/asm-generic/syscall.h
 F:     include/linux/ptrace.h
 F:     include/linux/regset.h
@@ -13671,33 +13692,30 @@ F:    include/linux/tracehook.h
 F:     include/uapi/linux/ptrace.h
 F:     include/uapi/linux/ptrace.h
 F:     kernel/ptrace.c
-F:     arch/*/ptrace*.c
-F:     arch/*/*/ptrace*.c
-F:     arch/*/include/asm/ptrace*.h
 
 PULSE8-CEC DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/usb/pulse8-cec/*
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/media/cec-drivers/pulse8-cec.rst
+F:     drivers/media/usb/pulse8-cec/*
 
 PVRUSB2 VIDEO4LINUX DRIVER
 M:     Mike Isely <isely@pobox.com>
 L:     pvrusb2@isely.net       (subscribers-only)
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     http://www.isely.net/pvrusb2/
 T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
 F:     Documentation/media/v4l-drivers/pvrusb2*
 F:     drivers/media/usb/pvrusb2/
 
 PWC WEBCAM DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Odd Fixes
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/usb/pwc/*
 F:     include/trace/events/pwc.h
 
@@ -13721,16 +13739,16 @@ M:    Thierry Reding <thierry.reding@gmail.com>
 R:     Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
 L:     linux-pwm@vger.kernel.org
 S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm.git
 Q:     https://patchwork.ozlabs.org/project/linux-pwm/list/
-F:     Documentation/driver-api/pwm.rst
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm.git
+F:     Documentation/devicetree/bindings/gpio/gpio-mvebu.txt
 F:     Documentation/devicetree/bindings/pwm/
-F:     include/linux/pwm.h
+F:     Documentation/driver-api/pwm.rst
+F:     drivers/gpio/gpio-mvebu.c
 F:     drivers/pwm/
 F:     drivers/video/backlight/pwm_bl.c
+F:     include/linux/pwm.h
 F:     include/linux/pwm_backlight.h
-F:     drivers/gpio/gpio-mvebu.c
-F:     Documentation/devicetree/bindings/gpio/gpio-mvebu.txt
 K:     pwm_(config|apply_state|ops)
 
 PXA GPIO DRIVER
@@ -13752,9 +13770,9 @@ M:      Daniel Mack <daniel@zonque.org>
 M:     Haojian Zhuang <haojian.zhuang@gmail.com>
 M:     Robert Jarzmik <robert.jarzmik@free.fr>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
 T:     git git://github.com/hzhuang1/linux.git
 T:     git git://github.com/rjarzmik/linux.git
-S:     Maintained
 F:     arch/arm/boot/dts/pxa*
 F:     arch/arm/mach-pxa/
 F:     drivers/dma/pxa*
@@ -13818,8 +13836,8 @@ M:      GR-everest-linux-l2@marvell.com
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/qlogic/qed/
-F:     include/linux/qed/
 F:     drivers/net/ethernet/qlogic/qede/
+F:     include/linux/qed/
 
 QLOGIC QL4xxx RDMA DRIVER
 M:     Michal Kalderon <mkalderon@marvell.com>
@@ -13885,8 +13903,8 @@ F:      drivers/media/tuners/qm1d1c0042*
 
 QNX4 FILESYSTEM
 M:     Anders Larsen <al@alarsen.net>
-W:     http://www.alarsen.net/linux/qnx4fs/
 S:     Maintained
+W:     http://www.alarsen.net/linux/qnx4fs/
 F:     fs/qnx4/
 F:     include/uapi/linux/qnx4_fs.h
 F:     include/uapi/linux/qnxtypes.h
@@ -13896,40 +13914,40 @@ M:    Stuart Yoder <stuyoder@gmail.com>
 M:     Laurentiu Tudor <laurentiu.tudor@nxp.com>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
-F:     drivers/bus/fsl-mc/
 F:     Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
 F:     Documentation/networking/device_drivers/freescale/dpaa2/overview.rst
+F:     drivers/bus/fsl-mc/
 
 QT1010 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/tuners/qt1010*
 
 QUALCOMM ATHEROS ATH10K WIRELESS DRIVER
 M:     Kalle Valo <kvalo@codeaurora.org>
 L:     ath10k@lists.infradead.org
+S:     Supported
 W:     http://wireless.kernel.org/en/users/Drivers/ath10k
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
-S:     Supported
 F:     drivers/net/wireless/ath/ath10k/
 
 QUALCOMM ATHEROS ATH11K WIRELESS DRIVER
 M:     Kalle Valo <kvalo@codeaurora.org>
 L:     ath11k@lists.infradead.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
 F:     drivers/net/wireless/ath/ath11k/
 
 QUALCOMM ATHEROS ATH9K WIRELESS DRIVER
 M:     QCA ath9k Development <ath9k-devel@qca.qualcomm.com>
 L:     linux-wireless@vger.kernel.org
-W:     http://wireless.kernel.org/en/users/Drivers/ath9k
 S:     Supported
+W:     http://wireless.kernel.org/en/users/Drivers/ath9k
 F:     drivers/net/wireless/ath/ath9k/
 
 QUALCOMM CAMERA SUBSYSTEM DRIVER
@@ -13940,20 +13958,20 @@ F:    Documentation/devicetree/bindings/media/qcom,camss.txt
 F:     Documentation/media/v4l-drivers/qcom_camss.rst
 F:     drivers/media/platform/qcom/camss/
 
-QUALCOMM CPUFREQ DRIVER MSM8996/APQ8096
-M:     Ilia Lin <ilia.lin@kernel.org>
-L:     linux-pm@vger.kernel.org
-S:     Maintained
-F:     Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt
-F:     drivers/cpufreq/qcom-cpufreq-nvmem.c
-
 QUALCOMM CORE POWER REDUCTION (CPR) AVS DRIVER
 M:     Niklas Cassel <nks@flawful.org>
 L:     linux-pm@vger.kernel.org
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/power/avs/qcom,cpr.txt
-F:     drivers/power/avs/qcom-cpr.c
+F:     Documentation/devicetree/bindings/power/avs/qcom,cpr.txt
+F:     drivers/power/avs/qcom-cpr.c
+
+QUALCOMM CPUFREQ DRIVER MSM8996/APQ8096
+M:     Ilia Lin <ilia.lin@kernel.org>
+L:     linux-pm@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt
+F:     drivers/cpufreq/qcom-cpufreq-nvmem.c
 
 QUALCOMM EMAC GIGABIT ETHERNET DRIVER
 M:     Timur Tabi <timur@kernel.org>
@@ -13965,8 +13983,8 @@ QUALCOMM ETHQOS ETHERNET DRIVER
 M:     Vinod Koul <vkoul@kernel.org>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
 F:     Documentation/devicetree/bindings/net/qcom,ethqos.txt
+F:     drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
 
 QUALCOMM GENERIC INTERFACE I2C DRIVER
 M:     Alok Chauhan <alokc@codeaurora.org>
@@ -14001,8 +14019,8 @@ M:      Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
 M:     Sean Tranchetti <stranche@codeaurora.org>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/ethernet/qualcomm/rmnet/
 F:     Documentation/networking/device_drivers/qualcomm/rmnet.txt
+F:     drivers/net/ethernet/qualcomm/rmnet/
 F:     include/linux/if_rmnet.h
 
 QUALCOMM TSENS THERMAL DRIVER
@@ -14010,24 +14028,24 @@ M:    Amit Kucheria <amit.kucheria@linaro.org>
 L:     linux-pm@vger.kernel.org
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
-F:     drivers/thermal/qcom/
 F:     Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
+F:     drivers/thermal/qcom/
 
 QUALCOMM VENUS VIDEO ACCELERATOR DRIVER
 M:     Stanimir Varbanov <stanimir.varbanov@linaro.org>
 L:     linux-media@vger.kernel.org
 L:     linux-arm-msm@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/platform/qcom/venus/
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/*venus*
+F:     drivers/media/platform/qcom/venus/
 
 QUALCOMM WCN36XX WIRELESS DRIVER
 M:     Kalle Valo <kvalo@codeaurora.org>
 L:     wcn36xx@lists.infradead.org
+S:     Supported
 W:     http://wireless.kernel.org/en/users/Drivers/wcn36xx
 T:     git git://github.com/KrasnikovEugene/wcn36xx.git
-S:     Supported
 F:     drivers/net/wireless/ath/wcn36xx/
 
 QUANTENNA QTNFMAC WIRELESS DRIVER
@@ -14043,12 +14061,12 @@ M:    Alex Deucher <alexander.deucher@amd.com>
 M:     Christian König <christian.koenig@amd.com>
 M:     David (ChunMing) Zhou <David1.Zhou@amd.com>
 L:     amd-gfx@lists.freedesktop.org
-T:     git git://people.freedesktop.org/~agd5f/linux
 S:     Supported
-F:     drivers/gpu/drm/radeon/
-F:     include/uapi/drm/radeon_drm.h
+T:     git git://people.freedesktop.org/~agd5f/linux
 F:     drivers/gpu/drm/amd/
+F:     drivers/gpu/drm/radeon/
 F:     include/uapi/drm/amdgpu_drm.h
+F:     include/uapi/drm/radeon_drm.h
 
 RADEON FRAMEBUFFER DISPLAY DRIVER
 M:     Benjamin Herrenschmidt <benh@kernel.crashing.org>
@@ -14060,15 +14078,15 @@ F:    include/uapi/linux/radeonfb.h
 RADIOSHARK RADIO DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/radio-shark.c
 
 RADIOSHARK2 RADIO DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/radio-shark2.c
 F:     drivers/media/radio/radio-tea5777.c
 
@@ -14077,10 +14095,10 @@ M:    Ilya Dryomov <idryomov@gmail.com>
 M:     Sage Weil <sage@redhat.com>
 R:     Dongsheng Yang <dongsheng.yang@easystack.cn>
 L:     ceph-devel@vger.kernel.org
+S:     Supported
 W:     http://ceph.com/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
 T:     git git://github.com/ceph/ceph-client.git
-S:     Supported
 F:     Documentation/ABI/testing/sysfs-bus-rbd
 F:     drivers/block/rbd.c
 F:     drivers/block/rbd_types.h
@@ -14094,8 +14112,8 @@ F:      drivers/video/fbdev/aty/aty128fb.c
 RAINSHADOW-CEC DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/usb/rainshadow-cec/*
 
 RALINK MIPS ARCHITECTURE
@@ -14121,8 +14139,8 @@ RANCHU VIRTUAL BOARD FOR MIPS
 M:     Miodrag Dinic <miodrag.dinic@mips.com>
 L:     linux-mips@vger.kernel.org
 S:     Supported
-F:     arch/mips/generic/board-ranchu.c
 F:     arch/mips/configs/generic/board-ranchu.config
+F:     arch/mips/generic/board-ranchu.c
 
 RANDOM NUMBER DRIVER
 M:     "Theodore Ts'o" <tytso@mit.edu>
@@ -14140,16 +14158,21 @@ M:    Tony Luck <tony.luck@intel.com>
 M:     Borislav Petkov <bp@alien8.de>
 L:     linux-edac@vger.kernel.org
 S:     Maintained
+F:     Documentation/admin-guide/ras.rst
 F:     drivers/ras/
 F:     include/linux/ras.h
 F:     include/ras/ras_event.h
-F:     Documentation/admin-guide/ras.rst
 
 RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
 L:     linux-wireless@vger.kernel.org
 S:     Orphan
 F:     drivers/net/wireless/ray*
 
+RCMM REMOTE CONTROLS DECODER
+M:     Patrick Lerda <patrick9876@free.fr>
+S:     Maintained
+F:     drivers/media/rc/ir-rcmm-decoder.c
+
 RCUTORTURE TEST FRAMEWORK
 M:     "Paul E. McKenney" <paulmck@kernel.org>
 M:     Josh Triplett <josh@joshtriplett.org>
@@ -14183,19 +14206,19 @@ M:    Santosh Shilimkar <santosh.shilimkar@oracle.com>
 L:     netdev@vger.kernel.org
 L:     linux-rdma@vger.kernel.org
 L:     rds-devel@oss.oracle.com (moderated for non-subscribers)
-W:     https://oss.oracle.com/projects/rds/
 S:     Supported
-F:     net/rds/
+W:     https://oss.oracle.com/projects/rds/
 F:     Documentation/networking/rds.txt
+F:     net/rds/
 
 RDT - RESOURCE ALLOCATION
 M:     Fenghua Yu <fenghua.yu@intel.com>
 M:     Reinette Chatre <reinette.chatre@intel.com>
 L:     linux-kernel@vger.kernel.org
 S:     Supported
-F:     arch/x86/kernel/cpu/resctrl/
-F:     arch/x86/include/asm/resctrl_sched.h
 F:     Documentation/x86/resctrl*
+F:     arch/x86/include/asm/resctrl_sched.h
+F:     arch/x86/kernel/cpu/resctrl/
 F:     tools/testing/selftests/resctrl/
 
 READ-COPY UPDATE (RCU)
@@ -14206,37 +14229,37 @@ R:    Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
 R:     Lai Jiangshan <jiangshanlai@gmail.com>
 R:     Joel Fernandes <joel@joelfernandes.org>
 L:     rcu@vger.kernel.org
-W:     http://www.rdrop.com/users/paulmck/RCU/
 S:     Supported
+W:     http://www.rdrop.com/users/paulmck/RCU/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev
 F:     Documentation/RCU/
-X:     Documentation/RCU/torture.txt
 F:     include/linux/rcu*
-X:     include/linux/srcu*.h
 F:     kernel/rcu/
+X:     Documentation/RCU/torture.txt
+X:     include/linux/srcu*.h
 X:     kernel/rcu/srcu*.c
 
 REAL TIME CLOCK (RTC) SUBSYSTEM
 M:     Alessandro Zummo <a.zummo@towertech.it>
 M:     Alexandre Belloni <alexandre.belloni@bootlin.com>
 L:     linux-rtc@vger.kernel.org
+S:     Maintained
 Q:     http://patchwork.ozlabs.org/project/rtc-linux/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git
-S:     Maintained
-F:     Documentation/devicetree/bindings/rtc/
 F:     Documentation/admin-guide/rtc.rst
+F:     Documentation/devicetree/bindings/rtc/
 F:     drivers/rtc/
+F:     include/linux/platform_data/rtc-*
 F:     include/linux/rtc.h
-F:     include/uapi/linux/rtc.h
 F:     include/linux/rtc/
-F:     include/linux/platform_data/rtc-*
+F:     include/uapi/linux/rtc.h
 F:     tools/testing/selftests/rtc/
 
 REALTEK AUDIO CODECS
 M:     Oder Chiou <oder_chiou@realtek.com>
 S:     Maintained
-F:     sound/soc/codecs/rt*
 F:     include/sound/rt*.h
+F:     sound/soc/codecs/rt*
 
 REALTEK RTL83xx SMI DSA ROUTER CHIPS
 M:     Linus Walleij <linus.walleij@linaro.org>
@@ -14245,6 +14268,20 @@ F:     Documentation/devicetree/bindings/net/dsa/realtek-smi.txt
 F:     drivers/net/dsa/realtek-smi*
 F:     drivers/net/dsa/rtl83*
 
+REALTEK WIRELESS DRIVER (rtlwifi family)
+M:     Ping-Ke Shih <pkshih@realtek.com>
+L:     linux-wireless@vger.kernel.org
+S:     Maintained
+W:     http://wireless.kernel.org/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
+F:     drivers/net/wireless/realtek/rtlwifi/
+
+REALTEK WIRELESS DRIVER (rtw88)
+M:     Yan-Hsuan Chuang <yhchuang@realtek.com>
+L:     linux-wireless@vger.kernel.org
+S:     Maintained
+F:     drivers/net/wireless/realtek/rtw88/
+
 REDPINE WIRELESS DRIVER
 M:     Amitkumar Karwar <amitkarwar@gmail.com>
 M:     Siva Rebbagondla <siva8118@gmail.com>
@@ -14255,8 +14292,8 @@ F:      drivers/net/wireless/rsi/
 REGISTER MAP ABSTRACTION
 M:     Mark Brown <broonie@kernel.org>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git
 F:     Documentation/devicetree/bindings/regmap/
 F:     drivers/base/regmap/
 F:     include/linux/regmap.h
@@ -14270,10 +14307,10 @@ REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM
 M:     Ohad Ben-Cohen <ohad@wizery.com>
 M:     Bjorn Andersson <bjorn.andersson@linaro.org>
 L:     linux-remoteproc@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc.git rproc-next
 S:     Maintained
-F:     Documentation/devicetree/bindings/remoteproc/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc.git rproc-next
 F:     Documentation/ABI/testing/sysfs-class-remoteproc
+F:     Documentation/devicetree/bindings/remoteproc/
 F:     Documentation/remoteproc.txt
 F:     drivers/remoteproc/
 F:     include/linux/remoteproc.h
@@ -14283,11 +14320,11 @@ REMOTE PROCESSOR MESSAGING (RPMSG) SUBSYSTEM
 M:     Ohad Ben-Cohen <ohad@wizery.com>
 M:     Bjorn Andersson <bjorn.andersson@linaro.org>
 L:     linux-remoteproc@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc.git rpmsg-next
 S:     Maintained
-F:     drivers/rpmsg/
-F:     Documentation/rpmsg.txt
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc.git rpmsg-next
 F:     Documentation/ABI/testing/sysfs-bus-rpmsg
+F:     Documentation/rpmsg.txt
+F:     drivers/rpmsg/
 F:     include/linux/rpmsg.h
 F:     include/linux/rpmsg/
 F:     include/uapi/linux/rpmsg.h
@@ -14296,8 +14333,8 @@ F:      samples/rpmsg/
 RENESAS CLOCK DRIVERS
 M:     Geert Uytterhoeven <geert+renesas@glider.be>
 L:     linux-renesas-soc@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git clk-renesas
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git clk-renesas
 F:     drivers/clk/renesas/
 
 RENESAS EMEV2 I2C DRIVER
@@ -14344,14 +14381,14 @@ F:    drivers/phy/renesas/phy-rcar-gen3-usb*.c
 
 RESET CONTROLLER FRAMEWORK
 M:     Philipp Zabel <p.zabel@pengutronix.de>
-T:     git git://git.pengutronix.de/git/pza/linux
 S:     Maintained
-F:     drivers/reset/
+T:     git git://git.pengutronix.de/git/pza/linux
 F:     Documentation/devicetree/bindings/reset/
+F:     drivers/reset/
 F:     include/dt-bindings/reset/
+F:     include/linux/reset-controller.h
 F:     include/linux/reset.h
 F:     include/linux/reset/
-F:     include/linux/reset-controller.h
 K:     \b(?:devm_|of_)?reset_control(?:ler_[a-z]+|_[a-z_]+)?\b
 
 RESTARTABLE SEQUENCES SUPPORT
@@ -14361,33 +14398,33 @@ M:    "Paul E. McKenney" <paulmck@kernel.org>
 M:     Boqun Feng <boqun.feng@gmail.com>
 L:     linux-kernel@vger.kernel.org
 S:     Supported
-F:     kernel/rseq.c
-F:     include/uapi/linux/rseq.h
 F:     include/trace/events/rseq.h
+F:     include/uapi/linux/rseq.h
+F:     kernel/rseq.c
 F:     tools/testing/selftests/rseq/
 
 RFKILL
 M:     Johannes Berg <johannes@sipsolutions.net>
 L:     linux-wireless@vger.kernel.org
+S:     Maintained
 W:     http://wireless.kernel.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
-S:     Maintained
-F:     Documentation/driver-api/rfkill.rst
 F:     Documentation/ABI/stable/sysfs-class-rfkill
-F:     net/rfkill/
+F:     Documentation/driver-api/rfkill.rst
 F:     include/linux/rfkill.h
 F:     include/uapi/linux/rfkill.h
+F:     net/rfkill/
 
 RHASHTABLE
 M:     Thomas Graf <tgraf@suug.ch>
 M:     Herbert Xu <herbert@gondor.apana.org.au>
 L:     netdev@vger.kernel.org
 S:     Maintained
+F:     include/linux/rhashtable-types.h
+F:     include/linux/rhashtable.h
 F:     lib/rhashtable.c
 F:     lib/test_rhashtable.c
-F:     include/linux/rhashtable.h
-F:     include/linux/rhashtable-types.h
 
 RICOH R5C592 MEMORYSTICK DRIVER
 M:     Maxim Levitsky <maximlevitsky@gmail.com>
@@ -14405,20 +14442,20 @@ M:    Paul Walmsley <paul.walmsley@sifive.com>
 M:     Palmer Dabbelt <palmer@dabbelt.com>
 M:     Albert Ou <aou@eecs.berkeley.edu>
 L:     linux-riscv@lists.infradead.org
+S:     Supported
 P:     Documentation/riscv/patch-acceptance.rst
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git
-S:     Supported
 F:     arch/riscv/
-K:     riscv
 N:     riscv
+K:     riscv
 
 ROCCAT DRIVERS
 M:     Stefan Achatz <erazor_de@users.sourceforge.net>
-W:     http://sourceforge.net/projects/roccat/
 S:     Maintained
+W:     http://sourceforge.net/projects/roccat/
+F:     Documentation/ABI/*/sysfs-driver-hid-roccat*
 F:     drivers/hid/hid-roccat*
 F:     include/linux/hid-roccat*
-F:     Documentation/ABI/*/sysfs-driver-hid-roccat*
 
 ROCKCHIP ISP V1 DRIVER
 M:     Helen Koike <helen.koike@collabora.com>
@@ -14431,18 +14468,8 @@ M:     Jacob Chen <jacob-chen@iotwrt.com>
 M:     Ezequiel Garcia <ezequiel@collabora.com>
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     drivers/media/platform/rockchip/rga/
 F:     Documentation/devicetree/bindings/media/rockchip-rga.txt
-
-HANTRO VPU CODEC DRIVER
-M:     Ezequiel Garcia <ezequiel@collabora.com>
-M:     Philipp Zabel <p.zabel@pengutronix.de>
-L:     linux-media@vger.kernel.org
-L:     linux-rockchip@lists.infradead.org
-S:     Maintained
-F:     drivers/staging/media/hantro/
-F:     Documentation/devicetree/bindings/media/nxp,imx8mq-vpu.yaml
-F:     Documentation/devicetree/bindings/media/rockchip-vpu.txt
+F:     drivers/media/platform/rockchip/rga/
 
 ROCKER DRIVER
 M:     Jiri Pirko <jiri@resnulli.us>
@@ -14451,8 +14478,8 @@ S:      Supported
 F:     drivers/net/ethernet/rocker/
 
 ROCKETPORT DRIVER
-W:     http://www.comtrol.com
 S:     Maintained
+W:     http://www.comtrol.com
 F:     Documentation/driver-api/serial/rocket.rst
 F:     drivers/tty/rocket*
 
@@ -14465,25 +14492,25 @@ F:    drivers/tty/serial/rp2.*
 ROHM BH1750 AMBIENT LIGHT SENSOR DRIVER
 M:     Tomasz Duszynski <tduszyns@gmail.com>
 S:     Maintained
-F:     drivers/iio/light/bh1750.c
 F:     Documentation/devicetree/bindings/iio/light/bh1750.yaml
+F:     drivers/iio/light/bh1750.c
 
 ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS
 M:     Marek Vasut <marek.vasut+renesas@gmail.com>
 L:     linux-kernel@vger.kernel.org
 L:     linux-renesas-soc@vger.kernel.org
 S:     Supported
+F:     Documentation/devicetree/bindings/mfd/bd9571mwv.txt
+F:     drivers/gpio/gpio-bd9571mwv.c
 F:     drivers/mfd/bd9571mwv.c
 F:     drivers/regulator/bd9571mwv-regulator.c
-F:     drivers/gpio/gpio-bd9571mwv.c
 F:     include/linux/mfd/bd9571mwv.h
-F:     Documentation/devicetree/bindings/mfd/bd9571mwv.txt
 
 ROSE NETWORK LAYER
 M:     Ralf Baechle <ralf@linux-mips.org>
 L:     linux-hams@vger.kernel.org
-W:     http://www.linux-ax25.org/
 S:     Maintained
+W:     http://www.linux-ax25.org/
 F:     include/net/rose.h
 F:     include/uapi/linux/rose.h
 F:     net/rose/
@@ -14491,46 +14518,46 @@ F:    net/rose/
 ROTATION DRIVER FOR ALLWINNER A83T
 M:     Jernej Skrabec <jernej.skrabec@siol.net>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/platform/sunxi/sun8i-rotate/
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml
+F:     drivers/media/platform/sunxi/sun8i-rotate/
 
 RTL2830 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/dvb-frontends/rtl2830*
 
 RTL2832 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/dvb-frontends/rtl2832*
 
 RTL2832_SDR MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/dvb-frontends/rtl2832_sdr*
 
 RTL8180 WIRELESS DRIVER
 L:     linux-wireless@vger.kernel.org
+S:     Orphan
 W:     http://wireless.kernel.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
-S:     Orphan
 F:     drivers/net/wireless/realtek/rtl818x/rtl8180/
 
 RTL8187 WIRELESS DRIVER
@@ -14538,43 +14565,29 @@ M:    Herton Ronaldo Krzesinski <herton@canonical.com>
 M:     Hin-Tak Leung <htl10@users.sourceforge.net>
 M:     Larry Finger <Larry.Finger@lwfinger.net>
 L:     linux-wireless@vger.kernel.org
-W:     http://wireless.kernel.org/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
 S:     Maintained
-F:     drivers/net/wireless/realtek/rtl818x/rtl8187/
-
-REALTEK WIRELESS DRIVER (rtlwifi family)
-M:     Ping-Ke Shih <pkshih@realtek.com>
-L:     linux-wireless@vger.kernel.org
 W:     http://wireless.kernel.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
-S:     Maintained
-F:     drivers/net/wireless/realtek/rtlwifi/
-
-REALTEK WIRELESS DRIVER (rtw88)
-M:     Yan-Hsuan Chuang <yhchuang@realtek.com>
-L:     linux-wireless@vger.kernel.org
-S:     Maintained
-F:     drivers/net/wireless/realtek/rtw88/
+F:     drivers/net/wireless/realtek/rtl818x/rtl8187/
 
 RTL8XXXU WIRELESS DRIVER (rtl8xxxu)
 M:     Jes Sorensen <Jes.Sorensen@gmail.com>
 L:     linux-wireless@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8xxxu-devel
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8xxxu-devel
 F:     drivers/net/wireless/realtek/rtl8xxxu/
 
 RXRPC SOCKETS (AF_RXRPC)
 M:     David Howells <dhowells@redhat.com>
 L:     linux-afs@lists.infradead.org
 S:     Supported
-F:     net/rxrpc/
+W:     https://www.infradead.org/~dhowells/kafs/
+F:     Documentation/networking/rxrpc.txt
 F:     include/keys/rxrpc-type.h
 F:     include/net/af_rxrpc.h
 F:     include/trace/events/rxrpc.h
 F:     include/uapi/linux/rxrpc.h
-F:     Documentation/networking/rxrpc.txt
-W:     https://www.infradead.org/~dhowells/kafs/
+F:     net/rxrpc/
 
 S3 SAVAGE FRAMEBUFFER DRIVER
 M:     Antonino Daplas <adaplas@gmail.com>
@@ -14587,44 +14600,44 @@ M:    Heiko Carstens <heiko.carstens@de.ibm.com>
 M:     Vasily Gorbik <gor@linux.ibm.com>
 M:     Christian Borntraeger <borntraeger@de.ibm.com>
 L:     linux-s390@vger.kernel.org
+S:     Supported
 W:     http://www.ibm.com/developerworks/linux/linux390/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git
-S:     Supported
+F:     Documentation/driver-api/s390-drivers.rst
+F:     Documentation/s390/
 F:     arch/s390/
 F:     drivers/s390/
-F:     Documentation/s390/
-F:     Documentation/driver-api/s390-drivers.rst
 
 S390 COMMON I/O LAYER
 M:     Vineeth Vijayan <vneethv@linux.ibm.com>
 M:     Peter Oberparleiter <oberpar@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
-W:     http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
+W:     http://www.ibm.com/developerworks/linux/linux390/
 F:     drivers/s390/cio/
 
 S390 DASD DRIVER
 M:     Stefan Haberland <sth@linux.ibm.com>
 M:     Jan Hoeppner <hoeppner@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
-W:     http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
-F:     drivers/s390/block/dasd*
+W:     http://www.ibm.com/developerworks/linux/linux390/
 F:     block/partitions/ibm.c
+F:     drivers/s390/block/dasd*
 
 S390 IOMMU (PCI)
 M:     Gerald Schaefer <gerald.schaefer@de.ibm.com>
 L:     linux-s390@vger.kernel.org
-W:     http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
+W:     http://www.ibm.com/developerworks/linux/linux390/
 F:     drivers/iommu/s390-iommu.c
 
 S390 IUCV NETWORK LAYER
 M:     Julian Wiedmann <jwi@linux.ibm.com>
 M:     Ursula Braun <ubraun@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
-W:     http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
+W:     http://www.ibm.com/developerworks/linux/linux390/
 F:     drivers/s390/net/*iucv*
 F:     include/net/iucv/
 F:     net/iucv/
@@ -14633,19 +14646,31 @@ S390 NETWORK DRIVERS
 M:     Julian Wiedmann <jwi@linux.ibm.com>
 M:     Ursula Braun <ubraun@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
-W:     http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
+W:     http://www.ibm.com/developerworks/linux/linux390/
 F:     drivers/s390/net/
 
 S390 PCI SUBSYSTEM
 M:     Niklas Schnelle <schnelle@linux.ibm.com>
 M:     Gerald Schaefer <gerald.schaefer@de.ibm.com>
 L:     linux-s390@vger.kernel.org
-W:     http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
+W:     http://www.ibm.com/developerworks/linux/linux390/
 F:     arch/s390/pci/
 F:     drivers/pci/hotplug/s390_pci_hpc.c
 
+S390 VFIO AP DRIVER
+M:     Tony Krowiak <akrowiak@linux.ibm.com>
+M:     Pierre Morel <pmorel@linux.ibm.com>
+M:     Halil Pasic <pasic@linux.ibm.com>
+L:     linux-s390@vger.kernel.org
+S:     Supported
+W:     http://www.ibm.com/developerworks/linux/linux390/
+F:     Documentation/s390/vfio-ap.rst
+F:     drivers/s390/crypto/vfio_ap_drv.c
+F:     drivers/s390/crypto/vfio_ap_ops.c
+F:     drivers/s390/crypto/vfio_ap_private.h
+
 S390 VFIO-CCW DRIVER
 M:     Cornelia Huck <cohuck@redhat.com>
 M:     Eric Farman <farman@linux.ibm.com>
@@ -14653,35 +14678,23 @@ R:    Halil Pasic <pasic@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
 L:     kvm@vger.kernel.org
 S:     Supported
-F:     drivers/s390/cio/vfio_ccw*
 F:     Documentation/s390/vfio-ccw.rst
+F:     drivers/s390/cio/vfio_ccw*
 F:     include/uapi/linux/vfio_ccw.h
 
 S390 ZCRYPT DRIVER
 M:     Harald Freudenberger <freude@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
-W:     http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
-F:     drivers/s390/crypto/
-
-S390 VFIO AP DRIVER
-M:     Tony Krowiak <akrowiak@linux.ibm.com>
-M:     Pierre Morel <pmorel@linux.ibm.com>
-M:     Halil Pasic <pasic@linux.ibm.com>
-L:     linux-s390@vger.kernel.org
 W:     http://www.ibm.com/developerworks/linux/linux390/
-S:     Supported
-F:     drivers/s390/crypto/vfio_ap_drv.c
-F:     drivers/s390/crypto/vfio_ap_private.h
-F:     drivers/s390/crypto/vfio_ap_ops.c
-F:     Documentation/s390/vfio-ap.rst
+F:     drivers/s390/crypto/
 
 S390 ZFCP DRIVER
 M:     Steffen Maier <maier@linux.ibm.com>
 M:     Benjamin Block <bblock@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
-W:     http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
+W:     http://www.ibm.com/developerworks/linux/linux390/
 F:     drivers/s390/scsi/zfcp_*
 
 S3C24XX SD/MMC Driver
@@ -14693,25 +14706,25 @@ F:    drivers/mmc/host/s3cmci.*
 SAA6588 RDS RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Odd Fixes
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/saa6588*
 
 SAA7134 VIDEO4LINUX DRIVER
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-media@vger.kernel.org
+S:     Odd fixes
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Odd fixes
 F:     Documentation/media/v4l-drivers/saa7134*
 F:     drivers/media/pci/saa7134/
 
 SAA7146 VIDEO4LINUX-2 DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/common/saa7146/
 F:     drivers/media/pci/saa7146/
 F:     include/media/drv-intf/saa7146*
@@ -14719,8 +14732,8 @@ F:      include/media/drv-intf/saa7146*
 SAFESETID SECURITY MODULE
 M:     Micah Morton <mortonm@chromium.org>
 S:     Supported
-F:     security/safesetid/
 F:     Documentation/admin-guide/LSM/SafeSetID.rst
+F:     security/safesetid/
 
 SAMSUNG AUDIO (ASoC) DRIVERS
 M:     Krzysztof Kozlowski <krzk@kernel.org>
@@ -14728,23 +14741,23 @@ M:    Sangbeom Kim <sbkim73@samsung.com>
 M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
-F:     sound/soc/samsung/
 F:     Documentation/devicetree/bindings/sound/samsung*
+F:     sound/soc/samsung/
 
 SAMSUNG EXYNOS PSEUDO RANDOM NUMBER GENERATOR (RNG) DRIVER
 M:     Krzysztof Kozlowski <krzk@kernel.org>
 L:     linux-crypto@vger.kernel.org
 L:     linux-samsung-soc@vger.kernel.org
 S:     Maintained
-F:     drivers/crypto/exynos-rng.c
 F:     Documentation/devicetree/bindings/rng/samsung,exynos4-rng.yaml
+F:     drivers/crypto/exynos-rng.c
 
 SAMSUNG EXYNOS TRUE RANDOM NUMBER GENERATOR (TRNG) DRIVER
 M:     Łukasz Stelmach <l.stelmach@samsung.com>
 L:     linux-samsung-soc@vger.kernel.org
 S:     Maintained
-F:     drivers/char/hw_random/exynos-trng.c
 F:     Documentation/devicetree/bindings/rng/samsung,exynos5250-trng.txt
+F:     drivers/char/hw_random/exynos-trng.c
 
 SAMSUNG FRAMEBUFFER DRIVER
 M:     Jingoo Han <jingoohan1@gmail.com>
@@ -14765,16 +14778,16 @@ M:    Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
 L:     linux-kernel@vger.kernel.org
 L:     linux-samsung-soc@vger.kernel.org
 S:     Supported
+F:     Documentation/devicetree/bindings/clock/samsung,s2mps11.txt
+F:     Documentation/devicetree/bindings/mfd/samsung,sec-core.txt
+F:     Documentation/devicetree/bindings/regulator/samsung,s2m*.txt
+F:     Documentation/devicetree/bindings/regulator/samsung,s5m*.txt
+F:     drivers/clk/clk-s2mps11.c
 F:     drivers/mfd/sec*.c
 F:     drivers/regulator/s2m*.c
 F:     drivers/regulator/s5m*.c
-F:     drivers/clk/clk-s2mps11.c
 F:     drivers/rtc/rtc-s5m.c
 F:     include/linux/mfd/samsung/
-F:     Documentation/devicetree/bindings/mfd/samsung,sec-core.txt
-F:     Documentation/devicetree/bindings/regulator/samsung,s2m*.txt
-F:     Documentation/devicetree/bindings/regulator/samsung,s5m*.txt
-F:     Documentation/devicetree/bindings/clock/samsung,s2mps11.txt
 
 SAMSUNG S3C24XX/S3C64XX SOC SERIES CAMIF DRIVER
 M:     Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
@@ -14820,22 +14833,22 @@ SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS
 M:     Kyungmin Park <kyungmin.park@samsung.com>
 M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
 L:     linux-media@vger.kernel.org
-Q:     https://patchwork.linuxtv.org/project/linux-media/list/
 S:     Supported
+Q:     https://patchwork.linuxtv.org/project/linux-media/list/
 F:     drivers/media/platform/exynos4-is/
 
 SAMSUNG SOC CLOCK DRIVERS
 M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
 M:     Tomasz Figa <tomasz.figa@gmail.com>
 M:     Chanwoo Choi <cw00.choi@samsung.com>
-S:     Supported
 L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
+S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk.git
-F:     drivers/clk/samsung/
-F:     include/dt-bindings/clock/exynos*.h
 F:     Documentation/devicetree/bindings/clock/exynos*.txt
 F:     Documentation/devicetree/bindings/clock/samsung,s3c*
 F:     Documentation/devicetree/bindings/clock/samsung,s5p*
+F:     drivers/clk/samsung/
+F:     include/dt-bindings/clock/exynos*.h
 
 SAMSUNG SPI DRIVERS
 M:     Kukjin Kim <kgene@kernel.org>
@@ -14850,8 +14863,8 @@ F:      include/linux/platform_data/spi-s3c64xx.h
 
 SAMSUNG SXGBE DRIVERS
 M:     Byungho An <bh74.an@samsung.com>
-S:     Supported
 L:     netdev@vger.kernel.org
+S:     Supported
 F:     drivers/net/ethernet/samsung/sxgbe/
 
 SAMSUNG THERMAL DRIVER
@@ -14891,13 +14904,13 @@ 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)
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched/core
 S:     Maintained
-F:     kernel/sched/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched/core
+F:     include/linux/preempt.h
 F:     include/linux/sched.h
-F:     include/uapi/linux/sched.h
 F:     include/linux/wait.h
-F:     include/linux/preempt.h
+F:     include/uapi/linux/sched.h
+F:     kernel/sched/
 
 SCR24X CHIP CARD INTERFACE DRIVER
 M:     Lubomir Rintel <lkundrak@v3.sk>
@@ -14907,8 +14920,8 @@ F:      drivers/char/pcmcia/scr24x_cs.c
 SCSI CDROM DRIVER
 M:     Jens Axboe <axboe@kernel.dk>
 L:     linux-scsi@vger.kernel.org
-W:     http://www.kernel.dk
 S:     Maintained
+W:     http://www.kernel.dk
 F:     drivers/scsi/sr*
 
 SCSI RDMA PROTOCOL (SRP) INITIATOR
@@ -14930,20 +14943,20 @@ F:    drivers/infiniband/ulp/srpt/
 SCSI SG DRIVER
 M:     Doug Gilbert <dgilbert@interlog.com>
 L:     linux-scsi@vger.kernel.org
-W:     http://sg.danny.cz/sg
 S:     Maintained
+W:     http://sg.danny.cz/sg
 F:     Documentation/scsi/scsi-generic.rst
 F:     drivers/scsi/sg.c
 F:     include/scsi/sg.h
 
 SCSI SUBSYSTEM
 M:     "James E.J. Bottomley" <jejb@linux.ibm.com>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git
 M:     "Martin K. Petersen" <martin.petersen@oracle.com>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git
-Q:     https://patchwork.kernel.org/project/linux-scsi/list/
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
+Q:     https://patchwork.kernel.org/project/linux-scsi/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git
 F:     Documentation/devicetree/bindings/scsi/
 F:     drivers/scsi/
 F:     include/scsi/
@@ -14960,25 +14973,25 @@ SCSI TARGET SUBSYSTEM
 M:     "Martin K. Petersen" <martin.petersen@oracle.com>
 L:     linux-scsi@vger.kernel.org
 L:     target-devel@vger.kernel.org
+S:     Supported
 W:     http://www.linux-iscsi.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git
 Q:     https://patchwork.kernel.org/project/target-devel/list/
-S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git
+F:     Documentation/target/
 F:     drivers/target/
 F:     include/target/
-F:     Documentation/target/
 
 SCTP PROTOCOL
 M:     Vlad Yasevich <vyasevich@gmail.com>
 M:     Neil Horman <nhorman@tuxdriver.com>
 M:     Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
 L:     linux-sctp@vger.kernel.org
-W:     http://lksctp.sourceforge.net
 S:     Maintained
+W:     http://lksctp.sourceforge.net
 F:     Documentation/networking/sctp.txt
 F:     include/linux/sctp.h
-F:     include/uapi/linux/sctp.h
 F:     include/net/sctp/
+F:     include/uapi/linux/sctp.h
 F:     net/sctp/
 
 SCx200 CPU SUPPORT
@@ -14986,9 +14999,9 @@ M:      Jim Cromie <jim.cromie@gmail.com>
 S:     Odd Fixes
 F:     Documentation/i2c/busses/scx200_acb.rst
 F:     arch/x86/platform/scx200/
-F:     drivers/watchdog/scx200_wdt.c
 F:     drivers/i2c/busses/scx200*
 F:     drivers/mtd/maps/scx200_docflash.c
+F:     drivers/watchdog/scx200_wdt.c
 F:     include/linux/scx200.h
 
 SCx200 GPIO DRIVER
@@ -15018,14 +15031,14 @@ SECURE COMPUTING
 M:     Kees Cook <keescook@chromium.org>
 R:     Andy Lutomirski <luto@amacapital.net>
 R:     Will Drewry <wad@chromium.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp
 S:     Supported
-F:     kernel/seccomp.c
-F:     include/uapi/linux/seccomp.h
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp
+F:     Documentation/userspace-api/seccomp_filter.rst
 F:     include/linux/seccomp.h
-F:     tools/testing/selftests/seccomp/*
+F:     include/uapi/linux/seccomp.h
+F:     kernel/seccomp.c
 F:     tools/testing/selftests/kselftest_harness.h
-F:     Documentation/userspace-api/seccomp_filter.rst
+F:     tools/testing/selftests/seccomp/*
 K:     \bsecure_computing
 K:     \bTIF_SECCOMP\b
 
@@ -15043,21 +15056,6 @@ S:     Maintained
 F:     drivers/mmc/host/sdhci*
 F:     include/linux/mmc/sdhci*
 
-EMMC CMDQ HOST CONTROLLER INTERFACE (CQHCI) DRIVER
-M:     Adrian Hunter <adrian.hunter@intel.com>
-M:     Ritesh Harjani <riteshh@codeaurora.org>
-M:     Asutosh Das <asutoshd@codeaurora.org>
-L:     linux-mmc@vger.kernel.org
-S:     Maintained
-F:     drivers/mmc/host/cqhci*
-
-SYNOPSYS SDHCI COMPLIANT DWC MSHC DRIVER
-M:     Prabu Thangamuthu <prabu.t@synopsys.com>
-M:     Manjunath M B <manjumb@synopsys.com>
-L:     linux-mmc@vger.kernel.org
-S:     Maintained
-F:     drivers/mmc/host/sdhci-pci-dwc-mshc.c
-
 SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER
 M:     Ludovic Desroches <ludovic.desroches@microchip.com>
 L:     linux-mmc@vger.kernel.org
@@ -15088,8 +15086,8 @@ M:      Jonathan Derrick <jonathan.derrick@intel.com>
 M:     Revanth Rajashekar <revanth.rajashekar@intel.com>
 L:     linux-block@vger.kernel.org
 S:     Supported
-F:     block/sed*
 F:     block/opal_proto.h
+F:     block/sed*
 F:     include/linux/sed*
 F:     include/uapi/linux/sed*
 
@@ -15101,9 +15099,9 @@ SECURITY SUBSYSTEM
 M:     James Morris <jmorris@namei.org>
 M:     "Serge E. Hallyn" <serge@hallyn.com>
 L:     linux-security-module@vger.kernel.org (suggested Cc:)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git
-W:     http://kernsec.org/
 S:     Supported
+W:     http://kernsec.org/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git
 F:     security/
 X:     security/selinux/
 
@@ -15112,16 +15110,16 @@ M:    Paul Moore <paul@paul-moore.com>
 M:     Stephen Smalley <stephen.smalley.work@gmail.com>
 M:     Eric Paris <eparis@parisplace.org>
 L:     selinux@vger.kernel.org
+S:     Supported
 W:     https://selinuxproject.org
 W:     https://github.com/SELinuxProject
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
-S:     Supported
+F:     Documentation/ABI/obsolete/sysfs-selinux-checkreqprot
+F:     Documentation/ABI/obsolete/sysfs-selinux-disable
+F:     Documentation/admin-guide/LSM/SELinux.rst
 F:     include/uapi/linux/selinux_netlink.h
-F:     security/selinux/
 F:     scripts/selinux/
-F:     Documentation/admin-guide/LSM/SELinux.rst
-F:     Documentation/ABI/obsolete/sysfs-selinux-disable
-F:     Documentation/ABI/obsolete/sysfs-selinux-checkreqprot
+F:     security/selinux/
 
 SENSABLE PHANTOM
 M:     Jiri Slaby <jirislaby@gmail.com>
@@ -15132,8 +15130,8 @@ F:      include/uapi/linux/phantom.h
 SENSIRION SPS30 AIR POLLUTION SENSOR DRIVER
 M:     Tomasz Duszynski <tduszyns@gmail.com>
 S:     Maintained
-F:     drivers/iio/chemical/sps30.c
 F:     Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.yaml
+F:     drivers/iio/chemical/sps30.c
 
 SERIAL DEVICE BUS
 M:     Rob Herring <robh@kernel.org>
@@ -15156,6 +15154,14 @@ L:     linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/media/rc/serial_ir.c
 
+SERIAL LOW-POWER INTER-CHIP MEDIA BUS (SLIMbus)
+M:     Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     Documentation/devicetree/bindings/slimbus/
+F:     drivers/slimbus/
+F:     include/linux/slimbus.h
+
 SFC NETWORK DRIVER
 M:     Solarflare linux maintainers <linux-net-drivers@solarflare.com>
 M:     Edward Cree <ecree@solarflare.com>
@@ -15189,23 +15195,23 @@ SHARED MEMORY COMMUNICATIONS (SMC) SOCKETS
 M:     Ursula Braun <ubraun@linux.ibm.com>
 M:     Karsten Graul <kgraul@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
-W:     http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
+W:     http://www.ibm.com/developerworks/linux/linux390/
 F:     net/smc/
 
 SHARP GP2AP002A00F/GP2AP002S00F SENSOR DRIVER
 M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-iio@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
 S:     Maintained
-F:     drivers/iio/light/gp2ap002.c
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
 F:     Documentation/devicetree/bindings/iio/light/sharp,gp2ap002.yaml
+F:     drivers/iio/light/gp2ap002.c
 
 SHARP RJ54N1CB0C SENSOR DRIVER
 M:     Jacopo Mondi <jacopo@jmondi.org>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Odd fixes
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/rj54n1cb0c.c
 F:     include/media/i2c/rj54n1cb0c.h
 
@@ -15223,107 +15229,107 @@ F:  include/media/drv-intf/sh_vou.h
 SI2157 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/tuners/si2157*
 
 SI2165 MEDIA DRIVER
 M:     Matthias Schwarzott <zzam@gentoo.org>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-S:     Maintained
 F:     drivers/media/dvb-frontends/si2165*
 
 SI2168 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/dvb-frontends/si2168*
 
 SI470X FM RADIO RECEIVER I2C DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Odd Fixes
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/si470x/radio-si470x-i2c.c
 
 SI470X FM RADIO RECEIVER USB DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/si470x/radio-si470x-common.c
-F:     drivers/media/radio/si470x/radio-si470x.h
 F:     drivers/media/radio/si470x/radio-si470x-usb.c
+F:     drivers/media/radio/si470x/radio-si470x.h
 
 SI4713 FM RADIO TRANSMITTER I2C DRIVER
 M:     Eduardo Valentin <edubezval@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Odd Fixes
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/si4713/si4713.?
 
 SI4713 FM RADIO TRANSMITTER PLATFORM DRIVER
 M:     Eduardo Valentin <edubezval@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Odd Fixes
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/si4713/radio-platform-si4713.c
 
 SI4713 FM RADIO TRANSMITTER USB DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/si4713/radio-usb-si4713.c
 
 SIANO DVB DRIVER
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-media@vger.kernel.org
+S:     Odd fixes
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Odd fixes
 F:     drivers/media/common/siano/
+F:     drivers/media/mmc/siano/
 F:     drivers/media/usb/siano/
 F:     drivers/media/usb/siano/
-F:     drivers/media/mmc/siano/
-
-SIFIVE PDMA DRIVER
-M:     Green Wan <green.wan@sifive.com>
-S:     Maintained
-F:     drivers/dma/sf-pdma/
-F:     Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml
 
 SIFIVE DRIVERS
 M:     Palmer Dabbelt <palmer@dabbelt.com>
 M:     Paul Walmsley <paul.walmsley@sifive.com>
 L:     linux-riscv@lists.infradead.org
-T:     git git://github.com/sifive/riscv-linux.git
 S:     Supported
-K:     [^@]sifive
+T:     git git://github.com/sifive/riscv-linux.git
 N:     sifive
+K:     [^@]sifive
 
 SIFIVE FU540 SYSTEM-ON-CHIP
 M:     Paul Walmsley <paul.walmsley@sifive.com>
 M:     Palmer Dabbelt <palmer@dabbelt.com>
 L:     linux-riscv@lists.infradead.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pjw/sifive.git
 S:     Supported
-K:     fu540
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pjw/sifive.git
 N:     fu540
+K:     fu540
+
+SIFIVE PDMA DRIVER
+M:     Green Wan <green.wan@sifive.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml
+F:     drivers/dma/sf-pdma/
 
 SILEAD TOUCHSCREEN DRIVER
 M:     Hans de Goede <hdegoede@redhat.com>
@@ -15344,12 +15350,12 @@ M:    Teddy Wang <teddy.wang@siliconmotion.com>
 M:     Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
 L:     linux-fbdev@vger.kernel.org
 S:     Maintained
-F:     drivers/video/fbdev/sm712*
 F:     Documentation/fb/sm712fb.rst
+F:     drivers/video/fbdev/sm712*
 
 SIMPLE FIRMWARE INTERFACE (SFI)
-W:     http://simplefirmware.org/
 S:     Obsolete
+W:     http://simplefirmware.org/
 F:     arch/x86/platform/sfi/
 F:     drivers/sfi/
 F:     include/linux/sfi*.h
@@ -15365,34 +15371,34 @@ F:    include/linux/platform_data/simplefb.h
 SIMTEC EB110ATX (Chalice CATS)
 M:     Vincent Sanders <vince@simtec.co.uk>
 M:     Simtec Linux Team <linux@simtec.co.uk>
-W:     http://www.simtec.co.uk/products/EB110ATX/
 S:     Supported
+W:     http://www.simtec.co.uk/products/EB110ATX/
 
 SIMTEC EB2410ITX (BAST)
 M:     Vincent Sanders <vince@simtec.co.uk>
 M:     Simtec Linux Team <linux@simtec.co.uk>
-W:     http://www.simtec.co.uk/products/EB2410ITX/
 S:     Supported
-F:     arch/arm/mach-s3c24xx/mach-bast.c
+W:     http://www.simtec.co.uk/products/EB2410ITX/
 F:     arch/arm/mach-s3c24xx/bast-ide.c
 F:     arch/arm/mach-s3c24xx/bast-irq.c
-
-SIPHASH PRF ROUTINES
-M:     Jason A. Donenfeld <Jason@zx2c4.com>
-S:     Maintained
-F:     lib/siphash.c
-F:     lib/test_siphash.c
-F:     include/linux/siphash.h
+F:     arch/arm/mach-s3c24xx/mach-bast.c
 
 SIOX
 M:     Thorsten Scherer <t.scherer@eckelmann.de>
 M:     Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
 R:     Pengutronix Kernel Team <kernel@pengutronix.de>
 S:     Supported
-F:     drivers/siox/*
 F:     drivers/gpio/gpio-siox.c
+F:     drivers/siox/*
 F:     include/trace/events/siox.h
 
+SIPHASH PRF ROUTINES
+M:     Jason A. Donenfeld <Jason@zx2c4.com>
+S:     Maintained
+F:     include/linux/siphash.h
+F:     lib/siphash.c
+F:     lib/test_siphash.c
+
 SIS 190 ETHERNET DRIVER
 M:     Francois Romieu <romieu@fr.zoreil.com>
 L:     netdev@vger.kernel.org
@@ -15401,23 +15407,23 @@ F:    drivers/net/ethernet/sis/sis190.c
 
 SIS 900/7016 FAST ETHERNET DRIVER
 M:     Daniele Venzano <venza@brownhat.org>
-W:     http://www.brownhat.org/sis900.html
 L:     netdev@vger.kernel.org
 S:     Maintained
+W:     http://www.brownhat.org/sis900.html
 F:     drivers/net/ethernet/sis/sis900.*
 
 SIS FRAMEBUFFER DRIVER
 M:     Thomas Winischhofer <thomas@winischhofer.net>
-W:     http://www.winischhofer.net/linuxsisvga.shtml
 S:     Maintained
+W:     http://www.winischhofer.net/linuxsisvga.shtml
 F:     Documentation/fb/sisfb.rst
 F:     drivers/video/fbdev/sis/
 F:     include/video/sisfb.h
 
 SIS USB2VGA DRIVER
 M:     Thomas Winischhofer <thomas@winischhofer.net>
-W:     http://www.winischhofer.at/linuxsisusbvga.shtml
 S:     Maintained
+W:     http://www.winischhofer.at/linuxsisusbvga.shtml
 F:     drivers/usb/misc/sisusbvga/
 
 SLAB ALLOCATOR
@@ -15438,26 +15444,18 @@ M:    Josh Triplett <josh@joshtriplett.org>
 R:     Steven Rostedt <rostedt@goodmis.org>
 R:     Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
 L:     rcu@vger.kernel.org
-W:     http://www.rdrop.com/users/paulmck/RCU/
 S:     Supported
+W:     http://www.rdrop.com/users/paulmck/RCU/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev
 F:     include/linux/srcu*.h
 F:     kernel/rcu/srcu*.c
 
-SERIAL LOW-POWER INTER-CHIP MEDIA BUS (SLIMbus)
-M:     Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
-L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-S:     Maintained
-F:     drivers/slimbus/
-F:     Documentation/devicetree/bindings/slimbus/
-F:     include/linux/slimbus.h
-
 SMACK SECURITY MODULE
 M:     Casey Schaufler <casey@schaufler-ca.com>
 L:     linux-security-module@vger.kernel.org
+S:     Maintained
 W:     http://schaufler-ca.com
 T:     git git://github.com/cschaufler/smack-next
-S:     Maintained
 F:     Documentation/admin-guide/LSM/Smack.rst
 F:     security/smack/
 
@@ -15470,11 +15468,11 @@ SMIA AND SMIA++ IMAGE SENSOR DRIVER
 M:     Sakari Ailus <sakari.ailus@linux.intel.com>
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     drivers/media/i2c/smiapp/
+F:     Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
 F:     drivers/media/i2c/smiapp-pll.c
 F:     drivers/media/i2c/smiapp-pll.h
+F:     drivers/media/i2c/smiapp/
 F:     include/uapi/linux/smiapp.h
-F:     Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
 
 SMM665 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
@@ -15514,8 +15512,8 @@ SMSC911x ETHERNET DRIVER
 M:     Steve Glendinning <steve.glendinning@shawell.net>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     include/linux/smsc911x.h
 F:     drivers/net/ethernet/smsc/smsc911x.*
+F:     include/linux/smsc911x.h
 
 SMSC9420 PCI ETHERNET DRIVER
 M:     Steve Glendinning <steve.glendinning@shawell.net>
@@ -15525,17 +15523,40 @@ F:    drivers/net/ethernet/smsc/smsc9420.*
 
 SOC-CAMERA V4L2 SUBSYSTEM
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Orphan
-F:     include/media/soc_camera.h
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/staging/media/soc_camera/
+F:     include/media/soc_camera.h
+
+SOCIONEXT (SNI) AVE NETWORK DRIVER
+M:     Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt
+F:     drivers/net/ethernet/socionext/sni_ave.c
+
+SOCIONEXT (SNI) NETSEC NETWORK DRIVER
+M:     Jassi Brar <jaswinder.singh@linaro.org>
+M:     Ilias Apalodimas <ilias.apalodimas@linaro.org>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/net/socionext-netsec.txt
+F:     drivers/net/ethernet/socionext/netsec.c
+
+SOCIONEXT (SNI) Synquacer SPI DRIVER
+M:     Masahisa Kojima <masahisa.kojima@linaro.org>
+M:     Jassi Brar <jaswinder.singh@linaro.org>
+L:     linux-spi@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/spi/spi-synquacer.txt
+F:     drivers/spi/spi-synquacer.c
 
 SOCIONEXT SYNQUACER I2C DRIVER
 M:     Ard Biesheuvel <ardb@kernel.org>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
-F:     drivers/i2c/busses/i2c-synquacer.c
 F:     Documentation/devicetree/bindings/i2c/i2c-synquacer.txt
+F:     drivers/i2c/busses/i2c-synquacer.c
 
 SOCIONEXT UNIPHIER SOUND DRIVER
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -15583,37 +15604,14 @@ F:    include/uapi/linux/arm_sdei.h
 SOFTWARE RAID (Multiple Disks) SUPPORT
 M:     Song Liu <song@kernel.org>
 L:     linux-raid@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/song/md.git
 S:     Supported
-F:     drivers/md/Makefile
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/song/md.git
 F:     drivers/md/Kconfig
+F:     drivers/md/Makefile
 F:     drivers/md/md*
 F:     drivers/md/raid*
-F:     include/linux/raid/
-F:     include/uapi/linux/raid/
-
-SOCIONEXT (SNI) AVE NETWORK DRIVER
-M:     Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     drivers/net/ethernet/socionext/sni_ave.c
-F:     Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt
-
-SOCIONEXT (SNI) NETSEC NETWORK DRIVER
-M:     Jassi Brar <jaswinder.singh@linaro.org>
-M:     Ilias Apalodimas <ilias.apalodimas@linaro.org>
-L:     netdev@vger.kernel.org
-S:     Maintained
-F:     drivers/net/ethernet/socionext/netsec.c
-F:     Documentation/devicetree/bindings/net/socionext-netsec.txt
-
-SOCIONEXT (SNI) Synquacer SPI DRIVER
-M:     Masahisa Kojima <masahisa.kojima@linaro.org>
-M:     Jassi Brar <jaswinder.singh@linaro.org>
-L:     linux-spi@vger.kernel.org
-S:     Maintained
-F:     drivers/spi/spi-synquacer.c
-F:     Documentation/devicetree/bindings/spi/spi-synquacer.txt
+F:     include/linux/raid/
+F:     include/uapi/linux/raid/
 
 SOLIDRUN CLEARFOG SUPPORT
 M:     Russell King <linux@armlinux.org.uk>
@@ -15644,54 +15642,54 @@ F:    include/linux/ssb/
 SONY IMX214 SENSOR DRIVER
 M:     Ricardo Ribalda <ricardo.ribalda@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/i2c/imx214.c
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/sony,imx214.txt
+F:     drivers/media/i2c/imx214.c
 
 SONY IMX219 SENSOR DRIVER
 M:     Dave Stevenson <dave.stevenson@raspberrypi.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/i2c/imx219.c
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/imx219.yaml
+F:     drivers/media/i2c/imx219.c
 
 SONY IMX258 SENSOR DRIVER
 M:     Sakari Ailus <sakari.ailus@linux.intel.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/imx258.c
 
 SONY IMX274 SENSOR DRIVER
 M:     Leon Luo <leonl@leopardimaging.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/i2c/imx274.c
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/imx274.txt
+F:     drivers/media/i2c/imx274.c
 
 SONY IMX290 SENSOR DRIVER
 M:     Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/i2c/imx290.c
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/imx290.txt
+F:     drivers/media/i2c/imx290.c
 
 SONY IMX319 SENSOR DRIVER
 M:     Bingbu Cao <bingbu.cao@intel.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/imx319.c
 
 SONY IMX355 SENSOR DRIVER
 M:     Tianshu Qiu <tian.shu.qiu@intel.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/imx355.c
 
 SONY MEMORYSTICK SUBSYSTEM
@@ -15699,8 +15697,8 @@ M:      Maxim Levitsky <maximlevitsky@gmail.com>
 M:     Alex Dubov <oakad@yahoo.com>
 M:     Ulf Hansson <ulf.hansson@linaro.org>
 L:     linux-mmc@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git
 F:     drivers/memstick/
 F:     include/linux/memstick.h
 
@@ -15718,10 +15716,10 @@ SOUND
 M:     Jaroslav Kysela <perex@perex.cz>
 M:     Takashi Iwai <tiwai@suse.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
 W:     http://www.alsa-project.org/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 Q:     http://patchwork.kernel.org/project/alsa-devel/list/
-S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 F:     Documentation/sound/
 F:     include/sound/
 F:     include/uapi/sound/
@@ -15730,8 +15728,8 @@ F:      sound/
 SOUND - COMPRESSED AUDIO
 M:     Vinod Koul <vkoul@kernel.org>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 F:     Documentation/sound/designs/compress-offload.rst
 F:     include/sound/compress_driver.h
 F:     include/uapi/sound/compress_*
@@ -15748,15 +15746,15 @@ F:    sound/soc/soc-generic-dmaengine-pcm.c
 SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
 M:     Liam Girdwood <lgirdwood@gmail.com>
 M:     Mark Brown <broonie@kernel.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-W:     http://alsa-project.org/main/index.php/ASoC
 S:     Supported
+W:     http://alsa-project.org/main/index.php/ASoC
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
 F:     Documentation/devicetree/bindings/sound/
 F:     Documentation/sound/soc/
-F:     sound/soc/
 F:     include/dt-bindings/sound/
 F:     include/sound/soc*
+F:     sound/soc/
 
 SOUND - SOUND OPEN FIRMWARE (SOF) DRIVERS
 M:     Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
@@ -15765,8 +15763,8 @@ M:      Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
 M:     Kai Vehmanen <kai.vehmanen@linux.intel.com>
 M:     Daniel Baluta <daniel.baluta@nxp.com>
 L:     sound-open-firmware@alsa-project.org (moderated for non-subscribers)
-W:     https://github.com/thesofproject/linux/
 S:     Supported
+W:     https://github.com/thesofproject/linux/
 F:     sound/soc/sof/
 
 SOUNDWIRE SUBSYSTEM
@@ -15782,28 +15780,27 @@ F:    include/linux/soundwire/
 SP2 MEDIA DRIVER
 M:     Olli Salonen <olli.salonen@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-S:     Maintained
 F:     drivers/media/dvb-frontends/sp2*
 
 SPARC + UltraSPARC (sparc/sparc64)
 M:     "David S. Miller" <davem@davemloft.net>
 L:     sparclinux@vger.kernel.org
+S:     Maintained
 Q:     http://patchwork.ozlabs.org/project/sparclinux/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next.git
-S:     Maintained
 F:     arch/sparc/
 F:     drivers/sbus/
 
 SPARC SERIAL DRIVERS
 M:     "David S. Miller" <davem@davemloft.net>
 L:     sparclinux@vger.kernel.org
+S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next.git
-S:     Maintained
-F:     include/linux/sunserialcore.h
 F:     drivers/tty/serial/suncore.c
 F:     drivers/tty/serial/sunhv.c
 F:     drivers/tty/serial/sunsab.c
@@ -15812,48 +15809,49 @@ F:    drivers/tty/serial/sunsu.c
 F:     drivers/tty/serial/sunzilog.c
 F:     drivers/tty/serial/sunzilog.h
 F:     drivers/tty/vcc.c
+F:     include/linux/sunserialcore.h
 
 SPARSE CHECKER
 M:     "Luc Van Oostenryck" <luc.vanoostenryck@gmail.com>
 L:     linux-sparse@vger.kernel.org
+S:     Maintained
 W:     https://sparse.wiki.kernel.org/
 T:     git git://git.kernel.org/pub/scm/devel/sparse/sparse.git
-S:     Maintained
 F:     include/linux/compiler.h
 
 SPEAR CLOCK FRAMEWORK SUPPORT
 M:     Viresh Kumar <vireshk@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.st.com/spear
 S:     Maintained
+W:     http://www.st.com/spear
 F:     drivers/clk/spear/
 
 SPEAR PLATFORM SUPPORT
 M:     Viresh Kumar <vireshk@kernel.org>
 M:     Shiraz Hashim <shiraz.linux.kernel@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.st.com/spear
 S:     Maintained
+W:     http://www.st.com/spear
 F:     arch/arm/boot/dts/spear*
 F:     arch/arm/mach-spear/
 
 SPI NOR SUBSYSTEM
 M:     Tudor Ambarus <tudor.ambarus@microchip.com>
 L:     linux-mtd@lists.infradead.org
+S:     Maintained
 W:     http://www.linux-mtd.infradead.org/
 Q:     http://patchwork.ozlabs.org/project/linux-mtd/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git spi-nor/next
 C:     irc://irc.oftc.net/mtd
-S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git spi-nor/next
 F:     drivers/mtd/spi-nor/
 F:     include/linux/mtd/spi-nor.h
 
 SPI SUBSYSTEM
 M:     Mark Brown <broonie@kernel.org>
 L:     linux-spi@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
-Q:     http://patchwork.kernel.org/project/spi-devel-general/list/
 S:     Maintained
+Q:     http://patchwork.kernel.org/project/spi-devel-general/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
 F:     Documentation/devicetree/bindings/spi/
 F:     Documentation/spi/
 F:     drivers/spi/
@@ -15880,17 +15878,17 @@ F:    include/trace/events/spmi.h
 SPU FILE SYSTEM
 M:     Jeremy Kerr <jk@ozlabs.org>
 L:     linuxppc-dev@lists.ozlabs.org
-W:     http://www.ibm.com/developerworks/power/cell/
 S:     Supported
+W:     http://www.ibm.com/developerworks/power/cell/
 F:     Documentation/filesystems/spufs.txt
 F:     arch/powerpc/platforms/cell/spufs/
 
 SQUASHFS FILE SYSTEM
 M:     Phillip Lougher <phillip@squashfs.org.uk>
 L:     squashfs-devel@lists.sourceforge.net (subscribers-only)
+S:     Maintained
 W:     http://squashfs.org.uk
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-next.git
-S:     Maintained
 F:     Documentation/filesystems/squashfs.rst
 F:     fs/squashfs/
 
@@ -15902,18 +15900,18 @@ F:    arch/alpha/kernel/srm_env.c
 ST LSM6DSx IMU IIO DRIVER
 M:     Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
 L:     linux-iio@vger.kernel.org
-W:     http://www.st.com/
 S:     Maintained
-F:     drivers/iio/imu/st_lsm6dsx/
+W:     http://www.st.com/
 F:     Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
+F:     drivers/iio/imu/st_lsm6dsx/
 
 ST MIPID02 CSI-2 TO PARALLEL BRIDGE DRIVER
 M:     Mickael Guene <mickael.guene@st.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/i2c/st-mipid02.c
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/i2c/st,st-mipid02.txt
+F:     drivers/media/i2c/st-mipid02.c
 
 ST STM32 I2C/SMBUS DRIVER
 M:     Pierre-Yves MORDRET <pierre-yves.mordret@st.com>
@@ -15925,8 +15923,8 @@ ST VL53L0X ToF RANGER(I2C) IIO DRIVER
 M:     Song Qiang <songqiang1304521@gmail.com>
 L:     linux-iio@vger.kernel.org
 S:     Maintained
-F:     drivers/iio/proximity/vl53l0x-i2c.c
 F:     Documentation/devicetree/bindings/iio/proximity/vl53l0x.txt
+F:     drivers/iio/proximity/vl53l0x-i2c.c
 
 STABLE BRANCH
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
@@ -15970,20 +15968,28 @@ STAGING - OLPC SECONDARY DISPLAY CONTROLLER (DCON)
 M:     Jens Frederich <jfrederich@gmail.com>
 M:     Daniel Drake <dsd@laptop.org>
 M:     Jon Nettleton <jon.nettleton@gmail.com>
-W:     http://wiki.laptop.org/go/DCON
 S:     Maintained
+W:     http://wiki.laptop.org/go/DCON
 F:     drivers/staging/olpc_dcon/
 
+STAGING - REALTEK RTL8188EU DRIVERS
+M:     Larry Finger <Larry.Finger@lwfinger.net>
+S:     Odd Fixes
+F:     drivers/staging/rtl8188eu/
+
 STAGING - REALTEK RTL8712U DRIVERS
 M:     Larry Finger <Larry.Finger@lwfinger.net>
 M:     Florian Schilhabel <florian.c.schilhabel@googlemail.com>.
 S:     Odd Fixes
 F:     drivers/staging/rtl8712/
 
-STAGING - REALTEK RTL8188EU DRIVERS
-M:     Larry Finger <Larry.Finger@lwfinger.net>
-S:     Odd Fixes
-F:     drivers/staging/rtl8188eu/
+STAGING - SEPS525 LCD CONTROLLER DRIVERS
+M:     Michael Hennerich <michael.hennerich@analog.com>
+M:     Beniamin Bia <beniamin.bia@analog.com>
+L:     linux-fbdev@vger.kernel.org
+S:     Supported
+F:     Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
+F:     drivers/staging/fbtft/fb_seps525.c
 
 STAGING - SILICON MOTION SM750 FRAME BUFFER DRIVER
 M:     Sudip Mukherjee <sudipm.mukherjee@gmail.com>
@@ -15999,8 +16005,8 @@ M:      Chris Brannon <chris@the-brannons.com>
 M:     Kirk Reiser <kirk@reisers.ca>
 M:     Samuel Thibault <samuel.thibault@ens-lyon.org>
 L:     speakup@linux-speakup.org
-W:     http://www.linux-speakup.org/
 S:     Odd Fixes
+W:     http://www.linux-speakup.org/
 F:     drivers/staging/speakup/
 
 STAGING - VIA VT665X DRIVERS
@@ -16015,19 +16021,11 @@ L:    linux-wireless@vger.kernel.org
 S:     Supported
 F:     drivers/staging/wilc1000/
 
-STAGING - SEPS525 LCD CONTROLLER DRIVERS
-M:     Michael Hennerich <michael.hennerich@analog.com>
-M:     Beniamin Bia <beniamin.bia@analog.com>
-L:     linux-fbdev@vger.kernel.org
-S:     Supported
-F:     drivers/staging/fbtft/fb_seps525.c
-F:     Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
-
 STAGING SUBSYSTEM
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
 L:     devel@driverdev.osuosl.org
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
 F:     drivers/staging/
 
 STARFIRE/DURALAN NETWORK DRIVER
@@ -16051,14 +16049,14 @@ F:    sound/soc/sti/
 STI CEC DRIVER
 M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
 S:     Maintained
-F:     drivers/media/platform/sti/cec/
 F:     Documentation/devicetree/bindings/media/stih-cec.txt
+F:     drivers/media/platform/sti/cec/
 
 STK1160 USB VIDEO CAPTURE DRIVER
 M:     Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/usb/stk1160/
 
 STM32 AUDIO (ASoC) DRIVERS
@@ -16072,38 +16070,29 @@ F:    sound/soc/stm/
 STM32 TIMER/LPTIMER DRIVERS
 M:     Fabrice Gasnier <fabrice.gasnier@st.com>
 S:     Maintained
+F:     Documentation/ABI/testing/*timer-stm32
+F:     Documentation/devicetree/bindings/*/*stm32-*timer*
 F:     drivers/*/stm32-*timer*
 F:     drivers/pwm/pwm-stm32*
 F:     include/linux/*/stm32-*tim*
-F:     Documentation/ABI/testing/*timer-stm32
-F:     Documentation/devicetree/bindings/*/*stm32-*timer*
 
 STMMAC ETHERNET DRIVER
 M:     Giuseppe Cavallaro <peppe.cavallaro@st.com>
 M:     Alexandre Torgue <alexandre.torgue@st.com>
 M:     Jose Abreu <joabreu@synopsys.com>
 L:     netdev@vger.kernel.org
-W:     http://www.stlinux.com
 S:     Supported
+W:     http://www.stlinux.com
 F:     Documentation/networking/device_drivers/stmicro/
 F:     drivers/net/ethernet/stmicro/stmmac/
 
-EXTRA BOOT CONFIG
-M:     Masami Hiramatsu <mhiramat@kernel.org>
-S:     Maintained
-F:     lib/bootconfig.c
-F:     fs/proc/bootconfig.c
-F:     include/linux/bootconfig.h
-F:     tools/bootconfig/*
-F:     Documentation/admin-guide/bootconfig.rst
-
 SUN3/3X
 M:     Sam Creasey <sammy@sammy.net>
-W:     http://sammy.net/sun3/
 S:     Maintained
+W:     http://sammy.net/sun3/
+F:     arch/m68k/include/asm/sun3*
 F:     arch/m68k/kernel/*sun3*
 F:     arch/m68k/sun3*/
-F:     arch/m68k/include/asm/sun3*
 F:     drivers/net/ethernet/i825xx/sun3*
 
 SUN4I LOW RES ADC ATTACHED TABLET KEYS DRIVER
@@ -16123,8 +16112,8 @@ SUPERH
 M:     Yoshinori Sato <ysato@users.sourceforge.jp>
 M:     Rich Felker <dalias@libc.org>
 L:     linux-sh@vger.kernel.org
-Q:     http://patchwork.kernel.org/project/linux-sh/list/
 S:     Maintained
+Q:     http://patchwork.kernel.org/project/linux-sh/list/
 F:     Documentation/sh/
 F:     arch/sh/
 F:     drivers/sh/
@@ -16134,15 +16123,15 @@ M:    "Rafael J. Wysocki" <rjw@rjwysocki.net>
 M:     Len Brown <len.brown@intel.com>
 M:     Pavel Machek <pavel@ucw.cz>
 L:     linux-pm@vger.kernel.org
-B:     https://bugzilla.kernel.org
 S:     Supported
+B:     https://bugzilla.kernel.org
 F:     Documentation/power/
 F:     arch/x86/kernel/acpi/
 F:     drivers/base/power/
-F:     kernel/power/
-F:     include/linux/suspend.h
 F:     include/linux/freezer.h
 F:     include/linux/pm.h
+F:     include/linux/suspend.h
+F:     kernel/power/
 
 SVGA HANDLING
 M:     Martin Mares <mj@ucw.cz>
@@ -16154,75 +16143,75 @@ F:    arch/x86/boot/video*
 SWIOTLB SUBSYSTEM
 M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
 L:     iommu@lists.linux-foundation.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/konrad/swiotlb.git
 S:     Supported
-F:     kernel/dma/swiotlb.c
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/konrad/swiotlb.git
 F:     arch/*/kernel/pci-swiotlb.c
 F:     include/linux/swiotlb.h
+F:     kernel/dma/swiotlb.c
 
 SWITCHDEV
 M:     Jiri Pirko <jiri@resnulli.us>
 M:     Ivan Vecera <ivecera@redhat.com>
 L:     netdev@vger.kernel.org
 S:     Supported
-F:     net/switchdev/
 F:     include/net/switchdev.h
+F:     net/switchdev/
 
 SY8106A REGULATOR DRIVER
 M:     Icenowy Zheng <icenowy@aosc.io>
 S:     Maintained
-F:     drivers/regulator/sy8106a-regulator.c
 F:     Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt
+F:     drivers/regulator/sy8106a-regulator.c
 
 SYNC FILE FRAMEWORK
 M:     Sumit Semwal <sumit.semwal@linaro.org>
 R:     Gustavo Padovan <gustavo@padovan.org>
-S:     Maintained
 L:     linux-media@vger.kernel.org
 L:     dri-devel@lists.freedesktop.org
-F:     drivers/dma-buf/sync_*
+S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+F:     Documentation/driver-api/sync_file.rst
 F:     drivers/dma-buf/dma-fence*
 F:     drivers/dma-buf/sw_sync.c
+F:     drivers/dma-buf/sync_*
 F:     include/linux/sync_file.h
 F:     include/uapi/linux/sync_file.h
-F:     Documentation/driver-api/sync_file.rst
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 
 SYNOPSYS ARC ARCHITECTURE
 M:     Vineet Gupta <vgupta@synopsys.com>
 L:     linux-snps-arc@lists.infradead.org
 S:     Supported
-F:     arch/arc/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git
 F:     Documentation/devicetree/bindings/arc/*
 F:     Documentation/devicetree/bindings/interrupt-controller/snps,arc*
+F:     arch/arc/
 F:     drivers/clocksource/arc_timer.c
 F:     drivers/tty/serial/arc_uart.c
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git
 
 SYNOPSYS ARC HSDK SDP pll clock driver
 M:     Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
 S:     Supported
-F:     drivers/clk/clk-hsdk-pll.c
 F:     Documentation/devicetree/bindings/clock/snps,hsdk-pll-clock.txt
+F:     drivers/clk/clk-hsdk-pll.c
 
 SYNOPSYS ARC SDP clock driver
 M:     Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
 S:     Supported
-F:     drivers/clk/axs10x/*
 F:     Documentation/devicetree/bindings/clock/snps,pll-clock.txt
+F:     drivers/clk/axs10x/*
 
 SYNOPSYS ARC SDP platform support
 M:     Alexey Brodkin <abrodkin@synopsys.com>
 S:     Supported
-F:     arch/arc/plat-axs10x
-F:     arch/arc/boot/dts/ax*
 F:     Documentation/devicetree/bindings/arc/axs10*
+F:     arch/arc/boot/dts/ax*
+F:     arch/arc/plat-axs10x
 
 SYNOPSYS AXS10x RESET CONTROLLER DRIVER
 M:     Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
 S:     Supported
-F:     drivers/reset/reset-axs10x.c
 F:     Documentation/devicetree/bindings/reset/snps,axs10x-reset.txt
+F:     drivers/reset/reset-axs10x.c
 
 SYNOPSYS CREG GPIO DRIVER
 M:     Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
@@ -16247,8 +16236,8 @@ F:      drivers/gpio/gpio-dwapb.c
 SYNOPSYS DESIGNWARE AXI DMAC DRIVER
 M:     Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
 S:     Maintained
-F:     drivers/dma/dw-axi-dmac/
 F:     Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.txt
+F:     drivers/dma/dw-axi-dmac/
 
 SYNOPSYS DESIGNWARE DMAC DRIVER
 M:     Viresh Kumar <vireshk@kernel.org>
@@ -16291,15 +16280,22 @@ F:    drivers/mmc/host/dw_mmc*
 SYNOPSYS HSDK RESET CONTROLLER DRIVER
 M:     Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
 S:     Supported
+F:     Documentation/devicetree/bindings/reset/snps,hsdk-reset.txt
 F:     drivers/reset/reset-hsdk.c
 F:     include/dt-bindings/reset/snps,hsdk-reset.h
-F:     Documentation/devicetree/bindings/reset/snps,hsdk-reset.txt
+
+SYNOPSYS SDHCI COMPLIANT DWC MSHC DRIVER
+M:     Prabu Thangamuthu <prabu.t@synopsys.com>
+M:     Manjunath M B <manjumb@synopsys.com>
+L:     linux-mmc@vger.kernel.org
+S:     Maintained
+F:     drivers/mmc/host/sdhci-pci-dwc-mshc.c
 
 SYSTEM CONFIGURATION (SYSCON)
 M:     Lee Jones <lee.jones@linaro.org>
 M:     Arnd Bergmann <arnd@arndb.de>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git
 F:     drivers/mfd/syscon.c
 
 SYSTEM CONTROL & POWER/MANAGEMENT INTERFACE (SCPI/SCMI) Message Protocol drivers
@@ -16309,8 +16305,8 @@ S:      Maintained
 F:     Documentation/devicetree/bindings/arm/arm,sc[mp]i.txt
 F:     drivers/clk/clk-sc[mp]i.c
 F:     drivers/cpufreq/sc[mp]i-cpufreq.c
-F:     drivers/firmware/arm_scpi.c
 F:     drivers/firmware/arm_scmi/
+F:     drivers/firmware/arm_scpi.c
 F:     drivers/reset/reset-scmi.c
 F:     include/linux/sc[mp]i_protocol.h
 F:     include/trace/events/scmi.h
@@ -16318,8 +16314,8 @@ F:      include/trace/events/scmi.h
 SYSTEM RESET/SHUTDOWN DRIVERS
 M:     Sebastian Reichel <sre@kernel.org>
 L:     linux-pm@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git
 F:     Documentation/devicetree/bindings/power/reset/
 F:     drivers/power/reset/
 
@@ -16377,125 +16373,125 @@ F:  drivers/media/dvb-frontends/tc90522*
 TCP LOW PRIORITY MODULE
 M:     "Wong Hoi Sing, Edison" <hswong3i@gmail.com>
 M:     "Hung Hing Lun, Mike" <hlhung3i@gmail.com>
-W:     http://tcp-lp-mod.sourceforge.net/
 S:     Maintained
+W:     http://tcp-lp-mod.sourceforge.net/
 F:     net/ipv4/tcp_lp.c
 
 TDA10071 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/dvb-frontends/tda10071*
 
 TDA18212 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/tuners/tda18212*
 
 TDA18218 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/tuners/tda18218*
 
 TDA18250 MEDIA DRIVER
 M:     Olli Salonen <olli.salonen@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
 F:     drivers/media/tuners/tda18250*
 
 TDA18271 MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mkrufky/tuners.git
-S:     Maintained
 F:     drivers/media/tuners/tda18271*
 
 TDA1997x MEDIA DRIVER
 M:     Tim Harvey <tharvey@gateworks.com>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-S:     Maintained
 F:     drivers/media/i2c/tda1997x.*
 
 TDA827x MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mkrufky/tuners.git
-S:     Maintained
 F:     drivers/media/tuners/tda8290.*
 
 TDA8290 MEDIA DRIVER
 M:     Michael Krufky <mkrufky@linuxtv.org>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mkrufky/tuners.git
-S:     Maintained
 F:     drivers/media/tuners/tda8290.*
 
 TDA9840 MEDIA DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/tda9840*
 
 TEA5761 TUNER DRIVER
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-media@vger.kernel.org
+S:     Odd fixes
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Odd fixes
 F:     drivers/media/tuners/tea5761.*
 
 TEA5767 TUNER DRIVER
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
 F:     drivers/media/tuners/tea5767.*
 
 TEA6415C MEDIA DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/tea6415c*
 
 TEA6420 MEDIA DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/i2c/tea6420*
 
 TEAM DRIVER
@@ -16527,18 +16523,18 @@ TEE SUBSYSTEM
 M:     Jens Wiklander <jens.wiklander@linaro.org>
 L:     tee-dev@lists.linaro.org
 S:     Maintained
+F:     Documentation/tee.txt
+F:     drivers/tee/
 F:     include/linux/tee_drv.h
 F:     include/uapi/linux/tee.h
-F:     drivers/tee/
-F:     Documentation/tee.txt
 
 TEGRA ARCHITECTURE SUPPORT
 M:     Thierry Reding <thierry.reding@gmail.com>
 M:     Jonathan Hunter <jonathanh@nvidia.com>
 L:     linux-tegra@vger.kernel.org
+S:     Supported
 Q:     http://patchwork.ozlabs.org/project/linux-tegra/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git
-S:     Supported
 N:     [^a-z]tegra
 
 TEGRA CLOCK DRIVER
@@ -16603,62 +16599,69 @@ L:    netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/tehuti/*
 
-Telecom Clock Driver for MCPL0010
+TELECOM CLOCK DRIVER FOR MCPL0010
 M:     Mark Gross <mark.gross@intel.com>
 S:     Supported
 F:     drivers/char/tlclk.c
 
+TEMPO SEMICONDUCTOR DRIVERS
+M:     Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/sound/tscs*.txt
+F:     sound/soc/codecs/tscs*.c
+F:     sound/soc/codecs/tscs*.h
+
 TENSILICA XTENSA PORT (xtensa)
 M:     Chris Zankel <chris@zankel.net>
 M:     Max Filippov <jcmvbkbc@gmail.com>
 L:     linux-xtensa@linux-xtensa.org
-T:     git git://github.com/czankel/xtensa-linux.git
-S:     Maintained
-F:     arch/xtensa/
-F:     drivers/irqchip/irq-xtensa-*
-
-Texas Instruments' System Control Interface (TISCI) Protocol Driver
-M:     Nishanth Menon <nm@ti.com>
-M:     Tero Kristo <t-kristo@ti.com>
-M:     Santosh Shilimkar <ssantosh@kernel.org>
-L:     linux-arm-kernel@lists.infradead.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
-F:     drivers/firmware/ti_sci*
-F:     include/linux/soc/ti/ti_sci_protocol.h
-F:     Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
-F:     drivers/soc/ti/ti_sci_pm_domains.c
-F:     include/dt-bindings/soc/ti,sci_pm_domain.h
-F:     Documentation/devicetree/bindings/reset/ti,sci-reset.txt
-F:     Documentation/devicetree/bindings/clock/ti,sci-clk.txt
-F:     drivers/clk/keystone/sci-clk.c
-F:     drivers/reset/reset-ti-sci.c
-F:     Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
-F:     Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
-F:     drivers/irqchip/irq-ti-sci-intr.c
-F:     drivers/irqchip/irq-ti-sci-inta.c
-F:     include/linux/soc/ti/ti_sci_inta_msi.h
-F:     drivers/soc/ti/ti_sci_inta_msi.c
+T:     git git://github.com/czankel/xtensa-linux.git
+F:     arch/xtensa/
+F:     drivers/irqchip/irq-xtensa-*
 
-Texas Instruments ASoC drivers
+TEXAS INSTRUMENTS ASoC DRIVERS
 M:     Peter Ujfalusi <peter.ujfalusi@ti.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Maintained
 F:     sound/soc/ti/
 
-Texas Instruments' DAC7612 DAC Driver
+TEXAS INSTRUMENTS' DAC7612 DAC DRIVER
 M:     Ricardo Ribalda <ricardo@ribalda.com>
 L:     linux-iio@vger.kernel.org
 S:     Supported
-F:     drivers/iio/dac/ti-dac7612.c
 F:     Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt
+F:     drivers/iio/dac/ti-dac7612.c
+
+TEXAS INSTRUMENTS' SYSTEM CONTROL INTERFACE (TISCI) PROTOCOL DRIVER
+M:     Nishanth Menon <nm@ti.com>
+M:     Tero Kristo <t-kristo@ti.com>
+M:     Santosh Shilimkar <ssantosh@kernel.org>
+L:     linux-arm-kernel@lists.infradead.org
+S:     Maintained
+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/reset/ti,sci-reset.txt
+F:     Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
+F:     drivers/clk/keystone/sci-clk.c
+F:     drivers/firmware/ti_sci*
+F:     drivers/irqchip/irq-ti-sci-inta.c
+F:     drivers/irqchip/irq-ti-sci-intr.c
+F:     drivers/reset/reset-ti-sci.c
+F:     drivers/soc/ti/ti_sci_inta_msi.c
+F:     drivers/soc/ti/ti_sci_pm_domains.c
+F:     include/dt-bindings/soc/ti,sci_pm_domain.h
+F:     include/linux/soc/ti/ti_sci_inta_msi.h
+F:     include/linux/soc/ti/ti_sci_protocol.h
 
 THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/radio-raremono.c
 
 THERMAL
@@ -16666,14 +16669,23 @@ M:    Zhang Rui <rui.zhang@intel.com>
 M:     Daniel Lezcano <daniel.lezcano@linaro.org>
 R:     Amit Kucheria <amit.kucheria@verdurent.com>
 L:     linux-pm@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git
-Q:     https://patchwork.kernel.org/project/linux-pm/list/
 S:     Supported
+Q:     https://patchwork.kernel.org/project/linux-pm/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git
+F:     Documentation/devicetree/bindings/thermal/
 F:     drivers/thermal/
+F:     include/linux/cpu_cooling.h
 F:     include/linux/thermal.h
 F:     include/uapi/linux/thermal.h
-F:     include/linux/cpu_cooling.h
-F:     Documentation/devicetree/bindings/thermal/
+
+THERMAL DRIVER FOR AMLOGIC SOCS
+M:     Guillaume La Roque <glaroque@baylibre.com>
+L:     linux-pm@vger.kernel.org
+L:     linux-amlogic@lists.infradead.org
+S:     Supported
+W:     http://linux-meson.com/
+F:     Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml
+F:     drivers/thermal/amlogic_thermal.c
 
 THERMAL/CPU_COOLING
 M:     Amit Daniel Kachhap <amit.kachhap@gmail.com>
@@ -16688,15 +16700,6 @@ F:     drivers/thermal/cpufreq_cooling.c
 F:     drivers/thermal/cpuidle_cooling.c
 F:     include/linux/cpu_cooling.h
 
-THERMAL DRIVER FOR AMLOGIC SOCS
-M:     Guillaume La Roque <glaroque@baylibre.com>
-L:     linux-pm@vger.kernel.org
-L:     linux-amlogic@lists.infradead.org
-W:     http://linux-meson.com/
-S:     Supported
-F:     drivers/thermal/amlogic_thermal.c
-F:     Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml
-
 THINKPAD ACPI EXTRAS DRIVER
 M:     Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br>
 L:     ibm-acpi-devel@lists.sourceforge.net
@@ -16735,10 +16738,10 @@ F:    drivers/gpio/gpio-thunderx.c
 TI AM437X VPFE DRIVER
 M:     "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
-S:     Maintained
 F:     drivers/media/platform/am437x/
 
 TI BANDGAP AND THERMAL DRIVER
@@ -16751,9 +16754,9 @@ F:      drivers/thermal/ti-soc-thermal/
 
 TI BQ27XXX POWER SUPPLY DRIVER
 R:     Andrew F. Davis <afd@ti.com>
-F:     include/linux/power/bq27xxx_battery.h
 F:     drivers/power/supply/bq27xxx_battery.c
 F:     drivers/power/supply/bq27xxx_battery_i2c.c
+F:     include/linux/power/bq27xxx_battery.h
 
 TI CDCE706 CLOCK DRIVER
 M:     Max Filippov <jcmvbkbc@gmail.com>
@@ -16771,12 +16774,12 @@ TI DAVINCI MACHINE SUPPORT
 M:     Sekhar Nori <nsekhar@ti.com>
 R:     Bartosz Golaszewski <bgolaszewski@baylibre.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nsekhar/linux-davinci.git
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nsekhar/linux-davinci.git
 F:     Documentation/devicetree/bindings/i2c/i2c-davinci.txt
+F:     arch/arm/boot/dts/da850*
 F:     arch/arm/mach-davinci/
 F:     drivers/i2c/busses/i2c-davinci.c
-F:     arch/arm/boot/dts/da850*
 
 TI DAVINCI SERIES CLOCK DRIVER
 M:     David Lechner <david@lechnology.com>
@@ -16795,10 +16798,10 @@ F:    drivers/gpio/gpio-davinci.c
 TI DAVINCI SERIES MEDIA DRIVER
 M:     "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
-S:     Maintained
 F:     drivers/media/platform/davinci/
 F:     include/media/davinci/
 
@@ -16830,16 +16833,16 @@ M:    Santosh Shilimkar <ssantosh@kernel.org>
 L:     linux-kernel@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     drivers/soc/ti/*
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone.git
+F:     drivers/soc/ti/*
 
 TI LM49xxx FAMILY ASoC CODEC DRIVERS
 M:     M R Swami Reddy <mr.swami.reddy@ti.com>
 M:     Vishwas A Deshpande <vishwas.a.deshpande@ti.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Maintained
-F:     sound/soc/codecs/lm49453*
 F:     sound/soc/codecs/isabelle*
+F:     sound/soc/codecs/lm49453*
 
 TI LP855x BACKLIGHT DRIVER
 M:     Milo Kim <milo.kim@ti.com>
@@ -16896,8 +16899,8 @@ M:      Mark Greer <mgreer@animalcreek.com>
 L:     linux-wireless@vger.kernel.org
 L:     linux-nfc@lists.01.org (moderated for non-subscribers)
 S:     Supported
-F:     drivers/nfc/trf7970a.c
 F:     Documentation/devicetree/bindings/net/nfc/trf7970a.txt
+F:     drivers/nfc/trf7970a.c
 
 TI TWL4030 SERIES SOC CODEC DRIVER
 M:     Peter Ujfalusi <peter.ujfalusi@ti.com>
@@ -16917,10 +16920,10 @@ F:    drivers/media/platform/ti-vpe/
 
 TI WILINK WIRELESS DRIVERS
 L:     linux-wireless@vger.kernel.org
+S:     Orphan
 W:     http://wireless.kernel.org/en/users/Drivers/wl12xx
 W:     http://wireless.kernel.org/en/users/Drivers/wl1251
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
-S:     Orphan
 F:     drivers/net/wireless/ti/
 F:     include/linux/wl12xx.h
 
@@ -16929,17 +16932,17 @@ M:    John Stultz <john.stultz@linaro.org>
 M:     Thomas Gleixner <tglx@linutronix.de>
 R:     Stephen Boyd <sboyd@kernel.org>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 S:     Supported
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 F:     include/linux/clocksource.h
 F:     include/linux/time.h
 F:     include/linux/timex.h
 F:     include/uapi/linux/time.h
 F:     include/uapi/linux/timex.h
-F:     kernel/time/clocksource.c
-F:     kernel/time/time*.c
 F:     kernel/time/alarmtimer.c
+F:     kernel/time/clocksource.c
 F:     kernel/time/ntp.c
+F:     kernel/time/time*.c
 F:     tools/testing/selftests/timers/
 
 TIPC NETWORK LAYER
@@ -16947,34 +16950,34 @@ M:    Jon Maloy <jmaloy@redhat.com>
 M:     Ying Xue <ying.xue@windriver.com>
 L:     netdev@vger.kernel.org (core kernel code)
 L:     tipc-discussion@lists.sourceforge.net (user apps, general discussion)
-W:     http://tipc.sourceforge.net/
 S:     Maintained
+W:     http://tipc.sourceforge.net/
 F:     include/uapi/linux/tipc*.h
 F:     net/tipc/
 
 TLAN NETWORK DRIVER
 M:     Samuel Chessman <chessman@tux.org>
 L:     tlan-devel@lists.sourceforge.net (subscribers-only)
-W:     http://sourceforge.net/projects/tlan/
 S:     Maintained
+W:     http://sourceforge.net/projects/tlan/
 F:     Documentation/networking/device_drivers/ti/tlan.txt
 F:     drivers/net/ethernet/ti/tlan.*
 
 TM6000 VIDEO4LINUX DRIVER
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-media@vger.kernel.org
+S:     Odd fixes
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Odd fixes
-F:     drivers/media/usb/tm6000/
 F:     Documentation/media/v4l-drivers/tm6000*
+F:     drivers/media/usb/tm6000/
 
 TMIO/SDHI MMC DRIVER
 M:     Wolfram Sang <wsa+renesas@sang-engineering.com>
 L:     linux-mmc@vger.kernel.org
 S:     Supported
-F:     drivers/mmc/host/tmio_mmc*
 F:     drivers/mmc/host/renesas_sdhi*
+F:     drivers/mmc/host/tmio_mmc*
 F:     include/linux/mfd/tmio.h
 
 TMP401 HARDWARE MONITOR DRIVER
@@ -17005,8 +17008,8 @@ L:      tomoyo-dev-en@lists.osdn.me (subscribers-only, for developers in English)
 L:     tomoyo-users-en@lists.osdn.me (subscribers-only, for users in English)
 L:     tomoyo-dev@lists.osdn.me (subscribers-only, for developers in Japanese)
 L:     tomoyo-users@lists.osdn.me (subscribers-only, for users in Japanese)
-W:     https://tomoyo.osdn.jp/
 S:     Maintained
+W:     https://tomoyo.osdn.jp/
 F:     security/tomoyo/
 
 TOPSTAR LAPTOP EXTRAS DRIVER
@@ -17023,10 +17026,10 @@ L:    linux-kernel@vger.kernel.org
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev
 F:     Documentation/RCU/torture.txt
-F:     kernel/torture.c
-F:     kernel/rcu/rcutorture.c
-F:     kernel/rcu/rcuperf.c
 F:     kernel/locking/locktorture.c
+F:     kernel/rcu/rcuperf.c
+F:     kernel/rcu/rcutorture.c
+F:     kernel/torture.c
 
 TOSHIBA ACPI EXTRAS DRIVER
 M:     Azael Avalos <coproscefalo@gmail.com>
@@ -17048,8 +17051,8 @@ F:      drivers/platform/x86/toshiba_haps.c
 
 TOSHIBA SMM DRIVER
 M:     Jonathan Buzzard <jonathan@buzzard.org.uk>
-W:     http://www.buzzard.org.uk/toshiba/
 S:     Maintained
+W:     http://www.buzzard.org.uk/toshiba/
 F:     drivers/char/toshiba.c
 F:     include/linux/toshiba.h
 F:     include/uapi/linux/toshiba.h
@@ -17072,17 +17075,17 @@ M:    Peter Huewe <peterhuewe@gmx.de>
 M:     Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
 R:     Jason Gunthorpe <jgg@ziepe.ca>
 L:     linux-integrity@vger.kernel.org
-Q:     https://patchwork.kernel.org/project/linux-integrity/list/
+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
-S:     Maintained
 F:     drivers/char/tpm/
 
 TRACING
 M:     Steven Rostedt <rostedt@goodmis.org>
 M:     Ingo Molnar <mingo@redhat.com>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core
 F:     Documentation/trace/ftrace.rst
 F:     arch/*/*/*/ftrace.h
 F:     arch/*/kernel/ftrace.c
@@ -17097,28 +17100,21 @@ M:    Steven Rostedt <rostedt@goodmis.org>
 M:     Ingo Molnar <mingo@kernel.org>
 R:     Karol Herbst <karolherbst@gmail.com>
 R:     Pekka Paalanen <ppaalanen@gmail.com>
-S:     Maintained
 L:     linux-kernel@vger.kernel.org
 L:     nouveau@lists.freedesktop.org
-F:     kernel/trace/trace_mmiotrace.c
-F:     include/linux/mmiotrace.h
+S:     Maintained
 F:     arch/x86/mm/kmmio.c
 F:     arch/x86/mm/mmio-mod.c
 F:     arch/x86/mm/testmmiotrace.c
+F:     include/linux/mmiotrace.h
+F:     kernel/trace/trace_mmiotrace.c
 
 TRIVIAL PATCHES
 M:     Jiri Kosina <trivial@kernel.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial.git
 K:     ^Subject:.*(?i)trivial
 
-TEMPO SEMICONDUCTOR DRIVERS
-M:     Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
-S:     Maintained
-F:     sound/soc/codecs/tscs*.c
-F:     sound/soc/codecs/tscs*.h
-F:     Documentation/devicetree/bindings/sound/tscs*.txt
-
 TTY LAYER
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 M:     Jiri Slaby <jslaby@suse.com>
@@ -17127,21 +17123,21 @@ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
 F:     Documentation/driver-api/serial/
 F:     drivers/tty/
 F:     drivers/tty/serial/serial_core.c
-F:     include/linux/serial_core.h
 F:     include/linux/serial.h
+F:     include/linux/serial_core.h
 F:     include/linux/tty.h
-F:     include/uapi/linux/serial_core.h
 F:     include/uapi/linux/serial.h
+F:     include/uapi/linux/serial_core.h
 F:     include/uapi/linux/tty.h
 
 TUA9001 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 W:     http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
 F:     drivers/media/tuners/tua9001*
 
 TULIP NETWORK DRIVERS
@@ -17152,8 +17148,8 @@ F:      drivers/net/ethernet/dec/tulip/
 
 TUN/TAP driver
 M:     Maxim Krasnyansky <maxk@qti.qualcomm.com>
-W:     http://vtun.sourceforge.net/tun
 S:     Maintained
+W:     http://vtun.sourceforge.net/tun
 F:     Documentation/networking/tuntap.txt
 F:     arch/um/os-Linux/drivers/
 
@@ -17161,18 +17157,18 @@ TURBOCHANNEL SUBSYSTEM
 M:     "Maciej W. Rozycki" <macro@linux-mips.org>
 M:     Ralf Baechle <ralf@linux-mips.org>
 L:     linux-mips@vger.kernel.org
-Q:     http://patchwork.linux-mips.org/project/linux-mips/list/
 S:     Maintained
+Q:     http://patchwork.linux-mips.org/project/linux-mips/list/
 F:     drivers/tc/
 F:     include/linux/tc.h
 
 TURBOSTAT UTILITY
 M:     "Len Brown" <lenb@kernel.org>
 L:     linux-pm@vger.kernel.org
-B:     https://bugzilla.kernel.org
+S:     Supported
 Q:     https://patchwork.kernel.org/project/linux-pm/list/
+B:     https://bugzilla.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git turbostat
-S:     Supported
 F:     tools/power/x86/turbostat/
 
 TW5864 VIDEO4LINUX DRIVER
@@ -17187,17 +17183,17 @@ F:    drivers/media/pci/tw5864/
 TW68 VIDEO4LINUX DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Odd Fixes
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/pci/tw68/
 
 TW686X VIDEO4LINUX DRIVER
 M:     Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     http://linuxtv.org
 S:     Maintained
+W:     http://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/pci/tw686x/
 
 UACCE ACCELERATOR FRAMEWORK
@@ -17215,24 +17211,24 @@ F:    include/uapi/misc/uacce/
 UBI FILE SYSTEM (UBIFS)
 M:     Richard Weinberger <richard@nod.at>
 L:     linux-mtd@lists.infradead.org
+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
-W:     http://www.linux-mtd.infradead.org/doc/ubifs.html
-S:     Supported
 F:     Documentation/filesystems/ubifs.rst
 F:     fs/ubifs/
 
 UCLINUX (M68KNOMMU AND COLDFIRE)
 M:     Greg Ungerer <gerg@linux-m68k.org>
-W:     http://www.linux-m68k.org/
-W:     http://www.uclinux.org/
 L:     linux-m68k@lists.linux-m68k.org
 L:     uclinux-dev@uclinux.org  (subscribers-only)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu.git
 S:     Maintained
-F:     arch/m68k/coldfire/
-F:     arch/m68k/68*/
+W:     http://www.linux-m68k.org/
+W:     http://www.uclinux.org/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu.git
 F:     arch/m68k/*/*_no.*
+F:     arch/m68k/68*/
+F:     arch/m68k/coldfire/
 F:     arch/m68k/include/asm/*_no.*
 
 UDF FILESYSTEM
@@ -17275,21 +17271,21 @@ F:    fs/unicode/
 
 UNICORE32 ARCHITECTURE
 M:     Guan Xuetao <gxt@pku.edu.cn>
-W:     http://mprc.pku.edu.cn/~guanxuetao/linux
 S:     Maintained
+W:     http://mprc.pku.edu.cn/~guanxuetao/linux
 T:     git git://github.com/gxt/linux.git
 F:     arch/unicore32/
 
 UNIFDEF
 M:     Tony Finch <dot@dotat.at>
-W:     http://dotat.at/prog/unifdef
 S:     Maintained
+W:     http://dotat.at/prog/unifdef
 F:     scripts/unifdef.c
 
 UNIFORM CDROM DRIVER
 M:     Jens Axboe <axboe@kernel.dk>
-W:     http://www.kernel.dk
 S:     Maintained
+W:     http://www.kernel.dk
 F:     Documentation/cdrom/
 F:     drivers/cdrom/cdrom.c
 F:     include/linux/cdrom.h
@@ -17299,9 +17295,9 @@ UNISYS S-PAR DRIVERS
 M:     David Kershner <david.kershner@unisys.com>
 L:     sparmaintainer@unisys.com (Unisys internal)
 S:     Supported
-F:     include/linux/visorbus.h
-F:     drivers/visorbus/
 F:     drivers/staging/unisys/
+F:     drivers/visorbus/
+F:     include/linux/visorbus.h
 
 UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER
 R:     Alim Akhtar <alim.akhtar@samsung.com>
@@ -17326,11 +17322,11 @@ F:    drivers/scsi/ufs/ufs-mediatek*
 
 UNSORTED BLOCK IMAGES (UBI)
 M:     Richard Weinberger <richard@nod.at>
-W:     http://www.linux-mtd.infradead.org/
 L:     linux-mtd@lists.infradead.org
+S:     Supported
+W:     http://www.linux-mtd.infradead.org/
 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
-S:     Supported
 F:     drivers/mtd/ubi/
 F:     include/linux/mtd/ubi.h
 F:     include/uapi/mtd/ubi-user.h
@@ -17338,8 +17334,8 @@ F:      include/uapi/mtd/ubi-user.h
 USB "USBNET" DRIVER FRAMEWORK
 M:     Oliver Neukum <oneukum@suse.com>
 L:     netdev@vger.kernel.org
-W:     http://www.linux-usb.org/usbnet
 S:     Maintained
+W:     http://www.linux-usb.org/usbnet
 F:     drivers/net/usb/usbnet.c
 F:     include/linux/usb/usbnet.h
 
@@ -17391,8 +17387,8 @@ F:      drivers/usb/c67x00/
 USB DAVICOM DM9601 DRIVER
 M:     Peter Korsgaard <jacmet@sunsite.dk>
 L:     netdev@vger.kernel.org
-W:     http://www.linux-usb.org/usbnet
 S:     Maintained
+W:     http://www.linux-usb.org/usbnet
 F:     drivers/net/usb/dm9601.c
 
 USB EHCI DRIVER
@@ -17405,9 +17401,9 @@ F:      drivers/usb/host/ehci*
 USB GADGET/PERIPHERAL SUBSYSTEM
 M:     Felipe Balbi <balbi@kernel.org>
 L:     linux-usb@vger.kernel.org
+S:     Maintained
 W:     http://www.linux-usb.org/gadget
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
-S:     Maintained
 F:     drivers/usb/gadget/
 F:     include/linux/usb/gadget*
 
@@ -17415,8 +17411,8 @@ USB HID/HIDBP DRIVERS (USB KEYBOARDS, MICE, REMOTE CONTROLS, ...)
 M:     Jiri Kosina <jikos@kernel.org>
 M:     Benjamin Tissoires <benjamin.tissoires@redhat.com>
 L:     linux-usb@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
 F:     Documentation/hid/hiddev.rst
 F:     drivers/hid/usbhid/
 
@@ -17460,8 +17456,8 @@ F:      drivers/usb/storage/
 USB MIDI DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 F:     sound/usb/midi.*
 
 USB NETWORKING DRIVERS
@@ -17478,9 +17474,9 @@ F:      drivers/usb/host/ohci*
 
 USB OTG FSM (Finite State Machine)
 M:     Peter Chen <Peter.Chen@nxp.com>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
 L:     linux-usb@vger.kernel.org
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
 F:     drivers/usb/common/usb-otg-fsm.c
 
 USB OVER IP DRIVER
@@ -17491,23 +17487,23 @@ L:    linux-usb@vger.kernel.org
 S:     Maintained
 F:     Documentation/usb/usbip_protocol.rst
 F:     drivers/usb/usbip/
-F:     tools/usb/usbip/
 F:     tools/testing/selftests/drivers/usb/usbip/
+F:     tools/usb/usbip/
 
 USB PEGASUS DRIVER
 M:     Petko Manolov <petkan@nucleusys.com>
 L:     linux-usb@vger.kernel.org
 L:     netdev@vger.kernel.org
-T:     git git://github.com/petkan/pegasus.git
-W:     https://github.com/petkan/pegasus
 S:     Maintained
+W:     https://github.com/petkan/pegasus
+T:     git git://github.com/petkan/pegasus.git
 F:     drivers/net/usb/pegasus.*
 
 USB PHY LAYER
 M:     Felipe Balbi <balbi@kernel.org>
 L:     linux-usb@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 F:     drivers/usb/phy/
 
 USB PRINTER DRIVER (usblp)
@@ -17527,16 +17523,16 @@ USB RTL8150 DRIVER
 M:     Petko Manolov <petkan@nucleusys.com>
 L:     linux-usb@vger.kernel.org
 L:     netdev@vger.kernel.org
-T:     git git://github.com/petkan/rtl8150.git
-W:     https://github.com/petkan/rtl8150
 S:     Maintained
+W:     https://github.com/petkan/rtl8150
+T:     git git://github.com/petkan/rtl8150.git
 F:     drivers/net/usb/rtl8150.c
 
 USB SERIAL SUBSYSTEM
 M:     Johan Hovold <johan@kernel.org>
 L:     linux-usb@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git
 F:     Documentation/usb/usb-serial.rst
 F:     drivers/usb/serial/
 F:     include/linux/usb/serial.h
@@ -17557,9 +17553,9 @@ F:      drivers/net/usb/smsc95xx.*
 USB SUBSYSTEM
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 L:     linux-usb@vger.kernel.org
+S:     Supported
 W:     http://www.linux-usb.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
-S:     Supported
 F:     Documentation/devicetree/bindings/usb/
 F:     Documentation/usb/
 F:     drivers/usb/
@@ -17606,18 +17602,18 @@ USB VIDEO CLASS
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-uvc-devel@lists.sourceforge.net (subscribers-only)
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     http://www.ideasonboard.org/uvc/
 S:     Maintained
+W:     http://www.ideasonboard.org/uvc/
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/usb/uvc/
 F:     include/uapi/linux/uvcvideo.h
 
 USB VISION DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Odd Fixes
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/staging/media/usbvision/
 
 USB WEBCAM GADGET
@@ -17638,22 +17634,22 @@ USB XHCI DRIVER
 M:     Mathias Nyman <mathias.nyman@intel.com>
 L:     linux-usb@vger.kernel.org
 S:     Supported
-F:     drivers/usb/host/xhci*
 F:     drivers/usb/host/pci-quirks*
+F:     drivers/usb/host/xhci*
 
 USB ZD1201 DRIVER
 L:     linux-wireless@vger.kernel.org
-W:     http://linux-lc100020.sourceforge.net
 S:     Orphan
+W:     http://linux-lc100020.sourceforge.net
 F:     drivers/net/wireless/zydas/zd1201.*
 
 USB ZR364XX DRIVER
 M:     Antoine Jacquet <royale@zerezo.com>
 L:     linux-usb@vger.kernel.org
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     http://royale.zerezo.com/zr364xx/
 S:     Maintained
+W:     http://royale.zerezo.com/zr364xx/
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/media/v4l-drivers/zr364xx*
 F:     drivers/media/usb/zr364xx/
 
@@ -17662,10 +17658,10 @@ M:    Jeff Dike <jdike@addtoit.com>
 M:     Richard Weinberger <richard@nod.at>
 M:     Anton Ivanov <anton.ivanov@cambridgegreys.com>
 L:     linux-um@lists.infradead.org
+S:     Maintained
 W:     http://user-mode-linux.sourceforge.net
 Q:     https://patchwork.ozlabs.org/project/linux-um/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml.git
-S:     Maintained
 F:     Documentation/virt/uml/
 F:     arch/um/
 F:     arch/x86/um/
@@ -17674,16 +17670,16 @@ F:    fs/hostfs/
 USERSPACE COPYIN/COPYOUT (UIOVEC)
 M:     Alexander Viro <viro@zeniv.linux.org.uk>
 S:     Maintained
-F:     lib/iov_iter.c
 F:     include/linux/uio.h
+F:     lib/iov_iter.c
 
 USERSPACE DMA BUFFER DRIVER
 M:     Gerd Hoffmann <kraxel@redhat.com>
-S:     Maintained
 L:     dri-devel@lists.freedesktop.org
+S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     drivers/dma-buf/udmabuf.c
 F:     include/uapi/linux/udmabuf.h
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 
 USERSPACE I/O (UIO)
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
@@ -17696,29 +17692,36 @@ F:    include/linux/uio_driver.h
 UTIL-LINUX PACKAGE
 M:     Karel Zak <kzak@redhat.com>
 L:     util-linux@vger.kernel.org
+S:     Maintained
 W:     http://en.wikipedia.org/wiki/Util-linux
 T:     git git://git.kernel.org/pub/scm/utils/util-linux/util-linux.git
-S:     Maintained
 
 UUID HELPERS
 M:     Christoph Hellwig <hch@lst.de>
 R:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 L:     linux-kernel@vger.kernel.org
+S:     Maintained
 T:     git git://git.infradead.org/users/hch/uuid.git
-F:     lib/uuid.c
-F:     lib/test_uuid.c
 F:     include/linux/uuid.h
 F:     include/uapi/linux/uuid.h
-S:     Maintained
+F:     lib/test_uuid.c
+F:     lib/uuid.c
 
 UVESAFB DRIVER
 M:     Michal Januszewski <spock@gentoo.org>
 L:     linux-fbdev@vger.kernel.org
-W:     https://github.com/mjanusz/v86d
 S:     Maintained
+W:     https://github.com/mjanusz/v86d
 F:     Documentation/fb/uvesafb.rst
 F:     drivers/video/fbdev/uvesafb.*
 
+Ux500 CLOCK DRIVERS
+M:     Ulf Hansson <ulf.hansson@linaro.org>
+L:     linux-clk@vger.kernel.org
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     drivers/clk/ux500/
+
 VF610 NAND DRIVER
 M:     Stefan Agner <stefan@agner.ch>
 L:     linux-mtd@lists.infradead.org
@@ -17735,8 +17738,8 @@ VFIO DRIVER
 M:     Alex Williamson <alex.williamson@redhat.com>
 R:     Cornelia Huck <cohuck@redhat.com>
 L:     kvm@vger.kernel.org
-T:     git git://github.com/awilliam/linux-vfio.git
 S:     Maintained
+T:     git git://github.com/awilliam/linux-vfio.git
 F:     Documentation/driver-api/vfio.rst
 F:     drivers/vfio/
 F:     include/linux/vfio.h
@@ -17760,10 +17763,10 @@ F:    drivers/vfio/platform/
 VGA_SWITCHEROO
 R:     Lukas Wunner <lukas@wunner.de>
 S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     Documentation/gpu/vga-switcheroo.rst
 F:     drivers/gpu/vga/vga_switcheroo.c
 F:     include/linux/vga_switcheroo.h
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 
 VIA RHINE NETWORK DRIVER
 S:     Orphan
@@ -17779,10 +17782,10 @@ VIA UNICHROME(PRO)/CHROME9 FRAMEBUFFER DRIVER
 M:     Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
 L:     linux-fbdev@vger.kernel.org
 S:     Maintained
+F:     drivers/video/fbdev/via/
 F:     include/linux/via-core.h
 F:     include/linux/via-gpio.h
 F:     include/linux/via_i2c.h
-F:     drivers/video/fbdev/via/
 
 VIA VELOCITY NETWORK DRIVER
 M:     Francois Romieu <romieu@fr.zoreil.com>
@@ -17791,18 +17794,12 @@ S:    Maintained
 F:     drivers/net/ethernet/via/via-velocity.*
 
 VICODEC VIRTUAL CODEC DRIVER
-M:     Hans Verkuil <hverkuil-cisco@xs4all.nl>
-L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
-S:     Maintained
-F:     drivers/media/platform/vicodec/*
-
-VIDEO MULTIPLEXER DRIVER
-M:     Philipp Zabel <p.zabel@pengutronix.de>
+M:     Hans Verkuil <hverkuil-cisco@xs4all.nl>
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     drivers/media/platform/video-mux.c
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
+F:     drivers/media/platform/vicodec/*
 
 VIDEO I2C POLLING DRIVER
 M:     Matt Ranostay <matt.ranostay@konsulko.com>
@@ -17810,6 +17807,12 @@ L:     linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/media/i2c/video-i2c.c
 
+VIDEO MULTIPLEXER DRIVER
+M:     Philipp Zabel <p.zabel@pengutronix.de>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     drivers/media/platform/video-mux.c
+
 VIDEOBUF2 FRAMEWORK
 M:     Pawel Osciak <pawel@osciak.com>
 M:     Marek Szyprowski <m.szyprowski@samsung.com>
@@ -17824,9 +17827,9 @@ VIMC VIRTUAL MEDIA CONTROLLER DRIVER
 M:     Helen Koike <helen.koike@collabora.com>
 R:     Shuah Khan <skhan@linuxfoundation.org>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/platform/vimc/*
 
 VIRT LIB
@@ -17843,19 +17846,32 @@ L:    kvm@vger.kernel.org
 L:     virtualization@lists.linux-foundation.org
 L:     netdev@vger.kernel.org
 S:     Maintained
+F:     drivers/net/vsockmon.c
+F:     drivers/vhost/vsock.c
 F:     include/linux/virtio_vsock.h
 F:     include/uapi/linux/virtio_vsock.h
-F:     include/uapi/linux/vsockmon.h
 F:     include/uapi/linux/vm_sockets_diag.h
-F:     net/vmw_vsock/diag.c
+F:     include/uapi/linux/vsockmon.h
 F:     net/vmw_vsock/af_vsock_tap.c
-F:     net/vmw_vsock/virtio_transport_common.c
+F:     net/vmw_vsock/diag.c
 F:     net/vmw_vsock/virtio_transport.c
+F:     net/vmw_vsock/virtio_transport_common.c
 F:     net/vmw_vsock/vsock_loopback.c
-F:     drivers/net/vsockmon.c
-F:     drivers/vhost/vsock.c
 F:     tools/testing/vsock/
 
+VIRTIO BLOCK AND SCSI DRIVERS
+M:     "Michael S. Tsirkin" <mst@redhat.com>
+M:     Jason Wang <jasowang@redhat.com>
+R:     Paolo Bonzini <pbonzini@redhat.com>
+R:     Stefan Hajnoczi <stefanha@redhat.com>
+L:     virtualization@lists.linux-foundation.org
+S:     Maintained
+F:     drivers/block/virtio_blk.c
+F:     drivers/scsi/virtio_scsi.c
+F:     drivers/vhost/scsi.c
+F:     include/uapi/linux/virtio_blk.h
+F:     include/uapi/linux/virtio_scsi.h
+
 VIRTIO CONSOLE DRIVER
 M:     Amit Shah <amit@kernel.org>
 L:     virtualization@lists.linux-foundation.org
@@ -17870,27 +17886,16 @@ M:    Jason Wang <jasowang@redhat.com>
 L:     virtualization@lists.linux-foundation.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/virtio/
-F:     drivers/virtio/
-F:     tools/virtio/
-F:     drivers/net/virtio_net.c
 F:     drivers/block/virtio_blk.c
+F:     drivers/crypto/virtio/
+F:     drivers/net/virtio_net.c
+F:     drivers/vdpa/
+F:     drivers/virtio/
+F:     include/linux/vdpa.h
 F:     include/linux/virtio*.h
 F:     include/uapi/linux/virtio_*.h
-F:     drivers/crypto/virtio/
 F:     mm/balloon_compaction.c
-
-VIRTIO BLOCK AND SCSI DRIVERS
-M:     "Michael S. Tsirkin" <mst@redhat.com>
-M:     Jason Wang <jasowang@redhat.com>
-R:     Paolo Bonzini <pbonzini@redhat.com>
-R:     Stefan Hajnoczi <stefanha@redhat.com>
-L:     virtualization@lists.linux-foundation.org
-S:     Maintained
-F:     drivers/block/virtio_blk.c
-F:     drivers/scsi/virtio_scsi.c
-F:     include/uapi/linux/virtio_blk.h
-F:     include/uapi/linux/virtio_scsi.h
-F:     drivers/vhost/scsi.c
+F:     tools/virtio/
 
 VIRTIO CRYPTO DRIVER
 M:     Gonglei <arei.gonglei@huawei.com>
@@ -17907,8 +17912,8 @@ L:      linux-s390@vger.kernel.org
 L:     virtualization@lists.linux-foundation.org
 L:     kvm@vger.kernel.org
 S:     Supported
-F:     drivers/s390/virtio/
 F:     arch/s390/include/uapi/asm/virtio-ccw.h
+F:     drivers/s390/virtio/
 
 VIRTIO FILE SYSTEM
 M:     Vivek Goyal <vgoyal@redhat.com>
@@ -17916,19 +17921,19 @@ M:    Stefan Hajnoczi <stefanha@redhat.com>
 M:     Miklos Szeredi <miklos@szeredi.hu>
 L:     virtualization@lists.linux-foundation.org
 L:     linux-fsdevel@vger.kernel.org
-W:     https://virtio-fs.gitlab.io/
 S:     Supported
+W:     https://virtio-fs.gitlab.io/
+F:     Documentation/filesystems/virtiofs.rst
 F:     fs/fuse/virtio_fs.c
 F:     include/uapi/linux/virtio_fs.h
-F:     Documentation/filesystems/virtiofs.rst
 
 VIRTIO GPU DRIVER
 M:     David Airlie <airlied@linux.ie>
 M:     Gerd Hoffmann <kraxel@redhat.com>
 L:     dri-devel@lists.freedesktop.org
 L:     virtualization@lists.linux-foundation.org
-T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
+T:     git git://anongit.freedesktop.org/drm/drm-misc
 F:     drivers/gpu/drm/virtio/
 F:     include/uapi/linux/virtio_gpu.h
 
@@ -17938,9 +17943,10 @@ M:     Jason Wang <jasowang@redhat.com>
 L:     kvm@vger.kernel.org
 L:     virtualization@lists.linux-foundation.org
 L:     netdev@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git
 F:     drivers/vhost/
+F:     include/linux/vhost_iotlb.h
 F:     include/uapi/linux/vhost.h
 
 VIRTIO INPUT DRIVER
@@ -17961,9 +17967,9 @@ M:      Hans de Goede <hdegoede@redhat.com>
 M:     Arnd Bergmann <arnd@arndb.de>
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 S:     Maintained
+F:     drivers/virt/vboxguest/
 F:     include/linux/vbox_utils.h
 F:     include/uapi/linux/vbox*.h
-F:     drivers/virt/vboxguest/
 
 VIRTUAL BOX SHARED FOLDER VFS DRIVER
 M:     Hans de Goede <hdegoede@redhat.com>
@@ -17988,9 +17994,9 @@ F:      net/dsa/tag_ocelot.c
 VIVID VIRTUAL VIDEO DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
-W:     https://linuxtv.org
 S:     Maintained
+W:     https://linuxtv.org
+T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/platform/vivid/*
 
 VLYNQ BUS
@@ -18024,15 +18030,8 @@ M:     Thomas Hellstrom <thellstrom@vmware.com>
 M:     "VMware, Inc." <pv-drivers@vmware.com>
 L:     virtualization@lists.linux-foundation.org
 S:     Supported
-F:     arch/x86/kernel/cpu/vmware.c
 F:     arch/x86/include/asm/vmware.h
-
-VMWARE VIRTUAL PTP CLOCK DRIVER
-M:     Vivek Thampi <vithampi@vmware.com>
-M:     "VMware, Inc." <pv-drivers@vmware.com>
-L:     netdev@vger.kernel.org
-S:     Supported
-F:     drivers/ptp/ptp_vmw.c
+F:     arch/x86/kernel/cpu/vmware.c
 
 VMWARE PVRDMA DRIVER
 M:     Adit Ranadive <aditr@vmware.com>
@@ -18049,6 +18048,13 @@ S:     Maintained
 F:     drivers/scsi/vmw_pvscsi.c
 F:     drivers/scsi/vmw_pvscsi.h
 
+VMWARE VIRTUAL PTP CLOCK DRIVER
+M:     Vivek Thampi <vithampi@vmware.com>
+M:     "VMware, Inc." <pv-drivers@vmware.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     drivers/ptp/ptp_vmw.c
+
 VMWARE VMMOUSE SUBDRIVER
 M:     "VMware Graphics" <linux-graphics-maintainer@vmware.com>
 M:     "VMware, Inc." <pv-drivers@vmware.com>
@@ -18074,9 +18080,9 @@ VOLTAGE AND CURRENT REGULATOR FRAMEWORK
 M:     Liam Girdwood <lgirdwood@gmail.com>
 M:     Mark Brown <broonie@kernel.org>
 L:     linux-kernel@vger.kernel.org
+S:     Supported
 W:     http://www.slimlogic.co.uk/?p=48
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git
-S:     Supported
 F:     Documentation/devicetree/bindings/regulator/
 F:     Documentation/power/regulator/
 F:     drivers/regulator/
@@ -18089,8 +18095,8 @@ M:      David Ahern <dsahern@kernel.org>
 M:     Shrijeet Mukherjee <shrijeet@gmail.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/vrf.c
 F:     Documentation/networking/vrf.txt
+F:     drivers/net/vrf.c
 
 VSPRINTF
 M:     Petr Mladek <pmladek@suse.com>
@@ -18098,11 +18104,11 @@ M:    Steven Rostedt <rostedt@goodmis.org>
 M:     Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
 R:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 R:     Rasmus Villemoes <linux@rasmusvillemoes.dk>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk.git
 S:     Maintained
-F:     lib/vsprintf.c
-F:     lib/test_printf.c
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk.git
 F:     Documentation/core-api/printk-formats.rst
+F:     lib/test_printf.c
+F:     lib/vsprintf.c
 
 VT1211 HARDWARE MONITOR DRIVER
 M:     Juerg Haefliger <juergh@gmail.com>
@@ -18166,9 +18172,9 @@ WATCHDOG DEVICE DRIVERS
 M:     Wim Van Sebroeck <wim@linux-watchdog.org>
 M:     Guenter Roeck <linux@roeck-us.net>
 L:     linux-watchdog@vger.kernel.org
+S:     Maintained
 W:     http://www.linux-watchdog.org/
 T:     git git://www.linux-watchdog.org/linux-watchdog.git
-S:     Maintained
 F:     Documentation/devicetree/bindings/watchdog/
 F:     Documentation/watchdog/
 F:     drivers/watchdog/
@@ -18218,11 +18224,6 @@ M:     David Härdeman <david@hardeman.nu>
 S:     Maintained
 F:     drivers/media/rc/winbond-cir.c
 
-RCMM REMOTE CONTROLS DECODER
-M:     Patrick Lerda <patrick9876@free.fr>
-S:     Maintained
-F:     drivers/media/rc/ir-rcmm-decoder.c
-
 WINSYSTEMS EBC-C384 WATCHDOG DRIVER
 M:     William Breathitt Gray <vilhelm.gray@gmail.com>
 L:     linux-watchdog@vger.kernel.org
@@ -18237,11 +18238,11 @@ F:    drivers/gpio/gpio-ws16c48.c
 
 WIREGUARD SECURE NETWORK TUNNEL
 M:     Jason A. Donenfeld <Jason@zx2c4.com>
+L:     wireguard@lists.zx2c4.com
+L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/wireguard/
 F:     tools/testing/selftests/wireguard/
-L:     wireguard@lists.zx2c4.com
-L:     netdev@vger.kernel.org
 
 WISTRON LAPTOP BUTTON DRIVER
 M:     Miloslav Trmac <mitr@volny.cz>
@@ -18255,32 +18256,32 @@ F:    drivers/net/wireless/wl3501*
 
 WOLFSON MICROELECTRONICS DRIVERS
 L:     patches@opensource.cirrus.com
-T:     git https://github.com/CirrusLogic/linux-drivers.git
-W:     https://github.com/CirrusLogic/linux-drivers/wiki
 S:     Supported
-F:     Documentation/hwmon/wm83??.rst
+W:     https://github.com/CirrusLogic/linux-drivers/wiki
+T:     git https://github.com/CirrusLogic/linux-drivers.git
 F:     Documentation/devicetree/bindings/extcon/extcon-arizona.txt
-F:     Documentation/devicetree/bindings/regulator/arizona-regulator.txt
 F:     Documentation/devicetree/bindings/mfd/arizona.txt
 F:     Documentation/devicetree/bindings/mfd/wm831x.txt
+F:     Documentation/devicetree/bindings/regulator/arizona-regulator.txt
 F:     Documentation/devicetree/bindings/sound/wlf,arizona.txt
+F:     Documentation/hwmon/wm83??.rst
 F:     arch/arm/mach-s3c64xx/mach-crag6410*
 F:     drivers/clk/clk-wm83*.c
 F:     drivers/extcon/extcon-arizona.c
-F:     drivers/leds/leds-wm83*.c
 F:     drivers/gpio/gpio-*wm*.c
 F:     drivers/gpio/gpio-arizona.c
 F:     drivers/hwmon/wm83??-hwmon.c
 F:     drivers/input/misc/wm831x-on.c
 F:     drivers/input/touchscreen/wm831x-ts.c
 F:     drivers/input/touchscreen/wm97*.c
+F:     drivers/leds/leds-wm83*.c
 F:     drivers/mfd/arizona*
-F:     drivers/mfd/wm*.c
 F:     drivers/mfd/cs47l24*
+F:     drivers/mfd/wm*.c
 F:     drivers/power/supply/wm83*.c
-F:     drivers/rtc/rtc-wm83*.c
-F:     drivers/regulator/wm8*.c
 F:     drivers/regulator/arizona*
+F:     drivers/regulator/wm8*.c
+F:     drivers/rtc/rtc-wm83*.c
 F:     drivers/video/backlight/wm83*_bl.c
 F:     drivers/watchdog/wm83*_wdt.c
 F:     include/linux/mfd/arizona/
@@ -18291,17 +18292,17 @@ F:    include/linux/regulator/arizona*
 F:     include/linux/wm97xx.h
 F:     include/sound/wm????.h
 F:     sound/soc/codecs/arizona.?
-F:     sound/soc/codecs/wm*
 F:     sound/soc/codecs/cs47l24*
+F:     sound/soc/codecs/wm*
 
 WORKQUEUE
 M:     Tejun Heo <tj@kernel.org>
 R:     Lai Jiangshan <jiangshanlai@gmail.com>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git
+F:     Documentation/core-api/workqueue.rst
 F:     include/linux/workqueue.h
 F:     kernel/workqueue.c
-F:     Documentation/core-api/workqueue.rst
 
 X-POWERS AXP288 PMIC DRIVERS
 M:     Hans de Goede <hdegoede@redhat.com>
@@ -18327,11 +18328,11 @@ X86 ARCHITECTURE (32-BIT AND 64-BIT)
 M:     Thomas Gleixner <tglx@linutronix.de>
 M:     Ingo Molnar <mingo@redhat.com>
 M:     Borislav Petkov <bp@alien8.de>
-R:     "H. Peter Anvin" <hpa@zytor.com>
 M:     x86@kernel.org
+R:     "H. Peter Anvin" <hpa@zytor.com>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core
 F:     Documentation/devicetree/bindings/x86/
 F:     Documentation/x86/
 F:     arch/x86/
@@ -18339,8 +18340,8 @@ F:      arch/x86/
 X86 ENTRY CODE
 M:     Andy Lutomirski <luto@kernel.org>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/asm
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/asm
 F:     arch/x86/entry/
 
 X86 MCE INFRASTRUCTURE
@@ -18360,8 +18361,8 @@ M:      Dave Hansen <dave.hansen@linux.intel.com>
 M:     Andy Lutomirski <luto@kernel.org>
 M:     Peter Zijlstra <peterz@infradead.org>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/mm
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/mm
 F:     arch/x86/mm/
 
 X86 PLATFORM DRIVERS
@@ -18378,15 +18379,15 @@ R:    Darren Hart <dvhart@infradead.org>
 R:     Andy Shevchenko <andy@infradead.org>
 L:     platform-driver-x86@vger.kernel.org
 L:     x86@kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core
 F:     arch/x86/platform
 
 X86 VDSO
 M:     Andy Lutomirski <luto@kernel.org>
 L:     linux-kernel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/vdso
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/vdso
 F:     arch/x86/entry/vdso/
 
 XARRAY
@@ -18394,24 +18395,24 @@ M:    Matthew Wilcox <willy@infradead.org>
 L:     linux-fsdevel@vger.kernel.org
 S:     Supported
 F:     Documentation/core-api/xarray.rst
-F:     lib/idr.c
-F:     lib/xarray.c
 F:     include/linux/idr.h
 F:     include/linux/xarray.h
+F:     lib/idr.c
+F:     lib/xarray.c
 F:     tools/testing/radix-tree
 
 XBOX DVD IR REMOTE
 M:     Benjamin Valentin <benpicco@googlemail.com>
 S:     Maintained
-F:     drivers/media/rc/xbox_remote.c
 F:     drivers/media/rc/keymaps/rc-xbox-dvd.c
+F:     drivers/media/rc/xbox_remote.c
 
 XC2028/3028 TUNER DRIVER
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
-S:     Maintained
 F:     drivers/media/tuners/tuner-xc2028.*
 
 XDP (eXpress Data Path)
@@ -18424,13 +18425,13 @@ M:    John Fastabend <john.fastabend@gmail.com>
 L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Supported
-F:     net/core/xdp.c
 F:     include/net/xdp.h
-F:     kernel/bpf/devmap.c
-F:     kernel/bpf/cpumap.c
 F:     include/trace/events/xdp.h
-K:     xdp
+F:     kernel/bpf/cpumap.c
+F:     kernel/bpf/devmap.c
+F:     net/core/xdp.c
 N:     xdp
+K:     xdp
 
 XDP SOCKETS (AF_XDP)
 M:     Björn Töpel <bjorn.topel@intel.com>
@@ -18447,40 +18448,40 @@ M:    Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
 M:     Roger Pau Monné <roger.pau@citrix.com>
 L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
 S:     Supported
-F:     drivers/block/xen-blkback/*
 F:     drivers/block/xen*
+F:     drivers/block/xen-blkback/*
 
 XEN HYPERVISOR ARM
 M:     Stefano Stabellini <sstabellini@kernel.org>
 L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm/xen/
 F:     arch/arm/include/asm/xen/
+F:     arch/arm/xen/
 
 XEN HYPERVISOR ARM64
 M:     Stefano Stabellini <sstabellini@kernel.org>
 L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm64/xen/
 F:     arch/arm64/include/asm/xen/
+F:     arch/arm64/xen/
 
 XEN HYPERVISOR INTERFACE
 M:     Boris Ostrovsky <boris.ostrovsky@oracle.com>
 M:     Juergen Gross <jgross@suse.com>
 R:     Stefano Stabellini <sstabellini@kernel.org>
 L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.git
 S:     Supported
-F:     arch/x86/xen/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.git
+F:     Documentation/ABI/stable/sysfs-hypervisor-xen
+F:     Documentation/ABI/testing/sysfs-hypervisor-xen
+F:     arch/x86/include/asm/pvclock-abi.h
+F:     arch/x86/include/asm/xen/
 F:     arch/x86/platform/pvh/
+F:     arch/x86/xen/
 F:     drivers/*/xen-*front.c
 F:     drivers/xen/
-F:     arch/x86/include/asm/xen/
-F:     arch/x86/include/asm/pvclock-abi.h
-F:     include/xen/
 F:     include/uapi/xen/
-F:     Documentation/ABI/stable/sysfs-hypervisor-xen
-F:     Documentation/ABI/testing/sysfs-hypervisor-xen
+F:     include/xen/
 
 XEN NETWORK BACKEND DRIVER
 M:     Wei Liu <wei.liu@kernel.org>
@@ -18506,6 +18507,13 @@ F:     drivers/scsi/xen-scsifront.c
 F:     drivers/xen/xen-scsiback.c
 F:     include/xen/interface/io/vscsiif.h
 
+XEN SOUND FRONTEND DRIVER
+M:     Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
+L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Supported
+F:     sound/xen/*
+
 XEN SWIOTLB SUBSYSTEM
 M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
 L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
@@ -18514,22 +18522,15 @@ S:    Supported
 F:     arch/x86/xen/*swiotlb*
 F:     drivers/xen/*swiotlb*
 
-XEN SOUND FRONTEND DRIVER
-M:     Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
-L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
-L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-S:     Supported
-F:     sound/xen/*
-
 XFS FILESYSTEM
 M:     Darrick J. Wong <darrick.wong@oracle.com>
 M:     linux-xfs@vger.kernel.org
 L:     linux-xfs@vger.kernel.org
+S:     Supported
 W:     http://xfs.org/
 T:     git git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git
-S:     Supported
-F:     Documentation/admin-guide/xfs.rst
 F:     Documentation/ABI/testing/sysfs-fs-xfs
+F:     Documentation/admin-guide/xfs.rst
 F:     Documentation/filesystems/xfs-delayed-logging-design.txt
 F:     Documentation/filesystems/xfs-self-describing-metadata.txt
 F:     fs/xfs/
@@ -18549,6 +18550,17 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/net/can/xilinx_can.txt
 F:     drivers/net/can/xilinx_can.c
 
+XILINX SD-FEC IP CORES
+M:     Derek Kiernan <derek.kiernan@xilinx.com>
+M:     Dragan Cvetic <dragan.cvetic@xilinx.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/misc/xlnx,sd-fec.txt
+F:     Documentation/misc-devices/xilinx_sdfec.rst
+F:     drivers/misc/Kconfig
+F:     drivers/misc/Makefile
+F:     drivers/misc/xilinx_sdfec.c
+F:     include/uapi/misc/xilinx_sdfec.h
+
 XILINX UARTLITE SERIAL DRIVER
 M:     Peter Korsgaard <jacmet@sunsite.dk>
 L:     linux-serial@vger.kernel.org
@@ -18559,23 +18571,12 @@ XILINX VIDEO IP CORES
 M:     Hyun Kwon <hyun.kwon@xilinx.com>
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-media@vger.kernel.org
-T:     git git://linuxtv.org/media_tree.git
 S:     Supported
+T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/xilinx/
 F:     drivers/media/platform/xilinx/
 F:     include/uapi/linux/xilinx-v4l2-controls.h
 
-XILINX SD-FEC IP CORES
-M:     Derek Kiernan <derek.kiernan@xilinx.com>
-M:     Dragan Cvetic <dragan.cvetic@xilinx.com>
-S:     Maintained
-F:     Documentation/devicetree/bindings/misc/xlnx,sd-fec.txt
-F:     Documentation/misc-devices/xilinx_sdfec.rst
-F:     drivers/misc/xilinx_sdfec.c
-F:     drivers/misc/Kconfig
-F:     drivers/misc/Makefile
-F:     include/uapi/misc/xilinx_sdfec.h
-
 XILLYBUS DRIVER
 M:     Eli Billauer <eli.billauer@gmail.com>
 L:     linux-kernel@vger.kernel.org
@@ -18585,8 +18586,8 @@ F:      drivers/char/xillybus/
 XLP9XX I2C DRIVER
 M:     George Cherian <gcherian@marvell.com>
 L:     linux-i2c@vger.kernel.org
-W:     http://www.marvell.com
 S:     Supported
+W:     http://www.marvell.com
 F:     Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt
 F:     drivers/i2c/busses/i2c-xlp9xx.c
 
@@ -18614,10 +18615,10 @@ F:    include/linux/yam.h
 
 YAMA SECURITY MODULE
 M:     Kees Cook <keescook@chromium.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip
 S:     Supported
-F:     security/yama/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip
 F:     Documentation/admin-guide/LSM/Yama.rst
+F:     security/yama/
 
 YEALINK PHONE DRIVER
 M:     Henk Vergonet <Henk.Vergonet@gmail.com>
@@ -18628,10 +18629,10 @@ F:    drivers/input/misc/yealink.*
 
 Z8530 DRIVER FOR AX.25
 M:     Joerg Reuter <jreuter@yaina.de>
-W:     http://yaina.de/jreuter/
-W:     http://www.qsl.net/dl1bke/
 L:     linux-hams@vger.kernel.org
 S:     Maintained
+W:     http://yaina.de/jreuter/
+W:     http://www.qsl.net/dl1bke/
 F:     Documentation/networking/z8530drv.txt
 F:     drivers/net/hamradio/*scc.c
 F:     drivers/net/hamradio/z8530.h
@@ -18641,34 +18642,34 @@ M:    Seth Jennings <sjenning@redhat.com>
 M:     Dan Streetman <ddstreet@ieee.org>
 L:     linux-mm@kvack.org
 S:     Maintained
-F:     mm/zbud.c
 F:     include/linux/zbud.h
+F:     mm/zbud.c
 
 ZD1211RW WIRELESS DRIVER
 M:     Daniel Drake <dsd@gentoo.org>
 M:     Ulrich Kunitz <kune@deine-taler.de>
-W:     http://zd1211.ath.cx/wiki/DriverRewrite
 L:     linux-wireless@vger.kernel.org
 L:     zd1211-devs@lists.sourceforge.net (subscribers-only)
 S:     Maintained
+W:     http://zd1211.ath.cx/wiki/DriverRewrite
 F:     drivers/net/wireless/zydas/zd1211rw/
 
 ZD1301 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org/
 W:     http://palosaari.fi/linux/
 Q:     https://patchwork.linuxtv.org/project/linux-media/list/
-S:     Maintained
 F:     drivers/media/usb/dvb-usb-v2/zd1301*
 
 ZD1301_DEMOD MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     https://linuxtv.org/
 W:     http://palosaari.fi/linux/
 Q:     https://patchwork.linuxtv.org/project/linux-media/list/
-S:     Maintained
 F:     drivers/media/dvb-frontends/zd1301_demod*
 
 ZHAOXIN PROCESSOR SUPPORT
@@ -18682,17 +18683,17 @@ M:    Damien Le Moal <damien.lemoal@wdc.com>
 M:     Naohiro Aota <naohiro.aota@wdc.com>
 R:     Johannes Thumshirn <jth@kernel.org>
 L:     linux-fsdevel@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/zonefs.git
 S:     Maintained
-F:     fs/zonefs/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/zonefs.git
 F:     Documentation/filesystems/zonefs.rst
+F:     fs/zonefs/
 
 ZPOOL COMPRESSED PAGE STORAGE API
 M:     Dan Streetman <ddstreet@ieee.org>
 L:     linux-mm@kvack.org
 S:     Maintained
-F:     mm/zpool.c
 F:     include/linux/zpool.h
+F:     mm/zpool.c
 
 ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER
 M:     Minchan Kim <minchan@kernel.org>
@@ -18700,8 +18701,8 @@ M:      Nitin Gupta <ngupta@vflare.org>
 R:     Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
-F:     drivers/block/zram/
 F:     Documentation/admin-guide/blockdev/zram.rst
+F:     drivers/block/zram/
 
 ZS DECSTATION Z85C30 SERIAL DRIVER
 M:     "Maciej W. Rozycki" <macro@linux-mips.org>
@@ -18714,9 +18715,9 @@ M:      Nitin Gupta <ngupta@vflare.org>
 R:     Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
 L:     linux-mm@kvack.org
 S:     Maintained
-F:     mm/zsmalloc.c
-F:     include/linux/zsmalloc.h
 F:     Documentation/vm/zsmalloc.rst
+F:     include/linux/zsmalloc.h
+F:     mm/zsmalloc.c
 
 ZSWAP COMPRESSED SWAP CACHING
 M:     Seth Jennings <sjenning@redhat.com>
@@ -18729,8 +18730,8 @@ F:      mm/zswap.c
 THE REST
 M:     Linus Torvalds <torvalds@linux-foundation.org>
 L:     linux-kernel@vger.kernel.org
+S:     Buried alive in reporters
 Q:     http://patchwork.kernel.org/project/LKML/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
-S:     Buried alive in reporters
 F:     *
 F:     */
index c913429..70def49 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 VERSION = 5
-PATCHLEVEL = 6
+PATCHLEVEL = 7
 SUBLEVEL = 0
-EXTRAVERSION =
+EXTRAVERSION = -rc1
 NAME = Kleptomaniac Octopus
 
 # *DOCUMENTATION*
@@ -399,8 +399,13 @@ HOST_LFS_CFLAGS := $(shell getconf LFS_CFLAGS 2>/dev/null)
 HOST_LFS_LDFLAGS := $(shell getconf LFS_LDFLAGS 2>/dev/null)
 HOST_LFS_LIBS := $(shell getconf LFS_LIBS 2>/dev/null)
 
-HOSTCC       = gcc
-HOSTCXX      = g++
+ifneq ($(LLVM),)
+HOSTCC = clang
+HOSTCXX        = clang++
+else
+HOSTCC = gcc
+HOSTCXX        = g++
+endif
 KBUILD_HOSTCFLAGS   := -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 \
                -fomit-frame-pointer -std=gnu89 $(HOST_LFS_CFLAGS) \
                $(HOSTCFLAGS)
@@ -409,16 +414,28 @@ KBUILD_HOSTLDFLAGS  := $(HOST_LFS_LDFLAGS) $(HOSTLDFLAGS)
 KBUILD_HOSTLDLIBS   := $(HOST_LFS_LIBS) $(HOSTLDLIBS)
 
 # Make variables (CC, etc...)
-LD             = $(CROSS_COMPILE)ld
-CC             = $(CROSS_COMPILE)gcc
 CPP            = $(CC) -E
+ifneq ($(LLVM),)
+CC             = clang
+LD             = ld.lld
+AR             = llvm-ar
+NM             = llvm-nm
+OBJCOPY                = llvm-objcopy
+OBJDUMP                = llvm-objdump
+READELF                = llvm-readelf
+OBJSIZE                = llvm-size
+STRIP          = llvm-strip
+else
+CC             = $(CROSS_COMPILE)gcc
+LD             = $(CROSS_COMPILE)ld
 AR             = $(CROSS_COMPILE)ar
 NM             = $(CROSS_COMPILE)nm
-STRIP          = $(CROSS_COMPILE)strip
 OBJCOPY                = $(CROSS_COMPILE)objcopy
 OBJDUMP                = $(CROSS_COMPILE)objdump
-OBJSIZE                = $(CROSS_COMPILE)size
 READELF                = $(CROSS_COMPILE)readelf
+OBJSIZE                = $(CROSS_COMPILE)size
+STRIP          = $(CROSS_COMPILE)strip
+endif
 PAHOLE         = pahole
 LEX            = flex
 YACC           = bison
@@ -538,7 +555,7 @@ endif
 ifneq ($(GCC_TOOLCHAIN),)
 CLANG_FLAGS    += --gcc-toolchain=$(GCC_TOOLCHAIN)
 endif
-ifeq ($(if $(AS),$(shell $(AS) --version 2>&1 | head -n 1 | grep clang)),)
+ifneq ($(LLVM_IAS),1)
 CLANG_FLAGS    += -no-integrated-as
 endif
 CLANG_FLAGS    += -Werror=unknown-warning-option
@@ -747,8 +764,6 @@ ifdef CONFIG_CC_IS_CLANG
 KBUILD_CPPFLAGS += -Qunused-arguments
 KBUILD_CFLAGS += -Wno-format-invalid-specifier
 KBUILD_CFLAGS += -Wno-gnu
-# Quiet clang warning: comparison of unsigned expression < 0 is always false
-KBUILD_CFLAGS += -Wno-tautological-compare
 # CLANG uses a _MergedGlobals as optimization, but this breaks modpost, as the
 # source of a reference will be _MergedGlobals and not on of the whitelisted names.
 # See modpost pattern 2
@@ -1036,8 +1051,13 @@ init-y           := $(patsubst %/, %/built-in.a, $(init-y))
 core-y         := $(patsubst %/, %/built-in.a, $(core-y))
 drivers-y      := $(patsubst %/, %/built-in.a, $(drivers-y))
 net-y          := $(patsubst %/, %/built-in.a, $(net-y))
+libs-y2                := $(patsubst %/, %/built-in.a, $(filter %/, $(libs-y)))
+ifdef CONFIG_MODULES
+libs-y1                := $(filter-out %/, $(libs-y))
+libs-y2                += $(patsubst %/, %/lib.a, $(filter %/, $(libs-y)))
+else
 libs-y1                := $(patsubst %/, %/lib.a, $(libs-y))
-libs-y2                := $(patsubst %/, %/built-in.a, $(filter-out %.a, $(libs-y)))
+endif
 virt-y         := $(patsubst %/, %/built-in.a, $(virt-y))
 
 # Externally visible symbols (used by link-vmlinux.sh)
index f3fb284..e241bd8 100644 (file)
@@ -90,9 +90,6 @@ typedef struct page *pgtable_t;
 #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 #endif /* CONFIG_DISCONTIGMEM */
 
-#define VM_DATA_DEFAULT_FLAGS          (VM_READ | VM_WRITE | VM_EXEC | \
-                                        VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
 
index 299791c..0267aa8 100644 (file)
@@ -268,7 +268,6 @@ extern inline void pud_clear(pud_t * pudp)  { pud_val(*pudp) = 0; }
 extern inline int pte_write(pte_t pte)         { return !(pte_val(pte) & _PAGE_FOW); }
 extern inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_DIRTY; }
 extern inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
-extern inline int pte_special(pte_t pte)       { return 0; }
 
 extern inline pte_t pte_wrprotect(pte_t pte)   { pte_val(pte) |= _PAGE_FOW; return pte; }
 extern inline pte_t pte_mkclean(pte_t pte)     { pte_val(pte) &= ~(__DIRTY_BITS); return pte; }
@@ -276,7 +275,6 @@ extern inline pte_t pte_mkold(pte_t pte)    { pte_val(pte) &= ~(__ACCESS_BITS); ret
 extern inline pte_t pte_mkwrite(pte_t pte)     { pte_val(pte) &= ~_PAGE_FOW; return pte; }
 extern inline pte_t pte_mkdirty(pte_t pte)     { pte_val(pte) |= __DIRTY_BITS; return pte; }
 extern inline pte_t pte_mkyoung(pte_t pte)     { pte_val(pte) |= __ACCESS_BITS; return pte; }
-extern inline pte_t pte_mkspecial(pte_t pte)   { return pte; }
 
 #define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
 
index 0a32e8c..b0dfed0 100644 (file)
@@ -102,7 +102,7 @@ typedef pte_t * pgtable_t;
 #define virt_addr_valid(kaddr)  pfn_valid(virt_to_pfn(kaddr))
 
 /* Default Permissions for stack/heaps pages (Non Executable) */
-#define VM_DATA_DEFAULT_FLAGS   (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_NON_EXEC
 
 #define WANT_PAGE_VIRTUAL   1
 
index cabdd8f..e8e1c86 100644 (file)
@@ -1450,7 +1450,8 @@ ENTRY(efi_enter_kernel)
                @ running beyond the PoU, and so calling cache_off below from
                @ inside the PE/COFF loader allocated region is unsafe unless
                @ we explicitly clean it to the PoC.
-               adr     r0, call_cache_fn               @ region of code we will
+ ARM(          adrl    r0, call_cache_fn       )
+ THUMB(                adr     r0, call_cache_fn       )       @ region of code we will
                adr     r1, 0f                          @ run with MMU off
                bl      cache_clean_flush
                bl      cache_off
index c2b75cb..11b058a 100644 (file)
@@ -161,9 +161,7 @@ extern int pfn_valid(unsigned long);
 
 #endif /* !__ASSEMBLY__ */
 
-#define VM_DATA_DEFAULT_FLAGS \
-       (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
-        VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_TSK_EXEC
 
 #include <asm-generic/getorder.h>
 
index 0d3ea35..9e084a4 100644 (file)
@@ -211,8 +211,6 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
 #define pmd_addr_end(addr,end) (end)
 
 #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)
-#define pte_special(pte)       (0)
-static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
 
 /*
  * We don't have huge page support for short descriptors, for the moment
index 0483cf4..befc8fc 100644 (file)
@@ -243,19 +243,8 @@ static inline void __sync_icache_dcache(pte_t pteval)
 extern void __sync_icache_dcache(pte_t pteval);
 #endif
 
-static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
-                             pte_t *ptep, pte_t pteval)
-{
-       unsigned long ext = 0;
-
-       if (addr < TASK_SIZE && pte_valid_user(pteval)) {
-               if (!pte_special(pteval))
-                       __sync_icache_dcache(pteval);
-               ext |= PTE_EXT_NG;
-       }
-
-       set_pte_ext(ptep, pteval, ext);
-}
+void set_pte_at(struct mm_struct *mm, unsigned long addr,
+                     pte_t *ptep, pte_t pteval);
 
 static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
 {
index d00e3c7..f70d561 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (C) 2011 Texas Instruments, Inc.
  *     Santosh Shilimkar <santosh.shilimkar@ti.com>
  * Copyright (C) 2012 Ivaylo Dimitrov <freemangordon@abv.bg>
- * Copyright (C) 2013 Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (C) 2013 Pali Rohár <pali@kernel.org>
  */
 
 #include <linux/arm-smccc.h>
index ba8c486..4aaa957 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (C) 2011 Texas Instruments, Inc.
  *     Santosh Shilimkar <santosh.shilimkar@ti.com>
  * Copyright (C) 2012 Ivaylo Dimitrov <freemangordon@abv.bg>
- * Copyright (C) 2013 Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (C) 2013 Pali Rohár <pali@kernel.org>
  */
 #ifndef OMAP_ARCH_OMAP_SECURE_H
 #define OMAP_ARCH_OMAP_SECURE_H
index d483284..7376f52 100644 (file)
@@ -6,7 +6,7 @@
  * Written by Santosh Shilimkar <santosh.shilimkar@ti.com>
  *
  * Copyright (C) 2012 Ivaylo Dimitrov <freemangordon@abv.bg>
- * Copyright (C) 2013 Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (C) 2013 Pali Rohár <pali@kernel.org>
  */
 
 #include <linux/linkage.h>
index 425855f..2e35354 100644 (file)
@@ -312,7 +312,6 @@ static struct pwm_lookup cm_x300_pwm_lookup[] = {
 static struct platform_pwm_backlight_data cm_x300_backlight_data = {
        .max_brightness = 100,
        .dft_brightness = 100,
-       .enable_gpio    = -1,
 };
 
 static struct platform_device cm_x300_backlight_device = {
index dbad2f1..e5879e8 100644 (file)
@@ -202,7 +202,6 @@ static struct pwm_lookup income_pwm_lookup[] = {
 static struct platform_pwm_backlight_data income_backlight_data = {
        .max_brightness = 0x3ff,
        .dft_brightness = 0x1ff,
-       .enable_gpio    = -1,
 };
 
 static struct platform_device income_backlight = {
index f2d7328..593c7f7 100644 (file)
@@ -563,13 +563,20 @@ static void corgi_bl_kick_battery(void)
        }
 }
 
+static struct gpiod_lookup_table corgi_lcdcon_gpio_table = {
+       .dev_id = "spi1.1",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", CORGI_GPIO_BACKLIGHT_CONT,
+                           "BL_CONT", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static struct corgi_lcd_platform_data corgi_lcdcon_info = {
        .init_mode              = CORGI_LCD_MODE_VGA,
        .max_intensity          = 0x2f,
        .default_intensity      = 0x1f,
        .limit_mask             = 0x0b,
-       .gpio_backlight_cont    = CORGI_GPIO_BACKLIGHT_CONT,
-       .gpio_backlight_on      = -1,
        .kick_battery           = corgi_bl_kick_battery,
 };
 
@@ -609,6 +616,7 @@ static struct spi_board_info corgi_spi_devices[] = {
 static void __init corgi_init_spi(void)
 {
        pxa2xx_set_spi_info(1, &corgi_spi_info);
+       gpiod_add_lookup_table(&corgi_lcdcon_gpio_table);
        spi_register_board_info(ARRAY_AND_SIZE(corgi_spi_devices));
 }
 #else
index ec10851..eb85950 100644 (file)
@@ -55,7 +55,6 @@ static struct pwm_lookup ezx_pwm_lookup[] __maybe_unused = {
 static struct platform_pwm_backlight_data ezx_backlight_data = {
        .max_brightness = 1023,
        .dft_brightness = 1023,
-       .enable_gpio    = -1,
 };
 
 static struct platform_device ezx_backlight_device = {
index 238a751..1d4c5db 100644 (file)
@@ -556,7 +556,6 @@ static struct platform_device hx4700_lcd = {
 static struct platform_pwm_backlight_data backlight_data = {
        .max_brightness = 200,
        .dft_brightness = 100,
-       .enable_gpio    = -1,
 };
 
 static struct platform_device backlight = {
index 20e00e9..6fc40bc 100644 (file)
@@ -277,7 +277,6 @@ static struct pwm_lookup lpd270_pwm_lookup[] = {
 static struct platform_pwm_backlight_data lpd270_backlight_data = {
        .max_brightness = 1,
        .dft_brightness = 1,
-       .enable_gpio    = -1,
 };
 
 static struct platform_device lpd270_backlight_device = {
index 5d0591f..cd9fa46 100644 (file)
@@ -401,7 +401,6 @@ static void magician_backlight_exit(struct device *dev)
 static struct platform_pwm_backlight_data backlight_data = {
        .max_brightness = 272,
        .dft_brightness = 100,
-       .enable_gpio    = -1,
        .init           = magician_backlight_init,
        .notify         = magician_backlight_notify,
        .exit           = magician_backlight_exit,
index 1b78829..d1010ec 100644 (file)
@@ -256,7 +256,6 @@ static struct pwm_lookup mainstone_pwm_lookup[] = {
 static struct platform_pwm_backlight_data mainstone_backlight_data = {
        .max_brightness = 1023,
        .dft_brightness = 1023,
-       .enable_gpio    = -1,
 };
 
 static struct platform_device mainstone_backlight_device = {
index 0b8bae9..d3af803 100644 (file)
@@ -176,7 +176,6 @@ static struct pwm_lookup mioa701_pwm_lookup[] = {
 static struct platform_pwm_backlight_data mioa701_backlight_data = {
        .max_brightness = 100,
        .dft_brightness = 50,
-       .enable_gpio    = -1,
 };
 
 /*
index b600b63..0d246a1 100644 (file)
@@ -318,7 +318,6 @@ static void palm27x_backlight_exit(struct device *dev)
 static struct platform_pwm_backlight_data palm27x_backlight_data = {
        .max_brightness = 0xfe,
        .dft_brightness = 0x7e,
-       .enable_gpio    = -1,
        .init           = palm27x_backlight_init,
        .notify         = palm27x_backlight_notify,
        .exit           = palm27x_backlight_exit,
index fda9dea..455cb8c 100644 (file)
@@ -174,6 +174,15 @@ static inline void palmtc_keys_init(void) {}
  * Backlight
  ******************************************************************************/
 #if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM_MODULE)
+
+static struct gpiod_lookup_table palmtc_pwm_bl_gpio_table = {
+       .dev_id = "pwm-backlight.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTC_BL_POWER,
+                           "enable", GPIO_ACTIVE_HIGH),
+       },
+};
+
 static struct pwm_lookup palmtc_pwm_lookup[] = {
        PWM_LOOKUP("pxa25x-pwm.1", 0, "pwm-backlight.0", NULL, PALMTC_PERIOD_NS,
                   PWM_POLARITY_NORMAL),
@@ -182,7 +191,6 @@ static struct pwm_lookup palmtc_pwm_lookup[] = {
 static struct platform_pwm_backlight_data palmtc_backlight_data = {
        .max_brightness = PALMTC_MAX_INTENSITY,
        .dft_brightness = PALMTC_MAX_INTENSITY,
-       .enable_gpio    = GPIO_NR_PALMTC_BL_POWER,
 };
 
 static struct platform_device palmtc_backlight = {
@@ -195,6 +203,7 @@ static struct platform_device palmtc_backlight = {
 
 static void __init palmtc_pwm_init(void)
 {
+       gpiod_add_lookup_table(&palmtc_pwm_bl_gpio_table);
        pwm_add_table(palmtc_pwm_lookup, ARRAY_SIZE(palmtc_pwm_lookup));
        platform_device_register(&palmtc_backlight);
 }
index 7171014..e3bcf58 100644 (file)
@@ -175,7 +175,6 @@ static void palmte2_backlight_exit(struct device *dev)
 static struct platform_pwm_backlight_data palmte2_backlight_data = {
        .max_brightness = PALMTE2_MAX_INTENSITY,
        .dft_brightness = PALMTE2_MAX_INTENSITY,
-       .enable_gpio    = -1,
        .init           = palmte2_backlight_init,
        .notify         = palmte2_backlight_notify,
        .exit           = palmte2_backlight_exit,
index cb1c567..bf613f8 100644 (file)
@@ -154,7 +154,6 @@ static struct pwm_lookup pcm990_pwm_lookup[] = {
 static struct platform_pwm_backlight_data pcm990_backlight_data = {
        .max_brightness = 1023,
        .dft_brightness = 1023,
-       .enable_gpio    = -1,
 };
 
 static struct platform_device pcm990_backlight_device = {
index a4fdc39..371008e 100644 (file)
@@ -525,13 +525,33 @@ static void spitz_bl_kick_battery(void)
        }
 }
 
+static struct gpiod_lookup_table spitz_lcdcon_gpio_table = {
+       .dev_id = "spi2.1",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", SPITZ_GPIO_BACKLIGHT_CONT,
+                           "BL_CONT", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", SPITZ_GPIO_BACKLIGHT_ON,
+                           "BL_ON", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
+static struct gpiod_lookup_table akita_lcdcon_gpio_table = {
+       .dev_id = "spi2.1",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", AKITA_GPIO_BACKLIGHT_CONT,
+                           "BL_CONT", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", AKITA_GPIO_BACKLIGHT_ON,
+                           "BL_ON", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static struct corgi_lcd_platform_data spitz_lcdcon_info = {
        .init_mode              = CORGI_LCD_MODE_VGA,
        .max_intensity          = 0x2f,
        .default_intensity      = 0x1f,
        .limit_mask             = 0x0b,
-       .gpio_backlight_cont    = SPITZ_GPIO_BACKLIGHT_CONT,
-       .gpio_backlight_on      = SPITZ_GPIO_BACKLIGHT_ON,
        .kick_battery           = spitz_bl_kick_battery,
 };
 
@@ -574,12 +594,10 @@ static struct pxa2xx_spi_controller spitz_spi_info = {
 
 static void __init spitz_spi_init(void)
 {
-       struct corgi_lcd_platform_data *lcd_data = &spitz_lcdcon_info;
-
-       if (machine_is_akita()) {
-               lcd_data->gpio_backlight_cont = AKITA_GPIO_BACKLIGHT_CONT;
-               lcd_data->gpio_backlight_on = AKITA_GPIO_BACKLIGHT_ON;
-       }
+       if (machine_is_akita())
+               gpiod_add_lookup_table(&akita_lcdcon_gpio_table);
+       else
+               gpiod_add_lookup_table(&spitz_lcdcon_gpio_table);
 
        pxa2xx_set_spi_info(2, &spitz_spi_info);
        spi_register_board_info(ARRAY_AND_SIZE(spitz_spi_devices));
index 93466fa..a15eb3b 100644 (file)
@@ -178,13 +178,11 @@ static struct platform_pwm_backlight_data tavorevb_backlight_data[] = {
                /* primary backlight */
                .max_brightness = 100,
                .dft_brightness = 100,
-               .enable_gpio    = -1,
        },
        [1] = {
                /* secondary backlight */
                .max_brightness = 100,
                .dft_brightness = 100,
-               .enable_gpio    = -1,
        },
 };
 
index c06031d..3aa34e9 100644 (file)
@@ -404,7 +404,6 @@ static void viper_backlight_exit(struct device *dev)
 static struct platform_pwm_backlight_data viper_backlight_data = {
        .max_brightness = 100,
        .dft_brightness = 100,
-       .enable_gpio    = -1,
        .init           = viper_backlight_init,
        .notify         = viper_backlight_notify,
        .exit           = viper_backlight_exit,
index 900cefc..21fd76b 100644 (file)
@@ -210,13 +210,11 @@ static struct platform_pwm_backlight_data z2_backlight_data[] = {
                /* Keypad Backlight */
                .max_brightness = 1023,
                .dft_brightness = 0,
-               .enable_gpio    = -1,
        },
        [1] = {
                /* LCD Backlight */
                .max_brightness = 1023,
                .dft_brightness = 512,
-               .enable_gpio    = -1,
        },
 };
 
index bf2ab5b..79f0025 100644 (file)
@@ -117,7 +117,6 @@ static struct pwm_lookup zylonite_pwm_lookup[] = {
 static struct platform_pwm_backlight_data zylonite_backlight_data = {
        .max_brightness = 100,
        .dft_brightness = 100,
-       .enable_gpio    = -1,
 };
 
 static struct platform_device zylonite_backlight_device = {
index 74d6b68..e1c372e 100644 (file)
@@ -516,7 +516,6 @@ static void h1940_backlight_exit(struct device *dev)
 static struct platform_pwm_backlight_data backlight_data = {
        .max_brightness = 100,
        .dft_brightness = 50,
-       .enable_gpio    = -1,
        .init           = h1940_backlight_init,
        .notify         = h1940_backlight_notify,
        .exit           = h1940_backlight_exit,
index 03d8f27..fde98b1 100644 (file)
@@ -534,7 +534,6 @@ static int rx1950_backlight_notify(struct device *dev, int brightness)
 static struct platform_pwm_backlight_data rx1950_backlight_data = {
        .max_brightness = 24,
        .dft_brightness = 4,
-       .enable_gpio = -1,
        .init = rx1950_backlight_init,
        .notify = rx1950_backlight_notify,
        .exit = rx1950_backlight_exit,
index 799cfdf..09e6da3 100644 (file)
@@ -65,7 +65,6 @@ static struct samsung_bl_drvdata samsung_dfl_bl_data __initdata = {
        .plat_data = {
                .max_brightness = 255,
                .dft_brightness = 255,
-               .enable_gpio    = -1,
                .init           = samsung_bl_init,
                .exit           = samsung_bl_exit,
        },
@@ -111,8 +110,6 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
                samsung_bl_data->dft_brightness = bl_data->dft_brightness;
        if (bl_data->lth_brightness)
                samsung_bl_data->lth_brightness = bl_data->lth_brightness;
-       if (bl_data->enable_gpio >= 0)
-               samsung_bl_data->enable_gpio = bl_data->enable_gpio;
        if (bl_data->init)
                samsung_bl_data->init = bl_data->init;
        if (bl_data->notify)
index 8ec6a4f..da96542 100644 (file)
@@ -114,7 +114,6 @@ static struct pwm_lookup crag6410_pwm_lookup[] = {
 static struct platform_pwm_backlight_data crag6410_backlight_data = {
        .max_brightness = 1000,
        .dft_brightness = 600,
-       .enable_gpio    = -1,
 };
 
 static struct platform_device crag6410_backlight_device = {
index bfe9881..e708021 100644 (file)
@@ -115,7 +115,6 @@ static void hmt_bl_exit(struct device *dev)
 static struct platform_pwm_backlight_data hmt_backlight_data = {
        .max_brightness = 100 * 256,
        .dft_brightness = 40 * 256,
-       .enable_gpio    = -1,
        .init           = hmt_bl_init,
        .notify         = hmt_bl_notify,
        .exit           = hmt_bl_exit,
index 829d5db..5025db6 100644 (file)
@@ -150,7 +150,6 @@ static int smartq_bl_init(struct device *dev)
 static struct platform_pwm_backlight_data smartq_backlight_data = {
        .max_brightness = 1000,
        .dft_brightness = 600,
-       .enable_gpio    = -1,
        .init           = smartq_bl_init,
 };
 
index 908e5aa..56f406c 100644 (file)
@@ -623,7 +623,7 @@ static struct pwm_lookup smdk6410_pwm_lookup[] = {
 };
 
 static struct platform_pwm_backlight_data smdk6410_bl_data = {
-       .enable_gpio = -1,
+       /* Intentionally blank */
 };
 
 static struct dwc2_hsotg_plat smdk6410_hsotg_pdata;
index b598e69..2dd5c41 100644 (file)
@@ -189,7 +189,7 @@ void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
  */
 static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma)
 {
-       unsigned int mask = VM_READ | VM_WRITE | VM_EXEC;
+       unsigned int mask = VM_ACCESS_FLAGS;
 
        if ((fsr & FSR_WRITE) && !(fsr & FSR_CM))
                mask = VM_WRITE;
index 69a337d..ec8d000 100644 (file)
@@ -1646,3 +1646,17 @@ void __init early_mm_init(const struct machine_desc *mdesc)
        build_mem_type_table();
        early_paging_init(mdesc);
 }
+
+void set_pte_at(struct mm_struct *mm, unsigned long addr,
+                             pte_t *ptep, pte_t pteval)
+{
+       unsigned long ext = 0;
+
+       if (addr < TASK_SIZE && pte_valid_user(pteval)) {
+               if (!pte_special(pteval))
+                       __sync_icache_dcache(pteval);
+               ext |= PTE_EXT_NG;
+       }
+
+       set_pte_ext(ptep, pteval, ext);
+}
index 6e41c4b..40fb05d 100644 (file)
@@ -1502,7 +1502,10 @@ config ARM64_PTR_AUTH
        default y
        depends on !KVM || ARM64_VHE
        depends on (CC_HAS_SIGN_RETURN_ADDRESS || CC_HAS_BRANCH_PROT_PAC_RET) && AS_HAS_PAC
-       depends on CC_IS_GCC || (CC_IS_CLANG && AS_HAS_CFI_NEGATE_RA_STATE)
+       # GCC 9.1 and later inserts a .note.gnu.property section note for PAC
+       # which is only understood by binutils starting with version 2.33.1.
+       depends on !CC_IS_GCC || GCC_VERSION < 90100 || LD_VERSION >= 233010000
+       depends on !CC_IS_CLANG || AS_HAS_CFI_NEGATE_RA_STATE
        depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_REGS)
        help
          Pointer authentication (part of the ARMv8.3 Extensions) provides
index 1c906d9..a1efa24 100644 (file)
@@ -52,19 +52,6 @@ config DEBUG_WX
 
          If in doubt, say "Y".
 
-config DEBUG_ALIGN_RODATA
-       depends on STRICT_KERNEL_RWX
-       bool "Align linker sections up to SECTION_SIZE"
-       help
-         If this option is enabled, sections that may potentially be marked as
-         read only or non-executable will be aligned up to the section size of
-         the kernel. This prevents sections from being split into pages and
-         avoids a potential TLB penalty. The downside is an increase in
-         alignment and potentially wasted space. Turn on this option if
-         performance is more important than memory pressure.
-
-         If in doubt, say N.
-
 config DEBUG_EFI
        depends on EFI && DEBUG_INFO
        bool "UEFI debugging"
index f15f92b..85e4149 100644 (file)
@@ -65,6 +65,10 @@ stack_protector_prepare: prepare0
                                        include/generated/asm-offsets.h))
 endif
 
+# Ensure that if the compiler supports branch protection we default it
+# off, this will be overridden if we are using branch protection.
+branch-prot-flags-y += $(call cc-option,-mbranch-protection=none)
+
 ifeq ($(CONFIG_ARM64_PTR_AUTH),y)
 branch-prot-flags-$(CONFIG_CC_HAS_SIGN_RETURN_ADDRESS) := -msign-return-address=all
 branch-prot-flags-$(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET) := -mbranch-protection=pac-ret+leaf
@@ -73,9 +77,10 @@ branch-prot-flags-$(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET) := -mbranch-protection=pa
 # we pass it only to the assembler. This option is utilized only in case of non
 # integrated assemblers.
 branch-prot-flags-$(CONFIG_AS_HAS_PAC) += -Wa,-march=armv8.3-a
-KBUILD_CFLAGS += $(branch-prot-flags-y)
 endif
 
+KBUILD_CFLAGS += $(branch-prot-flags-y)
+
 ifeq ($(CONFIG_CPU_BIG_ENDIAN), y)
 KBUILD_CPPFLAGS        += -mbig-endian
 CHECKFLAGS     += -D__AARCH64EB__
index 2be67b2..a1871bb 100644 (file)
 
 /*
  * Alignment of kernel segments (e.g. .text, .data).
- */
-#if defined(CONFIG_DEBUG_ALIGN_RODATA)
-/*
- *  4 KB granule:   1 level 2 entry
- * 16 KB granule: 128 level 3 entries, with contiguous bit
- * 64 KB granule:  32 level 3 entries, with contiguous bit
- */
-#define SEGMENT_ALIGN          SZ_2M
-#else
-/*
+ *
  *  4 KB granule:  16 level 3 entries, with contiguous bit
  * 16 KB granule:   4 level 3 entries, without contiguous bit
  * 64 KB granule:   1 level 3 entry
  */
 #define SEGMENT_ALIGN          SZ_64K
-#endif
 
 /*
  * Memory types available.
index 75d6cd2..c01b52a 100644 (file)
@@ -36,9 +36,7 @@ extern int pfn_valid(unsigned long);
 
 #endif /* !__ASSEMBLY__ */
 
-#define VM_DATA_DEFAULT_FLAGS \
-       (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
-        VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_TSK_EXEC
 
 #include <asm-generic/getorder.h>
 
index 4cc581a..c19aa81 100644 (file)
@@ -601,7 +601,7 @@ static struct undef_hook setend_hooks[] = {
        },
        {
                /* Thumb mode */
-               .instr_mask     = 0x0000fff7,
+               .instr_mask     = 0xfffffff7,
                .instr_val      = 0x0000b650,
                .pstate_mask    = (PSR_AA32_T_BIT | PSR_AA32_MODE_MASK),
                .pstate_val     = (PSR_AA32_T_BIT | PSR_AA32_MODE_USR),
index a475c68..449386d 100644 (file)
@@ -64,6 +64,4 @@ config KVM_ARM_PMU
 config KVM_INDIRECT_VECTORS
        def_bool KVM && (HARDEN_BRANCH_PREDICTOR || HARDEN_EL2_VECTORS)
 
-source "drivers/vhost/Kconfig"
-
 endif # VIRTUALIZATION
index 1027851..c9cedc0 100644 (file)
@@ -445,7 +445,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
        const struct fault_info *inf;
        struct mm_struct *mm = current->mm;
        vm_fault_t fault, major = 0;
-       unsigned long vm_flags = VM_READ | VM_WRITE | VM_EXEC;
+       unsigned long vm_flags = VM_ACCESS_FLAGS;
        unsigned int mm_flags = FAULT_FLAG_DEFAULT;
 
        if (kprobe_page_fault(regs, esr))
index b65dffd..e42727e 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mm.h>
 #include <linux/kexec.h>
 #include <linux/crash_dump.h>
+#include <linux/hugetlb.h>
 
 #include <asm/boot.h>
 #include <asm/fixmap.h>
@@ -457,6 +458,11 @@ void __init arm64_memblock_init(void)
        high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
 
        dma_contiguous_reserve(arm64_dma32_phys_limit);
+
+#ifdef CONFIG_ARM64_4K_PAGES
+       hugetlb_cma_reserve(PUD_SHIFT - PAGE_SHIFT);
+#endif
+
 }
 
 void __init bootmem_init(void)
index 9b08f7c..a374e4f 100644 (file)
@@ -1374,7 +1374,7 @@ static void __remove_pgd_mapping(pgd_t *pgdir, unsigned long start, u64 size)
 }
 
 int arch_add_memory(int nid, u64 start, u64 size,
-                       struct mhp_restrictions *restrictions)
+                   struct mhp_params *params)
 {
        int ret, flags = 0;
 
@@ -1382,12 +1382,13 @@ int arch_add_memory(int nid, u64 start, u64 size,
                flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
 
        __create_pgd_mapping(swapper_pg_dir, start, __phys_to_virt(start),
-                            size, PAGE_KERNEL, __pgd_pgtable_alloc, flags);
+                            size, params->pgprot, __pgd_pgtable_alloc,
+                            flags);
 
        memblock_clear_nomap(start, size);
 
        ret = __add_pages(nid, start >> PAGE_SHIFT, size >> PAGE_SHIFT,
-                          restrictions);
+                          params);
        if (ret)
                __remove_pgd_mapping(swapper_pg_dir,
                                     __phys_to_virt(start), size);
index 70db1e7..4007989 100644 (file)
@@ -2,10 +2,7 @@
 #ifndef _ASM_C6X_PAGE_H
 #define _ASM_C6X_PAGE_H
 
-#define VM_DATA_DEFAULT_FLAGS \
-       (VM_READ | VM_WRITE | \
-       ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
-                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_TSK_EXEC
 
 #include <asm-generic/page.h>
 
index 9738eac..9b98bf3 100644 (file)
@@ -85,9 +85,6 @@ extern unsigned long va_pa_offset;
                                 PHYS_OFFSET_OFFSET)
 #define virt_to_page(x)        (mem_map + MAP_NR(x))
 
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
-                               VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
 #define pfn_to_kaddr(x)        __va(PFN_PHYS(x))
 
 #include <asm-generic/memory_model.h>
index 9b7764c..9ab4a44 100644 (file)
@@ -110,9 +110,6 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
 extern void load_pgd(unsigned long pg_dir);
 extern pte_t invalid_pte_table[PTRS_PER_PTE];
 
-static inline int pte_special(pte_t pte) { return 0; }
-static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
-
 static inline void set_pte(pte_t *p, pte_t pte)
 {
        *p = pte;
index 8da5124..53e0375 100644 (file)
@@ -6,8 +6,6 @@
 #include <linux/types.h>
 
 #define MAP_NR(addr) (((uintptr_t)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #ifndef __ASSEMBLY__
 extern unsigned long rom_length;
diff --git a/arch/h8300/include/uapi/asm/bitsperlong.h b/arch/h8300/include/uapi/asm/bitsperlong.h
deleted file mode 100644 (file)
index a33e358..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef _UAPI__ASM_H8300_BITS_PER_LONG
-#define _UAPI__ASM_H8300_BITS_PER_LONG
-
-#include <asm-generic/bitsperlong.h>
-
-#if !defined(__ASSEMBLY__)
-/* h8300-unknown-linux required long */
-#define __kernel_size_t __kernel_size_t
-typedef unsigned long  __kernel_size_t;
-typedef long           __kernel_ssize_t;
-typedef long           __kernel_ptrdiff_t;
-#endif
-
-#endif /* _UAPI__ASM_H8300_BITS_PER_LONG */
diff --git a/arch/h8300/include/uapi/asm/posix_types.h b/arch/h8300/include/uapi/asm/posix_types.h
new file mode 100644 (file)
index 0000000..3efc9dd
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
+#ifndef _UAPI_ASM_POSIX_TYPES_H
+#define _UAPI_ASM_POSIX_TYPES_H
+
+/* h8300-unknown-linux required long */
+#define __kernel_size_t __kernel_size_t
+typedef unsigned long  __kernel_size_t;
+typedef long           __kernel_ssize_t;
+typedef long           __kernel_ptrdiff_t;
+
+#include <asm-generic/posix_types.h>
+
+#endif /* _UAPI_ASM_POSIX_TYPES_H */
index ee31f36..7cbf719 100644 (file)
@@ -93,8 +93,7 @@ struct page;
 #define virt_to_page(kaddr) pfn_to_page(PFN_DOWN(__pa(kaddr)))
 
 /* Default vm area behavior is non-executable.  */
-#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \
-                               VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_NON_EXEC
 
 #define pfn_valid(pfn) ((pfn) < max_mapnr)
 #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
index 2fec20a..d383e8b 100644 (file)
@@ -158,8 +158,6 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];  /* located in head.S */
 
 /* Seems to be zero even in architectures where the zero page is firewalled? */
 #define FIRST_USER_ADDRESS 0UL
-#define pte_special(pte)       0
-#define pte_mkspecial(pte)     (pte)
 
 /*  HUGETLB not working currently  */
 #ifdef CONFIG_HUGETLB_PAGE
index 5798bd2..b69a549 100644 (file)
@@ -218,10 +218,7 @@ get_order (unsigned long size)
 
 #define PAGE_OFFSET                    RGN_BASE(RGN_KERNEL)
 
-#define VM_DATA_DEFAULT_FLAGS          (VM_READ | VM_WRITE |                                   \
-                                        VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC |                \
-                                        (((current->personality & READ_IMPLIES_EXEC) != 0)     \
-                                         ? VM_EXEC : 0))
+#define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_TSK_EXEC
 
 #define GATE_ADDR              RGN_BASE(RGN_GATE)
 
index d602e7c..0e7b645 100644 (file)
@@ -298,7 +298,6 @@ extern unsigned long VMALLOC_END;
 #define pte_exec(pte)          ((pte_val(pte) & _PAGE_AR_RX) != 0)
 #define pte_dirty(pte)         ((pte_val(pte) & _PAGE_D) != 0)
 #define pte_young(pte)         ((pte_val(pte) & _PAGE_A) != 0)
-#define pte_special(pte)       0
 
 /*
  * Note: we convert AR_RWX to AR_RX and AR_RW to AR_R by clearing the 2nd bit in the
@@ -311,7 +310,6 @@ extern unsigned long VMALLOC_END;
 #define pte_mkclean(pte)       (__pte(pte_val(pte) & ~_PAGE_D))
 #define pte_mkdirty(pte)       (__pte(pte_val(pte) | _PAGE_D))
 #define pte_mkhuge(pte)                (__pte(pte_val(pte)))
-#define pte_mkspecial(pte)     (pte)
 
 /*
  * Because ia64's Icache and Dcache is not coherent (on a cpu), we need to
index b01d68a..d637b4e 100644 (file)
@@ -670,13 +670,16 @@ mem_init (void)
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 int arch_add_memory(int nid, u64 start, u64 size,
-                       struct mhp_restrictions *restrictions)
+                   struct mhp_params *params)
 {
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
        int ret;
 
-       ret = __add_pages(nid, start_pfn, nr_pages, restrictions);
+       if (WARN_ON_ONCE(params->pgprot.pgprot != PAGE_KERNEL.pgprot))
+               return -EINVAL;
+
+       ret = __add_pages(nid, start_pfn, nr_pages, params);
        if (ret)
                printk("%s: Problem encountered in __add_pages() as ret=%d\n",
                       __func__,  ret);
index 71ddb4c..1c8e8a8 100644 (file)
@@ -68,14 +68,6 @@ static irqreturn_t hw_tick(int irq, void *dummy)
 
 /***************************************************************************/
 
-static struct irqaction m68328_timer_irq = {
-       .name    = "timer",
-       .flags   = IRQF_TIMER,
-       .handler = hw_tick,
-};
-
-/***************************************************************************/
-
 static u64 m68328_read_clk(struct clocksource *cs)
 {
        unsigned long flags;
@@ -102,11 +94,17 @@ static struct clocksource m68328_clk = {
 
 void hw_timer_init(irq_handler_t handler)
 {
+       int ret;
+
        /* disable timer 1 */
        TCTL = 0;
 
        /* set ISR */
-       setup_irq(TMR_IRQ_NUM, &m68328_timer_irq);
+       ret = request_irq(TMR_IRQ_NUM, hw_tick, IRQF_TIMER, "timer", NULL);
+       if (ret) {
+               pr_err("Failed to request irq %d (timer): %pe\n", TMR_IRQ_NUM,
+                      ERR_PTR(ret));
+       }
 
        /* Restart mode, Enable int, Set clock source */
        TCTL = TCTL_OM | TCTL_IRQEN | CLOCK_SOURCE;
index eb6f16b..fd1d9c9 100644 (file)
@@ -111,14 +111,6 @@ static irqreturn_t pit_tick(int irq, void *dummy)
 
 /***************************************************************************/
 
-static struct irqaction pit_irq = {
-       .name    = "timer",
-       .flags   = IRQF_TIMER,
-       .handler = pit_tick,
-};
-
-/***************************************************************************/
-
 static u64 pit_read_clk(struct clocksource *cs)
 {
        unsigned long flags;
@@ -146,6 +138,8 @@ static struct clocksource pit_clk = {
 
 void hw_timer_init(irq_handler_t handler)
 {
+       int ret;
+
        cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id());
        cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
        cf_pit_clockevent.max_delta_ns =
@@ -156,7 +150,11 @@ void hw_timer_init(irq_handler_t handler)
        cf_pit_clockevent.min_delta_ticks = 0x3f;
        clockevents_register_device(&cf_pit_clockevent);
 
-       setup_irq(MCF_IRQ_PIT1, &pit_irq);
+       ret = request_irq(MCF_IRQ_PIT1, pit_tick, IRQF_TIMER, "timer", NULL);
+       if (ret) {
+               pr_err("Failed to request irq %d (timer): %pe\n", MCF_IRQ_PIT1,
+                      ERR_PTR(ret));
+       }
 
        clocksource_register_hz(&pit_clk, FREQ);
 }
index 1b11e7b..5ab81c9 100644 (file)
@@ -50,18 +50,19 @@ irqreturn_t mcfslt_profile_tick(int irq, void *dummy)
        return IRQ_HANDLED;
 }
 
-static struct irqaction mcfslt_profile_irq = {
-       .name    = "profile timer",
-       .flags   = IRQF_TIMER,
-       .handler = mcfslt_profile_tick,
-};
-
 void mcfslt_profile_init(void)
 {
+       int ret;
+
        printk(KERN_INFO "PROFILE: lodging TIMER 1 @ %dHz as profile timer\n",
               PROFILEHZ);
 
-       setup_irq(MCF_IRQ_PROFILER, &mcfslt_profile_irq);
+       ret = request_irq(MCF_IRQ_PROFILER, mcfslt_profile_tick, IRQF_TIMER,
+                         "profile timer", NULL);
+       if (ret) {
+               pr_err("Failed to request irq %d (profile timer): %pe\n",
+                      MCF_IRQ_PROFILER, ERR_PTR(ret));
+       }
 
        /* Set up TIMER 2 as high speed profile clock */
        __raw_writel(MCF_BUSCLK / PROFILEHZ - 1, PA(MCFSLT_STCNT));
@@ -92,12 +93,6 @@ static irqreturn_t mcfslt_tick(int irq, void *dummy)
        return timer_interrupt(irq, dummy);
 }
 
-static struct irqaction mcfslt_timer_irq = {
-       .name    = "timer",
-       .flags   = IRQF_TIMER,
-       .handler = mcfslt_tick,
-};
-
 static u64 mcfslt_read_clk(struct clocksource *cs)
 {
        unsigned long flags;
@@ -126,6 +121,8 @@ static struct clocksource mcfslt_clk = {
 
 void hw_timer_init(irq_handler_t handler)
 {
+       int r;
+
        mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ;
        /*
         *      The coldfire slice timer (SLT) runs from STCNT to 0 included,
@@ -140,7 +137,11 @@ void hw_timer_init(irq_handler_t handler)
        mcfslt_cnt = mcfslt_cycles_per_jiffy;
 
        timer_interrupt = handler;
-       setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq);
+       r = request_irq(MCF_IRQ_TIMER, mcfslt_tick, IRQF_TIMER, "timer", NULL);
+       if (r) {
+               pr_err("Failed to request irq %d (timer): %pe\n", MCF_IRQ_TIMER,
+                      ERR_PTR(r));
+       }
 
        clocksource_register_hz(&mcfslt_clk, MCF_BUSCLK);
 
index 227aa5d..b8301fd 100644 (file)
@@ -82,14 +82,6 @@ static irqreturn_t mcftmr_tick(int irq, void *dummy)
 
 /***************************************************************************/
 
-static struct irqaction mcftmr_timer_irq = {
-       .name    = "timer",
-       .flags   = IRQF_TIMER,
-       .handler = mcftmr_tick,
-};
-
-/***************************************************************************/
-
 static u64 mcftmr_read_clk(struct clocksource *cs)
 {
        unsigned long flags;
@@ -118,6 +110,8 @@ static struct clocksource mcftmr_clk = {
 
 void hw_timer_init(irq_handler_t handler)
 {
+       int r;
+
        __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
        mcftmr_cycles_per_jiffy = FREQ / HZ;
        /*
@@ -134,7 +128,11 @@ void hw_timer_init(irq_handler_t handler)
 
        timer_interrupt = handler;
        init_timer_irq();
-       setup_irq(MCF_IRQ_TIMER, &mcftmr_timer_irq);
+       r = request_irq(MCF_IRQ_TIMER, mcftmr_tick, IRQF_TIMER, "timer", NULL);
+       if (r) {
+               pr_err("Failed to request irq %d (timer): %pe\n", MCF_IRQ_TIMER,
+                      ERR_PTR(r));
+       }
 
 #ifdef CONFIG_HIGHPROFILE
        coldfire_profile_init();
@@ -170,14 +168,10 @@ irqreturn_t coldfire_profile_tick(int irq, void *dummy)
 
 /***************************************************************************/
 
-static struct irqaction coldfire_profile_irq = {
-       .name    = "profile timer",
-       .flags   = IRQF_TIMER,
-       .handler = coldfire_profile_tick,
-};
-
 void coldfire_profile_init(void)
 {
+       int ret;
+
        printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n",
               PROFILEHZ);
 
@@ -188,7 +182,12 @@ void coldfire_profile_init(void)
        __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
                MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR));
 
-       setup_irq(MCF_IRQ_PROFILER, &coldfire_profile_irq);
+       ret = request_irq(MCF_IRQ_PROFILER, coldfire_profile_tick, IRQF_TIMER,
+                         "profile timer", NULL);
+       if (ret) {
+               pr_err("Failed to request irq %d (profile timer): %pe\n",
+                      MCF_IRQ_PROFILER, ERR_PTR(ret));
+       }
 }
 
 /***************************************************************************/
index a0765aa..1bff55a 100644 (file)
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 generated-y += syscall_table.h
 generic-y += extable.h
-generic-y += hardirq.h
 generic-y += kvm_para.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
index b9f45ae..0031cd3 100644 (file)
@@ -235,11 +235,6 @@ static inline int pte_young(pte_t pte)
        return pte_val(pte) & CF_PAGE_ACCESSED;
 }
 
-static inline int pte_special(pte_t pte)
-{
-       return 0;
-}
-
 static inline pte_t pte_wrprotect(pte_t pte)
 {
        pte_val(pte) &= ~CF_PAGE_WRITABLE;
@@ -312,11 +307,6 @@ static inline pte_t pte_mkcache(pte_t pte)
        return pte;
 }
 
-static inline pte_t pte_mkspecial(pte_t pte)
-{
-       return pte;
-}
-
 #define swapper_pg_dir kernel_pg_dir
 extern pgd_t kernel_pg_dir[PTRS_PER_PGD];
 
index 4b91a47..48f19f0 100644 (file)
@@ -174,7 +174,6 @@ static inline void pud_set(pud_t *pudp, pmd_t *pmdp)
 static inline int pte_write(pte_t pte)         { return !(pte_val(pte) & _PAGE_RONLY); }
 static inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
-static inline int pte_special(pte_t pte)       { return 0; }
 
 static inline pte_t pte_wrprotect(pte_t pte)   { pte_val(pte) |= _PAGE_RONLY; return pte; }
 static inline pte_t pte_mkclean(pte_t pte)     { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
@@ -192,7 +191,6 @@ static inline pte_t pte_mkcache(pte_t pte)
        pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_supervisor_cachemode;
        return pte;
 }
-static inline pte_t pte_mkspecial(pte_t pte)   { return pte; }
 
 #define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
 
index da54648..2614a12 100644 (file)
@@ -65,9 +65,6 @@ extern unsigned long _ramend;
 #define __phys_to_pfn(paddr)   ((unsigned long)((paddr) >> PAGE_SHIFT))
 #define __pfn_to_phys(pfn)     PFN_PHYS(pfn)
 
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
 #include <asm-generic/getorder.h>
 
 #endif /* _M68K_PAGE_H */
index bc41552..0caa18a 100644 (file)
@@ -155,7 +155,6 @@ static inline void pmd_clear (pmd_t *pmdp) { pmd_val (*pmdp) = 0; }
 static inline int pte_write(pte_t pte)         { return pte_val(pte) & SUN3_PAGE_WRITEABLE; }
 static inline int pte_dirty(pte_t pte)         { return pte_val(pte) & SUN3_PAGE_MODIFIED; }
 static inline int pte_young(pte_t pte)         { return pte_val(pte) & SUN3_PAGE_ACCESSED; }
-static inline int pte_special(pte_t pte)       { return 0; }
 
 static inline pte_t pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~SUN3_PAGE_WRITEABLE; return pte; }
 static inline pte_t pte_mkclean(pte_t pte)     { pte_val(pte) &= ~SUN3_PAGE_MODIFIED; return pte; }
@@ -168,7 +167,6 @@ static inline pte_t pte_mknocache(pte_t pte)        { pte_val(pte) |= SUN3_PAGE_NOCACHE
 //static inline pte_t pte_mkcache(pte_t pte)   { pte_val(pte) &= SUN3_PAGE_NOCACHE; return pte; }
 // until then, use:
 static inline pte_t pte_mkcache(pte_t pte)     { return pte; }
-static inline pte_t pte_mkspecial(pte_t pte)   { return pte; }
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 extern pgd_t kernel_pg_dir[PTRS_PER_PGD];
index ae7215c..b13463d 100644 (file)
@@ -194,8 +194,6 @@ extern int page_is_ram(unsigned long pfn);
 
 #ifdef CONFIG_MMU
 
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 #endif /* CONFIG_MMU */
 
 #endif /* __KERNEL__ */
index 45b3087..6b056f6 100644 (file)
@@ -77,10 +77,6 @@ extern pte_t *va_to_pte(unsigned long address);
  * Undefined behaviour if not..
  */
 
-static inline int pte_special(pte_t pte)       { return 0; }
-
-static inline pte_t pte_mkspecial(pte_t pte)   { return pte; }
-
 /* Start and end of the vmalloc area. */
 /* Make sure to map the vmalloc area above the pinned kernel memory area
    of 32Mb.  */
index dbbcddc..89fa6e6 100644 (file)
@@ -117,7 +117,7 @@ static int __init prom_memtype_classify(union linux_memtypes type)
        return memtype_classify_arc(type);
 }
 
-void __init prom_meminit(void)
+void __weak __init prom_meminit(void)
 {
        struct linux_mdesc *p;
 
@@ -162,7 +162,7 @@ void __weak __init prom_cleanup(void)
 {
 }
 
-void __init prom_free_prom_memory(void)
+void __weak __init prom_free_prom_memory(void)
 {
        int i;
 
index 0ba4ce6..e2f503f 100644 (file)
@@ -253,10 +253,7 @@ extern bool __virt_addr_valid(const volatile void *kaddr);
 #define virt_addr_valid(kaddr)                                         \
        __virt_addr_valid((const volatile void *) (kaddr))
 
-#define VM_DATA_DEFAULT_FLAGS \
-       (VM_READ | VM_WRITE | \
-        ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
-        VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_TSK_EXEC
 
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
index aef5378..f1801e7 100644 (file)
@@ -270,6 +270,36 @@ cache_sync_done:
 extern pgd_t swapper_pg_dir[];
 
 /*
+ * Platform specific pte_special() and pte_mkspecial() definitions
+ * are required only when ARCH_HAS_PTE_SPECIAL is enabled.
+ */
+#if defined(CONFIG_ARCH_HAS_PTE_SPECIAL)
+#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32)
+static inline int pte_special(pte_t pte)
+{
+       return pte.pte_low & _PAGE_SPECIAL;
+}
+
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+       pte.pte_low |= _PAGE_SPECIAL;
+       return pte;
+}
+#else
+static inline int pte_special(pte_t pte)
+{
+       return pte_val(pte) & _PAGE_SPECIAL;
+}
+
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+       pte_val(pte) |= _PAGE_SPECIAL;
+       return pte;
+}
+#endif
+#endif /* CONFIG_ARCH_HAS_PTE_SPECIAL */
+
+/*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
@@ -277,7 +307,6 @@ extern pgd_t swapper_pg_dir[];
 static inline int pte_write(pte_t pte) { return pte.pte_low & _PAGE_WRITE; }
 static inline int pte_dirty(pte_t pte) { return pte.pte_low & _PAGE_MODIFIED; }
 static inline int pte_young(pte_t pte) { return pte.pte_low & _PAGE_ACCESSED; }
-static inline int pte_special(pte_t pte) { return pte.pte_low & _PAGE_SPECIAL; }
 
 static inline pte_t pte_wrprotect(pte_t pte)
 {
@@ -338,17 +367,10 @@ static inline pte_t pte_mkyoung(pte_t pte)
        }
        return pte;
 }
-
-static inline pte_t pte_mkspecial(pte_t pte)
-{
-       pte.pte_low |= _PAGE_SPECIAL;
-       return pte;
-}
 #else
 static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; }
 static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_MODIFIED; }
 static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
-static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; }
 
 static inline pte_t pte_wrprotect(pte_t pte)
 {
@@ -392,12 +414,6 @@ static inline pte_t pte_mkyoung(pte_t pte)
        return pte;
 }
 
-static inline pte_t pte_mkspecial(pte_t pte)
-{
-       pte_val(pte) |= _PAGE_SPECIAL;
-       return pte;
-}
-
 #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
 static inline int pte_huge(pte_t pte)  { return pte_val(pte) & _PAGE_HUGE; }
 
index eac25ae..b91d145 100644 (file)
@@ -72,6 +72,4 @@ config KVM_MIPS_DEBUG_COP0_COUNTERS
 
          If unsure, say N.
 
-source "drivers/vhost/Kconfig"
-
 endif # VIRTUALIZATION
index 86b3201..add33a7 100644 (file)
@@ -59,9 +59,6 @@ typedef struct page *pgtable_t;
 
 #endif /* !__ASSEMBLY__ */
 
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
 #endif /* __KERNEL__ */
 
 #endif
index 6abc58a..476cc4d 100644 (file)
@@ -286,15 +286,6 @@ PTE_BIT_FUNC(mkclean, &=~_PAGE_D);
 PTE_BIT_FUNC(mkdirty, |=_PAGE_D);
 PTE_BIT_FUNC(mkold, &=~_PAGE_YOUNG);
 PTE_BIT_FUNC(mkyoung, |=_PAGE_YOUNG);
-static inline int pte_special(pte_t pte)
-{
-       return 0;
-}
-
-static inline pte_t pte_mkspecial(pte_t pte)
-{
-       return pte;
-}
 
 /*
  * Mark the prot value as uncacheable and unbufferable.
index 0cf0c08..f331e53 100644 (file)
@@ -79,7 +79,7 @@ void do_page_fault(unsigned long entry, unsigned long addr,
        struct vm_area_struct *vma;
        int si_code;
        vm_fault_t fault;
-       unsigned int mask = VM_READ | VM_WRITE | VM_EXEC;
+       unsigned int mask = VM_ACCESS_FLAGS;
        unsigned int flags = FAULT_FLAG_DEFAULT;
 
        error_code = error_code & (ITYPE_mskINST | ITYPE_mskETYPE);
index 2fc4ed2..c664514 100644 (file)
@@ -7,6 +7,7 @@ config NIOS2
        select ARCH_HAS_SYNC_DMA_FOR_DEVICE
        select ARCH_HAS_DMA_SET_UNCACHED
        select ARCH_NO_SWAP
+       select COMMON_CLK
        select TIMER_OF
        select GENERIC_ATOMIC64
        select GENERIC_CLOCKEVENTS
index 5e4ab03..56339be 100644 (file)
                led_pio: gpio@180014d0 {
                        compatible = "altr,pio-1.0";
                        reg = <0x180014d0 0x00000010>;
-                       altr,gpio-bank-width = <4>;
-                       resetvalue = <15>;
+                       altr,ngpio = <4>;
                        #gpio-cells = <2>;
                        gpio-controller;
                };
                        reg = <0x180014c0 0x00000010>;
                        interrupt-parent = <&cpu>;
                        interrupts = <6>;
-                       altr,gpio-bank-width = <3>;
+                       altr,ngpio = <3>;
                        altr,interrupt-type = <2>;
                        edge_type = <1>;
                        level_trigger = <0>;
-                       resetvalue = <0>;
                        #gpio-cells = <2>;
                        gpio-controller;
                };
index 79fcac6..6a98981 100644 (file)
@@ -98,8 +98,7 @@ static inline bool pfn_valid(unsigned long pfn)
 # define virt_to_page(vaddr)   pfn_to_page(PFN_DOWN(virt_to_phys(vaddr)))
 # define virt_addr_valid(vaddr)        pfn_valid(PFN_DOWN(virt_to_phys(vaddr)))
 
-# define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+# define VM_DATA_DEFAULT_FLAGS VM_DATA_FLAGS_NON_EXEC
 
 #include <asm-generic/memory_model.h>
 
index 99985d8..f98b7f4 100644 (file)
@@ -113,7 +113,6 @@ static inline int pte_dirty(pte_t pte)              \
        { return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)         \
        { return pte_val(pte) & _PAGE_ACCESSED; }
-static inline int pte_special(pte_t pte)       { return 0; }
 
 #define pgprot_noncached pgprot_noncached
 
@@ -168,8 +167,6 @@ static inline pte_t pte_mkdirty(pte_t pte)
        return pte;
 }
 
-static inline pte_t pte_mkspecial(pte_t pte)   { return pte; }
-
 static inline pte_t pte_mkyoung(pte_t pte)
 {
        pte_val(pte) |= _PAGE_ACCESSED;
index 2a35154..9737a87 100644 (file)
 #include <linux/slab.h>
 #include <linux/sys_soc.h>
 #include <linux/io.h>
+#include <linux/clk-provider.h>
+
+static const struct of_device_id clk_match[] __initconst = {
+       { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
+       {}
+};
 
 static int __init nios2_soc_device_init(void)
 {
@@ -38,6 +44,8 @@ static int __init nios2_soc_device_init(void)
                }
        }
 
+       of_clk_init(clk_match);
+
        return 0;
 }
 
index 01069db..aab6e64 100644 (file)
@@ -86,11 +86,6 @@ typedef struct page *pgtable_t;
 
 #endif /* __ASSEMBLY__ */
 
-
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
-
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
 
index 248d22d..7f3fb9c 100644 (file)
@@ -236,8 +236,6 @@ static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; }
 static inline int pte_exec(pte_t pte)  { return pte_val(pte) & _PAGE_EXEC; }
 static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
-static inline int pte_special(pte_t pte) { return 0; }
-static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
 
 static inline pte_t pte_wrprotect(pte_t pte)
 {
index 796ae29..6b3f674 100644 (file)
@@ -180,9 +180,6 @@ extern int npmem_ranges;
 #define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
 #define virt_to_page(kaddr)     pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
 #include <asm/pdc.h>
index f0a3659..9832c73 100644 (file)
@@ -377,7 +377,6 @@ static inline void pud_clear(pud_t *pud) {
 static inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
 static inline int pte_write(pte_t pte)         { return pte_val(pte) & _PAGE_WRITE; }
-static inline int pte_special(pte_t pte)       { return 0; }
 
 static inline pte_t pte_mkclean(pte_t pte)     { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
 static inline pte_t pte_mkold(pte_t pte)       { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
@@ -385,7 +384,6 @@ static inline pte_t pte_wrprotect(pte_t pte)        { pte_val(pte) &= ~_PAGE_WRITE; ret
 static inline pte_t pte_mkdirty(pte_t pte)     { pte_val(pte) |= _PAGE_DIRTY; return pte; }
 static inline pte_t pte_mkyoung(pte_t pte)     { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkwrite(pte_t pte)     { pte_val(pte) |= _PAGE_WRITE; return pte; }
-static inline pte_t pte_mkspecial(pte_t pte)   { return pte; }
 
 /*
  * Huge pte definitions.
index 5fc4536..924c541 100644 (file)
@@ -122,6 +122,7 @@ config PPC
        select ARCH_HAS_GCOV_PROFILE_ALL
        select ARCH_HAS_KCOV
        select ARCH_HAS_HUGEPD                  if HUGETLB_PAGE
+       select ARCH_HAS_MEMREMAP_COMPAT_ALIGN
        select ARCH_HAS_MMIOWB                  if PPC64
        select ARCH_HAS_PHYS_TO_DMA
        select ARCH_HAS_PMEM_API
@@ -265,8 +266,9 @@ config PANIC_TIMEOUT
        default 180
 
 config COMPAT
-       bool
-       default y if PPC64
+       bool "Enable support for 32bit binaries"
+       depends on PPC64
+       default y if !CPU_LITTLE_ENDIAN
        select COMPAT_BINFMT_ELF
        select ARCH_WANT_OLD_COMPAT_IPC
        select COMPAT_OLD_SIGACTION
index 4db5171..81b55c8 100644 (file)
@@ -60,6 +60,8 @@ CONFIG_CFG80211=m
 CONFIG_CFG80211_WEXT=y
 CONFIG_MAC80211=m
 # CONFIG_MAC80211_RC_MINSTREL is not set
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=65535
index 2781ebf..6fc4520 100644 (file)
@@ -251,7 +251,8 @@ extern int __meminit hash__vmemmap_create_mapping(unsigned long start,
 extern void hash__vmemmap_remove_mapping(unsigned long start,
                                     unsigned long page_size);
 
-int hash__create_section_mapping(unsigned long start, unsigned long end, int nid);
+int hash__create_section_mapping(unsigned long start, unsigned long end,
+                                int nid, pgprot_t prot);
 int hash__remove_section_mapping(unsigned long start, unsigned long end);
 
 #endif /* !__ASSEMBLY__ */
index a1c60d5..08c222d 100644 (file)
@@ -294,7 +294,8 @@ static inline unsigned long radix__get_tree_size(void)
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-int radix__create_section_mapping(unsigned long start, unsigned long end, int nid);
+int radix__create_section_mapping(unsigned long start, unsigned long end,
+                                 int nid, pgprot_t prot);
 int radix__remove_section_mapping(unsigned long start, unsigned long end);
 #endif /* CONFIG_MEMORY_HOTPLUG */
 #endif /* __ASSEMBLY__ */
index 080a0bf..3ee8df0 100644 (file)
@@ -240,13 +240,8 @@ static inline bool pfn_valid(unsigned long pfn)
  * and needs to be executable.  This means the whole heap ends
  * up being executable.
  */
-#define VM_DATA_DEFAULT_FLAGS32 \
-       (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
-                                VM_READ | VM_WRITE | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
-#define VM_DATA_DEFAULT_FLAGS64        (VM_READ | VM_WRITE | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_DEFAULT_FLAGS32        VM_DATA_FLAGS_TSK_EXEC
+#define VM_DATA_DEFAULT_FLAGS64        VM_DATA_FLAGS_NON_EXEC
 
 #ifdef __powerpc64__
 #include <asm/page_64.h>
index 5962797..79a9b7c 100644 (file)
@@ -94,11 +94,8 @@ extern u64 ppc64_pft_size;
  * stack by default, so in the absence of a PT_GNU_STACK program header
  * we turn execute permission off.
  */
-#define VM_STACK_DEFAULT_FLAGS32       (VM_READ | VM_WRITE | VM_EXEC | \
-                                        VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
-#define VM_STACK_DEFAULT_FLAGS64       (VM_READ | VM_WRITE | \
-                                        VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_STACK_DEFAULT_FLAGS32       VM_DATA_FLAGS_EXEC
+#define VM_STACK_DEFAULT_FLAGS64       VM_DATA_FLAGS_NON_EXEC
 
 #define VM_STACK_DEFAULT_FLAGS \
        (is_32bit_task() ? \
index 3192d45..c89b324 100644 (file)
@@ -13,7 +13,8 @@
 #endif /* CONFIG_SPARSEMEM */
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-extern int create_section_mapping(unsigned long start, unsigned long end, int nid);
+extern int create_section_mapping(unsigned long start, unsigned long end,
+                                 int nid, pgprot_t prot);
 extern int remove_section_mapping(unsigned long start, unsigned long end);
 
 #ifdef CONFIG_PPC_BOOK3S_64
index a227074..ca6c970 100644 (file)
@@ -162,10 +162,10 @@ static inline bool test_thread_local_flags(unsigned int flags)
        return (ti->local_flags & flags) != 0;
 }
 
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_COMPAT
 #define is_32bit_task()        (test_thread_flag(TIF_32BIT))
 #else
-#define is_32bit_task()        (1)
+#define is_32bit_task()        (IS_ENABLED(CONFIG_PPC32))
 #endif
 
 #if defined(CONFIG_PPC64)
index b0720c7..700fcda 100644 (file)
@@ -31,6 +31,7 @@
 #define __ARCH_WANT_SYS_SOCKETCALL
 #define __ARCH_WANT_SYS_FADVISE64
 #define __ARCH_WANT_SYS_GETPGRP
+#define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_OLD_GETRLIMIT
 #define __ARCH_WANT_SYS_OLD_UNAME
index 570660e..1c43858 100644 (file)
@@ -40,16 +40,17 @@ CFLAGS_btext.o += -DDISABLE_BRANCH_PROFILING
 endif
 
 obj-y                          := cputable.o syscalls.o \
-                                  irq.o align.o signal_32.o pmc.o vdso.o \
+                                  irq.o align.o signal_$(BITS).o pmc.o vdso.o \
                                   process.o systbl.o idle.o \
                                   signal.o sysfs.o cacheinfo.o time.o \
                                   prom.o traps.o setup-common.o \
                                   udbg.o misc.o io.o misc_$(BITS).o \
                                   of_platform.o prom_parse.o
 obj-y                          += ptrace/
-obj-$(CONFIG_PPC64)            += setup_64.o sys_ppc32.o signal_64.o \
+obj-$(CONFIG_PPC64)            += setup_64.o \
                                   paca.o nvram_64.o firmware.o note.o \
                                   syscall_64.o
+obj-$(CONFIG_COMPAT)           += sys_ppc32.o signal_32.o
 obj-$(CONFIG_VDSO32)           += vdso32/
 obj-$(CONFIG_PPC_WATCHDOG)     += watchdog.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += hw_breakpoint.o
index 63f0a44..9a1e5d6 100644 (file)
 SYS_CALL_TABLE:
        .tc sys_call_table[TC],sys_call_table
 
+#ifdef CONFIG_COMPAT
 COMPAT_SYS_CALL_TABLE:
        .tc compat_sys_call_table[TC],compat_sys_call_table
+#endif
 
 /* This value is used to mark exception frames on the stack. */
 exception_marker:
index 18bbce1..728ccb0 100644 (file)
@@ -3121,22 +3121,3 @@ handle_dabr_fault:
        li      r5,SIGSEGV
        bl      bad_page_fault
        b       interrupt_return
-
-/*
- * When doorbell is triggered from system reset wakeup, the message is
- * not cleared, so it would fire again when EE is enabled.
- *
- * When coming from local_irq_enable, there may be the same problem if
- * we were hard disabled.
- *
- * Execute msgclr to clear pending exceptions before handling it.
- */
-h_doorbell_common_msgclr:
-       LOAD_REG_IMMEDIATE(r3, PPC_DBELL_MSGTYPE << (63-36))
-       PPC_MSGCLR(3)
-       b       h_doorbell_common_virt
-
-doorbell_super_common_msgclr:
-       LOAD_REG_IMMEDIATE(r3, PPC_DBELL_MSGTYPE << (63-36))
-       PPC_MSGCLRP(3)
-       b       doorbell_super_common_virt
index a25ed47..1f11698 100644 (file)
@@ -527,6 +527,19 @@ void irq_set_pending_from_srr1(unsigned long srr1)
                return;
        }
 
+       if (reason == PACA_IRQ_DBELL) {
+               /*
+                * When doorbell triggers a system reset wakeup, the message
+                * is not cleared, so if the doorbell interrupt is replayed
+                * and the IPI handled, the doorbell interrupt would still
+                * fire when EE is enabled.
+                *
+                * To avoid taking the superfluous doorbell interrupt,
+                * execute a msgclr here before the interrupt is replayed.
+                */
+               ppc_msgclr(PPC_DBELL_MSGTYPE);
+       }
+
        /*
         * The 0 index (SRR1[42:45]=b0000) must always evaluate to 0,
         * so this can be called unconditionally with the SRR1 wake
index f3bd0bb..2d4d21b 100644 (file)
@@ -55,14 +55,17 @@ _GLOBAL(ppc_save_regs)
        PPC_STL r29,29*SZL(r3)
        PPC_STL r30,30*SZL(r3)
        PPC_STL r31,31*SZL(r3)
+       lbz     r0,PACAIRQSOFTMASK(r13)
+       PPC_STL r0,SOFTE-STACK_FRAME_OVERHEAD(r3)
 #endif
        /* go up one stack frame for SP */
        PPC_LL  r4,0(r1)
        PPC_STL r4,1*SZL(r3)
        /* get caller's LR */
        PPC_LL  r0,LRSAVE(r4)
-       PPC_STL r0,_NIP-STACK_FRAME_OVERHEAD(r3)
        PPC_STL r0,_LINK-STACK_FRAME_OVERHEAD(r3)
+       mflr    r0
+       PPC_STL r0,_NIP-STACK_FRAME_OVERHEAD(r3)
        mfmsr   r0
        PPC_STL r0,_MSR-STACK_FRAME_OVERHEAD(r3)
        mfctr   r0
@@ -73,4 +76,5 @@ _GLOBAL(ppc_save_regs)
        PPC_STL r0,_CCR-STACK_FRAME_OVERHEAD(r3)
        li      r0,0
        PPC_STL r0,_TRAP-STACK_FRAME_OVERHEAD(r3)
+       PPC_STL r0,ORIG_GPR3-STACK_FRAME_OVERHEAD(r3)
        blr
index e9d97c2..c2f2402 100644 (file)
@@ -6,7 +6,7 @@
 CFLAGS_ptrace-view.o           += -DUTS_MACHINE='"$(UTS_MACHINE)"'
 
 obj-y                          += ptrace.o ptrace-view.o
-obj-$(CONFIG_PPC64)            += ptrace32.o
+obj-$(CONFIG_COMPAT)           += ptrace32.o
 obj-$(CONFIG_VSX)              += ptrace-vsx.o
 ifneq ($(CONFIG_VSX),y)
 obj-y                          += ptrace-novsx.o
index d215f95..a264989 100644 (file)
 #include <linux/syscalls.h>
 #include <asm/hw_breakpoint.h>
 #include <linux/uaccess.h>
+#include <asm/switch_to.h>
 #include <asm/unistd.h>
 #include <asm/debug.h>
 #include <asm/tm.h>
 
 #include "signal.h"
 
+#ifdef CONFIG_VSX
+unsigned long copy_fpr_to_user(void __user *to,
+                              struct task_struct *task)
+{
+       u64 buf[ELF_NFPREG];
+       int i;
+
+       /* save FPR copy to local buffer then write to the thread_struct */
+       for (i = 0; i < (ELF_NFPREG - 1) ; i++)
+               buf[i] = task->thread.TS_FPR(i);
+       buf[i] = task->thread.fp_state.fpscr;
+       return __copy_to_user(to, buf, ELF_NFPREG * sizeof(double));
+}
+
+unsigned long copy_fpr_from_user(struct task_struct *task,
+                                void __user *from)
+{
+       u64 buf[ELF_NFPREG];
+       int i;
+
+       if (__copy_from_user(buf, from, ELF_NFPREG * sizeof(double)))
+               return 1;
+       for (i = 0; i < (ELF_NFPREG - 1) ; i++)
+               task->thread.TS_FPR(i) = buf[i];
+       task->thread.fp_state.fpscr = buf[i];
+
+       return 0;
+}
+
+unsigned long copy_vsx_to_user(void __user *to,
+                              struct task_struct *task)
+{
+       u64 buf[ELF_NVSRHALFREG];
+       int i;
+
+       /* save FPR copy to local buffer then write to the thread_struct */
+       for (i = 0; i < ELF_NVSRHALFREG; i++)
+               buf[i] = task->thread.fp_state.fpr[i][TS_VSRLOWOFFSET];
+       return __copy_to_user(to, buf, ELF_NVSRHALFREG * sizeof(double));
+}
+
+unsigned long copy_vsx_from_user(struct task_struct *task,
+                                void __user *from)
+{
+       u64 buf[ELF_NVSRHALFREG];
+       int i;
+
+       if (__copy_from_user(buf, from, ELF_NVSRHALFREG * sizeof(double)))
+               return 1;
+       for (i = 0; i < ELF_NVSRHALFREG ; i++)
+               task->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];
+       return 0;
+}
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+unsigned long copy_ckfpr_to_user(void __user *to,
+                                 struct task_struct *task)
+{
+       u64 buf[ELF_NFPREG];
+       int i;
+
+       /* save FPR copy to local buffer then write to the thread_struct */
+       for (i = 0; i < (ELF_NFPREG - 1) ; i++)
+               buf[i] = task->thread.TS_CKFPR(i);
+       buf[i] = task->thread.ckfp_state.fpscr;
+       return __copy_to_user(to, buf, ELF_NFPREG * sizeof(double));
+}
+
+unsigned long copy_ckfpr_from_user(struct task_struct *task,
+                                         void __user *from)
+{
+       u64 buf[ELF_NFPREG];
+       int i;
+
+       if (__copy_from_user(buf, from, ELF_NFPREG * sizeof(double)))
+               return 1;
+       for (i = 0; i < (ELF_NFPREG - 1) ; i++)
+               task->thread.TS_CKFPR(i) = buf[i];
+       task->thread.ckfp_state.fpscr = buf[i];
+
+       return 0;
+}
+
+unsigned long copy_ckvsx_to_user(void __user *to,
+                                 struct task_struct *task)
+{
+       u64 buf[ELF_NVSRHALFREG];
+       int i;
+
+       /* save FPR copy to local buffer then write to the thread_struct */
+       for (i = 0; i < ELF_NVSRHALFREG; i++)
+               buf[i] = task->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET];
+       return __copy_to_user(to, buf, ELF_NVSRHALFREG * sizeof(double));
+}
+
+unsigned long copy_ckvsx_from_user(struct task_struct *task,
+                                         void __user *from)
+{
+       u64 buf[ELF_NVSRHALFREG];
+       int i;
+
+       if (__copy_from_user(buf, from, ELF_NVSRHALFREG * sizeof(double)))
+               return 1;
+       for (i = 0; i < ELF_NVSRHALFREG ; i++)
+               task->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];
+       return 0;
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+#else
+inline unsigned long copy_fpr_to_user(void __user *to,
+                                     struct task_struct *task)
+{
+       return __copy_to_user(to, task->thread.fp_state.fpr,
+                             ELF_NFPREG * sizeof(double));
+}
+
+inline unsigned long copy_fpr_from_user(struct task_struct *task,
+                                       void __user *from)
+{
+       return __copy_from_user(task->thread.fp_state.fpr, from,
+                             ELF_NFPREG * sizeof(double));
+}
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+inline unsigned long copy_ckfpr_to_user(void __user *to,
+                                        struct task_struct *task)
+{
+       return __copy_to_user(to, task->thread.ckfp_state.fpr,
+                             ELF_NFPREG * sizeof(double));
+}
+
+inline unsigned long copy_ckfpr_from_user(struct task_struct *task,
+                                                void __user *from)
+{
+       return __copy_from_user(task->thread.ckfp_state.fpr, from,
+                               ELF_NFPREG * sizeof(double));
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+#endif
+
 /* Log an error when sending an unhandled signal to a process. Controlled
  * through debug.exception-trace sysctl.
  */
@@ -106,7 +247,6 @@ static void do_signal(struct task_struct *tsk)
        sigset_t *oldset = sigmask_to_save();
        struct ksignal ksig = { .sig = 0 };
        int ret;
-       int is32 = is_32bit_task();
 
        BUG_ON(tsk != current);
 
@@ -136,7 +276,7 @@ static void do_signal(struct task_struct *tsk)
 
        rseq_signal_deliver(&ksig, tsk->thread.regs);
 
-       if (is32) {
+       if (is_32bit_task()) {
                if (ksig.ka.sa.sa_flags & SA_SIGINFO)
                        ret = handle_rt_signal32(&ksig, oldset, tsk);
                else
index 1b090a7..4f96d29 100644 (file)
@@ -235,146 +235,6 @@ struct rt_sigframe {
        int                     abigap[56];
 };
 
-#ifdef CONFIG_VSX
-unsigned long copy_fpr_to_user(void __user *to,
-                              struct task_struct *task)
-{
-       u64 buf[ELF_NFPREG];
-       int i;
-
-       /* save FPR copy to local buffer then write to the thread_struct */
-       for (i = 0; i < (ELF_NFPREG - 1) ; i++)
-               buf[i] = task->thread.TS_FPR(i);
-       buf[i] = task->thread.fp_state.fpscr;
-       return __copy_to_user(to, buf, ELF_NFPREG * sizeof(double));
-}
-
-unsigned long copy_fpr_from_user(struct task_struct *task,
-                                void __user *from)
-{
-       u64 buf[ELF_NFPREG];
-       int i;
-
-       if (__copy_from_user(buf, from, ELF_NFPREG * sizeof(double)))
-               return 1;
-       for (i = 0; i < (ELF_NFPREG - 1) ; i++)
-               task->thread.TS_FPR(i) = buf[i];
-       task->thread.fp_state.fpscr = buf[i];
-
-       return 0;
-}
-
-unsigned long copy_vsx_to_user(void __user *to,
-                              struct task_struct *task)
-{
-       u64 buf[ELF_NVSRHALFREG];
-       int i;
-
-       /* save FPR copy to local buffer then write to the thread_struct */
-       for (i = 0; i < ELF_NVSRHALFREG; i++)
-               buf[i] = task->thread.fp_state.fpr[i][TS_VSRLOWOFFSET];
-       return __copy_to_user(to, buf, ELF_NVSRHALFREG * sizeof(double));
-}
-
-unsigned long copy_vsx_from_user(struct task_struct *task,
-                                void __user *from)
-{
-       u64 buf[ELF_NVSRHALFREG];
-       int i;
-
-       if (__copy_from_user(buf, from, ELF_NVSRHALFREG * sizeof(double)))
-               return 1;
-       for (i = 0; i < ELF_NVSRHALFREG ; i++)
-               task->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];
-       return 0;
-}
-
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-unsigned long copy_ckfpr_to_user(void __user *to,
-                                 struct task_struct *task)
-{
-       u64 buf[ELF_NFPREG];
-       int i;
-
-       /* save FPR copy to local buffer then write to the thread_struct */
-       for (i = 0; i < (ELF_NFPREG - 1) ; i++)
-               buf[i] = task->thread.TS_CKFPR(i);
-       buf[i] = task->thread.ckfp_state.fpscr;
-       return __copy_to_user(to, buf, ELF_NFPREG * sizeof(double));
-}
-
-unsigned long copy_ckfpr_from_user(struct task_struct *task,
-                                         void __user *from)
-{
-       u64 buf[ELF_NFPREG];
-       int i;
-
-       if (__copy_from_user(buf, from, ELF_NFPREG * sizeof(double)))
-               return 1;
-       for (i = 0; i < (ELF_NFPREG - 1) ; i++)
-               task->thread.TS_CKFPR(i) = buf[i];
-       task->thread.ckfp_state.fpscr = buf[i];
-
-       return 0;
-}
-
-unsigned long copy_ckvsx_to_user(void __user *to,
-                                 struct task_struct *task)
-{
-       u64 buf[ELF_NVSRHALFREG];
-       int i;
-
-       /* save FPR copy to local buffer then write to the thread_struct */
-       for (i = 0; i < ELF_NVSRHALFREG; i++)
-               buf[i] = task->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET];
-       return __copy_to_user(to, buf, ELF_NVSRHALFREG * sizeof(double));
-}
-
-unsigned long copy_ckvsx_from_user(struct task_struct *task,
-                                         void __user *from)
-{
-       u64 buf[ELF_NVSRHALFREG];
-       int i;
-
-       if (__copy_from_user(buf, from, ELF_NVSRHALFREG * sizeof(double)))
-               return 1;
-       for (i = 0; i < ELF_NVSRHALFREG ; i++)
-               task->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];
-       return 0;
-}
-#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
-#else
-inline unsigned long copy_fpr_to_user(void __user *to,
-                                     struct task_struct *task)
-{
-       return __copy_to_user(to, task->thread.fp_state.fpr,
-                             ELF_NFPREG * sizeof(double));
-}
-
-inline unsigned long copy_fpr_from_user(struct task_struct *task,
-                                       void __user *from)
-{
-       return __copy_from_user(task->thread.fp_state.fpr, from,
-                             ELF_NFPREG * sizeof(double));
-}
-
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-inline unsigned long copy_ckfpr_to_user(void __user *to,
-                                        struct task_struct *task)
-{
-       return __copy_to_user(to, task->thread.ckfp_state.fpr,
-                             ELF_NFPREG * sizeof(double));
-}
-
-inline unsigned long copy_ckfpr_from_user(struct task_struct *task,
-                                                void __user *from)
-{
-       return __copy_from_user(task->thread.ckfp_state.fpr, from,
-                               ELF_NFPREG * sizeof(double));
-}
-#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
-#endif
-
 /*
  * Save the current user registers on the user stack.
  * We only save the altivec/spe registers if the process has used
index cf06eb4..c74295a 100644 (file)
@@ -22,7 +22,6 @@ notrace long system_call_exception(long r3, long r4, long r5,
                                   long r6, long r7, long r8,
                                   unsigned long r0, struct pt_regs *regs)
 {
-       unsigned long ti_flags;
        syscall_fn f;
 
        if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
@@ -60,8 +59,7 @@ notrace long system_call_exception(long r3, long r4, long r5,
 
        local_irq_enable();
 
-       ti_flags = current_thread_info()->flags;
-       if (unlikely(ti_flags & _TIF_SYSCALL_DOTRACE)) {
+       if (unlikely(current_thread_info()->flags & _TIF_SYSCALL_DOTRACE)) {
                /*
                 * We use the return value of do_syscall_trace_enter() as the
                 * syscall number. If the syscall was rejected for any reason
@@ -86,7 +84,7 @@ notrace long system_call_exception(long r3, long r4, long r5,
        /* May be faster to do array_index_nospec? */
        barrier_nospec();
 
-       if (unlikely(ti_flags & _TIF_32BIT)) {
+       if (unlikely(is_32bit_task())) {
                f = (void *)compat_sys_call_table[r0];
 
                r3 &= 0x00000000ffffffffULL;
index bda9cb4..6fcae43 100644 (file)
@@ -50,7 +50,7 @@
 #include <linux/irq.h>
 #include <linux/delay.h>
 #include <linux/irq_work.h>
-#include <linux/clk-provider.h>
+#include <linux/of_clk.h>
 #include <linux/suspend.h>
 #include <linux/sched/cputime.h>
 #include <linux/processor.h>
@@ -522,35 +522,6 @@ static inline void clear_irq_work_pending(void)
                "i" (offsetof(struct paca_struct, irq_work_pending)));
 }
 
-void arch_irq_work_raise(void)
-{
-       preempt_disable();
-       set_irq_work_pending_flag();
-       /*
-        * Non-nmi code running with interrupts disabled will replay
-        * irq_happened before it re-enables interrupts, so setthe
-        * decrementer there instead of causing a hardware exception
-        * which would immediately hit the masked interrupt handler
-        * and have the net effect of setting the decrementer in
-        * irq_happened.
-        *
-        * NMI interrupts can not check this when they return, so the
-        * decrementer hardware exception is raised, which will fire
-        * when interrupts are next enabled.
-        *
-        * BookE does not support this yet, it must audit all NMI
-        * interrupt handlers to ensure they call nmi_enter() so this
-        * check would be correct.
-        */
-       if (IS_ENABLED(CONFIG_BOOKE) || !irqs_disabled() || in_nmi()) {
-               set_dec(1);
-       } else {
-               hard_irq_disable();
-               local_paca->irq_happened |= PACA_IRQ_DEC;
-       }
-       preempt_enable();
-}
-
 #else /* 32-bit */
 
 DEFINE_PER_CPU(u8, irq_work_pending);
@@ -559,16 +530,27 @@ DEFINE_PER_CPU(u8, irq_work_pending);
 #define test_irq_work_pending()                __this_cpu_read(irq_work_pending)
 #define clear_irq_work_pending()       __this_cpu_write(irq_work_pending, 0)
 
+#endif /* 32 vs 64 bit */
+
 void arch_irq_work_raise(void)
 {
+       /*
+        * 64-bit code that uses irq soft-mask can just cause an immediate
+        * interrupt here that gets soft masked, if this is called under
+        * local_irq_disable(). It might be possible to prevent that happening
+        * by noticing interrupts are disabled and setting decrementer pending
+        * to be replayed when irqs are enabled. The problem there is that
+        * tracing can call irq_work_raise, including in code that does low
+        * level manipulations of irq soft-mask state (e.g., trace_hardirqs_on)
+        * which could get tangled up if we're messing with the same state
+        * here.
+        */
        preempt_disable();
        set_irq_work_pending_flag();
        set_dec(1);
        preempt_enable();
 }
 
-#endif /* 32 vs 64 bit */
-
 #else  /* CONFIG_IRQ_WORK */
 
 #define test_irq_work_pending()        0
@@ -1149,9 +1131,7 @@ void __init time_init(void)
        init_decrementer_clockevent();
        tick_setup_hrtimer_broadcast();
 
-#ifdef CONFIG_COMMON_CLK
        of_clk_init(NULL);
-#endif
 }
 
 /*
index d3b77c1..f38f26e 100644 (file)
@@ -651,7 +651,8 @@ static void __init vdso_setup_syscall_map(void)
                if (sys_call_table[i] != sys_ni_syscall)
                        vdso_data->syscall_map_64[i >> 5] |=
                                0x80000000UL >> (i & 0x1f);
-               if (compat_sys_call_table[i] != sys_ni_syscall)
+               if (IS_ENABLED(CONFIG_COMPAT) &&
+                   compat_sys_call_table[i] != sys_ni_syscall)
                        vdso_data->syscall_map_32[i >> 5] |=
                                0x80000000UL >> (i & 0x1f);
 #else /* CONFIG_PPC64 */
index 711fca9..12885ed 100644 (file)
@@ -204,6 +204,4 @@ config KVM_XIVE
        default y
        depends on KVM_XICS && PPC_XIVE_NATIVE && KVM_BOOK3S_HV_POSSIBLE
 
-source "drivers/vhost/Kconfig"
-
 endif # VIRTUALIZATION
index 7e5714a..8ed2411 100644 (file)
@@ -809,7 +809,8 @@ int resize_hpt_for_hotplug(unsigned long new_mem_size)
        return 0;
 }
 
-int hash__create_section_mapping(unsigned long start, unsigned long end, int nid)
+int hash__create_section_mapping(unsigned long start, unsigned long end,
+                                int nid, pgprot_t prot)
 {
        int rc;
 
@@ -819,7 +820,7 @@ int hash__create_section_mapping(unsigned long start, unsigned long end, int nid
        }
 
        rc = htab_bolt_mapping(start, end, __pa(start),
-                              pgprot_val(PAGE_KERNEL), mmu_linear_psize,
+                              pgprot_val(prot), mmu_linear_psize,
                               mmu_kernel_ssize);
 
        if (rc < 0) {
index 2bf7e1b..e0bb69c 100644 (file)
@@ -171,12 +171,13 @@ void mmu_cleanup_all(void)
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-int __meminit create_section_mapping(unsigned long start, unsigned long end, int nid)
+int __meminit create_section_mapping(unsigned long start, unsigned long end,
+                                    int nid, pgprot_t prot)
 {
        if (radix_enabled())
-               return radix__create_section_mapping(start, end, nid);
+               return radix__create_section_mapping(start, end, nid, prot);
 
-       return hash__create_section_mapping(start, end, nid);
+       return hash__create_section_mapping(start, end, nid, prot);
 }
 
 int __meminit remove_section_mapping(unsigned long start, unsigned long end)
index 07527f1..1199fc2 100644 (file)
@@ -315,7 +315,7 @@ int __execute_only_pkey(struct mm_struct *mm)
 static inline bool vma_is_pkey_exec_only(struct vm_area_struct *vma)
 {
        /* Do this check first since the vm_flags should be hot */
-       if ((vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)) != VM_EXEC)
+       if ((vma->vm_flags & VM_ACCESS_FLAGS) != VM_EXEC)
                return false;
 
        return (vma_pkey(vma) == vma->vm_mm->context.execute_only_pkey);
index 2a9a0cd..8f9edf0 100644 (file)
@@ -254,7 +254,7 @@ static unsigned long next_boundary(unsigned long addr, unsigned long end)
 
 static int __meminit create_physical_mapping(unsigned long start,
                                             unsigned long end,
-                                            int nid)
+                                            int nid, pgprot_t _prot)
 {
        unsigned long vaddr, addr, mapping_size = 0;
        bool prev_exec, exec = false;
@@ -290,7 +290,7 @@ static int __meminit create_physical_mapping(unsigned long start,
                        prot = PAGE_KERNEL_X;
                        exec = true;
                } else {
-                       prot = PAGE_KERNEL;
+                       prot = _prot;
                        exec = false;
                }
 
@@ -334,7 +334,7 @@ static void __init radix_init_pgtable(void)
 
                WARN_ON(create_physical_mapping(reg->base,
                                                reg->base + reg->size,
-                                               -1));
+                                               -1, PAGE_KERNEL));
        }
 
        /* Find out how many PID bits are supported */
@@ -713,8 +713,10 @@ static int __meminit stop_machine_change_mapping(void *data)
 
        spin_unlock(&init_mm.page_table_lock);
        pte_clear(&init_mm, params->aligned_start, params->pte);
-       create_physical_mapping(__pa(params->aligned_start), __pa(params->start), -1);
-       create_physical_mapping(__pa(params->end), __pa(params->aligned_end), -1);
+       create_physical_mapping(__pa(params->aligned_start),
+                               __pa(params->start), -1, PAGE_KERNEL);
+       create_physical_mapping(__pa(params->end), __pa(params->aligned_end),
+                               -1, PAGE_KERNEL);
        spin_lock(&init_mm.page_table_lock);
        return 0;
 }
@@ -871,14 +873,16 @@ static void __meminit remove_pagetable(unsigned long start, unsigned long end)
        radix__flush_tlb_kernel_range(start, end);
 }
 
-int __meminit radix__create_section_mapping(unsigned long start, unsigned long end, int nid)
+int __meminit radix__create_section_mapping(unsigned long start,
+                                           unsigned long end, int nid,
+                                           pgprot_t prot)
 {
        if (end >= RADIX_VMALLOC_START) {
                pr_warn("Outside the supported range\n");
                return -1;
        }
 
-       return create_physical_mapping(__pa(start), __pa(end), nid);
+       return create_physical_mapping(__pa(start), __pa(end), nid, prot);
 }
 
 int __meminit radix__remove_section_mapping(unsigned long start, unsigned long end)
index fc66964..b1a0aeb 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/mmzone.h>
 #include <linux/vmalloc.h>
 #include <asm/io-workarounds.h>
 
@@ -97,3 +98,23 @@ void __iomem *do_ioremap(phys_addr_t pa, phys_addr_t offset, unsigned long size,
 
        return NULL;
 }
+
+#ifdef CONFIG_ZONE_DEVICE
+/*
+ * Override the generic version in mm/memremap.c.
+ *
+ * With hash translation, the direct-map range is mapped with just one
+ * page size selected by htab_init_page_sizes(). Consult
+ * mmu_psize_defs[] to determine the minimum page size alignment.
+*/
+unsigned long memremap_compat_align(void)
+{
+       unsigned int shift = mmu_psize_defs[mmu_linear_psize].shift;
+
+       if (radix_enabled())
+               return SUBSECTION_SIZE;
+       return max(SUBSECTION_SIZE, 1UL << shift);
+
+}
+EXPORT_SYMBOL_GPL(memremap_compat_align);
+#endif
index 9b4f5fb..041ed7c 100644 (file)
@@ -90,7 +90,8 @@ int memory_add_physaddr_to_nid(u64 start)
 }
 #endif
 
-int __weak create_section_mapping(unsigned long start, unsigned long end, int nid)
+int __weak create_section_mapping(unsigned long start, unsigned long end,
+                                 int nid, pgprot_t prot)
 {
        return -ENODEV;
 }
@@ -122,7 +123,7 @@ static void flush_dcache_range_chunked(unsigned long start, unsigned long stop,
 }
 
 int __ref arch_add_memory(int nid, u64 start, u64 size,
-                       struct mhp_restrictions *restrictions)
+                         struct mhp_params *params)
 {
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
@@ -131,14 +132,15 @@ int __ref arch_add_memory(int nid, u64 start, u64 size,
        resize_hpt_for_hotplug(memblock_phys_mem_size());
 
        start = (unsigned long)__va(start);
-       rc = create_section_mapping(start, start + size, nid);
+       rc = create_section_mapping(start, start + size, nid,
+                                   params->pgprot);
        if (rc) {
                pr_warn("Unable to create mapping for hot added memory 0x%llx..0x%llx: %d\n",
                        start, start + size, rc);
                return -EFAULT;
        }
 
-       return __add_pages(nid, start_pfn, nr_pages, restrictions);
+       return __add_pages(nid, start_pfn, nr_pages, params);
 }
 
 void __ref arch_remove_memory(int nid, u64 start, u64 size,
index c155dcb..53d614e 100644 (file)
@@ -1,6 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_PERF_EVENTS)      += callchain.o perf_regs.o
+obj-$(CONFIG_PERF_EVENTS)      += callchain.o callchain_$(BITS).o perf_regs.o
+ifdef CONFIG_COMPAT
+obj-$(CONFIG_PERF_EVENTS)      += callchain_32.o
+endif
 
 obj-$(CONFIG_PPC_PERF_CTRS)    += core-book3s.o bhrb.o
 obj64-$(CONFIG_PPC_PERF_CTRS)  += ppc970-pmu.o power5-pmu.o \
index cbc2519..dd50510 100644 (file)
 #include <asm/sigcontext.h>
 #include <asm/ucontext.h>
 #include <asm/vdso.h>
-#ifdef CONFIG_PPC64
-#include "../kernel/ppc32.h"
-#endif
 #include <asm/pte-walk.h>
 
+#include "callchain.h"
 
 /*
  * Is sp valid as the address of the next kernel stack frame after prev_sp?
@@ -102,358 +100,6 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re
        }
 }
 
-#ifdef CONFIG_PPC64
-/*
- * On 64-bit we don't want to invoke hash_page on user addresses from
- * interrupt context, so if the access faults, we read the page tables
- * to find which page (if any) is mapped and access it directly.
- */
-static int read_user_stack_slow(void __user *ptr, void *buf, int nb)
-{
-       int ret = -EFAULT;
-       pgd_t *pgdir;
-       pte_t *ptep, pte;
-       unsigned shift;
-       unsigned long addr = (unsigned long) ptr;
-       unsigned long offset;
-       unsigned long pfn, flags;
-       void *kaddr;
-
-       pgdir = current->mm->pgd;
-       if (!pgdir)
-               return -EFAULT;
-
-       local_irq_save(flags);
-       ptep = find_current_mm_pte(pgdir, addr, NULL, &shift);
-       if (!ptep)
-               goto err_out;
-       if (!shift)
-               shift = PAGE_SHIFT;
-
-       /* align address to page boundary */
-       offset = addr & ((1UL << shift) - 1);
-
-       pte = READ_ONCE(*ptep);
-       if (!pte_present(pte) || !pte_user(pte))
-               goto err_out;
-       pfn = pte_pfn(pte);
-       if (!page_is_ram(pfn))
-               goto err_out;
-
-       /* no highmem to worry about here */
-       kaddr = pfn_to_kaddr(pfn);
-       memcpy(buf, kaddr + offset, nb);
-       ret = 0;
-err_out:
-       local_irq_restore(flags);
-       return ret;
-}
-
-static int read_user_stack_64(unsigned long __user *ptr, unsigned long *ret)
-{
-       if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned long) ||
-           ((unsigned long)ptr & 7))
-               return -EFAULT;
-
-       if (!probe_user_read(ret, ptr, sizeof(*ret)))
-               return 0;
-
-       return read_user_stack_slow(ptr, ret, 8);
-}
-
-static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
-{
-       if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
-           ((unsigned long)ptr & 3))
-               return -EFAULT;
-
-       if (!probe_user_read(ret, ptr, sizeof(*ret)))
-               return 0;
-
-       return read_user_stack_slow(ptr, ret, 4);
-}
-
-static inline int valid_user_sp(unsigned long sp, int is_64)
-{
-       if (!sp || (sp & 7) || sp > (is_64 ? TASK_SIZE : 0x100000000UL) - 32)
-               return 0;
-       return 1;
-}
-
-/*
- * 64-bit user processes use the same stack frame for RT and non-RT signals.
- */
-struct signal_frame_64 {
-       char            dummy[__SIGNAL_FRAMESIZE];
-       struct ucontext uc;
-       unsigned long   unused[2];
-       unsigned int    tramp[6];
-       struct siginfo  *pinfo;
-       void            *puc;
-       struct siginfo  info;
-       char            abigap[288];
-};
-
-static int is_sigreturn_64_address(unsigned long nip, unsigned long fp)
-{
-       if (nip == fp + offsetof(struct signal_frame_64, tramp))
-               return 1;
-       if (vdso64_rt_sigtramp && current->mm->context.vdso_base &&
-           nip == current->mm->context.vdso_base + vdso64_rt_sigtramp)
-               return 1;
-       return 0;
-}
-
-/*
- * Do some sanity checking on the signal frame pointed to by sp.
- * We check the pinfo and puc pointers in the frame.
- */
-static int sane_signal_64_frame(unsigned long sp)
-{
-       struct signal_frame_64 __user *sf;
-       unsigned long pinfo, puc;
-
-       sf = (struct signal_frame_64 __user *) sp;
-       if (read_user_stack_64((unsigned long __user *) &sf->pinfo, &pinfo) ||
-           read_user_stack_64((unsigned long __user *) &sf->puc, &puc))
-               return 0;
-       return pinfo == (unsigned long) &sf->info &&
-               puc == (unsigned long) &sf->uc;
-}
-
-static void perf_callchain_user_64(struct perf_callchain_entry_ctx *entry,
-                                  struct pt_regs *regs)
-{
-       unsigned long sp, next_sp;
-       unsigned long next_ip;
-       unsigned long lr;
-       long level = 0;
-       struct signal_frame_64 __user *sigframe;
-       unsigned long __user *fp, *uregs;
-
-       next_ip = perf_instruction_pointer(regs);
-       lr = regs->link;
-       sp = regs->gpr[1];
-       perf_callchain_store(entry, next_ip);
-
-       while (entry->nr < entry->max_stack) {
-               fp = (unsigned long __user *) sp;
-               if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp))
-                       return;
-               if (level > 0 && read_user_stack_64(&fp[2], &next_ip))
-                       return;
-
-               /*
-                * Note: the next_sp - sp >= signal frame size check
-                * is true when next_sp < sp, which can happen when
-                * transitioning from an alternate signal stack to the
-                * normal stack.
-                */
-               if (next_sp - sp >= sizeof(struct signal_frame_64) &&
-                   (is_sigreturn_64_address(next_ip, sp) ||
-                    (level <= 1 && is_sigreturn_64_address(lr, sp))) &&
-                   sane_signal_64_frame(sp)) {
-                       /*
-                        * This looks like an signal frame
-                        */
-                       sigframe = (struct signal_frame_64 __user *) sp;
-                       uregs = sigframe->uc.uc_mcontext.gp_regs;
-                       if (read_user_stack_64(&uregs[PT_NIP], &next_ip) ||
-                           read_user_stack_64(&uregs[PT_LNK], &lr) ||
-                           read_user_stack_64(&uregs[PT_R1], &sp))
-                               return;
-                       level = 0;
-                       perf_callchain_store_context(entry, PERF_CONTEXT_USER);
-                       perf_callchain_store(entry, next_ip);
-                       continue;
-               }
-
-               if (level == 0)
-                       next_ip = lr;
-               perf_callchain_store(entry, next_ip);
-               ++level;
-               sp = next_sp;
-       }
-}
-
-#else  /* CONFIG_PPC64 */
-/*
- * On 32-bit we just access the address and let hash_page create a
- * HPTE if necessary, so there is no need to fall back to reading
- * the page tables.  Since this is called at interrupt level,
- * do_page_fault() won't treat a DSI as a page fault.
- */
-static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
-{
-       if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
-           ((unsigned long)ptr & 3))
-               return -EFAULT;
-
-       return probe_user_read(ret, ptr, sizeof(*ret));
-}
-
-static inline void perf_callchain_user_64(struct perf_callchain_entry_ctx *entry,
-                                         struct pt_regs *regs)
-{
-}
-
-static inline int valid_user_sp(unsigned long sp, int is_64)
-{
-       if (!sp || (sp & 7) || sp > TASK_SIZE - 32)
-               return 0;
-       return 1;
-}
-
-#define __SIGNAL_FRAMESIZE32   __SIGNAL_FRAMESIZE
-#define sigcontext32           sigcontext
-#define mcontext32             mcontext
-#define ucontext32             ucontext
-#define compat_siginfo_t       struct siginfo
-
-#endif /* CONFIG_PPC64 */
-
-/*
- * Layout for non-RT signal frames
- */
-struct signal_frame_32 {
-       char                    dummy[__SIGNAL_FRAMESIZE32];
-       struct sigcontext32     sctx;
-       struct mcontext32       mctx;
-       int                     abigap[56];
-};
-
-/*
- * Layout for RT signal frames
- */
-struct rt_signal_frame_32 {
-       char                    dummy[__SIGNAL_FRAMESIZE32 + 16];
-       compat_siginfo_t        info;
-       struct ucontext32       uc;
-       int                     abigap[56];
-};
-
-static int is_sigreturn_32_address(unsigned int nip, unsigned int fp)
-{
-       if (nip == fp + offsetof(struct signal_frame_32, mctx.mc_pad))
-               return 1;
-       if (vdso32_sigtramp && current->mm->context.vdso_base &&
-           nip == current->mm->context.vdso_base + vdso32_sigtramp)
-               return 1;
-       return 0;
-}
-
-static int is_rt_sigreturn_32_address(unsigned int nip, unsigned int fp)
-{
-       if (nip == fp + offsetof(struct rt_signal_frame_32,
-                                uc.uc_mcontext.mc_pad))
-               return 1;
-       if (vdso32_rt_sigtramp && current->mm->context.vdso_base &&
-           nip == current->mm->context.vdso_base + vdso32_rt_sigtramp)
-               return 1;
-       return 0;
-}
-
-static int sane_signal_32_frame(unsigned int sp)
-{
-       struct signal_frame_32 __user *sf;
-       unsigned int regs;
-
-       sf = (struct signal_frame_32 __user *) (unsigned long) sp;
-       if (read_user_stack_32((unsigned int __user *) &sf->sctx.regs, &regs))
-               return 0;
-       return regs == (unsigned long) &sf->mctx;
-}
-
-static int sane_rt_signal_32_frame(unsigned int sp)
-{
-       struct rt_signal_frame_32 __user *sf;
-       unsigned int regs;
-
-       sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
-       if (read_user_stack_32((unsigned int __user *) &sf->uc.uc_regs, &regs))
-               return 0;
-       return regs == (unsigned long) &sf->uc.uc_mcontext;
-}
-
-static unsigned int __user *signal_frame_32_regs(unsigned int sp,
-                               unsigned int next_sp, unsigned int next_ip)
-{
-       struct mcontext32 __user *mctx = NULL;
-       struct signal_frame_32 __user *sf;
-       struct rt_signal_frame_32 __user *rt_sf;
-
-       /*
-        * Note: the next_sp - sp >= signal frame size check
-        * is true when next_sp < sp, for example, when
-        * transitioning from an alternate signal stack to the
-        * normal stack.
-        */
-       if (next_sp - sp >= sizeof(struct signal_frame_32) &&
-           is_sigreturn_32_address(next_ip, sp) &&
-           sane_signal_32_frame(sp)) {
-               sf = (struct signal_frame_32 __user *) (unsigned long) sp;
-               mctx = &sf->mctx;
-       }
-
-       if (!mctx && next_sp - sp >= sizeof(struct rt_signal_frame_32) &&
-           is_rt_sigreturn_32_address(next_ip, sp) &&
-           sane_rt_signal_32_frame(sp)) {
-               rt_sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
-               mctx = &rt_sf->uc.uc_mcontext;
-       }
-
-       if (!mctx)
-               return NULL;
-       return mctx->mc_gregs;
-}
-
-static void perf_callchain_user_32(struct perf_callchain_entry_ctx *entry,
-                                  struct pt_regs *regs)
-{
-       unsigned int sp, next_sp;
-       unsigned int next_ip;
-       unsigned int lr;
-       long level = 0;
-       unsigned int __user *fp, *uregs;
-
-       next_ip = perf_instruction_pointer(regs);
-       lr = regs->link;
-       sp = regs->gpr[1];
-       perf_callchain_store(entry, next_ip);
-
-       while (entry->nr < entry->max_stack) {
-               fp = (unsigned int __user *) (unsigned long) sp;
-               if (!valid_user_sp(sp, 0) || read_user_stack_32(fp, &next_sp))
-                       return;
-               if (level > 0 && read_user_stack_32(&fp[1], &next_ip))
-                       return;
-
-               uregs = signal_frame_32_regs(sp, next_sp, next_ip);
-               if (!uregs && level <= 1)
-                       uregs = signal_frame_32_regs(sp, next_sp, lr);
-               if (uregs) {
-                       /*
-                        * This looks like an signal frame, so restart
-                        * the stack trace with the values in it.
-                        */
-                       if (read_user_stack_32(&uregs[PT_NIP], &next_ip) ||
-                           read_user_stack_32(&uregs[PT_LNK], &lr) ||
-                           read_user_stack_32(&uregs[PT_R1], &sp))
-                               return;
-                       level = 0;
-                       perf_callchain_store_context(entry, PERF_CONTEXT_USER);
-                       perf_callchain_store(entry, next_ip);
-                       continue;
-               }
-
-               if (level == 0)
-                       next_ip = lr;
-               perf_callchain_store(entry, next_ip);
-               ++level;
-               sp = next_sp;
-       }
-}
-
 void
 perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
 {
diff --git a/arch/powerpc/perf/callchain.h b/arch/powerpc/perf/callchain.h
new file mode 100644 (file)
index 0000000..7a2cb9e
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _POWERPC_PERF_CALLCHAIN_H
+#define _POWERPC_PERF_CALLCHAIN_H
+
+int read_user_stack_slow(void __user *ptr, void *buf, int nb);
+void perf_callchain_user_64(struct perf_callchain_entry_ctx *entry,
+                           struct pt_regs *regs);
+void perf_callchain_user_32(struct perf_callchain_entry_ctx *entry,
+                           struct pt_regs *regs);
+
+static inline bool invalid_user_sp(unsigned long sp)
+{
+       unsigned long mask = is_32bit_task() ? 3 : 7;
+       unsigned long top = STACK_TOP - (is_32bit_task() ? 16 : 32);
+
+       return (!sp || (sp & mask) || (sp > top));
+}
+
+#endif /* _POWERPC_PERF_CALLCHAIN_H */
diff --git a/arch/powerpc/perf/callchain_32.c b/arch/powerpc/perf/callchain_32.c
new file mode 100644 (file)
index 0000000..8aa9510
--- /dev/null
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Performance counter callchain support - powerpc architecture code
+ *
+ * Copyright © 2009 Paul Mackerras, IBM Corporation.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/uaccess.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/pgtable.h>
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+#include <asm/vdso.h>
+#include <asm/pte-walk.h>
+
+#include "callchain.h"
+
+#ifdef CONFIG_PPC64
+#include "../kernel/ppc32.h"
+#else  /* CONFIG_PPC64 */
+
+#define __SIGNAL_FRAMESIZE32   __SIGNAL_FRAMESIZE
+#define sigcontext32           sigcontext
+#define mcontext32             mcontext
+#define ucontext32             ucontext
+#define compat_siginfo_t       struct siginfo
+
+#endif /* CONFIG_PPC64 */
+
+/*
+ * On 32-bit we just access the address and let hash_page create a
+ * HPTE if necessary, so there is no need to fall back to reading
+ * the page tables.  Since this is called at interrupt level,
+ * do_page_fault() won't treat a DSI as a page fault.
+ */
+static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
+{
+       int rc;
+
+       if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
+           ((unsigned long)ptr & 3))
+               return -EFAULT;
+
+       rc = probe_user_read(ret, ptr, sizeof(*ret));
+
+       if (IS_ENABLED(CONFIG_PPC64) && rc)
+               return read_user_stack_slow(ptr, ret, 4);
+
+       return rc;
+}
+
+/*
+ * Layout for non-RT signal frames
+ */
+struct signal_frame_32 {
+       char                    dummy[__SIGNAL_FRAMESIZE32];
+       struct sigcontext32     sctx;
+       struct mcontext32       mctx;
+       int                     abigap[56];
+};
+
+/*
+ * Layout for RT signal frames
+ */
+struct rt_signal_frame_32 {
+       char                    dummy[__SIGNAL_FRAMESIZE32 + 16];
+       compat_siginfo_t        info;
+       struct ucontext32       uc;
+       int                     abigap[56];
+};
+
+static int is_sigreturn_32_address(unsigned int nip, unsigned int fp)
+{
+       if (nip == fp + offsetof(struct signal_frame_32, mctx.mc_pad))
+               return 1;
+       if (vdso32_sigtramp && current->mm->context.vdso_base &&
+           nip == current->mm->context.vdso_base + vdso32_sigtramp)
+               return 1;
+       return 0;
+}
+
+static int is_rt_sigreturn_32_address(unsigned int nip, unsigned int fp)
+{
+       if (nip == fp + offsetof(struct rt_signal_frame_32,
+                                uc.uc_mcontext.mc_pad))
+               return 1;
+       if (vdso32_rt_sigtramp && current->mm->context.vdso_base &&
+           nip == current->mm->context.vdso_base + vdso32_rt_sigtramp)
+               return 1;
+       return 0;
+}
+
+static int sane_signal_32_frame(unsigned int sp)
+{
+       struct signal_frame_32 __user *sf;
+       unsigned int regs;
+
+       sf = (struct signal_frame_32 __user *) (unsigned long) sp;
+       if (read_user_stack_32((unsigned int __user *) &sf->sctx.regs, &regs))
+               return 0;
+       return regs == (unsigned long) &sf->mctx;
+}
+
+static int sane_rt_signal_32_frame(unsigned int sp)
+{
+       struct rt_signal_frame_32 __user *sf;
+       unsigned int regs;
+
+       sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
+       if (read_user_stack_32((unsigned int __user *) &sf->uc.uc_regs, &regs))
+               return 0;
+       return regs == (unsigned long) &sf->uc.uc_mcontext;
+}
+
+static unsigned int __user *signal_frame_32_regs(unsigned int sp,
+                               unsigned int next_sp, unsigned int next_ip)
+{
+       struct mcontext32 __user *mctx = NULL;
+       struct signal_frame_32 __user *sf;
+       struct rt_signal_frame_32 __user *rt_sf;
+
+       /*
+        * Note: the next_sp - sp >= signal frame size check
+        * is true when next_sp < sp, for example, when
+        * transitioning from an alternate signal stack to the
+        * normal stack.
+        */
+       if (next_sp - sp >= sizeof(struct signal_frame_32) &&
+           is_sigreturn_32_address(next_ip, sp) &&
+           sane_signal_32_frame(sp)) {
+               sf = (struct signal_frame_32 __user *) (unsigned long) sp;
+               mctx = &sf->mctx;
+       }
+
+       if (!mctx && next_sp - sp >= sizeof(struct rt_signal_frame_32) &&
+           is_rt_sigreturn_32_address(next_ip, sp) &&
+           sane_rt_signal_32_frame(sp)) {
+               rt_sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
+               mctx = &rt_sf->uc.uc_mcontext;
+       }
+
+       if (!mctx)
+               return NULL;
+       return mctx->mc_gregs;
+}
+
+void perf_callchain_user_32(struct perf_callchain_entry_ctx *entry,
+                           struct pt_regs *regs)
+{
+       unsigned int sp, next_sp;
+       unsigned int next_ip;
+       unsigned int lr;
+       long level = 0;
+       unsigned int __user *fp, *uregs;
+
+       next_ip = perf_instruction_pointer(regs);
+       lr = regs->link;
+       sp = regs->gpr[1];
+       perf_callchain_store(entry, next_ip);
+
+       while (entry->nr < entry->max_stack) {
+               fp = (unsigned int __user *) (unsigned long) sp;
+               if (invalid_user_sp(sp) || read_user_stack_32(fp, &next_sp))
+                       return;
+               if (level > 0 && read_user_stack_32(&fp[1], &next_ip))
+                       return;
+
+               uregs = signal_frame_32_regs(sp, next_sp, next_ip);
+               if (!uregs && level <= 1)
+                       uregs = signal_frame_32_regs(sp, next_sp, lr);
+               if (uregs) {
+                       /*
+                        * This looks like an signal frame, so restart
+                        * the stack trace with the values in it.
+                        */
+                       if (read_user_stack_32(&uregs[PT_NIP], &next_ip) ||
+                           read_user_stack_32(&uregs[PT_LNK], &lr) ||
+                           read_user_stack_32(&uregs[PT_R1], &sp))
+                               return;
+                       level = 0;
+                       perf_callchain_store_context(entry, PERF_CONTEXT_USER);
+                       perf_callchain_store(entry, next_ip);
+                       continue;
+               }
+
+               if (level == 0)
+                       next_ip = lr;
+               perf_callchain_store(entry, next_ip);
+               ++level;
+               sp = next_sp;
+       }
+}
diff --git a/arch/powerpc/perf/callchain_64.c b/arch/powerpc/perf/callchain_64.c
new file mode 100644 (file)
index 0000000..df1ffd8
--- /dev/null
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Performance counter callchain support - powerpc architecture code
+ *
+ * Copyright © 2009 Paul Mackerras, IBM Corporation.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/uaccess.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/pgtable.h>
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+#include <asm/vdso.h>
+#include <asm/pte-walk.h>
+
+#include "callchain.h"
+
+/*
+ * On 64-bit we don't want to invoke hash_page on user addresses from
+ * interrupt context, so if the access faults, we read the page tables
+ * to find which page (if any) is mapped and access it directly.
+ */
+int read_user_stack_slow(void __user *ptr, void *buf, int nb)
+{
+       int ret = -EFAULT;
+       pgd_t *pgdir;
+       pte_t *ptep, pte;
+       unsigned int shift;
+       unsigned long addr = (unsigned long) ptr;
+       unsigned long offset;
+       unsigned long pfn, flags;
+       void *kaddr;
+
+       pgdir = current->mm->pgd;
+       if (!pgdir)
+               return -EFAULT;
+
+       local_irq_save(flags);
+       ptep = find_current_mm_pte(pgdir, addr, NULL, &shift);
+       if (!ptep)
+               goto err_out;
+       if (!shift)
+               shift = PAGE_SHIFT;
+
+       /* align address to page boundary */
+       offset = addr & ((1UL << shift) - 1);
+
+       pte = READ_ONCE(*ptep);
+       if (!pte_present(pte) || !pte_user(pte))
+               goto err_out;
+       pfn = pte_pfn(pte);
+       if (!page_is_ram(pfn))
+               goto err_out;
+
+       /* no highmem to worry about here */
+       kaddr = pfn_to_kaddr(pfn);
+       memcpy(buf, kaddr + offset, nb);
+       ret = 0;
+err_out:
+       local_irq_restore(flags);
+       return ret;
+}
+
+static int read_user_stack_64(unsigned long __user *ptr, unsigned long *ret)
+{
+       if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned long) ||
+           ((unsigned long)ptr & 7))
+               return -EFAULT;
+
+       if (!probe_user_read(ret, ptr, sizeof(*ret)))
+               return 0;
+
+       return read_user_stack_slow(ptr, ret, 8);
+}
+
+/*
+ * 64-bit user processes use the same stack frame for RT and non-RT signals.
+ */
+struct signal_frame_64 {
+       char            dummy[__SIGNAL_FRAMESIZE];
+       struct ucontext uc;
+       unsigned long   unused[2];
+       unsigned int    tramp[6];
+       struct siginfo  *pinfo;
+       void            *puc;
+       struct siginfo  info;
+       char            abigap[288];
+};
+
+static int is_sigreturn_64_address(unsigned long nip, unsigned long fp)
+{
+       if (nip == fp + offsetof(struct signal_frame_64, tramp))
+               return 1;
+       if (vdso64_rt_sigtramp && current->mm->context.vdso_base &&
+           nip == current->mm->context.vdso_base + vdso64_rt_sigtramp)
+               return 1;
+       return 0;
+}
+
+/*
+ * Do some sanity checking on the signal frame pointed to by sp.
+ * We check the pinfo and puc pointers in the frame.
+ */
+static int sane_signal_64_frame(unsigned long sp)
+{
+       struct signal_frame_64 __user *sf;
+       unsigned long pinfo, puc;
+
+       sf = (struct signal_frame_64 __user *) sp;
+       if (read_user_stack_64((unsigned long __user *) &sf->pinfo, &pinfo) ||
+           read_user_stack_64((unsigned long __user *) &sf->puc, &puc))
+               return 0;
+       return pinfo == (unsigned long) &sf->info &&
+               puc == (unsigned long) &sf->uc;
+}
+
+void perf_callchain_user_64(struct perf_callchain_entry_ctx *entry,
+                           struct pt_regs *regs)
+{
+       unsigned long sp, next_sp;
+       unsigned long next_ip;
+       unsigned long lr;
+       long level = 0;
+       struct signal_frame_64 __user *sigframe;
+       unsigned long __user *fp, *uregs;
+
+       next_ip = perf_instruction_pointer(regs);
+       lr = regs->link;
+       sp = regs->gpr[1];
+       perf_callchain_store(entry, next_ip);
+
+       while (entry->nr < entry->max_stack) {
+               fp = (unsigned long __user *) sp;
+               if (invalid_user_sp(sp) || read_user_stack_64(fp, &next_sp))
+                       return;
+               if (level > 0 && read_user_stack_64(&fp[2], &next_ip))
+                       return;
+
+               /*
+                * Note: the next_sp - sp >= signal frame size check
+                * is true when next_sp < sp, which can happen when
+                * transitioning from an alternate signal stack to the
+                * normal stack.
+                */
+               if (next_sp - sp >= sizeof(struct signal_frame_64) &&
+                   (is_sigreturn_64_address(next_ip, sp) ||
+                    (level <= 1 && is_sigreturn_64_address(lr, sp))) &&
+                   sane_signal_64_frame(sp)) {
+                       /*
+                        * This looks like an signal frame
+                        */
+                       sigframe = (struct signal_frame_64 __user *) sp;
+                       uregs = sigframe->uc.uc_mcontext.gp_regs;
+                       if (read_user_stack_64(&uregs[PT_NIP], &next_ip) ||
+                           read_user_stack_64(&uregs[PT_LNK], &lr) ||
+                           read_user_stack_64(&uregs[PT_R1], &sp))
+                               return;
+                       level = 0;
+                       perf_callchain_store_context(entry, PERF_CONTEXT_USER);
+                       perf_callchain_store(entry, next_ip);
+                       continue;
+               }
+
+               if (level == 0)
+                       next_ip = lr;
+               perf_callchain_store(entry, next_ip);
+               ++level;
+               sp = next_sp;
+       }
+}
index cb50a9e..eb82dda 100644 (file)
@@ -44,6 +44,16 @@ static DEFINE_PER_CPU(u64 *, trace_imc_mem);
 static struct imc_pmu_ref *trace_imc_refc;
 static int trace_imc_mem_size;
 
+/*
+ * Global data structure used to avoid races between thread,
+ * core and trace-imc
+ */
+static struct imc_pmu_ref imc_global_refc = {
+       .lock = __MUTEX_INITIALIZER(imc_global_refc.lock),
+       .id = 0,
+       .refc = 0,
+};
+
 static struct imc_pmu *imc_event_to_pmu(struct perf_event *event)
 {
        return container_of(event->pmu, struct imc_pmu, pmu);
@@ -698,6 +708,16 @@ static int ppc_core_imc_cpu_offline(unsigned int cpu)
                        return -EINVAL;
 
                ref->refc = 0;
+               /*
+                * Reduce the global reference count, if this is the
+                * last cpu in this core and core-imc event running
+                * in this cpu.
+                */
+               mutex_lock(&imc_global_refc.lock);
+               if (imc_global_refc.id == IMC_DOMAIN_CORE)
+                       imc_global_refc.refc--;
+
+               mutex_unlock(&imc_global_refc.lock);
        }
        return 0;
 }
@@ -710,6 +730,23 @@ static int core_imc_pmu_cpumask_init(void)
                                 ppc_core_imc_cpu_offline);
 }
 
+static void reset_global_refc(struct perf_event *event)
+{
+               mutex_lock(&imc_global_refc.lock);
+               imc_global_refc.refc--;
+
+               /*
+                * If no other thread is running any
+                * event for this domain(thread/core/trace),
+                * set the global id to zero.
+                */
+               if (imc_global_refc.refc <= 0) {
+                       imc_global_refc.refc = 0;
+                       imc_global_refc.id = 0;
+               }
+               mutex_unlock(&imc_global_refc.lock);
+}
+
 static void core_imc_counters_release(struct perf_event *event)
 {
        int rc, core_id;
@@ -759,6 +796,8 @@ static void core_imc_counters_release(struct perf_event *event)
                ref->refc = 0;
        }
        mutex_unlock(&ref->lock);
+
+       reset_global_refc(event);
 }
 
 static int core_imc_event_init(struct perf_event *event)
@@ -819,6 +858,29 @@ static int core_imc_event_init(struct perf_event *event)
        ++ref->refc;
        mutex_unlock(&ref->lock);
 
+       /*
+        * Since the system can run either in accumulation or trace-mode
+        * of IMC at a time, core-imc events are allowed only if no other
+        * trace/thread imc events are enabled/monitored.
+        *
+        * Take the global lock, and check the refc.id
+        * to know whether any other trace/thread imc
+        * events are running.
+        */
+       mutex_lock(&imc_global_refc.lock);
+       if (imc_global_refc.id == 0 || imc_global_refc.id == IMC_DOMAIN_CORE) {
+               /*
+                * No other trace/thread imc events are running in
+                * the system, so set the refc.id to core-imc.
+                */
+               imc_global_refc.id = IMC_DOMAIN_CORE;
+               imc_global_refc.refc++;
+       } else {
+               mutex_unlock(&imc_global_refc.lock);
+               return -EBUSY;
+       }
+       mutex_unlock(&imc_global_refc.lock);
+
        event->hw.event_base = (u64)pcmi->vbase + (config & IMC_EVENT_OFFSET_MASK);
        event->destroy = core_imc_counters_release;
        return 0;
@@ -877,7 +939,23 @@ static int ppc_thread_imc_cpu_online(unsigned int cpu)
 
 static int ppc_thread_imc_cpu_offline(unsigned int cpu)
 {
-       mtspr(SPRN_LDBAR, 0);
+       /*
+        * Set the bit 0 of LDBAR to zero.
+        *
+        * If bit 0 of LDBAR is unset, it will stop posting
+        * the counter data to memory.
+        * For thread-imc, bit 0 of LDBAR will be set to 1 in the
+        * event_add function. So reset this bit here, to stop the updates
+        * to memory in the cpu_offline path.
+        */
+       mtspr(SPRN_LDBAR, (mfspr(SPRN_LDBAR) & (~(1UL << 63))));
+
+       /* Reduce the refc if thread-imc event running on this cpu */
+       mutex_lock(&imc_global_refc.lock);
+       if (imc_global_refc.id == IMC_DOMAIN_THREAD)
+               imc_global_refc.refc--;
+       mutex_unlock(&imc_global_refc.lock);
+
        return 0;
 }
 
@@ -916,7 +994,22 @@ static int thread_imc_event_init(struct perf_event *event)
        if (!target)
                return -EINVAL;
 
+       mutex_lock(&imc_global_refc.lock);
+       /*
+        * Check if any other trace/core imc events are running in the
+        * system, if not set the global id to thread-imc.
+        */
+       if (imc_global_refc.id == 0 || imc_global_refc.id == IMC_DOMAIN_THREAD) {
+               imc_global_refc.id = IMC_DOMAIN_THREAD;
+               imc_global_refc.refc++;
+       } else {
+               mutex_unlock(&imc_global_refc.lock);
+               return -EBUSY;
+       }
+       mutex_unlock(&imc_global_refc.lock);
+
        event->pmu->task_ctx_nr = perf_sw_context;
+       event->destroy = reset_global_refc;
        return 0;
 }
 
@@ -1063,10 +1156,12 @@ static void thread_imc_event_del(struct perf_event *event, int flags)
        int core_id;
        struct imc_pmu_ref *ref;
 
-       mtspr(SPRN_LDBAR, 0);
-
        core_id = smp_processor_id() / threads_per_core;
        ref = &core_imc_refc[core_id];
+       if (!ref) {
+               pr_debug("imc: Failed to get event reference count\n");
+               return;
+       }
 
        mutex_lock(&ref->lock);
        ref->refc--;
@@ -1082,6 +1177,10 @@ static void thread_imc_event_del(struct perf_event *event, int flags)
                ref->refc = 0;
        }
        mutex_unlock(&ref->lock);
+
+       /* Set bit 0 of LDBAR to zero, to stop posting updates to memory */
+       mtspr(SPRN_LDBAR, (mfspr(SPRN_LDBAR) & (~(1UL << 63))));
+
        /*
         * Take a snapshot and calculate the delta and update
         * the event counter values.
@@ -1133,7 +1232,18 @@ static int ppc_trace_imc_cpu_online(unsigned int cpu)
 
 static int ppc_trace_imc_cpu_offline(unsigned int cpu)
 {
-       mtspr(SPRN_LDBAR, 0);
+       /*
+        * No need to set bit 0 of LDBAR to zero, as
+        * it is set to zero for imc trace-mode
+        *
+        * Reduce the refc if any trace-imc event running
+        * on this cpu.
+        */
+       mutex_lock(&imc_global_refc.lock);
+       if (imc_global_refc.id == IMC_DOMAIN_TRACE)
+               imc_global_refc.refc--;
+       mutex_unlock(&imc_global_refc.lock);
+
        return 0;
 }
 
@@ -1226,15 +1336,14 @@ static int trace_imc_event_add(struct perf_event *event, int flags)
        local_mem = get_trace_imc_event_base_addr();
        ldbar_value = ((u64)local_mem & THREAD_IMC_LDBAR_MASK) | TRACE_IMC_ENABLE;
 
-       if (core_imc_refc)
-               ref = &core_imc_refc[core_id];
+       /* trace-imc reference count */
+       if (trace_imc_refc)
+               ref = &trace_imc_refc[core_id];
        if (!ref) {
-               /* If core-imc is not enabled, use trace-imc reference count */
-               if (trace_imc_refc)
-                       ref = &trace_imc_refc[core_id];
-               if (!ref)
-                       return -EINVAL;
+               pr_debug("imc: Failed to get the event reference count\n");
+               return -EINVAL;
        }
+
        mtspr(SPRN_LDBAR, ldbar_value);
        mutex_lock(&ref->lock);
        if (ref->refc == 0) {
@@ -1242,13 +1351,11 @@ static int trace_imc_event_add(struct perf_event *event, int flags)
                                get_hard_smp_processor_id(smp_processor_id()))) {
                        mutex_unlock(&ref->lock);
                        pr_err("trace-imc: Unable to start the counters for core %d\n", core_id);
-                       mtspr(SPRN_LDBAR, 0);
                        return -EINVAL;
                }
        }
        ++ref->refc;
        mutex_unlock(&ref->lock);
-
        return 0;
 }
 
@@ -1274,16 +1381,13 @@ static void trace_imc_event_del(struct perf_event *event, int flags)
        int core_id = smp_processor_id() / threads_per_core;
        struct imc_pmu_ref *ref = NULL;
 
-       if (core_imc_refc)
-               ref = &core_imc_refc[core_id];
+       if (trace_imc_refc)
+               ref = &trace_imc_refc[core_id];
        if (!ref) {
-               /* If core-imc is not enabled, use trace-imc reference count */
-               if (trace_imc_refc)
-                       ref = &trace_imc_refc[core_id];
-               if (!ref)
-                       return;
+               pr_debug("imc: Failed to get event reference count\n");
+               return;
        }
-       mtspr(SPRN_LDBAR, 0);
+
        mutex_lock(&ref->lock);
        ref->refc--;
        if (ref->refc == 0) {
@@ -1297,6 +1401,7 @@ static void trace_imc_event_del(struct perf_event *event, int flags)
                ref->refc = 0;
        }
        mutex_unlock(&ref->lock);
+
        trace_imc_event_stop(event, flags);
 }
 
@@ -1314,10 +1419,30 @@ static int trace_imc_event_init(struct perf_event *event)
        if (event->attr.sample_period == 0)
                return -ENOENT;
 
+       /*
+        * Take the global lock, and make sure
+        * no other thread is running any core/thread imc
+        * events
+        */
+       mutex_lock(&imc_global_refc.lock);
+       if (imc_global_refc.id == 0 || imc_global_refc.id == IMC_DOMAIN_TRACE) {
+               /*
+                * No core/thread imc events are running in the
+                * system, so set the refc.id to trace-imc.
+                */
+               imc_global_refc.id = IMC_DOMAIN_TRACE;
+               imc_global_refc.refc++;
+       } else {
+               mutex_unlock(&imc_global_refc.lock);
+               return -EBUSY;
+       }
+       mutex_unlock(&imc_global_refc.lock);
+
        event->hw.idx = -1;
        target = event->hw.target;
 
        event->pmu->task_ctx_nr = perf_hw_context;
+       event->destroy = reset_global_refc;
        return 0;
 }
 
@@ -1429,10 +1554,10 @@ static void cleanup_all_core_imc_memory(void)
 static void thread_imc_ldbar_disable(void *dummy)
 {
        /*
-        * By Zeroing LDBAR, we disable thread-imc
-        * updates.
+        * By setting 0th bit of LDBAR to zero, we disable thread-imc
+        * updates to memory.
         */
-       mtspr(SPRN_LDBAR, 0);
+       mtspr(SPRN_LDBAR, (mfspr(SPRN_LDBAR) & (~(1UL << 63))));
 }
 
 void thread_imc_disable(void)
index 968b9a4..7824cc3 100644 (file)
@@ -268,14 +268,7 @@ static int opal_imc_counters_probe(struct platform_device *pdev)
                        domain = IMC_DOMAIN_THREAD;
                        break;
                case IMC_TYPE_TRACE:
-                       /*
-                        * FIXME. Using trace_imc events to monitor application
-                        * or KVM thread performance can cause a checkstop
-                        * (system crash).
-                        * Disable it for now.
-                        */
-                       pr_info_once("IMC: disabling trace_imc PMU\n");
-                       domain = -1;
+                       domain = IMC_DOMAIN_TRACE;
                        break;
                default:
                        pr_warn("IMC Unknown Device type \n");
index cbddd63..e853037 100644 (file)
@@ -613,10 +613,8 @@ static int update_flash_db(void)
        /* Read in header and db from flash. */
 
        header = kmalloc(buf_len, GFP_KERNEL);
-       if (!header) {
-               pr_debug("%s: kmalloc failed\n", __func__);
+       if (!header)
                return -ENOMEM;
-       }
 
        count = os_area_flash_read(header, buf_len, 0);
        if (count < 0) {
index 2e0a8ea..6d47b4a 100644 (file)
@@ -945,6 +945,15 @@ static phys_addr_t ddw_memory_hotplug_max(void)
        phys_addr_t max_addr = memory_hotplug_max();
        struct device_node *memory;
 
+       /*
+        * The "ibm,pmemory" can appear anywhere in the address space.
+        * Assuming it is still backed by page structs, set the upper limit
+        * for the huge DMA window as MAX_PHYSMEM_BITS.
+        */
+       if (of_find_node_by_type(NULL, "ibm,pmemory"))
+               return (sizeof(phys_addr_t) * 8 <= MAX_PHYSMEM_BITS) ?
+                       (phys_addr_t) -1 : (1ULL << MAX_PHYSMEM_BITS);
+
        for_each_node_by_type(memory, "memory") {
                unsigned long start, size;
                int n_mem_addr_cells, n_mem_size_cells, len;
index e460610..f355924 100644 (file)
@@ -286,25 +286,6 @@ static int papr_scm_ndctl(struct nvdimm_bus_descriptor *nd_desc,
        return 0;
 }
 
-static inline int papr_scm_node(int node)
-{
-       int min_dist = INT_MAX, dist;
-       int nid, min_node;
-
-       if ((node == NUMA_NO_NODE) || node_online(node))
-               return node;
-
-       min_node = first_online_node;
-       for_each_online_node(nid) {
-               dist = node_distance(node, nid);
-               if (dist < min_dist) {
-                       min_dist = dist;
-                       min_node = nid;
-               }
-       }
-       return min_node;
-}
-
 static int papr_scm_nvdimm_init(struct papr_scm_priv *p)
 {
        struct device *dev = &p->pdev->dev;
@@ -329,7 +310,7 @@ static int papr_scm_nvdimm_init(struct papr_scm_priv *p)
        }
 
        dimm_flags = 0;
-       set_bit(NDD_ALIASING, &dimm_flags);
+       set_bit(NDD_LABELING, &dimm_flags);
 
        p->nvdimm = nvdimm_create(p->bus, p, NULL, dimm_flags,
                                  PAPR_SCM_DIMM_CMD_MASK, 0, NULL);
@@ -350,7 +331,7 @@ static int papr_scm_nvdimm_init(struct papr_scm_priv *p)
 
        memset(&ndr_desc, 0, sizeof(ndr_desc));
        target_nid = dev_to_node(&p->pdev->dev);
-       online_nid = papr_scm_node(target_nid);
+       online_nid = numa_map_to_online_node(target_nid);
        ndr_desc.numa_node = online_nid;
        ndr_desc.target_node = target_nid;
        ndr_desc.res = &p->res;
@@ -362,8 +343,10 @@ static int papr_scm_nvdimm_init(struct papr_scm_priv *p)
 
        if (p->is_volatile)
                p->region = nvdimm_volatile_region_create(p->bus, &ndr_desc);
-       else
+       else {
+               set_bit(ND_REGION_PERSIST_MEMCTRL, &ndr_desc.flags);
                p->region = nvdimm_pmem_region_create(p->bus, &ndr_desc);
+       }
        if (!p->region) {
                dev_err(dev, "Error registering region %pR from %pOF\n",
                                ndr_desc.res, p->dn);
index aa6208c..1d1da63 100644 (file)
@@ -686,6 +686,17 @@ static int mce_handle_error(struct pt_regs *regs, struct rtas_error_log *errp)
 #endif
 
 out:
+       /*
+        * Enable translation as we will be accessing per-cpu variables
+        * in save_mce_event() which may fall outside RMO region, also
+        * leave it enabled because subsequently we will be queuing work
+        * to workqueues where again per-cpu variables accessed, besides
+        * fwnmi_release_errinfo() crashes when called in realmode on
+        * pseries.
+        * Note: All the realmode handling like flushing SLB entries for
+        *       SLB multihit is done by now.
+        */
+       mtmsr(mfmsr() | MSR_IR | MSR_DR);
        save_mce_event(regs, disposition == RTAS_DISP_FULLY_RECOVERED,
                        &mce_err, regs->nip, eaddr, paddr);
 
index bd35ac7..62f7bfe 100644 (file)
@@ -20,7 +20,6 @@ config RISCV
        select CLONE_BACKWARDS
        select COMMON_CLK
        select GENERIC_CLOCKEVENTS
-       select GENERIC_CPU_DEVICES
        select GENERIC_IRQ_SHOW
        select GENERIC_PCI_IOMAP
        select GENERIC_SCHED_CLOCK
@@ -29,6 +28,7 @@ config RISCV
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_ATOMIC64 if !64BIT
        select GENERIC_IOREMAP
+       select GENERIC_PTDUMP if MMU
        select HAVE_ARCH_AUDITSYSCALL
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ASM_MODVERSIONS
@@ -58,6 +58,9 @@ config RISCV
        select HAVE_EBPF_JIT if MMU
        select EDAC_SUPPORT
        select ARCH_HAS_GIGANTIC_PAGE
+       select ARCH_HAS_SET_DIRECT_MAP
+       select ARCH_HAS_SET_MEMORY
+       select ARCH_HAS_STRICT_KERNEL_RWX
        select ARCH_WANT_HUGE_PMD_SHARE if 64BIT
        select SPARSEMEM_STATIC if 32BIT
        select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU
@@ -129,6 +132,9 @@ config ARCH_SELECT_MEMORY_MODEL
 config ARCH_WANT_GENERAL_HUGETLB
        def_bool y
 
+config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       def_bool y
+
 config SYS_SUPPORTS_HUGETLBFS
        def_bool y
 
@@ -247,6 +253,17 @@ config NR_CPUS
        depends on SMP
        default "8"
 
+config HOTPLUG_CPU
+       bool "Support for hot-pluggable CPUs"
+       depends on SMP
+       select GENERIC_IRQ_MIGRATION
+       help
+
+         Say Y here to experiment with turning CPUs off and on.  CPUs
+         can be controlled through /sys/devices/system/cpu.
+
+         Say N if you want to disable CPU hotplug.
+
 choice
        prompt "CPU Tuning"
        default TUNE_GENERIC
@@ -307,6 +324,13 @@ config SECCOMP
          and the task is only allowed to execute a few safe syscalls
          defined by each seccomp mode.
 
+config RISCV_SBI_V01
+       bool "SBI v0.1 support"
+       default y
+       depends on RISCV_SBI
+       help
+         This config allows kernel to use SBI v0.1 APIs. This will be
+         deprecated in future once legacy M-mode software are no longer in use.
 endmenu
 
 menu "Boot options"
index a131174..216286d 100644 (file)
@@ -20,4 +20,14 @@ config SOC_VIRT
        help
          This enables support for QEMU Virt Machine.
 
+config SOC_KENDRYTE
+       bool "Kendryte K210 SoC"
+       depends on !MMU
+       select BUILTIN_DTB
+       select SERIAL_SIFIVE if TTY
+       select SERIAL_SIFIVE_CONSOLE if TTY
+       select SIFIVE_PLIC
+       help
+         This enables support for Kendryte K210 SoC platform hardware.
+
 endmenu
index 259cb53..fb6e37d 100644 (file)
@@ -85,12 +85,12 @@ PHONY += vdso_install
 vdso_install:
        $(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@
 
-ifeq ($(CONFIG_RISCV_M_MODE),y)
-KBUILD_IMAGE := $(boot)/loader
+ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_SOC_KENDRYTE),yy)
+KBUILD_IMAGE := $(boot)/loader.bin
 else
 KBUILD_IMAGE := $(boot)/Image.gz
 endif
-BOOT_TARGETS := Image Image.gz loader
+BOOT_TARGETS := Image Image.gz loader loader.bin
 
 all:   $(notdir $(KBUILD_IMAGE))
 
index 36db814..3530c59 100644 (file)
@@ -41,6 +41,9 @@ $(obj)/Image.lzma: $(obj)/Image FORCE
 $(obj)/Image.lzo: $(obj)/Image FORCE
        $(call if_changed,lzo)
 
+$(obj)/loader.bin: $(obj)/loader FORCE
+       $(call if_changed,objcopy)
+
 install:
        $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
        $(obj)/Image System.map "$(INSTALL_PATH)"
index dcc3ada..557f0b5 100644 (file)
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 subdir-y += sifive
+subdir-y += kendryte
diff --git a/arch/riscv/boot/dts/kendryte/Makefile b/arch/riscv/boot/dts/kendryte/Makefile
new file mode 100644 (file)
index 0000000..815444e
--- /dev/null
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_SOC_KENDRYTE) += k210.dtb
diff --git a/arch/riscv/boot/dts/kendryte/k210.dts b/arch/riscv/boot/dts/kendryte/k210.dts
new file mode 100644 (file)
index 0000000..0d1f28f
--- /dev/null
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+/dts-v1/;
+
+#include "k210.dtsi"
+
+/ {
+       model = "Kendryte K210 generic";
+       compatible = "kendryte,k210";
+
+       chosen {
+               bootargs = "earlycon console=ttySIF0";
+               stdout-path = "serial0";
+       };
+};
+
+&uarths0 {
+       status = "okay";
+};
+
diff --git a/arch/riscv/boot/dts/kendryte/k210.dtsi b/arch/riscv/boot/dts/kendryte/k210.dtsi
new file mode 100644 (file)
index 0000000..c1df56c
--- /dev/null
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+#include <dt-bindings/clock/k210-clk.h>
+
+/ {
+       /*
+        * Although the K210 is a 64-bit CPU, the address bus is only 32-bits
+        * wide, and the upper half of all addresses is ignored.
+        */
+       #address-cells = <1>;
+       #size-cells = <1>;
+       compatible = "kendryte,k210";
+
+       aliases {
+               serial0 = &uarths0;
+       };
+
+       /*
+        * The K210 has an sv39 MMU following the priviledge specification v1.9.
+        * Since this is a non-ratified draft specification, the kernel does not
+        * support it and the K210 support enabled only for the !MMU case.
+        * Be consistent with this by setting the CPUs MMU type to "none".
+        */
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               timebase-frequency = <7800000>;
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       compatible = "kendryte,k210", "sifive,rocket0", "riscv";
+                       riscv,isa = "rv64imafdc";
+                       mmu-type = "none";
+                       i-cache-size = <0x8000>;
+                       i-cache-block-size = <64>;
+                       d-cache-size = <0x8000>;
+                       d-cache-block-size = <64>;
+                       clocks = <&sysctl K210_CLK_CPU>;
+                       clock-frequency = <390000000>;
+                       cpu0_intc: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               interrupt-controller;
+                               compatible = "riscv,cpu-intc";
+                       };
+               };
+               cpu1: cpu@1 {
+                       device_type = "cpu";
+                       reg = <1>;
+                       compatible = "kendryte,k210", "sifive,rocket0", "riscv";
+                       riscv,isa = "rv64imafdc";
+                       mmu-type = "none";
+                       i-cache-size = <0x8000>;
+                       i-cache-block-size = <64>;
+                       d-cache-size = <0x8000>;
+                       d-cache-block-size = <64>;
+                       clocks = <&sysctl K210_CLK_CPU>;
+                       clock-frequency = <390000000>;
+                       cpu1_intc: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               interrupt-controller;
+                               compatible = "riscv,cpu-intc";
+                       };
+               };
+       };
+
+       sram: memory@80000000 {
+               device_type = "memory";
+               reg = <0x80000000 0x400000>,
+                     <0x80400000 0x200000>,
+                     <0x80600000 0x200000>;
+               reg-names = "sram0", "sram1", "aisram";
+       };
+
+       clocks {
+               in0: oscillator {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <26000000>;
+               };
+       };
+
+       soc {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "kendryte,k210-soc", "simple-bus";
+               ranges;
+               interrupt-parent = <&plic0>;
+
+               sysctl: sysctl@50440000 {
+                       compatible = "kendryte,k210-sysctl", "simple-mfd";
+                       reg = <0x50440000 0x1000>;
+                       #clock-cells = <1>;
+               };
+
+               clint0: interrupt-controller@2000000 {
+                       compatible = "riscv,clint0";
+                       reg = <0x2000000 0xC000>;
+                       interrupts-extended = <&cpu0_intc 3>,  <&cpu1_intc 3>;
+                       clocks = <&sysctl K210_CLK_ACLK>;
+               };
+
+               plic0: interrupt-controller@c000000 {
+                       #interrupt-cells = <1>;
+                       interrupt-controller;
+                       compatible = "kendryte,k210-plic0", "riscv,plic0";
+                       reg = <0xC000000 0x4000000>;
+                       interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 0xffffffff>,
+                                             <&cpu1_intc 11>, <&cpu1_intc 0xffffffff>;
+                       riscv,ndev = <65>;
+                       riscv,max-priority = <7>;
+               };
+
+               uarths0: serial@38000000 {
+                       compatible = "kendryte,k210-uarths", "sifive,uart0";
+                       reg = <0x38000000 0x1000>;
+                       interrupts = <33>;
+                       clocks = <&sysctl K210_CLK_CPU>;
+               };
+       };
+};
index 2557c53..4da4886 100644 (file)
@@ -128,3 +128,4 @@ CONFIG_DEBUG_BLOCK_EXT_DEVT=y
 # CONFIG_FTRACE is not set
 # CONFIG_RUNTIME_TESTING_MENU is not set
 CONFIG_MEMTEST=y
+# CONFIG_SYSFS_SYSCALL is not set
diff --git a/arch/riscv/configs/nommu_k210_defconfig b/arch/riscv/configs/nommu_k210_defconfig
new file mode 100644 (file)
index 0000000..632aa2f
--- /dev/null
@@ -0,0 +1,68 @@
+# CONFIG_CPU_ISOLATION is not set
+CONFIG_LOG_BUF_SHIFT=15
+CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=12
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INITRAMFS_FORCE=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+# CONFIG_BOOT_CONFIG is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_SYSFS_SYSCALL is not set
+# CONFIG_FHANDLE is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_IO_URING is not set
+# CONFIG_ADVISE_SYSCALLS is not set
+# CONFIG_MEMBARRIER is not set
+# CONFIG_KALLSYMS is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLOB=y
+# CONFIG_SLAB_MERGE_DEFAULT is not set
+# CONFIG_MMU is not set
+CONFIG_SOC_KENDRYTE=y
+CONFIG_MAXPHYSMEM_2GB=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_CMDLINE="earlycon console=ttySIF0"
+CONFIG_CMDLINE_FORCE=y
+CONFIG_USE_BUILTIN_DTB=y
+CONFIG_BUILTIN_DTB_SOURCE="kendryte/k210"
+# CONFIG_BLOCK is not set
+CONFIG_BINFMT_FLAT=y
+# CONFIG_COREDUMP is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_ALLOW_DEV_COREDUMP is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_LDISC_AUTOLOAD is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_HID is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_VIRTIO_MENU is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_LSM="[]"
+CONFIG_PRINTK_TIME=y
+# CONFIG_DEBUG_MISC is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_FTRACE is not set
+# CONFIG_RUNTIME_TESTING_MENU is not set
index 0292879..05bbf52 100644 (file)
@@ -124,3 +124,4 @@ CONFIG_DEBUG_BLOCK_EXT_DEVT=y
 # CONFIG_FTRACE is not set
 # CONFIG_RUNTIME_TESTING_MENU is not set
 CONFIG_MEMTEST=y
+# CONFIG_SYSFS_SYSCALL is not set
index 75604fe..d6f1ec0 100644 (file)
 #define __BUG_INSN_32  _UL(0x00100073) /* ebreak */
 #define __BUG_INSN_16  _UL(0x9002) /* c.ebreak */
 
+#define GET_INSN_LENGTH(insn)                                          \
+({                                                                     \
+       unsigned long __len;                                            \
+       __len = ((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32) ?     \
+               4UL : 2UL;                                              \
+       __len;                                                          \
+})
+
 typedef u32 bug_insn_t;
 
 #ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
index 555b20b..c8677c7 100644 (file)
@@ -85,7 +85,7 @@ static inline void flush_dcache_page(struct page *page)
  * so instead we just flush the whole thing.
  */
 #define flush_icache_range(start, end) flush_icache_all()
-#define flush_icache_user_range(vma, pg, addr, len) flush_icache_all()
+#define flush_icache_user_range(vma, pg, addr, len) flush_icache_mm(vma->vm_mm, 0)
 
 #ifndef CONFIG_SMP
 
diff --git a/arch/riscv/include/asm/cpu_ops.h b/arch/riscv/include/asm/cpu_ops.h
new file mode 100644 (file)
index 0000000..a8ec3c5
--- /dev/null
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ * Based on arch/arm64/include/asm/cpu_ops.h
+ */
+#ifndef __ASM_CPU_OPS_H
+#define __ASM_CPU_OPS_H
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/threads.h>
+
+/**
+ * struct cpu_operations - Callback operations for hotplugging CPUs.
+ *
+ * @name:              Name of the boot protocol.
+ * @cpu_prepare:       Early one-time preparation step for a cpu. If there
+ *                     is a mechanism for doing so, tests whether it is
+ *                     possible to boot the given HART.
+ * @cpu_start:         Boots a cpu into the kernel.
+ * @cpu_disable:       Prepares a cpu to die. May fail for some
+ *                     mechanism-specific reason, which will cause the hot
+ *                     unplug to be aborted. Called from the cpu to be killed.
+ * @cpu_stop:          Makes a cpu leave the kernel. Must not fail. Called from
+ *                     the cpu being stopped.
+ * @cpu_is_stopped:    Ensures a cpu has left the kernel. Called from another
+ *                     cpu.
+ */
+struct cpu_operations {
+       const char      *name;
+       int             (*cpu_prepare)(unsigned int cpu);
+       int             (*cpu_start)(unsigned int cpu,
+                                    struct task_struct *tidle);
+#ifdef CONFIG_HOTPLUG_CPU
+       int             (*cpu_disable)(unsigned int cpu);
+       void            (*cpu_stop)(void);
+       int             (*cpu_is_stopped)(unsigned int cpu);
+#endif
+};
+
+extern const struct cpu_operations *cpu_ops[NR_CPUS];
+void __init cpu_set_ops(int cpu);
+void cpu_update_secondary_bootdata(unsigned int cpuid,
+                                  struct task_struct *tidle);
+
+#endif /* ifndef __ASM_CPU_OPS_H */
index dd973ef..1de233d 100644 (file)
@@ -17,6 +17,8 @@
 
 struct task_struct;
 
+register struct task_struct *riscv_current_is_tp __asm__("tp");
+
 /*
  * This only works because "struct thread_info" is at offset 0 from "struct
  * task_struct".  This constraint seems to be necessary on other architectures
@@ -26,8 +28,7 @@ struct task_struct;
  */
 static __always_inline struct task_struct *get_current(void)
 {
-       register struct task_struct *tp __asm__("tp");
-       return tp;
+       return riscv_current_is_tp;
 }
 
 #define current get_current()
index 42d2c42..2368d49 100644 (file)
@@ -27,6 +27,8 @@ enum fixed_addresses {
        FIX_FDT = FIX_FDT_END + FIX_FDT_SIZE / PAGE_SIZE - 1,
        FIX_PTE,
        FIX_PMD,
+       FIX_TEXT_POKE1,
+       FIX_TEXT_POKE0,
        FIX_EARLYCON_MEM_BASE,
        __end_of_fixed_addresses
 };
index eee6e65..b47045c 100644 (file)
@@ -13,7 +13,7 @@
 #define KASAN_SHADOW_SCALE_SHIFT       3
 
 #define KASAN_SHADOW_SIZE      (UL(1) << (38 - KASAN_SHADOW_SCALE_SHIFT))
-#define KASAN_SHADOW_START     0xffffffc000000000 /* 2^64 - 2^38 */
+#define KASAN_SHADOW_START     KERN_VIRT_START /* 2^64 - 2^38 */
 #define KASAN_SHADOW_END       (KASAN_SHADOW_START + KASAN_SHADOW_SIZE)
 
 #define KASAN_SHADOW_OFFSET    (KASAN_SHADOW_END - (1ULL << \
index 8ca1930..2d50f76 100644 (file)
@@ -137,8 +137,7 @@ extern phys_addr_t __phys_addr_symbol(unsigned long x);
 
 #define virt_addr_valid(vaddr) (pfn_valid(virt_to_pfn(vaddr)))
 
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_NON_EXEC
 
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
diff --git a/arch/riscv/include/asm/patch.h b/arch/riscv/include/asm/patch.h
new file mode 100644 (file)
index 0000000..b5918a6
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 SiFive
+ */
+
+#ifndef _ASM_RISCV_PATCH_H
+#define _ASM_RISCV_PATCH_H
+
+int riscv_patch_text_nosync(void *addr, const void *insns, size_t len);
+int riscv_patch_text(void *addr, u32 insn);
+
+#endif /* _ASM_RISCV_PATCH_H */
index 393f201..9c188ad 100644 (file)
@@ -449,6 +449,16 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
 #define __swp_entry_to_pte(x)  ((pte_t) { (x).val })
 
 /*
+ * In the RV64 Linux scheme, we give the user half of the virtual-address space
+ * and give the kernel the other (upper) half.
+ */
+#ifdef CONFIG_64BIT
+#define KERN_VIRT_START        (-(BIT(CONFIG_VA_BITS)) + TASK_SIZE)
+#else
+#define KERN_VIRT_START        FIXADDR_START
+#endif
+
+/*
  * Task size is 0x4000000000 for RV64 or 0x9fc00000 for RV32.
  * Note that PGDIR_SIZE must evenly divide TASK_SIZE.
  */
diff --git a/arch/riscv/include/asm/ptdump.h b/arch/riscv/include/asm/ptdump.h
new file mode 100644 (file)
index 0000000..e29af71
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 SiFive
+ */
+
+#ifndef _ASM_RISCV_PTDUMP_H
+#define _ASM_RISCV_PTDUMP_H
+
+void ptdump_check_wx(void);
+
+#endif /* _ASM_RISCV_PTDUMP_H */
index 2570c1e..653edb2 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (C) 2015 Regents of the University of California
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
  */
 
 #ifndef _ASM_RISCV_SBI_H
 #include <linux/types.h>
 
 #ifdef CONFIG_RISCV_SBI
-#define SBI_SET_TIMER 0
-#define SBI_CONSOLE_PUTCHAR 1
-#define SBI_CONSOLE_GETCHAR 2
-#define SBI_CLEAR_IPI 3
-#define SBI_SEND_IPI 4
-#define SBI_REMOTE_FENCE_I 5
-#define SBI_REMOTE_SFENCE_VMA 6
-#define SBI_REMOTE_SFENCE_VMA_ASID 7
-#define SBI_SHUTDOWN 8
-
-#define SBI_CALL(which, arg0, arg1, arg2, arg3) ({             \
-       register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);   \
-       register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);   \
-       register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);   \
-       register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);   \
-       register uintptr_t a7 asm ("a7") = (uintptr_t)(which);  \
-       asm volatile ("ecall"                                   \
-                     : "+r" (a0)                               \
-                     : "r" (a1), "r" (a2), "r" (a3), "r" (a7)  \
-                     : "memory");                              \
-       a0;                                                     \
-})
-
-/* Lazy implementations until SBI is finalized */
-#define SBI_CALL_0(which) SBI_CALL(which, 0, 0, 0, 0)
-#define SBI_CALL_1(which, arg0) SBI_CALL(which, arg0, 0, 0, 0)
-#define SBI_CALL_2(which, arg0, arg1) SBI_CALL(which, arg0, arg1, 0, 0)
-#define SBI_CALL_3(which, arg0, arg1, arg2) \
-               SBI_CALL(which, arg0, arg1, arg2, 0)
-#define SBI_CALL_4(which, arg0, arg1, arg2, arg3) \
-               SBI_CALL(which, arg0, arg1, arg2, arg3)
-
-static inline void sbi_console_putchar(int ch)
-{
-       SBI_CALL_1(SBI_CONSOLE_PUTCHAR, ch);
-}
+enum sbi_ext_id {
+#ifdef CONFIG_RISCV_SBI_V01
+       SBI_EXT_0_1_SET_TIMER = 0x0,
+       SBI_EXT_0_1_CONSOLE_PUTCHAR = 0x1,
+       SBI_EXT_0_1_CONSOLE_GETCHAR = 0x2,
+       SBI_EXT_0_1_CLEAR_IPI = 0x3,
+       SBI_EXT_0_1_SEND_IPI = 0x4,
+       SBI_EXT_0_1_REMOTE_FENCE_I = 0x5,
+       SBI_EXT_0_1_REMOTE_SFENCE_VMA = 0x6,
+       SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID = 0x7,
+       SBI_EXT_0_1_SHUTDOWN = 0x8,
+#endif
+       SBI_EXT_BASE = 0x10,
+       SBI_EXT_TIME = 0x54494D45,
+       SBI_EXT_IPI = 0x735049,
+       SBI_EXT_RFENCE = 0x52464E43,
+       SBI_EXT_HSM = 0x48534D,
+};
 
-static inline int sbi_console_getchar(void)
-{
-       return SBI_CALL_0(SBI_CONSOLE_GETCHAR);
-}
+enum sbi_ext_base_fid {
+       SBI_EXT_BASE_GET_SPEC_VERSION = 0,
+       SBI_EXT_BASE_GET_IMP_ID,
+       SBI_EXT_BASE_GET_IMP_VERSION,
+       SBI_EXT_BASE_PROBE_EXT,
+       SBI_EXT_BASE_GET_MVENDORID,
+       SBI_EXT_BASE_GET_MARCHID,
+       SBI_EXT_BASE_GET_MIMPID,
+};
 
-static inline void sbi_set_timer(uint64_t stime_value)
-{
-#if __riscv_xlen == 32
-       SBI_CALL_2(SBI_SET_TIMER, stime_value, stime_value >> 32);
-#else
-       SBI_CALL_1(SBI_SET_TIMER, stime_value);
-#endif
-}
+enum sbi_ext_time_fid {
+       SBI_EXT_TIME_SET_TIMER = 0,
+};
 
-static inline void sbi_shutdown(void)
-{
-       SBI_CALL_0(SBI_SHUTDOWN);
-}
+enum sbi_ext_ipi_fid {
+       SBI_EXT_IPI_SEND_IPI = 0,
+};
 
-static inline void sbi_clear_ipi(void)
-{
-       SBI_CALL_0(SBI_CLEAR_IPI);
-}
+enum sbi_ext_rfence_fid {
+       SBI_EXT_RFENCE_REMOTE_FENCE_I = 0,
+       SBI_EXT_RFENCE_REMOTE_SFENCE_VMA,
+       SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID,
+       SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA,
+       SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID,
+       SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA,
+       SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID,
+};
 
-static inline void sbi_send_ipi(const unsigned long *hart_mask)
-{
-       SBI_CALL_1(SBI_SEND_IPI, hart_mask);
-}
+enum sbi_ext_hsm_fid {
+       SBI_EXT_HSM_HART_START = 0,
+       SBI_EXT_HSM_HART_STOP,
+       SBI_EXT_HSM_HART_STATUS,
+};
+
+enum sbi_hsm_hart_status {
+       SBI_HSM_HART_STATUS_STARTED = 0,
+       SBI_HSM_HART_STATUS_STOPPED,
+       SBI_HSM_HART_STATUS_START_PENDING,
+       SBI_HSM_HART_STATUS_STOP_PENDING,
+};
+
+#define SBI_SPEC_VERSION_DEFAULT       0x1
+#define SBI_SPEC_VERSION_MAJOR_SHIFT   24
+#define SBI_SPEC_VERSION_MAJOR_MASK    0x7f
+#define SBI_SPEC_VERSION_MINOR_MASK    0xffffff
+
+/* SBI return error codes */
+#define SBI_SUCCESS            0
+#define SBI_ERR_FAILURE                -1
+#define SBI_ERR_NOT_SUPPORTED  -2
+#define SBI_ERR_INVALID_PARAM  -3
+#define SBI_ERR_DENIED         -4
+#define SBI_ERR_INVALID_ADDRESS        -5
 
-static inline void sbi_remote_fence_i(const unsigned long *hart_mask)
+extern unsigned long sbi_spec_version;
+struct sbiret {
+       long error;
+       long value;
+};
+
+int sbi_init(void);
+struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
+                       unsigned long arg1, unsigned long arg2,
+                       unsigned long arg3, unsigned long arg4,
+                       unsigned long arg5);
+
+void sbi_console_putchar(int ch);
+int sbi_console_getchar(void);
+void sbi_set_timer(uint64_t stime_value);
+void sbi_shutdown(void);
+void sbi_clear_ipi(void);
+void sbi_send_ipi(const unsigned long *hart_mask);
+void sbi_remote_fence_i(const unsigned long *hart_mask);
+void sbi_remote_sfence_vma(const unsigned long *hart_mask,
+                          unsigned long start,
+                          unsigned long size);
+
+void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
+                               unsigned long start,
+                               unsigned long size,
+                               unsigned long asid);
+int sbi_remote_hfence_gvma(const unsigned long *hart_mask,
+                          unsigned long start,
+                          unsigned long size);
+int sbi_remote_hfence_gvma_vmid(const unsigned long *hart_mask,
+                               unsigned long start,
+                               unsigned long size,
+                               unsigned long vmid);
+int sbi_remote_hfence_vvma(const unsigned long *hart_mask,
+                          unsigned long start,
+                          unsigned long size);
+int sbi_remote_hfence_vvma_asid(const unsigned long *hart_mask,
+                               unsigned long start,
+                               unsigned long size,
+                               unsigned long asid);
+int sbi_probe_extension(int ext);
+
+/* Check if current SBI specification version is 0.1 or not */
+static inline int sbi_spec_is_0_1(void)
 {
-       SBI_CALL_1(SBI_REMOTE_FENCE_I, hart_mask);
+       return (sbi_spec_version == SBI_SPEC_VERSION_DEFAULT) ? 1 : 0;
 }
 
-static inline void sbi_remote_sfence_vma(const unsigned long *hart_mask,
-                                        unsigned long start,
-                                        unsigned long size)
+/* Get the major version of SBI */
+static inline unsigned long sbi_major_version(void)
 {
-       SBI_CALL_3(SBI_REMOTE_SFENCE_VMA, hart_mask, start, size);
+       return (sbi_spec_version >> SBI_SPEC_VERSION_MAJOR_SHIFT) &
+               SBI_SPEC_VERSION_MAJOR_MASK;
 }
 
-static inline void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
-                                             unsigned long start,
-                                             unsigned long size,
-                                             unsigned long asid)
+/* Get the minor version of SBI */
+static inline unsigned long sbi_minor_version(void)
 {
-       SBI_CALL_4(SBI_REMOTE_SFENCE_VMA_ASID, hart_mask, start, size, asid);
+       return sbi_spec_version & SBI_SPEC_VERSION_MINOR_MASK;
 }
+
+int sbi_err_map_linux_errno(int err);
 #else /* CONFIG_RISCV_SBI */
 /* stubs for code that is only reachable under IS_ENABLED(CONFIG_RISCV_SBI): */
 void sbi_set_timer(uint64_t stime_value);
 void sbi_clear_ipi(void);
 void sbi_send_ipi(const unsigned long *hart_mask);
 void sbi_remote_fence_i(const unsigned long *hart_mask);
+void sbi_init(void);
 #endif /* CONFIG_RISCV_SBI */
 #endif /* _ASM_RISCV_SBI_H */
diff --git a/arch/riscv/include/asm/set_memory.h b/arch/riscv/include/asm/set_memory.h
new file mode 100644 (file)
index 0000000..c38df47
--- /dev/null
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2019 SiFive
+ */
+
+#ifndef _ASM_RISCV_SET_MEMORY_H
+#define _ASM_RISCV_SET_MEMORY_H
+
+#ifndef __ASSEMBLY__
+/*
+ * Functions to change memory attributes.
+ */
+#ifdef CONFIG_MMU
+int set_memory_ro(unsigned long addr, int numpages);
+int set_memory_rw(unsigned long addr, int numpages);
+int set_memory_x(unsigned long addr, int numpages);
+int set_memory_nx(unsigned long addr, int numpages);
+#else
+static inline int set_memory_ro(unsigned long addr, int numpages) { return 0; }
+static inline int set_memory_rw(unsigned long addr, int numpages) { return 0; }
+static inline int set_memory_x(unsigned long addr, int numpages) { return 0; }
+static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; }
+#endif
+
+#ifdef CONFIG_STRICT_KERNEL_RWX
+void set_kernel_text_ro(void);
+void set_kernel_text_rw(void);
+#else
+static inline void set_kernel_text_ro(void) { }
+static inline void set_kernel_text_rw(void) { }
+#endif
+
+int set_direct_map_invalid_noflush(struct page *page);
+int set_direct_map_default_noflush(struct page *page);
+
+#endif /* __ASSEMBLY__ */
+
+#ifdef CONFIG_ARCH_HAS_STRICT_KERNEL_RWX
+#ifdef CONFIG_64BIT
+#define SECTION_ALIGN (1 << 21)
+#else
+#define SECTION_ALIGN (1 << 22)
+#endif
+#else /* !CONFIG_ARCH_HAS_STRICT_KERNEL_RWX */
+#define SECTION_ALIGN L1_CACHE_BYTES
+#endif /* CONFIG_ARCH_HAS_STRICT_KERNEL_RWX */
+
+#endif /* _ASM_RISCV_SET_MEMORY_H */
index a83451d..f4c7cfd 100644 (file)
@@ -43,6 +43,13 @@ void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out);
  */
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
+#if defined CONFIG_HOTPLUG_CPU
+int __cpu_disable(void);
+void __cpu_die(unsigned int cpu);
+void cpu_stop(void);
+#else
+#endif /* CONFIG_HOTPLUG_CPU */
+
 #else
 
 static inline void show_ipi_stats(struct seq_file *p, int prec)
@@ -61,5 +68,22 @@ static inline unsigned long cpuid_to_hartid_map(int cpu)
        return boot_cpu_hartid;
 }
 
+static inline void riscv_cpuid_to_hartid_mask(const struct cpumask *in,
+                                             struct cpumask *out)
+{
+       cpumask_clear(out);
+       cpumask_set_cpu(boot_cpu_hartid, out);
+}
+
 #endif /* CONFIG_SMP */
+
+#if defined(CONFIG_HOTPLUG_CPU) && (CONFIG_SMP)
+bool cpu_has_hotplug(unsigned int cpu);
+#else
+static inline bool cpu_has_hotplug(unsigned int cpu)
+{
+       return false;
+}
+#endif
+
 #endif /* _ASM_RISCV_SMP_H */
diff --git a/arch/riscv/include/asm/soc.h b/arch/riscv/include/asm/soc.h
new file mode 100644 (file)
index 0000000..7cec196
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+#ifndef _ASM_RISCV_SOC_H
+#define _ASM_RISCV_SOC_H
+
+#include <linux/of.h>
+#include <linux/linkage.h>
+#include <linux/types.h>
+
+#define SOC_EARLY_INIT_DECLARE(name, compat, fn)                       \
+       static const struct of_device_id __soc_early_init__##name       \
+               __used __section(__soc_early_init_table)                \
+                = { .compatible = compat, .data = fn  }
+
+void soc_early_init(void);
+
+extern unsigned long __soc_early_init_table_start;
+extern unsigned long __soc_early_init_table_end;
+
+#endif
index f40205c..86c8308 100644 (file)
@@ -4,12 +4,14 @@
 #
 
 ifdef CONFIG_FTRACE
-CFLAGS_REMOVE_ftrace.o = -pg
+CFLAGS_REMOVE_ftrace.o = -pg
+CFLAGS_REMOVE_patch.o  = -pg
 endif
 
 extra-y += head.o
 extra-y += vmlinux.lds
 
+obj-y  += soc.o
 obj-y  += cpu.o
 obj-y  += cpufeature.o
 obj-y  += entry.o
@@ -26,12 +28,15 @@ obj-y       += traps.o
 obj-y  += riscv_ksyms.o
 obj-y  += stacktrace.o
 obj-y  += cacheinfo.o
+obj-y  += patch.o
 obj-$(CONFIG_MMU) += vdso.o vdso/
 
-obj-$(CONFIG_RISCV_M_MODE)     += clint.o
+obj-$(CONFIG_RISCV_M_MODE)     += clint.o traps_misaligned.o
 obj-$(CONFIG_FPU)              += fpu.o
 obj-$(CONFIG_SMP)              += smpboot.o
 obj-$(CONFIG_SMP)              += smp.o
+obj-$(CONFIG_SMP)              += cpu_ops.o
+obj-$(CONFIG_SMP)              += cpu_ops_spinwait.o
 obj-$(CONFIG_MODULES)          += module.o
 obj-$(CONFIG_MODULE_SECTIONS)  += module-sections.o
 
@@ -42,5 +47,9 @@ obj-$(CONFIG_PERF_EVENTS)     += perf_event.o
 obj-$(CONFIG_PERF_EVENTS)      += perf_callchain.o
 obj-$(CONFIG_HAVE_PERF_REGS)   += perf_regs.o
 obj-$(CONFIG_RISCV_SBI)                += sbi.o
+ifeq ($(CONFIG_RISCV_SBI), y)
+obj-$(CONFIG_SMP) += cpu_ops_sbi.o
+endif
+obj-$(CONFIG_HOTPLUG_CPU)      += cpu-hotplug.o
 
 clean:
diff --git a/arch/riscv/kernel/cpu-hotplug.c b/arch/riscv/kernel/cpu-hotplug.c
new file mode 100644 (file)
index 0000000..df84e0c
--- /dev/null
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/cpu.h>
+#include <linux/sched/hotplug.h>
+#include <asm/irq.h>
+#include <asm/cpu_ops.h>
+#include <asm/sbi.h>
+
+void cpu_stop(void);
+void arch_cpu_idle_dead(void)
+{
+       cpu_stop();
+}
+
+bool cpu_has_hotplug(unsigned int cpu)
+{
+       if (cpu_ops[cpu]->cpu_stop)
+               return true;
+
+       return false;
+}
+
+/*
+ * __cpu_disable runs on the processor to be shutdown.
+ */
+int __cpu_disable(void)
+{
+       int ret = 0;
+       unsigned int cpu = smp_processor_id();
+
+       if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_stop)
+               return -EOPNOTSUPP;
+
+       if (cpu_ops[cpu]->cpu_disable)
+               ret = cpu_ops[cpu]->cpu_disable(cpu);
+
+       if (ret)
+               return ret;
+
+       remove_cpu_topology(cpu);
+       set_cpu_online(cpu, false);
+       irq_migrate_all_off_this_cpu();
+
+       return ret;
+}
+
+/*
+ * Called on the thread which is asking for a CPU to be shutdown.
+ */
+void __cpu_die(unsigned int cpu)
+{
+       int ret = 0;
+
+       if (!cpu_wait_death(cpu, 5)) {
+               pr_err("CPU %u: didn't die\n", cpu);
+               return;
+       }
+       pr_notice("CPU%u: off\n", cpu);
+
+       /* Verify from the firmware if the cpu is really stopped*/
+       if (cpu_ops[cpu]->cpu_is_stopped)
+               ret = cpu_ops[cpu]->cpu_is_stopped(cpu);
+       if (ret)
+               pr_warn("CPU%d may not have stopped: %d\n", cpu, ret);
+}
+
+/*
+ * Called from the idle thread for the CPU which has been shutdown.
+ */
+void cpu_stop(void)
+{
+       idle_task_exit();
+
+       (void)cpu_report_death();
+
+       cpu_ops[smp_processor_id()]->cpu_stop();
+       /* It should never reach here */
+       BUG();
+}
diff --git a/arch/riscv/kernel/cpu_ops.c b/arch/riscv/kernel/cpu_ops.c
new file mode 100644 (file)
index 0000000..c4c33bf
--- /dev/null
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/sched/task_stack.h>
+#include <asm/cpu_ops.h>
+#include <asm/sbi.h>
+#include <asm/smp.h>
+
+const struct cpu_operations *cpu_ops[NR_CPUS] __ro_after_init;
+
+void *__cpu_up_stack_pointer[NR_CPUS];
+void *__cpu_up_task_pointer[NR_CPUS];
+
+extern const struct cpu_operations cpu_ops_sbi;
+extern const struct cpu_operations cpu_ops_spinwait;
+
+void cpu_update_secondary_bootdata(unsigned int cpuid,
+                                  struct task_struct *tidle)
+{
+       int hartid = cpuid_to_hartid_map(cpuid);
+
+       /* Make sure tidle is updated */
+       smp_mb();
+       WRITE_ONCE(__cpu_up_stack_pointer[hartid],
+                  task_stack_page(tidle) + THREAD_SIZE);
+       WRITE_ONCE(__cpu_up_task_pointer[hartid], tidle);
+}
+
+void __init cpu_set_ops(int cpuid)
+{
+#if IS_ENABLED(CONFIG_RISCV_SBI)
+       if (sbi_probe_extension(SBI_EXT_HSM) > 0) {
+               if (!cpuid)
+                       pr_info("SBI v0.2 HSM extension detected\n");
+               cpu_ops[cpuid] = &cpu_ops_sbi;
+       } else
+#endif
+               cpu_ops[cpuid] = &cpu_ops_spinwait;
+}
diff --git a/arch/riscv/kernel/cpu_ops_sbi.c b/arch/riscv/kernel/cpu_ops_sbi.c
new file mode 100644 (file)
index 0000000..685fae7
--- /dev/null
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * HSM extension and cpu_ops implementation.
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <asm/cpu_ops.h>
+#include <asm/sbi.h>
+#include <asm/smp.h>
+
+extern char secondary_start_sbi[];
+const struct cpu_operations cpu_ops_sbi;
+
+static int sbi_hsm_hart_start(unsigned long hartid, unsigned long saddr,
+                             unsigned long priv)
+{
+       struct sbiret ret;
+
+       ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_START,
+                       hartid, saddr, priv, 0, 0, 0);
+       if (ret.error)
+               return sbi_err_map_linux_errno(ret.error);
+       else
+               return 0;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static int sbi_hsm_hart_stop(void)
+{
+       struct sbiret ret;
+
+       ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STOP, 0, 0, 0, 0, 0, 0);
+
+       if (ret.error)
+               return sbi_err_map_linux_errno(ret.error);
+       else
+               return 0;
+}
+
+static int sbi_hsm_hart_get_status(unsigned long hartid)
+{
+       struct sbiret ret;
+
+       ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STATUS,
+                       hartid, 0, 0, 0, 0, 0);
+       if (ret.error)
+               return sbi_err_map_linux_errno(ret.error);
+       else
+               return ret.value;
+}
+#endif
+
+static int sbi_cpu_start(unsigned int cpuid, struct task_struct *tidle)
+{
+       int rc;
+       unsigned long boot_addr = __pa_symbol(secondary_start_sbi);
+       int hartid = cpuid_to_hartid_map(cpuid);
+
+       cpu_update_secondary_bootdata(cpuid, tidle);
+       rc = sbi_hsm_hart_start(hartid, boot_addr, 0);
+
+       return rc;
+}
+
+static int sbi_cpu_prepare(unsigned int cpuid)
+{
+       if (!cpu_ops_sbi.cpu_start) {
+               pr_err("cpu start method not defined for CPU [%d]\n", cpuid);
+               return -ENODEV;
+       }
+       return 0;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static int sbi_cpu_disable(unsigned int cpuid)
+{
+       if (!cpu_ops_sbi.cpu_stop)
+               return -EOPNOTSUPP;
+       return 0;
+}
+
+static void sbi_cpu_stop(void)
+{
+       int ret;
+
+       ret = sbi_hsm_hart_stop();
+       pr_crit("Unable to stop the cpu %u (%d)\n", smp_processor_id(), ret);
+}
+
+static int sbi_cpu_is_stopped(unsigned int cpuid)
+{
+       int rc;
+       int hartid = cpuid_to_hartid_map(cpuid);
+
+       rc = sbi_hsm_hart_get_status(hartid);
+
+       if (rc == SBI_HSM_HART_STATUS_STOPPED)
+               return 0;
+       return rc;
+}
+#endif
+
+const struct cpu_operations cpu_ops_sbi = {
+       .name           = "sbi",
+       .cpu_prepare    = sbi_cpu_prepare,
+       .cpu_start      = sbi_cpu_start,
+#ifdef CONFIG_HOTPLUG_CPU
+       .cpu_disable    = sbi_cpu_disable,
+       .cpu_stop       = sbi_cpu_stop,
+       .cpu_is_stopped = sbi_cpu_is_stopped,
+#endif
+};
diff --git a/arch/riscv/kernel/cpu_ops_spinwait.c b/arch/riscv/kernel/cpu_ops_spinwait.c
new file mode 100644 (file)
index 0000000..b2c957b
--- /dev/null
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+
+#include <linux/errno.h>
+#include <linux/of.h>
+#include <linux/string.h>
+#include <asm/cpu_ops.h>
+#include <asm/sbi.h>
+#include <asm/smp.h>
+
+const struct cpu_operations cpu_ops_spinwait;
+
+static int spinwait_cpu_prepare(unsigned int cpuid)
+{
+       if (!cpu_ops_spinwait.cpu_start) {
+               pr_err("cpu start method not defined for CPU [%d]\n", cpuid);
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static int spinwait_cpu_start(unsigned int cpuid, struct task_struct *tidle)
+{
+       /*
+        * In this protocol, all cpus boot on their own accord.  _start
+        * selects the first cpu to boot the kernel and causes the remainder
+        * of the cpus to spin in a loop waiting for their stack pointer to be
+        * setup by that main cpu.  Writing to bootdata
+        * (i.e __cpu_up_stack_pointer) signals to the spinning cpus that they
+        * can continue the boot process.
+        */
+       cpu_update_secondary_bootdata(cpuid, tidle);
+
+       return 0;
+}
+
+const struct cpu_operations cpu_ops_spinwait = {
+       .name           = "spinwait",
+       .cpu_prepare    = spinwait_cpu_prepare,
+       .cpu_start      = spinwait_cpu_start,
+};
index 208702d..56d071b 100644 (file)
 #include <asm/thread_info.h>
 #include <asm/asm-offsets.h>
 
-       .text
-       .altmacro
-
-/*
- * Prepares to enter a system call or exception by saving all registers to the
- * stack.
- */
-       .macro SAVE_ALL
-       LOCAL _restore_kernel_tpsp
-       LOCAL _save_context
+#if !IS_ENABLED(CONFIG_PREEMPTION)
+.set resume_kernel, restore_all
+#endif
 
+ENTRY(handle_exception)
        /*
         * If coming from userspace, preserve the user thread pointer and load
         * the kernel thread pointer.  If we came from the kernel, the scratch
@@ -90,77 +84,6 @@ _save_context:
        REG_S s3, PT_BADADDR(sp)
        REG_S s4, PT_CAUSE(sp)
        REG_S s5, PT_TP(sp)
-       .endm
-
-/*
- * Prepares to return from a system call or exception by restoring all
- * registers from the stack.
- */
-       .macro RESTORE_ALL
-       REG_L a0, PT_STATUS(sp)
-       /*
-        * The current load reservation is effectively part of the processor's
-        * state, in the sense that load reservations cannot be shared between
-        * different hart contexts.  We can't actually save and restore a load
-        * reservation, so instead here we clear any existing reservation --
-        * it's always legal for implementations to clear load reservations at
-        * any point (as long as the forward progress guarantee is kept, but
-        * we'll ignore that here).
-        *
-        * Dangling load reservations can be the result of taking a trap in the
-        * middle of an LR/SC sequence, but can also be the result of a taken
-        * forward branch around an SC -- which is how we implement CAS.  As a
-        * result we need to clear reservations between the last CAS and the
-        * jump back to the new context.  While it is unlikely the store
-        * completes, implementations are allowed to expand reservations to be
-        * arbitrarily large.
-        */
-       REG_L  a2, PT_EPC(sp)
-       REG_SC x0, a2, PT_EPC(sp)
-
-       csrw CSR_STATUS, a0
-       csrw CSR_EPC, a2
-
-       REG_L x1,  PT_RA(sp)
-       REG_L x3,  PT_GP(sp)
-       REG_L x4,  PT_TP(sp)
-       REG_L x5,  PT_T0(sp)
-       REG_L x6,  PT_T1(sp)
-       REG_L x7,  PT_T2(sp)
-       REG_L x8,  PT_S0(sp)
-       REG_L x9,  PT_S1(sp)
-       REG_L x10, PT_A0(sp)
-       REG_L x11, PT_A1(sp)
-       REG_L x12, PT_A2(sp)
-       REG_L x13, PT_A3(sp)
-       REG_L x14, PT_A4(sp)
-       REG_L x15, PT_A5(sp)
-       REG_L x16, PT_A6(sp)
-       REG_L x17, PT_A7(sp)
-       REG_L x18, PT_S2(sp)
-       REG_L x19, PT_S3(sp)
-       REG_L x20, PT_S4(sp)
-       REG_L x21, PT_S5(sp)
-       REG_L x22, PT_S6(sp)
-       REG_L x23, PT_S7(sp)
-       REG_L x24, PT_S8(sp)
-       REG_L x25, PT_S9(sp)
-       REG_L x26, PT_S10(sp)
-       REG_L x27, PT_S11(sp)
-       REG_L x28, PT_T3(sp)
-       REG_L x29, PT_T4(sp)
-       REG_L x30, PT_T5(sp)
-       REG_L x31, PT_T6(sp)
-
-       REG_L x2,  PT_SP(sp)
-       .endm
-
-#if !IS_ENABLED(CONFIG_PREEMPTION)
-.set resume_kernel, restore_all
-#endif
-
-ENTRY(handle_exception)
-       SAVE_ALL
 
        /*
         * Set the scratch register to 0, so that if a recursive exception
@@ -291,7 +214,63 @@ resume_userspace:
        csrw CSR_SCRATCH, tp
 
 restore_all:
-       RESTORE_ALL
+       REG_L a0, PT_STATUS(sp)
+       /*
+        * The current load reservation is effectively part of the processor's
+        * state, in the sense that load reservations cannot be shared between
+        * different hart contexts.  We can't actually save and restore a load
+        * reservation, so instead here we clear any existing reservation --
+        * it's always legal for implementations to clear load reservations at
+        * any point (as long as the forward progress guarantee is kept, but
+        * we'll ignore that here).
+        *
+        * Dangling load reservations can be the result of taking a trap in the
+        * middle of an LR/SC sequence, but can also be the result of a taken
+        * forward branch around an SC -- which is how we implement CAS.  As a
+        * result we need to clear reservations between the last CAS and the
+        * jump back to the new context.  While it is unlikely the store
+        * completes, implementations are allowed to expand reservations to be
+        * arbitrarily large.
+        */
+       REG_L  a2, PT_EPC(sp)
+       REG_SC x0, a2, PT_EPC(sp)
+
+       csrw CSR_STATUS, a0
+       csrw CSR_EPC, a2
+
+       REG_L x1,  PT_RA(sp)
+       REG_L x3,  PT_GP(sp)
+       REG_L x4,  PT_TP(sp)
+       REG_L x5,  PT_T0(sp)
+       REG_L x6,  PT_T1(sp)
+       REG_L x7,  PT_T2(sp)
+       REG_L x8,  PT_S0(sp)
+       REG_L x9,  PT_S1(sp)
+       REG_L x10, PT_A0(sp)
+       REG_L x11, PT_A1(sp)
+       REG_L x12, PT_A2(sp)
+       REG_L x13, PT_A3(sp)
+       REG_L x14, PT_A4(sp)
+       REG_L x15, PT_A5(sp)
+       REG_L x16, PT_A6(sp)
+       REG_L x17, PT_A7(sp)
+       REG_L x18, PT_S2(sp)
+       REG_L x19, PT_S3(sp)
+       REG_L x20, PT_S4(sp)
+       REG_L x21, PT_S5(sp)
+       REG_L x22, PT_S6(sp)
+       REG_L x23, PT_S7(sp)
+       REG_L x24, PT_S8(sp)
+       REG_L x25, PT_S9(sp)
+       REG_L x26, PT_S10(sp)
+       REG_L x27, PT_S11(sp)
+       REG_L x28, PT_T3(sp)
+       REG_L x29, PT_T4(sp)
+       REG_L x30, PT_T5(sp)
+       REG_L x31, PT_T6(sp)
+
+       REG_L x2,  PT_SP(sp)
+
 #ifdef CONFIG_RISCV_M_MODE
        mret
 #else
index c40fdcd..ce69b34 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/ftrace.h>
 #include <linux/uaccess.h>
 #include <asm/cacheflush.h>
+#include <asm/patch.h>
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 static int ftrace_check_current_call(unsigned long hook_pos,
@@ -46,20 +47,14 @@ static int __ftrace_modify_call(unsigned long hook_pos, unsigned long target,
 {
        unsigned int call[2];
        unsigned int nops[2] = {NOP4, NOP4};
-       int ret = 0;
 
        make_call(hook_pos, target, call);
 
-       /* replace the auipc-jalr pair at once */
-       ret = probe_kernel_write((void *)hook_pos, enable ? call : nops,
-                                MCOUNT_INSN_SIZE);
-       /* return must be -EPERM on write error */
-       if (ret)
+       /* Replace the auipc-jalr pair at once. Return -EPERM on write error. */
+       if (riscv_patch_text_nosync
+           ((void *)hook_pos, enable ? call : nops, MCOUNT_INSN_SIZE))
                return -EPERM;
 
-       smp_mb();
-       flush_icache_range((void *)hook_pos, (void *)hook_pos + MCOUNT_INSN_SIZE);
-
        return 0;
 }
 
index 85f2073..98a4064 100644 (file)
@@ -14,7 +14,7 @@
 #include <asm/hwcap.h>
 #include <asm/image.h>
 
-__INIT
+__HEAD
 ENTRY(_start)
        /*
         * Image header expected by Linux boot-loaders. The image header data
@@ -45,8 +45,111 @@ ENTRY(_start)
        .ascii RISCV_IMAGE_MAGIC2
        .word 0
 
-.global _start_kernel
-_start_kernel:
+.align 2
+#ifdef CONFIG_MMU
+relocate:
+       /* Relocate return address */
+       li a1, PAGE_OFFSET
+       la a2, _start
+       sub a1, a1, a2
+       add ra, ra, a1
+
+       /* Point stvec to virtual address of intruction after satp write */
+       la a2, 1f
+       add a2, a2, a1
+       csrw CSR_TVEC, a2
+
+       /* Compute satp for kernel page tables, but don't load it yet */
+       srl a2, a0, PAGE_SHIFT
+       li a1, SATP_MODE
+       or a2, a2, a1
+
+       /*
+        * Load trampoline page directory, which will cause us to trap to
+        * stvec if VA != PA, or simply fall through if VA == PA.  We need a
+        * full fence here because setup_vm() just wrote these PTEs and we need
+        * to ensure the new translations are in use.
+        */
+       la a0, trampoline_pg_dir
+       srl a0, a0, PAGE_SHIFT
+       or a0, a0, a1
+       sfence.vma
+       csrw CSR_SATP, a0
+.align 2
+1:
+       /* Set trap vector to spin forever to help debug */
+       la a0, .Lsecondary_park
+       csrw CSR_TVEC, a0
+
+       /* Reload the global pointer */
+.option push
+.option norelax
+       la gp, __global_pointer$
+.option pop
+
+       /*
+        * Switch to kernel page tables.  A full fence is necessary in order to
+        * avoid using the trampoline translations, which are only correct for
+        * the first superpage.  Fetching the fence is guarnteed to work
+        * because that first superpage is translated the same way.
+        */
+       csrw CSR_SATP, a2
+       sfence.vma
+
+       ret
+#endif /* CONFIG_MMU */
+#ifdef CONFIG_SMP
+       .global secondary_start_sbi
+secondary_start_sbi:
+       /* Mask all interrupts */
+       csrw CSR_IE, zero
+       csrw CSR_IP, zero
+
+       /* Load the global pointer */
+       .option push
+       .option norelax
+               la gp, __global_pointer$
+       .option pop
+
+       /*
+        * Disable FPU to detect illegal usage of
+        * floating point in kernel space
+        */
+       li t0, SR_FS
+       csrc CSR_STATUS, t0
+
+       /* Set trap vector to spin forever to help debug */
+       la a3, .Lsecondary_park
+       csrw CSR_TVEC, a3
+
+       slli a3, a0, LGREG
+       la a4, __cpu_up_stack_pointer
+       la a5, __cpu_up_task_pointer
+       add a4, a3, a4
+       add a5, a3, a5
+       REG_L sp, (a4)
+       REG_L tp, (a5)
+
+       .global secondary_start_common
+secondary_start_common:
+
+#ifdef CONFIG_MMU
+       /* Enable virtual memory and relocate to virtual address */
+       la a0, swapper_pg_dir
+       call relocate
+#endif
+       tail smp_callin
+#endif /* CONFIG_SMP */
+
+.Lsecondary_park:
+       /* We lack SMP support or have too many harts, so park this hart */
+       wfi
+       j .Lsecondary_park
+
+END(_start)
+
+       __INIT
+ENTRY(_start_kernel)
        /* Mask all interrupts */
        csrw CSR_IE, zero
        csrw CSR_IP, zero
@@ -131,62 +234,10 @@ clear_bss_done:
        call kasan_early_init
 #endif
        /* Start the kernel */
+       call soc_early_init
        call parse_dtb
        tail start_kernel
 
-#ifdef CONFIG_MMU
-relocate:
-       /* Relocate return address */
-       li a1, PAGE_OFFSET
-       la a2, _start
-       sub a1, a1, a2
-       add ra, ra, a1
-
-       /* Point stvec to virtual address of intruction after satp write */
-       la a2, 1f
-       add a2, a2, a1
-       csrw CSR_TVEC, a2
-
-       /* Compute satp for kernel page tables, but don't load it yet */
-       srl a2, a0, PAGE_SHIFT
-       li a1, SATP_MODE
-       or a2, a2, a1
-
-       /*
-        * Load trampoline page directory, which will cause us to trap to
-        * stvec if VA != PA, or simply fall through if VA == PA.  We need a
-        * full fence here because setup_vm() just wrote these PTEs and we need
-        * to ensure the new translations are in use.
-        */
-       la a0, trampoline_pg_dir
-       srl a0, a0, PAGE_SHIFT
-       or a0, a0, a1
-       sfence.vma
-       csrw CSR_SATP, a0
-.align 2
-1:
-       /* Set trap vector to spin forever to help debug */
-       la a0, .Lsecondary_park
-       csrw CSR_TVEC, a0
-
-       /* Reload the global pointer */
-.option push
-.option norelax
-       la gp, __global_pointer$
-.option pop
-
-       /*
-        * Switch to kernel page tables.  A full fence is necessary in order to
-        * avoid using the trampoline translations, which are only correct for
-        * the first superpage.  Fetching the fence is guarnteed to work
-        * because that first superpage is translated the same way.
-        */
-       csrw CSR_SATP, a2
-       sfence.vma
-
-       ret
-#endif /* CONFIG_MMU */
-
 .Lsecondary_start:
 #ifdef CONFIG_SMP
        /* Set trap vector to spin forever to help debug */
@@ -211,16 +262,10 @@ relocate:
        beqz tp, .Lwait_for_cpu_up
        fence
 
-#ifdef CONFIG_MMU
-       /* Enable virtual memory and relocate to virtual address */
-       la a0, swapper_pg_dir
-       call relocate
+       tail secondary_start_common
 #endif
 
-       tail smp_callin
-#endif
-
-END(_start)
+END(_start_kernel)
 
 #ifdef CONFIG_RISCV_M_MODE
 ENTRY(reset_regs)
@@ -301,13 +346,6 @@ ENTRY(reset_regs)
 END(reset_regs)
 #endif /* CONFIG_RISCV_M_MODE */
 
-.section ".text", "ax",@progbits
-.align 2
-.Lsecondary_park:
-       /* We lack SMP support or have too many harts, so park this hart */
-       wfi
-       j .Lsecondary_park
-
 __PAGE_ALIGNED_BSS
        /* Empty zero page */
        .balign PAGE_SIZE
diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c
new file mode 100644 (file)
index 0000000..8a4fc65
--- /dev/null
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020 SiFive
+ */
+
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <linux/stop_machine.h>
+#include <asm/kprobes.h>
+#include <asm/cacheflush.h>
+#include <asm/fixmap.h>
+
+struct riscv_insn_patch {
+       void *addr;
+       u32 insn;
+       atomic_t cpu_count;
+};
+
+#ifdef CONFIG_MMU
+static DEFINE_RAW_SPINLOCK(patch_lock);
+
+static void __kprobes *patch_map(void *addr, int fixmap)
+{
+       uintptr_t uintaddr = (uintptr_t) addr;
+       struct page *page;
+
+       if (core_kernel_text(uintaddr))
+               page = phys_to_page(__pa_symbol(addr));
+       else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
+               page = vmalloc_to_page(addr);
+       else
+               return addr;
+
+       BUG_ON(!page);
+
+       return (void *)set_fixmap_offset(fixmap, page_to_phys(page) +
+                                        (uintaddr & ~PAGE_MASK));
+}
+
+static void __kprobes patch_unmap(int fixmap)
+{
+       clear_fixmap(fixmap);
+}
+
+static int __kprobes riscv_insn_write(void *addr, const void *insn, size_t len)
+{
+       void *waddr = addr;
+       bool across_pages = (((uintptr_t) addr & ~PAGE_MASK) + len) > PAGE_SIZE;
+       unsigned long flags = 0;
+       int ret;
+
+       raw_spin_lock_irqsave(&patch_lock, flags);
+
+       if (across_pages)
+               patch_map(addr + len, FIX_TEXT_POKE1);
+
+       waddr = patch_map(addr, FIX_TEXT_POKE0);
+
+       ret = probe_kernel_write(waddr, insn, len);
+
+       patch_unmap(FIX_TEXT_POKE0);
+
+       if (across_pages)
+               patch_unmap(FIX_TEXT_POKE1);
+
+       raw_spin_unlock_irqrestore(&patch_lock, flags);
+
+       return ret;
+}
+#else
+static int __kprobes riscv_insn_write(void *addr, const void *insn, size_t len)
+{
+       return probe_kernel_write(addr, insn, len);
+}
+#endif /* CONFIG_MMU */
+
+int __kprobes riscv_patch_text_nosync(void *addr, const void *insns, size_t len)
+{
+       u32 *tp = addr;
+       int ret;
+
+       ret = riscv_insn_write(tp, insns, len);
+
+       if (!ret)
+               flush_icache_range((uintptr_t) tp, (uintptr_t) tp + len);
+
+       return ret;
+}
+
+static int __kprobes riscv_patch_text_cb(void *data)
+{
+       struct riscv_insn_patch *patch = data;
+       int ret = 0;
+
+       if (atomic_inc_return(&patch->cpu_count) == 1) {
+               ret =
+                   riscv_patch_text_nosync(patch->addr, &patch->insn,
+                                           GET_INSN_LENGTH(patch->insn));
+               atomic_inc(&patch->cpu_count);
+       } else {
+               while (atomic_read(&patch->cpu_count) <= num_online_cpus())
+                       cpu_relax();
+               smp_mb();
+       }
+
+       return ret;
+}
+
+int __kprobes riscv_patch_text(void *addr, u32 insn)
+{
+       struct riscv_insn_patch patch = {
+               .addr = addr,
+               .insn = insn,
+               .cpu_count = ATOMIC_INIT(0),
+       };
+
+       return stop_machine_cpuslocked(riscv_patch_text_cb,
+                                      &patch, cpu_online_mask);
+}
index 817cf7b..610c11e 100644 (file)
@@ -22,6 +22,8 @@
 #include <asm/switch_to.h>
 #include <asm/thread_info.h>
 
+unsigned long gp_in_global __asm__("gp");
+
 extern asmlinkage void ret_from_fork(void);
 extern asmlinkage void ret_from_kernel_thread(void);
 
@@ -107,9 +109,8 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
        /* p->thread holds context to be restored by __switch_to() */
        if (unlikely(p->flags & PF_KTHREAD)) {
                /* Kernel thread */
-               const register unsigned long gp __asm__ ("gp");
                memset(childregs, 0, sizeof(struct pt_regs));
-               childregs->gp = gp;
+               childregs->gp = gp_in_global;
                /* Supervisor/Machine, irqs on: */
                childregs->status = SR_PP | SR_PIE;
 
index f6c7c3e..7c24da5 100644 (file)
 // SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SBI initialilization and all extension implementation.
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
 
 #include <linux/init.h>
 #include <linux/pm.h>
 #include <asm/sbi.h>
+#include <asm/smp.h>
+
+/* default SBI version is 0.1 */
+unsigned long sbi_spec_version = SBI_SPEC_VERSION_DEFAULT;
+EXPORT_SYMBOL(sbi_spec_version);
+
+static void (*__sbi_set_timer)(uint64_t stime);
+static int (*__sbi_send_ipi)(const unsigned long *hart_mask);
+static int (*__sbi_rfence)(int fid, const unsigned long *hart_mask,
+                          unsigned long start, unsigned long size,
+                          unsigned long arg4, unsigned long arg5);
+
+struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
+                       unsigned long arg1, unsigned long arg2,
+                       unsigned long arg3, unsigned long arg4,
+                       unsigned long arg5)
+{
+       struct sbiret ret;
+
+       register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);
+       register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);
+       register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);
+       register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);
+       register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4);
+       register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5);
+       register uintptr_t a6 asm ("a6") = (uintptr_t)(fid);
+       register uintptr_t a7 asm ("a7") = (uintptr_t)(ext);
+       asm volatile ("ecall"
+                     : "+r" (a0), "+r" (a1)
+                     : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
+                     : "memory");
+       ret.error = a0;
+       ret.value = a1;
+
+       return ret;
+}
+EXPORT_SYMBOL(sbi_ecall);
+
+int sbi_err_map_linux_errno(int err)
+{
+       switch (err) {
+       case SBI_SUCCESS:
+               return 0;
+       case SBI_ERR_DENIED:
+               return -EPERM;
+       case SBI_ERR_INVALID_PARAM:
+               return -EINVAL;
+       case SBI_ERR_INVALID_ADDRESS:
+               return -EFAULT;
+       case SBI_ERR_NOT_SUPPORTED:
+       case SBI_ERR_FAILURE:
+       default:
+               return -ENOTSUPP;
+       };
+}
+EXPORT_SYMBOL(sbi_err_map_linux_errno);
+
+#ifdef CONFIG_RISCV_SBI_V01
+/**
+ * sbi_console_putchar() - Writes given character to the console device.
+ * @ch: The data to be written to the console.
+ *
+ * Return: None
+ */
+void sbi_console_putchar(int ch)
+{
+       sbi_ecall(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, ch, 0, 0, 0, 0, 0);
+}
+EXPORT_SYMBOL(sbi_console_putchar);
+
+/**
+ * sbi_console_getchar() - Reads a byte from console device.
+ *
+ * Returns the value read from console.
+ */
+int sbi_console_getchar(void)
+{
+       struct sbiret ret;
+
+       ret = sbi_ecall(SBI_EXT_0_1_CONSOLE_GETCHAR, 0, 0, 0, 0, 0, 0, 0);
+
+       return ret.error;
+}
+EXPORT_SYMBOL(sbi_console_getchar);
+
+/**
+ * sbi_shutdown() - Remove all the harts from executing supervisor code.
+ *
+ * Return: None
+ */
+void sbi_shutdown(void)
+{
+       sbi_ecall(SBI_EXT_0_1_SHUTDOWN, 0, 0, 0, 0, 0, 0, 0);
+}
+EXPORT_SYMBOL(sbi_set_timer);
+
+/**
+ * sbi_clear_ipi() - Clear any pending IPIs for the calling hart.
+ *
+ * Return: None
+ */
+void sbi_clear_ipi(void)
+{
+       sbi_ecall(SBI_EXT_0_1_CLEAR_IPI, 0, 0, 0, 0, 0, 0, 0);
+}
+EXPORT_SYMBOL(sbi_shutdown);
+
+/**
+ * sbi_set_timer_v01() - Program the timer for next timer event.
+ * @stime_value: The value after which next timer event should fire.
+ *
+ * Return: None
+ */
+static void __sbi_set_timer_v01(uint64_t stime_value)
+{
+#if __riscv_xlen == 32
+       sbi_ecall(SBI_EXT_0_1_SET_TIMER, 0, stime_value,
+                 stime_value >> 32, 0, 0, 0, 0);
+#else
+       sbi_ecall(SBI_EXT_0_1_SET_TIMER, 0, stime_value, 0, 0, 0, 0, 0);
+#endif
+}
+
+static int __sbi_send_ipi_v01(const unsigned long *hart_mask)
+{
+       sbi_ecall(SBI_EXT_0_1_SEND_IPI, 0, (unsigned long)hart_mask,
+                 0, 0, 0, 0, 0);
+       return 0;
+}
+
+static int __sbi_rfence_v01(int fid, const unsigned long *hart_mask,
+                           unsigned long start, unsigned long size,
+                           unsigned long arg4, unsigned long arg5)
+{
+       int result = 0;
+
+       /* v0.2 function IDs are equivalent to v0.1 extension IDs */
+       switch (fid) {
+       case SBI_EXT_RFENCE_REMOTE_FENCE_I:
+               sbi_ecall(SBI_EXT_0_1_REMOTE_FENCE_I, 0,
+                         (unsigned long)hart_mask, 0, 0, 0, 0, 0);
+               break;
+       case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
+               sbi_ecall(SBI_EXT_0_1_REMOTE_SFENCE_VMA, 0,
+                         (unsigned long)hart_mask, start, size,
+                         0, 0, 0);
+               break;
+       case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
+               sbi_ecall(SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID, 0,
+                         (unsigned long)hart_mask, start, size,
+                         arg4, 0, 0);
+               break;
+       default:
+               pr_err("SBI call [%d]not supported in SBI v0.1\n", fid);
+               result = -EINVAL;
+       }
+
+       return result;
+}
+#else
+static void __sbi_set_timer_v01(uint64_t stime_value)
+{
+       pr_warn("Timer extension is not available in SBI v%lu.%lu\n",
+               sbi_major_version(), sbi_minor_version());
+}
+
+static int __sbi_send_ipi_v01(const unsigned long *hart_mask)
+{
+       pr_warn("IPI extension is not available in SBI v%lu.%lu\n",
+               sbi_major_version(), sbi_minor_version());
+
+       return 0;
+}
+
+static int __sbi_rfence_v01(int fid, const unsigned long *hart_mask,
+                           unsigned long start, unsigned long size,
+                           unsigned long arg4, unsigned long arg5)
+{
+       pr_warn("remote fence extension is not available in SBI v%lu.%lu\n",
+               sbi_major_version(), sbi_minor_version());
+
+       return 0;
+}
+#endif /* CONFIG_RISCV_SBI_V01 */
+
+static void __sbi_set_timer_v02(uint64_t stime_value)
+{
+#if __riscv_xlen == 32
+       sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value,
+                 stime_value >> 32, 0, 0, 0, 0);
+#else
+       sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0,
+                 0, 0, 0, 0);
+#endif
+}
+
+static int __sbi_send_ipi_v02(const unsigned long *hart_mask)
+{
+       unsigned long hartid, hmask_val, hbase;
+       struct cpumask tmask;
+       struct sbiret ret = {0};
+       int result;
+
+       if (!hart_mask || !(*hart_mask)) {
+               riscv_cpuid_to_hartid_mask(cpu_online_mask, &tmask);
+               hart_mask = cpumask_bits(&tmask);
+       }
+
+       hmask_val = 0;
+       hbase = 0;
+       for_each_set_bit(hartid, hart_mask, NR_CPUS) {
+               if (hmask_val && ((hbase + BITS_PER_LONG) <= hartid)) {
+                       ret = sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI,
+                                       hmask_val, hbase, 0, 0, 0, 0);
+                       if (ret.error)
+                               goto ecall_failed;
+                       hmask_val = 0;
+                       hbase = 0;
+               }
+               if (!hmask_val)
+                       hbase = hartid;
+               hmask_val |= 1UL << (hartid - hbase);
+       }
+
+       if (hmask_val) {
+               ret = sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI,
+                               hmask_val, hbase, 0, 0, 0, 0);
+               if (ret.error)
+                       goto ecall_failed;
+       }
+
+       return 0;
+
+ecall_failed:
+       result = sbi_err_map_linux_errno(ret.error);
+       pr_err("%s: hbase = [%lu] hmask = [0x%lx] failed (error [%d])\n",
+              __func__, hbase, hmask_val, result);
+       return result;
+}
+
+static int __sbi_rfence_v02_call(unsigned long fid, unsigned long hmask_val,
+                                unsigned long hbase, unsigned long start,
+                                unsigned long size, unsigned long arg4,
+                                unsigned long arg5)
+{
+       struct sbiret ret = {0};
+       int ext = SBI_EXT_RFENCE;
+       int result = 0;
+
+       switch (fid) {
+       case SBI_EXT_RFENCE_REMOTE_FENCE_I:
+               ret = sbi_ecall(ext, fid, hmask_val, hbase, 0, 0, 0, 0);
+               break;
+       case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
+               ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
+                               size, 0, 0);
+               break;
+       case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
+               ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
+                               size, arg4, 0);
+               break;
+
+       case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
+               ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
+                               size, 0, 0);
+               break;
+       case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
+               ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
+                               size, arg4, 0);
+               break;
+       case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
+               ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
+                               size, 0, 0);
+               break;
+       case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
+               ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
+                               size, arg4, 0);
+               break;
+       default:
+               pr_err("unknown function ID [%lu] for SBI extension [%d]\n",
+                      fid, ext);
+               result = -EINVAL;
+       }
+
+       if (ret.error) {
+               result = sbi_err_map_linux_errno(ret.error);
+               pr_err("%s: hbase = [%lu] hmask = [0x%lx] failed (error [%d])\n",
+                      __func__, hbase, hmask_val, result);
+       }
+
+       return result;
+}
+
+static int __sbi_rfence_v02(int fid, const unsigned long *hart_mask,
+                           unsigned long start, unsigned long size,
+                           unsigned long arg4, unsigned long arg5)
+{
+       unsigned long hmask_val, hartid, hbase;
+       struct cpumask tmask;
+       int result;
+
+       if (!hart_mask || !(*hart_mask)) {
+               riscv_cpuid_to_hartid_mask(cpu_online_mask, &tmask);
+               hart_mask = cpumask_bits(&tmask);
+       }
+
+       hmask_val = 0;
+       hbase = 0;
+       for_each_set_bit(hartid, hart_mask, NR_CPUS) {
+               if (hmask_val && ((hbase + BITS_PER_LONG) <= hartid)) {
+                       result = __sbi_rfence_v02_call(fid, hmask_val, hbase,
+                                                      start, size, arg4, arg5);
+                       if (result)
+                               return result;
+                       hmask_val = 0;
+                       hbase = 0;
+               }
+               if (!hmask_val)
+                       hbase = hartid;
+               hmask_val |= 1UL << (hartid - hbase);
+       }
+
+       if (hmask_val) {
+               result = __sbi_rfence_v02_call(fid, hmask_val, hbase,
+                                              start, size, arg4, arg5);
+               if (result)
+                       return result;
+       }
+
+       return 0;
+}
+
+/**
+ * sbi_set_timer() - Program the timer for next timer event.
+ * @stime_value: The value after which next timer event should fire.
+ *
+ * Return: None
+ */
+void sbi_set_timer(uint64_t stime_value)
+{
+       __sbi_set_timer(stime_value);
+}
+
+/**
+ * sbi_send_ipi() - Send an IPI to any hart.
+ * @hart_mask: A cpu mask containing all the target harts.
+ *
+ * Return: None
+ */
+void sbi_send_ipi(const unsigned long *hart_mask)
+{
+       __sbi_send_ipi(hart_mask);
+}
+EXPORT_SYMBOL(sbi_send_ipi);
+
+/**
+ * sbi_remote_fence_i() - Execute FENCE.I instruction on given remote harts.
+ * @hart_mask: A cpu mask containing all the target harts.
+ *
+ * Return: None
+ */
+void sbi_remote_fence_i(const unsigned long *hart_mask)
+{
+       __sbi_rfence(SBI_EXT_RFENCE_REMOTE_FENCE_I,
+                    hart_mask, 0, 0, 0, 0);
+}
+EXPORT_SYMBOL(sbi_remote_fence_i);
+
+/**
+ * sbi_remote_sfence_vma() - Execute SFENCE.VMA instructions on given remote
+ *                          harts for the specified virtual address range.
+ * @hart_mask: A cpu mask containing all the target harts.
+ * @start: Start of the virtual address
+ * @size: Total size of the virtual address range.
+ *
+ * Return: None
+ */
+void sbi_remote_sfence_vma(const unsigned long *hart_mask,
+                          unsigned long start,
+                          unsigned long size)
+{
+       __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA,
+                    hart_mask, start, size, 0, 0);
+}
+EXPORT_SYMBOL(sbi_remote_sfence_vma);
+
+/**
+ * sbi_remote_sfence_vma_asid() - Execute SFENCE.VMA instructions on given
+ * remote harts for a virtual address range belonging to a specific ASID.
+ *
+ * @hart_mask: A cpu mask containing all the target harts.
+ * @start: Start of the virtual address
+ * @size: Total size of the virtual address range.
+ * @asid: The value of address space identifier (ASID).
+ *
+ * Return: None
+ */
+void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
+                               unsigned long start,
+                               unsigned long size,
+                               unsigned long asid)
+{
+       __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID,
+                    hart_mask, start, size, asid, 0);
+}
+EXPORT_SYMBOL(sbi_remote_sfence_vma_asid);
+
+/**
+ * sbi_remote_hfence_gvma() - Execute HFENCE.GVMA instructions on given remote
+ *                        harts for the specified guest physical address range.
+ * @hart_mask: A cpu mask containing all the target harts.
+ * @start: Start of the guest physical address
+ * @size: Total size of the guest physical address range.
+ *
+ * Return: None
+ */
+int sbi_remote_hfence_gvma(const unsigned long *hart_mask,
+                          unsigned long start,
+                          unsigned long size)
+{
+       return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA,
+                           hart_mask, start, size, 0, 0);
+}
+EXPORT_SYMBOL_GPL(sbi_remote_hfence_gvma);
+
+/**
+ * sbi_remote_hfence_gvma_vmid() - Execute HFENCE.GVMA instructions on given
+ * remote harts for a guest physical address range belonging to a specific VMID.
+ *
+ * @hart_mask: A cpu mask containing all the target harts.
+ * @start: Start of the guest physical address
+ * @size: Total size of the guest physical address range.
+ * @vmid: The value of guest ID (VMID).
+ *
+ * Return: 0 if success, Error otherwise.
+ */
+int sbi_remote_hfence_gvma_vmid(const unsigned long *hart_mask,
+                               unsigned long start,
+                               unsigned long size,
+                               unsigned long vmid)
+{
+       return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID,
+                           hart_mask, start, size, vmid, 0);
+}
+EXPORT_SYMBOL(sbi_remote_hfence_gvma_vmid);
+
+/**
+ * sbi_remote_hfence_vvma() - Execute HFENCE.VVMA instructions on given remote
+ *                          harts for the current guest virtual address range.
+ * @hart_mask: A cpu mask containing all the target harts.
+ * @start: Start of the current guest virtual address
+ * @size: Total size of the current guest virtual address range.
+ *
+ * Return: None
+ */
+int sbi_remote_hfence_vvma(const unsigned long *hart_mask,
+                          unsigned long start,
+                          unsigned long size)
+{
+       return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA,
+                           hart_mask, start, size, 0, 0);
+}
+EXPORT_SYMBOL(sbi_remote_hfence_vvma);
+
+/**
+ * sbi_remote_hfence_vvma_asid() - Execute HFENCE.VVMA instructions on given
+ * remote harts for current guest virtual address range belonging to a specific
+ * ASID.
+ *
+ * @hart_mask: A cpu mask containing all the target harts.
+ * @start: Start of the current guest virtual address
+ * @size: Total size of the current guest virtual address range.
+ * @asid: The value of address space identifier (ASID).
+ *
+ * Return: None
+ */
+int sbi_remote_hfence_vvma_asid(const unsigned long *hart_mask,
+                               unsigned long start,
+                               unsigned long size,
+                               unsigned long asid)
+{
+       return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID,
+                           hart_mask, start, size, asid, 0);
+}
+EXPORT_SYMBOL(sbi_remote_hfence_vvma_asid);
+
+/**
+ * sbi_probe_extension() - Check if an SBI extension ID is supported or not.
+ * @extid: The extension ID to be probed.
+ *
+ * Return: Extension specific nonzero value f yes, -ENOTSUPP otherwise.
+ */
+int sbi_probe_extension(int extid)
+{
+       struct sbiret ret;
+
+       ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, extid,
+                       0, 0, 0, 0, 0);
+       if (!ret.error)
+               if (ret.value)
+                       return ret.value;
+
+       return -ENOTSUPP;
+}
+EXPORT_SYMBOL(sbi_probe_extension);
+
+static long __sbi_base_ecall(int fid)
+{
+       struct sbiret ret;
+
+       ret = sbi_ecall(SBI_EXT_BASE, fid, 0, 0, 0, 0, 0, 0);
+       if (!ret.error)
+               return ret.value;
+       else
+               return sbi_err_map_linux_errno(ret.error);
+}
+
+static inline long sbi_get_spec_version(void)
+{
+       return __sbi_base_ecall(SBI_EXT_BASE_GET_SPEC_VERSION);
+}
+
+static inline long sbi_get_firmware_id(void)
+{
+       return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_ID);
+}
+
+static inline long sbi_get_firmware_version(void)
+{
+       return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_VERSION);
+}
 
 static void sbi_power_off(void)
 {
        sbi_shutdown();
 }
 
-static int __init sbi_init(void)
+int __init sbi_init(void)
 {
+       int ret;
+
        pm_power_off = sbi_power_off;
+       ret = sbi_get_spec_version();
+       if (ret > 0)
+               sbi_spec_version = ret;
+
+       pr_info("SBI specification v%lu.%lu detected\n",
+               sbi_major_version(), sbi_minor_version());
+
+       if (!sbi_spec_is_0_1()) {
+               pr_info("SBI implementation ID=0x%lx Version=0x%lx\n",
+                       sbi_get_firmware_id(), sbi_get_firmware_version());
+               if (sbi_probe_extension(SBI_EXT_TIME) > 0) {
+                       __sbi_set_timer = __sbi_set_timer_v02;
+                       pr_info("SBI v0.2 TIME extension detected\n");
+               } else {
+                       __sbi_set_timer = __sbi_set_timer_v01;
+               }
+               if (sbi_probe_extension(SBI_EXT_IPI) > 0) {
+                       __sbi_send_ipi  = __sbi_send_ipi_v02;
+                       pr_info("SBI v0.2 IPI extension detected\n");
+               } else {
+                       __sbi_send_ipi  = __sbi_send_ipi_v01;
+               }
+               if (sbi_probe_extension(SBI_EXT_RFENCE) > 0) {
+                       __sbi_rfence    = __sbi_rfence_v02;
+                       pr_info("SBI v0.2 RFENCE extension detected\n");
+               } else {
+                       __sbi_rfence    = __sbi_rfence_v01;
+               }
+       } else {
+               __sbi_set_timer = __sbi_set_timer_v01;
+               __sbi_send_ipi  = __sbi_send_ipi_v01;
+               __sbi_rfence    = __sbi_rfence_v01;
+       }
+
        return 0;
 }
-early_initcall(sbi_init);
index 0a6d415..145128a 100644 (file)
 #include <linux/of_platform.h>
 #include <linux/sched/task.h>
 #include <linux/swiotlb.h>
+#include <linux/smp.h>
 
 #include <asm/clint.h>
+#include <asm/cpu_ops.h>
 #include <asm/setup.h>
 #include <asm/sections.h>
 #include <asm/pgtable.h>
-#include <asm/smp.h>
+#include <asm/sbi.h>
 #include <asm/tlbflush.h>
 #include <asm/thread_info.h>
 #include <asm/kasan.h>
@@ -39,9 +41,14 @@ struct screen_info screen_info = {
 };
 #endif
 
-/* The lucky hart to first increment this variable will boot the other cores */
-atomic_t hart_lottery;
+/*
+ * The lucky hart to first increment this variable will boot the other cores.
+ * This is used before the kernel initializes the BSS so it can't be in the
+ * BSS.
+ */
+atomic_t hart_lottery __section(.sdata);
 unsigned long boot_cpu_hartid;
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
 
 void __init parse_dtb(void)
 {
@@ -79,9 +86,28 @@ void __init setup_arch(char **cmdline_p)
        kasan_init();
 #endif
 
+#if IS_ENABLED(CONFIG_RISCV_SBI)
+       sbi_init();
+#endif
+
 #ifdef CONFIG_SMP
        setup_smp();
 #endif
 
        riscv_fill_hwcap();
 }
+
+static int __init topology_init(void)
+{
+       int i;
+
+       for_each_possible_cpu(i) {
+               struct cpu *cpu = &per_cpu(cpu_devices, i);
+
+               cpu->hotpluggable = cpu_has_hotplug(i);
+               register_cpu(cpu, i);
+       }
+
+       return 0;
+}
+subsys_initcall(topology_init);
index 8bc01f0..4e99227 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/sched/task_stack.h>
 #include <linux/sched/mm.h>
 #include <asm/clint.h>
+#include <asm/cpu_ops.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
@@ -34,8 +35,6 @@
 
 #include "head.h"
 
-void *__cpu_up_stack_pointer[NR_CPUS];
-void *__cpu_up_task_pointer[NR_CPUS];
 static DECLARE_COMPLETION(cpu_running);
 
 void __init smp_prepare_boot_cpu(void)
@@ -46,6 +45,7 @@ void __init smp_prepare_boot_cpu(void)
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
        int cpuid;
+       int ret;
 
        /* This covers non-smp usecase mandated by "nosmp" option */
        if (max_cpus == 0)
@@ -54,6 +54,11 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        for_each_possible_cpu(cpuid) {
                if (cpuid == smp_processor_id())
                        continue;
+               if (cpu_ops[cpuid]->cpu_prepare) {
+                       ret = cpu_ops[cpuid]->cpu_prepare(cpuid);
+                       if (ret)
+                               continue;
+               }
                set_cpu_present(cpuid, true);
        }
 }
@@ -65,6 +70,8 @@ void __init setup_smp(void)
        bool found_boot_cpu = false;
        int cpuid = 1;
 
+       cpu_set_ops(0);
+
        for_each_of_cpu_node(dn) {
                hart = riscv_of_processor_hartid(dn);
                if (hart < 0)
@@ -92,36 +99,38 @@ void __init setup_smp(void)
                        cpuid, nr_cpu_ids);
 
        for (cpuid = 1; cpuid < nr_cpu_ids; cpuid++) {
-               if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID)
+               if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID) {
+                       cpu_set_ops(cpuid);
                        set_cpu_possible(cpuid, true);
+               }
        }
 }
 
+int start_secondary_cpu(int cpu, struct task_struct *tidle)
+{
+       if (cpu_ops[cpu]->cpu_start)
+               return cpu_ops[cpu]->cpu_start(cpu, tidle);
+
+       return -EOPNOTSUPP;
+}
+
 int __cpu_up(unsigned int cpu, struct task_struct *tidle)
 {
        int ret = 0;
-       int hartid = cpuid_to_hartid_map(cpu);
        tidle->thread_info.cpu = cpu;
 
-       /*
-        * On RISC-V systems, all harts boot on their own accord.  Our _start
-        * selects the first hart to boot the kernel and causes the remainder
-        * of the harts to spin in a loop waiting for their stack pointer to be
-        * setup by that main hart.  Writing __cpu_up_stack_pointer signals to
-        * the spinning harts that they can continue the boot process.
-        */
-       smp_mb();
-       WRITE_ONCE(__cpu_up_stack_pointer[hartid],
-                 task_stack_page(tidle) + THREAD_SIZE);
-       WRITE_ONCE(__cpu_up_task_pointer[hartid], tidle);
-
-       lockdep_assert_held(&cpu_running);
-       wait_for_completion_timeout(&cpu_running,
+       ret = start_secondary_cpu(cpu, tidle);
+       if (!ret) {
+               lockdep_assert_held(&cpu_running);
+               wait_for_completion_timeout(&cpu_running,
                                            msecs_to_jiffies(1000));
 
-       if (!cpu_online(cpu)) {
-               pr_crit("CPU%u: failed to come online\n", cpu);
-               ret = -EIO;
+               if (!cpu_online(cpu)) {
+                       pr_crit("CPU%u: failed to come online\n", cpu);
+                       ret = -EIO;
+               }
+       } else {
+               pr_crit("CPU%u: failed to start\n", cpu);
        }
 
        return ret;
@@ -134,7 +143,7 @@ void __init smp_cpus_done(unsigned int max_cpus)
 /*
  * C entry point for a secondary processor.
  */
-asmlinkage __visible void __init smp_callin(void)
+asmlinkage __visible void smp_callin(void)
 {
        struct mm_struct *mm = &init_mm;
 
diff --git a/arch/riscv/kernel/soc.c b/arch/riscv/kernel/soc.c
new file mode 100644 (file)
index 0000000..0b3b3dc
--- /dev/null
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+#include <linux/init.h>
+#include <linux/libfdt.h>
+#include <asm/pgtable.h>
+#include <asm/soc.h>
+
+/*
+ * This is called extremly early, before parse_dtb(), to allow initializing
+ * SoC hardware before memory or any device driver initialization.
+ */
+void __init soc_early_init(void)
+{
+       void (*early_fn)(const void *fdt);
+       const struct of_device_id *s;
+       const void *fdt = dtb_early_va;
+
+       for (s = (void *)&__soc_early_init_table_start;
+            (void *)s < (void *)&__soc_early_init_table_end; s++) {
+               if (!fdt_node_check_compatible(fdt, 0, s->compatible)) {
+                       early_fn = s->data;
+                       early_fn(fdt);
+                       return;
+               }
+       }
+}
index 0940681..02087fe 100644 (file)
@@ -19,6 +19,8 @@ struct stackframe {
        unsigned long ra;
 };
 
+register unsigned long sp_in_global __asm__("sp");
+
 void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
                             bool (*fn)(unsigned long, void *), void *arg)
 {
@@ -29,7 +31,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
                sp = user_stack_pointer(regs);
                pc = instruction_pointer(regs);
        } else if (task == NULL || task == current) {
-               const register unsigned long current_sp __asm__ ("sp");
+               const register unsigned long current_sp = sp_in_global;
                fp = (unsigned long)__builtin_frame_address(0);
                sp = current_sp;
                pc = (unsigned long)walk_stackframe;
@@ -73,8 +75,7 @@ static void notrace walk_stackframe(struct task_struct *task,
                sp = user_stack_pointer(regs);
                pc = instruction_pointer(regs);
        } else if (task == NULL || task == current) {
-               const register unsigned long current_sp __asm__ ("sp");
-               sp = current_sp;
+               sp = sp_in_global;
                pc = (unsigned long)walk_stackframe;
        } else {
                /* task blocked in __switch_to */
index 55ea614..7f58fa5 100644 (file)
@@ -97,12 +97,33 @@ DO_ERROR_INFO(do_trap_insn_fault,
        SIGSEGV, SEGV_ACCERR, "instruction access fault");
 DO_ERROR_INFO(do_trap_insn_illegal,
        SIGILL, ILL_ILLOPC, "illegal instruction");
-DO_ERROR_INFO(do_trap_load_misaligned,
-       SIGBUS, BUS_ADRALN, "load address misaligned");
 DO_ERROR_INFO(do_trap_load_fault,
        SIGSEGV, SEGV_ACCERR, "load access fault");
+#ifndef CONFIG_RISCV_M_MODE
+DO_ERROR_INFO(do_trap_load_misaligned,
+       SIGBUS, BUS_ADRALN, "Oops - load address misaligned");
 DO_ERROR_INFO(do_trap_store_misaligned,
-       SIGBUS, BUS_ADRALN, "store (or AMO) address misaligned");
+       SIGBUS, BUS_ADRALN, "Oops - store (or AMO) address misaligned");
+#else
+int handle_misaligned_load(struct pt_regs *regs);
+int handle_misaligned_store(struct pt_regs *regs);
+
+asmlinkage void do_trap_load_misaligned(struct pt_regs *regs)
+{
+       if (!handle_misaligned_load(regs))
+               return;
+       do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
+                     "Oops - load address misaligned");
+}
+
+asmlinkage void do_trap_store_misaligned(struct pt_regs *regs)
+{
+       if (!handle_misaligned_store(regs))
+               return;
+       do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
+                     "Oops - store (or AMO) address misaligned");
+}
+#endif
 DO_ERROR_INFO(do_trap_store_fault,
        SIGSEGV, SEGV_ACCERR, "store (or AMO) access fault");
 DO_ERROR_INFO(do_trap_ecall_u,
@@ -118,7 +139,8 @@ static inline unsigned long get_break_insn_length(unsigned long pc)
 
        if (probe_kernel_address((bug_insn_t *)pc, insn))
                return 0;
-       return (((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32) ? 4UL : 2UL);
+
+       return GET_INSN_LENGTH(insn);
 }
 
 asmlinkage __visible void do_trap_break(struct pt_regs *regs)
@@ -147,7 +169,7 @@ int is_valid_bugaddr(unsigned long pc)
 }
 #endif /* CONFIG_GENERIC_BUG */
 
-void __init trap_init(void)
+void trap_init(void)
 {
        /*
         * Set sup0 scratch register to 0, indicating to exception vector
diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
new file mode 100644 (file)
index 0000000..46c4daf
--- /dev/null
@@ -0,0 +1,370 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/csr.h>
+
+#define INSN_MATCH_LB                  0x3
+#define INSN_MASK_LB                   0x707f
+#define INSN_MATCH_LH                  0x1003
+#define INSN_MASK_LH                   0x707f
+#define INSN_MATCH_LW                  0x2003
+#define INSN_MASK_LW                   0x707f
+#define INSN_MATCH_LD                  0x3003
+#define INSN_MASK_LD                   0x707f
+#define INSN_MATCH_LBU                 0x4003
+#define INSN_MASK_LBU                  0x707f
+#define INSN_MATCH_LHU                 0x5003
+#define INSN_MASK_LHU                  0x707f
+#define INSN_MATCH_LWU                 0x6003
+#define INSN_MASK_LWU                  0x707f
+#define INSN_MATCH_SB                  0x23
+#define INSN_MASK_SB                   0x707f
+#define INSN_MATCH_SH                  0x1023
+#define INSN_MASK_SH                   0x707f
+#define INSN_MATCH_SW                  0x2023
+#define INSN_MASK_SW                   0x707f
+#define INSN_MATCH_SD                  0x3023
+#define INSN_MASK_SD                   0x707f
+
+#define INSN_MATCH_FLW                 0x2007
+#define INSN_MASK_FLW                  0x707f
+#define INSN_MATCH_FLD                 0x3007
+#define INSN_MASK_FLD                  0x707f
+#define INSN_MATCH_FLQ                 0x4007
+#define INSN_MASK_FLQ                  0x707f
+#define INSN_MATCH_FSW                 0x2027
+#define INSN_MASK_FSW                  0x707f
+#define INSN_MATCH_FSD                 0x3027
+#define INSN_MASK_FSD                  0x707f
+#define INSN_MATCH_FSQ                 0x4027
+#define INSN_MASK_FSQ                  0x707f
+
+#define INSN_MATCH_C_LD                        0x6000
+#define INSN_MASK_C_LD                 0xe003
+#define INSN_MATCH_C_SD                        0xe000
+#define INSN_MASK_C_SD                 0xe003
+#define INSN_MATCH_C_LW                        0x4000
+#define INSN_MASK_C_LW                 0xe003
+#define INSN_MATCH_C_SW                        0xc000
+#define INSN_MASK_C_SW                 0xe003
+#define INSN_MATCH_C_LDSP              0x6002
+#define INSN_MASK_C_LDSP               0xe003
+#define INSN_MATCH_C_SDSP              0xe002
+#define INSN_MASK_C_SDSP               0xe003
+#define INSN_MATCH_C_LWSP              0x4002
+#define INSN_MASK_C_LWSP               0xe003
+#define INSN_MATCH_C_SWSP              0xc002
+#define INSN_MASK_C_SWSP               0xe003
+
+#define INSN_MATCH_C_FLD               0x2000
+#define INSN_MASK_C_FLD                        0xe003
+#define INSN_MATCH_C_FLW               0x6000
+#define INSN_MASK_C_FLW                        0xe003
+#define INSN_MATCH_C_FSD               0xa000
+#define INSN_MASK_C_FSD                        0xe003
+#define INSN_MATCH_C_FSW               0xe000
+#define INSN_MASK_C_FSW                        0xe003
+#define INSN_MATCH_C_FLDSP             0x2002
+#define INSN_MASK_C_FLDSP              0xe003
+#define INSN_MATCH_C_FSDSP             0xa002
+#define INSN_MASK_C_FSDSP              0xe003
+#define INSN_MATCH_C_FLWSP             0x6002
+#define INSN_MASK_C_FLWSP              0xe003
+#define INSN_MATCH_C_FSWSP             0xe002
+#define INSN_MASK_C_FSWSP              0xe003
+
+#define INSN_LEN(insn)                 ((((insn) & 0x3) < 0x3) ? 2 : 4)
+
+#if defined(CONFIG_64BIT)
+#define LOG_REGBYTES                   3
+#define XLEN                           64
+#else
+#define LOG_REGBYTES                   2
+#define XLEN                           32
+#endif
+#define REGBYTES                       (1 << LOG_REGBYTES)
+#define XLEN_MINUS_16                  ((XLEN) - 16)
+
+#define SH_RD                          7
+#define SH_RS1                         15
+#define SH_RS2                         20
+#define SH_RS2C                                2
+
+#define RV_X(x, s, n)                  (((x) >> (s)) & ((1 << (n)) - 1))
+#define RVC_LW_IMM(x)                  ((RV_X(x, 6, 1) << 2) | \
+                                        (RV_X(x, 10, 3) << 3) | \
+                                        (RV_X(x, 5, 1) << 6))
+#define RVC_LD_IMM(x)                  ((RV_X(x, 10, 3) << 3) | \
+                                        (RV_X(x, 5, 2) << 6))
+#define RVC_LWSP_IMM(x)                        ((RV_X(x, 4, 3) << 2) | \
+                                        (RV_X(x, 12, 1) << 5) | \
+                                        (RV_X(x, 2, 2) << 6))
+#define RVC_LDSP_IMM(x)                        ((RV_X(x, 5, 2) << 3) | \
+                                        (RV_X(x, 12, 1) << 5) | \
+                                        (RV_X(x, 2, 3) << 6))
+#define RVC_SWSP_IMM(x)                        ((RV_X(x, 9, 4) << 2) | \
+                                        (RV_X(x, 7, 2) << 6))
+#define RVC_SDSP_IMM(x)                        ((RV_X(x, 10, 3) << 3) | \
+                                        (RV_X(x, 7, 3) << 6))
+#define RVC_RS1S(insn)                 (8 + RV_X(insn, SH_RD, 3))
+#define RVC_RS2S(insn)                 (8 + RV_X(insn, SH_RS2C, 3))
+#define RVC_RS2(insn)                  RV_X(insn, SH_RS2C, 5)
+
+#define SHIFT_RIGHT(x, y)              \
+       ((y) < 0 ? ((x) << -(y)) : ((x) >> (y)))
+
+#define REG_MASK                       \
+       ((1 << (5 + LOG_REGBYTES)) - (1 << LOG_REGBYTES))
+
+#define REG_OFFSET(insn, pos)          \
+       (SHIFT_RIGHT((insn), (pos) - LOG_REGBYTES) & REG_MASK)
+
+#define REG_PTR(insn, pos, regs)       \
+       (ulong *)((ulong)(regs) + REG_OFFSET(insn, pos))
+
+#define GET_RM(insn)                   (((insn) >> 12) & 7)
+
+#define GET_RS1(insn, regs)            (*REG_PTR(insn, SH_RS1, regs))
+#define GET_RS2(insn, regs)            (*REG_PTR(insn, SH_RS2, regs))
+#define GET_RS1S(insn, regs)           (*REG_PTR(RVC_RS1S(insn), 0, regs))
+#define GET_RS2S(insn, regs)           (*REG_PTR(RVC_RS2S(insn), 0, regs))
+#define GET_RS2C(insn, regs)           (*REG_PTR(insn, SH_RS2C, regs))
+#define GET_SP(regs)                   (*REG_PTR(2, 0, regs))
+#define SET_RD(insn, regs, val)                (*REG_PTR(insn, SH_RD, regs) = (val))
+#define IMM_I(insn)                    ((s32)(insn) >> 20)
+#define IMM_S(insn)                    (((s32)(insn) >> 25 << 5) | \
+                                        (s32)(((insn) >> 7) & 0x1f))
+#define MASK_FUNCT3                    0x7000
+
+#define GET_PRECISION(insn) (((insn) >> 25) & 3)
+#define GET_RM(insn) (((insn) >> 12) & 7)
+#define PRECISION_S 0
+#define PRECISION_D 1
+
+#define STR(x) XSTR(x)
+#define XSTR(x) #x
+
+#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type, insn)                 \
+static inline type load_##type(const type *addr)                       \
+{                                                                      \
+       type val;                                                       \
+       asm (#insn " %0, %1"                                            \
+       : "=&r" (val) : "m" (*addr));                                   \
+       return val;                                                     \
+}
+
+#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type, insn)                        \
+static inline void store_##type(type *addr, type val)                  \
+{                                                                      \
+       asm volatile (#insn " %0, %1\n"                                 \
+       : : "r" (val), "m" (*addr));                                    \
+}
+
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u8, sb)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u16, sh)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u32, sw)
+#if defined(CONFIG_64BIT)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
+#else
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
+
+static inline u64 load_u64(const u64 *addr)
+{
+       return load_u32((u32 *)addr)
+               + ((u64)load_u32((u32 *)addr + 1) << 32);
+}
+
+static inline void store_u64(u64 *addr, u64 val)
+{
+       store_u32((u32 *)addr, val);
+       store_u32((u32 *)addr + 1, val >> 32);
+}
+#endif
+
+static inline ulong get_insn(ulong mepc)
+{
+       register ulong __mepc asm ("a2") = mepc;
+       ulong val, rvc_mask = 3, tmp;
+
+       asm ("and %[tmp], %[addr], 2\n"
+               "bnez %[tmp], 1f\n"
+#if defined(CONFIG_64BIT)
+               STR(LWU) " %[insn], (%[addr])\n"
+#else
+               STR(LW) " %[insn], (%[addr])\n"
+#endif
+               "and %[tmp], %[insn], %[rvc_mask]\n"
+               "beq %[tmp], %[rvc_mask], 2f\n"
+               "sll %[insn], %[insn], %[xlen_minus_16]\n"
+               "srl %[insn], %[insn], %[xlen_minus_16]\n"
+               "j 2f\n"
+               "1:\n"
+               "lhu %[insn], (%[addr])\n"
+               "and %[tmp], %[insn], %[rvc_mask]\n"
+               "bne %[tmp], %[rvc_mask], 2f\n"
+               "lhu %[tmp], 2(%[addr])\n"
+               "sll %[tmp], %[tmp], 16\n"
+               "add %[insn], %[insn], %[tmp]\n"
+               "2:"
+       : [insn] "=&r" (val), [tmp] "=&r" (tmp)
+       : [addr] "r" (__mepc), [rvc_mask] "r" (rvc_mask),
+         [xlen_minus_16] "i" (XLEN_MINUS_16));
+
+       return val;
+}
+
+union reg_data {
+       u8 data_bytes[8];
+       ulong data_ulong;
+       u64 data_u64;
+};
+
+int handle_misaligned_load(struct pt_regs *regs)
+{
+       union reg_data val;
+       unsigned long epc = regs->epc;
+       unsigned long insn = get_insn(epc);
+       unsigned long addr = csr_read(mtval);
+       int i, fp = 0, shift = 0, len = 0;
+
+       regs->epc = 0;
+
+       if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
+               len = 4;
+               shift = 8 * (sizeof(unsigned long) - len);
+#if defined(CONFIG_64BIT)
+       } else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
+               len = 8;
+               shift = 8 * (sizeof(unsigned long) - len);
+       } else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) {
+               len = 4;
+#endif
+       } else if ((insn & INSN_MASK_FLD) == INSN_MATCH_FLD) {
+               fp = 1;
+               len = 8;
+       } else if ((insn & INSN_MASK_FLW) == INSN_MATCH_FLW) {
+               fp = 1;
+               len = 4;
+       } else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) {
+               len = 2;
+               shift = 8 * (sizeof(unsigned long) - len);
+       } else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) {
+               len = 2;
+#if defined(CONFIG_64BIT)
+       } else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) {
+               len = 8;
+               shift = 8 * (sizeof(unsigned long) - len);
+               insn = RVC_RS2S(insn) << SH_RD;
+       } else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP &&
+                  ((insn >> SH_RD) & 0x1f)) {
+               len = 8;
+               shift = 8 * (sizeof(unsigned long) - len);
+#endif
+       } else if ((insn & INSN_MASK_C_LW) == INSN_MATCH_C_LW) {
+               len = 4;
+               shift = 8 * (sizeof(unsigned long) - len);
+               insn = RVC_RS2S(insn) << SH_RD;
+       } else if ((insn & INSN_MASK_C_LWSP) == INSN_MATCH_C_LWSP &&
+                  ((insn >> SH_RD) & 0x1f)) {
+               len = 4;
+               shift = 8 * (sizeof(unsigned long) - len);
+       } else if ((insn & INSN_MASK_C_FLD) == INSN_MATCH_C_FLD) {
+               fp = 1;
+               len = 8;
+               insn = RVC_RS2S(insn) << SH_RD;
+       } else if ((insn & INSN_MASK_C_FLDSP) == INSN_MATCH_C_FLDSP) {
+               fp = 1;
+               len = 8;
+#if defined(CONFIG_32BIT)
+       } else if ((insn & INSN_MASK_C_FLW) == INSN_MATCH_C_FLW) {
+               fp = 1;
+               len = 4;
+               insn = RVC_RS2S(insn) << SH_RD;
+       } else if ((insn & INSN_MASK_C_FLWSP) == INSN_MATCH_C_FLWSP) {
+               fp = 1;
+               len = 4;
+#endif
+       } else {
+               regs->epc = epc;
+               return -1;
+       }
+
+       val.data_u64 = 0;
+       for (i = 0; i < len; i++)
+               val.data_bytes[i] = load_u8((void *)(addr + i));
+
+       if (fp)
+               return -1;
+       SET_RD(insn, regs, val.data_ulong << shift >> shift);
+
+       regs->epc = epc + INSN_LEN(insn);
+
+       return 0;
+}
+
+int handle_misaligned_store(struct pt_regs *regs)
+{
+       union reg_data val;
+       unsigned long epc = regs->epc;
+       unsigned long insn = get_insn(epc);
+       unsigned long addr = csr_read(mtval);
+       int i, len = 0;
+
+       regs->epc = 0;
+
+       val.data_ulong = GET_RS2(insn, regs);
+
+       if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) {
+               len = 4;
+#if defined(CONFIG_64BIT)
+       } else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) {
+               len = 8;
+#endif
+       } else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
+               len = 2;
+#if defined(CONFIG_64BIT)
+       } else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
+               len = 8;
+               val.data_ulong = GET_RS2S(insn, regs);
+       } else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP &&
+                  ((insn >> SH_RD) & 0x1f)) {
+               len = 8;
+               val.data_ulong = GET_RS2C(insn, regs);
+#endif
+       } else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) {
+               len = 4;
+               val.data_ulong = GET_RS2S(insn, regs);
+       } else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP &&
+                  ((insn >> SH_RD) & 0x1f)) {
+               len = 4;
+               val.data_ulong = GET_RS2C(insn, regs);
+       } else {
+               regs->epc = epc;
+               return -1;
+       }
+
+       for (i = 0; i < len; i++)
+               store_u8((void *)(addr + i), val.data_bytes[i]);
+
+       regs->epc = epc + INSN_LEN(insn);
+
+       return 0;
+}
index 1e0193d..0339b6b 100644 (file)
@@ -9,7 +9,9 @@
 #include <asm/page.h>
 #include <asm/cache.h>
 #include <asm/thread_info.h>
+#include <asm/set_memory.h>
 
+#include <linux/sizes.h>
 OUTPUT_ARCH(riscv)
 ENTRY(_start)
 
@@ -20,10 +22,18 @@ SECTIONS
        /* Beginning of code and text segment */
        . = LOAD_OFFSET;
        _start = .;
-       __init_begin = .;
        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 = .;
+               KEEP(*(__soc_early_init_table))
+               __soc_early_init_table_end = .;
+       }
        /* we have to discard exit text and such at runtime, not link time */
        .exit.text :
        {
@@ -36,6 +46,7 @@ SECTIONS
        PERCPU_SECTION(L1_CACHE_BYTES)
        __init_end = .;
 
+       . = ALIGN(SECTION_ALIGN);
        .text : {
                _text = .;
                _stext = .;
@@ -53,24 +64,26 @@ SECTIONS
 
        /* Start of data section */
        _sdata = .;
-       RO_DATA(L1_CACHE_BYTES)
+       RO_DATA(SECTION_ALIGN)
        .srodata : {
                *(.srodata*)
        }
 
+       EXCEPTION_TABLE(0x10)
+
+       . = ALIGN(SECTION_ALIGN);
+       _data = .;
+
        RW_DATA(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)
        .sdata : {
                __global_pointer$ = . + 0x800;
                *(.sdata*)
                /* End of data section */
                _edata = .;
-               *(.sbss*)
        }
 
        BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 0)
 
-       EXCEPTION_TABLE(0x10)
-
        .rel.dyn : {
                *(.rel.dyn*)
        }
index f29d2ba..fceaeb1 100644 (file)
@@ -3,14 +3,12 @@
 #include <asm/asm.h>
 #include <asm/csr.h>
 
-       .altmacro
        .macro fixup op reg addr lbl
-       LOCAL _epc
-_epc:
+100:
        \op \reg, \addr
        .section __ex_table,"a"
        .balign RISCV_SZPTR
-       RISCV_PTR _epc, \lbl
+       RISCV_PTR 100b, \lbl
        .previous
        .endm
 
index 50b7af5..363ef01 100644 (file)
@@ -7,7 +7,7 @@ endif
 
 obj-y += init.o
 obj-y += extable.o
-obj-$(CONFIG_MMU) += fault.o
+obj-$(CONFIG_MMU) += fault.o pageattr.o
 obj-y += cacheflush.o
 obj-y += context.o
 
@@ -15,6 +15,7 @@ ifeq ($(CONFIG_MMU),y)
 obj-$(CONFIG_SMP) += tlbflush.o
 endif
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
+obj-$(CONFIG_PTDUMP_CORE) += ptdump.o
 obj-$(CONFIG_KASAN)   += kasan_init.o
 
 ifdef CONFIG_KASAN
index 0d4747e..a6189ed 100644 (file)
@@ -4,14 +4,12 @@
 
 int pud_huge(pud_t pud)
 {
-       return pud_present(pud) &&
-               (pud_val(pud) & (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC));
+       return pud_leaf(pud);
 }
 
 int pmd_huge(pmd_t pmd)
 {
-       return pmd_present(pmd) &&
-               (pmd_val(pmd) & (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC));
+       return pmd_leaf(pmd);
 }
 
 static __init int setup_hugepagesz(char *opt)
index fab8559..b55be44 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/sizes.h>
 #include <linux/of_fdt.h>
 #include <linux/libfdt.h>
+#include <linux/set_memory.h>
 
 #include <asm/fixmap.h>
 #include <asm/tlbflush.h>
@@ -477,6 +478,17 @@ static void __init setup_vm_final(void)
        csr_write(CSR_SATP, PFN_DOWN(__pa_symbol(swapper_pg_dir)) | SATP_MODE);
        local_flush_tlb_all();
 }
+
+void free_initmem(void)
+{
+       unsigned long init_begin = (unsigned long)__init_begin;
+       unsigned long init_end = (unsigned long)__init_end;
+
+       /* Make the region as non-execuatble. */
+       set_memory_nx(init_begin, (init_end - init_begin) >> PAGE_SHIFT);
+       free_initmem_default(POISON_FREE_INITMEM);
+}
+
 #else
 asmlinkage void __init setup_vm(uintptr_t dtb_pa)
 {
@@ -488,6 +500,38 @@ static inline void setup_vm_final(void)
 }
 #endif /* CONFIG_MMU */
 
+#ifdef CONFIG_STRICT_KERNEL_RWX
+void set_kernel_text_rw(void)
+{
+       unsigned long text_start = (unsigned long)_text;
+       unsigned long text_end = (unsigned long)_etext;
+
+       set_memory_rw(text_start, (text_end - text_start) >> PAGE_SHIFT);
+}
+
+void set_kernel_text_ro(void)
+{
+       unsigned long text_start = (unsigned long)_text;
+       unsigned long text_end = (unsigned long)_etext;
+
+       set_memory_ro(text_start, (text_end - text_start) >> PAGE_SHIFT);
+}
+
+void mark_rodata_ro(void)
+{
+       unsigned long text_start = (unsigned long)_text;
+       unsigned long text_end = (unsigned long)_etext;
+       unsigned long rodata_start = (unsigned long)__start_rodata;
+       unsigned long data_start = (unsigned long)_data;
+       unsigned long max_low = (unsigned long)(__va(PFN_PHYS(max_low_pfn)));
+
+       set_memory_ro(text_start, (text_end - text_start) >> PAGE_SHIFT);
+       set_memory_ro(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
+       set_memory_nx(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
+       set_memory_nx(data_start, (max_low - data_start) >> PAGE_SHIFT);
+}
+#endif
+
 void __init paging_init(void)
 {
        setup_vm_final();
diff --git a/arch/riscv/mm/pageattr.c b/arch/riscv/mm/pageattr.c
new file mode 100644 (file)
index 0000000..728759e
--- /dev/null
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2019 SiFive
+ */
+
+#include <linux/pagewalk.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/bitops.h>
+
+struct pageattr_masks {
+       pgprot_t set_mask;
+       pgprot_t clear_mask;
+};
+
+static unsigned long set_pageattr_masks(unsigned long val, struct mm_walk *walk)
+{
+       struct pageattr_masks *masks = walk->private;
+       unsigned long new_val = val;
+
+       new_val &= ~(pgprot_val(masks->clear_mask));
+       new_val |= (pgprot_val(masks->set_mask));
+
+       return new_val;
+}
+
+static int pageattr_pgd_entry(pgd_t *pgd, unsigned long addr,
+                             unsigned long next, struct mm_walk *walk)
+{
+       pgd_t val = READ_ONCE(*pgd);
+
+       if (pgd_leaf(val)) {
+               val = __pgd(set_pageattr_masks(pgd_val(val), walk));
+               set_pgd(pgd, val);
+       }
+
+       return 0;
+}
+
+static int pageattr_p4d_entry(p4d_t *p4d, unsigned long addr,
+                             unsigned long next, struct mm_walk *walk)
+{
+       p4d_t val = READ_ONCE(*p4d);
+
+       if (p4d_leaf(val)) {
+               val = __p4d(set_pageattr_masks(p4d_val(val), walk));
+               set_p4d(p4d, val);
+       }
+
+       return 0;
+}
+
+static int pageattr_pud_entry(pud_t *pud, unsigned long addr,
+                             unsigned long next, struct mm_walk *walk)
+{
+       pud_t val = READ_ONCE(*pud);
+
+       if (pud_leaf(val)) {
+               val = __pud(set_pageattr_masks(pud_val(val), walk));
+               set_pud(pud, val);
+       }
+
+       return 0;
+}
+
+static int pageattr_pmd_entry(pmd_t *pmd, unsigned long addr,
+                             unsigned long next, struct mm_walk *walk)
+{
+       pmd_t val = READ_ONCE(*pmd);
+
+       if (pmd_leaf(val)) {
+               val = __pmd(set_pageattr_masks(pmd_val(val), walk));
+               set_pmd(pmd, val);
+       }
+
+       return 0;
+}
+
+static int pageattr_pte_entry(pte_t *pte, unsigned long addr,
+                             unsigned long next, struct mm_walk *walk)
+{
+       pte_t val = READ_ONCE(*pte);
+
+       val = __pte(set_pageattr_masks(pte_val(val), walk));
+       set_pte(pte, val);
+
+       return 0;
+}
+
+static int pageattr_pte_hole(unsigned long addr, unsigned long next,
+                            int depth, struct mm_walk *walk)
+{
+       /* Nothing to do here */
+       return 0;
+}
+
+const static struct mm_walk_ops pageattr_ops = {
+       .pgd_entry = pageattr_pgd_entry,
+       .p4d_entry = pageattr_p4d_entry,
+       .pud_entry = pageattr_pud_entry,
+       .pmd_entry = pageattr_pmd_entry,
+       .pte_entry = pageattr_pte_entry,
+       .pte_hole = pageattr_pte_hole,
+};
+
+static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask,
+                       pgprot_t clear_mask)
+{
+       int ret;
+       unsigned long start = addr;
+       unsigned long end = start + PAGE_SIZE * numpages;
+       struct pageattr_masks masks = {
+               .set_mask = set_mask,
+               .clear_mask = clear_mask
+       };
+
+       if (!numpages)
+               return 0;
+
+       down_read(&init_mm.mmap_sem);
+       ret =  walk_page_range_novma(&init_mm, start, end, &pageattr_ops, NULL,
+                                    &masks);
+       up_read(&init_mm.mmap_sem);
+
+       flush_tlb_kernel_range(start, end);
+
+       return ret;
+}
+
+int set_memory_ro(unsigned long addr, int numpages)
+{
+       return __set_memory(addr, numpages, __pgprot(_PAGE_READ),
+                           __pgprot(_PAGE_WRITE));
+}
+
+int set_memory_rw(unsigned long addr, int numpages)
+{
+       return __set_memory(addr, numpages, __pgprot(_PAGE_READ | _PAGE_WRITE),
+                           __pgprot(0));
+}
+
+int set_memory_x(unsigned long addr, int numpages)
+{
+       return __set_memory(addr, numpages, __pgprot(_PAGE_EXEC), __pgprot(0));
+}
+
+int set_memory_nx(unsigned long addr, int numpages)
+{
+       return __set_memory(addr, numpages, __pgprot(0), __pgprot(_PAGE_EXEC));
+}
+
+int set_direct_map_invalid_noflush(struct page *page)
+{
+       unsigned long start = (unsigned long)page_address(page);
+       unsigned long end = start + PAGE_SIZE;
+       struct pageattr_masks masks = {
+               .set_mask = __pgprot(0),
+               .clear_mask = __pgprot(_PAGE_PRESENT)
+       };
+
+       return walk_page_range(&init_mm, start, end, &pageattr_ops, &masks);
+}
+
+int set_direct_map_default_noflush(struct page *page)
+{
+       unsigned long start = (unsigned long)page_address(page);
+       unsigned long end = start + PAGE_SIZE;
+       struct pageattr_masks masks = {
+               .set_mask = PAGE_KERNEL,
+               .clear_mask = __pgprot(0)
+       };
+
+       return walk_page_range(&init_mm, start, end, &pageattr_ops, &masks);
+}
+
+void __kernel_map_pages(struct page *page, int numpages, int enable)
+{
+       if (!debug_pagealloc_enabled())
+               return;
+
+       if (enable)
+               __set_memory((unsigned long)page_address(page), numpages,
+                            __pgprot(_PAGE_PRESENT), __pgprot(0));
+       else
+               __set_memory((unsigned long)page_address(page), numpages,
+                            __pgprot(0), __pgprot(_PAGE_PRESENT));
+}
diff --git a/arch/riscv/mm/ptdump.c b/arch/riscv/mm/ptdump.c
new file mode 100644 (file)
index 0000000..7eab76a
--- /dev/null
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2019 SiFive
+ */
+
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/ptdump.h>
+
+#include <asm/ptdump.h>
+#include <asm/pgtable.h>
+#include <asm/kasan.h>
+
+#define pt_dump_seq_printf(m, fmt, args...)    \
+({                                             \
+       if (m)                                  \
+               seq_printf(m, fmt, ##args);     \
+})
+
+#define pt_dump_seq_puts(m, fmt)       \
+({                                     \
+       if (m)                          \
+               seq_printf(m, fmt);     \
+})
+
+/*
+ * The page dumper groups page table entries of the same type into a single
+ * description. It uses pg_state to track the range information while
+ * iterating over the pte entries. When the continuity is broken it then
+ * dumps out a description of the range.
+ */
+struct pg_state {
+       struct ptdump_state ptdump;
+       struct seq_file *seq;
+       const struct addr_marker *marker;
+       unsigned long start_address;
+       unsigned long start_pa;
+       unsigned long last_pa;
+       int level;
+       u64 current_prot;
+       bool check_wx;
+       unsigned long wx_pages;
+};
+
+/* Address marker */
+struct addr_marker {
+       unsigned long start_address;
+       const char *name;
+};
+
+static struct addr_marker address_markers[] = {
+#ifdef CONFIG_KASAN
+       {KASAN_SHADOW_START,    "Kasan shadow start"},
+       {KASAN_SHADOW_END,      "Kasan shadow end"},
+#endif
+       {FIXADDR_START,         "Fixmap start"},
+       {FIXADDR_TOP,           "Fixmap end"},
+       {PCI_IO_START,          "PCI I/O start"},
+       {PCI_IO_END,            "PCI I/O end"},
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+       {VMEMMAP_START,         "vmemmap start"},
+       {VMEMMAP_END,           "vmemmap end"},
+#endif
+       {VMALLOC_START,         "vmalloc() area"},
+       {VMALLOC_END,           "vmalloc() end"},
+       {PAGE_OFFSET,           "Linear mapping"},
+       {-1, NULL},
+};
+
+/* Page Table Entry */
+struct prot_bits {
+       u64 mask;
+       u64 val;
+       const char *set;
+       const char *clear;
+};
+
+static const struct prot_bits pte_bits[] = {
+       {
+               .mask = _PAGE_SOFT,
+               .val = _PAGE_SOFT,
+               .set = "RSW",
+               .clear = "   ",
+       }, {
+               .mask = _PAGE_DIRTY,
+               .val = _PAGE_DIRTY,
+               .set = "D",
+               .clear = ".",
+       }, {
+               .mask = _PAGE_ACCESSED,
+               .val = _PAGE_ACCESSED,
+               .set = "A",
+               .clear = ".",
+       }, {
+               .mask = _PAGE_GLOBAL,
+               .val = _PAGE_GLOBAL,
+               .set = "G",
+               .clear = ".",
+       }, {
+               .mask = _PAGE_USER,
+               .val = _PAGE_USER,
+               .set = "U",
+               .clear = ".",
+       }, {
+               .mask = _PAGE_EXEC,
+               .val = _PAGE_EXEC,
+               .set = "X",
+               .clear = ".",
+       }, {
+               .mask = _PAGE_WRITE,
+               .val = _PAGE_WRITE,
+               .set = "W",
+               .clear = ".",
+       }, {
+               .mask = _PAGE_READ,
+               .val = _PAGE_READ,
+               .set = "R",
+               .clear = ".",
+       }, {
+               .mask = _PAGE_PRESENT,
+               .val = _PAGE_PRESENT,
+               .set = "V",
+               .clear = ".",
+       }
+};
+
+/* Page Level */
+struct pg_level {
+       const char *name;
+       u64 mask;
+};
+
+static struct pg_level pg_level[] = {
+       { /* pgd */
+               .name = "PGD",
+       }, { /* p4d */
+               .name = (CONFIG_PGTABLE_LEVELS > 4) ? "P4D" : "PGD",
+       }, { /* pud */
+               .name = (CONFIG_PGTABLE_LEVELS > 3) ? "PUD" : "PGD",
+       }, { /* pmd */
+               .name = (CONFIG_PGTABLE_LEVELS > 2) ? "PMD" : "PGD",
+       }, { /* pte */
+               .name = "PTE",
+       },
+};
+
+static void dump_prot(struct pg_state *st)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(pte_bits); i++) {
+               const char *s;
+
+               if ((st->current_prot & pte_bits[i].mask) == pte_bits[i].val)
+                       s = pte_bits[i].set;
+               else
+                       s = pte_bits[i].clear;
+
+               if (s)
+                       pt_dump_seq_printf(st->seq, " %s", s);
+       }
+}
+
+#ifdef CONFIG_64BIT
+#define ADDR_FORMAT    "0x%016lx"
+#else
+#define ADDR_FORMAT    "0x%08lx"
+#endif
+static void dump_addr(struct pg_state *st, unsigned long addr)
+{
+       static const char units[] = "KMGTPE";
+       const char *unit = units;
+       unsigned long delta;
+
+       pt_dump_seq_printf(st->seq, ADDR_FORMAT "-" ADDR_FORMAT "   ",
+                          st->start_address, addr);
+
+       pt_dump_seq_printf(st->seq, " " ADDR_FORMAT " ", st->start_pa);
+       delta = (addr - st->start_address) >> 10;
+
+       while (!(delta & 1023) && unit[1]) {
+               delta >>= 10;
+               unit++;
+       }
+
+       pt_dump_seq_printf(st->seq, "%9lu%c %s", delta, *unit,
+                          pg_level[st->level].name);
+}
+
+static void note_prot_wx(struct pg_state *st, unsigned long addr)
+{
+       if (!st->check_wx)
+               return;
+
+       if ((st->current_prot & (_PAGE_WRITE | _PAGE_EXEC)) !=
+           (_PAGE_WRITE | _PAGE_EXEC))
+               return;
+
+       WARN_ONCE(1, "riscv/mm: Found insecure W+X mapping at address %p/%pS\n",
+                 (void *)st->start_address, (void *)st->start_address);
+
+       st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
+}
+
+static void note_page(struct ptdump_state *pt_st, unsigned long addr,
+                     int level, unsigned long val)
+{
+       struct pg_state *st = container_of(pt_st, struct pg_state, ptdump);
+       u64 pa = PFN_PHYS(pte_pfn(__pte(val)));
+       u64 prot = 0;
+
+       if (level >= 0)
+               prot = val & pg_level[level].mask;
+
+       if (st->level == -1) {
+               st->level = level;
+               st->current_prot = prot;
+               st->start_address = addr;
+               st->start_pa = pa;
+               st->last_pa = pa;
+               pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
+       } else if (prot != st->current_prot ||
+                  level != st->level || addr >= st->marker[1].start_address) {
+               if (st->current_prot) {
+                       note_prot_wx(st, addr);
+                       dump_addr(st, addr);
+                       dump_prot(st);
+                       pt_dump_seq_puts(st->seq, "\n");
+               }
+
+               while (addr >= st->marker[1].start_address) {
+                       st->marker++;
+                       pt_dump_seq_printf(st->seq, "---[ %s ]---\n",
+                                          st->marker->name);
+               }
+
+               st->start_address = addr;
+               st->start_pa = pa;
+               st->last_pa = pa;
+               st->current_prot = prot;
+               st->level = level;
+       } else {
+               st->last_pa = pa;
+       }
+}
+
+static void ptdump_walk(struct seq_file *s)
+{
+       struct pg_state st = {
+               .seq = s,
+               .marker = address_markers,
+               .level = -1,
+               .ptdump = {
+                       .note_page = note_page,
+                       .range = (struct ptdump_range[]) {
+                               {KERN_VIRT_START, ULONG_MAX},
+                               {0, 0}
+                       }
+               }
+       };
+
+       ptdump_walk_pgd(&st.ptdump, &init_mm, NULL);
+}
+
+void ptdump_check_wx(void)
+{
+       struct pg_state st = {
+               .seq = NULL,
+               .marker = (struct addr_marker[]) {
+                       {0, NULL},
+                       {-1, NULL},
+               },
+               .level = -1,
+               .check_wx = true,
+               .ptdump = {
+                       .note_page = note_page,
+                       .range = (struct ptdump_range[]) {
+                               {KERN_VIRT_START, ULONG_MAX},
+                               {0, 0}
+                       }
+               }
+       };
+
+       ptdump_walk_pgd(&st.ptdump, &init_mm, NULL);
+
+       if (st.wx_pages)
+               pr_warn("Checked W+X mappings: failed, %lu W+X pages found\n",
+                       st.wx_pages);
+       else
+               pr_info("Checked W+X mappings: passed, no W+X pages found\n");
+}
+
+static int ptdump_show(struct seq_file *m, void *v)
+{
+       ptdump_walk(m);
+
+       return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(ptdump);
+
+static int ptdump_init(void)
+{
+       unsigned int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(pg_level); i++)
+               for (j = 0; j < ARRAY_SIZE(pte_bits); j++)
+                       pg_level[i].mask |= pte_bits[j].mask;
+
+       debugfs_create_file("kernel_page_tables", 0400, NULL, NULL,
+                           &ptdump_fops);
+
+       return 0;
+}
+
+device_initcall(ptdump_init);
index f2d4c1b..cc98f9b 100644 (file)
@@ -181,8 +181,7 @@ int arch_make_page_accessible(struct page *page);
 
 #define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr))
 
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_NON_EXEC
 
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
index e577f85..86a3796 100644 (file)
@@ -325,7 +325,6 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int,
 
 /**
  * struct qdio_initialize - qdio initialization data
- * @cdev: associated ccw device
  * @q_format: queue format
  * @qdr_ac: feature flags to set
  * @adapter_name: name for the adapter
@@ -341,12 +340,11 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int,
  * @irq_poll: Data IRQ polling handler (NULL when not supported)
  * @scan_threshold: # of in-use buffers that triggers scan on output queue
  * @int_parm: interruption parameter
- * @input_sbal_addr_array:  address of no_input_qs * 128 pointers
- * @output_sbal_addr_array: address of no_output_qs * 128 pointers
+ * @input_sbal_addr_array:  per-queue array, each element points to 128 SBALs
+ * @output_sbal_addr_array: per-queue array, each element points to 128 SBALs
  * @output_sbal_state_array: no_output_qs * 128 state info (for CQ or NULL)
  */
 struct qdio_initialize {
-       struct ccw_device *cdev;
        unsigned char q_format;
        unsigned char qdr_ac;
        unsigned char adapter_name[8];
@@ -362,8 +360,8 @@ struct qdio_initialize {
        void (*irq_poll)(struct ccw_device *cdev, unsigned long data);
        unsigned int scan_threshold;
        unsigned long int_parm;
-       struct qdio_buffer **input_sbal_addr_array;
-       struct qdio_buffer **output_sbal_addr_array;
+       struct qdio_buffer ***input_sbal_addr_array;
+       struct qdio_buffer ***output_sbal_addr_array;
        struct qdio_outbuf_state *output_sbal_state_array;
 };
 
@@ -408,8 +406,10 @@ int qdio_alloc_buffers(struct qdio_buffer **buf, unsigned int count);
 void qdio_free_buffers(struct qdio_buffer **buf, unsigned int count);
 void qdio_reset_buffers(struct qdio_buffer **buf, unsigned int count);
 
-extern int qdio_allocate(struct qdio_initialize *);
-extern int qdio_establish(struct qdio_initialize *);
+extern int qdio_allocate(struct ccw_device *cdev, unsigned int no_input_qs,
+                        unsigned int no_output_qs);
+extern int qdio_establish(struct ccw_device *cdev,
+                         struct qdio_initialize *init_data);
 extern int qdio_activate(struct ccw_device *);
 extern void qdio_release_aob(struct qaob *);
 extern int do_QDIO(struct ccw_device *, unsigned int, int, unsigned int,
index d3db3d7..def3b60 100644 (file)
@@ -55,8 +55,4 @@ config KVM_S390_UCONTROL
 
          If unsure, say N.
 
-# OK, it's a little counter-intuitive to do this, but it puts it neatly under
-# the virtualization menu.
-source "drivers/vhost/Kconfig"
-
 endif # VIRTUALIZATION
index 076090f..4f6c22d 100644 (file)
@@ -1202,6 +1202,7 @@ static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
                scb_s->iprcc = PGM_ADDRESSING;
                scb_s->pgmilc = 4;
                scb_s->gpsw.addr = __rewind_psw(scb_s->gpsw, 4);
+               rc = 1;
        }
        return rc;
 }
index d56f677..dedc28b 100644 (file)
@@ -580,7 +580,7 @@ void do_dat_exception(struct pt_regs *regs)
        int access;
        vm_fault_t fault;
 
-       access = VM_READ | VM_EXEC | VM_WRITE;
+       access = VM_ACCESS_FLAGS;
        fault = do_exception(regs, access);
        if (unlikely(fault))
                do_fault_error(regs, access, fault);
@@ -852,9 +852,7 @@ void do_secure_storage_access(struct pt_regs *regs)
                        BUG();
                break;
        case VDSO_FAULT:
-               /* fallthrough */
        case GMAP_FAULT:
-               /* fallthrough */
        default:
                do_fault_error(regs, VM_READ | VM_WRITE, VM_FAULT_BADMAP);
                WARN_ON_ONCE(1);
index 2fbece4..1a95d88 100644 (file)
@@ -787,14 +787,18 @@ static void gmap_call_notifier(struct gmap *gmap, unsigned long start,
 static inline unsigned long *gmap_table_walk(struct gmap *gmap,
                                             unsigned long gaddr, int level)
 {
+       const int asce_type = gmap->asce & _ASCE_TYPE_MASK;
        unsigned long *table;
 
        if ((gmap->asce & _ASCE_TYPE_MASK) + 4 < (level * 4))
                return NULL;
        if (gmap_is_shadow(gmap) && gmap->removed)
                return NULL;
-       if (gaddr & (-1UL << (31 + ((gmap->asce & _ASCE_TYPE_MASK) >> 2)*11)))
+
+       if (asce_type != _ASCE_TYPE_REGION1 &&
+           gaddr & (-1UL << (31 + (asce_type >> 2) * 11)))
                return NULL;
+
        table = gmap->table;
        switch (gmap->asce & _ASCE_TYPE_MASK) {
        case _ASCE_TYPE_REGION1:
@@ -1840,6 +1844,7 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,
                goto out_free;
        } else if (*table & _REGION_ENTRY_ORIGIN) {
                rc = -EAGAIN;           /* Race with shadow */
+               goto out_free;
        }
        crst_table_init(s_r3t, _REGION3_ENTRY_EMPTY);
        /* mark as invalid as long as the parent table is not protected */
index ac44bd7..87b2d02 100644 (file)
@@ -268,20 +268,23 @@ device_initcall(s390_cma_mem_init);
 #endif /* CONFIG_CMA */
 
 int arch_add_memory(int nid, u64 start, u64 size,
-               struct mhp_restrictions *restrictions)
+                   struct mhp_params *params)
 {
        unsigned long start_pfn = PFN_DOWN(start);
        unsigned long size_pages = PFN_DOWN(size);
        int rc;
 
-       if (WARN_ON_ONCE(restrictions->altmap))
+       if (WARN_ON_ONCE(params->altmap))
+               return -EINVAL;
+
+       if (WARN_ON_ONCE(params->pgprot.pgprot != PAGE_KERNEL.pgprot))
                return -EINVAL;
 
        rc = vmem_add_mapping(start, size);
        if (rc)
                return rc;
 
-       rc = __add_pages(nid, start_pfn, size_pages, restrictions);
+       rc = __add_pages(nid, start_pfn, size_pages, params);
        if (rc)
                vmem_remove_mapping(start, size);
        return rc;
index 4668803..cfe5465 100644 (file)
 #define BYTE_OFFSET(nr)                ((nr) % BITS_PER_BYTE)
 #endif
 
-#define IS_IMMEDIATE(nr)       (__builtin_constant_p(nr))
-
 static inline void __set_bit(int nr, volatile unsigned long *addr)
 {
-       if (IS_IMMEDIATE(nr)) {
+       if (__builtin_constant_p(nr)) {
                __asm__ __volatile__ (
                        "bset.b %1, @(%O2,%0)           ! __set_bit\n\t"
                        : "+r" (addr)
@@ -37,7 +35,7 @@ static inline void __set_bit(int nr, volatile unsigned long *addr)
 
 static inline void __clear_bit(int nr, volatile unsigned long *addr)
 {
-       if (IS_IMMEDIATE(nr)) {
+       if (__builtin_constant_p(nr)) {
                __asm__ __volatile__ (
                        "bclr.b %1, @(%O2,%0)           ! __clear_bit\n\t"
                        : "+r" (addr)
@@ -64,7 +62,7 @@ static inline void __clear_bit(int nr, volatile unsigned long *addr)
  */
 static inline void __change_bit(int nr, volatile unsigned long *addr)
 {
-       if (IS_IMMEDIATE(nr)) {
+       if (__builtin_constant_p(nr)) {
                __asm__ __volatile__ (
                        "bxor.b %1, @(%O2,%0)           ! __change_bit\n\t"
                        : "+r" (addr)
index 5eef8be..ea8d68f 100644 (file)
@@ -182,9 +182,6 @@ typedef struct page *pgtable_t;
 #endif
 #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
 
diff --git a/arch/sh/include/uapi/asm/setup.h b/arch/sh/include/uapi/asm/setup.h
deleted file mode 100644 (file)
index 4bd19f8..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#include <asm-generic/setup.h>
diff --git a/arch/sh/include/uapi/asm/types.h b/arch/sh/include/uapi/asm/types.h
deleted file mode 100644 (file)
index 68100e1..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#include <asm-generic/types.h>
index d1b1ff2..b9de2d4 100644 (file)
@@ -406,14 +406,17 @@ void __init mem_init(void)
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 int arch_add_memory(int nid, u64 start, u64 size,
-                       struct mhp_restrictions *restrictions)
+                   struct mhp_params *params)
 {
        unsigned long start_pfn = PFN_DOWN(start);
        unsigned long nr_pages = size >> PAGE_SHIFT;
        int ret;
 
+       if (WARN_ON_ONCE(params->pgprot.pgprot != PAGE_KERNEL.pgprot)
+               return -EINVAL;
+
        /* We only have ZONE_NORMAL, so this is easy.. */
-       ret = __add_pages(nid, start_pfn, nr_pages, restrictions);
+       ret = __add_pages(nid, start_pfn, nr_pages, params);
        if (unlikely(ret))
                printk("%s: Failed, __add_pages() == %d\n", __func__, ret);
 
index b76d59e..4782600 100644 (file)
@@ -133,9 +133,6 @@ extern unsigned long pfn_base;
 #define pfn_valid(pfn)         (((pfn) >= (pfn_base)) && (((pfn)-(pfn_base)) < max_mapnr))
 #define virt_addr_valid(kaddr) ((((unsigned long)(kaddr)-PAGE_OFFSET)>>PAGE_SHIFT) < max_mapnr)
 
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
 #include <asm-generic/memory_model.h>
 #include <asm-generic/getorder.h>
 
index e80f2d5..254dffd 100644 (file)
@@ -158,9 +158,6 @@ extern unsigned long PAGE_OFFSET;
 
 #endif /* !(__ASSEMBLY__) */
 
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
 #include <asm-generic/getorder.h>
 
 #endif /* _SPARC64_PAGE_H */
index 6d6f44c..0de659a 100644 (file)
@@ -223,11 +223,6 @@ static inline int pte_young(pte_t pte)
        return pte_val(pte) & SRMMU_REF;
 }
 
-static inline int pte_special(pte_t pte)
-{
-       return 0;
-}
-
 static inline pte_t pte_wrprotect(pte_t pte)
 {
        return __pte(pte_val(pte) & ~SRMMU_WRITE);
@@ -258,8 +253,6 @@ static inline pte_t pte_mkyoung(pte_t pte)
        return __pte(pte_val(pte) | SRMMU_REF);
 }
 
-#define pte_mkspecial(pte)    (pte)
-
 #define pfn_pte(pfn, prot)             mk_pte(pfn_to_page(pfn), prot)
 
 static inline unsigned long pte_pfn(pte_t pte)
index 65494c3..da527b2 100644 (file)
@@ -907,11 +907,11 @@ static inline unsigned long pud_pfn(pud_t pud)
         (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)))
 
 /* Find an entry in the third-level page table.. */
-#define pte_index(dir, address)        \
-       ((pte_t *) __pmd_page(*(dir)) + \
-        ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
-#define pte_offset_kernel              pte_index
-#define pte_offset_map                 pte_index
+#define pte_index(address)                     \
+        ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset_kernel(dir, address)        \
+       ((pte_t *) __pmd_page(*(dir)) + pte_index(address))
+#define pte_offset_map(dir, address)   pte_offset_kernel((dir), (address))
 #define pte_unmap(pte)                 do { } while (0)
 
 /* We cannot include <linux/mm_types.h> at this point yet: */
index 2daa58d..b5ddf5d 100644 (file)
@@ -167,11 +167,6 @@ static inline int pte_newprot(pte_t pte)
        return(pte_present(pte) && (pte_get_bits(pte, _PAGE_NEWPROT)));
 }
 
-static inline int pte_special(pte_t pte)
-{
-       return 0;
-}
-
 /*
  * =================================
  * Flags setting section.
@@ -247,11 +242,6 @@ static inline pte_t pte_mknewpage(pte_t pte)
        return(pte);
 }
 
-static inline pte_t pte_mkspecial(pte_t pte)
-{
-       return(pte);
-}
-
 static inline void set_pte(pte_t *pteptr, pte_t pteval)
 {
        pte_copy(*pteptr, pteval);
index 8a89335..96d6bdf 100644 (file)
@@ -69,9 +69,6 @@ extern int pfn_valid(unsigned long);
 
 #endif /* !__ASSEMBLY__ */
 
-#define VM_DATA_DEFAULT_FLAGS \
-       (VM_READ | VM_WRITE | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
 #include <asm-generic/getorder.h>
 
 #endif
index c8f7ba1..3b8731b 100644 (file)
@@ -177,7 +177,6 @@ extern struct page *empty_zero_page;
 #define pte_dirty(pte)         (pte_val(pte) & PTE_DIRTY)
 #define pte_young(pte)         (pte_val(pte) & PTE_YOUNG)
 #define pte_exec(pte)          (pte_val(pte) & PTE_EXEC)
-#define pte_special(pte)       (0)
 
 #define PTE_BIT_FUNC(fn, op) \
 static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
@@ -189,8 +188,6 @@ PTE_BIT_FUNC(mkdirty,   |= PTE_DIRTY);
 PTE_BIT_FUNC(mkold,     &= ~PTE_YOUNG);
 PTE_BIT_FUNC(mkyoung,   |= PTE_YOUNG);
 
-static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
-
 /*
  * Mark the prot value as uncacheable.
  */
index a3bf2ff..e251f50 100644 (file)
@@ -55,7 +55,6 @@ static struct pwm_lookup nb0916_pwm_lookup[] = {
 static struct platform_pwm_backlight_data nb0916_backlight_data = {
        .max_brightness = 100,
        .dft_brightness = 100,
-       .enable_gpio    = -1,
 };
 
 static struct gpio_keys_button nb0916_gpio_keys[] = {
index a9bd08f..3022104 100644 (file)
@@ -149,7 +149,7 @@ void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
  */
 static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma)
 {
-       unsigned int mask = VM_READ | VM_WRITE | VM_EXEC;
+       unsigned int mask = VM_ACCESS_FLAGS;
 
        if (!(fsr ^ 0x12))      /* write? */
                mask = VM_WRITE;
index 8d07864..1d6104e 100644 (file)
@@ -1661,6 +1661,7 @@ config X86_PMEM_LEGACY
        depends on PHYS_ADDR_T_64BIT
        depends on BLK_DEV
        select X86_PMEM_LEGACY_DEVICE
+       select NUMA_KEEP_MEMINFO if NUMA
        select LIBNVDIMM
        help
          Treat memory marked using the non-standard e820 type of 12 as used
@@ -2931,3 +2932,5 @@ config HAVE_ATOMIC_IOMAP
 source "drivers/firmware/Kconfig"
 
 source "arch/x86/kvm/Kconfig"
+
+source "arch/x86/Kconfig.assembler"
diff --git a/arch/x86/Kconfig.assembler b/arch/x86/Kconfig.assembler
new file mode 100644 (file)
index 0000000..13de0db
--- /dev/null
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+
+config AS_AVX512
+       def_bool $(as-instr,vpmovm2b %k1$(comma)%zmm5)
+       help
+         Supported by binutils >= 2.25 and LLVM integrated assembler
+
+config AS_SHA1_NI
+       def_bool $(as-instr,sha1msg1 %xmm0$(comma)%xmm1)
+       help
+         Supported by binutils >= 2.24 and LLVM integrated assembler
+
+config AS_SHA256_NI
+       def_bool $(as-instr,sha256msg1 %xmm0$(comma)%xmm1)
+       help
+         Supported by binutils >= 2.24 and LLVM integrated assembler
index 513a555..b65ec63 100644 (file)
@@ -177,28 +177,6 @@ ifeq ($(ACCUMULATE_OUTGOING_ARGS), 1)
        KBUILD_CFLAGS += $(call cc-option,-maccumulate-outgoing-args,)
 endif
 
-# Stackpointer is addressed different for 32 bit and 64 bit x86
-sp-$(CONFIG_X86_32) := esp
-sp-$(CONFIG_X86_64) := rsp
-
-# do binutils support CFI?
-cfi := $(call as-instr,.cfi_startproc\n.cfi_rel_offset $(sp-y)$(comma)0\n.cfi_endproc,-DCONFIG_AS_CFI=1)
-# is .cfi_signal_frame supported too?
-cfi-sigframe := $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONFIG_AS_CFI_SIGNAL_FRAME=1)
-cfi-sections := $(call as-instr,.cfi_sections .debug_frame,-DCONFIG_AS_CFI_SECTIONS=1)
-
-# does binutils support specific instructions?
-asinstr += $(call as-instr,pshufb %xmm0$(comma)%xmm0,-DCONFIG_AS_SSSE3=1)
-avx_instr := $(call as-instr,vxorps %ymm0$(comma)%ymm1$(comma)%ymm2,-DCONFIG_AS_AVX=1)
-avx2_instr :=$(call as-instr,vpbroadcastb %xmm0$(comma)%ymm1,-DCONFIG_AS_AVX2=1)
-avx512_instr :=$(call as-instr,vpmovm2b %k1$(comma)%zmm5,-DCONFIG_AS_AVX512=1)
-sha1_ni_instr :=$(call as-instr,sha1msg1 %xmm0$(comma)%xmm1,-DCONFIG_AS_SHA1_NI=1)
-sha256_ni_instr :=$(call as-instr,sha256msg1 %xmm0$(comma)%xmm1,-DCONFIG_AS_SHA256_NI=1)
-adx_instr := $(call as-instr,adox %r10$(comma)%r10,-DCONFIG_AS_ADX=1)
-
-KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr) $(adx_instr)
-KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr) $(adx_instr)
-
 KBUILD_LDFLAGS := -m elf_$(UTS_MACHINE)
 
 #
index 8c2e9ea..a31de0c 100644 (file)
 # SPDX-License-Identifier: GPL-2.0
 #
-# Arch-specific CryptoAPI modules.
-#
+# x86 crypto algorithms
 
 OBJECT_FILES_NON_STANDARD := y
 
-avx_supported := $(call as-instr,vpxor %xmm0$(comma)%xmm0$(comma)%xmm0,yes,no)
-avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\
-                               $(comma)4)$(comma)%ymm2,yes,no)
-avx512_supported :=$(call as-instr,vpmovm2b %k1$(comma)%zmm5,yes,no)
-sha1_ni_supported :=$(call as-instr,sha1msg1 %xmm0$(comma)%xmm1,yes,no)
-sha256_ni_supported :=$(call as-instr,sha256msg1 %xmm0$(comma)%xmm1,yes,no)
-adx_supported := $(call as-instr,adox %r10$(comma)%r10,yes,no)
-
 obj-$(CONFIG_CRYPTO_GLUE_HELPER_X86) += glue_helper.o
 
 obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o
+twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o
+obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
+twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o
+obj-$(CONFIG_CRYPTO_TWOFISH_X86_64_3WAY) += twofish-x86_64-3way.o
+twofish-x86_64-3way-y := twofish-x86_64-asm_64-3way.o twofish_glue_3way.o
+obj-$(CONFIG_CRYPTO_TWOFISH_AVX_X86_64) += twofish-avx-x86_64.o
+twofish-avx-x86_64-y := twofish-avx-x86_64-asm_64.o twofish_avx_glue.o
+
 obj-$(CONFIG_CRYPTO_SERPENT_SSE2_586) += serpent-sse2-i586.o
+serpent-sse2-i586-y := serpent-sse2-i586-asm_32.o serpent_sse2_glue.o
+obj-$(CONFIG_CRYPTO_SERPENT_SSE2_X86_64) += serpent-sse2-x86_64.o
+serpent-sse2-x86_64-y := serpent-sse2-x86_64-asm_64.o serpent_sse2_glue.o
+obj-$(CONFIG_CRYPTO_SERPENT_AVX_X86_64) += serpent-avx-x86_64.o
+serpent-avx-x86_64-y := serpent-avx-x86_64-asm_64.o serpent_avx_glue.o
+obj-$(CONFIG_CRYPTO_SERPENT_AVX2_X86_64) += serpent-avx2.o
+serpent-avx2-y := serpent-avx2-asm_64.o serpent_avx2_glue.o
 
 obj-$(CONFIG_CRYPTO_DES3_EDE_X86_64) += des3_ede-x86_64.o
+des3_ede-x86_64-y := des3_ede-asm_64.o des3_ede_glue.o
+
 obj-$(CONFIG_CRYPTO_CAMELLIA_X86_64) += camellia-x86_64.o
+camellia-x86_64-y := camellia-x86_64-asm_64.o camellia_glue.o
+obj-$(CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64) += camellia-aesni-avx-x86_64.o
+camellia-aesni-avx-x86_64-y := camellia-aesni-avx-asm_64.o camellia_aesni_avx_glue.o
+obj-$(CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64) += camellia-aesni-avx2.o
+camellia-aesni-avx2-y := camellia-aesni-avx2-asm_64.o camellia_aesni_avx2_glue.o
+
 obj-$(CONFIG_CRYPTO_BLOWFISH_X86_64) += blowfish-x86_64.o
-obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
-obj-$(CONFIG_CRYPTO_TWOFISH_X86_64_3WAY) += twofish-x86_64-3way.o
-obj-$(CONFIG_CRYPTO_CHACHA20_X86_64) += chacha-x86_64.o
-obj-$(CONFIG_CRYPTO_SERPENT_SSE2_X86_64) += serpent-sse2-x86_64.o
-obj-$(CONFIG_CRYPTO_AES_NI_INTEL) += aesni-intel.o
-obj-$(CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL) += ghash-clmulni-intel.o
+blowfish-x86_64-y := blowfish-x86_64-asm_64.o blowfish_glue.o
 
-obj-$(CONFIG_CRYPTO_CRC32C_INTEL) += crc32c-intel.o
-obj-$(CONFIG_CRYPTO_SHA1_SSSE3) += sha1-ssse3.o
-obj-$(CONFIG_CRYPTO_CRC32_PCLMUL) += crc32-pclmul.o
-obj-$(CONFIG_CRYPTO_SHA256_SSSE3) += sha256-ssse3.o
-obj-$(CONFIG_CRYPTO_SHA512_SSSE3) += sha512-ssse3.o
-obj-$(CONFIG_CRYPTO_CRCT10DIF_PCLMUL) += crct10dif-pclmul.o
-obj-$(CONFIG_CRYPTO_POLY1305_X86_64) += poly1305-x86_64.o
+obj-$(CONFIG_CRYPTO_CAST5_AVX_X86_64) += cast5-avx-x86_64.o
+cast5-avx-x86_64-y := cast5-avx-x86_64-asm_64.o cast5_avx_glue.o
+
+obj-$(CONFIG_CRYPTO_CAST6_AVX_X86_64) += cast6-avx-x86_64.o
+cast6-avx-x86_64-y := cast6-avx-x86_64-asm_64.o cast6_avx_glue.o
 
 obj-$(CONFIG_CRYPTO_AEGIS128_AESNI_SSE2) += aegis128-aesni.o
+aegis128-aesni-y := aegis128-aesni-asm.o aegis128-aesni-glue.o
 
-obj-$(CONFIG_CRYPTO_NHPOLY1305_SSE2) += nhpoly1305-sse2.o
-obj-$(CONFIG_CRYPTO_NHPOLY1305_AVX2) += nhpoly1305-avx2.o
+obj-$(CONFIG_CRYPTO_CHACHA20_X86_64) += chacha-x86_64.o
+chacha-x86_64-y := chacha-avx2-x86_64.o chacha-ssse3-x86_64.o chacha_glue.o
+chacha-x86_64-$(CONFIG_AS_AVX512) += chacha-avx512vl-x86_64.o
 
-# These modules require the assembler to support ADX.
-ifeq ($(adx_supported),yes)
-       obj-$(CONFIG_CRYPTO_CURVE25519_X86) += curve25519-x86_64.o
-endif
-
-# These modules require assembler to support AVX.
-ifeq ($(avx_supported),yes)
-       obj-$(CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64) += \
-                                               camellia-aesni-avx-x86_64.o
-       obj-$(CONFIG_CRYPTO_CAST5_AVX_X86_64) += cast5-avx-x86_64.o
-       obj-$(CONFIG_CRYPTO_CAST6_AVX_X86_64) += cast6-avx-x86_64.o
-       obj-$(CONFIG_CRYPTO_TWOFISH_AVX_X86_64) += twofish-avx-x86_64.o
-       obj-$(CONFIG_CRYPTO_SERPENT_AVX_X86_64) += serpent-avx-x86_64.o
-       obj-$(CONFIG_CRYPTO_BLAKE2S_X86) += blake2s-x86_64.o
-endif
-
-# These modules require assembler to support AVX2.
-ifeq ($(avx2_supported),yes)
-       obj-$(CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64) += camellia-aesni-avx2.o
-       obj-$(CONFIG_CRYPTO_SERPENT_AVX2_X86_64) += serpent-avx2.o
-endif
+obj-$(CONFIG_CRYPTO_AES_NI_INTEL) += aesni-intel.o
+aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o
+aesni-intel-$(CONFIG_64BIT) += aesni-intel_avx-x86_64.o aes_ctrby8_avx-x86_64.o
 
-twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o
-serpent-sse2-i586-y := serpent-sse2-i586-asm_32.o serpent_sse2_glue.o
+obj-$(CONFIG_CRYPTO_SHA1_SSSE3) += sha1-ssse3.o
+sha1-ssse3-y := sha1_avx2_x86_64_asm.o sha1_ssse3_asm.o sha1_ssse3_glue.o
+sha1-ssse3-$(CONFIG_AS_SHA1_NI) += sha1_ni_asm.o
 
-des3_ede-x86_64-y := des3_ede-asm_64.o des3_ede_glue.o
-camellia-x86_64-y := camellia-x86_64-asm_64.o camellia_glue.o
-blowfish-x86_64-y := blowfish-x86_64-asm_64.o blowfish_glue.o
-twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o
-twofish-x86_64-3way-y := twofish-x86_64-asm_64-3way.o twofish_glue_3way.o
-chacha-x86_64-y := chacha-ssse3-x86_64.o chacha_glue.o
-serpent-sse2-x86_64-y := serpent-sse2-x86_64-asm_64.o serpent_sse2_glue.o
+obj-$(CONFIG_CRYPTO_SHA256_SSSE3) += sha256-ssse3.o
+sha256-ssse3-y := sha256-ssse3-asm.o sha256-avx-asm.o sha256-avx2-asm.o sha256_ssse3_glue.o
+sha256-ssse3-$(CONFIG_AS_SHA256_NI) += sha256_ni_asm.o
 
-aegis128-aesni-y := aegis128-aesni-asm.o aegis128-aesni-glue.o
+obj-$(CONFIG_CRYPTO_SHA512_SSSE3) += sha512-ssse3.o
+sha512-ssse3-y := sha512-ssse3-asm.o sha512-avx-asm.o sha512-avx2-asm.o sha512_ssse3_glue.o
 
-nhpoly1305-sse2-y := nh-sse2-x86_64.o nhpoly1305-sse2-glue.o
+obj-$(CONFIG_CRYPTO_BLAKE2S_X86) += blake2s-x86_64.o
 blake2s-x86_64-y := blake2s-core.o blake2s-glue.o
-poly1305-x86_64-y := poly1305-x86_64-cryptogams.o poly1305_glue.o
-ifneq ($(CONFIG_CRYPTO_POLY1305_X86_64),)
-targets += poly1305-x86_64-cryptogams.S
-endif
-
-ifeq ($(avx_supported),yes)
-       camellia-aesni-avx-x86_64-y := camellia-aesni-avx-asm_64.o \
-                                       camellia_aesni_avx_glue.o
-       cast5-avx-x86_64-y := cast5-avx-x86_64-asm_64.o cast5_avx_glue.o
-       cast6-avx-x86_64-y := cast6-avx-x86_64-asm_64.o cast6_avx_glue.o
-       twofish-avx-x86_64-y := twofish-avx-x86_64-asm_64.o \
-                               twofish_avx_glue.o
-       serpent-avx-x86_64-y := serpent-avx-x86_64-asm_64.o \
-                               serpent_avx_glue.o
-endif
-
-ifeq ($(avx2_supported),yes)
-       camellia-aesni-avx2-y := camellia-aesni-avx2-asm_64.o camellia_aesni_avx2_glue.o
-       chacha-x86_64-y += chacha-avx2-x86_64.o
-       serpent-avx2-y := serpent-avx2-asm_64.o serpent_avx2_glue.o
-
-       nhpoly1305-avx2-y := nh-avx2-x86_64.o nhpoly1305-avx2-glue.o
-endif
-
-ifeq ($(avx512_supported),yes)
-       chacha-x86_64-y += chacha-avx512vl-x86_64.o
-endif
 
-aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o
-aesni-intel-$(CONFIG_64BIT) += aesni-intel_avx-x86_64.o aes_ctrby8_avx-x86_64.o
+obj-$(CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL) += ghash-clmulni-intel.o
 ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o
-sha1-ssse3-y := sha1_ssse3_asm.o sha1_ssse3_glue.o
-ifeq ($(avx2_supported),yes)
-sha1-ssse3-y += sha1_avx2_x86_64_asm.o
-endif
-ifeq ($(sha1_ni_supported),yes)
-sha1-ssse3-y += sha1_ni_asm.o
-endif
+
+obj-$(CONFIG_CRYPTO_CRC32C_INTEL) += crc32c-intel.o
 crc32c-intel-y := crc32c-intel_glue.o
 crc32c-intel-$(CONFIG_64BIT) += crc32c-pcl-intel-asm_64.o
+
+obj-$(CONFIG_CRYPTO_CRC32_PCLMUL) += crc32-pclmul.o
 crc32-pclmul-y := crc32-pclmul_asm.o crc32-pclmul_glue.o
-sha256-ssse3-y := sha256-ssse3-asm.o sha256-avx-asm.o sha256-avx2-asm.o sha256_ssse3_glue.o
-ifeq ($(sha256_ni_supported),yes)
-sha256-ssse3-y += sha256_ni_asm.o
-endif
-sha512-ssse3-y := sha512-ssse3-asm.o sha512-avx-asm.o sha512-avx2-asm.o sha512_ssse3_glue.o
+
+obj-$(CONFIG_CRYPTO_CRCT10DIF_PCLMUL) += crct10dif-pclmul.o
 crct10dif-pclmul-y := crct10dif-pcl-asm_64.o crct10dif-pclmul_glue.o
 
+obj-$(CONFIG_CRYPTO_POLY1305_X86_64) += poly1305-x86_64.o
+poly1305-x86_64-y := poly1305-x86_64-cryptogams.o poly1305_glue.o
+targets += poly1305-x86_64-cryptogams.S
+
+obj-$(CONFIG_CRYPTO_NHPOLY1305_SSE2) += nhpoly1305-sse2.o
+nhpoly1305-sse2-y := nh-sse2-x86_64.o nhpoly1305-sse2-glue.o
+obj-$(CONFIG_CRYPTO_NHPOLY1305_AVX2) += nhpoly1305-avx2.o
+nhpoly1305-avx2-y := nh-avx2-x86_64.o nhpoly1305-avx2-glue.o
+
+obj-$(CONFIG_CRYPTO_CURVE25519_X86) += curve25519-x86_64.o
+
 quiet_cmd_perlasm = PERLASM $@
       cmd_perlasm = $(PERL) $< > $@
 $(obj)/%.S: $(src)/%.pl FORCE
index bfa1c0b..0cea332 100644 (file)
@@ -886,7 +886,6 @@ _less_than_8_bytes_left_\@:
 _partial_block_done_\@:
 .endm # PARTIAL_BLOCK
 
-#ifdef CONFIG_AS_AVX
 ###############################################################################
 # GHASH_MUL MACRO to implement: Data*HashKey mod (128,127,126,121,0)
 # Input: A and B (128-bits each, bit-reflected)
@@ -1869,9 +1868,6 @@ key_256_finalize:
         ret
 SYM_FUNC_END(aesni_gcm_finalize_avx_gen2)
 
-#endif /* CONFIG_AS_AVX */
-
-#ifdef CONFIG_AS_AVX2
 ###############################################################################
 # GHASH_MUL MACRO to implement: Data*HashKey mod (128,127,126,121,0)
 # Input: A and B (128-bits each, bit-reflected)
@@ -2839,5 +2835,3 @@ key_256_finalize4:
         FUNC_RESTORE
         ret
 SYM_FUNC_END(aesni_gcm_finalize_avx_gen4)
-
-#endif /* CONFIG_AS_AVX2 */
index 75b6ea2..ad8a718 100644 (file)
@@ -185,7 +185,6 @@ static const struct aesni_gcm_tfm_s aesni_gcm_tfm_sse = {
        .finalize = &aesni_gcm_finalize,
 };
 
-#ifdef CONFIG_AS_AVX
 asmlinkage void aes_ctr_enc_128_avx_by8(const u8 *in, u8 *iv,
                void *keys, u8 *out, unsigned int num_bytes);
 asmlinkage void aes_ctr_enc_192_avx_by8(const u8 *in, u8 *iv,
@@ -234,9 +233,6 @@ static const struct aesni_gcm_tfm_s aesni_gcm_tfm_avx_gen2 = {
        .finalize = &aesni_gcm_finalize_avx_gen2,
 };
 
-#endif
-
-#ifdef CONFIG_AS_AVX2
 /*
  * asmlinkage void aesni_gcm_init_avx_gen4()
  * gcm_data *my_ctx_data, context data
@@ -279,8 +275,6 @@ static const struct aesni_gcm_tfm_s aesni_gcm_tfm_avx_gen4 = {
        .finalize = &aesni_gcm_finalize_avx_gen4,
 };
 
-#endif
-
 static inline struct
 aesni_rfc4106_gcm_ctx *aesni_rfc4106_gcm_ctx_get(struct crypto_aead *tfm)
 {
@@ -476,7 +470,6 @@ static void ctr_crypt_final(struct crypto_aes_ctx *ctx,
        crypto_inc(ctrblk, AES_BLOCK_SIZE);
 }
 
-#ifdef CONFIG_AS_AVX
 static void aesni_ctr_enc_avx_tfm(struct crypto_aes_ctx *ctx, u8 *out,
                              const u8 *in, unsigned int len, u8 *iv)
 {
@@ -493,7 +486,6 @@ static void aesni_ctr_enc_avx_tfm(struct crypto_aes_ctx *ctx, u8 *out,
        else
                aes_ctr_enc_256_avx_by8(in, iv, (void *)ctx, out, len);
 }
-#endif
 
 static int ctr_crypt(struct skcipher_request *req)
 {
@@ -711,14 +703,10 @@ static int gcmaes_crypt_by_sg(bool enc, struct aead_request *req,
        if (!enc)
                left -= auth_tag_len;
 
-#ifdef CONFIG_AS_AVX2
        if (left < AVX_GEN4_OPTSIZE && gcm_tfm == &aesni_gcm_tfm_avx_gen4)
                gcm_tfm = &aesni_gcm_tfm_avx_gen2;
-#endif
-#ifdef CONFIG_AS_AVX
        if (left < AVX_GEN2_OPTSIZE && gcm_tfm == &aesni_gcm_tfm_avx_gen2)
                gcm_tfm = &aesni_gcm_tfm_sse;
-#endif
 
        /* Linearize assoc, if not already linear */
        if (req->src->length >= assoclen && req->src->length &&
@@ -1076,31 +1064,24 @@ static int __init aesni_init(void)
        if (!x86_match_cpu(aesni_cpu_id))
                return -ENODEV;
 #ifdef CONFIG_X86_64
-#ifdef CONFIG_AS_AVX2
        if (boot_cpu_has(X86_FEATURE_AVX2)) {
                pr_info("AVX2 version of gcm_enc/dec engaged.\n");
                aesni_gcm_tfm = &aesni_gcm_tfm_avx_gen4;
        } else
-#endif
-#ifdef CONFIG_AS_AVX
        if (boot_cpu_has(X86_FEATURE_AVX)) {
                pr_info("AVX version of gcm_enc/dec engaged.\n");
                aesni_gcm_tfm = &aesni_gcm_tfm_avx_gen2;
-       } else
-#endif
-       {
+       } else {
                pr_info("SSE version of gcm_enc/dec engaged.\n");
                aesni_gcm_tfm = &aesni_gcm_tfm_sse;
        }
        aesni_ctr_enc_tfm = aesni_ctr_enc;
-#ifdef CONFIG_AS_AVX
        if (boot_cpu_has(X86_FEATURE_AVX)) {
                /* optimize performance of ctr mode encryption transform */
                aesni_ctr_enc_tfm = aesni_ctr_enc_avx_tfm;
                pr_info("AES CTR mode by8 optimization enabled\n");
        }
 #endif
-#endif
 
        err = crypto_register_alg(&aesni_cipher_alg);
        if (err)
index 24910b7..2ca7997 100644 (file)
@@ -46,7 +46,6 @@ SIGMA2:
 #endif /* CONFIG_AS_AVX512 */
 
 .text
-#ifdef CONFIG_AS_SSSE3
 SYM_FUNC_START(blake2s_compress_ssse3)
        testq           %rdx,%rdx
        je              .Lendofloop
@@ -174,7 +173,6 @@ SYM_FUNC_START(blake2s_compress_ssse3)
 .Lendofloop:
        ret
 SYM_FUNC_END(blake2s_compress_ssse3)
-#endif /* CONFIG_AS_SSSE3 */
 
 #ifdef CONFIG_AS_AVX512
 SYM_FUNC_START(blake2s_compress_avx512)
index 68a7495..b412c21 100644 (file)
@@ -79,8 +79,7 @@ static void chacha_dosimd(u32 *state, u8 *dst, const u8 *src,
                }
        }
 
-       if (IS_ENABLED(CONFIG_AS_AVX2) &&
-           static_branch_likely(&chacha_use_avx2)) {
+       if (static_branch_likely(&chacha_use_avx2)) {
                while (bytes >= CHACHA_BLOCK_SIZE * 8) {
                        chacha_8block_xor_avx2(state, dst, src, bytes, nrounds);
                        bytes -= CHACHA_BLOCK_SIZE * 8;
@@ -288,8 +287,7 @@ static int __init chacha_simd_mod_init(void)
 
        static_branch_enable(&chacha_use_simd);
 
-       if (IS_ENABLED(CONFIG_AS_AVX2) &&
-           boot_cpu_has(X86_FEATURE_AVX) &&
+       if (boot_cpu_has(X86_FEATURE_AVX) &&
            boot_cpu_has(X86_FEATURE_AVX2) &&
            cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL)) {
                static_branch_enable(&chacha_use_avx2);
index 7a6b538..137edcf 100644 (file)
@@ -404,10 +404,6 @@ ___
 &end_function("poly1305_emit_x86_64");
 if ($avx) {
 
-if($kernel) {
-       $code .= "#ifdef CONFIG_AS_AVX\n";
-}
-
 ########################################################################
 # Layout of opaque area is following.
 #
@@ -1516,16 +1512,8 @@ $code.=<<___;
 ___
 &end_function("poly1305_emit_avx");
 
-if ($kernel) {
-       $code .= "#endif\n";
-}
-
 if ($avx>1) {
 
-if ($kernel) {
-       $code .= "#ifdef CONFIG_AS_AVX2\n";
-}
-
 my ($H0,$H1,$H2,$H3,$H4, $MASK, $T4,$T0,$T1,$T2,$T3, $D0,$D1,$D2,$D3,$D4) =
     map("%ymm$_",(0..15));
 my $S4=$MASK;
@@ -2816,10 +2804,6 @@ ___
 poly1305_blocks_avxN(0);
 &end_function("poly1305_blocks_avx2");
 
-if($kernel) {
-       $code .= "#endif\n";
-}
-
 #######################################################################
 if ($avx>2) {
 # On entry we have input length divisible by 64. But since inner loop
index 79bb587..6dfec19 100644 (file)
@@ -94,7 +94,7 @@ static void poly1305_simd_blocks(void *ctx, const u8 *inp, size_t len,
        BUILD_BUG_ON(PAGE_SIZE < POLY1305_BLOCK_SIZE ||
                     PAGE_SIZE % POLY1305_BLOCK_SIZE);
 
-       if (!IS_ENABLED(CONFIG_AS_AVX) || !static_branch_likely(&poly1305_use_avx) ||
+       if (!static_branch_likely(&poly1305_use_avx) ||
            (len < (POLY1305_BLOCK_SIZE * 18) && !state->is_base2_26) ||
            !crypto_simd_usable()) {
                convert_to_base2_64(ctx);
@@ -108,7 +108,7 @@ static void poly1305_simd_blocks(void *ctx, const u8 *inp, size_t len,
                kernel_fpu_begin();
                if (IS_ENABLED(CONFIG_AS_AVX512) && static_branch_likely(&poly1305_use_avx512))
                        poly1305_blocks_avx512(ctx, inp, bytes, padbit);
-               else if (IS_ENABLED(CONFIG_AS_AVX2) && static_branch_likely(&poly1305_use_avx2))
+               else if (static_branch_likely(&poly1305_use_avx2))
                        poly1305_blocks_avx2(ctx, inp, bytes, padbit);
                else
                        poly1305_blocks_avx(ctx, inp, bytes, padbit);
@@ -123,7 +123,7 @@ static void poly1305_simd_blocks(void *ctx, const u8 *inp, size_t len,
 static void poly1305_simd_emit(void *ctx, u8 mac[POLY1305_DIGEST_SIZE],
                               const u32 nonce[4])
 {
-       if (!IS_ENABLED(CONFIG_AS_AVX) || !static_branch_likely(&poly1305_use_avx))
+       if (!static_branch_likely(&poly1305_use_avx))
                poly1305_emit_x86_64(ctx, mac, nonce);
        else
                poly1305_emit_avx(ctx, mac, nonce);
@@ -261,11 +261,10 @@ static struct shash_alg alg = {
 
 static int __init poly1305_simd_mod_init(void)
 {
-       if (IS_ENABLED(CONFIG_AS_AVX) && boot_cpu_has(X86_FEATURE_AVX) &&
+       if (boot_cpu_has(X86_FEATURE_AVX) &&
            cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL))
                static_branch_enable(&poly1305_use_avx);
-       if (IS_ENABLED(CONFIG_AS_AVX2) && boot_cpu_has(X86_FEATURE_AVX) &&
-           boot_cpu_has(X86_FEATURE_AVX2) &&
+       if (boot_cpu_has(X86_FEATURE_AVX) && boot_cpu_has(X86_FEATURE_AVX2) &&
            cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL))
                static_branch_enable(&poly1305_use_avx2);
        if (IS_ENABLED(CONFIG_AS_AVX512) && boot_cpu_has(X86_FEATURE_AVX) &&
index 12e2d19..d25668d 100644 (file)
@@ -467,8 +467,6 @@ W_PRECALC_SSSE3
  */
 SHA1_VECTOR_ASM     sha1_transform_ssse3
 
-#ifdef CONFIG_AS_AVX
-
 .macro W_PRECALC_AVX
 
 .purgem W_PRECALC_00_15
@@ -553,5 +551,3 @@ W_PRECALC_AVX
  *                                    const u8 *data, int blocks);
  */
 SHA1_VECTOR_ASM     sha1_transform_avx
-
-#endif
index d70b40a..a801ffc 100644 (file)
@@ -114,7 +114,6 @@ static void unregister_sha1_ssse3(void)
                crypto_unregister_shash(&sha1_ssse3_alg);
 }
 
-#ifdef CONFIG_AS_AVX
 asmlinkage void sha1_transform_avx(struct sha1_state *state,
                                   const u8 *data, int blocks);
 
@@ -175,13 +174,6 @@ static void unregister_sha1_avx(void)
                crypto_unregister_shash(&sha1_avx_alg);
 }
 
-#else  /* CONFIG_AS_AVX */
-static inline int register_sha1_avx(void) { return 0; }
-static inline void unregister_sha1_avx(void) { }
-#endif /* CONFIG_AS_AVX */
-
-
-#if defined(CONFIG_AS_AVX2) && (CONFIG_AS_AVX)
 #define SHA1_AVX2_BLOCK_OPTSIZE        4       /* optimal 4*64 bytes of SHA1 blocks */
 
 asmlinkage void sha1_transform_avx2(struct sha1_state *state,
@@ -253,11 +245,6 @@ static void unregister_sha1_avx2(void)
                crypto_unregister_shash(&sha1_avx2_alg);
 }
 
-#else
-static inline int register_sha1_avx2(void) { return 0; }
-static inline void unregister_sha1_avx2(void) { }
-#endif
-
 #ifdef CONFIG_AS_SHA1_NI
 asmlinkage void sha1_ni_transform(struct sha1_state *digest, const u8 *data,
                                  int rounds);
index fcbc30f..4739cd3 100644 (file)
@@ -47,7 +47,6 @@
 # This code schedules 1 block at a time, with 4 lanes per block
 ########################################################################
 
-#ifdef CONFIG_AS_AVX
 #include <linux/linkage.h>
 
 ## assume buffers not aligned
@@ -498,5 +497,3 @@ _SHUF_00BA:
 # shuffle xDxC -> DC00
 _SHUF_DC00:
        .octa 0x0b0a090803020100FFFFFFFFFFFFFFFF
-
-#endif
index 499d9ec..11ff60c 100644 (file)
@@ -48,7 +48,6 @@
 # This code schedules 2 blocks at a time, with 4 lanes per block
 ########################################################################
 
-#ifdef CONFIG_AS_AVX2
 #include <linux/linkage.h>
 
 ## assume buffers not aligned
@@ -767,5 +766,3 @@ _SHUF_00BA:
 .align 32
 _SHUF_DC00:
        .octa 0x0b0a090803020100FFFFFFFFFFFFFFFF,0x0b0a090803020100FFFFFFFFFFFFFFFF
-
-#endif
index 03ad657..6394b5f 100644 (file)
@@ -144,7 +144,6 @@ static void unregister_sha256_ssse3(void)
                                ARRAY_SIZE(sha256_ssse3_algs));
 }
 
-#ifdef CONFIG_AS_AVX
 asmlinkage void sha256_transform_avx(struct sha256_state *state,
                                     const u8 *data, int blocks);
 
@@ -221,12 +220,6 @@ static void unregister_sha256_avx(void)
                                ARRAY_SIZE(sha256_avx_algs));
 }
 
-#else
-static inline int register_sha256_avx(void) { return 0; }
-static inline void unregister_sha256_avx(void) { }
-#endif
-
-#if defined(CONFIG_AS_AVX2) && defined(CONFIG_AS_AVX)
 asmlinkage void sha256_transform_rorx(struct sha256_state *state,
                                      const u8 *data, int blocks);
 
@@ -301,11 +294,6 @@ static void unregister_sha256_avx2(void)
                                ARRAY_SIZE(sha256_avx2_algs));
 }
 
-#else
-static inline int register_sha256_avx2(void) { return 0; }
-static inline void unregister_sha256_avx2(void) { }
-#endif
-
 #ifdef CONFIG_AS_SHA256_NI
 asmlinkage void sha256_ni_transform(struct sha256_state *digest,
                                    const u8 *data, int rounds);
index 90ea945..63470fd 100644 (file)
@@ -47,7 +47,6 @@
 #
 ########################################################################
 
-#ifdef CONFIG_AS_AVX
 #include <linux/linkage.h>
 
 .text
@@ -424,4 +423,3 @@ K512:
        .quad 0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
        .quad 0x4cc5d4becb3e42b6,0x597f299cfc657e2a
        .quad 0x5fcb6fab3ad6faec,0x6c44198c4a475817
-#endif
index 3dd886b..3a44bdc 100644 (file)
@@ -49,7 +49,6 @@
 # This code schedules 1 blocks at a time, with 4 lanes per block
 ########################################################################
 
-#ifdef CONFIG_AS_AVX2
 #include <linux/linkage.h>
 
 .text
@@ -749,5 +748,3 @@ PSHUFFLE_BYTE_FLIP_MASK:
 MASK_YMM_LO:
        .octa 0x00000000000000000000000000000000
        .octa 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
-
-#endif
index 1c444f4..82cc1b3 100644 (file)
@@ -142,7 +142,6 @@ static void unregister_sha512_ssse3(void)
                        ARRAY_SIZE(sha512_ssse3_algs));
 }
 
-#ifdef CONFIG_AS_AVX
 asmlinkage void sha512_transform_avx(struct sha512_state *state,
                                     const u8 *data, int blocks);
 static bool avx_usable(void)
@@ -218,12 +217,7 @@ static void unregister_sha512_avx(void)
                crypto_unregister_shashes(sha512_avx_algs,
                        ARRAY_SIZE(sha512_avx_algs));
 }
-#else
-static inline int register_sha512_avx(void) { return 0; }
-static inline void unregister_sha512_avx(void) { }
-#endif
 
-#if defined(CONFIG_AS_AVX2) && defined(CONFIG_AS_AVX)
 asmlinkage void sha512_transform_rorx(struct sha512_state *state,
                                      const u8 *data, int blocks);
 
@@ -298,10 +292,6 @@ static void unregister_sha512_avx2(void)
                crypto_unregister_shashes(sha512_avx2_algs,
                        ARRAY_SIZE(sha512_avx2_algs));
 }
-#else
-static inline int register_sha512_avx2(void) { return 0; }
-static inline void unregister_sha512_avx2(void) { }
-#endif
 
 static int __init sha512_ssse3_mod_init(void)
 {
index 1ba72c5..cf76d66 100644 (file)
@@ -1476,6 +1476,12 @@ static const struct intel_uncore_init_fun tgl_l_uncore_init __initconst = {
        .mmio_init = tgl_l_uncore_mmio_init,
 };
 
+static const struct intel_uncore_init_fun icx_uncore_init __initconst = {
+       .cpu_init = icx_uncore_cpu_init,
+       .pci_init = icx_uncore_pci_init,
+       .mmio_init = icx_uncore_mmio_init,
+};
+
 static const struct intel_uncore_init_fun snr_uncore_init __initconst = {
        .cpu_init = snr_uncore_cpu_init,
        .pci_init = snr_uncore_pci_init,
@@ -1511,6 +1517,8 @@ static const struct x86_cpu_id intel_uncore_match[] __initconst = {
        X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L,           &icl_uncore_init),
        X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_NNPI,        &icl_uncore_init),
        X86_MATCH_INTEL_FAM6_MODEL(ICELAKE,             &icl_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D,           &icx_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X,           &icx_uncore_init),
        X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L,         &tgl_l_uncore_init),
        X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE,           &tgl_uncore_init),
        X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_D,      &snr_uncore_init),
index b30429f..0da4a46 100644 (file)
@@ -550,6 +550,9 @@ void skx_uncore_cpu_init(void);
 int snr_uncore_pci_init(void);
 void snr_uncore_cpu_init(void);
 void snr_uncore_mmio_init(void);
+int icx_uncore_pci_init(void);
+void icx_uncore_cpu_init(void);
+void icx_uncore_mmio_init(void);
 
 /* uncore_nhmex.c */
 void nhmex_uncore_cpu_init(void);
index 01023f0..07652fa 100644 (file)
 #define SNR_IMC_MMIO_MEM0_OFFSET               0xd8
 #define SNR_IMC_MMIO_MEM0_MASK                 0x7FF
 
+/* ICX CHA */
+#define ICX_C34_MSR_PMON_CTR0                  0xb68
+#define ICX_C34_MSR_PMON_CTL0                  0xb61
+#define ICX_C34_MSR_PMON_BOX_CTL               0xb60
+#define ICX_C34_MSR_PMON_BOX_FILTER0           0xb65
+
+/* ICX IIO */
+#define ICX_IIO_MSR_PMON_CTL0                  0xa58
+#define ICX_IIO_MSR_PMON_CTR0                  0xa51
+#define ICX_IIO_MSR_PMON_BOX_CTL               0xa50
+
+/* ICX IRP */
+#define ICX_IRP0_MSR_PMON_CTL0                 0xa4d
+#define ICX_IRP0_MSR_PMON_CTR0                 0xa4b
+#define ICX_IRP0_MSR_PMON_BOX_CTL              0xa4a
+
+/* ICX M2PCIE */
+#define ICX_M2PCIE_MSR_PMON_CTL0               0xa46
+#define ICX_M2PCIE_MSR_PMON_CTR0               0xa41
+#define ICX_M2PCIE_MSR_PMON_BOX_CTL            0xa40
+
+/* ICX UPI */
+#define ICX_UPI_PCI_PMON_CTL0                  0x350
+#define ICX_UPI_PCI_PMON_CTR0                  0x320
+#define ICX_UPI_PCI_PMON_BOX_CTL               0x318
+#define ICX_UPI_CTL_UMASK_EXT                  0xffffff
+
+/* ICX M3UPI*/
+#define ICX_M3UPI_PCI_PMON_CTL0                        0xd8
+#define ICX_M3UPI_PCI_PMON_CTR0                        0xa8
+#define ICX_M3UPI_PCI_PMON_BOX_CTL             0xa0
+
+/* ICX IMC */
+#define ICX_NUMBER_IMC_CHN                     2
+#define ICX_IMC_MEM_STRIDE                     0x4
+
 DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
 DEFINE_UNCORE_FORMAT_ATTR(event2, event, "config:0-6");
 DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
@@ -390,6 +426,7 @@ DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
 DEFINE_UNCORE_FORMAT_ATTR(umask_ext, umask, "config:8-15,32-43,45-55");
 DEFINE_UNCORE_FORMAT_ATTR(umask_ext2, umask, "config:8-15,32-57");
 DEFINE_UNCORE_FORMAT_ATTR(umask_ext3, umask, "config:8-15,32-39");
+DEFINE_UNCORE_FORMAT_ATTR(umask_ext4, umask, "config:8-15,32-55");
 DEFINE_UNCORE_FORMAT_ATTR(qor, qor, "config:16");
 DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
 DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19");
@@ -4551,3 +4588,477 @@ void snr_uncore_mmio_init(void)
 }
 
 /* end of SNR uncore support */
+
+/* ICX uncore support */
+
+static unsigned icx_cha_msr_offsets[] = {
+       0x2a0, 0x2ae, 0x2bc, 0x2ca, 0x2d8, 0x2e6, 0x2f4, 0x302, 0x310,
+       0x31e, 0x32c, 0x33a, 0x348, 0x356, 0x364, 0x372, 0x380, 0x38e,
+       0x3aa, 0x3b8, 0x3c6, 0x3d4, 0x3e2, 0x3f0, 0x3fe, 0x40c, 0x41a,
+       0x428, 0x436, 0x444, 0x452, 0x460, 0x46e, 0x47c, 0x0,   0xe,
+       0x1c,  0x2a,  0x38,  0x46,
+};
+
+static int icx_cha_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       bool tie_en = !!(event->hw.config & SNBEP_CBO_PMON_CTL_TID_EN);
+
+       if (tie_en) {
+               reg1->reg = ICX_C34_MSR_PMON_BOX_FILTER0 +
+                           icx_cha_msr_offsets[box->pmu->pmu_idx];
+               reg1->config = event->attr.config1 & SKX_CHA_MSR_PMON_BOX_FILTER_TID;
+               reg1->idx = 0;
+       }
+
+       return 0;
+}
+
+static struct intel_uncore_ops icx_uncore_chabox_ops = {
+       .init_box               = ivbep_uncore_msr_init_box,
+       .disable_box            = snbep_uncore_msr_disable_box,
+       .enable_box             = snbep_uncore_msr_enable_box,
+       .disable_event          = snbep_uncore_msr_disable_event,
+       .enable_event           = snr_cha_enable_event,
+       .read_counter           = uncore_msr_read_counter,
+       .hw_config              = icx_cha_hw_config,
+};
+
+static struct intel_uncore_type icx_uncore_chabox = {
+       .name                   = "cha",
+       .num_counters           = 4,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = ICX_C34_MSR_PMON_CTL0,
+       .perf_ctr               = ICX_C34_MSR_PMON_CTR0,
+       .box_ctl                = ICX_C34_MSR_PMON_BOX_CTL,
+       .msr_offsets            = icx_cha_msr_offsets,
+       .event_mask             = HSWEP_S_MSR_PMON_RAW_EVENT_MASK,
+       .event_mask_ext         = SNR_CHA_RAW_EVENT_MASK_EXT,
+       .constraints            = skx_uncore_chabox_constraints,
+       .ops                    = &icx_uncore_chabox_ops,
+       .format_group           = &snr_uncore_chabox_format_group,
+};
+
+static unsigned icx_msr_offsets[] = {
+       0x0, 0x20, 0x40, 0x90, 0xb0, 0xd0,
+};
+
+static struct event_constraint icx_uncore_iio_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x02, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x03, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x83, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0xc0, 0xc),
+       UNCORE_EVENT_CONSTRAINT(0xc5, 0xc),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type icx_uncore_iio = {
+       .name                   = "iio",
+       .num_counters           = 4,
+       .num_boxes              = 6,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = ICX_IIO_MSR_PMON_CTL0,
+       .perf_ctr               = ICX_IIO_MSR_PMON_CTR0,
+       .event_mask             = SNBEP_PMON_RAW_EVENT_MASK,
+       .event_mask_ext         = SNR_IIO_PMON_RAW_EVENT_MASK_EXT,
+       .box_ctl                = ICX_IIO_MSR_PMON_BOX_CTL,
+       .msr_offsets            = icx_msr_offsets,
+       .constraints            = icx_uncore_iio_constraints,
+       .ops                    = &skx_uncore_iio_ops,
+       .format_group           = &snr_uncore_iio_format_group,
+};
+
+static struct intel_uncore_type icx_uncore_irp = {
+       .name                   = "irp",
+       .num_counters           = 2,
+       .num_boxes              = 6,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = ICX_IRP0_MSR_PMON_CTL0,
+       .perf_ctr               = ICX_IRP0_MSR_PMON_CTR0,
+       .event_mask             = SNBEP_PMON_RAW_EVENT_MASK,
+       .box_ctl                = ICX_IRP0_MSR_PMON_BOX_CTL,
+       .msr_offsets            = icx_msr_offsets,
+       .ops                    = &ivbep_uncore_msr_ops,
+       .format_group           = &ivbep_uncore_format_group,
+};
+
+static struct event_constraint icx_uncore_m2pcie_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x14, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type icx_uncore_m2pcie = {
+       .name           = "m2pcie",
+       .num_counters   = 4,
+       .num_boxes      = 6,
+       .perf_ctr_bits  = 48,
+       .event_ctl      = ICX_M2PCIE_MSR_PMON_CTL0,
+       .perf_ctr       = ICX_M2PCIE_MSR_PMON_CTR0,
+       .box_ctl        = ICX_M2PCIE_MSR_PMON_BOX_CTL,
+       .msr_offsets    = icx_msr_offsets,
+       .constraints    = icx_uncore_m2pcie_constraints,
+       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,
+       .ops            = &ivbep_uncore_msr_ops,
+       .format_group   = &ivbep_uncore_format_group,
+};
+
+enum perf_uncore_icx_iio_freerunning_type_id {
+       ICX_IIO_MSR_IOCLK,
+       ICX_IIO_MSR_BW_IN,
+
+       ICX_IIO_FREERUNNING_TYPE_MAX,
+};
+
+static unsigned icx_iio_clk_freerunning_box_offsets[] = {
+       0x0, 0x20, 0x40, 0x90, 0xb0, 0xd0,
+};
+
+static unsigned icx_iio_bw_freerunning_box_offsets[] = {
+       0x0, 0x10, 0x20, 0x90, 0xa0, 0xb0,
+};
+
+static struct freerunning_counters icx_iio_freerunning[] = {
+       [ICX_IIO_MSR_IOCLK]     = { 0xa55, 0x1, 0x20, 1, 48, icx_iio_clk_freerunning_box_offsets },
+       [ICX_IIO_MSR_BW_IN]     = { 0xaa0, 0x1, 0x10, 8, 48, icx_iio_bw_freerunning_box_offsets },
+};
+
+static struct uncore_event_desc icx_uncore_iio_freerunning_events[] = {
+       /* Free-Running IIO CLOCKS Counter */
+       INTEL_UNCORE_EVENT_DESC(ioclk,                  "event=0xff,umask=0x10"),
+       /* Free-Running IIO BANDWIDTH IN Counters */
+       INTEL_UNCORE_EVENT_DESC(bw_in_port0,            "event=0xff,umask=0x20"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port0.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port0.unit,       "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port1,            "event=0xff,umask=0x21"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port1.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port1.unit,       "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port2,            "event=0xff,umask=0x22"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port2.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port2.unit,       "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port3,            "event=0xff,umask=0x23"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port3.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port3.unit,       "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port4,            "event=0xff,umask=0x24"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port4.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port4.unit,       "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port5,            "event=0xff,umask=0x25"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port5.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port5.unit,       "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port6,            "event=0xff,umask=0x26"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port6.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port6.unit,       "MiB"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port7,            "event=0xff,umask=0x27"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port7.scale,      "3.814697266e-6"),
+       INTEL_UNCORE_EVENT_DESC(bw_in_port7.unit,       "MiB"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_type icx_uncore_iio_free_running = {
+       .name                   = "iio_free_running",
+       .num_counters           = 9,
+       .num_boxes              = 6,
+       .num_freerunning_types  = ICX_IIO_FREERUNNING_TYPE_MAX,
+       .freerunning            = icx_iio_freerunning,
+       .ops                    = &skx_uncore_iio_freerunning_ops,
+       .event_descs            = icx_uncore_iio_freerunning_events,
+       .format_group           = &skx_uncore_iio_freerunning_format_group,
+};
+
+static struct intel_uncore_type *icx_msr_uncores[] = {
+       &skx_uncore_ubox,
+       &icx_uncore_chabox,
+       &icx_uncore_iio,
+       &icx_uncore_irp,
+       &icx_uncore_m2pcie,
+       &skx_uncore_pcu,
+       &icx_uncore_iio_free_running,
+       NULL,
+};
+
+/*
+ * To determine the number of CHAs, it should read CAPID6(Low) and CAPID7 (High)
+ * registers which located at Device 30, Function 3
+ */
+#define ICX_CAPID6             0x9c
+#define ICX_CAPID7             0xa0
+
+static u64 icx_count_chabox(void)
+{
+       struct pci_dev *dev = NULL;
+       u64 caps = 0;
+
+       dev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x345b, dev);
+       if (!dev)
+               goto out;
+
+       pci_read_config_dword(dev, ICX_CAPID6, (u32 *)&caps);
+       pci_read_config_dword(dev, ICX_CAPID7, (u32 *)&caps + 1);
+out:
+       pci_dev_put(dev);
+       return hweight64(caps);
+}
+
+void icx_uncore_cpu_init(void)
+{
+       u64 num_boxes = icx_count_chabox();
+
+       if (WARN_ON(num_boxes > ARRAY_SIZE(icx_cha_msr_offsets)))
+               return;
+       icx_uncore_chabox.num_boxes = num_boxes;
+       uncore_msr_uncores = icx_msr_uncores;
+}
+
+static struct intel_uncore_type icx_uncore_m2m = {
+       .name           = "m2m",
+       .num_counters   = 4,
+       .num_boxes      = 4,
+       .perf_ctr_bits  = 48,
+       .perf_ctr       = SNR_M2M_PCI_PMON_CTR0,
+       .event_ctl      = SNR_M2M_PCI_PMON_CTL0,
+       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,
+       .box_ctl        = SNR_M2M_PCI_PMON_BOX_CTL,
+       .ops            = &snr_m2m_uncore_pci_ops,
+       .format_group   = &skx_uncore_format_group,
+};
+
+static struct attribute *icx_upi_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask_ext4.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       NULL,
+};
+
+static const struct attribute_group icx_upi_uncore_format_group = {
+       .name = "format",
+       .attrs = icx_upi_uncore_formats_attr,
+};
+
+static struct intel_uncore_type icx_uncore_upi = {
+       .name           = "upi",
+       .num_counters   = 4,
+       .num_boxes      = 3,
+       .perf_ctr_bits  = 48,
+       .perf_ctr       = ICX_UPI_PCI_PMON_CTR0,
+       .event_ctl      = ICX_UPI_PCI_PMON_CTL0,
+       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,
+       .event_mask_ext = ICX_UPI_CTL_UMASK_EXT,
+       .box_ctl        = ICX_UPI_PCI_PMON_BOX_CTL,
+       .ops            = &skx_upi_uncore_pci_ops,
+       .format_group   = &icx_upi_uncore_format_group,
+};
+
+static struct event_constraint icx_uncore_m3upi_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x1c, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x1d, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x1e, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x1f, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x40, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x4e, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x4f, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x50, 0x7),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type icx_uncore_m3upi = {
+       .name           = "m3upi",
+       .num_counters   = 4,
+       .num_boxes      = 3,
+       .perf_ctr_bits  = 48,
+       .perf_ctr       = ICX_M3UPI_PCI_PMON_CTR0,
+       .event_ctl      = ICX_M3UPI_PCI_PMON_CTL0,
+       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,
+       .box_ctl        = ICX_M3UPI_PCI_PMON_BOX_CTL,
+       .constraints    = icx_uncore_m3upi_constraints,
+       .ops            = &ivbep_uncore_pci_ops,
+       .format_group   = &skx_uncore_format_group,
+};
+
+enum {
+       ICX_PCI_UNCORE_M2M,
+       ICX_PCI_UNCORE_UPI,
+       ICX_PCI_UNCORE_M3UPI,
+};
+
+static struct intel_uncore_type *icx_pci_uncores[] = {
+       [ICX_PCI_UNCORE_M2M]            = &icx_uncore_m2m,
+       [ICX_PCI_UNCORE_UPI]            = &icx_uncore_upi,
+       [ICX_PCI_UNCORE_M3UPI]          = &icx_uncore_m3upi,
+       NULL,
+};
+
+static const struct pci_device_id icx_uncore_pci_ids[] = {
+       { /* M2M 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x344a),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(12, 0, ICX_PCI_UNCORE_M2M, 0),
+       },
+       { /* M2M 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x344a),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(13, 0, ICX_PCI_UNCORE_M2M, 1),
+       },
+       { /* M2M 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x344a),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(14, 0, ICX_PCI_UNCORE_M2M, 2),
+       },
+       { /* M2M 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x344a),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(15, 0, ICX_PCI_UNCORE_M2M, 3),
+       },
+       { /* UPI Link 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3441),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(2, 1, ICX_PCI_UNCORE_UPI, 0),
+       },
+       { /* UPI Link 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3441),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(3, 1, ICX_PCI_UNCORE_UPI, 1),
+       },
+       { /* UPI Link 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3441),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(4, 1, ICX_PCI_UNCORE_UPI, 2),
+       },
+       { /* M3UPI Link 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3446),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(5, 1, ICX_PCI_UNCORE_M3UPI, 0),
+       },
+       { /* M3UPI Link 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3446),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(6, 1, ICX_PCI_UNCORE_M3UPI, 1),
+       },
+       { /* M3UPI Link 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3446),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(7, 1, ICX_PCI_UNCORE_M3UPI, 2),
+       },
+       { /* end: all zeroes */ }
+};
+
+static struct pci_driver icx_uncore_pci_driver = {
+       .name           = "icx_uncore",
+       .id_table       = icx_uncore_pci_ids,
+};
+
+int icx_uncore_pci_init(void)
+{
+       /* ICX UBOX DID */
+       int ret = snbep_pci2phy_map_init(0x3450, SKX_CPUNODEID,
+                                        SKX_GIDNIDMAP, true);
+
+       if (ret)
+               return ret;
+
+       uncore_pci_uncores = icx_pci_uncores;
+       uncore_pci_driver = &icx_uncore_pci_driver;
+       return 0;
+}
+
+static void icx_uncore_imc_init_box(struct intel_uncore_box *box)
+{
+       unsigned int box_ctl = box->pmu->type->box_ctl +
+                              box->pmu->type->mmio_offset * (box->pmu->pmu_idx % ICX_NUMBER_IMC_CHN);
+       int mem_offset = (box->pmu->pmu_idx / ICX_NUMBER_IMC_CHN) * ICX_IMC_MEM_STRIDE +
+                        SNR_IMC_MMIO_MEM0_OFFSET;
+
+       __snr_uncore_mmio_init_box(box, box_ctl, mem_offset);
+}
+
+static struct intel_uncore_ops icx_uncore_mmio_ops = {
+       .init_box       = icx_uncore_imc_init_box,
+       .exit_box       = uncore_mmio_exit_box,
+       .disable_box    = snr_uncore_mmio_disable_box,
+       .enable_box     = snr_uncore_mmio_enable_box,
+       .disable_event  = snr_uncore_mmio_disable_event,
+       .enable_event   = snr_uncore_mmio_enable_event,
+       .read_counter   = uncore_mmio_read_counter,
+};
+
+static struct intel_uncore_type icx_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 4,
+       .num_boxes      = 8,
+       .perf_ctr_bits  = 48,
+       .fixed_ctr_bits = 48,
+       .fixed_ctr      = SNR_IMC_MMIO_PMON_FIXED_CTR,
+       .fixed_ctl      = SNR_IMC_MMIO_PMON_FIXED_CTL,
+       .event_descs    = hswep_uncore_imc_events,
+       .perf_ctr       = SNR_IMC_MMIO_PMON_CTR0,
+       .event_ctl      = SNR_IMC_MMIO_PMON_CTL0,
+       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,
+       .box_ctl        = SNR_IMC_MMIO_PMON_BOX_CTL,
+       .mmio_offset    = SNR_IMC_MMIO_OFFSET,
+       .ops            = &icx_uncore_mmio_ops,
+       .format_group   = &skx_uncore_format_group,
+};
+
+enum perf_uncore_icx_imc_freerunning_type_id {
+       ICX_IMC_DCLK,
+       ICX_IMC_DDR,
+       ICX_IMC_DDRT,
+
+       ICX_IMC_FREERUNNING_TYPE_MAX,
+};
+
+static struct freerunning_counters icx_imc_freerunning[] = {
+       [ICX_IMC_DCLK]  = { 0x22b0, 0x0, 0, 1, 48 },
+       [ICX_IMC_DDR]   = { 0x2290, 0x8, 0, 2, 48 },
+       [ICX_IMC_DDRT]  = { 0x22a0, 0x8, 0, 2, 48 },
+};
+
+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.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.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.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.unit,        "MiB"),
+       { /* end: all zeroes */ },
+};
+
+static void icx_uncore_imc_freerunning_init_box(struct intel_uncore_box *box)
+{
+       int mem_offset = box->pmu->pmu_idx * ICX_IMC_MEM_STRIDE +
+                        SNR_IMC_MMIO_MEM0_OFFSET;
+
+       __snr_uncore_mmio_init_box(box, uncore_mmio_box_ctl(box), mem_offset);
+}
+
+static struct intel_uncore_ops icx_uncore_imc_freerunning_ops = {
+       .init_box       = icx_uncore_imc_freerunning_init_box,
+       .exit_box       = uncore_mmio_exit_box,
+       .read_counter   = uncore_mmio_read_counter,
+       .hw_config      = uncore_freerunning_hw_config,
+};
+
+static struct intel_uncore_type icx_uncore_imc_free_running = {
+       .name                   = "imc_free_running",
+       .num_counters           = 5,
+       .num_boxes              = 4,
+       .num_freerunning_types  = ICX_IMC_FREERUNNING_TYPE_MAX,
+       .freerunning            = icx_imc_freerunning,
+       .ops                    = &icx_uncore_imc_freerunning_ops,
+       .event_descs            = icx_uncore_imc_freerunning_events,
+       .format_group           = &skx_uncore_iio_freerunning_format_group,
+};
+
+static struct intel_uncore_type *icx_mmio_uncores[] = {
+       &icx_uncore_imc,
+       &icx_uncore_imc_free_running,
+       NULL,
+};
+
+void icx_uncore_mmio_init(void)
+{
+       uncore_mmio_uncores = icx_mmio_uncores;
+}
+
+/* end of ICX uncore support */
index b0da532..624f5d9 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 #include <linux/hyperv.h>
 #include <linux/slab.h>
+#include <linux/kernel.h>
 #include <linux/cpuhotplug.h>
 #include <linux/syscore_ops.h>
 #include <clocksource/hyperv_timer.h>
@@ -419,11 +420,14 @@ void hyperv_cleanup(void)
 }
 EXPORT_SYMBOL_GPL(hyperv_cleanup);
 
-void hyperv_report_panic(struct pt_regs *regs, long err)
+void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die)
 {
        static bool panic_reported;
        u64 guest_id;
 
+       if (in_die && !panic_on_oops)
+               return;
+
        /*
         * We prefer to report panic on 'die' chain as we have proper
         * registers to report, but if we miss it (e.g. on BUG()) we need
index ff6f3ca..dd17c2d 100644 (file)
@@ -44,6 +44,7 @@ unsigned int x86_stepping(unsigned int sig);
 extern void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c);
 extern void switch_to_sld(unsigned long tifn);
 extern bool handle_user_split_lock(struct pt_regs *regs, long error_code);
+extern bool handle_guest_split_lock(unsigned long ip);
 #else
 static inline void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c) {}
 static inline void switch_to_sld(unsigned long tifn) {}
@@ -51,5 +52,10 @@ static inline bool handle_user_split_lock(struct pt_regs *regs, long error_code)
 {
        return false;
 }
+
+static inline bool handle_guest_split_lock(unsigned long ip)
+{
+       return false;
+}
 #endif
 #endif /* _ASM_X86_CPU_H */
index f71a0cc..430fca1 100644 (file)
@@ -6,15 +6,6 @@
 #warning "asm/dwarf2.h should be only included in pure assembly files"
 #endif
 
-/*
- * Macros for dwarf2 CFI unwind table entries.
- * See "as.info" for details on these pseudo ops. Unfortunately
- * they are only supported in very new binutils, so define them
- * away for older version.
- */
-
-#ifdef CONFIG_AS_CFI
-
 #define CFI_STARTPROC          .cfi_startproc
 #define CFI_ENDPROC            .cfi_endproc
 #define CFI_DEF_CFA            .cfi_def_cfa
 #define CFI_UNDEFINED          .cfi_undefined
 #define CFI_ESCAPE             .cfi_escape
 
-#ifdef CONFIG_AS_CFI_SIGNAL_FRAME
-#define CFI_SIGNAL_FRAME       .cfi_signal_frame
-#else
-#define CFI_SIGNAL_FRAME
-#endif
-
-#if defined(CONFIG_AS_CFI_SECTIONS) && defined(__ASSEMBLY__)
 #ifndef BUILD_VDSO
        /*
         * Emit CFI data in .debug_frame sections, not .eh_frame sections.
          */
        .cfi_sections .eh_frame, .debug_frame
 #endif
-#endif
-
-#else
-
-/*
- * Due to the structure of pre-exisiting code, don't use assembler line
- * comment character # to ignore the arguments. Instead, use a dummy macro.
- */
-.macro cfi_ignore a=0, b=0, c=0, d=0
-.endm
-
-#define CFI_STARTPROC          cfi_ignore
-#define CFI_ENDPROC            cfi_ignore
-#define CFI_DEF_CFA            cfi_ignore
-#define CFI_DEF_CFA_REGISTER   cfi_ignore
-#define CFI_DEF_CFA_OFFSET     cfi_ignore
-#define CFI_ADJUST_CFA_OFFSET  cfi_ignore
-#define CFI_OFFSET             cfi_ignore
-#define CFI_REL_OFFSET         cfi_ignore
-#define CFI_REGISTER           cfi_ignore
-#define CFI_RESTORE            cfi_ignore
-#define CFI_REMEMBER_STATE     cfi_ignore
-#define CFI_RESTORE_STATE      cfi_ignore
-#define CFI_UNDEFINED          cfi_ignore
-#define CFI_ESCAPE             cfi_ignore
-#define CFI_SIGNAL_FRAME       cfi_ignore
-
-#endif
 
 #endif /* _ASM_X86_DWARF2_H */
index cdcf48d..8391c11 100644 (file)
@@ -178,8 +178,10 @@ extern void efi_free_boot_services(void);
 extern pgd_t * __init efi_uv1_memmap_phys_prolog(void);
 extern void __init efi_uv1_memmap_phys_epilog(pgd_t *save_pgd);
 
+/* kexec external ABI */
 struct efi_setup_data {
        u64 fw_vendor;
+       u64 __unused;
        u64 tables;
        u64 smbios;
        u64 reserved[8];
index c85e150..a506a41 100644 (file)
@@ -35,9 +35,7 @@
 
 #define PAGE_OFFSET            ((unsigned long)__PAGE_OFFSET)
 
-#define VM_DATA_DEFAULT_FLAGS \
-       (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \
-        VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_TSK_EXEC
 
 #define __PHYSICAL_START       ALIGN(CONFIG_PHYSICAL_START, \
                                      CONFIG_PHYSICAL_ALIGN)
@@ -73,9 +71,6 @@ static inline phys_addr_t get_max_mapped(void)
 
 bool pfn_range_is_mapped(unsigned long start_pfn, unsigned long end_pfn);
 
-extern unsigned long init_memory_mapping(unsigned long start,
-                                        unsigned long end);
-
 extern void initmem_init(void);
 
 #endif /* !__ASSEMBLY__ */
index 28838d7..4d02e64 100644 (file)
@@ -860,7 +860,10 @@ static inline unsigned long pmd_index(unsigned long address)
  *
  * this function returns the index of the entry in the pte page which would
  * control the given virtual address
+ *
+ * Also define macro so we can test if pte_index is defined for arch.
  */
+#define pte_index pte_index
 static inline unsigned long pte_index(unsigned long address)
 {
        return (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
@@ -1078,6 +1081,9 @@ static inline void __meminit init_trampoline_default(void)
 
 void __init poking_init(void);
 
+unsigned long init_memory_mapping(unsigned long start,
+                                 unsigned long end, pgprot_t prot);
+
 # ifdef CONFIG_RANDOMIZE_MEMORY
 void __meminit init_trampoline(void);
 # else
index 950532c..ec2c0a0 100644 (file)
@@ -34,6 +34,7 @@
  * The caller is required to take care of these.
  */
 
+int __set_memory_prot(unsigned long addr, int numpages, pgprot_t prot);
 int _set_memory_uc(unsigned long addr, int numpages);
 int _set_memory_wc(unsigned long addr, int numpages);
 int _set_memory_wt(unsigned long addr, int numpages);
index d61ddf3..0c4e5b5 100644 (file)
@@ -11,8 +11,6 @@
  * Based on Ingo Molnar and Zach Brown's respective MMX and SSE routines
  */
 
-#ifdef CONFIG_AS_AVX
-
 #include <linux/compiler.h>
 #include <asm/fpu/api.h>
 
@@ -170,11 +168,4 @@ do { \
 #define AVX_SELECT(FASTEST) \
        (boot_cpu_has(X86_FEATURE_AVX) && boot_cpu_has(X86_FEATURE_OSXSAVE) ? &xor_block_avx : FASTEST)
 
-#else
-
-#define AVX_XOR_SPEED {}
-
-#define AVX_SELECT(FASTEST) (FASTEST)
-
-#endif
 #endif
index 1ae5439..683ed9e 100644 (file)
@@ -45,7 +45,7 @@ EXPORT_SYMBOL(acpi_disabled);
 #define PREFIX                 "ACPI: "
 
 int acpi_noirq;                                /* skip ACPI IRQ initialization */
-int acpi_nobgrt;                       /* skip ACPI BGRT */
+static int acpi_nobgrt;                        /* skip ACPI BGRT */
 int acpi_pci_disabled;         /* skip ACPI PCI scan and IRQ initialization */
 EXPORT_SYMBOL(acpi_pci_disabled);
 
index 4e5f502..1613381 100644 (file)
@@ -744,7 +744,8 @@ int __init gart_iommu_init(void)
 
        start_pfn = PFN_DOWN(aper_base);
        if (!pfn_range_is_mapped(start_pfn, end_pfn))
-               init_memory_mapping(start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
+               init_memory_mapping(start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT,
+                                   PAGE_KERNEL);
 
        pr_info("PCI-DMA: using GART IOMMU.\n");
        iommu_size = check_iommu_size(info.aper_base, aper_size);
index 9a26e97..bf08d45 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/elf.h>
 #include <asm/cpu_device_id.h>
 #include <asm/cmdline.h>
+#include <asm/traps.h>
 
 #ifdef CONFIG_X86_64
 #include <linux/topology.h>
@@ -1066,13 +1067,10 @@ static void split_lock_init(void)
        split_lock_verify_msr(sld_state != sld_off);
 }
 
-bool handle_user_split_lock(struct pt_regs *regs, long error_code)
+static void split_lock_warn(unsigned long ip)
 {
-       if ((regs->flags & X86_EFLAGS_AC) || sld_state == sld_fatal)
-               return false;
-
        pr_warn_ratelimited("#AC: %s/%d took a split_lock trap at address: 0x%lx\n",
-                           current->comm, current->pid, regs->ip);
+                           current->comm, current->pid, ip);
 
        /*
         * Disable the split lock detection for this task so it can make
@@ -1081,6 +1079,31 @@ bool handle_user_split_lock(struct pt_regs *regs, long error_code)
         */
        sld_update_msr(false);
        set_tsk_thread_flag(current, TIF_SLD);
+}
+
+bool handle_guest_split_lock(unsigned long ip)
+{
+       if (sld_state == sld_warn) {
+               split_lock_warn(ip);
+               return true;
+       }
+
+       pr_warn_once("#AC: %s/%d %s split_lock trap at address: 0x%lx\n",
+                    current->comm, current->pid,
+                    sld_state == sld_fatal ? "fatal" : "bogus", ip);
+
+       current->thread.error_code = 0;
+       current->thread.trap_nr = X86_TRAP_AC;
+       force_sig_fault(SIGBUS, BUS_ADRALN, NULL);
+       return false;
+}
+EXPORT_SYMBOL_GPL(handle_guest_split_lock);
+
+bool handle_user_split_lock(struct pt_regs *regs, long error_code)
+{
+       if ((regs->flags & X86_EFLAGS_AC) || sld_state == sld_fatal)
+               return false;
+       split_lock_warn(regs->ip);
        return true;
 }
 
index caa032c..ebf34c7 100644 (file)
@@ -227,8 +227,8 @@ static void __init ms_hyperv_init_platform(void)
        ms_hyperv.misc_features = cpuid_edx(HYPERV_CPUID_FEATURES);
        ms_hyperv.hints    = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO);
 
-       pr_info("Hyper-V: features 0x%x, hints 0x%x\n",
-               ms_hyperv.features, ms_hyperv.hints);
+       pr_info("Hyper-V: features 0x%x, hints 0x%x, misc 0x%x\n",
+               ms_hyperv.features, ms_hyperv.hints, ms_hyperv.misc_features);
 
        ms_hyperv.max_vp_index = cpuid_eax(HYPERV_CPUID_IMPLEMENT_LIMITS);
        ms_hyperv.max_lp_index = cpuid_ebx(HYPERV_CPUID_IMPLEMENT_LIMITS);
@@ -263,6 +263,16 @@ static void __init ms_hyperv_init_platform(void)
                        cpuid_eax(HYPERV_CPUID_NESTED_FEATURES);
        }
 
+       /*
+        * Hyper-V expects to get crash register data or kmsg when
+        * crash enlightment is available and system crashes. Set
+        * crash_kexec_post_notifiers to be true to make sure that
+        * calling crash enlightment interface before running kdump
+        * kernel.
+        */
+       if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE)
+               crash_kexec_post_notifiers = true;
+
 #ifdef CONFIG_X86_LOCAL_APIC
        if (ms_hyperv.features & HV_X64_ACCESS_FREQUENCY_MSRS &&
            ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) {
index e6b5450..4b3fa6c 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/pci.h>
 #include <linux/root_dev.h>
 #include <linux/sfi.h>
+#include <linux/hugetlb.h>
 #include <linux/tboot.h>
 #include <linux/usb/xhci-dbgp.h>
 
@@ -1157,6 +1158,9 @@ void __init setup_arch(char **cmdline_p)
        initmem_init();
        dma_contiguous_reserve(max_pfn_mapped << PAGE_SHIFT);
 
+       if (boot_cpu_has(X86_FEATURE_GBPAGES))
+               hugetlb_cma_reserve(PUD_SHIFT - PAGE_SHIFT);
+
        /*
         * Reserve memory for crash kernel after SRAT is parsed so that it
         * won't consume hotpluggable memory.
index 9fea075..d8154e0 100644 (file)
@@ -107,8 +107,4 @@ config KVM_MMU_AUDIT
         This option adds a R/W kVM module parameter 'mmu_audit', which allows
         auditing of KVM MMU events at runtime.
 
-# OK, it's a little counter-intuitive to do this, but it puts it neatly under
-# the virtualization menu.
-source "drivers/vhost/Kconfig"
-
 endif # VIRTUALIZATION
index e553f0f..a789759 100644 (file)
@@ -14,7 +14,7 @@ kvm-y                 += x86.o emulate.o i8259.o irq.o lapic.o \
                           hyperv.o debugfs.o mmu/mmu.o mmu/page_track.o
 
 kvm-intel-y            += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o vmx/evmcs.o vmx/nested.o
-kvm-amd-y              += svm.o pmu_amd.o
+kvm-amd-y              += svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o svm/sev.o
 
 obj-$(CONFIG_KVM)      += kvm.o
 obj-$(CONFIG_KVM_INTEL)        += kvm-intel.o
index ca80daf..9af25c9 100644 (file)
@@ -59,9 +59,6 @@
 #define MAX_APIC_VECTOR                        256
 #define APIC_VECTORS_PER_REG           32
 
-#define APIC_BROADCAST                 0xFF
-#define X2APIC_BROADCAST               0xFFFFFFFFul
-
 static bool lapic_timer_advance_dynamic __read_mostly;
 #define LAPIC_TIMER_ADVANCE_ADJUST_MIN 100     /* clock cycles */
 #define LAPIC_TIMER_ADVANCE_ADJUST_MAX 10000   /* clock cycles */
index 40ed6ed..a0ffb43 100644 (file)
@@ -17,6 +17,9 @@
 #define APIC_BUS_CYCLE_NS       1
 #define APIC_BUS_FREQUENCY      (1000000000ULL / APIC_BUS_CYCLE_NS)
 
+#define APIC_BROADCAST                 0xFF
+#define X2APIC_BROADCAST               0xFFFFFFFFul
+
 enum lapic_mode {
        LAPIC_MODE_DISABLED = 0,
        LAPIC_MODE_INVALID = X2APIC_ENABLE,
diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
new file mode 100644 (file)
index 0000000..e80daa9
--- /dev/null
@@ -0,0 +1,1027 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * AMD SVM support
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
+ *
+ * Authors:
+ *   Yaniv Kamay  <yaniv@qumranet.com>
+ *   Avi Kivity   <avi@qumranet.com>
+ */
+
+#define pr_fmt(fmt) "SVM: " fmt
+
+#include <linux/kvm_types.h>
+#include <linux/hashtable.h>
+#include <linux/amd-iommu.h>
+#include <linux/kvm_host.h>
+
+#include <asm/irq_remapping.h>
+
+#include "trace.h"
+#include "lapic.h"
+#include "x86.h"
+#include "irq.h"
+#include "svm.h"
+
+/* enable / disable AVIC */
+int avic;
+#ifdef CONFIG_X86_LOCAL_APIC
+module_param(avic, int, S_IRUGO);
+#endif
+
+#define SVM_AVIC_DOORBELL      0xc001011b
+
+#define AVIC_HPA_MASK  ~((0xFFFULL << 52) | 0xFFF)
+
+/*
+ * 0xff is broadcast, so the max index allowed for physical APIC ID
+ * table is 0xfe.  APIC IDs above 0xff are reserved.
+ */
+#define AVIC_MAX_PHYSICAL_ID_COUNT     255
+
+#define AVIC_UNACCEL_ACCESS_WRITE_MASK         1
+#define AVIC_UNACCEL_ACCESS_OFFSET_MASK                0xFF0
+#define AVIC_UNACCEL_ACCESS_VECTOR_MASK                0xFFFFFFFF
+
+/* AVIC GATAG is encoded using VM and VCPU IDs */
+#define AVIC_VCPU_ID_BITS              8
+#define AVIC_VCPU_ID_MASK              ((1 << AVIC_VCPU_ID_BITS) - 1)
+
+#define AVIC_VM_ID_BITS                        24
+#define AVIC_VM_ID_NR                  (1 << AVIC_VM_ID_BITS)
+#define AVIC_VM_ID_MASK                        ((1 << AVIC_VM_ID_BITS) - 1)
+
+#define AVIC_GATAG(x, y)               (((x & AVIC_VM_ID_MASK) << AVIC_VCPU_ID_BITS) | \
+                                               (y & AVIC_VCPU_ID_MASK))
+#define AVIC_GATAG_TO_VMID(x)          ((x >> AVIC_VCPU_ID_BITS) & AVIC_VM_ID_MASK)
+#define AVIC_GATAG_TO_VCPUID(x)                (x & AVIC_VCPU_ID_MASK)
+
+/* Note:
+ * This hash table is used to map VM_ID to a struct kvm_svm,
+ * when handling AMD IOMMU GALOG notification to schedule in
+ * a particular vCPU.
+ */
+#define SVM_VM_DATA_HASH_BITS  8
+static DEFINE_HASHTABLE(svm_vm_data_hash, SVM_VM_DATA_HASH_BITS);
+static u32 next_vm_id = 0;
+static bool next_vm_id_wrapped = 0;
+static DEFINE_SPINLOCK(svm_vm_data_hash_lock);
+
+/*
+ * This is a wrapper of struct amd_iommu_ir_data.
+ */
+struct amd_svm_iommu_ir {
+       struct list_head node;  /* Used by SVM for per-vcpu ir_list */
+       void *data;             /* Storing pointer to struct amd_ir_data */
+};
+
+enum avic_ipi_failure_cause {
+       AVIC_IPI_FAILURE_INVALID_INT_TYPE,
+       AVIC_IPI_FAILURE_TARGET_NOT_RUNNING,
+       AVIC_IPI_FAILURE_INVALID_TARGET,
+       AVIC_IPI_FAILURE_INVALID_BACKING_PAGE,
+};
+
+/* Note:
+ * This function is called from IOMMU driver to notify
+ * SVM to schedule in a particular vCPU of a particular VM.
+ */
+int avic_ga_log_notifier(u32 ga_tag)
+{
+       unsigned long flags;
+       struct kvm_svm *kvm_svm;
+       struct kvm_vcpu *vcpu = NULL;
+       u32 vm_id = AVIC_GATAG_TO_VMID(ga_tag);
+       u32 vcpu_id = AVIC_GATAG_TO_VCPUID(ga_tag);
+
+       pr_debug("SVM: %s: vm_id=%#x, vcpu_id=%#x\n", __func__, vm_id, vcpu_id);
+       trace_kvm_avic_ga_log(vm_id, vcpu_id);
+
+       spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
+       hash_for_each_possible(svm_vm_data_hash, kvm_svm, hnode, vm_id) {
+               if (kvm_svm->avic_vm_id != vm_id)
+                       continue;
+               vcpu = kvm_get_vcpu_by_id(&kvm_svm->kvm, vcpu_id);
+               break;
+       }
+       spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
+
+       /* Note:
+        * At this point, the IOMMU should have already set the pending
+        * bit in the vAPIC backing page. So, we just need to schedule
+        * in the vcpu.
+        */
+       if (vcpu)
+               kvm_vcpu_wake_up(vcpu);
+
+       return 0;
+}
+
+void avic_vm_destroy(struct kvm *kvm)
+{
+       unsigned long flags;
+       struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
+
+       if (!avic)
+               return;
+
+       if (kvm_svm->avic_logical_id_table_page)
+               __free_page(kvm_svm->avic_logical_id_table_page);
+       if (kvm_svm->avic_physical_id_table_page)
+               __free_page(kvm_svm->avic_physical_id_table_page);
+
+       spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
+       hash_del(&kvm_svm->hnode);
+       spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
+}
+
+int avic_vm_init(struct kvm *kvm)
+{
+       unsigned long flags;
+       int err = -ENOMEM;
+       struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
+       struct kvm_svm *k2;
+       struct page *p_page;
+       struct page *l_page;
+       u32 vm_id;
+
+       if (!avic)
+               return 0;
+
+       /* Allocating physical APIC ID table (4KB) */
+       p_page = alloc_page(GFP_KERNEL_ACCOUNT);
+       if (!p_page)
+               goto free_avic;
+
+       kvm_svm->avic_physical_id_table_page = p_page;
+       clear_page(page_address(p_page));
+
+       /* Allocating logical APIC ID table (4KB) */
+       l_page = alloc_page(GFP_KERNEL_ACCOUNT);
+       if (!l_page)
+               goto free_avic;
+
+       kvm_svm->avic_logical_id_table_page = l_page;
+       clear_page(page_address(l_page));
+
+       spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
+ again:
+       vm_id = next_vm_id = (next_vm_id + 1) & AVIC_VM_ID_MASK;
+       if (vm_id == 0) { /* id is 1-based, zero is not okay */
+               next_vm_id_wrapped = 1;
+               goto again;
+       }
+       /* Is it still in use? Only possible if wrapped at least once */
+       if (next_vm_id_wrapped) {
+               hash_for_each_possible(svm_vm_data_hash, k2, hnode, vm_id) {
+                       if (k2->avic_vm_id == vm_id)
+                               goto again;
+               }
+       }
+       kvm_svm->avic_vm_id = vm_id;
+       hash_add(svm_vm_data_hash, &kvm_svm->hnode, kvm_svm->avic_vm_id);
+       spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
+
+       return 0;
+
+free_avic:
+       avic_vm_destroy(kvm);
+       return err;
+}
+
+void avic_init_vmcb(struct vcpu_svm *svm)
+{
+       struct vmcb *vmcb = svm->vmcb;
+       struct kvm_svm *kvm_svm = to_kvm_svm(svm->vcpu.kvm);
+       phys_addr_t bpa = __sme_set(page_to_phys(svm->avic_backing_page));
+       phys_addr_t lpa = __sme_set(page_to_phys(kvm_svm->avic_logical_id_table_page));
+       phys_addr_t ppa = __sme_set(page_to_phys(kvm_svm->avic_physical_id_table_page));
+
+       vmcb->control.avic_backing_page = bpa & AVIC_HPA_MASK;
+       vmcb->control.avic_logical_id = lpa & AVIC_HPA_MASK;
+       vmcb->control.avic_physical_id = ppa & AVIC_HPA_MASK;
+       vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID_COUNT;
+       if (kvm_apicv_activated(svm->vcpu.kvm))
+               vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
+       else
+               vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK;
+}
+
+static u64 *avic_get_physical_id_entry(struct kvm_vcpu *vcpu,
+                                      unsigned int index)
+{
+       u64 *avic_physical_id_table;
+       struct kvm_svm *kvm_svm = to_kvm_svm(vcpu->kvm);
+
+       if (index >= AVIC_MAX_PHYSICAL_ID_COUNT)
+               return NULL;
+
+       avic_physical_id_table = page_address(kvm_svm->avic_physical_id_table_page);
+
+       return &avic_physical_id_table[index];
+}
+
+/**
+ * Note:
+ * AVIC hardware walks the nested page table to check permissions,
+ * but does not use the SPA address specified in the leaf page
+ * table entry since it uses  address in the AVIC_BACKING_PAGE pointer
+ * field of the VMCB. Therefore, we set up the
+ * APIC_ACCESS_PAGE_PRIVATE_MEMSLOT (4KB) here.
+ */
+static int avic_update_access_page(struct kvm *kvm, bool activate)
+{
+       int ret = 0;
+
+       mutex_lock(&kvm->slots_lock);
+       /*
+        * During kvm_destroy_vm(), kvm_pit_set_reinject() could trigger
+        * APICv mode change, which update APIC_ACCESS_PAGE_PRIVATE_MEMSLOT
+        * memory region. So, we need to ensure that kvm->mm == current->mm.
+        */
+       if ((kvm->arch.apic_access_page_done == activate) ||
+           (kvm->mm != current->mm))
+               goto out;
+
+       ret = __x86_set_memory_region(kvm,
+                                     APIC_ACCESS_PAGE_PRIVATE_MEMSLOT,
+                                     APIC_DEFAULT_PHYS_BASE,
+                                     activate ? PAGE_SIZE : 0);
+       if (ret)
+               goto out;
+
+       kvm->arch.apic_access_page_done = activate;
+out:
+       mutex_unlock(&kvm->slots_lock);
+       return ret;
+}
+
+static int avic_init_backing_page(struct kvm_vcpu *vcpu)
+{
+       u64 *entry, new_entry;
+       int id = vcpu->vcpu_id;
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       if (id >= AVIC_MAX_PHYSICAL_ID_COUNT)
+               return -EINVAL;
+
+       if (!svm->vcpu.arch.apic->regs)
+               return -EINVAL;
+
+       if (kvm_apicv_activated(vcpu->kvm)) {
+               int ret;
+
+               ret = avic_update_access_page(vcpu->kvm, true);
+               if (ret)
+                       return ret;
+       }
+
+       svm->avic_backing_page = virt_to_page(svm->vcpu.arch.apic->regs);
+
+       /* Setting AVIC backing page address in the phy APIC ID table */
+       entry = avic_get_physical_id_entry(vcpu, id);
+       if (!entry)
+               return -EINVAL;
+
+       new_entry = __sme_set((page_to_phys(svm->avic_backing_page) &
+                             AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK) |
+                             AVIC_PHYSICAL_ID_ENTRY_VALID_MASK);
+       WRITE_ONCE(*entry, new_entry);
+
+       svm->avic_physical_id_cache = entry;
+
+       return 0;
+}
+
+int avic_incomplete_ipi_interception(struct vcpu_svm *svm)
+{
+       u32 icrh = svm->vmcb->control.exit_info_1 >> 32;
+       u32 icrl = svm->vmcb->control.exit_info_1;
+       u32 id = svm->vmcb->control.exit_info_2 >> 32;
+       u32 index = svm->vmcb->control.exit_info_2 & 0xFF;
+       struct kvm_lapic *apic = svm->vcpu.arch.apic;
+
+       trace_kvm_avic_incomplete_ipi(svm->vcpu.vcpu_id, icrh, icrl, id, index);
+
+       switch (id) {
+       case AVIC_IPI_FAILURE_INVALID_INT_TYPE:
+               /*
+                * AVIC hardware handles the generation of
+                * IPIs when the specified Message Type is Fixed
+                * (also known as fixed delivery mode) and
+                * the Trigger Mode is edge-triggered. The hardware
+                * also supports self and broadcast delivery modes
+                * specified via the Destination Shorthand(DSH)
+                * field of the ICRL. Logical and physical APIC ID
+                * formats are supported. All other IPI types cause
+                * a #VMEXIT, which needs to emulated.
+                */
+               kvm_lapic_reg_write(apic, APIC_ICR2, icrh);
+               kvm_lapic_reg_write(apic, APIC_ICR, icrl);
+               break;
+       case AVIC_IPI_FAILURE_TARGET_NOT_RUNNING: {
+               int i;
+               struct kvm_vcpu *vcpu;
+               struct kvm *kvm = svm->vcpu.kvm;
+               struct kvm_lapic *apic = svm->vcpu.arch.apic;
+
+               /*
+                * At this point, we expect that the AVIC HW has already
+                * set the appropriate IRR bits on the valid target
+                * vcpus. So, we just need to kick the appropriate vcpu.
+                */
+               kvm_for_each_vcpu(i, vcpu, kvm) {
+                       bool m = kvm_apic_match_dest(vcpu, apic,
+                                                    icrl & APIC_SHORT_MASK,
+                                                    GET_APIC_DEST_FIELD(icrh),
+                                                    icrl & APIC_DEST_MASK);
+
+                       if (m && !avic_vcpu_is_running(vcpu))
+                               kvm_vcpu_wake_up(vcpu);
+               }
+               break;
+       }
+       case AVIC_IPI_FAILURE_INVALID_TARGET:
+               WARN_ONCE(1, "Invalid IPI target: index=%u, vcpu=%d, icr=%#0x:%#0x\n",
+                         index, svm->vcpu.vcpu_id, icrh, icrl);
+               break;
+       case AVIC_IPI_FAILURE_INVALID_BACKING_PAGE:
+               WARN_ONCE(1, "Invalid backing page\n");
+               break;
+       default:
+               pr_err("Unknown IPI interception\n");
+       }
+
+       return 1;
+}
+
+static u32 *avic_get_logical_id_entry(struct kvm_vcpu *vcpu, u32 ldr, bool flat)
+{
+       struct kvm_svm *kvm_svm = to_kvm_svm(vcpu->kvm);
+       int index;
+       u32 *logical_apic_id_table;
+       int dlid = GET_APIC_LOGICAL_ID(ldr);
+
+       if (!dlid)
+               return NULL;
+
+       if (flat) { /* flat */
+               index = ffs(dlid) - 1;
+               if (index > 7)
+                       return NULL;
+       } else { /* cluster */
+               int cluster = (dlid & 0xf0) >> 4;
+               int apic = ffs(dlid & 0x0f) - 1;
+
+               if ((apic < 0) || (apic > 7) ||
+                   (cluster >= 0xf))
+                       return NULL;
+               index = (cluster << 2) + apic;
+       }
+
+       logical_apic_id_table = (u32 *) page_address(kvm_svm->avic_logical_id_table_page);
+
+       return &logical_apic_id_table[index];
+}
+
+static int avic_ldr_write(struct kvm_vcpu *vcpu, u8 g_physical_id, u32 ldr)
+{
+       bool flat;
+       u32 *entry, new_entry;
+
+       flat = kvm_lapic_get_reg(vcpu->arch.apic, APIC_DFR) == APIC_DFR_FLAT;
+       entry = avic_get_logical_id_entry(vcpu, ldr, flat);
+       if (!entry)
+               return -EINVAL;
+
+       new_entry = READ_ONCE(*entry);
+       new_entry &= ~AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK;
+       new_entry |= (g_physical_id & AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK);
+       new_entry |= AVIC_LOGICAL_ID_ENTRY_VALID_MASK;
+       WRITE_ONCE(*entry, new_entry);
+
+       return 0;
+}
+
+static void avic_invalidate_logical_id_entry(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       bool flat = svm->dfr_reg == APIC_DFR_FLAT;
+       u32 *entry = avic_get_logical_id_entry(vcpu, svm->ldr_reg, flat);
+
+       if (entry)
+               clear_bit(AVIC_LOGICAL_ID_ENTRY_VALID_BIT, (unsigned long *)entry);
+}
+
+static int avic_handle_ldr_update(struct kvm_vcpu *vcpu)
+{
+       int ret = 0;
+       struct vcpu_svm *svm = to_svm(vcpu);
+       u32 ldr = kvm_lapic_get_reg(vcpu->arch.apic, APIC_LDR);
+       u32 id = kvm_xapic_id(vcpu->arch.apic);
+
+       if (ldr == svm->ldr_reg)
+               return 0;
+
+       avic_invalidate_logical_id_entry(vcpu);
+
+       if (ldr)
+               ret = avic_ldr_write(vcpu, id, ldr);
+
+       if (!ret)
+               svm->ldr_reg = ldr;
+
+       return ret;
+}
+
+static int avic_handle_apic_id_update(struct kvm_vcpu *vcpu)
+{
+       u64 *old, *new;
+       struct vcpu_svm *svm = to_svm(vcpu);
+       u32 id = kvm_xapic_id(vcpu->arch.apic);
+
+       if (vcpu->vcpu_id == id)
+               return 0;
+
+       old = avic_get_physical_id_entry(vcpu, vcpu->vcpu_id);
+       new = avic_get_physical_id_entry(vcpu, id);
+       if (!new || !old)
+               return 1;
+
+       /* We need to move physical_id_entry to new offset */
+       *new = *old;
+       *old = 0ULL;
+       to_svm(vcpu)->avic_physical_id_cache = new;
+
+       /*
+        * Also update the guest physical APIC ID in the logical
+        * APIC ID table entry if already setup the LDR.
+        */
+       if (svm->ldr_reg)
+               avic_handle_ldr_update(vcpu);
+
+       return 0;
+}
+
+static void avic_handle_dfr_update(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       u32 dfr = kvm_lapic_get_reg(vcpu->arch.apic, APIC_DFR);
+
+       if (svm->dfr_reg == dfr)
+               return;
+
+       avic_invalidate_logical_id_entry(vcpu);
+       svm->dfr_reg = dfr;
+}
+
+static int avic_unaccel_trap_write(struct vcpu_svm *svm)
+{
+       struct kvm_lapic *apic = svm->vcpu.arch.apic;
+       u32 offset = svm->vmcb->control.exit_info_1 &
+                               AVIC_UNACCEL_ACCESS_OFFSET_MASK;
+
+       switch (offset) {
+       case APIC_ID:
+               if (avic_handle_apic_id_update(&svm->vcpu))
+                       return 0;
+               break;
+       case APIC_LDR:
+               if (avic_handle_ldr_update(&svm->vcpu))
+                       return 0;
+               break;
+       case APIC_DFR:
+               avic_handle_dfr_update(&svm->vcpu);
+               break;
+       default:
+               break;
+       }
+
+       kvm_lapic_reg_write(apic, offset, kvm_lapic_get_reg(apic, offset));
+
+       return 1;
+}
+
+static bool is_avic_unaccelerated_access_trap(u32 offset)
+{
+       bool ret = false;
+
+       switch (offset) {
+       case APIC_ID:
+       case APIC_EOI:
+       case APIC_RRR:
+       case APIC_LDR:
+       case APIC_DFR:
+       case APIC_SPIV:
+       case APIC_ESR:
+       case APIC_ICR:
+       case APIC_LVTT:
+       case APIC_LVTTHMR:
+       case APIC_LVTPC:
+       case APIC_LVT0:
+       case APIC_LVT1:
+       case APIC_LVTERR:
+       case APIC_TMICT:
+       case APIC_TDCR:
+               ret = true;
+               break;
+       default:
+               break;
+       }
+       return ret;
+}
+
+int avic_unaccelerated_access_interception(struct vcpu_svm *svm)
+{
+       int ret = 0;
+       u32 offset = svm->vmcb->control.exit_info_1 &
+                    AVIC_UNACCEL_ACCESS_OFFSET_MASK;
+       u32 vector = svm->vmcb->control.exit_info_2 &
+                    AVIC_UNACCEL_ACCESS_VECTOR_MASK;
+       bool write = (svm->vmcb->control.exit_info_1 >> 32) &
+                    AVIC_UNACCEL_ACCESS_WRITE_MASK;
+       bool trap = is_avic_unaccelerated_access_trap(offset);
+
+       trace_kvm_avic_unaccelerated_access(svm->vcpu.vcpu_id, offset,
+                                           trap, write, vector);
+       if (trap) {
+               /* Handling Trap */
+               WARN_ONCE(!write, "svm: Handling trap read.\n");
+               ret = avic_unaccel_trap_write(svm);
+       } else {
+               /* Handling Fault */
+               ret = kvm_emulate_instruction(&svm->vcpu, 0);
+       }
+
+       return ret;
+}
+
+int avic_init_vcpu(struct vcpu_svm *svm)
+{
+       int ret;
+       struct kvm_vcpu *vcpu = &svm->vcpu;
+
+       if (!avic || !irqchip_in_kernel(vcpu->kvm))
+               return 0;
+
+       ret = avic_init_backing_page(&svm->vcpu);
+       if (ret)
+               return ret;
+
+       INIT_LIST_HEAD(&svm->ir_list);
+       spin_lock_init(&svm->ir_list_lock);
+       svm->dfr_reg = APIC_DFR_FLAT;
+
+       return ret;
+}
+
+void avic_post_state_restore(struct kvm_vcpu *vcpu)
+{
+       if (avic_handle_apic_id_update(vcpu) != 0)
+               return;
+       avic_handle_dfr_update(vcpu);
+       avic_handle_ldr_update(vcpu);
+}
+
+void svm_toggle_avic_for_irq_window(struct kvm_vcpu *vcpu, bool activate)
+{
+       if (!avic || !lapic_in_kernel(vcpu))
+               return;
+
+       srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
+       kvm_request_apicv_update(vcpu->kvm, activate,
+                                APICV_INHIBIT_REASON_IRQWIN);
+       vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
+}
+
+void svm_set_virtual_apic_mode(struct kvm_vcpu *vcpu)
+{
+       return;
+}
+
+void svm_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr)
+{
+}
+
+void svm_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr)
+{
+}
+
+static int svm_set_pi_irte_mode(struct kvm_vcpu *vcpu, bool activate)
+{
+       int ret = 0;
+       unsigned long flags;
+       struct amd_svm_iommu_ir *ir;
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       if (!kvm_arch_has_assigned_device(vcpu->kvm))
+               return 0;
+
+       /*
+        * Here, we go through the per-vcpu ir_list to update all existing
+        * interrupt remapping table entry targeting this vcpu.
+        */
+       spin_lock_irqsave(&svm->ir_list_lock, flags);
+
+       if (list_empty(&svm->ir_list))
+               goto out;
+
+       list_for_each_entry(ir, &svm->ir_list, node) {
+               if (activate)
+                       ret = amd_iommu_activate_guest_mode(ir->data);
+               else
+                       ret = amd_iommu_deactivate_guest_mode(ir->data);
+               if (ret)
+                       break;
+       }
+out:
+       spin_unlock_irqrestore(&svm->ir_list_lock, flags);
+       return ret;
+}
+
+void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       struct vmcb *vmcb = svm->vmcb;
+       bool activated = kvm_vcpu_apicv_active(vcpu);
+
+       if (!avic)
+               return;
+
+       if (activated) {
+               /**
+                * During AVIC temporary deactivation, guest could update
+                * APIC ID, DFR and LDR registers, which would not be trapped
+                * by avic_unaccelerated_access_interception(). In this case,
+                * we need to check and update the AVIC logical APIC ID table
+                * accordingly before re-activating.
+                */
+               avic_post_state_restore(vcpu);
+               vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
+       } else {
+               vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK;
+       }
+       mark_dirty(vmcb, VMCB_AVIC);
+
+       svm_set_pi_irte_mode(vcpu, activated);
+}
+
+void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
+{
+       return;
+}
+
+int svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec)
+{
+       if (!vcpu->arch.apicv_active)
+               return -1;
+
+       kvm_lapic_set_irr(vec, vcpu->arch.apic);
+       smp_mb__after_atomic();
+
+       if (avic_vcpu_is_running(vcpu)) {
+               int cpuid = vcpu->cpu;
+
+               if (cpuid != get_cpu())
+                       wrmsrl(SVM_AVIC_DOORBELL, kvm_cpu_get_apicid(cpuid));
+               put_cpu();
+       } else
+               kvm_vcpu_wake_up(vcpu);
+
+       return 0;
+}
+
+bool svm_dy_apicv_has_pending_interrupt(struct kvm_vcpu *vcpu)
+{
+       return false;
+}
+
+static void svm_ir_list_del(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi)
+{
+       unsigned long flags;
+       struct amd_svm_iommu_ir *cur;
+
+       spin_lock_irqsave(&svm->ir_list_lock, flags);
+       list_for_each_entry(cur, &svm->ir_list, node) {
+               if (cur->data != pi->ir_data)
+                       continue;
+               list_del(&cur->node);
+               kfree(cur);
+               break;
+       }
+       spin_unlock_irqrestore(&svm->ir_list_lock, flags);
+}
+
+static int svm_ir_list_add(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi)
+{
+       int ret = 0;
+       unsigned long flags;
+       struct amd_svm_iommu_ir *ir;
+
+       /**
+        * In some cases, the existing irte is updaed and re-set,
+        * so we need to check here if it's already been * added
+        * to the ir_list.
+        */
+       if (pi->ir_data && (pi->prev_ga_tag != 0)) {
+               struct kvm *kvm = svm->vcpu.kvm;
+               u32 vcpu_id = AVIC_GATAG_TO_VCPUID(pi->prev_ga_tag);
+               struct kvm_vcpu *prev_vcpu = kvm_get_vcpu_by_id(kvm, vcpu_id);
+               struct vcpu_svm *prev_svm;
+
+               if (!prev_vcpu) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               prev_svm = to_svm(prev_vcpu);
+               svm_ir_list_del(prev_svm, pi);
+       }
+
+       /**
+        * Allocating new amd_iommu_pi_data, which will get
+        * add to the per-vcpu ir_list.
+        */
+       ir = kzalloc(sizeof(struct amd_svm_iommu_ir), GFP_KERNEL_ACCOUNT);
+       if (!ir) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       ir->data = pi->ir_data;
+
+       spin_lock_irqsave(&svm->ir_list_lock, flags);
+       list_add(&ir->node, &svm->ir_list);
+       spin_unlock_irqrestore(&svm->ir_list_lock, flags);
+out:
+       return ret;
+}
+
+/**
+ * Note:
+ * The HW cannot support posting multicast/broadcast
+ * interrupts to a vCPU. So, we still use legacy interrupt
+ * remapping for these kind of interrupts.
+ *
+ * For lowest-priority interrupts, we only support
+ * those with single CPU as the destination, e.g. user
+ * configures the interrupts via /proc/irq or uses
+ * irqbalance to make the interrupts single-CPU.
+ */
+static int
+get_pi_vcpu_info(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *e,
+                struct vcpu_data *vcpu_info, struct vcpu_svm **svm)
+{
+       struct kvm_lapic_irq irq;
+       struct kvm_vcpu *vcpu = NULL;
+
+       kvm_set_msi_irq(kvm, e, &irq);
+
+       if (!kvm_intr_is_single_vcpu(kvm, &irq, &vcpu) ||
+           !kvm_irq_is_postable(&irq)) {
+               pr_debug("SVM: %s: use legacy intr remap mode for irq %u\n",
+                        __func__, irq.vector);
+               return -1;
+       }
+
+       pr_debug("SVM: %s: use GA mode for irq %u\n", __func__,
+                irq.vector);
+       *svm = to_svm(vcpu);
+       vcpu_info->pi_desc_addr = __sme_set(page_to_phys((*svm)->avic_backing_page));
+       vcpu_info->vector = irq.vector;
+
+       return 0;
+}
+
+/*
+ * svm_update_pi_irte - set IRTE for Posted-Interrupts
+ *
+ * @kvm: kvm
+ * @host_irq: host irq of the interrupt
+ * @guest_irq: gsi of the interrupt
+ * @set: set or unset PI
+ * returns 0 on success, < 0 on failure
+ */
+int svm_update_pi_irte(struct kvm *kvm, unsigned int host_irq,
+                      uint32_t guest_irq, bool set)
+{
+       struct kvm_kernel_irq_routing_entry *e;
+       struct kvm_irq_routing_table *irq_rt;
+       int idx, ret = -EINVAL;
+
+       if (!kvm_arch_has_assigned_device(kvm) ||
+           !irq_remapping_cap(IRQ_POSTING_CAP))
+               return 0;
+
+       pr_debug("SVM: %s: host_irq=%#x, guest_irq=%#x, set=%#x\n",
+                __func__, host_irq, guest_irq, set);
+
+       idx = srcu_read_lock(&kvm->irq_srcu);
+       irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
+       WARN_ON(guest_irq >= irq_rt->nr_rt_entries);
+
+       hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) {
+               struct vcpu_data vcpu_info;
+               struct vcpu_svm *svm = NULL;
+
+               if (e->type != KVM_IRQ_ROUTING_MSI)
+                       continue;
+
+               /**
+                * Here, we setup with legacy mode in the following cases:
+                * 1. When cannot target interrupt to a specific vcpu.
+                * 2. Unsetting posted interrupt.
+                * 3. APIC virtialization is disabled for the vcpu.
+                * 4. IRQ has incompatible delivery mode (SMI, INIT, etc)
+                */
+               if (!get_pi_vcpu_info(kvm, e, &vcpu_info, &svm) && set &&
+                   kvm_vcpu_apicv_active(&svm->vcpu)) {
+                       struct amd_iommu_pi_data pi;
+
+                       /* Try to enable guest_mode in IRTE */
+                       pi.base = __sme_set(page_to_phys(svm->avic_backing_page) &
+                                           AVIC_HPA_MASK);
+                       pi.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)->avic_vm_id,
+                                                    svm->vcpu.vcpu_id);
+                       pi.is_guest_mode = true;
+                       pi.vcpu_data = &vcpu_info;
+                       ret = irq_set_vcpu_affinity(host_irq, &pi);
+
+                       /**
+                        * Here, we successfully setting up vcpu affinity in
+                        * IOMMU guest mode. Now, we need to store the posted
+                        * interrupt information in a per-vcpu ir_list so that
+                        * we can reference to them directly when we update vcpu
+                        * scheduling information in IOMMU irte.
+                        */
+                       if (!ret && pi.is_guest_mode)
+                               svm_ir_list_add(svm, &pi);
+               } else {
+                       /* Use legacy mode in IRTE */
+                       struct amd_iommu_pi_data pi;
+
+                       /**
+                        * Here, pi is used to:
+                        * - Tell IOMMU to use legacy mode for this interrupt.
+                        * - Retrieve ga_tag of prior interrupt remapping data.
+                        */
+                       pi.is_guest_mode = false;
+                       ret = irq_set_vcpu_affinity(host_irq, &pi);
+
+                       /**
+                        * Check if the posted interrupt was previously
+                        * setup with the guest_mode by checking if the ga_tag
+                        * was cached. If so, we need to clean up the per-vcpu
+                        * ir_list.
+                        */
+                       if (!ret && pi.prev_ga_tag) {
+                               int id = AVIC_GATAG_TO_VCPUID(pi.prev_ga_tag);
+                               struct kvm_vcpu *vcpu;
+
+                               vcpu = kvm_get_vcpu_by_id(kvm, id);
+                               if (vcpu)
+                                       svm_ir_list_del(to_svm(vcpu), &pi);
+                       }
+               }
+
+               if (!ret && svm) {
+                       trace_kvm_pi_irte_update(host_irq, svm->vcpu.vcpu_id,
+                                                e->gsi, vcpu_info.vector,
+                                                vcpu_info.pi_desc_addr, set);
+               }
+
+               if (ret < 0) {
+                       pr_err("%s: failed to update PI IRTE\n", __func__);
+                       goto out;
+               }
+       }
+
+       ret = 0;
+out:
+       srcu_read_unlock(&kvm->irq_srcu, idx);
+       return ret;
+}
+
+bool svm_check_apicv_inhibit_reasons(ulong bit)
+{
+       ulong supported = BIT(APICV_INHIBIT_REASON_DISABLE) |
+                         BIT(APICV_INHIBIT_REASON_HYPERV) |
+                         BIT(APICV_INHIBIT_REASON_NESTED) |
+                         BIT(APICV_INHIBIT_REASON_IRQWIN) |
+                         BIT(APICV_INHIBIT_REASON_PIT_REINJ) |
+                         BIT(APICV_INHIBIT_REASON_X2APIC);
+
+       return supported & BIT(bit);
+}
+
+void svm_pre_update_apicv_exec_ctrl(struct kvm *kvm, bool activate)
+{
+       avic_update_access_page(kvm, activate);
+}
+
+static inline int
+avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int cpu, bool r)
+{
+       int ret = 0;
+       unsigned long flags;
+       struct amd_svm_iommu_ir *ir;
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       if (!kvm_arch_has_assigned_device(vcpu->kvm))
+               return 0;
+
+       /*
+        * Here, we go through the per-vcpu ir_list to update all existing
+        * interrupt remapping table entry targeting this vcpu.
+        */
+       spin_lock_irqsave(&svm->ir_list_lock, flags);
+
+       if (list_empty(&svm->ir_list))
+               goto out;
+
+       list_for_each_entry(ir, &svm->ir_list, node) {
+               ret = amd_iommu_update_ga(cpu, r, ir->data);
+               if (ret)
+                       break;
+       }
+out:
+       spin_unlock_irqrestore(&svm->ir_list_lock, flags);
+       return ret;
+}
+
+void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+       u64 entry;
+       /* ID = 0xff (broadcast), ID > 0xff (reserved) */
+       int h_physical_id = kvm_cpu_get_apicid(cpu);
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       if (!kvm_vcpu_apicv_active(vcpu))
+               return;
+
+       /*
+        * Since the host physical APIC id is 8 bits,
+        * we can support host APIC ID upto 255.
+        */
+       if (WARN_ON(h_physical_id > AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK))
+               return;
+
+       entry = READ_ONCE(*(svm->avic_physical_id_cache));
+       WARN_ON(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK);
+
+       entry &= ~AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
+       entry |= (h_physical_id & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK);
+
+       entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
+       if (svm->avic_is_running)
+               entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
+
+       WRITE_ONCE(*(svm->avic_physical_id_cache), entry);
+       avic_update_iommu_vcpu_affinity(vcpu, h_physical_id,
+                                       svm->avic_is_running);
+}
+
+void avic_vcpu_put(struct kvm_vcpu *vcpu)
+{
+       u64 entry;
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       if (!kvm_vcpu_apicv_active(vcpu))
+               return;
+
+       entry = READ_ONCE(*(svm->avic_physical_id_cache));
+       if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK)
+               avic_update_iommu_vcpu_affinity(vcpu, -1, 0);
+
+       entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
+       WRITE_ONCE(*(svm->avic_physical_id_cache), entry);
+}
+
+/**
+ * This function is called during VCPU halt/unhalt.
+ */
+static void avic_set_running(struct kvm_vcpu *vcpu, bool is_run)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       svm->avic_is_running = is_run;
+       if (is_run)
+               avic_vcpu_load(vcpu, vcpu->cpu);
+       else
+               avic_vcpu_put(vcpu);
+}
+
+void svm_vcpu_blocking(struct kvm_vcpu *vcpu)
+{
+       avic_set_running(vcpu, false);
+}
+
+void svm_vcpu_unblocking(struct kvm_vcpu *vcpu)
+{
+       if (kvm_check_request(KVM_REQ_APICV_UPDATE, vcpu))
+               kvm_vcpu_update_apicv(vcpu);
+       avic_set_running(vcpu, true);
+}
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
new file mode 100644 (file)
index 0000000..90a1ca9
--- /dev/null
@@ -0,0 +1,823 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * AMD SVM support
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
+ *
+ * Authors:
+ *   Yaniv Kamay  <yaniv@qumranet.com>
+ *   Avi Kivity   <avi@qumranet.com>
+ */
+
+#define pr_fmt(fmt) "SVM: " fmt
+
+#include <linux/kvm_types.h>
+#include <linux/kvm_host.h>
+#include <linux/kernel.h>
+
+#include <asm/msr-index.h>
+
+#include "kvm_emulate.h"
+#include "trace.h"
+#include "mmu.h"
+#include "x86.h"
+#include "svm.h"
+
+static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu,
+                                      struct x86_exception *fault)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       if (svm->vmcb->control.exit_code != SVM_EXIT_NPF) {
+               /*
+                * TODO: track the cause of the nested page fault, and
+                * correctly fill in the high bits of exit_info_1.
+                */
+               svm->vmcb->control.exit_code = SVM_EXIT_NPF;
+               svm->vmcb->control.exit_code_hi = 0;
+               svm->vmcb->control.exit_info_1 = (1ULL << 32);
+               svm->vmcb->control.exit_info_2 = fault->address;
+       }
+
+       svm->vmcb->control.exit_info_1 &= ~0xffffffffULL;
+       svm->vmcb->control.exit_info_1 |= fault->error_code;
+
+       /*
+        * The present bit is always zero for page structure faults on real
+        * hardware.
+        */
+       if (svm->vmcb->control.exit_info_1 & (2ULL << 32))
+               svm->vmcb->control.exit_info_1 &= ~1;
+
+       nested_svm_vmexit(svm);
+}
+
+static u64 nested_svm_get_tdp_pdptr(struct kvm_vcpu *vcpu, int index)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       u64 cr3 = svm->nested.nested_cr3;
+       u64 pdpte;
+       int ret;
+
+       ret = kvm_vcpu_read_guest_page(vcpu, gpa_to_gfn(__sme_clr(cr3)), &pdpte,
+                                      offset_in_page(cr3) + index * 8, 8);
+       if (ret)
+               return 0;
+       return pdpte;
+}
+
+static unsigned long nested_svm_get_tdp_cr3(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       return svm->nested.nested_cr3;
+}
+
+static void nested_svm_init_mmu_context(struct kvm_vcpu *vcpu)
+{
+       WARN_ON(mmu_is_nested(vcpu));
+
+       vcpu->arch.mmu = &vcpu->arch.guest_mmu;
+       kvm_init_shadow_mmu(vcpu);
+       vcpu->arch.mmu->get_guest_pgd     = nested_svm_get_tdp_cr3;
+       vcpu->arch.mmu->get_pdptr         = nested_svm_get_tdp_pdptr;
+       vcpu->arch.mmu->inject_page_fault = nested_svm_inject_npf_exit;
+       vcpu->arch.mmu->shadow_root_level = kvm_x86_ops.get_tdp_level(vcpu);
+       reset_shadow_zero_bits_mask(vcpu, vcpu->arch.mmu);
+       vcpu->arch.walk_mmu              = &vcpu->arch.nested_mmu;
+}
+
+static void nested_svm_uninit_mmu_context(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.mmu = &vcpu->arch.root_mmu;
+       vcpu->arch.walk_mmu = &vcpu->arch.root_mmu;
+}
+
+void recalc_intercepts(struct vcpu_svm *svm)
+{
+       struct vmcb_control_area *c, *h;
+       struct nested_state *g;
+
+       mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
+
+       if (!is_guest_mode(&svm->vcpu))
+               return;
+
+       c = &svm->vmcb->control;
+       h = &svm->nested.hsave->control;
+       g = &svm->nested;
+
+       c->intercept_cr = h->intercept_cr;
+       c->intercept_dr = h->intercept_dr;
+       c->intercept_exceptions = h->intercept_exceptions;
+       c->intercept = h->intercept;
+
+       if (svm->vcpu.arch.hflags & HF_VINTR_MASK) {
+               /* We only want the cr8 intercept bits of L1 */
+               c->intercept_cr &= ~(1U << INTERCEPT_CR8_READ);
+               c->intercept_cr &= ~(1U << INTERCEPT_CR8_WRITE);
+
+               /*
+                * Once running L2 with HF_VINTR_MASK, EFLAGS.IF does not
+                * affect any interrupt we may want to inject; therefore,
+                * interrupt window vmexits are irrelevant to L0.
+                */
+               c->intercept &= ~(1ULL << INTERCEPT_VINTR);
+       }
+
+       /* We don't want to see VMMCALLs from a nested guest */
+       c->intercept &= ~(1ULL << INTERCEPT_VMMCALL);
+
+       c->intercept_cr |= g->intercept_cr;
+       c->intercept_dr |= g->intercept_dr;
+       c->intercept_exceptions |= g->intercept_exceptions;
+       c->intercept |= g->intercept;
+}
+
+static void copy_vmcb_control_area(struct vmcb *dst_vmcb, struct vmcb *from_vmcb)
+{
+       struct vmcb_control_area *dst  = &dst_vmcb->control;
+       struct vmcb_control_area *from = &from_vmcb->control;
+
+       dst->intercept_cr         = from->intercept_cr;
+       dst->intercept_dr         = from->intercept_dr;
+       dst->intercept_exceptions = from->intercept_exceptions;
+       dst->intercept            = from->intercept;
+       dst->iopm_base_pa         = from->iopm_base_pa;
+       dst->msrpm_base_pa        = from->msrpm_base_pa;
+       dst->tsc_offset           = from->tsc_offset;
+       dst->asid                 = from->asid;
+       dst->tlb_ctl              = from->tlb_ctl;
+       dst->int_ctl              = from->int_ctl;
+       dst->int_vector           = from->int_vector;
+       dst->int_state            = from->int_state;
+       dst->exit_code            = from->exit_code;
+       dst->exit_code_hi         = from->exit_code_hi;
+       dst->exit_info_1          = from->exit_info_1;
+       dst->exit_info_2          = from->exit_info_2;
+       dst->exit_int_info        = from->exit_int_info;
+       dst->exit_int_info_err    = from->exit_int_info_err;
+       dst->nested_ctl           = from->nested_ctl;
+       dst->event_inj            = from->event_inj;
+       dst->event_inj_err        = from->event_inj_err;
+       dst->nested_cr3           = from->nested_cr3;
+       dst->virt_ext              = from->virt_ext;
+       dst->pause_filter_count   = from->pause_filter_count;
+       dst->pause_filter_thresh  = from->pause_filter_thresh;
+}
+
+static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
+{
+       /*
+        * This function merges the msr permission bitmaps of kvm and the
+        * nested vmcb. It is optimized in that it only merges the parts where
+        * the kvm msr permission bitmap may contain zero bits
+        */
+       int i;
+
+       if (!(svm->nested.intercept & (1ULL << INTERCEPT_MSR_PROT)))
+               return true;
+
+       for (i = 0; i < MSRPM_OFFSETS; i++) {
+               u32 value, p;
+               u64 offset;
+
+               if (msrpm_offsets[i] == 0xffffffff)
+                       break;
+
+               p      = msrpm_offsets[i];
+               offset = svm->nested.vmcb_msrpm + (p * 4);
+
+               if (kvm_vcpu_read_guest(&svm->vcpu, offset, &value, 4))
+                       return false;
+
+               svm->nested.msrpm[p] = svm->msrpm[p] | value;
+       }
+
+       svm->vmcb->control.msrpm_base_pa = __sme_set(__pa(svm->nested.msrpm));
+
+       return true;
+}
+
+static bool nested_vmcb_checks(struct vmcb *vmcb)
+{
+       if ((vmcb->save.efer & EFER_SVME) == 0)
+               return false;
+
+       if ((vmcb->control.intercept & (1ULL << INTERCEPT_VMRUN)) == 0)
+               return false;
+
+       if (vmcb->control.asid == 0)
+               return false;
+
+       if ((vmcb->control.nested_ctl & SVM_NESTED_CTL_NP_ENABLE) &&
+           !npt_enabled)
+               return false;
+
+       return true;
+}
+
+void enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb_gpa,
+                         struct vmcb *nested_vmcb, struct kvm_host_map *map)
+{
+       bool evaluate_pending_interrupts =
+               is_intercept(svm, INTERCEPT_VINTR) ||
+               is_intercept(svm, INTERCEPT_IRET);
+
+       if (kvm_get_rflags(&svm->vcpu) & X86_EFLAGS_IF)
+               svm->vcpu.arch.hflags |= HF_HIF_MASK;
+       else
+               svm->vcpu.arch.hflags &= ~HF_HIF_MASK;
+
+       if (nested_vmcb->control.nested_ctl & SVM_NESTED_CTL_NP_ENABLE) {
+               svm->nested.nested_cr3 = nested_vmcb->control.nested_cr3;
+               nested_svm_init_mmu_context(&svm->vcpu);
+       }
+
+       /* Load the nested guest state */
+       svm->vmcb->save.es = nested_vmcb->save.es;
+       svm->vmcb->save.cs = nested_vmcb->save.cs;
+       svm->vmcb->save.ss = nested_vmcb->save.ss;
+       svm->vmcb->save.ds = nested_vmcb->save.ds;
+       svm->vmcb->save.gdtr = nested_vmcb->save.gdtr;
+       svm->vmcb->save.idtr = nested_vmcb->save.idtr;
+       kvm_set_rflags(&svm->vcpu, nested_vmcb->save.rflags);
+       svm_set_efer(&svm->vcpu, nested_vmcb->save.efer);
+       svm_set_cr0(&svm->vcpu, nested_vmcb->save.cr0);
+       svm_set_cr4(&svm->vcpu, nested_vmcb->save.cr4);
+       if (npt_enabled) {
+               svm->vmcb->save.cr3 = nested_vmcb->save.cr3;
+               svm->vcpu.arch.cr3 = nested_vmcb->save.cr3;
+       } else
+               (void)kvm_set_cr3(&svm->vcpu, nested_vmcb->save.cr3);
+
+       /* Guest paging mode is active - reset mmu */
+       kvm_mmu_reset_context(&svm->vcpu);
+
+       svm->vmcb->save.cr2 = svm->vcpu.arch.cr2 = nested_vmcb->save.cr2;
+       kvm_rax_write(&svm->vcpu, nested_vmcb->save.rax);
+       kvm_rsp_write(&svm->vcpu, nested_vmcb->save.rsp);
+       kvm_rip_write(&svm->vcpu, nested_vmcb->save.rip);
+
+       /* In case we don't even reach vcpu_run, the fields are not updated */
+       svm->vmcb->save.rax = nested_vmcb->save.rax;
+       svm->vmcb->save.rsp = nested_vmcb->save.rsp;
+       svm->vmcb->save.rip = nested_vmcb->save.rip;
+       svm->vmcb->save.dr7 = nested_vmcb->save.dr7;
+       svm->vmcb->save.dr6 = nested_vmcb->save.dr6;
+       svm->vmcb->save.cpl = nested_vmcb->save.cpl;
+
+       svm->nested.vmcb_msrpm = nested_vmcb->control.msrpm_base_pa & ~0x0fffULL;
+       svm->nested.vmcb_iopm  = nested_vmcb->control.iopm_base_pa  & ~0x0fffULL;
+
+       /* cache intercepts */
+       svm->nested.intercept_cr         = nested_vmcb->control.intercept_cr;
+       svm->nested.intercept_dr         = nested_vmcb->control.intercept_dr;
+       svm->nested.intercept_exceptions = nested_vmcb->control.intercept_exceptions;
+       svm->nested.intercept            = nested_vmcb->control.intercept;
+
+       svm_flush_tlb(&svm->vcpu, true);
+       svm->vmcb->control.int_ctl = nested_vmcb->control.int_ctl | V_INTR_MASKING_MASK;
+       if (nested_vmcb->control.int_ctl & V_INTR_MASKING_MASK)
+               svm->vcpu.arch.hflags |= HF_VINTR_MASK;
+       else
+               svm->vcpu.arch.hflags &= ~HF_VINTR_MASK;
+
+       svm->vcpu.arch.tsc_offset += nested_vmcb->control.tsc_offset;
+       svm->vmcb->control.tsc_offset = svm->vcpu.arch.tsc_offset;
+
+       svm->vmcb->control.virt_ext = nested_vmcb->control.virt_ext;
+       svm->vmcb->control.int_vector = nested_vmcb->control.int_vector;
+       svm->vmcb->control.int_state = nested_vmcb->control.int_state;
+       svm->vmcb->control.event_inj = nested_vmcb->control.event_inj;
+       svm->vmcb->control.event_inj_err = nested_vmcb->control.event_inj_err;
+
+       svm->vmcb->control.pause_filter_count =
+               nested_vmcb->control.pause_filter_count;
+       svm->vmcb->control.pause_filter_thresh =
+               nested_vmcb->control.pause_filter_thresh;
+
+       kvm_vcpu_unmap(&svm->vcpu, map, true);
+
+       /* Enter Guest-Mode */
+       enter_guest_mode(&svm->vcpu);
+
+       /*
+        * Merge guest and host intercepts - must be called  with vcpu in
+        * guest-mode to take affect here
+        */
+       recalc_intercepts(svm);
+
+       svm->nested.vmcb = vmcb_gpa;
+
+       /*
+        * If L1 had a pending IRQ/NMI before executing VMRUN,
+        * which wasn't delivered because it was disallowed (e.g.
+        * interrupts disabled), L0 needs to evaluate if this pending
+        * event should cause an exit from L2 to L1 or be delivered
+        * directly to L2.
+        *
+        * Usually this would be handled by the processor noticing an
+        * IRQ/NMI window request.  However, VMRUN can unblock interrupts
+        * by implicitly setting GIF, so force L0 to perform pending event
+        * evaluation by requesting a KVM_REQ_EVENT.
+        */
+       enable_gif(svm);
+       if (unlikely(evaluate_pending_interrupts))
+               kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
+
+       mark_all_dirty(svm->vmcb);
+}
+
+int nested_svm_vmrun(struct vcpu_svm *svm)
+{
+       int ret;
+       struct vmcb *nested_vmcb;
+       struct vmcb *hsave = svm->nested.hsave;
+       struct vmcb *vmcb = svm->vmcb;
+       struct kvm_host_map map;
+       u64 vmcb_gpa;
+
+       vmcb_gpa = svm->vmcb->save.rax;
+
+       ret = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(vmcb_gpa), &map);
+       if (ret == -EINVAL) {
+               kvm_inject_gp(&svm->vcpu, 0);
+               return 1;
+       } else if (ret) {
+               return kvm_skip_emulated_instruction(&svm->vcpu);
+       }
+
+       ret = kvm_skip_emulated_instruction(&svm->vcpu);
+
+       nested_vmcb = map.hva;
+
+       if (!nested_vmcb_checks(nested_vmcb)) {
+               nested_vmcb->control.exit_code    = SVM_EXIT_ERR;
+               nested_vmcb->control.exit_code_hi = 0;
+               nested_vmcb->control.exit_info_1  = 0;
+               nested_vmcb->control.exit_info_2  = 0;
+
+               kvm_vcpu_unmap(&svm->vcpu, &map, true);
+
+               return ret;
+       }
+
+       trace_kvm_nested_vmrun(svm->vmcb->save.rip, vmcb_gpa,
+                              nested_vmcb->save.rip,
+                              nested_vmcb->control.int_ctl,
+                              nested_vmcb->control.event_inj,
+                              nested_vmcb->control.nested_ctl);
+
+       trace_kvm_nested_intercepts(nested_vmcb->control.intercept_cr & 0xffff,
+                                   nested_vmcb->control.intercept_cr >> 16,
+                                   nested_vmcb->control.intercept_exceptions,
+                                   nested_vmcb->control.intercept);
+
+       /* Clear internal status */
+       kvm_clear_exception_queue(&svm->vcpu);
+       kvm_clear_interrupt_queue(&svm->vcpu);
+
+       /*
+        * Save the old vmcb, so we don't need to pick what we save, but can
+        * restore everything when a VMEXIT occurs
+        */
+       hsave->save.es     = vmcb->save.es;
+       hsave->save.cs     = vmcb->save.cs;
+       hsave->save.ss     = vmcb->save.ss;
+       hsave->save.ds     = vmcb->save.ds;
+       hsave->save.gdtr   = vmcb->save.gdtr;
+       hsave->save.idtr   = vmcb->save.idtr;
+       hsave->save.efer   = svm->vcpu.arch.efer;
+       hsave->save.cr0    = kvm_read_cr0(&svm->vcpu);
+       hsave->save.cr4    = svm->vcpu.arch.cr4;
+       hsave->save.rflags = kvm_get_rflags(&svm->vcpu);
+       hsave->save.rip    = kvm_rip_read(&svm->vcpu);
+       hsave->save.rsp    = vmcb->save.rsp;
+       hsave->save.rax    = vmcb->save.rax;
+       if (npt_enabled)
+               hsave->save.cr3    = vmcb->save.cr3;
+       else
+               hsave->save.cr3    = kvm_read_cr3(&svm->vcpu);
+
+       copy_vmcb_control_area(hsave, vmcb);
+
+       enter_svm_guest_mode(svm, vmcb_gpa, nested_vmcb, &map);
+
+       if (!nested_svm_vmrun_msrpm(svm)) {
+               svm->vmcb->control.exit_code    = SVM_EXIT_ERR;
+               svm->vmcb->control.exit_code_hi = 0;
+               svm->vmcb->control.exit_info_1  = 0;
+               svm->vmcb->control.exit_info_2  = 0;
+
+               nested_svm_vmexit(svm);
+       }
+
+       return ret;
+}
+
+void nested_svm_vmloadsave(struct vmcb *from_vmcb, struct vmcb *to_vmcb)
+{
+       to_vmcb->save.fs = from_vmcb->save.fs;
+       to_vmcb->save.gs = from_vmcb->save.gs;
+       to_vmcb->save.tr = from_vmcb->save.tr;
+       to_vmcb->save.ldtr = from_vmcb->save.ldtr;
+       to_vmcb->save.kernel_gs_base = from_vmcb->save.kernel_gs_base;
+       to_vmcb->save.star = from_vmcb->save.star;
+       to_vmcb->save.lstar = from_vmcb->save.lstar;
+       to_vmcb->save.cstar = from_vmcb->save.cstar;
+       to_vmcb->save.sfmask = from_vmcb->save.sfmask;
+       to_vmcb->save.sysenter_cs = from_vmcb->save.sysenter_cs;
+       to_vmcb->save.sysenter_esp = from_vmcb->save.sysenter_esp;
+       to_vmcb->save.sysenter_eip = from_vmcb->save.sysenter_eip;
+}
+
+int nested_svm_vmexit(struct vcpu_svm *svm)
+{
+       int rc;
+       struct vmcb *nested_vmcb;
+       struct vmcb *hsave = svm->nested.hsave;
+       struct vmcb *vmcb = svm->vmcb;
+       struct kvm_host_map map;
+
+       trace_kvm_nested_vmexit_inject(vmcb->control.exit_code,
+                                      vmcb->control.exit_info_1,
+                                      vmcb->control.exit_info_2,
+                                      vmcb->control.exit_int_info,
+                                      vmcb->control.exit_int_info_err,
+                                      KVM_ISA_SVM);
+
+       rc = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(svm->nested.vmcb), &map);
+       if (rc) {
+               if (rc == -EINVAL)
+                       kvm_inject_gp(&svm->vcpu, 0);
+               return 1;
+       }
+
+       nested_vmcb = map.hva;
+
+       /* Exit Guest-Mode */
+       leave_guest_mode(&svm->vcpu);
+       svm->nested.vmcb = 0;
+
+       /* Give the current vmcb to the guest */
+       disable_gif(svm);
+
+       nested_vmcb->save.es     = vmcb->save.es;
+       nested_vmcb->save.cs     = vmcb->save.cs;
+       nested_vmcb->save.ss     = vmcb->save.ss;
+       nested_vmcb->save.ds     = vmcb->save.ds;
+       nested_vmcb->save.gdtr   = vmcb->save.gdtr;
+       nested_vmcb->save.idtr   = vmcb->save.idtr;
+       nested_vmcb->save.efer   = svm->vcpu.arch.efer;
+       nested_vmcb->save.cr0    = kvm_read_cr0(&svm->vcpu);
+       nested_vmcb->save.cr3    = kvm_read_cr3(&svm->vcpu);
+       nested_vmcb->save.cr2    = vmcb->save.cr2;
+       nested_vmcb->save.cr4    = svm->vcpu.arch.cr4;
+       nested_vmcb->save.rflags = kvm_get_rflags(&svm->vcpu);
+       nested_vmcb->save.rip    = vmcb->save.rip;
+       nested_vmcb->save.rsp    = vmcb->save.rsp;
+       nested_vmcb->save.rax    = vmcb->save.rax;
+       nested_vmcb->save.dr7    = vmcb->save.dr7;
+       nested_vmcb->save.dr6    = vmcb->save.dr6;
+       nested_vmcb->save.cpl    = vmcb->save.cpl;
+
+       nested_vmcb->control.int_ctl           = vmcb->control.int_ctl;
+       nested_vmcb->control.int_vector        = vmcb->control.int_vector;
+       nested_vmcb->control.int_state         = vmcb->control.int_state;
+       nested_vmcb->control.exit_code         = vmcb->control.exit_code;
+       nested_vmcb->control.exit_code_hi      = vmcb->control.exit_code_hi;
+       nested_vmcb->control.exit_info_1       = vmcb->control.exit_info_1;
+       nested_vmcb->control.exit_info_2       = vmcb->control.exit_info_2;
+       nested_vmcb->control.exit_int_info     = vmcb->control.exit_int_info;
+       nested_vmcb->control.exit_int_info_err = vmcb->control.exit_int_info_err;
+
+       if (svm->nrips_enabled)
+               nested_vmcb->control.next_rip  = vmcb->control.next_rip;
+
+       /*
+        * If we emulate a VMRUN/#VMEXIT in the same host #vmexit cycle we have
+        * to make sure that we do not lose injected events. So check event_inj
+        * here and copy it to exit_int_info if it is valid.
+        * Exit_int_info and event_inj can't be both valid because the case
+        * below only happens on a VMRUN instruction intercept which has
+        * no valid exit_int_info set.
+        */
+       if (vmcb->control.event_inj & SVM_EVTINJ_VALID) {
+               struct vmcb_control_area *nc = &nested_vmcb->control;
+
+               nc->exit_int_info     = vmcb->control.event_inj;
+               nc->exit_int_info_err = vmcb->control.event_inj_err;
+       }
+
+       nested_vmcb->control.tlb_ctl           = 0;
+       nested_vmcb->control.event_inj         = 0;
+       nested_vmcb->control.event_inj_err     = 0;
+
+       nested_vmcb->control.pause_filter_count =
+               svm->vmcb->control.pause_filter_count;
+       nested_vmcb->control.pause_filter_thresh =
+               svm->vmcb->control.pause_filter_thresh;
+
+       /* We always set V_INTR_MASKING and remember the old value in hflags */
+       if (!(svm->vcpu.arch.hflags & HF_VINTR_MASK))
+               nested_vmcb->control.int_ctl &= ~V_INTR_MASKING_MASK;
+
+       /* Restore the original control entries */
+       copy_vmcb_control_area(vmcb, hsave);
+
+       svm->vcpu.arch.tsc_offset = svm->vmcb->control.tsc_offset;
+       kvm_clear_exception_queue(&svm->vcpu);
+       kvm_clear_interrupt_queue(&svm->vcpu);
+
+       svm->nested.nested_cr3 = 0;
+
+       /* Restore selected save entries */
+       svm->vmcb->save.es = hsave->save.es;
+       svm->vmcb->save.cs = hsave->save.cs;
+       svm->vmcb->save.ss = hsave->save.ss;
+       svm->vmcb->save.ds = hsave->save.ds;
+       svm->vmcb->save.gdtr = hsave->save.gdtr;
+       svm->vmcb->save.idtr = hsave->save.idtr;
+       kvm_set_rflags(&svm->vcpu, hsave->save.rflags);
+       svm_set_efer(&svm->vcpu, hsave->save.efer);
+       svm_set_cr0(&svm->vcpu, hsave->save.cr0 | X86_CR0_PE);
+       svm_set_cr4(&svm->vcpu, hsave->save.cr4);
+       if (npt_enabled) {
+               svm->vmcb->save.cr3 = hsave->save.cr3;
+               svm->vcpu.arch.cr3 = hsave->save.cr3;
+       } else {
+               (void)kvm_set_cr3(&svm->vcpu, hsave->save.cr3);
+       }
+       kvm_rax_write(&svm->vcpu, hsave->save.rax);
+       kvm_rsp_write(&svm->vcpu, hsave->save.rsp);
+       kvm_rip_write(&svm->vcpu, hsave->save.rip);
+       svm->vmcb->save.dr7 = 0;
+       svm->vmcb->save.cpl = 0;
+       svm->vmcb->control.exit_int_info = 0;
+
+       mark_all_dirty(svm->vmcb);
+
+       kvm_vcpu_unmap(&svm->vcpu, &map, true);
+
+       nested_svm_uninit_mmu_context(&svm->vcpu);
+       kvm_mmu_reset_context(&svm->vcpu);
+       kvm_mmu_load(&svm->vcpu);
+
+       /*
+        * Drop what we picked up for L2 via svm_complete_interrupts() so it
+        * doesn't end up in L1.
+        */
+       svm->vcpu.arch.nmi_injected = false;
+       kvm_clear_exception_queue(&svm->vcpu);
+       kvm_clear_interrupt_queue(&svm->vcpu);
+
+       return 0;
+}
+
+static int nested_svm_exit_handled_msr(struct vcpu_svm *svm)
+{
+       u32 offset, msr, value;
+       int write, mask;
+
+       if (!(svm->nested.intercept & (1ULL << INTERCEPT_MSR_PROT)))
+               return NESTED_EXIT_HOST;
+
+       msr    = svm->vcpu.arch.regs[VCPU_REGS_RCX];
+       offset = svm_msrpm_offset(msr);
+       write  = svm->vmcb->control.exit_info_1 & 1;
+       mask   = 1 << ((2 * (msr & 0xf)) + write);
+
+       if (offset == MSR_INVALID)
+               return NESTED_EXIT_DONE;
+
+       /* Offset is in 32 bit units but need in 8 bit units */
+       offset *= 4;
+
+       if (kvm_vcpu_read_guest(&svm->vcpu, svm->nested.vmcb_msrpm + offset, &value, 4))
+               return NESTED_EXIT_DONE;
+
+       return (value & mask) ? NESTED_EXIT_DONE : NESTED_EXIT_HOST;
+}
+
+/* DB exceptions for our internal use must not cause vmexit */
+static int nested_svm_intercept_db(struct vcpu_svm *svm)
+{
+       unsigned long dr6;
+
+       /* if we're not singlestepping, it's not ours */
+       if (!svm->nmi_singlestep)
+               return NESTED_EXIT_DONE;
+
+       /* if it's not a singlestep exception, it's not ours */
+       if (kvm_get_dr(&svm->vcpu, 6, &dr6))
+               return NESTED_EXIT_DONE;
+       if (!(dr6 & DR6_BS))
+               return NESTED_EXIT_DONE;
+
+       /* if the guest is singlestepping, it should get the vmexit */
+       if (svm->nmi_singlestep_guest_rflags & X86_EFLAGS_TF) {
+               disable_nmi_singlestep(svm);
+               return NESTED_EXIT_DONE;
+       }
+
+       /* it's ours, the nested hypervisor must not see this one */
+       return NESTED_EXIT_HOST;
+}
+
+static int nested_svm_intercept_ioio(struct vcpu_svm *svm)
+{
+       unsigned port, size, iopm_len;
+       u16 val, mask;
+       u8 start_bit;
+       u64 gpa;
+
+       if (!(svm->nested.intercept & (1ULL << INTERCEPT_IOIO_PROT)))
+               return NESTED_EXIT_HOST;
+
+       port = svm->vmcb->control.exit_info_1 >> 16;
+       size = (svm->vmcb->control.exit_info_1 & SVM_IOIO_SIZE_MASK) >>
+               SVM_IOIO_SIZE_SHIFT;
+       gpa  = svm->nested.vmcb_iopm + (port / 8);
+       start_bit = port % 8;
+       iopm_len = (start_bit + size > 8) ? 2 : 1;
+       mask = (0xf >> (4 - size)) << start_bit;
+       val = 0;
+
+       if (kvm_vcpu_read_guest(&svm->vcpu, gpa, &val, iopm_len))
+               return NESTED_EXIT_DONE;
+
+       return (val & mask) ? NESTED_EXIT_DONE : NESTED_EXIT_HOST;
+}
+
+static int nested_svm_intercept(struct vcpu_svm *svm)
+{
+       u32 exit_code = svm->vmcb->control.exit_code;
+       int vmexit = NESTED_EXIT_HOST;
+
+       switch (exit_code) {
+       case SVM_EXIT_MSR:
+               vmexit = nested_svm_exit_handled_msr(svm);
+               break;
+       case SVM_EXIT_IOIO:
+               vmexit = nested_svm_intercept_ioio(svm);
+               break;
+       case SVM_EXIT_READ_CR0 ... SVM_EXIT_WRITE_CR8: {
+               u32 bit = 1U << (exit_code - SVM_EXIT_READ_CR0);
+               if (svm->nested.intercept_cr & bit)
+                       vmexit = NESTED_EXIT_DONE;
+               break;
+       }
+       case SVM_EXIT_READ_DR0 ... SVM_EXIT_WRITE_DR7: {
+               u32 bit = 1U << (exit_code - SVM_EXIT_READ_DR0);
+               if (svm->nested.intercept_dr & bit)
+                       vmexit = NESTED_EXIT_DONE;
+               break;
+       }
+       case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 0x1f: {
+               u32 excp_bits = 1 << (exit_code - SVM_EXIT_EXCP_BASE);
+               if (svm->nested.intercept_exceptions & excp_bits) {
+                       if (exit_code == SVM_EXIT_EXCP_BASE + DB_VECTOR)
+                               vmexit = nested_svm_intercept_db(svm);
+                       else
+                               vmexit = NESTED_EXIT_DONE;
+               }
+               /* async page fault always cause vmexit */
+               else if ((exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR) &&
+                        svm->vcpu.arch.exception.nested_apf != 0)
+                       vmexit = NESTED_EXIT_DONE;
+               break;
+       }
+       case SVM_EXIT_ERR: {
+               vmexit = NESTED_EXIT_DONE;
+               break;
+       }
+       default: {
+               u64 exit_bits = 1ULL << (exit_code - SVM_EXIT_INTR);
+               if (svm->nested.intercept & exit_bits)
+                       vmexit = NESTED_EXIT_DONE;
+       }
+       }
+
+       return vmexit;
+}
+
+int nested_svm_exit_handled(struct vcpu_svm *svm)
+{
+       int vmexit;
+
+       vmexit = nested_svm_intercept(svm);
+
+       if (vmexit == NESTED_EXIT_DONE)
+               nested_svm_vmexit(svm);
+
+       return vmexit;
+}
+
+int nested_svm_check_permissions(struct vcpu_svm *svm)
+{
+       if (!(svm->vcpu.arch.efer & EFER_SVME) ||
+           !is_paging(&svm->vcpu)) {
+               kvm_queue_exception(&svm->vcpu, UD_VECTOR);
+               return 1;
+       }
+
+       if (svm->vmcb->save.cpl) {
+               kvm_inject_gp(&svm->vcpu, 0);
+               return 1;
+       }
+
+       return 0;
+}
+
+int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
+                              bool has_error_code, u32 error_code)
+{
+       int vmexit;
+
+       if (!is_guest_mode(&svm->vcpu))
+               return 0;
+
+       vmexit = nested_svm_intercept(svm);
+       if (vmexit != NESTED_EXIT_DONE)
+               return 0;
+
+       svm->vmcb->control.exit_code = SVM_EXIT_EXCP_BASE + nr;
+       svm->vmcb->control.exit_code_hi = 0;
+       svm->vmcb->control.exit_info_1 = error_code;
+
+       /*
+        * EXITINFO2 is undefined for all exception intercepts other
+        * than #PF.
+        */
+       if (svm->vcpu.arch.exception.nested_apf)
+               svm->vmcb->control.exit_info_2 = svm->vcpu.arch.apf.nested_apf_token;
+       else if (svm->vcpu.arch.exception.has_payload)
+               svm->vmcb->control.exit_info_2 = svm->vcpu.arch.exception.payload;
+       else
+               svm->vmcb->control.exit_info_2 = svm->vcpu.arch.cr2;
+
+       svm->nested.exit_required = true;
+       return vmexit;
+}
+
+static void nested_svm_intr(struct vcpu_svm *svm)
+{
+       svm->vmcb->control.exit_code   = SVM_EXIT_INTR;
+       svm->vmcb->control.exit_info_1 = 0;
+       svm->vmcb->control.exit_info_2 = 0;
+
+       /* nested_svm_vmexit this gets called afterwards from handle_exit */
+       svm->nested.exit_required = true;
+       trace_kvm_nested_intr_vmexit(svm->vmcb->save.rip);
+}
+
+static bool nested_exit_on_intr(struct vcpu_svm *svm)
+{
+       return (svm->nested.intercept & 1ULL);
+}
+
+int svm_check_nested_events(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       bool block_nested_events =
+               kvm_event_needs_reinjection(vcpu) || svm->nested.exit_required;
+
+       if (kvm_cpu_has_interrupt(vcpu) && nested_exit_on_intr(svm)) {
+               if (block_nested_events)
+                       return -EBUSY;
+               nested_svm_intr(svm);
+               return 0;
+       }
+
+       return 0;
+}
+
+int nested_svm_exit_special(struct vcpu_svm *svm)
+{
+       u32 exit_code = svm->vmcb->control.exit_code;
+
+       switch (exit_code) {
+       case SVM_EXIT_INTR:
+       case SVM_EXIT_NMI:
+       case SVM_EXIT_EXCP_BASE + MC_VECTOR:
+               return NESTED_EXIT_HOST;
+       case SVM_EXIT_NPF:
+               /* For now we are always handling NPFs when using them */
+               if (npt_enabled)
+                       return NESTED_EXIT_HOST;
+               break;
+       case SVM_EXIT_EXCP_BASE + PF_VECTOR:
+               /* When we're shadowing, trap PFs, but not async PF */
+               if (!npt_enabled && svm->vcpu.arch.apf.host_apf_reason == 0)
+                       return NESTED_EXIT_HOST;
+               break;
+       default:
+               break;
+       }
+
+       return NESTED_EXIT_CONTINUE;
+}
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
new file mode 100644 (file)
index 0000000..0e3fc31
--- /dev/null
@@ -0,0 +1,1187 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * AMD SVM-SEV support
+ *
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
+ */
+
+#include <linux/kvm_types.h>
+#include <linux/kvm_host.h>
+#include <linux/kernel.h>
+#include <linux/highmem.h>
+#include <linux/psp-sev.h>
+#include <linux/swap.h>
+
+#include "x86.h"
+#include "svm.h"
+
+static int sev_flush_asids(void);
+static DECLARE_RWSEM(sev_deactivate_lock);
+static DEFINE_MUTEX(sev_bitmap_lock);
+unsigned int max_sev_asid;
+static unsigned int min_sev_asid;
+static unsigned long *sev_asid_bitmap;
+static unsigned long *sev_reclaim_asid_bitmap;
+#define __sme_page_pa(x) __sme_set(page_to_pfn(x) << PAGE_SHIFT)
+
+struct enc_region {
+       struct list_head list;
+       unsigned long npages;
+       struct page **pages;
+       unsigned long uaddr;
+       unsigned long size;
+};
+
+static int sev_flush_asids(void)
+{
+       int ret, error = 0;
+
+       /*
+        * DEACTIVATE will clear the WBINVD indicator causing DF_FLUSH to fail,
+        * so it must be guarded.
+        */
+       down_write(&sev_deactivate_lock);
+
+       wbinvd_on_all_cpus();
+       ret = sev_guest_df_flush(&error);
+
+       up_write(&sev_deactivate_lock);
+
+       if (ret)
+               pr_err("SEV: DF_FLUSH failed, ret=%d, error=%#x\n", ret, error);
+
+       return ret;
+}
+
+/* Must be called with the sev_bitmap_lock held */
+static bool __sev_recycle_asids(void)
+{
+       int pos;
+
+       /* Check if there are any ASIDs to reclaim before performing a flush */
+       pos = find_next_bit(sev_reclaim_asid_bitmap,
+                           max_sev_asid, min_sev_asid - 1);
+       if (pos >= max_sev_asid)
+               return false;
+
+       if (sev_flush_asids())
+               return false;
+
+       bitmap_xor(sev_asid_bitmap, sev_asid_bitmap, sev_reclaim_asid_bitmap,
+                  max_sev_asid);
+       bitmap_zero(sev_reclaim_asid_bitmap, max_sev_asid);
+
+       return true;
+}
+
+static int sev_asid_new(void)
+{
+       bool retry = true;
+       int pos;
+
+       mutex_lock(&sev_bitmap_lock);
+
+       /*
+        * SEV-enabled guest must use asid from min_sev_asid to max_sev_asid.
+        */
+again:
+       pos = find_next_zero_bit(sev_asid_bitmap, max_sev_asid, min_sev_asid - 1);
+       if (pos >= max_sev_asid) {
+               if (retry && __sev_recycle_asids()) {
+                       retry = false;
+                       goto again;
+               }
+               mutex_unlock(&sev_bitmap_lock);
+               return -EBUSY;
+       }
+
+       __set_bit(pos, sev_asid_bitmap);
+
+       mutex_unlock(&sev_bitmap_lock);
+
+       return pos + 1;
+}
+
+static int sev_get_asid(struct kvm *kvm)
+{
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+
+       return sev->asid;
+}
+
+static void sev_asid_free(int asid)
+{
+       struct svm_cpu_data *sd;
+       int cpu, pos;
+
+       mutex_lock(&sev_bitmap_lock);
+
+       pos = asid - 1;
+       __set_bit(pos, sev_reclaim_asid_bitmap);
+
+       for_each_possible_cpu(cpu) {
+               sd = per_cpu(svm_data, cpu);
+               sd->sev_vmcbs[pos] = NULL;
+       }
+
+       mutex_unlock(&sev_bitmap_lock);
+}
+
+static void sev_unbind_asid(struct kvm *kvm, unsigned int handle)
+{
+       struct sev_data_decommission *decommission;
+       struct sev_data_deactivate *data;
+
+       if (!handle)
+               return;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return;
+
+       /* deactivate handle */
+       data->handle = handle;
+
+       /* Guard DEACTIVATE against WBINVD/DF_FLUSH used in ASID recycling */
+       down_read(&sev_deactivate_lock);
+       sev_guest_deactivate(data, NULL);
+       up_read(&sev_deactivate_lock);
+
+       kfree(data);
+
+       decommission = kzalloc(sizeof(*decommission), GFP_KERNEL);
+       if (!decommission)
+               return;
+
+       /* decommission handle */
+       decommission->handle = handle;
+       sev_guest_decommission(decommission, NULL);
+
+       kfree(decommission);
+}
+
+static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
+{
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+       int asid, ret;
+
+       ret = -EBUSY;
+       if (unlikely(sev->active))
+               return ret;
+
+       asid = sev_asid_new();
+       if (asid < 0)
+               return ret;
+
+       ret = sev_platform_init(&argp->error);
+       if (ret)
+               goto e_free;
+
+       sev->active = true;
+       sev->asid = asid;
+       INIT_LIST_HEAD(&sev->regions_list);
+
+       return 0;
+
+e_free:
+       sev_asid_free(asid);
+       return ret;
+}
+
+static int sev_bind_asid(struct kvm *kvm, unsigned int handle, int *error)
+{
+       struct sev_data_activate *data;
+       int asid = sev_get_asid(kvm);
+       int ret;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
+       if (!data)
+               return -ENOMEM;
+
+       /* activate ASID on the given handle */
+       data->handle = handle;
+       data->asid   = asid;
+       ret = sev_guest_activate(data, error);
+       kfree(data);
+
+       return ret;
+}
+
+static int __sev_issue_cmd(int fd, int id, void *data, int *error)
+{
+       struct fd f;
+       int ret;
+
+       f = fdget(fd);
+       if (!f.file)
+               return -EBADF;
+
+       ret = sev_issue_cmd_external_user(f.file, id, data, error);
+
+       fdput(f);
+       return ret;
+}
+
+static int sev_issue_cmd(struct kvm *kvm, int id, void *data, int *error)
+{
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+
+       return __sev_issue_cmd(sev->fd, id, data, error);
+}
+
+static int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
+{
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+       struct sev_data_launch_start *start;
+       struct kvm_sev_launch_start params;
+       void *dh_blob, *session_blob;
+       int *error = &argp->error;
+       int ret;
+
+       if (!sev_guest(kvm))
+               return -ENOTTY;
+
+       if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
+               return -EFAULT;
+
+       start = kzalloc(sizeof(*start), GFP_KERNEL_ACCOUNT);
+       if (!start)
+               return -ENOMEM;
+
+       dh_blob = NULL;
+       if (params.dh_uaddr) {
+               dh_blob = psp_copy_user_blob(params.dh_uaddr, params.dh_len);
+               if (IS_ERR(dh_blob)) {
+                       ret = PTR_ERR(dh_blob);
+                       goto e_free;
+               }
+
+               start->dh_cert_address = __sme_set(__pa(dh_blob));
+               start->dh_cert_len = params.dh_len;
+       }
+
+       session_blob = NULL;
+       if (params.session_uaddr) {
+               session_blob = psp_copy_user_blob(params.session_uaddr, params.session_len);
+               if (IS_ERR(session_blob)) {
+                       ret = PTR_ERR(session_blob);
+                       goto e_free_dh;
+               }
+
+               start->session_address = __sme_set(__pa(session_blob));
+               start->session_len = params.session_len;
+       }
+
+       start->handle = params.handle;
+       start->policy = params.policy;
+
+       /* create memory encryption context */
+       ret = __sev_issue_cmd(argp->sev_fd, SEV_CMD_LAUNCH_START, start, error);
+       if (ret)
+               goto e_free_session;
+
+       /* Bind ASID to this guest */
+       ret = sev_bind_asid(kvm, start->handle, error);
+       if (ret)
+               goto e_free_session;
+
+       /* return handle to userspace */
+       params.handle = start->handle;
+       if (copy_to_user((void __user *)(uintptr_t)argp->data, &params, sizeof(params))) {
+               sev_unbind_asid(kvm, start->handle);
+               ret = -EFAULT;
+               goto e_free_session;
+       }
+
+       sev->handle = start->handle;
+       sev->fd = argp->sev_fd;
+
+e_free_session:
+       kfree(session_blob);
+e_free_dh:
+       kfree(dh_blob);
+e_free:
+       kfree(start);
+       return ret;
+}
+
+static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
+                                   unsigned long ulen, unsigned long *n,
+                                   int write)
+{
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+       unsigned long npages, npinned, size;
+       unsigned long locked, lock_limit;
+       struct page **pages;
+       unsigned long first, last;
+
+       if (ulen == 0 || uaddr + ulen < uaddr)
+               return NULL;
+
+       /* Calculate number of pages. */
+       first = (uaddr & PAGE_MASK) >> PAGE_SHIFT;
+       last = ((uaddr + ulen - 1) & PAGE_MASK) >> PAGE_SHIFT;
+       npages = (last - first + 1);
+
+       locked = sev->pages_locked + npages;
+       lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+       if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
+               pr_err("SEV: %lu locked pages exceed the lock limit of %lu.\n", locked, lock_limit);
+               return NULL;
+       }
+
+       /* Avoid using vmalloc for smaller buffers. */
+       size = npages * sizeof(struct page *);
+       if (size > PAGE_SIZE)
+               pages = __vmalloc(size, GFP_KERNEL_ACCOUNT | __GFP_ZERO,
+                                 PAGE_KERNEL);
+       else
+               pages = kmalloc(size, GFP_KERNEL_ACCOUNT);
+
+       if (!pages)
+               return NULL;
+
+       /* Pin the user virtual address. */
+       npinned = get_user_pages_fast(uaddr, npages, FOLL_WRITE, pages);
+       if (npinned != npages) {
+               pr_err("SEV: Failure locking %lu pages.\n", npages);
+               goto err;
+       }
+
+       *n = npages;
+       sev->pages_locked = locked;
+
+       return pages;
+
+err:
+       if (npinned > 0)
+               release_pages(pages, npinned);
+
+       kvfree(pages);
+       return NULL;
+}
+
+static void sev_unpin_memory(struct kvm *kvm, struct page **pages,
+                            unsigned long npages)
+{
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+
+       release_pages(pages, npages);
+       kvfree(pages);
+       sev->pages_locked -= npages;
+}
+
+static void sev_clflush_pages(struct page *pages[], unsigned long npages)
+{
+       uint8_t *page_virtual;
+       unsigned long i;
+
+       if (npages == 0 || pages == NULL)
+               return;
+
+       for (i = 0; i < npages; i++) {
+               page_virtual = kmap_atomic(pages[i]);
+               clflush_cache_range(page_virtual, PAGE_SIZE);
+               kunmap_atomic(page_virtual);
+       }
+}
+
+static unsigned long get_num_contig_pages(unsigned long idx,
+                               struct page **inpages, unsigned long npages)
+{
+       unsigned long paddr, next_paddr;
+       unsigned long i = idx + 1, pages = 1;
+
+       /* find the number of contiguous pages starting from idx */
+       paddr = __sme_page_pa(inpages[idx]);
+       while (i < npages) {
+               next_paddr = __sme_page_pa(inpages[i++]);
+               if ((paddr + PAGE_SIZE) == next_paddr) {
+                       pages++;
+                       paddr = next_paddr;
+                       continue;
+               }
+               break;
+       }
+
+       return pages;
+}
+
+static int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
+{
+       unsigned long vaddr, vaddr_end, next_vaddr, npages, pages, size, i;
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+       struct kvm_sev_launch_update_data params;
+       struct sev_data_launch_update_data *data;
+       struct page **inpages;
+       int ret;
+
+       if (!sev_guest(kvm))
+               return -ENOTTY;
+
+       if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
+               return -EFAULT;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
+       if (!data)
+               return -ENOMEM;
+
+       vaddr = params.uaddr;
+       size = params.len;
+       vaddr_end = vaddr + size;
+
+       /* Lock the user memory. */
+       inpages = sev_pin_memory(kvm, vaddr, size, &npages, 1);
+       if (!inpages) {
+               ret = -ENOMEM;
+               goto e_free;
+       }
+
+       /*
+        * The LAUNCH_UPDATE command will perform in-place encryption of the
+        * memory content (i.e it will write the same memory region with C=1).
+        * It's possible that the cache may contain the data with C=0, i.e.,
+        * unencrypted so invalidate it first.
+        */
+       sev_clflush_pages(inpages, npages);
+
+       for (i = 0; vaddr < vaddr_end; vaddr = next_vaddr, i += pages) {
+               int offset, len;
+
+               /*
+                * If the user buffer is not page-aligned, calculate the offset
+                * within the page.
+                */
+               offset = vaddr & (PAGE_SIZE - 1);
+
+               /* Calculate the number of pages that can be encrypted in one go. */
+               pages = get_num_contig_pages(i, inpages, npages);
+
+               len = min_t(size_t, ((pages * PAGE_SIZE) - offset), size);
+
+               data->handle = sev->handle;
+               data->len = len;
+               data->address = __sme_page_pa(inpages[i]) + offset;
+               ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_DATA, data, &argp->error);
+               if (ret)
+                       goto e_unpin;
+
+               size -= len;
+               next_vaddr = vaddr + len;
+       }
+
+e_unpin:
+       /* content of memory is updated, mark pages dirty */
+       for (i = 0; i < npages; i++) {
+               set_page_dirty_lock(inpages[i]);
+               mark_page_accessed(inpages[i]);
+       }
+       /* unlock the user pages */
+       sev_unpin_memory(kvm, inpages, npages);
+e_free:
+       kfree(data);
+       return ret;
+}
+
+static int sev_launch_measure(struct kvm *kvm, struct kvm_sev_cmd *argp)
+{
+       void __user *measure = (void __user *)(uintptr_t)argp->data;
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+       struct sev_data_launch_measure *data;
+       struct kvm_sev_launch_measure params;
+       void __user *p = NULL;
+       void *blob = NULL;
+       int ret;
+
+       if (!sev_guest(kvm))
+               return -ENOTTY;
+
+       if (copy_from_user(&params, measure, sizeof(params)))
+               return -EFAULT;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
+       if (!data)
+               return -ENOMEM;
+
+       /* User wants to query the blob length */
+       if (!params.len)
+               goto cmd;
+
+       p = (void __user *)(uintptr_t)params.uaddr;
+       if (p) {
+               if (params.len > SEV_FW_BLOB_MAX_SIZE) {
+                       ret = -EINVAL;
+                       goto e_free;
+               }
+
+               ret = -ENOMEM;
+               blob = kmalloc(params.len, GFP_KERNEL);
+               if (!blob)
+                       goto e_free;
+
+               data->address = __psp_pa(blob);
+               data->len = params.len;
+       }
+
+cmd:
+       data->handle = sev->handle;
+       ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_MEASURE, data, &argp->error);
+
+       /*
+        * If we query the session length, FW responded with expected data.
+        */
+       if (!params.len)
+               goto done;
+
+       if (ret)
+               goto e_free_blob;
+
+       if (blob) {
+               if (copy_to_user(p, blob, params.len))
+                       ret = -EFAULT;
+       }
+
+done:
+       params.len = data->len;
+       if (copy_to_user(measure, &params, sizeof(params)))
+               ret = -EFAULT;
+e_free_blob:
+       kfree(blob);
+e_free:
+       kfree(data);
+       return ret;
+}
+
+static int sev_launch_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
+{
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+       struct sev_data_launch_finish *data;
+       int ret;
+
+       if (!sev_guest(kvm))
+               return -ENOTTY;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
+       if (!data)
+               return -ENOMEM;
+
+       data->handle = sev->handle;
+       ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_FINISH, data, &argp->error);
+
+       kfree(data);
+       return ret;
+}
+
+static int sev_guest_status(struct kvm *kvm, struct kvm_sev_cmd *argp)
+{
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+       struct kvm_sev_guest_status params;
+       struct sev_data_guest_status *data;
+       int ret;
+
+       if (!sev_guest(kvm))
+               return -ENOTTY;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
+       if (!data)
+               return -ENOMEM;
+
+       data->handle = sev->handle;
+       ret = sev_issue_cmd(kvm, SEV_CMD_GUEST_STATUS, data, &argp->error);
+       if (ret)
+               goto e_free;
+
+       params.policy = data->policy;
+       params.state = data->state;
+       params.handle = data->handle;
+
+       if (copy_to_user((void __user *)(uintptr_t)argp->data, &params, sizeof(params)))
+               ret = -EFAULT;
+e_free:
+       kfree(data);
+       return ret;
+}
+
+static int __sev_issue_dbg_cmd(struct kvm *kvm, unsigned long src,
+                              unsigned long dst, int size,
+                              int *error, bool enc)
+{
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+       struct sev_data_dbg *data;
+       int ret;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
+       if (!data)
+               return -ENOMEM;
+
+       data->handle = sev->handle;
+       data->dst_addr = dst;
+       data->src_addr = src;
+       data->len = size;
+
+       ret = sev_issue_cmd(kvm,
+                           enc ? SEV_CMD_DBG_ENCRYPT : SEV_CMD_DBG_DECRYPT,
+                           data, error);
+       kfree(data);
+       return ret;
+}
+
+static int __sev_dbg_decrypt(struct kvm *kvm, unsigned long src_paddr,
+                            unsigned long dst_paddr, int sz, int *err)
+{
+       int offset;
+
+       /*
+        * Its safe to read more than we are asked, caller should ensure that
+        * destination has enough space.
+        */
+       src_paddr = round_down(src_paddr, 16);
+       offset = src_paddr & 15;
+       sz = round_up(sz + offset, 16);
+
+       return __sev_issue_dbg_cmd(kvm, src_paddr, dst_paddr, sz, err, false);
+}
+
+static int __sev_dbg_decrypt_user(struct kvm *kvm, unsigned long paddr,
+                                 unsigned long __user dst_uaddr,
+                                 unsigned long dst_paddr,
+                                 int size, int *err)
+{
+       struct page *tpage = NULL;
+       int ret, offset;
+
+       /* if inputs are not 16-byte then use intermediate buffer */
+       if (!IS_ALIGNED(dst_paddr, 16) ||
+           !IS_ALIGNED(paddr,     16) ||
+           !IS_ALIGNED(size,      16)) {
+               tpage = (void *)alloc_page(GFP_KERNEL);
+               if (!tpage)
+                       return -ENOMEM;
+
+               dst_paddr = __sme_page_pa(tpage);
+       }
+
+       ret = __sev_dbg_decrypt(kvm, paddr, dst_paddr, size, err);
+       if (ret)
+               goto e_free;
+
+       if (tpage) {
+               offset = paddr & 15;
+               if (copy_to_user((void __user *)(uintptr_t)dst_uaddr,
+                                page_address(tpage) + offset, size))
+                       ret = -EFAULT;
+       }
+
+e_free:
+       if (tpage)
+               __free_page(tpage);
+
+       return ret;
+}
+
+static int __sev_dbg_encrypt_user(struct kvm *kvm, unsigned long paddr,
+                                 unsigned long __user vaddr,
+                                 unsigned long dst_paddr,
+                                 unsigned long __user dst_vaddr,
+                                 int size, int *error)
+{
+       struct page *src_tpage = NULL;
+       struct page *dst_tpage = NULL;
+       int ret, len = size;
+
+       /* If source buffer is not aligned then use an intermediate buffer */
+       if (!IS_ALIGNED(vaddr, 16)) {
+               src_tpage = alloc_page(GFP_KERNEL);
+               if (!src_tpage)
+                       return -ENOMEM;
+
+               if (copy_from_user(page_address(src_tpage),
+                               (void __user *)(uintptr_t)vaddr, size)) {
+                       __free_page(src_tpage);
+                       return -EFAULT;
+               }
+
+               paddr = __sme_page_pa(src_tpage);
+       }
+
+       /*
+        *  If destination buffer or length is not aligned then do read-modify-write:
+        *   - decrypt destination in an intermediate buffer
+        *   - copy the source buffer in an intermediate buffer
+        *   - use the intermediate buffer as source buffer
+        */
+       if (!IS_ALIGNED(dst_vaddr, 16) || !IS_ALIGNED(size, 16)) {
+               int dst_offset;
+
+               dst_tpage = alloc_page(GFP_KERNEL);
+               if (!dst_tpage) {
+                       ret = -ENOMEM;
+                       goto e_free;
+               }
+
+               ret = __sev_dbg_decrypt(kvm, dst_paddr,
+                                       __sme_page_pa(dst_tpage), size, error);
+               if (ret)
+                       goto e_free;
+
+               /*
+                *  If source is kernel buffer then use memcpy() otherwise
+                *  copy_from_user().
+                */
+               dst_offset = dst_paddr & 15;
+
+               if (src_tpage)
+                       memcpy(page_address(dst_tpage) + dst_offset,
+                              page_address(src_tpage), size);
+               else {
+                       if (copy_from_user(page_address(dst_tpage) + dst_offset,
+                                          (void __user *)(uintptr_t)vaddr, size)) {
+                               ret = -EFAULT;
+                               goto e_free;
+                       }
+               }
+
+               paddr = __sme_page_pa(dst_tpage);
+               dst_paddr = round_down(dst_paddr, 16);
+               len = round_up(size, 16);
+       }
+
+       ret = __sev_issue_dbg_cmd(kvm, paddr, dst_paddr, len, error, true);
+
+e_free:
+       if (src_tpage)
+               __free_page(src_tpage);
+       if (dst_tpage)
+               __free_page(dst_tpage);
+       return ret;
+}
+
+static int sev_dbg_crypt(struct kvm *kvm, struct kvm_sev_cmd *argp, bool dec)
+{
+       unsigned long vaddr, vaddr_end, next_vaddr;
+       unsigned long dst_vaddr;
+       struct page **src_p, **dst_p;
+       struct kvm_sev_dbg debug;
+       unsigned long n;
+       unsigned int size;
+       int ret;
+
+       if (!sev_guest(kvm))
+               return -ENOTTY;
+
+       if (copy_from_user(&debug, (void __user *)(uintptr_t)argp->data, sizeof(debug)))
+               return -EFAULT;
+
+       if (!debug.len || debug.src_uaddr + debug.len < debug.src_uaddr)
+               return -EINVAL;
+       if (!debug.dst_uaddr)
+               return -EINVAL;
+
+       vaddr = debug.src_uaddr;
+       size = debug.len;
+       vaddr_end = vaddr + size;
+       dst_vaddr = debug.dst_uaddr;
+
+       for (; vaddr < vaddr_end; vaddr = next_vaddr) {
+               int len, s_off, d_off;
+
+               /* lock userspace source and destination page */
+               src_p = sev_pin_memory(kvm, vaddr & PAGE_MASK, PAGE_SIZE, &n, 0);
+               if (!src_p)
+                       return -EFAULT;
+
+               dst_p = sev_pin_memory(kvm, dst_vaddr & PAGE_MASK, PAGE_SIZE, &n, 1);
+               if (!dst_p) {
+                       sev_unpin_memory(kvm, src_p, n);
+                       return -EFAULT;
+               }
+
+               /*
+                * The DBG_{DE,EN}CRYPT commands will perform {dec,en}cryption of the
+                * memory content (i.e it will write the same memory region with C=1).
+                * It's possible that the cache may contain the data with C=0, i.e.,
+                * unencrypted so invalidate it first.
+                */
+               sev_clflush_pages(src_p, 1);
+               sev_clflush_pages(dst_p, 1);
+
+               /*
+                * Since user buffer may not be page aligned, calculate the
+                * offset within the page.
+                */
+               s_off = vaddr & ~PAGE_MASK;
+               d_off = dst_vaddr & ~PAGE_MASK;
+               len = min_t(size_t, (PAGE_SIZE - s_off), size);
+
+               if (dec)
+                       ret = __sev_dbg_decrypt_user(kvm,
+                                                    __sme_page_pa(src_p[0]) + s_off,
+                                                    dst_vaddr,
+                                                    __sme_page_pa(dst_p[0]) + d_off,
+                                                    len, &argp->error);
+               else
+                       ret = __sev_dbg_encrypt_user(kvm,
+                                                    __sme_page_pa(src_p[0]) + s_off,
+                                                    vaddr,
+                                                    __sme_page_pa(dst_p[0]) + d_off,
+                                                    dst_vaddr,
+                                                    len, &argp->error);
+
+               sev_unpin_memory(kvm, src_p, n);
+               sev_unpin_memory(kvm, dst_p, n);
+
+               if (ret)
+                       goto err;
+
+               next_vaddr = vaddr + len;
+               dst_vaddr = dst_vaddr + len;
+               size -= len;
+       }
+err:
+       return ret;
+}
+
+static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp)
+{
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+       struct sev_data_launch_secret *data;
+       struct kvm_sev_launch_secret params;
+       struct page **pages;
+       void *blob, *hdr;
+       unsigned long n;
+       int ret, offset;
+
+       if (!sev_guest(kvm))
+               return -ENOTTY;
+
+       if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
+               return -EFAULT;
+
+       pages = sev_pin_memory(kvm, params.guest_uaddr, params.guest_len, &n, 1);
+       if (!pages)
+               return -ENOMEM;
+
+       /*
+        * The secret must be copied into contiguous memory region, lets verify
+        * that userspace memory pages are contiguous before we issue command.
+        */
+       if (get_num_contig_pages(0, pages, n) != n) {
+               ret = -EINVAL;
+               goto e_unpin_memory;
+       }
+
+       ret = -ENOMEM;
+       data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
+       if (!data)
+               goto e_unpin_memory;
+
+       offset = params.guest_uaddr & (PAGE_SIZE - 1);
+       data->guest_address = __sme_page_pa(pages[0]) + offset;
+       data->guest_len = params.guest_len;
+
+       blob = psp_copy_user_blob(params.trans_uaddr, params.trans_len);
+       if (IS_ERR(blob)) {
+               ret = PTR_ERR(blob);
+               goto e_free;
+       }
+
+       data->trans_address = __psp_pa(blob);
+       data->trans_len = params.trans_len;
+
+       hdr = psp_copy_user_blob(params.hdr_uaddr, params.hdr_len);
+       if (IS_ERR(hdr)) {
+               ret = PTR_ERR(hdr);
+               goto e_free_blob;
+       }
+       data->hdr_address = __psp_pa(hdr);
+       data->hdr_len = params.hdr_len;
+
+       data->handle = sev->handle;
+       ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_SECRET, data, &argp->error);
+
+       kfree(hdr);
+
+e_free_blob:
+       kfree(blob);
+e_free:
+       kfree(data);
+e_unpin_memory:
+       sev_unpin_memory(kvm, pages, n);
+       return ret;
+}
+
+int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
+{
+       struct kvm_sev_cmd sev_cmd;
+       int r;
+
+       if (!svm_sev_enabled())
+               return -ENOTTY;
+
+       if (!argp)
+               return 0;
+
+       if (copy_from_user(&sev_cmd, argp, sizeof(struct kvm_sev_cmd)))
+               return -EFAULT;
+
+       mutex_lock(&kvm->lock);
+
+       switch (sev_cmd.id) {
+       case KVM_SEV_INIT:
+               r = sev_guest_init(kvm, &sev_cmd);
+               break;
+       case KVM_SEV_LAUNCH_START:
+               r = sev_launch_start(kvm, &sev_cmd);
+               break;
+       case KVM_SEV_LAUNCH_UPDATE_DATA:
+               r = sev_launch_update_data(kvm, &sev_cmd);
+               break;
+       case KVM_SEV_LAUNCH_MEASURE:
+               r = sev_launch_measure(kvm, &sev_cmd);
+               break;
+       case KVM_SEV_LAUNCH_FINISH:
+               r = sev_launch_finish(kvm, &sev_cmd);
+               break;
+       case KVM_SEV_GUEST_STATUS:
+               r = sev_guest_status(kvm, &sev_cmd);
+               break;
+       case KVM_SEV_DBG_DECRYPT:
+               r = sev_dbg_crypt(kvm, &sev_cmd, true);
+               break;
+       case KVM_SEV_DBG_ENCRYPT:
+               r = sev_dbg_crypt(kvm, &sev_cmd, false);
+               break;
+       case KVM_SEV_LAUNCH_SECRET:
+               r = sev_launch_secret(kvm, &sev_cmd);
+               break;
+       default:
+               r = -EINVAL;
+               goto out;
+       }
+
+       if (copy_to_user(argp, &sev_cmd, sizeof(struct kvm_sev_cmd)))
+               r = -EFAULT;
+
+out:
+       mutex_unlock(&kvm->lock);
+       return r;
+}
+
+int svm_register_enc_region(struct kvm *kvm,
+                           struct kvm_enc_region *range)
+{
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+       struct enc_region *region;
+       int ret = 0;
+
+       if (!sev_guest(kvm))
+               return -ENOTTY;
+
+       if (range->addr > ULONG_MAX || range->size > ULONG_MAX)
+               return -EINVAL;
+
+       region = kzalloc(sizeof(*region), GFP_KERNEL_ACCOUNT);
+       if (!region)
+               return -ENOMEM;
+
+       region->pages = sev_pin_memory(kvm, range->addr, range->size, &region->npages, 1);
+       if (!region->pages) {
+               ret = -ENOMEM;
+               goto e_free;
+       }
+
+       /*
+        * The guest may change the memory encryption attribute from C=0 -> C=1
+        * or vice versa for this memory range. Lets make sure caches are
+        * flushed to ensure that guest data gets written into memory with
+        * correct C-bit.
+        */
+       sev_clflush_pages(region->pages, region->npages);
+
+       region->uaddr = range->addr;
+       region->size = range->size;
+
+       mutex_lock(&kvm->lock);
+       list_add_tail(&region->list, &sev->regions_list);
+       mutex_unlock(&kvm->lock);
+
+       return ret;
+
+e_free:
+       kfree(region);
+       return ret;
+}
+
+static struct enc_region *
+find_enc_region(struct kvm *kvm, struct kvm_enc_region *range)
+{
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+       struct list_head *head = &sev->regions_list;
+       struct enc_region *i;
+
+       list_for_each_entry(i, head, list) {
+               if (i->uaddr == range->addr &&
+                   i->size == range->size)
+                       return i;
+       }
+
+       return NULL;
+}
+
+static void __unregister_enc_region_locked(struct kvm *kvm,
+                                          struct enc_region *region)
+{
+       sev_unpin_memory(kvm, region->pages, region->npages);
+       list_del(&region->list);
+       kfree(region);
+}
+
+int svm_unregister_enc_region(struct kvm *kvm,
+                             struct kvm_enc_region *range)
+{
+       struct enc_region *region;
+       int ret;
+
+       mutex_lock(&kvm->lock);
+
+       if (!sev_guest(kvm)) {
+               ret = -ENOTTY;
+               goto failed;
+       }
+
+       region = find_enc_region(kvm, range);
+       if (!region) {
+               ret = -EINVAL;
+               goto failed;
+       }
+
+       /*
+        * Ensure that all guest tagged cache entries are flushed before
+        * releasing the pages back to the system for use. CLFLUSH will
+        * not do this, so issue a WBINVD.
+        */
+       wbinvd_on_all_cpus();
+
+       __unregister_enc_region_locked(kvm, region);
+
+       mutex_unlock(&kvm->lock);
+       return 0;
+
+failed:
+       mutex_unlock(&kvm->lock);
+       return ret;
+}
+
+void sev_vm_destroy(struct kvm *kvm)
+{
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+       struct list_head *head = &sev->regions_list;
+       struct list_head *pos, *q;
+
+       if (!sev_guest(kvm))
+               return;
+
+       mutex_lock(&kvm->lock);
+
+       /*
+        * Ensure that all guest tagged cache entries are flushed before
+        * releasing the pages back to the system for use. CLFLUSH will
+        * not do this, so issue a WBINVD.
+        */
+       wbinvd_on_all_cpus();
+
+       /*
+        * if userspace was terminated before unregistering the memory regions
+        * then lets unpin all the registered memory.
+        */
+       if (!list_empty(head)) {
+               list_for_each_safe(pos, q, head) {
+                       __unregister_enc_region_locked(kvm,
+                               list_entry(pos, struct enc_region, list));
+               }
+       }
+
+       mutex_unlock(&kvm->lock);
+
+       sev_unbind_asid(kvm, sev->handle);
+       sev_asid_free(sev->asid);
+}
+
+int __init sev_hardware_setup(void)
+{
+       struct sev_user_data_status *status;
+       int rc;
+
+       /* Maximum number of encrypted guests supported simultaneously */
+       max_sev_asid = cpuid_ecx(0x8000001F);
+
+       if (!max_sev_asid)
+               return 1;
+
+       /* Minimum ASID value that should be used for SEV guest */
+       min_sev_asid = cpuid_edx(0x8000001F);
+
+       /* Initialize SEV ASID bitmaps */
+       sev_asid_bitmap = bitmap_zalloc(max_sev_asid, GFP_KERNEL);
+       if (!sev_asid_bitmap)
+               return 1;
+
+       sev_reclaim_asid_bitmap = bitmap_zalloc(max_sev_asid, GFP_KERNEL);
+       if (!sev_reclaim_asid_bitmap)
+               return 1;
+
+       status = kmalloc(sizeof(*status), GFP_KERNEL);
+       if (!status)
+               return 1;
+
+       /*
+        * Check SEV platform status.
+        *
+        * PLATFORM_STATUS can be called in any state, if we failed to query
+        * the PLATFORM status then either PSP firmware does not support SEV
+        * feature or SEV firmware is dead.
+        */
+       rc = sev_platform_status(status, NULL);
+       if (rc)
+               goto err;
+
+       pr_info("SEV supported\n");
+
+err:
+       kfree(status);
+       return rc;
+}
+
+void sev_hardware_teardown(void)
+{
+       bitmap_free(sev_asid_bitmap);
+       bitmap_free(sev_reclaim_asid_bitmap);
+
+       sev_flush_asids();
+}
+
+void pre_sev_run(struct vcpu_svm *svm, int cpu)
+{
+       struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
+       int asid = sev_get_asid(svm->vcpu.kvm);
+
+       /* Assign the asid allocated with this SEV guest */
+       svm->vmcb->control.asid = asid;
+
+       /*
+        * Flush guest TLB:
+        *
+        * 1) when different VMCB for the same ASID is to be run on the same host CPU.
+        * 2) or this VMCB was executed on different host CPU in previous VMRUNs.
+        */
+       if (sd->sev_vmcbs[asid] == svm->vmcb &&
+           svm->last_cpu == cpu)
+               return;
+
+       svm->last_cpu = cpu;
+       sd->sev_vmcbs[asid] = svm->vmcb;
+       svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ASID;
+       mark_dirty(svm->vmcb, VMCB_ASID);
+}
similarity index 54%
rename from arch/x86/kvm/svm.c
rename to arch/x86/kvm/svm/svm.c
index 851e9cc..2be5bba 100644 (file)
@@ -1,17 +1,3 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Kernel-based Virtual Machine driver for Linux
- *
- * AMD SVM support
- *
- * Copyright (C) 2006 Qumranet, Inc.
- * Copyright 2010 Red Hat, Inc. and/or its affiliates.
- *
- * Authors:
- *   Yaniv Kamay  <yaniv@qumranet.com>
- *   Avi Kivity   <avi@qumranet.com>
- */
-
 #define pr_fmt(fmt) "SVM: " fmt
 
 #include <linux/kvm_host.h>
 #include <linux/kernel.h>
 #include <linux/vmalloc.h>
 #include <linux/highmem.h>
+#include <linux/amd-iommu.h>
 #include <linux/sched.h>
 #include <linux/trace_events.h>
 #include <linux/slab.h>
-#include <linux/amd-iommu.h>
 #include <linux/hashtable.h>
 #include <linux/frame.h>
 #include <linux/psp-sev.h>
@@ -53,6 +39,8 @@
 #include <asm/virtext.h>
 #include "trace.h"
 
+#include "svm.h"
+
 #define __ex(x) __kvm_handle_fault_on_reboot(x)
 
 MODULE_AUTHOR("Qumranet");
@@ -80,107 +68,15 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id);
 #define SVM_FEATURE_DECODE_ASSIST  (1 <<  7)
 #define SVM_FEATURE_PAUSE_FILTER   (1 << 10)
 
-#define SVM_AVIC_DOORBELL      0xc001011b
-
-#define NESTED_EXIT_HOST       0       /* Exit handled on host level */
-#define NESTED_EXIT_DONE       1       /* Exit caused nested vmexit  */
-#define NESTED_EXIT_CONTINUE   2       /* Further checks needed      */
-
 #define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
 
 #define TSC_RATIO_RSVD          0xffffff0000000000ULL
 #define TSC_RATIO_MIN          0x0000000000000001ULL
 #define TSC_RATIO_MAX          0x000000ffffffffffULL
 
-#define AVIC_HPA_MASK  ~((0xFFFULL << 52) | 0xFFF)
-
-/*
- * 0xff is broadcast, so the max index allowed for physical APIC ID
- * table is 0xfe.  APIC IDs above 0xff are reserved.
- */
-#define AVIC_MAX_PHYSICAL_ID_COUNT     255
-
-#define AVIC_UNACCEL_ACCESS_WRITE_MASK         1
-#define AVIC_UNACCEL_ACCESS_OFFSET_MASK                0xFF0
-#define AVIC_UNACCEL_ACCESS_VECTOR_MASK                0xFFFFFFFF
-
-/* AVIC GATAG is encoded using VM and VCPU IDs */
-#define AVIC_VCPU_ID_BITS              8
-#define AVIC_VCPU_ID_MASK              ((1 << AVIC_VCPU_ID_BITS) - 1)
-
-#define AVIC_VM_ID_BITS                        24
-#define AVIC_VM_ID_NR                  (1 << AVIC_VM_ID_BITS)
-#define AVIC_VM_ID_MASK                        ((1 << AVIC_VM_ID_BITS) - 1)
-
-#define AVIC_GATAG(x, y)               (((x & AVIC_VM_ID_MASK) << AVIC_VCPU_ID_BITS) | \
-                                               (y & AVIC_VCPU_ID_MASK))
-#define AVIC_GATAG_TO_VMID(x)          ((x >> AVIC_VCPU_ID_BITS) & AVIC_VM_ID_MASK)
-#define AVIC_GATAG_TO_VCPUID(x)                (x & AVIC_VCPU_ID_MASK)
-
 static bool erratum_383_found __read_mostly;
 
-static const u32 host_save_user_msrs[] = {
-#ifdef CONFIG_X86_64
-       MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
-       MSR_FS_BASE,
-#endif
-       MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
-       MSR_TSC_AUX,
-};
-
-#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
-
-struct kvm_sev_info {
-       bool active;            /* SEV enabled guest */
-       unsigned int asid;      /* ASID used for this guest */
-       unsigned int handle;    /* SEV firmware handle */
-       int fd;                 /* SEV device fd */
-       unsigned long pages_locked; /* Number of pages locked */
-       struct list_head regions_list;  /* List of registered regions */
-};
-
-struct kvm_svm {
-       struct kvm kvm;
-
-       /* Struct members for AVIC */
-       u32 avic_vm_id;
-       struct page *avic_logical_id_table_page;
-       struct page *avic_physical_id_table_page;
-       struct hlist_node hnode;
-
-       struct kvm_sev_info sev_info;
-};
-
-struct kvm_vcpu;
-
-struct nested_state {
-       struct vmcb *hsave;
-       u64 hsave_msr;
-       u64 vm_cr_msr;
-       u64 vmcb;
-
-       /* These are the merged vectors */
-       u32 *msrpm;
-
-       /* gpa pointers to the real vectors */
-       u64 vmcb_msrpm;
-       u64 vmcb_iopm;
-
-       /* A VMEXIT is required but not yet emulated */
-       bool exit_required;
-
-       /* cache for intercepts of the guest */
-       u32 intercept_cr;
-       u32 intercept_dr;
-       u32 intercept_exceptions;
-       u64 intercept;
-
-       /* Nested Paging related state */
-       u64 nested_cr3;
-};
-
-#define MSRPM_OFFSETS  16
-static u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
+u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
 
 /*
  * Set osvw_len to higher value when updated Revision Guides
@@ -188,92 +84,9 @@ static u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
  */
 static uint64_t osvw_len = 4, osvw_status;
 
-struct vcpu_svm {
-       struct kvm_vcpu vcpu;
-       struct vmcb *vmcb;
-       unsigned long vmcb_pa;
-       struct svm_cpu_data *svm_data;
-       uint64_t asid_generation;
-       uint64_t sysenter_esp;
-       uint64_t sysenter_eip;
-       uint64_t tsc_aux;
-
-       u64 msr_decfg;
-
-       u64 next_rip;
-
-       u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS];
-       struct {
-               u16 fs;
-               u16 gs;
-               u16 ldt;
-               u64 gs_base;
-       } host;
-
-       u64 spec_ctrl;
-       /*
-        * Contains guest-controlled bits of VIRT_SPEC_CTRL, which will be
-        * translated into the appropriate L2_CFG bits on the host to
-        * perform speculative control.
-        */
-       u64 virt_spec_ctrl;
-
-       u32 *msrpm;
-
-       ulong nmi_iret_rip;
-
-       struct nested_state nested;
-
-       bool nmi_singlestep;
-       u64 nmi_singlestep_guest_rflags;
-
-       unsigned int3_injected;
-       unsigned long int3_rip;
-
-       /* cached guest cpuid flags for faster access */
-       bool nrips_enabled      : 1;
-
-       u32 ldr_reg;
-       u32 dfr_reg;
-       struct page *avic_backing_page;
-       u64 *avic_physical_id_cache;
-       bool avic_is_running;
-
-       /*
-        * Per-vcpu list of struct amd_svm_iommu_ir:
-        * This is used mainly to store interrupt remapping information used
-        * when update the vcpu affinity. This avoids the need to scan for
-        * IRTE and try to match ga_tag in the IOMMU driver.
-        */
-       struct list_head ir_list;
-       spinlock_t ir_list_lock;
-
-       /* which host CPU was used for running this vcpu */
-       unsigned int last_cpu;
-};
-
-/*
- * This is a wrapper of struct amd_iommu_ir_data.
- */
-struct amd_svm_iommu_ir {
-       struct list_head node;  /* Used by SVM for per-vcpu ir_list */
-       void *data;             /* Storing pointer to struct amd_ir_data */
-};
-
-#define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK   (0xFF)
-#define AVIC_LOGICAL_ID_ENTRY_VALID_BIT                        31
-#define AVIC_LOGICAL_ID_ENTRY_VALID_MASK               (1 << 31)
-
-#define AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK   (0xFFULL)
-#define AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK       (0xFFFFFFFFFFULL << 12)
-#define AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK         (1ULL << 62)
-#define AVIC_PHYSICAL_ID_ENTRY_VALID_MASK              (1ULL << 63)
-
 static DEFINE_PER_CPU(u64, current_tsc_ratio);
 #define TSC_RATIO_DEFAULT      0x0100000000ULL
 
-#define MSR_INVALID                    0xffffffffU
-
 static const struct svm_direct_access_msrs {
        u32 index;   /* Index of the MSR */
        bool always; /* True if intercept is always on */
@@ -299,9 +112,9 @@ static const struct svm_direct_access_msrs {
 
 /* enable NPT for AMD64 and X86 with PAE */
 #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
-static bool npt_enabled = true;
+bool npt_enabled = true;
 #else
-static bool npt_enabled;
+bool npt_enabled;
 #endif
 
 /*
@@ -360,12 +173,6 @@ module_param(npt, int, S_IRUGO);
 static int nested = true;
 module_param(nested, int, S_IRUGO);
 
-/* enable / disable AVIC */
-static int avic;
-#ifdef CONFIG_X86_LOCAL_APIC
-module_param(avic, int, S_IRUGO);
-#endif
-
 /* enable/disable Next RIP Save */
 static int nrips = true;
 module_param(nrips, int, 0444);
@@ -387,303 +194,7 @@ module_param(dump_invalid_vmcb, bool, 0644);
 
 static u8 rsm_ins_bytes[] = "\x0f\xaa";
 
-static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
-static void svm_flush_tlb(struct kvm_vcpu *vcpu, bool invalidate_gpa);
 static void svm_complete_interrupts(struct vcpu_svm *svm);
-static void svm_toggle_avic_for_irq_window(struct kvm_vcpu *vcpu, bool activate);
-static inline void avic_post_state_restore(struct kvm_vcpu *vcpu);
-
-static int nested_svm_exit_handled(struct vcpu_svm *svm);
-static int nested_svm_intercept(struct vcpu_svm *svm);
-static int nested_svm_vmexit(struct vcpu_svm *svm);
-static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
-                                     bool has_error_code, u32 error_code);
-
-enum {
-       VMCB_INTERCEPTS, /* Intercept vectors, TSC offset,
-                           pause filter count */
-       VMCB_PERM_MAP,   /* IOPM Base and MSRPM Base */
-       VMCB_ASID,       /* ASID */
-       VMCB_INTR,       /* int_ctl, int_vector */
-       VMCB_NPT,        /* npt_en, nCR3, gPAT */
-       VMCB_CR,         /* CR0, CR3, CR4, EFER */
-       VMCB_DR,         /* DR6, DR7 */
-       VMCB_DT,         /* GDT, IDT */
-       VMCB_SEG,        /* CS, DS, SS, ES, CPL */
-       VMCB_CR2,        /* CR2 only */
-       VMCB_LBR,        /* DBGCTL, BR_FROM, BR_TO, LAST_EX_FROM, LAST_EX_TO */
-       VMCB_AVIC,       /* AVIC APIC_BAR, AVIC APIC_BACKING_PAGE,
-                         * AVIC PHYSICAL_TABLE pointer,
-                         * AVIC LOGICAL_TABLE pointer
-                         */
-       VMCB_DIRTY_MAX,
-};
-
-/* TPR and CR2 are always written before VMRUN */
-#define VMCB_ALWAYS_DIRTY_MASK ((1U << VMCB_INTR) | (1U << VMCB_CR2))
-
-#define VMCB_AVIC_APIC_BAR_MASK                0xFFFFFFFFFF000ULL
-
-static int sev_flush_asids(void);
-static DECLARE_RWSEM(sev_deactivate_lock);
-static DEFINE_MUTEX(sev_bitmap_lock);
-static unsigned int max_sev_asid;
-static unsigned int min_sev_asid;
-static unsigned long *sev_asid_bitmap;
-static unsigned long *sev_reclaim_asid_bitmap;
-#define __sme_page_pa(x) __sme_set(page_to_pfn(x) << PAGE_SHIFT)
-
-struct enc_region {
-       struct list_head list;
-       unsigned long npages;
-       struct page **pages;
-       unsigned long uaddr;
-       unsigned long size;
-};
-
-
-static inline struct kvm_svm *to_kvm_svm(struct kvm *kvm)
-{
-       return container_of(kvm, struct kvm_svm, kvm);
-}
-
-static inline bool svm_sev_enabled(void)
-{
-       return IS_ENABLED(CONFIG_KVM_AMD_SEV) ? max_sev_asid : 0;
-}
-
-static inline bool sev_guest(struct kvm *kvm)
-{
-#ifdef CONFIG_KVM_AMD_SEV
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-
-       return sev->active;
-#else
-       return false;
-#endif
-}
-
-static inline int sev_get_asid(struct kvm *kvm)
-{
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-
-       return sev->asid;
-}
-
-static inline void mark_all_dirty(struct vmcb *vmcb)
-{
-       vmcb->control.clean = 0;
-}
-
-static inline void mark_all_clean(struct vmcb *vmcb)
-{
-       vmcb->control.clean = ((1 << VMCB_DIRTY_MAX) - 1)
-                              & ~VMCB_ALWAYS_DIRTY_MASK;
-}
-
-static inline void mark_dirty(struct vmcb *vmcb, int bit)
-{
-       vmcb->control.clean &= ~(1 << bit);
-}
-
-static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
-{
-       return container_of(vcpu, struct vcpu_svm, vcpu);
-}
-
-static inline void avic_update_vapic_bar(struct vcpu_svm *svm, u64 data)
-{
-       svm->vmcb->control.avic_vapic_bar = data & VMCB_AVIC_APIC_BAR_MASK;
-       mark_dirty(svm->vmcb, VMCB_AVIC);
-}
-
-static inline bool avic_vcpu_is_running(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       u64 *entry = svm->avic_physical_id_cache;
-
-       if (!entry)
-               return false;
-
-       return (READ_ONCE(*entry) & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK);
-}
-
-static void recalc_intercepts(struct vcpu_svm *svm)
-{
-       struct vmcb_control_area *c, *h;
-       struct nested_state *g;
-
-       mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
-
-       if (!is_guest_mode(&svm->vcpu))
-               return;
-
-       c = &svm->vmcb->control;
-       h = &svm->nested.hsave->control;
-       g = &svm->nested;
-
-       c->intercept_cr = h->intercept_cr;
-       c->intercept_dr = h->intercept_dr;
-       c->intercept_exceptions = h->intercept_exceptions;
-       c->intercept = h->intercept;
-
-       if (svm->vcpu.arch.hflags & HF_VINTR_MASK) {
-               /* We only want the cr8 intercept bits of L1 */
-               c->intercept_cr &= ~(1U << INTERCEPT_CR8_READ);
-               c->intercept_cr &= ~(1U << INTERCEPT_CR8_WRITE);
-
-               /*
-                * Once running L2 with HF_VINTR_MASK, EFLAGS.IF does not
-                * affect any interrupt we may want to inject; therefore,
-                * interrupt window vmexits are irrelevant to L0.
-                */
-               c->intercept &= ~(1ULL << INTERCEPT_VINTR);
-       }
-
-       /* We don't want to see VMMCALLs from a nested guest */
-       c->intercept &= ~(1ULL << INTERCEPT_VMMCALL);
-
-       c->intercept_cr |= g->intercept_cr;
-       c->intercept_dr |= g->intercept_dr;
-       c->intercept_exceptions |= g->intercept_exceptions;
-       c->intercept |= g->intercept;
-}
-
-static inline struct vmcb *get_host_vmcb(struct vcpu_svm *svm)
-{
-       if (is_guest_mode(&svm->vcpu))
-               return svm->nested.hsave;
-       else
-               return svm->vmcb;
-}
-
-static inline void set_cr_intercept(struct vcpu_svm *svm, int bit)
-{
-       struct vmcb *vmcb = get_host_vmcb(svm);
-
-       vmcb->control.intercept_cr |= (1U << bit);
-
-       recalc_intercepts(svm);
-}
-
-static inline void clr_cr_intercept(struct vcpu_svm *svm, int bit)
-{
-       struct vmcb *vmcb = get_host_vmcb(svm);
-
-       vmcb->control.intercept_cr &= ~(1U << bit);
-
-       recalc_intercepts(svm);
-}
-
-static inline bool is_cr_intercept(struct vcpu_svm *svm, int bit)
-{
-       struct vmcb *vmcb = get_host_vmcb(svm);
-
-       return vmcb->control.intercept_cr & (1U << bit);
-}
-
-static inline void set_dr_intercepts(struct vcpu_svm *svm)
-{
-       struct vmcb *vmcb = get_host_vmcb(svm);
-
-       vmcb->control.intercept_dr = (1 << INTERCEPT_DR0_READ)
-               | (1 << INTERCEPT_DR1_READ)
-               | (1 << INTERCEPT_DR2_READ)
-               | (1 << INTERCEPT_DR3_READ)
-               | (1 << INTERCEPT_DR4_READ)
-               | (1 << INTERCEPT_DR5_READ)
-               | (1 << INTERCEPT_DR6_READ)
-               | (1 << INTERCEPT_DR7_READ)
-               | (1 << INTERCEPT_DR0_WRITE)
-               | (1 << INTERCEPT_DR1_WRITE)
-               | (1 << INTERCEPT_DR2_WRITE)
-               | (1 << INTERCEPT_DR3_WRITE)
-               | (1 << INTERCEPT_DR4_WRITE)
-               | (1 << INTERCEPT_DR5_WRITE)
-               | (1 << INTERCEPT_DR6_WRITE)
-               | (1 << INTERCEPT_DR7_WRITE);
-
-       recalc_intercepts(svm);
-}
-
-static inline void clr_dr_intercepts(struct vcpu_svm *svm)
-{
-       struct vmcb *vmcb = get_host_vmcb(svm);
-
-       vmcb->control.intercept_dr = 0;
-
-       recalc_intercepts(svm);
-}
-
-static inline void set_exception_intercept(struct vcpu_svm *svm, int bit)
-{
-       struct vmcb *vmcb = get_host_vmcb(svm);
-
-       vmcb->control.intercept_exceptions |= (1U << bit);
-
-       recalc_intercepts(svm);
-}
-
-static inline void clr_exception_intercept(struct vcpu_svm *svm, int bit)
-{
-       struct vmcb *vmcb = get_host_vmcb(svm);
-
-       vmcb->control.intercept_exceptions &= ~(1U << bit);
-
-       recalc_intercepts(svm);
-}
-
-static inline void set_intercept(struct vcpu_svm *svm, int bit)
-{
-       struct vmcb *vmcb = get_host_vmcb(svm);
-
-       vmcb->control.intercept |= (1ULL << bit);
-
-       recalc_intercepts(svm);
-}
-
-static inline void clr_intercept(struct vcpu_svm *svm, int bit)
-{
-       struct vmcb *vmcb = get_host_vmcb(svm);
-
-       vmcb->control.intercept &= ~(1ULL << bit);
-
-       recalc_intercepts(svm);
-}
-
-static inline bool is_intercept(struct vcpu_svm *svm, int bit)
-{
-       return (svm->vmcb->control.intercept & (1ULL << bit)) != 0;
-}
-
-static inline bool vgif_enabled(struct vcpu_svm *svm)
-{
-       return !!(svm->vmcb->control.int_ctl & V_GIF_ENABLE_MASK);
-}
-
-static inline void enable_gif(struct vcpu_svm *svm)
-{
-       if (vgif_enabled(svm))
-               svm->vmcb->control.int_ctl |= V_GIF_MASK;
-       else
-               svm->vcpu.arch.hflags |= HF_GIF_MASK;
-}
-
-static inline void disable_gif(struct vcpu_svm *svm)
-{
-       if (vgif_enabled(svm))
-               svm->vmcb->control.int_ctl &= ~V_GIF_MASK;
-       else
-               svm->vcpu.arch.hflags &= ~HF_GIF_MASK;
-}
-
-static inline bool gif_set(struct vcpu_svm *svm)
-{
-       if (vgif_enabled(svm))
-               return !!(svm->vmcb->control.int_ctl & V_GIF_MASK);
-       else
-               return !!(svm->vcpu.arch.hflags & HF_GIF_MASK);
-}
 
 static unsigned long iopm_base;
 
@@ -696,23 +207,7 @@ struct kvm_ldttss_desc {
        u32 zero1;
 } __attribute__((packed));
 
-struct svm_cpu_data {
-       int cpu;
-
-       u64 asid_generation;
-       u32 max_asid;
-       u32 next_asid;
-       u32 min_asid;
-       struct kvm_ldttss_desc *tss_desc;
-
-       struct page *save_area;
-       struct vmcb *current_vmcb;
-
-       /* index = sev_asid, value = vmcb pointer */
-       struct vmcb **sev_vmcbs;
-};
-
-static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data);
+DEFINE_PER_CPU(struct svm_cpu_data *, svm_data);
 
 static const u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000};
 
@@ -720,7 +215,7 @@ static const u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000};
 #define MSRS_RANGE_SIZE 2048
 #define MSRS_IN_RANGE (MSRS_RANGE_SIZE * 8 / 2)
 
-static u32 svm_msrpm_offset(u32 msr)
+u32 svm_msrpm_offset(u32 msr)
 {
        u32 offset;
        int i;
@@ -767,7 +262,7 @@ static int get_npt_level(struct kvm_vcpu *vcpu)
 #endif
 }
 
-static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
+void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
 {
        vcpu->arch.efer = efer;
 
@@ -1198,7 +693,7 @@ static void svm_disable_lbrv(struct vcpu_svm *svm)
        set_msr_interception(msrpm, MSR_IA32_LASTINTTOIP, 0, 0);
 }
 
-static void disable_nmi_singlestep(struct vcpu_svm *svm)
+void disable_nmi_singlestep(struct vcpu_svm *svm)
 {
        svm->nmi_singlestep = false;
 
@@ -1211,97 +706,6 @@ static void disable_nmi_singlestep(struct vcpu_svm *svm)
        }
 }
 
-/* Note:
- * This hash table is used to map VM_ID to a struct kvm_svm,
- * when handling AMD IOMMU GALOG notification to schedule in
- * a particular vCPU.
- */
-#define SVM_VM_DATA_HASH_BITS  8
-static DEFINE_HASHTABLE(svm_vm_data_hash, SVM_VM_DATA_HASH_BITS);
-static u32 next_vm_id = 0;
-static bool next_vm_id_wrapped = 0;
-static DEFINE_SPINLOCK(svm_vm_data_hash_lock);
-
-/* Note:
- * This function is called from IOMMU driver to notify
- * SVM to schedule in a particular vCPU of a particular VM.
- */
-static int avic_ga_log_notifier(u32 ga_tag)
-{
-       unsigned long flags;
-       struct kvm_svm *kvm_svm;
-       struct kvm_vcpu *vcpu = NULL;
-       u32 vm_id = AVIC_GATAG_TO_VMID(ga_tag);
-       u32 vcpu_id = AVIC_GATAG_TO_VCPUID(ga_tag);
-
-       pr_debug("SVM: %s: vm_id=%#x, vcpu_id=%#x\n", __func__, vm_id, vcpu_id);
-       trace_kvm_avic_ga_log(vm_id, vcpu_id);
-
-       spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
-       hash_for_each_possible(svm_vm_data_hash, kvm_svm, hnode, vm_id) {
-               if (kvm_svm->avic_vm_id != vm_id)
-                       continue;
-               vcpu = kvm_get_vcpu_by_id(&kvm_svm->kvm, vcpu_id);
-               break;
-       }
-       spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
-
-       /* Note:
-        * At this point, the IOMMU should have already set the pending
-        * bit in the vAPIC backing page. So, we just need to schedule
-        * in the vcpu.
-        */
-       if (vcpu)
-               kvm_vcpu_wake_up(vcpu);
-
-       return 0;
-}
-
-static __init int sev_hardware_setup(void)
-{
-       struct sev_user_data_status *status;
-       int rc;
-
-       /* Maximum number of encrypted guests supported simultaneously */
-       max_sev_asid = cpuid_ecx(0x8000001F);
-
-       if (!max_sev_asid)
-               return 1;
-
-       /* Minimum ASID value that should be used for SEV guest */
-       min_sev_asid = cpuid_edx(0x8000001F);
-
-       /* Initialize SEV ASID bitmaps */
-       sev_asid_bitmap = bitmap_zalloc(max_sev_asid, GFP_KERNEL);
-       if (!sev_asid_bitmap)
-               return 1;
-
-       sev_reclaim_asid_bitmap = bitmap_zalloc(max_sev_asid, GFP_KERNEL);
-       if (!sev_reclaim_asid_bitmap)
-               return 1;
-
-       status = kmalloc(sizeof(*status), GFP_KERNEL);
-       if (!status)
-               return 1;
-
-       /*
-        * Check SEV platform status.
-        *
-        * PLATFORM_STATUS can be called in any state, if we failed to query
-        * the PLATFORM status then either PSP firmware does not support SEV
-        * feature or SEV firmware is dead.
-        */
-       rc = sev_platform_status(status, NULL);
-       if (rc)
-               goto err;
-
-       pr_info("SEV supported\n");
-
-err:
-       kfree(status);
-       return rc;
-}
-
 static void grow_ple_window(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -1383,12 +787,8 @@ static void svm_hardware_teardown(void)
 {
        int cpu;
 
-       if (svm_sev_enabled()) {
-               bitmap_free(sev_asid_bitmap);
-               bitmap_free(sev_reclaim_asid_bitmap);
-
-               sev_flush_asids();
-       }
+       if (svm_sev_enabled())
+               sev_hardware_teardown();
 
        for_each_possible_cpu(cpu)
                svm_cpu_uninit(cpu);
@@ -1585,24 +985,6 @@ static u64 svm_write_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
        return svm->vmcb->control.tsc_offset;
 }
 
-static void avic_init_vmcb(struct vcpu_svm *svm)
-{
-       struct vmcb *vmcb = svm->vmcb;
-       struct kvm_svm *kvm_svm = to_kvm_svm(svm->vcpu.kvm);
-       phys_addr_t bpa = __sme_set(page_to_phys(svm->avic_backing_page));
-       phys_addr_t lpa = __sme_set(page_to_phys(kvm_svm->avic_logical_id_table_page));
-       phys_addr_t ppa = __sme_set(page_to_phys(kvm_svm->avic_physical_id_table_page));
-
-       vmcb->control.avic_backing_page = bpa & AVIC_HPA_MASK;
-       vmcb->control.avic_logical_id = lpa & AVIC_HPA_MASK;
-       vmcb->control.avic_physical_id = ppa & AVIC_HPA_MASK;
-       vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID_COUNT;
-       if (kvm_apicv_activated(svm->vcpu.kvm))
-               vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
-       else
-               vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK;
-}
-
 static void init_vmcb(struct vcpu_svm *svm)
 {
        struct vmcb_control_area *control = &svm->vmcb->control;
@@ -1762,465 +1144,22 @@ static void init_vmcb(struct vcpu_svm *svm)
 
 }
 
-static u64 *avic_get_physical_id_entry(struct kvm_vcpu *vcpu,
-                                      unsigned int index)
+static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 {
-       u64 *avic_physical_id_table;
-       struct kvm_svm *kvm_svm = to_kvm_svm(vcpu->kvm);
+       struct vcpu_svm *svm = to_svm(vcpu);
+       u32 dummy;
+       u32 eax = 1;
 
-       if (index >= AVIC_MAX_PHYSICAL_ID_COUNT)
-               return NULL;
+       svm->spec_ctrl = 0;
+       svm->virt_spec_ctrl = 0;
 
-       avic_physical_id_table = page_address(kvm_svm->avic_physical_id_table_page);
-
-       return &avic_physical_id_table[index];
-}
-
-/**
- * Note:
- * AVIC hardware walks the nested page table to check permissions,
- * but does not use the SPA address specified in the leaf page
- * table entry since it uses  address in the AVIC_BACKING_PAGE pointer
- * field of the VMCB. Therefore, we set up the
- * APIC_ACCESS_PAGE_PRIVATE_MEMSLOT (4KB) here.
- */
-static int avic_update_access_page(struct kvm *kvm, bool activate)
-{
-       int ret = 0;
-
-       mutex_lock(&kvm->slots_lock);
-       /*
-        * During kvm_destroy_vm(), kvm_pit_set_reinject() could trigger
-        * APICv mode change, which update APIC_ACCESS_PAGE_PRIVATE_MEMSLOT
-        * memory region. So, we need to ensure that kvm->mm == current->mm.
-        */
-       if ((kvm->arch.apic_access_page_done == activate) ||
-           (kvm->mm != current->mm))
-               goto out;
-
-       ret = __x86_set_memory_region(kvm,
-                                     APIC_ACCESS_PAGE_PRIVATE_MEMSLOT,
-                                     APIC_DEFAULT_PHYS_BASE,
-                                     activate ? PAGE_SIZE : 0);
-       if (ret)
-               goto out;
-
-       kvm->arch.apic_access_page_done = activate;
-out:
-       mutex_unlock(&kvm->slots_lock);
-       return ret;
-}
-
-static int avic_init_backing_page(struct kvm_vcpu *vcpu)
-{
-       u64 *entry, new_entry;
-       int id = vcpu->vcpu_id;
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       if (id >= AVIC_MAX_PHYSICAL_ID_COUNT)
-               return -EINVAL;
-
-       if (!svm->vcpu.arch.apic->regs)
-               return -EINVAL;
-
-       if (kvm_apicv_activated(vcpu->kvm)) {
-               int ret;
-
-               ret = avic_update_access_page(vcpu->kvm, true);
-               if (ret)
-                       return ret;
-       }
-
-       svm->avic_backing_page = virt_to_page(svm->vcpu.arch.apic->regs);
-
-       /* Setting AVIC backing page address in the phy APIC ID table */
-       entry = avic_get_physical_id_entry(vcpu, id);
-       if (!entry)
-               return -EINVAL;
-
-       new_entry = __sme_set((page_to_phys(svm->avic_backing_page) &
-                             AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK) |
-                             AVIC_PHYSICAL_ID_ENTRY_VALID_MASK);
-       WRITE_ONCE(*entry, new_entry);
-
-       svm->avic_physical_id_cache = entry;
-
-       return 0;
-}
-
-static void sev_asid_free(int asid)
-{
-       struct svm_cpu_data *sd;
-       int cpu, pos;
-
-       mutex_lock(&sev_bitmap_lock);
-
-       pos = asid - 1;
-       __set_bit(pos, sev_reclaim_asid_bitmap);
-
-       for_each_possible_cpu(cpu) {
-               sd = per_cpu(svm_data, cpu);
-               sd->sev_vmcbs[pos] = NULL;
-       }
-
-       mutex_unlock(&sev_bitmap_lock);
-}
-
-static void sev_unbind_asid(struct kvm *kvm, unsigned int handle)
-{
-       struct sev_data_decommission *decommission;
-       struct sev_data_deactivate *data;
-
-       if (!handle)
-               return;
-
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data)
-               return;
-
-       /* deactivate handle */
-       data->handle = handle;
-
-       /* Guard DEACTIVATE against WBINVD/DF_FLUSH used in ASID recycling */
-       down_read(&sev_deactivate_lock);
-       sev_guest_deactivate(data, NULL);
-       up_read(&sev_deactivate_lock);
-
-       kfree(data);
-
-       decommission = kzalloc(sizeof(*decommission), GFP_KERNEL);
-       if (!decommission)
-               return;
-
-       /* decommission handle */
-       decommission->handle = handle;
-       sev_guest_decommission(decommission, NULL);
-
-       kfree(decommission);
-}
-
-static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
-                                   unsigned long ulen, unsigned long *n,
-                                   int write)
-{
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-       unsigned long npages, npinned, size;
-       unsigned long locked, lock_limit;
-       struct page **pages;
-       unsigned long first, last;
-
-       if (ulen == 0 || uaddr + ulen < uaddr)
-               return NULL;
-
-       /* Calculate number of pages. */
-       first = (uaddr & PAGE_MASK) >> PAGE_SHIFT;
-       last = ((uaddr + ulen - 1) & PAGE_MASK) >> PAGE_SHIFT;
-       npages = (last - first + 1);
-
-       locked = sev->pages_locked + npages;
-       lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-       if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
-               pr_err("SEV: %lu locked pages exceed the lock limit of %lu.\n", locked, lock_limit);
-               return NULL;
-       }
-
-       /* Avoid using vmalloc for smaller buffers. */
-       size = npages * sizeof(struct page *);
-       if (size > PAGE_SIZE)
-               pages = __vmalloc(size, GFP_KERNEL_ACCOUNT | __GFP_ZERO,
-                                 PAGE_KERNEL);
-       else
-               pages = kmalloc(size, GFP_KERNEL_ACCOUNT);
-
-       if (!pages)
-               return NULL;
-
-       /* Pin the user virtual address. */
-       npinned = get_user_pages_fast(uaddr, npages, FOLL_WRITE, pages);
-       if (npinned != npages) {
-               pr_err("SEV: Failure locking %lu pages.\n", npages);
-               goto err;
-       }
-
-       *n = npages;
-       sev->pages_locked = locked;
-
-       return pages;
-
-err:
-       if (npinned > 0)
-               release_pages(pages, npinned);
-
-       kvfree(pages);
-       return NULL;
-}
-
-static void sev_unpin_memory(struct kvm *kvm, struct page **pages,
-                            unsigned long npages)
-{
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-
-       release_pages(pages, npages);
-       kvfree(pages);
-       sev->pages_locked -= npages;
-}
-
-static void sev_clflush_pages(struct page *pages[], unsigned long npages)
-{
-       uint8_t *page_virtual;
-       unsigned long i;
-
-       if (npages == 0 || pages == NULL)
-               return;
-
-       for (i = 0; i < npages; i++) {
-               page_virtual = kmap_atomic(pages[i]);
-               clflush_cache_range(page_virtual, PAGE_SIZE);
-               kunmap_atomic(page_virtual);
-       }
-}
-
-static void __unregister_enc_region_locked(struct kvm *kvm,
-                                          struct enc_region *region)
-{
-       sev_unpin_memory(kvm, region->pages, region->npages);
-       list_del(&region->list);
-       kfree(region);
-}
-
-static void sev_vm_destroy(struct kvm *kvm)
-{
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-       struct list_head *head = &sev->regions_list;
-       struct list_head *pos, *q;
-
-       if (!sev_guest(kvm))
-               return;
-
-       mutex_lock(&kvm->lock);
-
-       /*
-        * Ensure that all guest tagged cache entries are flushed before
-        * releasing the pages back to the system for use. CLFLUSH will
-        * not do this, so issue a WBINVD.
-        */
-       wbinvd_on_all_cpus();
-
-       /*
-        * if userspace was terminated before unregistering the memory regions
-        * then lets unpin all the registered memory.
-        */
-       if (!list_empty(head)) {
-               list_for_each_safe(pos, q, head) {
-                       __unregister_enc_region_locked(kvm,
-                               list_entry(pos, struct enc_region, list));
-               }
-       }
-
-       mutex_unlock(&kvm->lock);
-
-       sev_unbind_asid(kvm, sev->handle);
-       sev_asid_free(sev->asid);
-}
-
-static void avic_vm_destroy(struct kvm *kvm)
-{
-       unsigned long flags;
-       struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
-
-       if (!avic)
-               return;
-
-       if (kvm_svm->avic_logical_id_table_page)
-               __free_page(kvm_svm->avic_logical_id_table_page);
-       if (kvm_svm->avic_physical_id_table_page)
-               __free_page(kvm_svm->avic_physical_id_table_page);
-
-       spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
-       hash_del(&kvm_svm->hnode);
-       spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
-}
-
-static void svm_vm_destroy(struct kvm *kvm)
-{
-       avic_vm_destroy(kvm);
-       sev_vm_destroy(kvm);
-}
-
-static int avic_vm_init(struct kvm *kvm)
-{
-       unsigned long flags;
-       int err = -ENOMEM;
-       struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
-       struct kvm_svm *k2;
-       struct page *p_page;
-       struct page *l_page;
-       u32 vm_id;
-
-       if (!avic)
-               return 0;
-
-       /* Allocating physical APIC ID table (4KB) */
-       p_page = alloc_page(GFP_KERNEL_ACCOUNT);
-       if (!p_page)
-               goto free_avic;
-
-       kvm_svm->avic_physical_id_table_page = p_page;
-       clear_page(page_address(p_page));
-
-       /* Allocating logical APIC ID table (4KB) */
-       l_page = alloc_page(GFP_KERNEL_ACCOUNT);
-       if (!l_page)
-               goto free_avic;
-
-       kvm_svm->avic_logical_id_table_page = l_page;
-       clear_page(page_address(l_page));
-
-       spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
- again:
-       vm_id = next_vm_id = (next_vm_id + 1) & AVIC_VM_ID_MASK;
-       if (vm_id == 0) { /* id is 1-based, zero is not okay */
-               next_vm_id_wrapped = 1;
-               goto again;
-       }
-       /* Is it still in use? Only possible if wrapped at least once */
-       if (next_vm_id_wrapped) {
-               hash_for_each_possible(svm_vm_data_hash, k2, hnode, vm_id) {
-                       if (k2->avic_vm_id == vm_id)
-                               goto again;
-               }
-       }
-       kvm_svm->avic_vm_id = vm_id;
-       hash_add(svm_vm_data_hash, &kvm_svm->hnode, kvm_svm->avic_vm_id);
-       spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
-
-       return 0;
-
-free_avic:
-       avic_vm_destroy(kvm);
-       return err;
-}
-
-static int svm_vm_init(struct kvm *kvm)
-{
-       if (avic) {
-               int ret = avic_vm_init(kvm);
-               if (ret)
-                       return ret;
-       }
-
-       kvm_apicv_init(kvm, avic);
-       return 0;
-}
-
-static inline int
-avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int cpu, bool r)
-{
-       int ret = 0;
-       unsigned long flags;
-       struct amd_svm_iommu_ir *ir;
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       if (!kvm_arch_has_assigned_device(vcpu->kvm))
-               return 0;
-
-       /*
-        * Here, we go through the per-vcpu ir_list to update all existing
-        * interrupt remapping table entry targeting this vcpu.
-        */
-       spin_lock_irqsave(&svm->ir_list_lock, flags);
-
-       if (list_empty(&svm->ir_list))
-               goto out;
-
-       list_for_each_entry(ir, &svm->ir_list, node) {
-               ret = amd_iommu_update_ga(cpu, r, ir->data);
-               if (ret)
-                       break;
-       }
-out:
-       spin_unlock_irqrestore(&svm->ir_list_lock, flags);
-       return ret;
-}
-
-static void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
-{
-       u64 entry;
-       /* ID = 0xff (broadcast), ID > 0xff (reserved) */
-       int h_physical_id = kvm_cpu_get_apicid(cpu);
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       if (!kvm_vcpu_apicv_active(vcpu))
-               return;
-
-       /*
-        * Since the host physical APIC id is 8 bits,
-        * we can support host APIC ID upto 255.
-        */
-       if (WARN_ON(h_physical_id > AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK))
-               return;
-
-       entry = READ_ONCE(*(svm->avic_physical_id_cache));
-       WARN_ON(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK);
-
-       entry &= ~AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
-       entry |= (h_physical_id & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK);
-
-       entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
-       if (svm->avic_is_running)
-               entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
-
-       WRITE_ONCE(*(svm->avic_physical_id_cache), entry);
-       avic_update_iommu_vcpu_affinity(vcpu, h_physical_id,
-                                       svm->avic_is_running);
-}
-
-static void avic_vcpu_put(struct kvm_vcpu *vcpu)
-{
-       u64 entry;
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       if (!kvm_vcpu_apicv_active(vcpu))
-               return;
-
-       entry = READ_ONCE(*(svm->avic_physical_id_cache));
-       if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK)
-               avic_update_iommu_vcpu_affinity(vcpu, -1, 0);
-
-       entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
-       WRITE_ONCE(*(svm->avic_physical_id_cache), entry);
-}
-
-/**
- * This function is called during VCPU halt/unhalt.
- */
-static void avic_set_running(struct kvm_vcpu *vcpu, bool is_run)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       svm->avic_is_running = is_run;
-       if (is_run)
-               avic_vcpu_load(vcpu, vcpu->cpu);
-       else
-               avic_vcpu_put(vcpu);
-}
-
-static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       u32 dummy;
-       u32 eax = 1;
-
-       svm->spec_ctrl = 0;
-       svm->virt_spec_ctrl = 0;
-
-       if (!init_event) {
-               svm->vcpu.arch.apic_base = APIC_DEFAULT_PHYS_BASE |
-                                          MSR_IA32_APICBASE_ENABLE;
-               if (kvm_vcpu_is_reset_bsp(&svm->vcpu))
-                       svm->vcpu.arch.apic_base |= MSR_IA32_APICBASE_BSP;
-       }
-       init_vmcb(svm);
+       if (!init_event) {
+               svm->vcpu.arch.apic_base = APIC_DEFAULT_PHYS_BASE |
+                                          MSR_IA32_APICBASE_ENABLE;
+               if (kvm_vcpu_is_reset_bsp(&svm->vcpu))
+                       svm->vcpu.arch.apic_base |= MSR_IA32_APICBASE_BSP;
+       }
+       init_vmcb(svm);
 
        kvm_cpuid(vcpu, &eax, &dummy, &dummy, &dummy, false);
        kvm_rdx_write(vcpu, eax);
@@ -2229,25 +1168,6 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
                avic_update_vapic_bar(svm, APIC_DEFAULT_PHYS_BASE);
 }
 
-static int avic_init_vcpu(struct vcpu_svm *svm)
-{
-       int ret;
-       struct kvm_vcpu *vcpu = &svm->vcpu;
-
-       if (!avic || !irqchip_in_kernel(vcpu->kvm))
-               return 0;
-
-       ret = avic_init_backing_page(&svm->vcpu);
-       if (ret)
-               return ret;
-
-       INIT_LIST_HEAD(&svm->ir_list);
-       spin_lock_init(&svm->ir_list_lock);
-       svm->dfr_reg = APIC_DFR_FLAT;
-
-       return ret;
-}
-
 static int svm_create_vcpu(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm;
@@ -2404,18 +1324,6 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
                wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
 }
 
-static void svm_vcpu_blocking(struct kvm_vcpu *vcpu)
-{
-       avic_set_running(vcpu, false);
-}
-
-static void svm_vcpu_unblocking(struct kvm_vcpu *vcpu)
-{
-       if (kvm_check_request(KVM_REQ_APICV_UPDATE, vcpu))
-               kvm_vcpu_update_apicv(vcpu);
-       avic_set_running(vcpu, true);
-}
-
 static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -2652,7 +1560,7 @@ static void update_cr0_intercept(struct vcpu_svm *svm)
        }
 }
 
-static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
+void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
@@ -2686,7 +1594,7 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
        update_cr0_intercept(svm);
 }
 
-static int svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
+int svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 {
        unsigned long host_cr4_mce = cr4_read_shadow() & X86_CR4_MCE;
        unsigned long old_cr4 = to_svm(vcpu)->vmcb->save.cr4;
@@ -3022,4256 +1930,1881 @@ static int vmmcall_interception(struct vcpu_svm *svm)
        return kvm_emulate_hypercall(&svm->vcpu);
 }
 
-static unsigned long nested_svm_get_tdp_cr3(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       return svm->nested.nested_cr3;
-}
-
-static u64 nested_svm_get_tdp_pdptr(struct kvm_vcpu *vcpu, int index)
+static int vmload_interception(struct vcpu_svm *svm)
 {
-       struct vcpu_svm *svm = to_svm(vcpu);
-       u64 cr3 = svm->nested.nested_cr3;
-       u64 pdpte;
+       struct vmcb *nested_vmcb;
+       struct kvm_host_map map;
        int ret;
 
-       ret = kvm_vcpu_read_guest_page(vcpu, gpa_to_gfn(__sme_clr(cr3)), &pdpte,
-                                      offset_in_page(cr3) + index * 8, 8);
-       if (ret)
-               return 0;
-       return pdpte;
-}
-
-static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu,
-                                      struct x86_exception *fault)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
+       if (nested_svm_check_permissions(svm))
+               return 1;
 
-       if (svm->vmcb->control.exit_code != SVM_EXIT_NPF) {
-               /*
-                * TODO: track the cause of the nested page fault, and
-                * correctly fill in the high bits of exit_info_1.
-                */
-               svm->vmcb->control.exit_code = SVM_EXIT_NPF;
-               svm->vmcb->control.exit_code_hi = 0;
-               svm->vmcb->control.exit_info_1 = (1ULL << 32);
-               svm->vmcb->control.exit_info_2 = fault->address;
+       ret = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(svm->vmcb->save.rax), &map);
+       if (ret) {
+               if (ret == -EINVAL)
+                       kvm_inject_gp(&svm->vcpu, 0);
+               return 1;
        }
 
-       svm->vmcb->control.exit_info_1 &= ~0xffffffffULL;
-       svm->vmcb->control.exit_info_1 |= fault->error_code;
+       nested_vmcb = map.hva;
 
-       /*
-        * The present bit is always zero for page structure faults on real
-        * hardware.
-        */
-       if (svm->vmcb->control.exit_info_1 & (2ULL << 32))
-               svm->vmcb->control.exit_info_1 &= ~1;
-
-       nested_svm_vmexit(svm);
-}
+       ret = kvm_skip_emulated_instruction(&svm->vcpu);
 
-static void nested_svm_init_mmu_context(struct kvm_vcpu *vcpu)
-{
-       WARN_ON(mmu_is_nested(vcpu));
+       nested_svm_vmloadsave(nested_vmcb, svm->vmcb);
+       kvm_vcpu_unmap(&svm->vcpu, &map, true);
 
-       vcpu->arch.mmu = &vcpu->arch.guest_mmu;
-       kvm_init_shadow_mmu(vcpu);
-       vcpu->arch.mmu->get_guest_pgd     = nested_svm_get_tdp_cr3;
-       vcpu->arch.mmu->get_pdptr         = nested_svm_get_tdp_pdptr;
-       vcpu->arch.mmu->inject_page_fault = nested_svm_inject_npf_exit;
-       vcpu->arch.mmu->shadow_root_level = get_npt_level(vcpu);
-       reset_shadow_zero_bits_mask(vcpu, vcpu->arch.mmu);
-       vcpu->arch.walk_mmu              = &vcpu->arch.nested_mmu;
+       return ret;
 }
 
-static void nested_svm_uninit_mmu_context(struct kvm_vcpu *vcpu)
+static int vmsave_interception(struct vcpu_svm *svm)
 {
-       vcpu->arch.mmu = &vcpu->arch.root_mmu;
-       vcpu->arch.walk_mmu = &vcpu->arch.root_mmu;
-}
+       struct vmcb *nested_vmcb;
+       struct kvm_host_map map;
+       int ret;
 
-static int nested_svm_check_permissions(struct vcpu_svm *svm)
-{
-       if (!(svm->vcpu.arch.efer & EFER_SVME) ||
-           !is_paging(&svm->vcpu)) {
-               kvm_queue_exception(&svm->vcpu, UD_VECTOR);
+       if (nested_svm_check_permissions(svm))
                return 1;
-       }
 
-       if (svm->vmcb->save.cpl) {
-               kvm_inject_gp(&svm->vcpu, 0);
+       ret = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(svm->vmcb->save.rax), &map);
+       if (ret) {
+               if (ret == -EINVAL)
+                       kvm_inject_gp(&svm->vcpu, 0);
                return 1;
        }
 
-       return 0;
+       nested_vmcb = map.hva;
+
+       ret = kvm_skip_emulated_instruction(&svm->vcpu);
+
+       nested_svm_vmloadsave(svm->vmcb, nested_vmcb);
+       kvm_vcpu_unmap(&svm->vcpu, &map, true);
+
+       return ret;
 }
 
-static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
-                                     bool has_error_code, u32 error_code)
+static int vmrun_interception(struct vcpu_svm *svm)
 {
-       int vmexit;
+       if (nested_svm_check_permissions(svm))
+               return 1;
 
-       if (!is_guest_mode(&svm->vcpu))
-               return 0;
+       return nested_svm_vmrun(svm);
+}
 
-       vmexit = nested_svm_intercept(svm);
-       if (vmexit != NESTED_EXIT_DONE)
-               return 0;
+static int stgi_interception(struct vcpu_svm *svm)
+{
+       int ret;
 
-       svm->vmcb->control.exit_code = SVM_EXIT_EXCP_BASE + nr;
-       svm->vmcb->control.exit_code_hi = 0;
-       svm->vmcb->control.exit_info_1 = error_code;
+       if (nested_svm_check_permissions(svm))
+               return 1;
 
        /*
-        * EXITINFO2 is undefined for all exception intercepts other
-        * than #PF.
+        * If VGIF is enabled, the STGI intercept is only added to
+        * detect the opening of the SMI/NMI window; remove it now.
         */
-       if (svm->vcpu.arch.exception.nested_apf)
-               svm->vmcb->control.exit_info_2 = svm->vcpu.arch.apf.nested_apf_token;
-       else if (svm->vcpu.arch.exception.has_payload)
-               svm->vmcb->control.exit_info_2 = svm->vcpu.arch.exception.payload;
-       else
-               svm->vmcb->control.exit_info_2 = svm->vcpu.arch.cr2;
-
-       svm->nested.exit_required = true;
-       return vmexit;
-}
+       if (vgif_enabled(svm))
+               clr_intercept(svm, INTERCEPT_STGI);
 
-static void nested_svm_intr(struct vcpu_svm *svm)
-{
-       svm->vmcb->control.exit_code   = SVM_EXIT_INTR;
-       svm->vmcb->control.exit_info_1 = 0;
-       svm->vmcb->control.exit_info_2 = 0;
+       ret = kvm_skip_emulated_instruction(&svm->vcpu);
+       kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
 
-       /* nested_svm_vmexit this gets called afterwards from handle_exit */
-       svm->nested.exit_required = true;
-       trace_kvm_nested_intr_vmexit(svm->vmcb->save.rip);
-}
+       enable_gif(svm);
 
-static bool nested_exit_on_intr(struct vcpu_svm *svm)
-{
-       return (svm->nested.intercept & 1ULL);
+       return ret;
 }
 
-static int svm_check_nested_events(struct kvm_vcpu *vcpu)
+static int clgi_interception(struct vcpu_svm *svm)
 {
-       struct vcpu_svm *svm = to_svm(vcpu);
-       bool block_nested_events =
-               kvm_event_needs_reinjection(vcpu) || svm->nested.exit_required;
-
-       if (kvm_cpu_has_interrupt(vcpu) && nested_exit_on_intr(svm)) {
-               if (block_nested_events)
-                       return -EBUSY;
-               nested_svm_intr(svm);
-               return 0;
-       }
+       int ret;
 
-       return 0;
-}
+       if (nested_svm_check_permissions(svm))
+               return 1;
 
-/* This function returns true if it is save to enable the nmi window */
-static inline bool nested_svm_nmi(struct vcpu_svm *svm)
-{
-       if (!is_guest_mode(&svm->vcpu))
-               return true;
+       ret = kvm_skip_emulated_instruction(&svm->vcpu);
 
-       if (!(svm->nested.intercept & (1ULL << INTERCEPT_NMI)))
-               return true;
+       disable_gif(svm);
 
-       svm->vmcb->control.exit_code = SVM_EXIT_NMI;
-       svm->nested.exit_required = true;
+       /* After a CLGI no interrupts should come */
+       if (!kvm_vcpu_apicv_active(&svm->vcpu))
+               svm_clear_vintr(svm);
 
-       return false;
+       return ret;
 }
 
-static int nested_svm_intercept_ioio(struct vcpu_svm *svm)
+static int invlpga_interception(struct vcpu_svm *svm)
 {
-       unsigned port, size, iopm_len;
-       u16 val, mask;
-       u8 start_bit;
-       u64 gpa;
-
-       if (!(svm->nested.intercept & (1ULL << INTERCEPT_IOIO_PROT)))
-               return NESTED_EXIT_HOST;
+       struct kvm_vcpu *vcpu = &svm->vcpu;
 
-       port = svm->vmcb->control.exit_info_1 >> 16;
-       size = (svm->vmcb->control.exit_info_1 & SVM_IOIO_SIZE_MASK) >>
-               SVM_IOIO_SIZE_SHIFT;
-       gpa  = svm->nested.vmcb_iopm + (port / 8);
-       start_bit = port % 8;
-       iopm_len = (start_bit + size > 8) ? 2 : 1;
-       mask = (0xf >> (4 - size)) << start_bit;
-       val = 0;
+       trace_kvm_invlpga(svm->vmcb->save.rip, kvm_rcx_read(&svm->vcpu),
+                         kvm_rax_read(&svm->vcpu));
 
-       if (kvm_vcpu_read_guest(&svm->vcpu, gpa, &val, iopm_len))
-               return NESTED_EXIT_DONE;
+       /* Let's treat INVLPGA the same as INVLPG (can be optimized!) */
+       kvm_mmu_invlpg(vcpu, kvm_rax_read(&svm->vcpu));
 
-       return (val & mask) ? NESTED_EXIT_DONE : NESTED_EXIT_HOST;
+       return kvm_skip_emulated_instruction(&svm->vcpu);
 }
 
-static int nested_svm_exit_handled_msr(struct vcpu_svm *svm)
+static int skinit_interception(struct vcpu_svm *svm)
 {
-       u32 offset, msr, value;
-       int write, mask;
+       trace_kvm_skinit(svm->vmcb->save.rip, kvm_rax_read(&svm->vcpu));
 
-       if (!(svm->nested.intercept & (1ULL << INTERCEPT_MSR_PROT)))
-               return NESTED_EXIT_HOST;
+       kvm_queue_exception(&svm->vcpu, UD_VECTOR);
+       return 1;
+}
 
-       msr    = svm->vcpu.arch.regs[VCPU_REGS_RCX];
-       offset = svm_msrpm_offset(msr);
-       write  = svm->vmcb->control.exit_info_1 & 1;
-       mask   = 1 << ((2 * (msr & 0xf)) + write);
+static int wbinvd_interception(struct vcpu_svm *svm)
+{
+       return kvm_emulate_wbinvd(&svm->vcpu);
+}
 
-       if (offset == MSR_INVALID)
-               return NESTED_EXIT_DONE;
+static int xsetbv_interception(struct vcpu_svm *svm)
+{
+       u64 new_bv = kvm_read_edx_eax(&svm->vcpu);
+       u32 index = kvm_rcx_read(&svm->vcpu);
 
-       /* Offset is in 32 bit units but need in 8 bit units */
-       offset *= 4;
+       if (kvm_set_xcr(&svm->vcpu, index, new_bv) == 0) {
+               return kvm_skip_emulated_instruction(&svm->vcpu);
+       }
 
-       if (kvm_vcpu_read_guest(&svm->vcpu, svm->nested.vmcb_msrpm + offset, &value, 4))
-               return NESTED_EXIT_DONE;
+       return 1;
+}
 
-       return (value & mask) ? NESTED_EXIT_DONE : NESTED_EXIT_HOST;
+static int rdpru_interception(struct vcpu_svm *svm)
+{
+       kvm_queue_exception(&svm->vcpu, UD_VECTOR);
+       return 1;
 }
 
-/* DB exceptions for our internal use must not cause vmexit */
-static int nested_svm_intercept_db(struct vcpu_svm *svm)
+static int task_switch_interception(struct vcpu_svm *svm)
 {
-       unsigned long dr6;
+       u16 tss_selector;
+       int reason;
+       int int_type = svm->vmcb->control.exit_int_info &
+               SVM_EXITINTINFO_TYPE_MASK;
+       int int_vec = svm->vmcb->control.exit_int_info & SVM_EVTINJ_VEC_MASK;
+       uint32_t type =
+               svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_TYPE_MASK;
+       uint32_t idt_v =
+               svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID;
+       bool has_error_code = false;
+       u32 error_code = 0;
 
-       /* if we're not singlestepping, it's not ours */
-       if (!svm->nmi_singlestep)
-               return NESTED_EXIT_DONE;
+       tss_selector = (u16)svm->vmcb->control.exit_info_1;
 
-       /* if it's not a singlestep exception, it's not ours */
-       if (kvm_get_dr(&svm->vcpu, 6, &dr6))
-               return NESTED_EXIT_DONE;
-       if (!(dr6 & DR6_BS))
-               return NESTED_EXIT_DONE;
+       if (svm->vmcb->control.exit_info_2 &
+           (1ULL << SVM_EXITINFOSHIFT_TS_REASON_IRET))
+               reason = TASK_SWITCH_IRET;
+       else if (svm->vmcb->control.exit_info_2 &
+                (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP))
+               reason = TASK_SWITCH_JMP;
+       else if (idt_v)
+               reason = TASK_SWITCH_GATE;
+       else
+               reason = TASK_SWITCH_CALL;
 
-       /* if the guest is singlestepping, it should get the vmexit */
-       if (svm->nmi_singlestep_guest_rflags & X86_EFLAGS_TF) {
-               disable_nmi_singlestep(svm);
-               return NESTED_EXIT_DONE;
+       if (reason == TASK_SWITCH_GATE) {
+               switch (type) {
+               case SVM_EXITINTINFO_TYPE_NMI:
+                       svm->vcpu.arch.nmi_injected = false;
+                       break;
+               case SVM_EXITINTINFO_TYPE_EXEPT:
+                       if (svm->vmcb->control.exit_info_2 &
+                           (1ULL << SVM_EXITINFOSHIFT_TS_HAS_ERROR_CODE)) {
+                               has_error_code = true;
+                               error_code =
+                                       (u32)svm->vmcb->control.exit_info_2;
+                       }
+                       kvm_clear_exception_queue(&svm->vcpu);
+                       break;
+               case SVM_EXITINTINFO_TYPE_INTR:
+                       kvm_clear_interrupt_queue(&svm->vcpu);
+                       break;
+               default:
+                       break;
+               }
        }
 
-       /* it's ours, the nested hypervisor must not see this one */
-       return NESTED_EXIT_HOST;
-}
-
-static int nested_svm_exit_special(struct vcpu_svm *svm)
-{
-       u32 exit_code = svm->vmcb->control.exit_code;
-
-       switch (exit_code) {
-       case SVM_EXIT_INTR:
-       case SVM_EXIT_NMI:
-       case SVM_EXIT_EXCP_BASE + MC_VECTOR:
-               return NESTED_EXIT_HOST;
-       case SVM_EXIT_NPF:
-               /* For now we are always handling NPFs when using them */
-               if (npt_enabled)
-                       return NESTED_EXIT_HOST;
-               break;
-       case SVM_EXIT_EXCP_BASE + PF_VECTOR:
-               /* When we're shadowing, trap PFs, but not async PF */
-               if (!npt_enabled && svm->vcpu.arch.apf.host_apf_reason == 0)
-                       return NESTED_EXIT_HOST;
-               break;
-       default:
-               break;
+       if (reason != TASK_SWITCH_GATE ||
+           int_type == SVM_EXITINTINFO_TYPE_SOFT ||
+           (int_type == SVM_EXITINTINFO_TYPE_EXEPT &&
+            (int_vec == OF_VECTOR || int_vec == BP_VECTOR))) {
+               if (!skip_emulated_instruction(&svm->vcpu))
+                       return 0;
        }
 
-       return NESTED_EXIT_CONTINUE;
+       if (int_type != SVM_EXITINTINFO_TYPE_SOFT)
+               int_vec = -1;
+
+       return kvm_task_switch(&svm->vcpu, tss_selector, int_vec, reason,
+                              has_error_code, error_code);
 }
 
-static int nested_svm_intercept(struct vcpu_svm *svm)
+static int cpuid_interception(struct vcpu_svm *svm)
 {
-       u32 exit_code = svm->vmcb->control.exit_code;
-       int vmexit = NESTED_EXIT_HOST;
-
-       switch (exit_code) {
-       case SVM_EXIT_MSR:
-               vmexit = nested_svm_exit_handled_msr(svm);
-               break;
-       case SVM_EXIT_IOIO:
-               vmexit = nested_svm_intercept_ioio(svm);
-               break;
-       case SVM_EXIT_READ_CR0 ... SVM_EXIT_WRITE_CR8: {
-               u32 bit = 1U << (exit_code - SVM_EXIT_READ_CR0);
-               if (svm->nested.intercept_cr & bit)
-                       vmexit = NESTED_EXIT_DONE;
-               break;
-       }
-       case SVM_EXIT_READ_DR0 ... SVM_EXIT_WRITE_DR7: {
-               u32 bit = 1U << (exit_code - SVM_EXIT_READ_DR0);
-               if (svm->nested.intercept_dr & bit)
-                       vmexit = NESTED_EXIT_DONE;
-               break;
-       }
-       case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 0x1f: {
-               u32 excp_bits = 1 << (exit_code - SVM_EXIT_EXCP_BASE);
-               if (svm->nested.intercept_exceptions & excp_bits) {
-                       if (exit_code == SVM_EXIT_EXCP_BASE + DB_VECTOR)
-                               vmexit = nested_svm_intercept_db(svm);
-                       else
-                               vmexit = NESTED_EXIT_DONE;
-               }
-               /* async page fault always cause vmexit */
-               else if ((exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR) &&
-                        svm->vcpu.arch.exception.nested_apf != 0)
-                       vmexit = NESTED_EXIT_DONE;
-               break;
-       }
-       case SVM_EXIT_ERR: {
-               vmexit = NESTED_EXIT_DONE;
-               break;
-       }
-       default: {
-               u64 exit_bits = 1ULL << (exit_code - SVM_EXIT_INTR);
-               if (svm->nested.intercept & exit_bits)
-                       vmexit = NESTED_EXIT_DONE;
-       }
-       }
+       return kvm_emulate_cpuid(&svm->vcpu);
+}
 
-       return vmexit;
+static int iret_interception(struct vcpu_svm *svm)
+{
+       ++svm->vcpu.stat.nmi_window_exits;
+       clr_intercept(svm, INTERCEPT_IRET);
+       svm->vcpu.arch.hflags |= HF_IRET_MASK;
+       svm->nmi_iret_rip = kvm_rip_read(&svm->vcpu);
+       kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
+       return 1;
 }
 
-static int nested_svm_exit_handled(struct vcpu_svm *svm)
+static int invlpg_interception(struct vcpu_svm *svm)
 {
-       int vmexit;
+       if (!static_cpu_has(X86_FEATURE_DECODEASSISTS))
+               return kvm_emulate_instruction(&svm->vcpu, 0);
 
-       vmexit = nested_svm_intercept(svm);
+       kvm_mmu_invlpg(&svm->vcpu, svm->vmcb->control.exit_info_1);
+       return kvm_skip_emulated_instruction(&svm->vcpu);
+}
 
-       if (vmexit == NESTED_EXIT_DONE)
-               nested_svm_vmexit(svm);
+static int emulate_on_interception(struct vcpu_svm *svm)
+{
+       return kvm_emulate_instruction(&svm->vcpu, 0);
+}
 
-       return vmexit;
-}
-
-static inline void copy_vmcb_control_area(struct vmcb *dst_vmcb, struct vmcb *from_vmcb)
-{
-       struct vmcb_control_area *dst  = &dst_vmcb->control;
-       struct vmcb_control_area *from = &from_vmcb->control;
-
-       dst->intercept_cr         = from->intercept_cr;
-       dst->intercept_dr         = from->intercept_dr;
-       dst->intercept_exceptions = from->intercept_exceptions;
-       dst->intercept            = from->intercept;
-       dst->iopm_base_pa         = from->iopm_base_pa;
-       dst->msrpm_base_pa        = from->msrpm_base_pa;
-       dst->tsc_offset           = from->tsc_offset;
-       dst->asid                 = from->asid;
-       dst->tlb_ctl              = from->tlb_ctl;
-       dst->int_ctl              = from->int_ctl;
-       dst->int_vector           = from->int_vector;
-       dst->int_state            = from->int_state;
-       dst->exit_code            = from->exit_code;
-       dst->exit_code_hi         = from->exit_code_hi;
-       dst->exit_info_1          = from->exit_info_1;
-       dst->exit_info_2          = from->exit_info_2;
-       dst->exit_int_info        = from->exit_int_info;
-       dst->exit_int_info_err    = from->exit_int_info_err;
-       dst->nested_ctl           = from->nested_ctl;
-       dst->event_inj            = from->event_inj;
-       dst->event_inj_err        = from->event_inj_err;
-       dst->nested_cr3           = from->nested_cr3;
-       dst->virt_ext              = from->virt_ext;
-       dst->pause_filter_count   = from->pause_filter_count;
-       dst->pause_filter_thresh  = from->pause_filter_thresh;
-}
-
-static int nested_svm_vmexit(struct vcpu_svm *svm)
-{
-       int rc;
-       struct vmcb *nested_vmcb;
-       struct vmcb *hsave = svm->nested.hsave;
-       struct vmcb *vmcb = svm->vmcb;
-       struct kvm_host_map map;
+static int rsm_interception(struct vcpu_svm *svm)
+{
+       return kvm_emulate_instruction_from_buffer(&svm->vcpu, rsm_ins_bytes, 2);
+}
 
-       trace_kvm_nested_vmexit_inject(vmcb->control.exit_code,
-                                      vmcb->control.exit_info_1,
-                                      vmcb->control.exit_info_2,
-                                      vmcb->control.exit_int_info,
-                                      vmcb->control.exit_int_info_err,
-                                      KVM_ISA_SVM);
+static int rdpmc_interception(struct vcpu_svm *svm)
+{
+       int err;
 
-       rc = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(svm->nested.vmcb), &map);
-       if (rc) {
-               if (rc == -EINVAL)
-                       kvm_inject_gp(&svm->vcpu, 0);
-               return 1;
-       }
+       if (!nrips)
+               return emulate_on_interception(svm);
 
-       nested_vmcb = map.hva;
+       err = kvm_rdpmc(&svm->vcpu);
+       return kvm_complete_insn_gp(&svm->vcpu, err);
+}
 
-       /* Exit Guest-Mode */
-       leave_guest_mode(&svm->vcpu);
-       svm->nested.vmcb = 0;
+static bool check_selective_cr0_intercepted(struct vcpu_svm *svm,
+                                           unsigned long val)
+{
+       unsigned long cr0 = svm->vcpu.arch.cr0;
+       bool ret = false;
+       u64 intercept;
 
-       /* Give the current vmcb to the guest */
-       disable_gif(svm);
+       intercept = svm->nested.intercept;
 
-       nested_vmcb->save.es     = vmcb->save.es;
-       nested_vmcb->save.cs     = vmcb->save.cs;
-       nested_vmcb->save.ss     = vmcb->save.ss;
-       nested_vmcb->save.ds     = vmcb->save.ds;
-       nested_vmcb->save.gdtr   = vmcb->save.gdtr;
-       nested_vmcb->save.idtr   = vmcb->save.idtr;
-       nested_vmcb->save.efer   = svm->vcpu.arch.efer;
-       nested_vmcb->save.cr0    = kvm_read_cr0(&svm->vcpu);
-       nested_vmcb->save.cr3    = kvm_read_cr3(&svm->vcpu);
-       nested_vmcb->save.cr2    = vmcb->save.cr2;
-       nested_vmcb->save.cr4    = svm->vcpu.arch.cr4;
-       nested_vmcb->save.rflags = kvm_get_rflags(&svm->vcpu);
-       nested_vmcb->save.rip    = vmcb->save.rip;
-       nested_vmcb->save.rsp    = vmcb->save.rsp;
-       nested_vmcb->save.rax    = vmcb->save.rax;
-       nested_vmcb->save.dr7    = vmcb->save.dr7;
-       nested_vmcb->save.dr6    = vmcb->save.dr6;
-       nested_vmcb->save.cpl    = vmcb->save.cpl;
-
-       nested_vmcb->control.int_ctl           = vmcb->control.int_ctl;
-       nested_vmcb->control.int_vector        = vmcb->control.int_vector;
-       nested_vmcb->control.int_state         = vmcb->control.int_state;
-       nested_vmcb->control.exit_code         = vmcb->control.exit_code;
-       nested_vmcb->control.exit_code_hi      = vmcb->control.exit_code_hi;
-       nested_vmcb->control.exit_info_1       = vmcb->control.exit_info_1;
-       nested_vmcb->control.exit_info_2       = vmcb->control.exit_info_2;
-       nested_vmcb->control.exit_int_info     = vmcb->control.exit_int_info;
-       nested_vmcb->control.exit_int_info_err = vmcb->control.exit_int_info_err;
-
-       if (svm->nrips_enabled)
-               nested_vmcb->control.next_rip  = vmcb->control.next_rip;
+       if (!is_guest_mode(&svm->vcpu) ||
+           (!(intercept & (1ULL << INTERCEPT_SELECTIVE_CR0))))
+               return false;
 
-       /*
-        * If we emulate a VMRUN/#VMEXIT in the same host #vmexit cycle we have
-        * to make sure that we do not lose injected events. So check event_inj
-        * here and copy it to exit_int_info if it is valid.
-        * Exit_int_info and event_inj can't be both valid because the case
-        * below only happens on a VMRUN instruction intercept which has
-        * no valid exit_int_info set.
-        */
-       if (vmcb->control.event_inj & SVM_EVTINJ_VALID) {
-               struct vmcb_control_area *nc = &nested_vmcb->control;
+       cr0 &= ~SVM_CR0_SELECTIVE_MASK;
+       val &= ~SVM_CR0_SELECTIVE_MASK;
 
-               nc->exit_int_info     = vmcb->control.event_inj;
-               nc->exit_int_info_err = vmcb->control.event_inj_err;
+       if (cr0 ^ val) {
+               svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE;
+               ret = (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE);
        }
 
-       nested_vmcb->control.tlb_ctl           = 0;
-       nested_vmcb->control.event_inj         = 0;
-       nested_vmcb->control.event_inj_err     = 0;
+       return ret;
+}
 
-       nested_vmcb->control.pause_filter_count =
-               svm->vmcb->control.pause_filter_count;
-       nested_vmcb->control.pause_filter_thresh =
-               svm->vmcb->control.pause_filter_thresh;
+#define CR_VALID (1ULL << 63)
 
-       /* We always set V_INTR_MASKING and remember the old value in hflags */
-       if (!(svm->vcpu.arch.hflags & HF_VINTR_MASK))
-               nested_vmcb->control.int_ctl &= ~V_INTR_MASKING_MASK;
+static int cr_interception(struct vcpu_svm *svm)
+{
+       int reg, cr;
+       unsigned long val;
+       int err;
 
-       /* Restore the original control entries */
-       copy_vmcb_control_area(vmcb, hsave);
+       if (!static_cpu_has(X86_FEATURE_DECODEASSISTS))
+               return emulate_on_interception(svm);
 
-       svm->vcpu.arch.tsc_offset = svm->vmcb->control.tsc_offset;
-       kvm_clear_exception_queue(&svm->vcpu);
-       kvm_clear_interrupt_queue(&svm->vcpu);
-
-       svm->nested.nested_cr3 = 0;
-
-       /* Restore selected save entries */
-       svm->vmcb->save.es = hsave->save.es;
-       svm->vmcb->save.cs = hsave->save.cs;
-       svm->vmcb->save.ss = hsave->save.ss;
-       svm->vmcb->save.ds = hsave->save.ds;
-       svm->vmcb->save.gdtr = hsave->save.gdtr;
-       svm->vmcb->save.idtr = hsave->save.idtr;
-       kvm_set_rflags(&svm->vcpu, hsave->save.rflags);
-       svm_set_efer(&svm->vcpu, hsave->save.efer);
-       svm_set_cr0(&svm->vcpu, hsave->save.cr0 | X86_CR0_PE);
-       svm_set_cr4(&svm->vcpu, hsave->save.cr4);
-       if (npt_enabled) {
-               svm->vmcb->save.cr3 = hsave->save.cr3;
-               svm->vcpu.arch.cr3 = hsave->save.cr3;
-       } else {
-               (void)kvm_set_cr3(&svm->vcpu, hsave->save.cr3);
-       }
-       kvm_rax_write(&svm->vcpu, hsave->save.rax);
-       kvm_rsp_write(&svm->vcpu, hsave->save.rsp);
-       kvm_rip_write(&svm->vcpu, hsave->save.rip);
-       svm->vmcb->save.dr7 = 0;
-       svm->vmcb->save.cpl = 0;
-       svm->vmcb->control.exit_int_info = 0;
-
-       mark_all_dirty(svm->vmcb);
-
-       kvm_vcpu_unmap(&svm->vcpu, &map, true);
+       if (unlikely((svm->vmcb->control.exit_info_1 & CR_VALID) == 0))
+               return emulate_on_interception(svm);
 
-       nested_svm_uninit_mmu_context(&svm->vcpu);
-       kvm_mmu_reset_context(&svm->vcpu);
-       kvm_mmu_load(&svm->vcpu);
+       reg = svm->vmcb->control.exit_info_1 & SVM_EXITINFO_REG_MASK;
+       if (svm->vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE)
+               cr = SVM_EXIT_WRITE_CR0 - SVM_EXIT_READ_CR0;
+       else
+               cr = svm->vmcb->control.exit_code - SVM_EXIT_READ_CR0;
 
-       /*
-        * Drop what we picked up for L2 via svm_complete_interrupts() so it
-        * doesn't end up in L1.
-        */
-       svm->vcpu.arch.nmi_injected = false;
-       kvm_clear_exception_queue(&svm->vcpu);
-       kvm_clear_interrupt_queue(&svm->vcpu);
+       err = 0;
+       if (cr >= 16) { /* mov to cr */
+               cr -= 16;
+               val = kvm_register_read(&svm->vcpu, reg);
+               switch (cr) {
+               case 0:
+                       if (!check_selective_cr0_intercepted(svm, val))
+                               err = kvm_set_cr0(&svm->vcpu, val);
+                       else
+                               return 1;
 
-       return 0;
+                       break;
+               case 3:
+                       err = kvm_set_cr3(&svm->vcpu, val);
+                       break;
+               case 4:
+                       err = kvm_set_cr4(&svm->vcpu, val);
+                       break;
+               case 8:
+                       err = kvm_set_cr8(&svm->vcpu, val);
+                       break;
+               default:
+                       WARN(1, "unhandled write to CR%d", cr);
+                       kvm_queue_exception(&svm->vcpu, UD_VECTOR);
+                       return 1;
+               }
+       } else { /* mov from cr */
+               switch (cr) {
+               case 0:
+                       val = kvm_read_cr0(&svm->vcpu);
+                       break;
+               case 2:
+                       val = svm->vcpu.arch.cr2;
+                       break;
+               case 3:
+                       val = kvm_read_cr3(&svm->vcpu);
+                       break;
+               case 4:
+                       val = kvm_read_cr4(&svm->vcpu);
+                       break;
+               case 8:
+                       val = kvm_get_cr8(&svm->vcpu);
+                       break;
+               default:
+                       WARN(1, "unhandled read from CR%d", cr);
+                       kvm_queue_exception(&svm->vcpu, UD_VECTOR);
+                       return 1;
+               }
+               kvm_register_write(&svm->vcpu, reg, val);
+       }
+       return kvm_complete_insn_gp(&svm->vcpu, err);
 }
 
-static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
+static int dr_interception(struct vcpu_svm *svm)
 {
-       /*
-        * This function merges the msr permission bitmaps of kvm and the
-        * nested vmcb. It is optimized in that it only merges the parts where
-        * the kvm msr permission bitmap may contain zero bits
-        */
-       int i;
-
-       if (!(svm->nested.intercept & (1ULL << INTERCEPT_MSR_PROT)))
-               return true;
-
-       for (i = 0; i < MSRPM_OFFSETS; i++) {
-               u32 value, p;
-               u64 offset;
+       int reg, dr;
+       unsigned long val;
 
-               if (msrpm_offsets[i] == 0xffffffff)
-                       break;
+       if (svm->vcpu.guest_debug == 0) {
+               /*
+                * No more DR vmexits; force a reload of the debug registers
+                * and reenter on this instruction.  The next vmexit will
+                * retrieve the full state of the debug registers.
+                */
+               clr_dr_intercepts(svm);
+               svm->vcpu.arch.switch_db_regs |= KVM_DEBUGREG_WONT_EXIT;
+               return 1;
+       }
 
-               p      = msrpm_offsets[i];
-               offset = svm->nested.vmcb_msrpm + (p * 4);
+       if (!boot_cpu_has(X86_FEATURE_DECODEASSISTS))
+               return emulate_on_interception(svm);
 
-               if (kvm_vcpu_read_guest(&svm->vcpu, offset, &value, 4))
-                       return false;
+       reg = svm->vmcb->control.exit_info_1 & SVM_EXITINFO_REG_MASK;
+       dr = svm->vmcb->control.exit_code - SVM_EXIT_READ_DR0;
 
-               svm->nested.msrpm[p] = svm->msrpm[p] | value;
+       if (dr >= 16) { /* mov to DRn */
+               if (!kvm_require_dr(&svm->vcpu, dr - 16))
+                       return 1;
+               val = kvm_register_read(&svm->vcpu, reg);
+               kvm_set_dr(&svm->vcpu, dr - 16, val);
+       } else {
+               if (!kvm_require_dr(&svm->vcpu, dr))
+                       return 1;
+               kvm_get_dr(&svm->vcpu, dr, &val);
+               kvm_register_write(&svm->vcpu, reg, val);
        }
 
-       svm->vmcb->control.msrpm_base_pa = __sme_set(__pa(svm->nested.msrpm));
-
-       return true;
+       return kvm_skip_emulated_instruction(&svm->vcpu);
 }
 
-static bool nested_vmcb_checks(struct vmcb *vmcb)
+static int cr8_write_interception(struct vcpu_svm *svm)
 {
-       if ((vmcb->save.efer & EFER_SVME) == 0)
-               return false;
-
-       if ((vmcb->control.intercept & (1ULL << INTERCEPT_VMRUN)) == 0)
-               return false;
-
-       if (vmcb->control.asid == 0)
-               return false;
-
-       if ((vmcb->control.nested_ctl & SVM_NESTED_CTL_NP_ENABLE) &&
-           !npt_enabled)
-               return false;
+       struct kvm_run *kvm_run = svm->vcpu.run;
+       int r;
 
-       return true;
+       u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
+       /* instruction emulation calls kvm_set_cr8() */
+       r = cr_interception(svm);
+       if (lapic_in_kernel(&svm->vcpu))
+               return r;
+       if (cr8_prev <= kvm_get_cr8(&svm->vcpu))
+               return r;
+       kvm_run->exit_reason = KVM_EXIT_SET_TPR;
+       return 0;
 }
 
-static void enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb_gpa,
-                                struct vmcb *nested_vmcb, struct kvm_host_map *map)
+static int svm_get_msr_feature(struct kvm_msr_entry *msr)
 {
-       bool evaluate_pending_interrupts =
-               is_intercept(svm, INTERCEPT_VINTR) ||
-               is_intercept(svm, INTERCEPT_IRET);
-
-       if (kvm_get_rflags(&svm->vcpu) & X86_EFLAGS_IF)
-               svm->vcpu.arch.hflags |= HF_HIF_MASK;
-       else
-               svm->vcpu.arch.hflags &= ~HF_HIF_MASK;
+       msr->data = 0;
 
-       if (nested_vmcb->control.nested_ctl & SVM_NESTED_CTL_NP_ENABLE) {
-               svm->nested.nested_cr3 = nested_vmcb->control.nested_cr3;
-               nested_svm_init_mmu_context(&svm->vcpu);
+       switch (msr->index) {
+       case MSR_F10H_DECFG:
+               if (boot_cpu_has(X86_FEATURE_LFENCE_RDTSC))
+                       msr->data |= MSR_F10H_DECFG_LFENCE_SERIALIZE;
+               break;
+       default:
+               return 1;
        }
 
-       /* Load the nested guest state */
-       svm->vmcb->save.es = nested_vmcb->save.es;
-       svm->vmcb->save.cs = nested_vmcb->save.cs;
-       svm->vmcb->save.ss = nested_vmcb->save.ss;
-       svm->vmcb->save.ds = nested_vmcb->save.ds;
-       svm->vmcb->save.gdtr = nested_vmcb->save.gdtr;
-       svm->vmcb->save.idtr = nested_vmcb->save.idtr;
-       kvm_set_rflags(&svm->vcpu, nested_vmcb->save.rflags);
-       svm_set_efer(&svm->vcpu, nested_vmcb->save.efer);
-       svm_set_cr0(&svm->vcpu, nested_vmcb->save.cr0);
-       svm_set_cr4(&svm->vcpu, nested_vmcb->save.cr4);
-       if (npt_enabled) {
-               svm->vmcb->save.cr3 = nested_vmcb->save.cr3;
-               svm->vcpu.arch.cr3 = nested_vmcb->save.cr3;
-       } else
-               (void)kvm_set_cr3(&svm->vcpu, nested_vmcb->save.cr3);
-
-       /* Guest paging mode is active - reset mmu */
-       kvm_mmu_reset_context(&svm->vcpu);
+       return 0;
+}
 
-       svm->vmcb->save.cr2 = svm->vcpu.arch.cr2 = nested_vmcb->save.cr2;
-       kvm_rax_write(&svm->vcpu, nested_vmcb->save.rax);
-       kvm_rsp_write(&svm->vcpu, nested_vmcb->save.rsp);
-       kvm_rip_write(&svm->vcpu, nested_vmcb->save.rip);
-
-       /* In case we don't even reach vcpu_run, the fields are not updated */
-       svm->vmcb->save.rax = nested_vmcb->save.rax;
-       svm->vmcb->save.rsp = nested_vmcb->save.rsp;
-       svm->vmcb->save.rip = nested_vmcb->save.rip;
-       svm->vmcb->save.dr7 = nested_vmcb->save.dr7;
-       svm->vmcb->save.dr6 = nested_vmcb->save.dr6;
-       svm->vmcb->save.cpl = nested_vmcb->save.cpl;
-
-       svm->nested.vmcb_msrpm = nested_vmcb->control.msrpm_base_pa & ~0x0fffULL;
-       svm->nested.vmcb_iopm  = nested_vmcb->control.iopm_base_pa  & ~0x0fffULL;
-
-       /* cache intercepts */
-       svm->nested.intercept_cr         = nested_vmcb->control.intercept_cr;
-       svm->nested.intercept_dr         = nested_vmcb->control.intercept_dr;
-       svm->nested.intercept_exceptions = nested_vmcb->control.intercept_exceptions;
-       svm->nested.intercept            = nested_vmcb->control.intercept;
-
-       svm_flush_tlb(&svm->vcpu, true);
-       svm->vmcb->control.int_ctl = nested_vmcb->control.int_ctl | V_INTR_MASKING_MASK;
-       if (nested_vmcb->control.int_ctl & V_INTR_MASKING_MASK)
-               svm->vcpu.arch.hflags |= HF_VINTR_MASK;
-       else
-               svm->vcpu.arch.hflags &= ~HF_VINTR_MASK;
+static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
 
-       svm->vcpu.arch.tsc_offset += nested_vmcb->control.tsc_offset;
-       svm->vmcb->control.tsc_offset = svm->vcpu.arch.tsc_offset;
+       switch (msr_info->index) {
+       case MSR_STAR:
+               msr_info->data = svm->vmcb->save.star;
+               break;
+#ifdef CONFIG_X86_64
+       case MSR_LSTAR:
+               msr_info->data = svm->vmcb->save.lstar;
+               break;
+       case MSR_CSTAR:
+               msr_info->data = svm->vmcb->save.cstar;
+               break;
+       case MSR_KERNEL_GS_BASE:
+               msr_info->data = svm->vmcb->save.kernel_gs_base;
+               break;
+       case MSR_SYSCALL_MASK:
+               msr_info->data = svm->vmcb->save.sfmask;
+               break;
+#endif
+       case MSR_IA32_SYSENTER_CS:
+               msr_info->data = svm->vmcb->save.sysenter_cs;
+               break;
+       case MSR_IA32_SYSENTER_EIP:
+               msr_info->data = svm->sysenter_eip;
+               break;
+       case MSR_IA32_SYSENTER_ESP:
+               msr_info->data = svm->sysenter_esp;
+               break;
+       case MSR_TSC_AUX:
+               if (!boot_cpu_has(X86_FEATURE_RDTSCP))
+                       return 1;
+               msr_info->data = svm->tsc_aux;
+               break;
+       /*
+        * Nobody will change the following 5 values in the VMCB so we can
+        * safely return them on rdmsr. They will always be 0 until LBRV is
+        * implemented.
+        */
+       case MSR_IA32_DEBUGCTLMSR:
+               msr_info->data = svm->vmcb->save.dbgctl;
+               break;
+       case MSR_IA32_LASTBRANCHFROMIP:
+               msr_info->data = svm->vmcb->save.br_from;
+               break;
+       case MSR_IA32_LASTBRANCHTOIP:
+               msr_info->data = svm->vmcb->save.br_to;
+               break;
+       case MSR_IA32_LASTINTFROMIP:
+               msr_info->data = svm->vmcb->save.last_excp_from;
+               break;
+       case MSR_IA32_LASTINTTOIP:
+               msr_info->data = svm->vmcb->save.last_excp_to;
+               break;
+       case MSR_VM_HSAVE_PA:
+               msr_info->data = svm->nested.hsave_msr;
+               break;
+       case MSR_VM_CR:
+               msr_info->data = svm->nested.vm_cr_msr;
+               break;
+       case MSR_IA32_SPEC_CTRL:
+               if (!msr_info->host_initiated &&
+                   !guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL) &&
+                   !guest_cpuid_has(vcpu, X86_FEATURE_AMD_STIBP) &&
+                   !guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBRS) &&
+                   !guest_cpuid_has(vcpu, X86_FEATURE_AMD_SSBD))
+                       return 1;
 
-       svm->vmcb->control.virt_ext = nested_vmcb->control.virt_ext;
-       svm->vmcb->control.int_vector = nested_vmcb->control.int_vector;
-       svm->vmcb->control.int_state = nested_vmcb->control.int_state;
-       svm->vmcb->control.event_inj = nested_vmcb->control.event_inj;
-       svm->vmcb->control.event_inj_err = nested_vmcb->control.event_inj_err;
+               msr_info->data = svm->spec_ctrl;
+               break;
+       case MSR_AMD64_VIRT_SPEC_CTRL:
+               if (!msr_info->host_initiated &&
+                   !guest_cpuid_has(vcpu, X86_FEATURE_VIRT_SSBD))
+                       return 1;
 
-       svm->vmcb->control.pause_filter_count =
-               nested_vmcb->control.pause_filter_count;
-       svm->vmcb->control.pause_filter_thresh =
-               nested_vmcb->control.pause_filter_thresh;
+               msr_info->data = svm->virt_spec_ctrl;
+               break;
+       case MSR_F15H_IC_CFG: {
 
-       kvm_vcpu_unmap(&svm->vcpu, map, true);
+               int family, model;
 
-       /* Enter Guest-Mode */
-       enter_guest_mode(&svm->vcpu);
+               family = guest_cpuid_family(vcpu);
+               model  = guest_cpuid_model(vcpu);
 
-       /*
-        * Merge guest and host intercepts - must be called  with vcpu in
-        * guest-mode to take affect here
-        */
-       recalc_intercepts(svm);
+               if (family < 0 || model < 0)
+                       return kvm_get_msr_common(vcpu, msr_info);
 
-       svm->nested.vmcb = vmcb_gpa;
+               msr_info->data = 0;
 
-       /*
-        * If L1 had a pending IRQ/NMI before executing VMRUN,
-        * which wasn't delivered because it was disallowed (e.g.
-        * interrupts disabled), L0 needs to evaluate if this pending
-        * event should cause an exit from L2 to L1 or be delivered
-        * directly to L2.
-        *
-        * Usually this would be handled by the processor noticing an
-        * IRQ/NMI window request.  However, VMRUN can unblock interrupts
-        * by implicitly setting GIF, so force L0 to perform pending event
-        * evaluation by requesting a KVM_REQ_EVENT.
-        */
-       enable_gif(svm);
-       if (unlikely(evaluate_pending_interrupts))
-               kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
+               if (family == 0x15 &&
+                   (model >= 0x2 && model < 0x20))
+                       msr_info->data = 0x1E;
+               }
+               break;
+       case MSR_F10H_DECFG:
+               msr_info->data = svm->msr_decfg;
+               break;
+       default:
+               return kvm_get_msr_common(vcpu, msr_info);
+       }
+       return 0;
+}
 
-       mark_all_dirty(svm->vmcb);
+static int rdmsr_interception(struct vcpu_svm *svm)
+{
+       return kvm_emulate_rdmsr(&svm->vcpu);
 }
 
-static int nested_svm_vmrun(struct vcpu_svm *svm)
+static int svm_set_vm_cr(struct kvm_vcpu *vcpu, u64 data)
 {
-       int ret;
-       struct vmcb *nested_vmcb;
-       struct vmcb *hsave = svm->nested.hsave;
-       struct vmcb *vmcb = svm->vmcb;
-       struct kvm_host_map map;
-       u64 vmcb_gpa;
-
-       vmcb_gpa = svm->vmcb->save.rax;
+       struct vcpu_svm *svm = to_svm(vcpu);
+       int svm_dis, chg_mask;
 
-       ret = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(vmcb_gpa), &map);
-       if (ret == -EINVAL) {
-               kvm_inject_gp(&svm->vcpu, 0);
+       if (data & ~SVM_VM_CR_VALID_MASK)
                return 1;
-       } else if (ret) {
-               return kvm_skip_emulated_instruction(&svm->vcpu);
-       }
 
-       ret = kvm_skip_emulated_instruction(&svm->vcpu);
+       chg_mask = SVM_VM_CR_VALID_MASK;
 
-       nested_vmcb = map.hva;
+       if (svm->nested.vm_cr_msr & SVM_VM_CR_SVM_DIS_MASK)
+               chg_mask &= ~(SVM_VM_CR_SVM_LOCK_MASK | SVM_VM_CR_SVM_DIS_MASK);
 
-       if (!nested_vmcb_checks(nested_vmcb)) {
-               nested_vmcb->control.exit_code    = SVM_EXIT_ERR;
-               nested_vmcb->control.exit_code_hi = 0;
-               nested_vmcb->control.exit_info_1  = 0;
-               nested_vmcb->control.exit_info_2  = 0;
+       svm->nested.vm_cr_msr &= ~chg_mask;
+       svm->nested.vm_cr_msr |= (data & chg_mask);
 
-               kvm_vcpu_unmap(&svm->vcpu, &map, true);
+       svm_dis = svm->nested.vm_cr_msr & SVM_VM_CR_SVM_DIS_MASK;
 
-               return ret;
-       }
+       /* check for svm_disable while efer.svme is set */
+       if (svm_dis && (vcpu->arch.efer & EFER_SVME))
+               return 1;
 
-       trace_kvm_nested_vmrun(svm->vmcb->save.rip, vmcb_gpa,
-                              nested_vmcb->save.rip,
-                              nested_vmcb->control.int_ctl,
-                              nested_vmcb->control.event_inj,
-                              nested_vmcb->control.nested_ctl);
+       return 0;
+}
 
-       trace_kvm_nested_intercepts(nested_vmcb->control.intercept_cr & 0xffff,
-                                   nested_vmcb->control.intercept_cr >> 16,
-                                   nested_vmcb->control.intercept_exceptions,
-                                   nested_vmcb->control.intercept);
+static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
 
-       /* Clear internal status */
-       kvm_clear_exception_queue(&svm->vcpu);
-       kvm_clear_interrupt_queue(&svm->vcpu);
+       u32 ecx = msr->index;
+       u64 data = msr->data;
+       switch (ecx) {
+       case MSR_IA32_CR_PAT:
+               if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data))
+                       return 1;
+               vcpu->arch.pat = data;
+               svm->vmcb->save.g_pat = data;
+               mark_dirty(svm->vmcb, VMCB_NPT);
+               break;
+       case MSR_IA32_SPEC_CTRL:
+               if (!msr->host_initiated &&
+                   !guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL) &&
+                   !guest_cpuid_has(vcpu, X86_FEATURE_AMD_STIBP) &&
+                   !guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBRS) &&
+                   !guest_cpuid_has(vcpu, X86_FEATURE_AMD_SSBD))
+                       return 1;
 
-       /*
-        * Save the old vmcb, so we don't need to pick what we save, but can
-        * restore everything when a VMEXIT occurs
-        */
-       hsave->save.es     = vmcb->save.es;
-       hsave->save.cs     = vmcb->save.cs;
-       hsave->save.ss     = vmcb->save.ss;
-       hsave->save.ds     = vmcb->save.ds;
-       hsave->save.gdtr   = vmcb->save.gdtr;
-       hsave->save.idtr   = vmcb->save.idtr;
-       hsave->save.efer   = svm->vcpu.arch.efer;
-       hsave->save.cr0    = kvm_read_cr0(&svm->vcpu);
-       hsave->save.cr4    = svm->vcpu.arch.cr4;
-       hsave->save.rflags = kvm_get_rflags(&svm->vcpu);
-       hsave->save.rip    = kvm_rip_read(&svm->vcpu);
-       hsave->save.rsp    = vmcb->save.rsp;
-       hsave->save.rax    = vmcb->save.rax;
-       if (npt_enabled)
-               hsave->save.cr3    = vmcb->save.cr3;
-       else
-               hsave->save.cr3    = kvm_read_cr3(&svm->vcpu);
+               if (data & ~kvm_spec_ctrl_valid_bits(vcpu))
+                       return 1;
 
-       copy_vmcb_control_area(hsave, vmcb);
+               svm->spec_ctrl = data;
+               if (!data)
+                       break;
 
-       enter_svm_guest_mode(svm, vmcb_gpa, nested_vmcb, &map);
+               /*
+                * For non-nested:
+                * When it's written (to non-zero) for the first time, pass
+                * it through.
+                *
+                * For nested:
+                * The handling of the MSR bitmap for L2 guests is done in
+                * nested_svm_vmrun_msrpm.
+                * We update the L1 MSR bit as well since it will end up
+                * touching the MSR anyway now.
+                */
+               set_msr_interception(svm->msrpm, MSR_IA32_SPEC_CTRL, 1, 1);
+               break;
+       case MSR_IA32_PRED_CMD:
+               if (!msr->host_initiated &&
+                   !guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBPB))
+                       return 1;
 
-       if (!nested_svm_vmrun_msrpm(svm)) {
-               svm->vmcb->control.exit_code    = SVM_EXIT_ERR;
-               svm->vmcb->control.exit_code_hi = 0;
-               svm->vmcb->control.exit_info_1  = 0;
-               svm->vmcb->control.exit_info_2  = 0;
+               if (data & ~PRED_CMD_IBPB)
+                       return 1;
+               if (!boot_cpu_has(X86_FEATURE_AMD_IBPB))
+                       return 1;
+               if (!data)
+                       break;
 
-               nested_svm_vmexit(svm);
-       }
+               wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB);
+               set_msr_interception(svm->msrpm, MSR_IA32_PRED_CMD, 0, 1);
+               break;
+       case MSR_AMD64_VIRT_SPEC_CTRL:
+               if (!msr->host_initiated &&
+                   !guest_cpuid_has(vcpu, X86_FEATURE_VIRT_SSBD))
+                       return 1;
 
-       return ret;
-}
+               if (data & ~SPEC_CTRL_SSBD)
+                       return 1;
 
-static void nested_svm_vmloadsave(struct vmcb *from_vmcb, struct vmcb *to_vmcb)
-{
-       to_vmcb->save.fs = from_vmcb->save.fs;
-       to_vmcb->save.gs = from_vmcb->save.gs;
-       to_vmcb->save.tr = from_vmcb->save.tr;
-       to_vmcb->save.ldtr = from_vmcb->save.ldtr;
-       to_vmcb->save.kernel_gs_base = from_vmcb->save.kernel_gs_base;
-       to_vmcb->save.star = from_vmcb->save.star;
-       to_vmcb->save.lstar = from_vmcb->save.lstar;
-       to_vmcb->save.cstar = from_vmcb->save.cstar;
-       to_vmcb->save.sfmask = from_vmcb->save.sfmask;
-       to_vmcb->save.sysenter_cs = from_vmcb->save.sysenter_cs;
-       to_vmcb->save.sysenter_esp = from_vmcb->save.sysenter_esp;
-       to_vmcb->save.sysenter_eip = from_vmcb->save.sysenter_eip;
-}
+               svm->virt_spec_ctrl = data;
+               break;
+       case MSR_STAR:
+               svm->vmcb->save.star = data;
+               break;
+#ifdef CONFIG_X86_64
+       case MSR_LSTAR:
+               svm->vmcb->save.lstar = data;
+               break;
+       case MSR_CSTAR:
+               svm->vmcb->save.cstar = data;
+               break;
+       case MSR_KERNEL_GS_BASE:
+               svm->vmcb->save.kernel_gs_base = data;
+               break;
+       case MSR_SYSCALL_MASK:
+               svm->vmcb->save.sfmask = data;
+               break;
+#endif
+       case MSR_IA32_SYSENTER_CS:
+               svm->vmcb->save.sysenter_cs = data;
+               break;
+       case MSR_IA32_SYSENTER_EIP:
+               svm->sysenter_eip = data;
+               svm->vmcb->save.sysenter_eip = data;
+               break;
+       case MSR_IA32_SYSENTER_ESP:
+               svm->sysenter_esp = data;
+               svm->vmcb->save.sysenter_esp = data;
+               break;
+       case MSR_TSC_AUX:
+               if (!boot_cpu_has(X86_FEATURE_RDTSCP))
+                       return 1;
 
-static int vmload_interception(struct vcpu_svm *svm)
-{
-       struct vmcb *nested_vmcb;
-       struct kvm_host_map map;
-       int ret;
+               /*
+                * This is rare, so we update the MSR here instead of using
+                * direct_access_msrs.  Doing that would require a rdmsr in
+                * svm_vcpu_put.
+                */
+               svm->tsc_aux = data;
+               wrmsrl(MSR_TSC_AUX, svm->tsc_aux);
+               break;
+       case MSR_IA32_DEBUGCTLMSR:
+               if (!boot_cpu_has(X86_FEATURE_LBRV)) {
+                       vcpu_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTL 0x%llx, nop\n",
+                                   __func__, data);
+                       break;
+               }
+               if (data & DEBUGCTL_RESERVED_BITS)
+                       return 1;
 
-       if (nested_svm_check_permissions(svm))
-               return 1;
+               svm->vmcb->save.dbgctl = data;
+               mark_dirty(svm->vmcb, VMCB_LBR);
+               if (data & (1ULL<<0))
+                       svm_enable_lbrv(svm);
+               else
+                       svm_disable_lbrv(svm);
+               break;
+       case MSR_VM_HSAVE_PA:
+               svm->nested.hsave_msr = data;
+               break;
+       case MSR_VM_CR:
+               return svm_set_vm_cr(vcpu, data);
+       case MSR_VM_IGNNE:
+               vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data);
+               break;
+       case MSR_F10H_DECFG: {
+               struct kvm_msr_entry msr_entry;
 
-       ret = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(svm->vmcb->save.rax), &map);
-       if (ret) {
-               if (ret == -EINVAL)
-                       kvm_inject_gp(&svm->vcpu, 0);
-               return 1;
-       }
+               msr_entry.index = msr->index;
+               if (svm_get_msr_feature(&msr_entry))
+                       return 1;
 
-       nested_vmcb = map.hva;
+               /* Check the supported bits */
+               if (data & ~msr_entry.data)
+                       return 1;
 
-       ret = kvm_skip_emulated_instruction(&svm->vcpu);
+               /* Don't allow the guest to change a bit, #GP */
+               if (!msr->host_initiated && (data ^ msr_entry.data))
+                       return 1;
 
-       nested_svm_vmloadsave(nested_vmcb, svm->vmcb);
-       kvm_vcpu_unmap(&svm->vcpu, &map, true);
+               svm->msr_decfg = data;
+               break;
+       }
+       case MSR_IA32_APICBASE:
+               if (kvm_vcpu_apicv_active(vcpu))
+                       avic_update_vapic_bar(to_svm(vcpu), data);
+               /* Fall through */
+       default:
+               return kvm_set_msr_common(vcpu, msr);
+       }
+       return 0;
+}
 
-       return ret;
+static int wrmsr_interception(struct vcpu_svm *svm)
+{
+       return kvm_emulate_wrmsr(&svm->vcpu);
 }
 
-static int vmsave_interception(struct vcpu_svm *svm)
+static int msr_interception(struct vcpu_svm *svm)
 {
-       struct vmcb *nested_vmcb;
-       struct kvm_host_map map;
-       int ret;
+       if (svm->vmcb->control.exit_info_1)
+               return wrmsr_interception(svm);
+       else
+               return rdmsr_interception(svm);
+}
 
-       if (nested_svm_check_permissions(svm))
-               return 1;
+static int interrupt_window_interception(struct vcpu_svm *svm)
+{
+       kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
+       svm_clear_vintr(svm);
 
-       ret = kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(svm->vmcb->save.rax), &map);
-       if (ret) {
-               if (ret == -EINVAL)
-                       kvm_inject_gp(&svm->vcpu, 0);
-               return 1;
-       }
+       /*
+        * For AVIC, the only reason to end up here is ExtINTs.
+        * In this case AVIC was temporarily disabled for
+        * requesting the IRQ window and we have to re-enable it.
+        */
+       svm_toggle_avic_for_irq_window(&svm->vcpu, true);
 
-       nested_vmcb = map.hva;
+       svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
+       mark_dirty(svm->vmcb, VMCB_INTR);
+       ++svm->vcpu.stat.irq_window_exits;
+       return 1;
+}
 
-       ret = kvm_skip_emulated_instruction(&svm->vcpu);
+static int pause_interception(struct vcpu_svm *svm)
+{
+       struct kvm_vcpu *vcpu = &svm->vcpu;
+       bool in_kernel = (svm_get_cpl(vcpu) == 0);
 
-       nested_svm_vmloadsave(svm->vmcb, nested_vmcb);
-       kvm_vcpu_unmap(&svm->vcpu, &map, true);
+       if (pause_filter_thresh)
+               grow_ple_window(vcpu);
 
-       return ret;
+       kvm_vcpu_on_spin(vcpu, in_kernel);
+       return 1;
 }
 
-static int vmrun_interception(struct vcpu_svm *svm)
+static int nop_interception(struct vcpu_svm *svm)
 {
-       if (nested_svm_check_permissions(svm))
-               return 1;
-
-       return nested_svm_vmrun(svm);
+       return kvm_skip_emulated_instruction(&(svm->vcpu));
 }
 
-static int stgi_interception(struct vcpu_svm *svm)
+static int monitor_interception(struct vcpu_svm *svm)
 {
-       int ret;
-
-       if (nested_svm_check_permissions(svm))
-               return 1;
-
-       /*
-        * If VGIF is enabled, the STGI intercept is only added to
-        * detect the opening of the SMI/NMI window; remove it now.
-        */
-       if (vgif_enabled(svm))
-               clr_intercept(svm, INTERCEPT_STGI);
-
-       ret = kvm_skip_emulated_instruction(&svm->vcpu);
-       kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
-
-       enable_gif(svm);
-
-       return ret;
-}
-
-static int clgi_interception(struct vcpu_svm *svm)
-{
-       int ret;
-
-       if (nested_svm_check_permissions(svm))
-               return 1;
-
-       ret = kvm_skip_emulated_instruction(&svm->vcpu);
-
-       disable_gif(svm);
-
-       /* After a CLGI no interrupts should come */
-       if (!kvm_vcpu_apicv_active(&svm->vcpu))
-               svm_clear_vintr(svm);
-
-       return ret;
-}
-
-static int invlpga_interception(struct vcpu_svm *svm)
-{
-       struct kvm_vcpu *vcpu = &svm->vcpu;
-
-       trace_kvm_invlpga(svm->vmcb->save.rip, kvm_rcx_read(&svm->vcpu),
-                         kvm_rax_read(&svm->vcpu));
-
-       /* Let's treat INVLPGA the same as INVLPG (can be optimized!) */
-       kvm_mmu_invlpg(vcpu, kvm_rax_read(&svm->vcpu));
-
-       return kvm_skip_emulated_instruction(&svm->vcpu);
-}
-
-static int skinit_interception(struct vcpu_svm *svm)
-{
-       trace_kvm_skinit(svm->vmcb->save.rip, kvm_rax_read(&svm->vcpu));
-
-       kvm_queue_exception(&svm->vcpu, UD_VECTOR);
-       return 1;
-}
-
-static int wbinvd_interception(struct vcpu_svm *svm)
-{
-       return kvm_emulate_wbinvd(&svm->vcpu);
+       printk_once(KERN_WARNING "kvm: MONITOR instruction emulated as NOP!\n");
+       return nop_interception(svm);
 }
 
-static int xsetbv_interception(struct vcpu_svm *svm)
+static int mwait_interception(struct vcpu_svm *svm)
 {
-       u64 new_bv = kvm_read_edx_eax(&svm->vcpu);
-       u32 index = kvm_rcx_read(&svm->vcpu);
-
-       if (kvm_set_xcr(&svm->vcpu, index, new_bv) == 0) {
-               return kvm_skip_emulated_instruction(&svm->vcpu);
-       }
-
-       return 1;
+       printk_once(KERN_WARNING "kvm: MWAIT instruction emulated as NOP!\n");
+       return nop_interception(svm);
 }
 
-static int rdpru_interception(struct vcpu_svm *svm)
-{
-       kvm_queue_exception(&svm->vcpu, UD_VECTOR);
-       return 1;
-}
+static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = {
+       [SVM_EXIT_READ_CR0]                     = cr_interception,
+       [SVM_EXIT_READ_CR3]                     = cr_interception,
+       [SVM_EXIT_READ_CR4]                     = cr_interception,
+       [SVM_EXIT_READ_CR8]                     = cr_interception,
+       [SVM_EXIT_CR0_SEL_WRITE]                = cr_interception,
+       [SVM_EXIT_WRITE_CR0]                    = cr_interception,
+       [SVM_EXIT_WRITE_CR3]                    = cr_interception,
+       [SVM_EXIT_WRITE_CR4]                    = cr_interception,
+       [SVM_EXIT_WRITE_CR8]                    = cr8_write_interception,
+       [SVM_EXIT_READ_DR0]                     = dr_interception,
+       [SVM_EXIT_READ_DR1]                     = dr_interception,
+       [SVM_EXIT_READ_DR2]                     = dr_interception,
+       [SVM_EXIT_READ_DR3]                     = dr_interception,
+       [SVM_EXIT_READ_DR4]                     = dr_interception,
+       [SVM_EXIT_READ_DR5]                     = dr_interception,
+       [SVM_EXIT_READ_DR6]                     = dr_interception,
+       [SVM_EXIT_READ_DR7]                     = dr_interception,
+       [SVM_EXIT_WRITE_DR0]                    = dr_interception,
+       [SVM_EXIT_WRITE_DR1]                    = dr_interception,
+       [SVM_EXIT_WRITE_DR2]                    = dr_interception,
+       [SVM_EXIT_WRITE_DR3]                    = dr_interception,
+       [SVM_EXIT_WRITE_DR4]                    = dr_interception,
+       [SVM_EXIT_WRITE_DR5]                    = dr_interception,
+       [SVM_EXIT_WRITE_DR6]                    = dr_interception,
+       [SVM_EXIT_WRITE_DR7]                    = dr_interception,
+       [SVM_EXIT_EXCP_BASE + DB_VECTOR]        = db_interception,
+       [SVM_EXIT_EXCP_BASE + BP_VECTOR]        = bp_interception,
+       [SVM_EXIT_EXCP_BASE + UD_VECTOR]        = ud_interception,
+       [SVM_EXIT_EXCP_BASE + PF_VECTOR]        = pf_interception,
+       [SVM_EXIT_EXCP_BASE + MC_VECTOR]        = mc_interception,
+       [SVM_EXIT_EXCP_BASE + AC_VECTOR]        = ac_interception,
+       [SVM_EXIT_EXCP_BASE + GP_VECTOR]        = gp_interception,
+       [SVM_EXIT_INTR]                         = intr_interception,
+       [SVM_EXIT_NMI]                          = nmi_interception,
+       [SVM_EXIT_SMI]                          = nop_on_interception,
+       [SVM_EXIT_INIT]                         = nop_on_interception,
+       [SVM_EXIT_VINTR]                        = interrupt_window_interception,
+       [SVM_EXIT_RDPMC]                        = rdpmc_interception,
+       [SVM_EXIT_CPUID]                        = cpuid_interception,
+       [SVM_EXIT_IRET]                         = iret_interception,
+       [SVM_EXIT_INVD]                         = emulate_on_interception,
+       [SVM_EXIT_PAUSE]                        = pause_interception,
+       [SVM_EXIT_HLT]                          = halt_interception,
+       [SVM_EXIT_INVLPG]                       = invlpg_interception,
+       [SVM_EXIT_INVLPGA]                      = invlpga_interception,
+       [SVM_EXIT_IOIO]                         = io_interception,
+       [SVM_EXIT_MSR]                          = msr_interception,
+       [SVM_EXIT_TASK_SWITCH]                  = task_switch_interception,
+       [SVM_EXIT_SHUTDOWN]                     = shutdown_interception,
+       [SVM_EXIT_VMRUN]                        = vmrun_interception,
+       [SVM_EXIT_VMMCALL]                      = vmmcall_interception,
+       [SVM_EXIT_VMLOAD]                       = vmload_interception,
+       [SVM_EXIT_VMSAVE]                       = vmsave_interception,
+       [SVM_EXIT_STGI]                         = stgi_interception,
+       [SVM_EXIT_CLGI]                         = clgi_interception,
+       [SVM_EXIT_SKINIT]                       = skinit_interception,
+       [SVM_EXIT_WBINVD]                       = wbinvd_interception,
+       [SVM_EXIT_MONITOR]                      = monitor_interception,
+       [SVM_EXIT_MWAIT]                        = mwait_interception,
+       [SVM_EXIT_XSETBV]                       = xsetbv_interception,
+       [SVM_EXIT_RDPRU]                        = rdpru_interception,
+       [SVM_EXIT_NPF]                          = npf_interception,
+       [SVM_EXIT_RSM]                          = rsm_interception,
+       [SVM_EXIT_AVIC_INCOMPLETE_IPI]          = avic_incomplete_ipi_interception,
+       [SVM_EXIT_AVIC_UNACCELERATED_ACCESS]    = avic_unaccelerated_access_interception,
+};
 
-static int task_switch_interception(struct vcpu_svm *svm)
+static void dump_vmcb(struct kvm_vcpu *vcpu)
 {
-       u16 tss_selector;
-       int reason;
-       int int_type = svm->vmcb->control.exit_int_info &
-               SVM_EXITINTINFO_TYPE_MASK;
-       int int_vec = svm->vmcb->control.exit_int_info & SVM_EVTINJ_VEC_MASK;
-       uint32_t type =
-               svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_TYPE_MASK;
-       uint32_t idt_v =
-               svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID;
-       bool has_error_code = false;
-       u32 error_code = 0;
-
-       tss_selector = (u16)svm->vmcb->control.exit_info_1;
-
-       if (svm->vmcb->control.exit_info_2 &
-           (1ULL << SVM_EXITINFOSHIFT_TS_REASON_IRET))
-               reason = TASK_SWITCH_IRET;
-       else if (svm->vmcb->control.exit_info_2 &
-                (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP))
-               reason = TASK_SWITCH_JMP;
-       else if (idt_v)
-               reason = TASK_SWITCH_GATE;
-       else
-               reason = TASK_SWITCH_CALL;
-
-       if (reason == TASK_SWITCH_GATE) {
-               switch (type) {
-               case SVM_EXITINTINFO_TYPE_NMI:
-                       svm->vcpu.arch.nmi_injected = false;
-                       break;
-               case SVM_EXITINTINFO_TYPE_EXEPT:
-                       if (svm->vmcb->control.exit_info_2 &
-                           (1ULL << SVM_EXITINFOSHIFT_TS_HAS_ERROR_CODE)) {
-                               has_error_code = true;
-                               error_code =
-                                       (u32)svm->vmcb->control.exit_info_2;
-                       }
-                       kvm_clear_exception_queue(&svm->vcpu);
-                       break;
-               case SVM_EXITINTINFO_TYPE_INTR:
-                       kvm_clear_interrupt_queue(&svm->vcpu);
-                       break;
-               default:
-                       break;
-               }
-       }
+       struct vcpu_svm *svm = to_svm(vcpu);
+       struct vmcb_control_area *control = &svm->vmcb->control;
+       struct vmcb_save_area *save = &svm->vmcb->save;
 
-       if (reason != TASK_SWITCH_GATE ||
-           int_type == SVM_EXITINTINFO_TYPE_SOFT ||
-           (int_type == SVM_EXITINTINFO_TYPE_EXEPT &&
-            (int_vec == OF_VECTOR || int_vec == BP_VECTOR))) {
-               if (!skip_emulated_instruction(&svm->vcpu))
-                       return 0;
+       if (!dump_invalid_vmcb) {
+               pr_warn_ratelimited("set kvm_amd.dump_invalid_vmcb=1 to dump internal KVM state.\n");
+               return;
        }
 
-       if (int_type != SVM_EXITINTINFO_TYPE_SOFT)
-               int_vec = -1;
-
-       return kvm_task_switch(&svm->vcpu, tss_selector, int_vec, reason,
-                              has_error_code, error_code);
-}
-
-static int cpuid_interception(struct vcpu_svm *svm)
-{
-       return kvm_emulate_cpuid(&svm->vcpu);
-}
-
-static int iret_interception(struct vcpu_svm *svm)
-{
-       ++svm->vcpu.stat.nmi_window_exits;
-       clr_intercept(svm, INTERCEPT_IRET);
-       svm->vcpu.arch.hflags |= HF_IRET_MASK;
-       svm->nmi_iret_rip = kvm_rip_read(&svm->vcpu);
-       kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
-       return 1;
-}
-
-static int invlpg_interception(struct vcpu_svm *svm)
-{
-       if (!static_cpu_has(X86_FEATURE_DECODEASSISTS))
-               return kvm_emulate_instruction(&svm->vcpu, 0);
-
-       kvm_mmu_invlpg(&svm->vcpu, svm->vmcb->control.exit_info_1);
-       return kvm_skip_emulated_instruction(&svm->vcpu);
-}
-
-static int emulate_on_interception(struct vcpu_svm *svm)
-{
-       return kvm_emulate_instruction(&svm->vcpu, 0);
-}
-
-static int rsm_interception(struct vcpu_svm *svm)
-{
-       return kvm_emulate_instruction_from_buffer(&svm->vcpu, rsm_ins_bytes, 2);
-}
-
-static int rdpmc_interception(struct vcpu_svm *svm)
-{
-       int err;
-
-       if (!nrips)
-               return emulate_on_interception(svm);
-
-       err = kvm_rdpmc(&svm->vcpu);
-       return kvm_complete_insn_gp(&svm->vcpu, err);
-}
-
-static bool check_selective_cr0_intercepted(struct vcpu_svm *svm,
-                                           unsigned long val)
-{
-       unsigned long cr0 = svm->vcpu.arch.cr0;
-       bool ret = false;
-       u64 intercept;
-
-       intercept = svm->nested.intercept;
-
-       if (!is_guest_mode(&svm->vcpu) ||
-           (!(intercept & (1ULL << INTERCEPT_SELECTIVE_CR0))))
-               return false;
-
-       cr0 &= ~SVM_CR0_SELECTIVE_MASK;
-       val &= ~SVM_CR0_SELECTIVE_MASK;
-
-       if (cr0 ^ val) {
-               svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE;
-               ret = (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE);
-       }
-
-       return ret;
-}
-
-#define CR_VALID (1ULL << 63)
-
-static int cr_interception(struct vcpu_svm *svm)
-{
-       int reg, cr;
-       unsigned long val;
-       int err;
-
-       if (!static_cpu_has(X86_FEATURE_DECODEASSISTS))
-               return emulate_on_interception(svm);
-
-       if (unlikely((svm->vmcb->control.exit_info_1 & CR_VALID) == 0))
-               return emulate_on_interception(svm);
-
-       reg = svm->vmcb->control.exit_info_1 & SVM_EXITINFO_REG_MASK;
-       if (svm->vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE)
-               cr = SVM_EXIT_WRITE_CR0 - SVM_EXIT_READ_CR0;
-       else
-               cr = svm->vmcb->control.exit_code - SVM_EXIT_READ_CR0;
-
-       err = 0;
-       if (cr >= 16) { /* mov to cr */
-               cr -= 16;
-               val = kvm_register_read(&svm->vcpu, reg);
-               switch (cr) {
-               case 0:
-                       if (!check_selective_cr0_intercepted(svm, val))
-                               err = kvm_set_cr0(&svm->vcpu, val);
-                       else
-                               return 1;
-
-                       break;
-               case 3:
-                       err = kvm_set_cr3(&svm->vcpu, val);
-                       break;
-               case 4:
-                       err = kvm_set_cr4(&svm->vcpu, val);
-                       break;
-               case 8:
-                       err = kvm_set_cr8(&svm->vcpu, val);
-                       break;
-               default:
-                       WARN(1, "unhandled write to CR%d", cr);
-                       kvm_queue_exception(&svm->vcpu, UD_VECTOR);
-                       return 1;
-               }
-       } else { /* mov from cr */
-               switch (cr) {
-               case 0:
-                       val = kvm_read_cr0(&svm->vcpu);
-                       break;
-               case 2:
-                       val = svm->vcpu.arch.cr2;
-                       break;
-               case 3:
-                       val = kvm_read_cr3(&svm->vcpu);
-                       break;
-               case 4:
-                       val = kvm_read_cr4(&svm->vcpu);
-                       break;
-               case 8:
-                       val = kvm_get_cr8(&svm->vcpu);
-                       break;
-               default:
-                       WARN(1, "unhandled read from CR%d", cr);
-                       kvm_queue_exception(&svm->vcpu, UD_VECTOR);
-                       return 1;
-               }
-               kvm_register_write(&svm->vcpu, reg, val);
-       }
-       return kvm_complete_insn_gp(&svm->vcpu, err);
-}
-
-static int dr_interception(struct vcpu_svm *svm)
-{
-       int reg, dr;
-       unsigned long val;
-
-       if (svm->vcpu.guest_debug == 0) {
-               /*
-                * No more DR vmexits; force a reload of the debug registers
-                * and reenter on this instruction.  The next vmexit will
-                * retrieve the full state of the debug registers.
-                */
-               clr_dr_intercepts(svm);
-               svm->vcpu.arch.switch_db_regs |= KVM_DEBUGREG_WONT_EXIT;
-               return 1;
-       }
-
-       if (!boot_cpu_has(X86_FEATURE_DECODEASSISTS))
-               return emulate_on_interception(svm);
-
-       reg = svm->vmcb->control.exit_info_1 & SVM_EXITINFO_REG_MASK;
-       dr = svm->vmcb->control.exit_code - SVM_EXIT_READ_DR0;
-
-       if (dr >= 16) { /* mov to DRn */
-               if (!kvm_require_dr(&svm->vcpu, dr - 16))
-                       return 1;
-               val = kvm_register_read(&svm->vcpu, reg);
-               kvm_set_dr(&svm->vcpu, dr - 16, val);
-       } else {
-               if (!kvm_require_dr(&svm->vcpu, dr))
-                       return 1;
-               kvm_get_dr(&svm->vcpu, dr, &val);
-               kvm_register_write(&svm->vcpu, reg, val);
-       }
-
-       return kvm_skip_emulated_instruction(&svm->vcpu);
-}
-
-static int cr8_write_interception(struct vcpu_svm *svm)
-{
-       struct kvm_run *kvm_run = svm->vcpu.run;
-       int r;
-
-       u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
-       /* instruction emulation calls kvm_set_cr8() */
-       r = cr_interception(svm);
-       if (lapic_in_kernel(&svm->vcpu))
-               return r;
-       if (cr8_prev <= kvm_get_cr8(&svm->vcpu))
-               return r;
-       kvm_run->exit_reason = KVM_EXIT_SET_TPR;
-       return 0;
-}
-
-static int svm_get_msr_feature(struct kvm_msr_entry *msr)
-{
-       msr->data = 0;
-
-       switch (msr->index) {
-       case MSR_F10H_DECFG:
-               if (boot_cpu_has(X86_FEATURE_LFENCE_RDTSC))
-                       msr->data |= MSR_F10H_DECFG_LFENCE_SERIALIZE;
-               break;
-       default:
-               return 1;
-       }
-
-       return 0;
-}
-
-static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       switch (msr_info->index) {
-       case MSR_STAR:
-               msr_info->data = svm->vmcb->save.star;
-               break;
-#ifdef CONFIG_X86_64
-       case MSR_LSTAR:
-               msr_info->data = svm->vmcb->save.lstar;
-               break;
-       case MSR_CSTAR:
-               msr_info->data = svm->vmcb->save.cstar;
-               break;
-       case MSR_KERNEL_GS_BASE:
-               msr_info->data = svm->vmcb->save.kernel_gs_base;
-               break;
-       case MSR_SYSCALL_MASK:
-               msr_info->data = svm->vmcb->save.sfmask;
-               break;
-#endif
-       case MSR_IA32_SYSENTER_CS:
-               msr_info->data = svm->vmcb->save.sysenter_cs;
-               break;
-       case MSR_IA32_SYSENTER_EIP:
-               msr_info->data = svm->sysenter_eip;
-               break;
-       case MSR_IA32_SYSENTER_ESP:
-               msr_info->data = svm->sysenter_esp;
-               break;
-       case MSR_TSC_AUX:
-               if (!boot_cpu_has(X86_FEATURE_RDTSCP))
-                       return 1;
-               msr_info->data = svm->tsc_aux;
-               break;
-       /*
-        * Nobody will change the following 5 values in the VMCB so we can
-        * safely return them on rdmsr. They will always be 0 until LBRV is
-        * implemented.
-        */
-       case MSR_IA32_DEBUGCTLMSR:
-               msr_info->data = svm->vmcb->save.dbgctl;
-               break;
-       case MSR_IA32_LASTBRANCHFROMIP:
-               msr_info->data = svm->vmcb->save.br_from;
-               break;
-       case MSR_IA32_LASTBRANCHTOIP:
-               msr_info->data = svm->vmcb->save.br_to;
-               break;
-       case MSR_IA32_LASTINTFROMIP:
-               msr_info->data = svm->vmcb->save.last_excp_from;
-               break;
-       case MSR_IA32_LASTINTTOIP:
-               msr_info->data = svm->vmcb->save.last_excp_to;
-               break;
-       case MSR_VM_HSAVE_PA:
-               msr_info->data = svm->nested.hsave_msr;
-               break;
-       case MSR_VM_CR:
-               msr_info->data = svm->nested.vm_cr_msr;
-               break;
-       case MSR_IA32_SPEC_CTRL:
-               if (!msr_info->host_initiated &&
-                   !guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL) &&
-                   !guest_cpuid_has(vcpu, X86_FEATURE_AMD_STIBP) &&
-                   !guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBRS) &&
-                   !guest_cpuid_has(vcpu, X86_FEATURE_AMD_SSBD))
-                       return 1;
-
-               msr_info->data = svm->spec_ctrl;
-               break;
-       case MSR_AMD64_VIRT_SPEC_CTRL:
-               if (!msr_info->host_initiated &&
-                   !guest_cpuid_has(vcpu, X86_FEATURE_VIRT_SSBD))
-                       return 1;
-
-               msr_info->data = svm->virt_spec_ctrl;
-               break;
-       case MSR_F15H_IC_CFG: {
-
-               int family, model;
-
-               family = guest_cpuid_family(vcpu);
-               model  = guest_cpuid_model(vcpu);
-
-               if (family < 0 || model < 0)
-                       return kvm_get_msr_common(vcpu, msr_info);
-
-               msr_info->data = 0;
-
-               if (family == 0x15 &&
-                   (model >= 0x2 && model < 0x20))
-                       msr_info->data = 0x1E;
-               }
-               break;
-       case MSR_F10H_DECFG:
-               msr_info->data = svm->msr_decfg;
-               break;
-       default:
-               return kvm_get_msr_common(vcpu, msr_info);
-       }
-       return 0;
-}
-
-static int rdmsr_interception(struct vcpu_svm *svm)
-{
-       return kvm_emulate_rdmsr(&svm->vcpu);
-}
-
-static int svm_set_vm_cr(struct kvm_vcpu *vcpu, u64 data)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       int svm_dis, chg_mask;
-
-       if (data & ~SVM_VM_CR_VALID_MASK)
-               return 1;
-
-       chg_mask = SVM_VM_CR_VALID_MASK;
-
-       if (svm->nested.vm_cr_msr & SVM_VM_CR_SVM_DIS_MASK)
-               chg_mask &= ~(SVM_VM_CR_SVM_LOCK_MASK | SVM_VM_CR_SVM_DIS_MASK);
-
-       svm->nested.vm_cr_msr &= ~chg_mask;
-       svm->nested.vm_cr_msr |= (data & chg_mask);
-
-       svm_dis = svm->nested.vm_cr_msr & SVM_VM_CR_SVM_DIS_MASK;
-
-       /* check for svm_disable while efer.svme is set */
-       if (svm_dis && (vcpu->arch.efer & EFER_SVME))
-               return 1;
-
-       return 0;
-}
-
-static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       u32 ecx = msr->index;
-       u64 data = msr->data;
-       switch (ecx) {
-       case MSR_IA32_CR_PAT:
-               if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data))
-                       return 1;
-               vcpu->arch.pat = data;
-               svm->vmcb->save.g_pat = data;
-               mark_dirty(svm->vmcb, VMCB_NPT);
-               break;
-       case MSR_IA32_SPEC_CTRL:
-               if (!msr->host_initiated &&
-                   !guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL) &&
-                   !guest_cpuid_has(vcpu, X86_FEATURE_AMD_STIBP) &&
-                   !guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBRS) &&
-                   !guest_cpuid_has(vcpu, X86_FEATURE_AMD_SSBD))
-                       return 1;
-
-               if (data & ~kvm_spec_ctrl_valid_bits(vcpu))
-                       return 1;
-
-               svm->spec_ctrl = data;
-               if (!data)
-                       break;
-
-               /*
-                * For non-nested:
-                * When it's written (to non-zero) for the first time, pass
-                * it through.
-                *
-                * For nested:
-                * The handling of the MSR bitmap for L2 guests is done in
-                * nested_svm_vmrun_msrpm.
-                * We update the L1 MSR bit as well since it will end up
-                * touching the MSR anyway now.
-                */
-               set_msr_interception(svm->msrpm, MSR_IA32_SPEC_CTRL, 1, 1);
-               break;
-       case MSR_IA32_PRED_CMD:
-               if (!msr->host_initiated &&
-                   !guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBPB))
-                       return 1;
-
-               if (data & ~PRED_CMD_IBPB)
-                       return 1;
-               if (!boot_cpu_has(X86_FEATURE_AMD_IBPB))
-                       return 1;
-               if (!data)
-                       break;
-
-               wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB);
-               set_msr_interception(svm->msrpm, MSR_IA32_PRED_CMD, 0, 1);
-               break;
-       case MSR_AMD64_VIRT_SPEC_CTRL:
-               if (!msr->host_initiated &&
-                   !guest_cpuid_has(vcpu, X86_FEATURE_VIRT_SSBD))
-                       return 1;
-
-               if (data & ~SPEC_CTRL_SSBD)
-                       return 1;
-
-               svm->virt_spec_ctrl = data;
-               break;
-       case MSR_STAR:
-               svm->vmcb->save.star = data;
-               break;
-#ifdef CONFIG_X86_64
-       case MSR_LSTAR:
-               svm->vmcb->save.lstar = data;
-               break;
-       case MSR_CSTAR:
-               svm->vmcb->save.cstar = data;
-               break;
-       case MSR_KERNEL_GS_BASE:
-               svm->vmcb->save.kernel_gs_base = data;
-               break;
-       case MSR_SYSCALL_MASK:
-               svm->vmcb->save.sfmask = data;
-               break;
-#endif
-       case MSR_IA32_SYSENTER_CS:
-               svm->vmcb->save.sysenter_cs = data;
-               break;
-       case MSR_IA32_SYSENTER_EIP:
-               svm->sysenter_eip = data;
-               svm->vmcb->save.sysenter_eip = data;
-               break;
-       case MSR_IA32_SYSENTER_ESP:
-               svm->sysenter_esp = data;
-               svm->vmcb->save.sysenter_esp = data;
-               break;
-       case MSR_TSC_AUX:
-               if (!boot_cpu_has(X86_FEATURE_RDTSCP))
-                       return 1;
-
-               /*
-                * This is rare, so we update the MSR here instead of using
-                * direct_access_msrs.  Doing that would require a rdmsr in
-                * svm_vcpu_put.
-                */
-               svm->tsc_aux = data;
-               wrmsrl(MSR_TSC_AUX, svm->tsc_aux);
-               break;
-       case MSR_IA32_DEBUGCTLMSR:
-               if (!boot_cpu_has(X86_FEATURE_LBRV)) {
-                       vcpu_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTL 0x%llx, nop\n",
-                                   __func__, data);
-                       break;
-               }
-               if (data & DEBUGCTL_RESERVED_BITS)
-                       return 1;
-
-               svm->vmcb->save.dbgctl = data;
-               mark_dirty(svm->vmcb, VMCB_LBR);
-               if (data & (1ULL<<0))
-                       svm_enable_lbrv(svm);
-               else
-                       svm_disable_lbrv(svm);
-               break;
-       case MSR_VM_HSAVE_PA:
-               svm->nested.hsave_msr = data;
-               break;
-       case MSR_VM_CR:
-               return svm_set_vm_cr(vcpu, data);
-       case MSR_VM_IGNNE:
-               vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data);
-               break;
-       case MSR_F10H_DECFG: {
-               struct kvm_msr_entry msr_entry;
-
-               msr_entry.index = msr->index;
-               if (svm_get_msr_feature(&msr_entry))
-                       return 1;
-
-               /* Check the supported bits */
-               if (data & ~msr_entry.data)
-                       return 1;
-
-               /* Don't allow the guest to change a bit, #GP */
-               if (!msr->host_initiated && (data ^ msr_entry.data))
-                       return 1;
-
-               svm->msr_decfg = data;
-               break;
-       }
-       case MSR_IA32_APICBASE:
-               if (kvm_vcpu_apicv_active(vcpu))
-                       avic_update_vapic_bar(to_svm(vcpu), data);
-               /* Fall through */
-       default:
-               return kvm_set_msr_common(vcpu, msr);
-       }
-       return 0;
-}
-
-static int wrmsr_interception(struct vcpu_svm *svm)
-{
-       return kvm_emulate_wrmsr(&svm->vcpu);
-}
-
-static int msr_interception(struct vcpu_svm *svm)
-{
-       if (svm->vmcb->control.exit_info_1)
-               return wrmsr_interception(svm);
-       else
-               return rdmsr_interception(svm);
-}
-
-static int interrupt_window_interception(struct vcpu_svm *svm)
-{
-       kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
-       svm_clear_vintr(svm);
-
-       /*
-        * For AVIC, the only reason to end up here is ExtINTs.
-        * In this case AVIC was temporarily disabled for
-        * requesting the IRQ window and we have to re-enable it.
-        */
-       svm_toggle_avic_for_irq_window(&svm->vcpu, true);
-
-       svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
-       mark_dirty(svm->vmcb, VMCB_INTR);
-       ++svm->vcpu.stat.irq_window_exits;
-       return 1;
-}
-
-static int pause_interception(struct vcpu_svm *svm)
-{
-       struct kvm_vcpu *vcpu = &svm->vcpu;
-       bool in_kernel = (svm_get_cpl(vcpu) == 0);
-
-       if (pause_filter_thresh)
-               grow_ple_window(vcpu);
-
-       kvm_vcpu_on_spin(vcpu, in_kernel);
-       return 1;
-}
-
-static int nop_interception(struct vcpu_svm *svm)
-{
-       return kvm_skip_emulated_instruction(&(svm->vcpu));
-}
-
-static int monitor_interception(struct vcpu_svm *svm)
-{
-       printk_once(KERN_WARNING "kvm: MONITOR instruction emulated as NOP!\n");
-       return nop_interception(svm);
-}
-
-static int mwait_interception(struct vcpu_svm *svm)
-{
-       printk_once(KERN_WARNING "kvm: MWAIT instruction emulated as NOP!\n");
-       return nop_interception(svm);
-}
-
-enum avic_ipi_failure_cause {
-       AVIC_IPI_FAILURE_INVALID_INT_TYPE,
-       AVIC_IPI_FAILURE_TARGET_NOT_RUNNING,
-       AVIC_IPI_FAILURE_INVALID_TARGET,
-       AVIC_IPI_FAILURE_INVALID_BACKING_PAGE,
-};
-
-static int avic_incomplete_ipi_interception(struct vcpu_svm *svm)
-{
-       u32 icrh = svm->vmcb->control.exit_info_1 >> 32;
-       u32 icrl = svm->vmcb->control.exit_info_1;
-       u32 id = svm->vmcb->control.exit_info_2 >> 32;
-       u32 index = svm->vmcb->control.exit_info_2 & 0xFF;
-       struct kvm_lapic *apic = svm->vcpu.arch.apic;
-
-       trace_kvm_avic_incomplete_ipi(svm->vcpu.vcpu_id, icrh, icrl, id, index);
-
-       switch (id) {
-       case AVIC_IPI_FAILURE_INVALID_INT_TYPE:
-               /*
-                * AVIC hardware handles the generation of
-                * IPIs when the specified Message Type is Fixed
-                * (also known as fixed delivery mode) and
-                * the Trigger Mode is edge-triggered. The hardware
-                * also supports self and broadcast delivery modes
-                * specified via the Destination Shorthand(DSH)
-                * field of the ICRL. Logical and physical APIC ID
-                * formats are supported. All other IPI types cause
-                * a #VMEXIT, which needs to emulated.
-                */
-               kvm_lapic_reg_write(apic, APIC_ICR2, icrh);
-               kvm_lapic_reg_write(apic, APIC_ICR, icrl);
-               break;
-       case AVIC_IPI_FAILURE_TARGET_NOT_RUNNING: {
-               int i;
-               struct kvm_vcpu *vcpu;
-               struct kvm *kvm = svm->vcpu.kvm;
-               struct kvm_lapic *apic = svm->vcpu.arch.apic;
-
-               /*
-                * At this point, we expect that the AVIC HW has already
-                * set the appropriate IRR bits on the valid target
-                * vcpus. So, we just need to kick the appropriate vcpu.
-                */
-               kvm_for_each_vcpu(i, vcpu, kvm) {
-                       bool m = kvm_apic_match_dest(vcpu, apic,
-                                                    icrl & APIC_SHORT_MASK,
-                                                    GET_APIC_DEST_FIELD(icrh),
-                                                    icrl & APIC_DEST_MASK);
-
-                       if (m && !avic_vcpu_is_running(vcpu))
-                               kvm_vcpu_wake_up(vcpu);
-               }
-               break;
-       }
-       case AVIC_IPI_FAILURE_INVALID_TARGET:
-               WARN_ONCE(1, "Invalid IPI target: index=%u, vcpu=%d, icr=%#0x:%#0x\n",
-                         index, svm->vcpu.vcpu_id, icrh, icrl);
-               break;
-       case AVIC_IPI_FAILURE_INVALID_BACKING_PAGE:
-               WARN_ONCE(1, "Invalid backing page\n");
-               break;
-       default:
-               pr_err("Unknown IPI interception\n");
-       }
-
-       return 1;
-}
-
-static u32 *avic_get_logical_id_entry(struct kvm_vcpu *vcpu, u32 ldr, bool flat)
-{
-       struct kvm_svm *kvm_svm = to_kvm_svm(vcpu->kvm);
-       int index;
-       u32 *logical_apic_id_table;
-       int dlid = GET_APIC_LOGICAL_ID(ldr);
-
-       if (!dlid)
-               return NULL;
-
-       if (flat) { /* flat */
-               index = ffs(dlid) - 1;
-               if (index > 7)
-                       return NULL;
-       } else { /* cluster */
-               int cluster = (dlid & 0xf0) >> 4;
-               int apic = ffs(dlid & 0x0f) - 1;
-
-               if ((apic < 0) || (apic > 7) ||
-                   (cluster >= 0xf))
-                       return NULL;
-               index = (cluster << 2) + apic;
-       }
-
-       logical_apic_id_table = (u32 *) page_address(kvm_svm->avic_logical_id_table_page);
-
-       return &logical_apic_id_table[index];
-}
-
-static int avic_ldr_write(struct kvm_vcpu *vcpu, u8 g_physical_id, u32 ldr)
-{
-       bool flat;
-       u32 *entry, new_entry;
-
-       flat = kvm_lapic_get_reg(vcpu->arch.apic, APIC_DFR) == APIC_DFR_FLAT;
-       entry = avic_get_logical_id_entry(vcpu, ldr, flat);
-       if (!entry)
-               return -EINVAL;
-
-       new_entry = READ_ONCE(*entry);
-       new_entry &= ~AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK;
-       new_entry |= (g_physical_id & AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK);
-       new_entry |= AVIC_LOGICAL_ID_ENTRY_VALID_MASK;
-       WRITE_ONCE(*entry, new_entry);
-
-       return 0;
-}
-
-static void avic_invalidate_logical_id_entry(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       bool flat = svm->dfr_reg == APIC_DFR_FLAT;
-       u32 *entry = avic_get_logical_id_entry(vcpu, svm->ldr_reg, flat);
-
-       if (entry)
-               clear_bit(AVIC_LOGICAL_ID_ENTRY_VALID_BIT, (unsigned long *)entry);
-}
-
-static int avic_handle_ldr_update(struct kvm_vcpu *vcpu)
-{
-       int ret = 0;
-       struct vcpu_svm *svm = to_svm(vcpu);
-       u32 ldr = kvm_lapic_get_reg(vcpu->arch.apic, APIC_LDR);
-       u32 id = kvm_xapic_id(vcpu->arch.apic);
-
-       if (ldr == svm->ldr_reg)
-               return 0;
-
-       avic_invalidate_logical_id_entry(vcpu);
-
-       if (ldr)
-               ret = avic_ldr_write(vcpu, id, ldr);
-
-       if (!ret)
-               svm->ldr_reg = ldr;
-
-       return ret;
-}
-
-static int avic_handle_apic_id_update(struct kvm_vcpu *vcpu)
-{
-       u64 *old, *new;
-       struct vcpu_svm *svm = to_svm(vcpu);
-       u32 id = kvm_xapic_id(vcpu->arch.apic);
-
-       if (vcpu->vcpu_id == id)
-               return 0;
-
-       old = avic_get_physical_id_entry(vcpu, vcpu->vcpu_id);
-       new = avic_get_physical_id_entry(vcpu, id);
-       if (!new || !old)
-               return 1;
-
-       /* We need to move physical_id_entry to new offset */
-       *new = *old;
-       *old = 0ULL;
-       to_svm(vcpu)->avic_physical_id_cache = new;
-
-       /*
-        * Also update the guest physical APIC ID in the logical
-        * APIC ID table entry if already setup the LDR.
-        */
-       if (svm->ldr_reg)
-               avic_handle_ldr_update(vcpu);
-
-       return 0;
-}
-
-static void avic_handle_dfr_update(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       u32 dfr = kvm_lapic_get_reg(vcpu->arch.apic, APIC_DFR);
-
-       if (svm->dfr_reg == dfr)
-               return;
-
-       avic_invalidate_logical_id_entry(vcpu);
-       svm->dfr_reg = dfr;
-}
-
-static int avic_unaccel_trap_write(struct vcpu_svm *svm)
-{
-       struct kvm_lapic *apic = svm->vcpu.arch.apic;
-       u32 offset = svm->vmcb->control.exit_info_1 &
-                               AVIC_UNACCEL_ACCESS_OFFSET_MASK;
-
-       switch (offset) {
-       case APIC_ID:
-               if (avic_handle_apic_id_update(&svm->vcpu))
-                       return 0;
-               break;
-       case APIC_LDR:
-               if (avic_handle_ldr_update(&svm->vcpu))
-                       return 0;
-               break;
-       case APIC_DFR:
-               avic_handle_dfr_update(&svm->vcpu);
-               break;
-       default:
-               break;
-       }
-
-       kvm_lapic_reg_write(apic, offset, kvm_lapic_get_reg(apic, offset));
-
-       return 1;
-}
-
-static bool is_avic_unaccelerated_access_trap(u32 offset)
-{
-       bool ret = false;
-
-       switch (offset) {
-       case APIC_ID:
-       case APIC_EOI:
-       case APIC_RRR:
-       case APIC_LDR:
-       case APIC_DFR:
-       case APIC_SPIV:
-       case APIC_ESR:
-       case APIC_ICR:
-       case APIC_LVTT:
-       case APIC_LVTTHMR:
-       case APIC_LVTPC:
-       case APIC_LVT0:
-       case APIC_LVT1:
-       case APIC_LVTERR:
-       case APIC_TMICT:
-       case APIC_TDCR:
-               ret = true;
-               break;
-       default:
-               break;
-       }
-       return ret;
-}
-
-static int avic_unaccelerated_access_interception(struct vcpu_svm *svm)
-{
-       int ret = 0;
-       u32 offset = svm->vmcb->control.exit_info_1 &
-                    AVIC_UNACCEL_ACCESS_OFFSET_MASK;
-       u32 vector = svm->vmcb->control.exit_info_2 &
-                    AVIC_UNACCEL_ACCESS_VECTOR_MASK;
-       bool write = (svm->vmcb->control.exit_info_1 >> 32) &
-                    AVIC_UNACCEL_ACCESS_WRITE_MASK;
-       bool trap = is_avic_unaccelerated_access_trap(offset);
-
-       trace_kvm_avic_unaccelerated_access(svm->vcpu.vcpu_id, offset,
-                                           trap, write, vector);
-       if (trap) {
-               /* Handling Trap */
-               WARN_ONCE(!write, "svm: Handling trap read.\n");
-               ret = avic_unaccel_trap_write(svm);
-       } else {
-               /* Handling Fault */
-               ret = kvm_emulate_instruction(&svm->vcpu, 0);
-       }
-
-       return ret;
-}
-
-static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = {
-       [SVM_EXIT_READ_CR0]                     = cr_interception,
-       [SVM_EXIT_READ_CR3]                     = cr_interception,
-       [SVM_EXIT_READ_CR4]                     = cr_interception,
-       [SVM_EXIT_READ_CR8]                     = cr_interception,
-       [SVM_EXIT_CR0_SEL_WRITE]                = cr_interception,
-       [SVM_EXIT_WRITE_CR0]                    = cr_interception,
-       [SVM_EXIT_WRITE_CR3]                    = cr_interception,
-       [SVM_EXIT_WRITE_CR4]                    = cr_interception,
-       [SVM_EXIT_WRITE_CR8]                    = cr8_write_interception,
-       [SVM_EXIT_READ_DR0]                     = dr_interception,
-       [SVM_EXIT_READ_DR1]                     = dr_interception,
-       [SVM_EXIT_READ_DR2]                     = dr_interception,
-       [SVM_EXIT_READ_DR3]                     = dr_interception,
-       [SVM_EXIT_READ_DR4]                     = dr_interception,
-       [SVM_EXIT_READ_DR5]                     = dr_interception,
-       [SVM_EXIT_READ_DR6]                     = dr_interception,
-       [SVM_EXIT_READ_DR7]                     = dr_interception,
-       [SVM_EXIT_WRITE_DR0]                    = dr_interception,
-       [SVM_EXIT_WRITE_DR1]                    = dr_interception,
-       [SVM_EXIT_WRITE_DR2]                    = dr_interception,
-       [SVM_EXIT_WRITE_DR3]                    = dr_interception,
-       [SVM_EXIT_WRITE_DR4]                    = dr_interception,
-       [SVM_EXIT_WRITE_DR5]                    = dr_interception,
-       [SVM_EXIT_WRITE_DR6]                    = dr_interception,
-       [SVM_EXIT_WRITE_DR7]                    = dr_interception,
-       [SVM_EXIT_EXCP_BASE + DB_VECTOR]        = db_interception,
-       [SVM_EXIT_EXCP_BASE + BP_VECTOR]        = bp_interception,
-       [SVM_EXIT_EXCP_BASE + UD_VECTOR]        = ud_interception,
-       [SVM_EXIT_EXCP_BASE + PF_VECTOR]        = pf_interception,
-       [SVM_EXIT_EXCP_BASE + MC_VECTOR]        = mc_interception,
-       [SVM_EXIT_EXCP_BASE + AC_VECTOR]        = ac_interception,
-       [SVM_EXIT_EXCP_BASE + GP_VECTOR]        = gp_interception,
-       [SVM_EXIT_INTR]                         = intr_interception,
-       [SVM_EXIT_NMI]                          = nmi_interception,
-       [SVM_EXIT_SMI]                          = nop_on_interception,
-       [SVM_EXIT_INIT]                         = nop_on_interception,
-       [SVM_EXIT_VINTR]                        = interrupt_window_interception,
-       [SVM_EXIT_RDPMC]                        = rdpmc_interception,
-       [SVM_EXIT_CPUID]                        = cpuid_interception,
-       [SVM_EXIT_IRET]                         = iret_interception,
-       [SVM_EXIT_INVD]                         = emulate_on_interception,
-       [SVM_EXIT_PAUSE]                        = pause_interception,
-       [SVM_EXIT_HLT]                          = halt_interception,
-       [SVM_EXIT_INVLPG]                       = invlpg_interception,
-       [SVM_EXIT_INVLPGA]                      = invlpga_interception,
-       [SVM_EXIT_IOIO]                         = io_interception,
-       [SVM_EXIT_MSR]                          = msr_interception,
-       [SVM_EXIT_TASK_SWITCH]                  = task_switch_interception,
-       [SVM_EXIT_SHUTDOWN]                     = shutdown_interception,
-       [SVM_EXIT_VMRUN]                        = vmrun_interception,
-       [SVM_EXIT_VMMCALL]                      = vmmcall_interception,
-       [SVM_EXIT_VMLOAD]                       = vmload_interception,
-       [SVM_EXIT_VMSAVE]                       = vmsave_interception,
-       [SVM_EXIT_STGI]                         = stgi_interception,
-       [SVM_EXIT_CLGI]                         = clgi_interception,
-       [SVM_EXIT_SKINIT]                       = skinit_interception,
-       [SVM_EXIT_WBINVD]                       = wbinvd_interception,
-       [SVM_EXIT_MONITOR]                      = monitor_interception,
-       [SVM_EXIT_MWAIT]                        = mwait_interception,
-       [SVM_EXIT_XSETBV]                       = xsetbv_interception,
-       [SVM_EXIT_RDPRU]                        = rdpru_interception,
-       [SVM_EXIT_NPF]                          = npf_interception,
-       [SVM_EXIT_RSM]                          = rsm_interception,
-       [SVM_EXIT_AVIC_INCOMPLETE_IPI]          = avic_incomplete_ipi_interception,
-       [SVM_EXIT_AVIC_UNACCELERATED_ACCESS]    = avic_unaccelerated_access_interception,
-};
-
-static void dump_vmcb(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       struct vmcb_control_area *control = &svm->vmcb->control;
-       struct vmcb_save_area *save = &svm->vmcb->save;
-
-       if (!dump_invalid_vmcb) {
-               pr_warn_ratelimited("set kvm_amd.dump_invalid_vmcb=1 to dump internal KVM state.\n");
-               return;
-       }
-
-       pr_err("VMCB Control Area:\n");
-       pr_err("%-20s%04x\n", "cr_read:", control->intercept_cr & 0xffff);
-       pr_err("%-20s%04x\n", "cr_write:", control->intercept_cr >> 16);
-       pr_err("%-20s%04x\n", "dr_read:", control->intercept_dr & 0xffff);
-       pr_err("%-20s%04x\n", "dr_write:", control->intercept_dr >> 16);
-       pr_err("%-20s%08x\n", "exceptions:", control->intercept_exceptions);
-       pr_err("%-20s%016llx\n", "intercepts:", control->intercept);
-       pr_err("%-20s%d\n", "pause filter count:", control->pause_filter_count);
-       pr_err("%-20s%d\n", "pause filter threshold:",
-              control->pause_filter_thresh);
-       pr_err("%-20s%016llx\n", "iopm_base_pa:", control->iopm_base_pa);
-       pr_err("%-20s%016llx\n", "msrpm_base_pa:", control->msrpm_base_pa);
-       pr_err("%-20s%016llx\n", "tsc_offset:", control->tsc_offset);
-       pr_err("%-20s%d\n", "asid:", control->asid);
-       pr_err("%-20s%d\n", "tlb_ctl:", control->tlb_ctl);
-       pr_err("%-20s%08x\n", "int_ctl:", control->int_ctl);
-       pr_err("%-20s%08x\n", "int_vector:", control->int_vector);
-       pr_err("%-20s%08x\n", "int_state:", control->int_state);
-       pr_err("%-20s%08x\n", "exit_code:", control->exit_code);
-       pr_err("%-20s%016llx\n", "exit_info1:", control->exit_info_1);
-       pr_err("%-20s%016llx\n", "exit_info2:", control->exit_info_2);
-       pr_err("%-20s%08x\n", "exit_int_info:", control->exit_int_info);
-       pr_err("%-20s%08x\n", "exit_int_info_err:", control->exit_int_info_err);
-       pr_err("%-20s%lld\n", "nested_ctl:", control->nested_ctl);
-       pr_err("%-20s%016llx\n", "nested_cr3:", control->nested_cr3);
-       pr_err("%-20s%016llx\n", "avic_vapic_bar:", control->avic_vapic_bar);
-       pr_err("%-20s%08x\n", "event_inj:", control->event_inj);
-       pr_err("%-20s%08x\n", "event_inj_err:", control->event_inj_err);
-       pr_err("%-20s%lld\n", "virt_ext:", control->virt_ext);
-       pr_err("%-20s%016llx\n", "next_rip:", control->next_rip);
-       pr_err("%-20s%016llx\n", "avic_backing_page:", control->avic_backing_page);
-       pr_err("%-20s%016llx\n", "avic_logical_id:", control->avic_logical_id);
-       pr_err("%-20s%016llx\n", "avic_physical_id:", control->avic_physical_id);
-       pr_err("VMCB State Save Area:\n");
-       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
-              "es:",
-              save->es.selector, save->es.attrib,
-              save->es.limit, save->es.base);
-       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
-              "cs:",
-              save->cs.selector, save->cs.attrib,
-              save->cs.limit, save->cs.base);
-       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
-              "ss:",
-              save->ss.selector, save->ss.attrib,
-              save->ss.limit, save->ss.base);
-       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
-              "ds:",
-              save->ds.selector, save->ds.attrib,
-              save->ds.limit, save->ds.base);
-       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
-              "fs:",
-              save->fs.selector, save->fs.attrib,
-              save->fs.limit, save->fs.base);
-       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
-              "gs:",
-              save->gs.selector, save->gs.attrib,
-              save->gs.limit, save->gs.base);
-       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
-              "gdtr:",
-              save->gdtr.selector, save->gdtr.attrib,
-              save->gdtr.limit, save->gdtr.base);
-       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
-              "ldtr:",
-              save->ldtr.selector, save->ldtr.attrib,
-              save->ldtr.limit, save->ldtr.base);
-       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
-              "idtr:",
-              save->idtr.selector, save->idtr.attrib,
-              save->idtr.limit, save->idtr.base);
-       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
-              "tr:",
-              save->tr.selector, save->tr.attrib,
-              save->tr.limit, save->tr.base);
-       pr_err("cpl:            %d                efer:         %016llx\n",
-               save->cpl, save->efer);
-       pr_err("%-15s %016llx %-13s %016llx\n",
-              "cr0:", save->cr0, "cr2:", save->cr2);
-       pr_err("%-15s %016llx %-13s %016llx\n",
-              "cr3:", save->cr3, "cr4:", save->cr4);
-       pr_err("%-15s %016llx %-13s %016llx\n",
-              "dr6:", save->dr6, "dr7:", save->dr7);
-       pr_err("%-15s %016llx %-13s %016llx\n",
-              "rip:", save->rip, "rflags:", save->rflags);
-       pr_err("%-15s %016llx %-13s %016llx\n",
-              "rsp:", save->rsp, "rax:", save->rax);
-       pr_err("%-15s %016llx %-13s %016llx\n",
-              "star:", save->star, "lstar:", save->lstar);
-       pr_err("%-15s %016llx %-13s %016llx\n",
-              "cstar:", save->cstar, "sfmask:", save->sfmask);
-       pr_err("%-15s %016llx %-13s %016llx\n",
-              "kernel_gs_base:", save->kernel_gs_base,
-              "sysenter_cs:", save->sysenter_cs);
-       pr_err("%-15s %016llx %-13s %016llx\n",
-              "sysenter_esp:", save->sysenter_esp,
-              "sysenter_eip:", save->sysenter_eip);
-       pr_err("%-15s %016llx %-13s %016llx\n",
-              "gpat:", save->g_pat, "dbgctl:", save->dbgctl);
-       pr_err("%-15s %016llx %-13s %016llx\n",
-              "br_from:", save->br_from, "br_to:", save->br_to);
-       pr_err("%-15s %016llx %-13s %016llx\n",
-              "excp_from:", save->last_excp_from,
-              "excp_to:", save->last_excp_to);
-}
-
-static void svm_get_exit_info(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2)
-{
-       struct vmcb_control_area *control = &to_svm(vcpu)->vmcb->control;
-
-       *info1 = control->exit_info_1;
-       *info2 = control->exit_info_2;
-}
-
-static int handle_exit(struct kvm_vcpu *vcpu,
-       enum exit_fastpath_completion exit_fastpath)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       struct kvm_run *kvm_run = vcpu->run;
-       u32 exit_code = svm->vmcb->control.exit_code;
-
-       trace_kvm_exit(exit_code, vcpu, KVM_ISA_SVM);
-
-       if (!is_cr_intercept(svm, INTERCEPT_CR0_WRITE))
-               vcpu->arch.cr0 = svm->vmcb->save.cr0;
-       if (npt_enabled)
-               vcpu->arch.cr3 = svm->vmcb->save.cr3;
-
-       if (unlikely(svm->nested.exit_required)) {
-               nested_svm_vmexit(svm);
-               svm->nested.exit_required = false;
-
-               return 1;
-       }
-
-       if (is_guest_mode(vcpu)) {
-               int vmexit;
-
-               trace_kvm_nested_vmexit(svm->vmcb->save.rip, exit_code,
-                                       svm->vmcb->control.exit_info_1,
-                                       svm->vmcb->control.exit_info_2,
-                                       svm->vmcb->control.exit_int_info,
-                                       svm->vmcb->control.exit_int_info_err,
-                                       KVM_ISA_SVM);
-
-               vmexit = nested_svm_exit_special(svm);
-
-               if (vmexit == NESTED_EXIT_CONTINUE)
-                       vmexit = nested_svm_exit_handled(svm);
-
-               if (vmexit == NESTED_EXIT_DONE)
-                       return 1;
-       }
-
-       svm_complete_interrupts(svm);
-
-       if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
-               kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
-               kvm_run->fail_entry.hardware_entry_failure_reason
-                       = svm->vmcb->control.exit_code;
-               dump_vmcb(vcpu);
-               return 0;
-       }
-
-       if (is_external_interrupt(svm->vmcb->control.exit_int_info) &&
-           exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR &&
-           exit_code != SVM_EXIT_NPF && exit_code != SVM_EXIT_TASK_SWITCH &&
-           exit_code != SVM_EXIT_INTR && exit_code != SVM_EXIT_NMI)
-               printk(KERN_ERR "%s: unexpected exit_int_info 0x%x "
-                      "exit_code 0x%x\n",
-                      __func__, svm->vmcb->control.exit_int_info,
-                      exit_code);
-
-       if (exit_fastpath == EXIT_FASTPATH_SKIP_EMUL_INS) {
-               kvm_skip_emulated_instruction(vcpu);
-               return 1;
-       } else if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
-           || !svm_exit_handlers[exit_code]) {
-               vcpu_unimpl(vcpu, "svm: unexpected exit reason 0x%x\n", exit_code);
-               dump_vmcb(vcpu);
-               vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
-               vcpu->run->internal.suberror =
-                       KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON;
-               vcpu->run->internal.ndata = 1;
-               vcpu->run->internal.data[0] = exit_code;
-               return 0;
-       }
-
-#ifdef CONFIG_RETPOLINE
-       if (exit_code == SVM_EXIT_MSR)
-               return msr_interception(svm);
-       else if (exit_code == SVM_EXIT_VINTR)
-               return interrupt_window_interception(svm);
-       else if (exit_code == SVM_EXIT_INTR)
-               return intr_interception(svm);
-       else if (exit_code == SVM_EXIT_HLT)
-               return halt_interception(svm);
-       else if (exit_code == SVM_EXIT_NPF)
-               return npf_interception(svm);
-#endif
-       return svm_exit_handlers[exit_code](svm);
-}
-
-static void reload_tss(struct kvm_vcpu *vcpu)
-{
-       int cpu = raw_smp_processor_id();
-
-       struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
-       sd->tss_desc->type = 9; /* available 32/64-bit TSS */
-       load_TR_desc();
-}
-
-static void pre_sev_run(struct vcpu_svm *svm, int cpu)
-{
-       struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
-       int asid = sev_get_asid(svm->vcpu.kvm);
-
-       /* Assign the asid allocated with this SEV guest */
-       svm->vmcb->control.asid = asid;
-
-       /*
-        * Flush guest TLB:
-        *
-        * 1) when different VMCB for the same ASID is to be run on the same host CPU.
-        * 2) or this VMCB was executed on different host CPU in previous VMRUNs.
-        */
-       if (sd->sev_vmcbs[asid] == svm->vmcb &&
-           svm->last_cpu == cpu)
-               return;
-
-       svm->last_cpu = cpu;
-       sd->sev_vmcbs[asid] = svm->vmcb;
-       svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ASID;
-       mark_dirty(svm->vmcb, VMCB_ASID);
-}
-
-static void pre_svm_run(struct vcpu_svm *svm)
-{
-       int cpu = raw_smp_processor_id();
-
-       struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
-
-       if (sev_guest(svm->vcpu.kvm))
-               return pre_sev_run(svm, cpu);
-
-       /* FIXME: handle wraparound of asid_generation */
-       if (svm->asid_generation != sd->asid_generation)
-               new_asid(svm, sd);
-}
-
-static void svm_inject_nmi(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_NMI;
-       vcpu->arch.hflags |= HF_NMI_MASK;
-       set_intercept(svm, INTERCEPT_IRET);
-       ++vcpu->stat.nmi_injections;
-}
-
-static void svm_set_irq(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       BUG_ON(!(gif_set(svm)));
-
-       trace_kvm_inj_virq(vcpu->arch.interrupt.nr);
-       ++vcpu->stat.irq_injections;
-
-       svm->vmcb->control.event_inj = vcpu->arch.interrupt.nr |
-               SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
-}
-
-static inline bool svm_nested_virtualize_tpr(struct kvm_vcpu *vcpu)
-{
-       return is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK);
-}
-
-static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       if (svm_nested_virtualize_tpr(vcpu))
-               return;
-
-       clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
-
-       if (irr == -1)
-               return;
-
-       if (tpr >= irr)
-               set_cr_intercept(svm, INTERCEPT_CR8_WRITE);
-}
-
-static void svm_set_virtual_apic_mode(struct kvm_vcpu *vcpu)
-{
-       return;
-}
-
-static void svm_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr)
-{
-}
-
-static void svm_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr)
-{
-}
-
-static void svm_toggle_avic_for_irq_window(struct kvm_vcpu *vcpu, bool activate)
-{
-       if (!avic || !lapic_in_kernel(vcpu))
-               return;
-
-       srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
-       kvm_request_apicv_update(vcpu->kvm, activate,
-                                APICV_INHIBIT_REASON_IRQWIN);
-       vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
-}
-
-static int svm_set_pi_irte_mode(struct kvm_vcpu *vcpu, bool activate)
-{
-       int ret = 0;
-       unsigned long flags;
-       struct amd_svm_iommu_ir *ir;
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       if (!kvm_arch_has_assigned_device(vcpu->kvm))
-               return 0;
-
-       /*
-        * Here, we go through the per-vcpu ir_list to update all existing
-        * interrupt remapping table entry targeting this vcpu.
-        */
-       spin_lock_irqsave(&svm->ir_list_lock, flags);
-
-       if (list_empty(&svm->ir_list))
-               goto out;
-
-       list_for_each_entry(ir, &svm->ir_list, node) {
-               if (activate)
-                       ret = amd_iommu_activate_guest_mode(ir->data);
-               else
-                       ret = amd_iommu_deactivate_guest_mode(ir->data);
-               if (ret)
-                       break;
-       }
-out:
-       spin_unlock_irqrestore(&svm->ir_list_lock, flags);
-       return ret;
-}
-
-static void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       struct vmcb *vmcb = svm->vmcb;
-       bool activated = kvm_vcpu_apicv_active(vcpu);
-
-       if (!avic)
-               return;
-
-       if (activated) {
-               /**
-                * During AVIC temporary deactivation, guest could update
-                * APIC ID, DFR and LDR registers, which would not be trapped
-                * by avic_unaccelerated_access_interception(). In this case,
-                * we need to check and update the AVIC logical APIC ID table
-                * accordingly before re-activating.
-                */
-               avic_post_state_restore(vcpu);
-               vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
-       } else {
-               vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK;
-       }
-       mark_dirty(vmcb, VMCB_AVIC);
-
-       svm_set_pi_irte_mode(vcpu, activated);
-}
-
-static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
-{
-       return;
-}
-
-static int svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec)
-{
-       if (!vcpu->arch.apicv_active)
-               return -1;
-
-       kvm_lapic_set_irr(vec, vcpu->arch.apic);
-       smp_mb__after_atomic();
-
-       if (avic_vcpu_is_running(vcpu)) {
-               int cpuid = vcpu->cpu;
-
-               if (cpuid != get_cpu())
-                       wrmsrl(SVM_AVIC_DOORBELL, kvm_cpu_get_apicid(cpuid));
-               put_cpu();
-       } else
-               kvm_vcpu_wake_up(vcpu);
-
-       return 0;
-}
-
-static bool svm_dy_apicv_has_pending_interrupt(struct kvm_vcpu *vcpu)
-{
-       return false;
-}
-
-static void svm_ir_list_del(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi)
-{
-       unsigned long flags;
-       struct amd_svm_iommu_ir *cur;
-
-       spin_lock_irqsave(&svm->ir_list_lock, flags);
-       list_for_each_entry(cur, &svm->ir_list, node) {
-               if (cur->data != pi->ir_data)
-                       continue;
-               list_del(&cur->node);
-               kfree(cur);
-               break;
-       }
-       spin_unlock_irqrestore(&svm->ir_list_lock, flags);
-}
-
-static int svm_ir_list_add(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi)
-{
-       int ret = 0;
-       unsigned long flags;
-       struct amd_svm_iommu_ir *ir;
-
-       /**
-        * In some cases, the existing irte is updaed and re-set,
-        * so we need to check here if it's already been * added
-        * to the ir_list.
-        */
-       if (pi->ir_data && (pi->prev_ga_tag != 0)) {
-               struct kvm *kvm = svm->vcpu.kvm;
-               u32 vcpu_id = AVIC_GATAG_TO_VCPUID(pi->prev_ga_tag);
-               struct kvm_vcpu *prev_vcpu = kvm_get_vcpu_by_id(kvm, vcpu_id);
-               struct vcpu_svm *prev_svm;
-
-               if (!prev_vcpu) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               prev_svm = to_svm(prev_vcpu);
-               svm_ir_list_del(prev_svm, pi);
-       }
-
-       /**
-        * Allocating new amd_iommu_pi_data, which will get
-        * add to the per-vcpu ir_list.
-        */
-       ir = kzalloc(sizeof(struct amd_svm_iommu_ir), GFP_KERNEL_ACCOUNT);
-       if (!ir) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       ir->data = pi->ir_data;
-
-       spin_lock_irqsave(&svm->ir_list_lock, flags);
-       list_add(&ir->node, &svm->ir_list);
-       spin_unlock_irqrestore(&svm->ir_list_lock, flags);
-out:
-       return ret;
-}
-
-/**
- * Note:
- * The HW cannot support posting multicast/broadcast
- * interrupts to a vCPU. So, we still use legacy interrupt
- * remapping for these kind of interrupts.
- *
- * For lowest-priority interrupts, we only support
- * those with single CPU as the destination, e.g. user
- * configures the interrupts via /proc/irq or uses
- * irqbalance to make the interrupts single-CPU.
- */
-static int
-get_pi_vcpu_info(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *e,
-                struct vcpu_data *vcpu_info, struct vcpu_svm **svm)
-{
-       struct kvm_lapic_irq irq;
-       struct kvm_vcpu *vcpu = NULL;
-
-       kvm_set_msi_irq(kvm, e, &irq);
-
-       if (!kvm_intr_is_single_vcpu(kvm, &irq, &vcpu) ||
-           !kvm_irq_is_postable(&irq)) {
-               pr_debug("SVM: %s: use legacy intr remap mode for irq %u\n",
-                        __func__, irq.vector);
-               return -1;
-       }
-
-       pr_debug("SVM: %s: use GA mode for irq %u\n", __func__,
-                irq.vector);
-       *svm = to_svm(vcpu);
-       vcpu_info->pi_desc_addr = __sme_set(page_to_phys((*svm)->avic_backing_page));
-       vcpu_info->vector = irq.vector;
-
-       return 0;
-}
-
-/*
- * svm_update_pi_irte - set IRTE for Posted-Interrupts
- *
- * @kvm: kvm
- * @host_irq: host irq of the interrupt
- * @guest_irq: gsi of the interrupt
- * @set: set or unset PI
- * returns 0 on success, < 0 on failure
- */
-static int svm_update_pi_irte(struct kvm *kvm, unsigned int host_irq,
-                             uint32_t guest_irq, bool set)
-{
-       struct kvm_kernel_irq_routing_entry *e;
-       struct kvm_irq_routing_table *irq_rt;
-       int idx, ret = -EINVAL;
-
-       if (!kvm_arch_has_assigned_device(kvm) ||
-           !irq_remapping_cap(IRQ_POSTING_CAP))
-               return 0;
-
-       pr_debug("SVM: %s: host_irq=%#x, guest_irq=%#x, set=%#x\n",
-                __func__, host_irq, guest_irq, set);
-
-       idx = srcu_read_lock(&kvm->irq_srcu);
-       irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
-       WARN_ON(guest_irq >= irq_rt->nr_rt_entries);
-
-       hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) {
-               struct vcpu_data vcpu_info;
-               struct vcpu_svm *svm = NULL;
-
-               if (e->type != KVM_IRQ_ROUTING_MSI)
-                       continue;
-
-               /**
-                * Here, we setup with legacy mode in the following cases:
-                * 1. When cannot target interrupt to a specific vcpu.
-                * 2. Unsetting posted interrupt.
-                * 3. APIC virtialization is disabled for the vcpu.
-                * 4. IRQ has incompatible delivery mode (SMI, INIT, etc)
-                */
-               if (!get_pi_vcpu_info(kvm, e, &vcpu_info, &svm) && set &&
-                   kvm_vcpu_apicv_active(&svm->vcpu)) {
-                       struct amd_iommu_pi_data pi;
-
-                       /* Try to enable guest_mode in IRTE */
-                       pi.base = __sme_set(page_to_phys(svm->avic_backing_page) &
-                                           AVIC_HPA_MASK);
-                       pi.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)->avic_vm_id,
-                                                    svm->vcpu.vcpu_id);
-                       pi.is_guest_mode = true;
-                       pi.vcpu_data = &vcpu_info;
-                       ret = irq_set_vcpu_affinity(host_irq, &pi);
-
-                       /**
-                        * Here, we successfully setting up vcpu affinity in
-                        * IOMMU guest mode. Now, we need to store the posted
-                        * interrupt information in a per-vcpu ir_list so that
-                        * we can reference to them directly when we update vcpu
-                        * scheduling information in IOMMU irte.
-                        */
-                       if (!ret && pi.is_guest_mode)
-                               svm_ir_list_add(svm, &pi);
-               } else {
-                       /* Use legacy mode in IRTE */
-                       struct amd_iommu_pi_data pi;
-
-                       /**
-                        * Here, pi is used to:
-                        * - Tell IOMMU to use legacy mode for this interrupt.
-                        * - Retrieve ga_tag of prior interrupt remapping data.
-                        */
-                       pi.is_guest_mode = false;
-                       ret = irq_set_vcpu_affinity(host_irq, &pi);
-
-                       /**
-                        * Check if the posted interrupt was previously
-                        * setup with the guest_mode by checking if the ga_tag
-                        * was cached. If so, we need to clean up the per-vcpu
-                        * ir_list.
-                        */
-                       if (!ret && pi.prev_ga_tag) {
-                               int id = AVIC_GATAG_TO_VCPUID(pi.prev_ga_tag);
-                               struct kvm_vcpu *vcpu;
-
-                               vcpu = kvm_get_vcpu_by_id(kvm, id);
-                               if (vcpu)
-                                       svm_ir_list_del(to_svm(vcpu), &pi);
-                       }
-               }
-
-               if (!ret && svm) {
-                       trace_kvm_pi_irte_update(host_irq, svm->vcpu.vcpu_id,
-                                                e->gsi, vcpu_info.vector,
-                                                vcpu_info.pi_desc_addr, set);
-               }
-
-               if (ret < 0) {
-                       pr_err("%s: failed to update PI IRTE\n", __func__);
-                       goto out;
-               }
-       }
-
-       ret = 0;
-out:
-       srcu_read_unlock(&kvm->irq_srcu, idx);
-       return ret;
-}
-
-static int svm_nmi_allowed(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       struct vmcb *vmcb = svm->vmcb;
-       int ret;
-       ret = !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) &&
-             !(svm->vcpu.arch.hflags & HF_NMI_MASK);
-       ret = ret && gif_set(svm) && nested_svm_nmi(svm);
-
-       return ret;
-}
-
-static bool svm_get_nmi_mask(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       return !!(svm->vcpu.arch.hflags & HF_NMI_MASK);
-}
-
-static void svm_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       if (masked) {
-               svm->vcpu.arch.hflags |= HF_NMI_MASK;
-               set_intercept(svm, INTERCEPT_IRET);
-       } else {
-               svm->vcpu.arch.hflags &= ~HF_NMI_MASK;
-               clr_intercept(svm, INTERCEPT_IRET);
-       }
-}
-
-static int svm_interrupt_allowed(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       struct vmcb *vmcb = svm->vmcb;
-
-       if (!gif_set(svm) ||
-            (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK))
-               return 0;
-
-       if (is_guest_mode(vcpu) && (svm->vcpu.arch.hflags & HF_VINTR_MASK))
-               return !!(svm->vcpu.arch.hflags & HF_HIF_MASK);
-       else
-               return !!(kvm_get_rflags(vcpu) & X86_EFLAGS_IF);
-}
-
-static void enable_irq_window(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       /*
-        * In case GIF=0 we can't rely on the CPU to tell us when GIF becomes
-        * 1, because that's a separate STGI/VMRUN intercept.  The next time we
-        * get that intercept, this function will be called again though and
-        * we'll get the vintr intercept. However, if the vGIF feature is
-        * enabled, the STGI interception will not occur. Enable the irq
-        * window under the assumption that the hardware will set the GIF.
-        */
-       if (vgif_enabled(svm) || gif_set(svm)) {
-               /*
-                * IRQ window is not needed when AVIC is enabled,
-                * unless we have pending ExtINT since it cannot be injected
-                * via AVIC. In such case, we need to temporarily disable AVIC,
-                * and fallback to injecting IRQ via V_IRQ.
-                */
-               svm_toggle_avic_for_irq_window(vcpu, false);
-               svm_set_vintr(svm);
-       }
-}
-
-static void enable_nmi_window(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       if ((svm->vcpu.arch.hflags & (HF_NMI_MASK | HF_IRET_MASK))
-           == HF_NMI_MASK)
-               return; /* IRET will cause a vm exit */
-
-       if (!gif_set(svm)) {
-               if (vgif_enabled(svm))
-                       set_intercept(svm, INTERCEPT_STGI);
-               return; /* STGI will cause a vm exit */
-       }
-
-       if (svm->nested.exit_required)
-               return; /* we're not going to run the guest yet */
-
-       /*
-        * Something prevents NMI from been injected. Single step over possible
-        * problem (IRET or exception injection or interrupt shadow)
-        */
-       svm->nmi_singlestep_guest_rflags = svm_get_rflags(vcpu);
-       svm->nmi_singlestep = true;
-       svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF);
-}
-
-static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr)
-{
-       return 0;
-}
-
-static int svm_set_identity_map_addr(struct kvm *kvm, u64 ident_addr)
-{
-       return 0;
-}
-
-static void svm_flush_tlb(struct kvm_vcpu *vcpu, bool invalidate_gpa)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       if (static_cpu_has(X86_FEATURE_FLUSHBYASID))
-               svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ASID;
-       else
-               svm->asid_generation--;
-}
-
-static void svm_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t gva)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       invlpga(gva, svm->vmcb->control.asid);
-}
-
-static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu)
-{
-}
-
-static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       if (svm_nested_virtualize_tpr(vcpu))
-               return;
-
-       if (!is_cr_intercept(svm, INTERCEPT_CR8_WRITE)) {
-               int cr8 = svm->vmcb->control.int_ctl & V_TPR_MASK;
-               kvm_set_cr8(vcpu, cr8);
-       }
-}
-
-static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       u64 cr8;
-
-       if (svm_nested_virtualize_tpr(vcpu) ||
-           kvm_vcpu_apicv_active(vcpu))
-               return;
-
-       cr8 = kvm_get_cr8(vcpu);
-       svm->vmcb->control.int_ctl &= ~V_TPR_MASK;
-       svm->vmcb->control.int_ctl |= cr8 & V_TPR_MASK;
-}
-
-static void svm_complete_interrupts(struct vcpu_svm *svm)
-{
-       u8 vector;
-       int type;
-       u32 exitintinfo = svm->vmcb->control.exit_int_info;
-       unsigned int3_injected = svm->int3_injected;
-
-       svm->int3_injected = 0;
-
-       /*
-        * If we've made progress since setting HF_IRET_MASK, we've
-        * executed an IRET and can allow NMI injection.
-        */
-       if ((svm->vcpu.arch.hflags & HF_IRET_MASK)
-           && kvm_rip_read(&svm->vcpu) != svm->nmi_iret_rip) {
-               svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK);
-               kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
-       }
-
-       svm->vcpu.arch.nmi_injected = false;
-       kvm_clear_exception_queue(&svm->vcpu);
-       kvm_clear_interrupt_queue(&svm->vcpu);
-
-       if (!(exitintinfo & SVM_EXITINTINFO_VALID))
-               return;
-
-       kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
-
-       vector = exitintinfo & SVM_EXITINTINFO_VEC_MASK;
-       type = exitintinfo & SVM_EXITINTINFO_TYPE_MASK;
-
-       switch (type) {
-       case SVM_EXITINTINFO_TYPE_NMI:
-               svm->vcpu.arch.nmi_injected = true;
-               break;
-       case SVM_EXITINTINFO_TYPE_EXEPT:
-               /*
-                * In case of software exceptions, do not reinject the vector,
-                * but re-execute the instruction instead. Rewind RIP first
-                * if we emulated INT3 before.
-                */
-               if (kvm_exception_is_soft(vector)) {
-                       if (vector == BP_VECTOR && int3_injected &&
-                           kvm_is_linear_rip(&svm->vcpu, svm->int3_rip))
-                               kvm_rip_write(&svm->vcpu,
-                                             kvm_rip_read(&svm->vcpu) -
-                                             int3_injected);
-                       break;
-               }
-               if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) {
-                       u32 err = svm->vmcb->control.exit_int_info_err;
-                       kvm_requeue_exception_e(&svm->vcpu, vector, err);
-
-               } else
-                       kvm_requeue_exception(&svm->vcpu, vector);
-               break;
-       case SVM_EXITINTINFO_TYPE_INTR:
-               kvm_queue_interrupt(&svm->vcpu, vector, false);
-               break;
-       default:
-               break;
-       }
-}
-
-static void svm_cancel_injection(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       struct vmcb_control_area *control = &svm->vmcb->control;
-
-       control->exit_int_info = control->event_inj;
-       control->exit_int_info_err = control->event_inj_err;
-       control->event_inj = 0;
-       svm_complete_interrupts(svm);
-}
-
-static void svm_vcpu_run(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX];
-       svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP];
-       svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP];
-
-       /*
-        * A vmexit emulation is required before the vcpu can be executed
-        * again.
-        */
-       if (unlikely(svm->nested.exit_required))
-               return;
-
-       /*
-        * Disable singlestep if we're injecting an interrupt/exception.
-        * We don't want our modified rflags to be pushed on the stack where
-        * we might not be able to easily reset them if we disabled NMI
-        * singlestep later.
-        */
-       if (svm->nmi_singlestep && svm->vmcb->control.event_inj) {
-               /*
-                * Event injection happens before external interrupts cause a
-                * vmexit and interrupts are disabled here, so smp_send_reschedule
-                * is enough to force an immediate vmexit.
-                */
-               disable_nmi_singlestep(svm);
-               smp_send_reschedule(vcpu->cpu);
-       }
-
-       pre_svm_run(svm);
-
-       sync_lapic_to_cr8(vcpu);
-
-       svm->vmcb->save.cr2 = vcpu->arch.cr2;
-
-       clgi();
-       kvm_load_guest_xsave_state(vcpu);
-
-       if (lapic_in_kernel(vcpu) &&
-               vcpu->arch.apic->lapic_timer.timer_advance_ns)
-               kvm_wait_lapic_expire(vcpu);
-
-       /*
-        * If this vCPU has touched SPEC_CTRL, restore the guest's value if
-        * it's non-zero. Since vmentry is serialising on affected CPUs, there
-        * is no need to worry about the conditional branch over the wrmsr
-        * being speculatively taken.
-        */
-       x86_spec_ctrl_set_guest(svm->spec_ctrl, svm->virt_spec_ctrl);
-
-       local_irq_enable();
-
-       asm volatile (
-               "push %%" _ASM_BP "; \n\t"
-               "mov %c[rbx](%[svm]), %%" _ASM_BX " \n\t"
-               "mov %c[rcx](%[svm]), %%" _ASM_CX " \n\t"
-               "mov %c[rdx](%[svm]), %%" _ASM_DX " \n\t"
-               "mov %c[rsi](%[svm]), %%" _ASM_SI " \n\t"
-               "mov %c[rdi](%[svm]), %%" _ASM_DI " \n\t"
-               "mov %c[rbp](%[svm]), %%" _ASM_BP " \n\t"
-#ifdef CONFIG_X86_64
-               "mov %c[r8](%[svm]),  %%r8  \n\t"
-               "mov %c[r9](%[svm]),  %%r9  \n\t"
-               "mov %c[r10](%[svm]), %%r10 \n\t"
-               "mov %c[r11](%[svm]), %%r11 \n\t"
-               "mov %c[r12](%[svm]), %%r12 \n\t"
-               "mov %c[r13](%[svm]), %%r13 \n\t"
-               "mov %c[r14](%[svm]), %%r14 \n\t"
-               "mov %c[r15](%[svm]), %%r15 \n\t"
-#endif
-
-               /* Enter guest mode */
-               "push %%" _ASM_AX " \n\t"
-               "mov %c[vmcb](%[svm]), %%" _ASM_AX " \n\t"
-               __ex("vmload %%" _ASM_AX) "\n\t"
-               __ex("vmrun %%" _ASM_AX) "\n\t"
-               __ex("vmsave %%" _ASM_AX) "\n\t"
-               "pop %%" _ASM_AX " \n\t"
-
-               /* Save guest registers, load host registers */
-               "mov %%" _ASM_BX ", %c[rbx](%[svm]) \n\t"
-               "mov %%" _ASM_CX ", %c[rcx](%[svm]) \n\t"
-               "mov %%" _ASM_DX ", %c[rdx](%[svm]) \n\t"
-               "mov %%" _ASM_SI ", %c[rsi](%[svm]) \n\t"
-               "mov %%" _ASM_DI ", %c[rdi](%[svm]) \n\t"
-               "mov %%" _ASM_BP ", %c[rbp](%[svm]) \n\t"
-#ifdef CONFIG_X86_64
-               "mov %%r8,  %c[r8](%[svm]) \n\t"
-               "mov %%r9,  %c[r9](%[svm]) \n\t"
-               "mov %%r10, %c[r10](%[svm]) \n\t"
-               "mov %%r11, %c[r11](%[svm]) \n\t"
-               "mov %%r12, %c[r12](%[svm]) \n\t"
-               "mov %%r13, %c[r13](%[svm]) \n\t"
-               "mov %%r14, %c[r14](%[svm]) \n\t"
-               "mov %%r15, %c[r15](%[svm]) \n\t"
-               /*
-               * Clear host registers marked as clobbered to prevent
-               * speculative use.
-               */
-               "xor %%r8d, %%r8d \n\t"
-               "xor %%r9d, %%r9d \n\t"
-               "xor %%r10d, %%r10d \n\t"
-               "xor %%r11d, %%r11d \n\t"
-               "xor %%r12d, %%r12d \n\t"
-               "xor %%r13d, %%r13d \n\t"
-               "xor %%r14d, %%r14d \n\t"
-               "xor %%r15d, %%r15d \n\t"
-#endif
-               "xor %%ebx, %%ebx \n\t"
-               "xor %%ecx, %%ecx \n\t"
-               "xor %%edx, %%edx \n\t"
-               "xor %%esi, %%esi \n\t"
-               "xor %%edi, %%edi \n\t"
-               "pop %%" _ASM_BP
-               :
-               : [svm]"a"(svm),
-                 [vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)),
-                 [rbx]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_RBX])),
-                 [rcx]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_RCX])),
-                 [rdx]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_RDX])),
-                 [rsi]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_RSI])),
-                 [rdi]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_RDI])),
-                 [rbp]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_RBP]))
-#ifdef CONFIG_X86_64
-                 , [r8]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R8])),
-                 [r9]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R9])),
-                 [r10]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R10])),
-                 [r11]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R11])),
-                 [r12]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R12])),
-                 [r13]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R13])),
-                 [r14]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R14])),
-                 [r15]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R15]))
-#endif
-               : "cc", "memory"
-#ifdef CONFIG_X86_64
-               , "rbx", "rcx", "rdx", "rsi", "rdi"
-               , "r8", "r9", "r10", "r11" , "r12", "r13", "r14", "r15"
-#else
-               , "ebx", "ecx", "edx", "esi", "edi"
-#endif
-               );
-
-       /* Eliminate branch target predictions from guest mode */
-       vmexit_fill_RSB();
-
-#ifdef CONFIG_X86_64
-       wrmsrl(MSR_GS_BASE, svm->host.gs_base);
-#else
-       loadsegment(fs, svm->host.fs);
-#ifndef CONFIG_X86_32_LAZY_GS
-       loadsegment(gs, svm->host.gs);
-#endif
-#endif
-
-       /*
-        * We do not use IBRS in the kernel. If this vCPU has used the
-        * SPEC_CTRL MSR it may have left it on; save the value and
-        * turn it off. This is much more efficient than blindly adding
-        * it to the atomic save/restore list. Especially as the former
-        * (Saving guest MSRs on vmexit) doesn't even exist in KVM.
-        *
-        * For non-nested case:
-        * If the L01 MSR bitmap does not intercept the MSR, then we need to
-        * save it.
-        *
-        * For nested case:
-        * If the L02 MSR bitmap does not intercept the MSR, then we need to
-        * save it.
-        */
-       if (unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL)))
-               svm->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL);
-
-       reload_tss(vcpu);
-
-       local_irq_disable();
-
-       x86_spec_ctrl_restore_host(svm->spec_ctrl, svm->virt_spec_ctrl);
-
-       vcpu->arch.cr2 = svm->vmcb->save.cr2;
-       vcpu->arch.regs[VCPU_REGS_RAX] = svm->vmcb->save.rax;
-       vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
-       vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
-
-       if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
-               kvm_before_interrupt(&svm->vcpu);
-
-       kvm_load_host_xsave_state(vcpu);
-       stgi();
-
-       /* Any pending NMI will happen here */
-
-       if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
-               kvm_after_interrupt(&svm->vcpu);
-
-       sync_cr8_to_lapic(vcpu);
-
-       svm->next_rip = 0;
-
-       svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
-
-       /* if exit due to PF check for async PF */
-       if (svm->vmcb->control.exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR)
-               svm->vcpu.arch.apf.host_apf_reason = kvm_read_and_reset_pf_reason();
-
-       if (npt_enabled) {
-               vcpu->arch.regs_avail &= ~(1 << VCPU_EXREG_PDPTR);
-               vcpu->arch.regs_dirty &= ~(1 << VCPU_EXREG_PDPTR);
-       }
-
-       /*
-        * We need to handle MC intercepts here before the vcpu has a chance to
-        * change the physical cpu
-        */
-       if (unlikely(svm->vmcb->control.exit_code ==
-                    SVM_EXIT_EXCP_BASE + MC_VECTOR))
-               svm_handle_mce(svm);
-
-       mark_all_clean(svm->vmcb);
-}
-STACK_FRAME_NON_STANDARD(svm_vcpu_run);
-
-static void svm_load_mmu_pgd(struct kvm_vcpu *vcpu, unsigned long root)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-       bool update_guest_cr3 = true;
-       unsigned long cr3;
-
-       cr3 = __sme_set(root);
-       if (npt_enabled) {
-               svm->vmcb->control.nested_cr3 = cr3;
-               mark_dirty(svm->vmcb, VMCB_NPT);
-
-               /* Loading L2's CR3 is handled by enter_svm_guest_mode.  */
-               if (is_guest_mode(vcpu))
-                       update_guest_cr3 = false;
-               else if (test_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail))
-                       cr3 = vcpu->arch.cr3;
-               else /* CR3 is already up-to-date.  */
-                       update_guest_cr3 = false;
-       }
-
-       if (update_guest_cr3) {
-               svm->vmcb->save.cr3 = cr3;
-               mark_dirty(svm->vmcb, VMCB_CR);
-       }
-}
-
-static int is_disabled(void)
-{
-       u64 vm_cr;
-
-       rdmsrl(MSR_VM_CR, vm_cr);
-       if (vm_cr & (1 << SVM_VM_CR_SVM_DISABLE))
-               return 1;
-
-       return 0;
-}
-
-static void
-svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
-{
-       /*
-        * Patch in the VMMCALL instruction:
-        */
-       hypercall[0] = 0x0f;
-       hypercall[1] = 0x01;
-       hypercall[2] = 0xd9;
-}
-
-static int __init svm_check_processor_compat(void)
-{
-       return 0;
-}
-
-static bool svm_cpu_has_accelerated_tpr(void)
-{
-       return false;
-}
-
-static bool svm_has_emulated_msr(int index)
-{
-       switch (index) {
-       case MSR_IA32_MCG_EXT_CTL:
-       case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC:
-               return false;
-       default:
-               break;
-       }
-
-       return true;
-}
-
-static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
-{
-       return 0;
-}
-
-static void svm_cpuid_update(struct kvm_vcpu *vcpu)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       vcpu->arch.xsaves_enabled = guest_cpuid_has(vcpu, X86_FEATURE_XSAVE) &&
-                                   boot_cpu_has(X86_FEATURE_XSAVE) &&
-                                   boot_cpu_has(X86_FEATURE_XSAVES);
-
-       /* Update nrips enabled cache */
-       svm->nrips_enabled = kvm_cpu_cap_has(X86_FEATURE_NRIPS) &&
-                            guest_cpuid_has(&svm->vcpu, X86_FEATURE_NRIPS);
-
-       if (!kvm_vcpu_apicv_active(vcpu))
-               return;
-
-       /*
-        * AVIC does not work with an x2APIC mode guest. If the X2APIC feature
-        * is exposed to the guest, disable AVIC.
-        */
-       if (guest_cpuid_has(vcpu, X86_FEATURE_X2APIC))
-               kvm_request_apicv_update(vcpu->kvm, false,
-                                        APICV_INHIBIT_REASON_X2APIC);
-
-       /*
-        * Currently, AVIC does not work with nested virtualization.
-        * So, we disable AVIC when cpuid for SVM is set in the L1 guest.
-        */
-       if (nested && guest_cpuid_has(vcpu, X86_FEATURE_SVM))
-               kvm_request_apicv_update(vcpu->kvm, false,
-                                        APICV_INHIBIT_REASON_NESTED);
-}
-
-static bool svm_has_wbinvd_exit(void)
-{
-       return true;
-}
-
-#define PRE_EX(exit)  { .exit_code = (exit), \
-                       .stage = X86_ICPT_PRE_EXCEPT, }
-#define POST_EX(exit) { .exit_code = (exit), \
-                       .stage = X86_ICPT_POST_EXCEPT, }
-#define POST_MEM(exit) { .exit_code = (exit), \
-                       .stage = X86_ICPT_POST_MEMACCESS, }
-
-static const struct __x86_intercept {
-       u32 exit_code;
-       enum x86_intercept_stage stage;
-} x86_intercept_map[] = {
-       [x86_intercept_cr_read]         = POST_EX(SVM_EXIT_READ_CR0),
-       [x86_intercept_cr_write]        = POST_EX(SVM_EXIT_WRITE_CR0),
-       [x86_intercept_clts]            = POST_EX(SVM_EXIT_WRITE_CR0),
-       [x86_intercept_lmsw]            = POST_EX(SVM_EXIT_WRITE_CR0),
-       [x86_intercept_smsw]            = POST_EX(SVM_EXIT_READ_CR0),
-       [x86_intercept_dr_read]         = POST_EX(SVM_EXIT_READ_DR0),
-       [x86_intercept_dr_write]        = POST_EX(SVM_EXIT_WRITE_DR0),
-       [x86_intercept_sldt]            = POST_EX(SVM_EXIT_LDTR_READ),
-       [x86_intercept_str]             = POST_EX(SVM_EXIT_TR_READ),
-       [x86_intercept_lldt]            = POST_EX(SVM_EXIT_LDTR_WRITE),
-       [x86_intercept_ltr]             = POST_EX(SVM_EXIT_TR_WRITE),
-       [x86_intercept_sgdt]            = POST_EX(SVM_EXIT_GDTR_READ),
-       [x86_intercept_sidt]            = POST_EX(SVM_EXIT_IDTR_READ),
-       [x86_intercept_lgdt]            = POST_EX(SVM_EXIT_GDTR_WRITE),
-       [x86_intercept_lidt]            = POST_EX(SVM_EXIT_IDTR_WRITE),
-       [x86_intercept_vmrun]           = POST_EX(SVM_EXIT_VMRUN),
-       [x86_intercept_vmmcall]         = POST_EX(SVM_EXIT_VMMCALL),
-       [x86_intercept_vmload]          = POST_EX(SVM_EXIT_VMLOAD),
-       [x86_intercept_vmsave]          = POST_EX(SVM_EXIT_VMSAVE),
-       [x86_intercept_stgi]            = POST_EX(SVM_EXIT_STGI),
-       [x86_intercept_clgi]            = POST_EX(SVM_EXIT_CLGI),
-       [x86_intercept_skinit]          = POST_EX(SVM_EXIT_SKINIT),
-       [x86_intercept_invlpga]         = POST_EX(SVM_EXIT_INVLPGA),
-       [x86_intercept_rdtscp]          = POST_EX(SVM_EXIT_RDTSCP),
-       [x86_intercept_monitor]         = POST_MEM(SVM_EXIT_MONITOR),
-       [x86_intercept_mwait]           = POST_EX(SVM_EXIT_MWAIT),
-       [x86_intercept_invlpg]          = POST_EX(SVM_EXIT_INVLPG),
-       [x86_intercept_invd]            = POST_EX(SVM_EXIT_INVD),
-       [x86_intercept_wbinvd]          = POST_EX(SVM_EXIT_WBINVD),
-       [x86_intercept_wrmsr]           = POST_EX(SVM_EXIT_MSR),
-       [x86_intercept_rdtsc]           = POST_EX(SVM_EXIT_RDTSC),
-       [x86_intercept_rdmsr]           = POST_EX(SVM_EXIT_MSR),
-       [x86_intercept_rdpmc]           = POST_EX(SVM_EXIT_RDPMC),
-       [x86_intercept_cpuid]           = PRE_EX(SVM_EXIT_CPUID),
-       [x86_intercept_rsm]             = PRE_EX(SVM_EXIT_RSM),
-       [x86_intercept_pause]           = PRE_EX(SVM_EXIT_PAUSE),
-       [x86_intercept_pushf]           = PRE_EX(SVM_EXIT_PUSHF),
-       [x86_intercept_popf]            = PRE_EX(SVM_EXIT_POPF),
-       [x86_intercept_intn]            = PRE_EX(SVM_EXIT_SWINT),
-       [x86_intercept_iret]            = PRE_EX(SVM_EXIT_IRET),
-       [x86_intercept_icebp]           = PRE_EX(SVM_EXIT_ICEBP),
-       [x86_intercept_hlt]             = POST_EX(SVM_EXIT_HLT),
-       [x86_intercept_in]              = POST_EX(SVM_EXIT_IOIO),
-       [x86_intercept_ins]             = POST_EX(SVM_EXIT_IOIO),
-       [x86_intercept_out]             = POST_EX(SVM_EXIT_IOIO),
-       [x86_intercept_outs]            = POST_EX(SVM_EXIT_IOIO),
-       [x86_intercept_xsetbv]          = PRE_EX(SVM_EXIT_XSETBV),
-};
-
-#undef PRE_EX
-#undef POST_EX
-#undef POST_MEM
+       pr_err("VMCB Control Area:\n");
+       pr_err("%-20s%04x\n", "cr_read:", control->intercept_cr & 0xffff);
+       pr_err("%-20s%04x\n", "cr_write:", control->intercept_cr >> 16);
+       pr_err("%-20s%04x\n", "dr_read:", control->intercept_dr & 0xffff);
+       pr_err("%-20s%04x\n", "dr_write:", control->intercept_dr >> 16);
+       pr_err("%-20s%08x\n", "exceptions:", control->intercept_exceptions);
+       pr_err("%-20s%016llx\n", "intercepts:", control->intercept);
+       pr_err("%-20s%d\n", "pause filter count:", control->pause_filter_count);
+       pr_err("%-20s%d\n", "pause filter threshold:",
+              control->pause_filter_thresh);
+       pr_err("%-20s%016llx\n", "iopm_base_pa:", control->iopm_base_pa);
+       pr_err("%-20s%016llx\n", "msrpm_base_pa:", control->msrpm_base_pa);
+       pr_err("%-20s%016llx\n", "tsc_offset:", control->tsc_offset);
+       pr_err("%-20s%d\n", "asid:", control->asid);
+       pr_err("%-20s%d\n", "tlb_ctl:", control->tlb_ctl);
+       pr_err("%-20s%08x\n", "int_ctl:", control->int_ctl);
+       pr_err("%-20s%08x\n", "int_vector:", control->int_vector);
+       pr_err("%-20s%08x\n", "int_state:", control->int_state);
+       pr_err("%-20s%08x\n", "exit_code:", control->exit_code);
+       pr_err("%-20s%016llx\n", "exit_info1:", control->exit_info_1);
+       pr_err("%-20s%016llx\n", "exit_info2:", control->exit_info_2);
+       pr_err("%-20s%08x\n", "exit_int_info:", control->exit_int_info);
+       pr_err("%-20s%08x\n", "exit_int_info_err:", control->exit_int_info_err);
+       pr_err("%-20s%lld\n", "nested_ctl:", control->nested_ctl);
+       pr_err("%-20s%016llx\n", "nested_cr3:", control->nested_cr3);
+       pr_err("%-20s%016llx\n", "avic_vapic_bar:", control->avic_vapic_bar);
+       pr_err("%-20s%08x\n", "event_inj:", control->event_inj);
+       pr_err("%-20s%08x\n", "event_inj_err:", control->event_inj_err);
+       pr_err("%-20s%lld\n", "virt_ext:", control->virt_ext);
+       pr_err("%-20s%016llx\n", "next_rip:", control->next_rip);
+       pr_err("%-20s%016llx\n", "avic_backing_page:", control->avic_backing_page);
+       pr_err("%-20s%016llx\n", "avic_logical_id:", control->avic_logical_id);
+       pr_err("%-20s%016llx\n", "avic_physical_id:", control->avic_physical_id);
+       pr_err("VMCB State Save Area:\n");
+       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+              "es:",
+              save->es.selector, save->es.attrib,
+              save->es.limit, save->es.base);
+       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+              "cs:",
+              save->cs.selector, save->cs.attrib,
+              save->cs.limit, save->cs.base);
+       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+              "ss:",
+              save->ss.selector, save->ss.attrib,
+              save->ss.limit, save->ss.base);
+       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+              "ds:",
+              save->ds.selector, save->ds.attrib,
+              save->ds.limit, save->ds.base);
+       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+              "fs:",
+              save->fs.selector, save->fs.attrib,
+              save->fs.limit, save->fs.base);
+       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+              "gs:",
+              save->gs.selector, save->gs.attrib,
+              save->gs.limit, save->gs.base);
+       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+              "gdtr:",
+              save->gdtr.selector, save->gdtr.attrib,
+              save->gdtr.limit, save->gdtr.base);
+       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+              "ldtr:",
+              save->ldtr.selector, save->ldtr.attrib,
+              save->ldtr.limit, save->ldtr.base);
+       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+              "idtr:",
+              save->idtr.selector, save->idtr.attrib,
+              save->idtr.limit, save->idtr.base);
+       pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+              "tr:",
+              save->tr.selector, save->tr.attrib,
+              save->tr.limit, save->tr.base);
+       pr_err("cpl:            %d                efer:         %016llx\n",
+               save->cpl, save->efer);
+       pr_err("%-15s %016llx %-13s %016llx\n",
+              "cr0:", save->cr0, "cr2:", save->cr2);
+       pr_err("%-15s %016llx %-13s %016llx\n",
+              "cr3:", save->cr3, "cr4:", save->cr4);
+       pr_err("%-15s %016llx %-13s %016llx\n",
+              "dr6:", save->dr6, "dr7:", save->dr7);
+       pr_err("%-15s %016llx %-13s %016llx\n",
+              "rip:", save->rip, "rflags:", save->rflags);
+       pr_err("%-15s %016llx %-13s %016llx\n",
+              "rsp:", save->rsp, "rax:", save->rax);
+       pr_err("%-15s %016llx %-13s %016llx\n",
+              "star:", save->star, "lstar:", save->lstar);
+       pr_err("%-15s %016llx %-13s %016llx\n",
+              "cstar:", save->cstar, "sfmask:", save->sfmask);
+       pr_err("%-15s %016llx %-13s %016llx\n",
+              "kernel_gs_base:", save->kernel_gs_base,
+              "sysenter_cs:", save->sysenter_cs);
+       pr_err("%-15s %016llx %-13s %016llx\n",
+              "sysenter_esp:", save->sysenter_esp,
+              "sysenter_eip:", save->sysenter_eip);
+       pr_err("%-15s %016llx %-13s %016llx\n",
+              "gpat:", save->g_pat, "dbgctl:", save->dbgctl);
+       pr_err("%-15s %016llx %-13s %016llx\n",
+              "br_from:", save->br_from, "br_to:", save->br_to);
+       pr_err("%-15s %016llx %-13s %016llx\n",
+              "excp_from:", save->last_excp_from,
+              "excp_to:", save->last_excp_to);
+}
 
-static int svm_check_intercept(struct kvm_vcpu *vcpu,
-                              struct x86_instruction_info *info,
-                              enum x86_intercept_stage stage,
-                              struct x86_exception *exception)
+static void svm_get_exit_info(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2)
 {
-       struct vcpu_svm *svm = to_svm(vcpu);
-       int vmexit, ret = X86EMUL_CONTINUE;
-       struct __x86_intercept icpt_info;
-       struct vmcb *vmcb = svm->vmcb;
-
-       if (info->intercept >= ARRAY_SIZE(x86_intercept_map))
-               goto out;
-
-       icpt_info = x86_intercept_map[info->intercept];
-
-       if (stage != icpt_info.stage)
-               goto out;
-
-       switch (icpt_info.exit_code) {
-       case SVM_EXIT_READ_CR0:
-               if (info->intercept == x86_intercept_cr_read)
-                       icpt_info.exit_code += info->modrm_reg;
-               break;
-       case SVM_EXIT_WRITE_CR0: {
-               unsigned long cr0, val;
-               u64 intercept;
-
-               if (info->intercept == x86_intercept_cr_write)
-                       icpt_info.exit_code += info->modrm_reg;
-
-               if (icpt_info.exit_code != SVM_EXIT_WRITE_CR0 ||
-                   info->intercept == x86_intercept_clts)
-                       break;
+       struct vmcb_control_area *control = &to_svm(vcpu)->vmcb->control;
 
-               intercept = svm->nested.intercept;
+       *info1 = control->exit_info_1;
+       *info2 = control->exit_info_2;
+}
 
-               if (!(intercept & (1ULL << INTERCEPT_SELECTIVE_CR0)))
-                       break;
+static int handle_exit(struct kvm_vcpu *vcpu,
+       enum exit_fastpath_completion exit_fastpath)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       struct kvm_run *kvm_run = vcpu->run;
+       u32 exit_code = svm->vmcb->control.exit_code;
 
-               cr0 = vcpu->arch.cr0 & ~SVM_CR0_SELECTIVE_MASK;
-               val = info->src_val  & ~SVM_CR0_SELECTIVE_MASK;
+       trace_kvm_exit(exit_code, vcpu, KVM_ISA_SVM);
 
-               if (info->intercept == x86_intercept_lmsw) {
-                       cr0 &= 0xfUL;
-                       val &= 0xfUL;
-                       /* lmsw can't clear PE - catch this here */
-                       if (cr0 & X86_CR0_PE)
-                               val |= X86_CR0_PE;
-               }
+       if (!is_cr_intercept(svm, INTERCEPT_CR0_WRITE))
+               vcpu->arch.cr0 = svm->vmcb->save.cr0;
+       if (npt_enabled)
+               vcpu->arch.cr3 = svm->vmcb->save.cr3;
 
-               if (cr0 ^ val)
-                       icpt_info.exit_code = SVM_EXIT_CR0_SEL_WRITE;
+       if (unlikely(svm->nested.exit_required)) {
+               nested_svm_vmexit(svm);
+               svm->nested.exit_required = false;
 
-               break;
+               return 1;
        }
-       case SVM_EXIT_READ_DR0:
-       case SVM_EXIT_WRITE_DR0:
-               icpt_info.exit_code += info->modrm_reg;
-               break;
-       case SVM_EXIT_MSR:
-               if (info->intercept == x86_intercept_wrmsr)
-                       vmcb->control.exit_info_1 = 1;
-               else
-                       vmcb->control.exit_info_1 = 0;
-               break;
-       case SVM_EXIT_PAUSE:
-               /*
-                * We get this for NOP only, but pause
-                * is rep not, check this here
-                */
-               if (info->rep_prefix != REPE_PREFIX)
-                       goto out;
-               break;
-       case SVM_EXIT_IOIO: {
-               u64 exit_info;
-               u32 bytes;
 
-               if (info->intercept == x86_intercept_in ||
-                   info->intercept == x86_intercept_ins) {
-                       exit_info = ((info->src_val & 0xffff) << 16) |
-                               SVM_IOIO_TYPE_MASK;
-                       bytes = info->dst_bytes;
-               } else {
-                       exit_info = (info->dst_val & 0xffff) << 16;
-                       bytes = info->src_bytes;
-               }
-
-               if (info->intercept == x86_intercept_outs ||
-                   info->intercept == x86_intercept_ins)
-                       exit_info |= SVM_IOIO_STR_MASK;
+       if (is_guest_mode(vcpu)) {
+               int vmexit;
 
-               if (info->rep_prefix)
-                       exit_info |= SVM_IOIO_REP_MASK;
+               trace_kvm_nested_vmexit(svm->vmcb->save.rip, exit_code,
+                                       svm->vmcb->control.exit_info_1,
+                                       svm->vmcb->control.exit_info_2,
+                                       svm->vmcb->control.exit_int_info,
+                                       svm->vmcb->control.exit_int_info_err,
+                                       KVM_ISA_SVM);
 
-               bytes = min(bytes, 4u);
+               vmexit = nested_svm_exit_special(svm);
 
-               exit_info |= bytes << SVM_IOIO_SIZE_SHIFT;
+               if (vmexit == NESTED_EXIT_CONTINUE)
+                       vmexit = nested_svm_exit_handled(svm);
 
-               exit_info |= (u32)info->ad_bytes << (SVM_IOIO_ASIZE_SHIFT - 1);
+               if (vmexit == NESTED_EXIT_DONE)
+                       return 1;
+       }
 
-               vmcb->control.exit_info_1 = exit_info;
-               vmcb->control.exit_info_2 = info->next_rip;
+       svm_complete_interrupts(svm);
 
-               break;
-       }
-       default:
-               break;
+       if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
+               kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+               kvm_run->fail_entry.hardware_entry_failure_reason
+                       = svm->vmcb->control.exit_code;
+               dump_vmcb(vcpu);
+               return 0;
        }
 
-       /* TODO: Advertise NRIPS to guest hypervisor unconditionally */
-       if (static_cpu_has(X86_FEATURE_NRIPS))
-               vmcb->control.next_rip  = info->next_rip;
-       vmcb->control.exit_code = icpt_info.exit_code;
-       vmexit = nested_svm_exit_handled(svm);
+       if (is_external_interrupt(svm->vmcb->control.exit_int_info) &&
+           exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR &&
+           exit_code != SVM_EXIT_NPF && exit_code != SVM_EXIT_TASK_SWITCH &&
+           exit_code != SVM_EXIT_INTR && exit_code != SVM_EXIT_NMI)
+               printk(KERN_ERR "%s: unexpected exit_int_info 0x%x "
+                      "exit_code 0x%x\n",
+                      __func__, svm->vmcb->control.exit_int_info,
+                      exit_code);
 
-       ret = (vmexit == NESTED_EXIT_DONE) ? X86EMUL_INTERCEPTED
-                                          : X86EMUL_CONTINUE;
+       if (exit_fastpath == EXIT_FASTPATH_SKIP_EMUL_INS) {
+               kvm_skip_emulated_instruction(vcpu);
+               return 1;
+       } else if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
+           || !svm_exit_handlers[exit_code]) {
+               vcpu_unimpl(vcpu, "svm: unexpected exit reason 0x%x\n", exit_code);
+               dump_vmcb(vcpu);
+               vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+               vcpu->run->internal.suberror =
+                       KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON;
+               vcpu->run->internal.ndata = 1;
+               vcpu->run->internal.data[0] = exit_code;
+               return 0;
+       }
 
-out:
-       return ret;
+#ifdef CONFIG_RETPOLINE
+       if (exit_code == SVM_EXIT_MSR)
+               return msr_interception(svm);
+       else if (exit_code == SVM_EXIT_VINTR)
+               return interrupt_window_interception(svm);
+       else if (exit_code == SVM_EXIT_INTR)
+               return intr_interception(svm);
+       else if (exit_code == SVM_EXIT_HLT)
+               return halt_interception(svm);
+       else if (exit_code == SVM_EXIT_NPF)
+               return npf_interception(svm);
+#endif
+       return svm_exit_handlers[exit_code](svm);
 }
 
-static void svm_handle_exit_irqoff(struct kvm_vcpu *vcpu,
-       enum exit_fastpath_completion *exit_fastpath)
+static void reload_tss(struct kvm_vcpu *vcpu)
 {
-       if (!is_guest_mode(vcpu) &&
-           to_svm(vcpu)->vmcb->control.exit_code == SVM_EXIT_MSR &&
-           to_svm(vcpu)->vmcb->control.exit_info_1)
-               *exit_fastpath = handle_fastpath_set_msr_irqoff(vcpu);
-}
+       int cpu = raw_smp_processor_id();
 
-static void svm_sched_in(struct kvm_vcpu *vcpu, int cpu)
-{
-       if (pause_filter_thresh)
-               shrink_ple_window(vcpu);
+       struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
+       sd->tss_desc->type = 9; /* available 32/64-bit TSS */
+       load_TR_desc();
 }
 
-static inline void avic_post_state_restore(struct kvm_vcpu *vcpu)
+static void pre_svm_run(struct vcpu_svm *svm)
 {
-       if (avic_handle_apic_id_update(vcpu) != 0)
-               return;
-       avic_handle_dfr_update(vcpu);
-       avic_handle_ldr_update(vcpu);
-}
+       int cpu = raw_smp_processor_id();
 
-static void svm_setup_mce(struct kvm_vcpu *vcpu)
-{
-       /* [63:9] are reserved. */
-       vcpu->arch.mcg_cap &= 0x1ff;
+       struct svm_cpu_data *sd = per_cpu(svm_data, cpu);
+
+       if (sev_guest(svm->vcpu.kvm))
+               return pre_sev_run(svm, cpu);
+
+       /* FIXME: handle wraparound of asid_generation */
+       if (svm->asid_generation != sd->asid_generation)
+               new_asid(svm, sd);
 }
 
-static int svm_smi_allowed(struct kvm_vcpu *vcpu)
+static void svm_inject_nmi(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       /* Per APM Vol.2 15.22.2 "Response to SMI" */
-       if (!gif_set(svm))
-               return 0;
-
-       if (is_guest_mode(&svm->vcpu) &&
-           svm->nested.intercept & (1ULL << INTERCEPT_SMI)) {
-               /* TODO: Might need to set exit_info_1 and exit_info_2 here */
-               svm->vmcb->control.exit_code = SVM_EXIT_SMI;
-               svm->nested.exit_required = true;
-               return 0;
-       }
-
-       return 1;
+       svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_NMI;
+       vcpu->arch.hflags |= HF_NMI_MASK;
+       set_intercept(svm, INTERCEPT_IRET);
+       ++vcpu->stat.nmi_injections;
 }
 
-static int svm_pre_enter_smm(struct kvm_vcpu *vcpu, char *smstate)
+static void svm_set_irq(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
-       int ret;
 
-       if (is_guest_mode(vcpu)) {
-               /* FED8h - SVM Guest */
-               put_smstate(u64, smstate, 0x7ed8, 1);
-               /* FEE0h - SVM Guest VMCB Physical Address */
-               put_smstate(u64, smstate, 0x7ee0, svm->nested.vmcb);
+       BUG_ON(!(gif_set(svm)));
 
-               svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX];
-               svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP];
-               svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP];
+       trace_kvm_inj_virq(vcpu->arch.interrupt.nr);
+       ++vcpu->stat.irq_injections;
 
-               ret = nested_svm_vmexit(svm);
-               if (ret)
-                       return ret;
-       }
-       return 0;
+       svm->vmcb->control.event_inj = vcpu->arch.interrupt.nr |
+               SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
 }
 
-static int svm_pre_leave_smm(struct kvm_vcpu *vcpu, const char *smstate)
+static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
-       struct vmcb *nested_vmcb;
-       struct kvm_host_map map;
-       u64 guest;
-       u64 vmcb;
 
-       guest = GET_SMSTATE(u64, smstate, 0x7ed8);
-       vmcb = GET_SMSTATE(u64, smstate, 0x7ee0);
+       if (svm_nested_virtualize_tpr(vcpu))
+               return;
 
-       if (guest) {
-               if (kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(vmcb), &map) == -EINVAL)
-                       return 1;
-               nested_vmcb = map.hva;
-               enter_svm_guest_mode(svm, vmcb, nested_vmcb, &map);
-       }
-       return 0;
+       clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
+
+       if (irr == -1)
+               return;
+
+       if (tpr >= irr)
+               set_cr_intercept(svm, INTERCEPT_CR8_WRITE);
 }
 
-static int enable_smi_window(struct kvm_vcpu *vcpu)
+static int svm_nmi_allowed(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
+       struct vmcb *vmcb = svm->vmcb;
+       int ret;
+       ret = !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) &&
+             !(svm->vcpu.arch.hflags & HF_NMI_MASK);
+       ret = ret && gif_set(svm) && nested_svm_nmi(svm);
 
-       if (!gif_set(svm)) {
-               if (vgif_enabled(svm))
-                       set_intercept(svm, INTERCEPT_STGI);
-               /* STGI will cause a vm exit */
-               return 1;
-       }
-       return 0;
+       return ret;
 }
 
-static int sev_flush_asids(void)
+static bool svm_get_nmi_mask(struct kvm_vcpu *vcpu)
 {
-       int ret, error;
-
-       /*
-        * DEACTIVATE will clear the WBINVD indicator causing DF_FLUSH to fail,
-        * so it must be guarded.
-        */
-       down_write(&sev_deactivate_lock);
-
-       wbinvd_on_all_cpus();
-       ret = sev_guest_df_flush(&error);
-
-       up_write(&sev_deactivate_lock);
-
-       if (ret)
-               pr_err("SEV: DF_FLUSH failed, ret=%d, error=%#x\n", ret, error);
+       struct vcpu_svm *svm = to_svm(vcpu);
 
-       return ret;
+       return !!(svm->vcpu.arch.hflags & HF_NMI_MASK);
 }
 
-/* Must be called with the sev_bitmap_lock held */
-static bool __sev_recycle_asids(void)
+static void svm_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
 {
-       int pos;
+       struct vcpu_svm *svm = to_svm(vcpu);
 
-       /* Check if there are any ASIDs to reclaim before performing a flush */
-       pos = find_next_bit(sev_reclaim_asid_bitmap,
-                           max_sev_asid, min_sev_asid - 1);
-       if (pos >= max_sev_asid)
-               return false;
+       if (masked) {
+               svm->vcpu.arch.hflags |= HF_NMI_MASK;
+               set_intercept(svm, INTERCEPT_IRET);
+       } else {
+               svm->vcpu.arch.hflags &= ~HF_NMI_MASK;
+               clr_intercept(svm, INTERCEPT_IRET);
+       }
+}
 
-       if (sev_flush_asids())
-               return false;
+static int svm_interrupt_allowed(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       struct vmcb *vmcb = svm->vmcb;
 
-       bitmap_xor(sev_asid_bitmap, sev_asid_bitmap, sev_reclaim_asid_bitmap,
-                  max_sev_asid);
-       bitmap_zero(sev_reclaim_asid_bitmap, max_sev_asid);
+       if (!gif_set(svm) ||
+            (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK))
+               return 0;
 
-       return true;
+       if (is_guest_mode(vcpu) && (svm->vcpu.arch.hflags & HF_VINTR_MASK))
+               return !!(svm->vcpu.arch.hflags & HF_HIF_MASK);
+       else
+               return !!(kvm_get_rflags(vcpu) & X86_EFLAGS_IF);
 }
 
-static int sev_asid_new(void)
+static void enable_irq_window(struct kvm_vcpu *vcpu)
 {
-       bool retry = true;
-       int pos;
-
-       mutex_lock(&sev_bitmap_lock);
+       struct vcpu_svm *svm = to_svm(vcpu);
 
        /*
-        * SEV-enabled guest must use asid from min_sev_asid to max_sev_asid.
+        * In case GIF=0 we can't rely on the CPU to tell us when GIF becomes
+        * 1, because that's a separate STGI/VMRUN intercept.  The next time we
+        * get that intercept, this function will be called again though and
+        * we'll get the vintr intercept. However, if the vGIF feature is
+        * enabled, the STGI interception will not occur. Enable the irq
+        * window under the assumption that the hardware will set the GIF.
         */
-again:
-       pos = find_next_zero_bit(sev_asid_bitmap, max_sev_asid, min_sev_asid - 1);
-       if (pos >= max_sev_asid) {
-               if (retry && __sev_recycle_asids()) {
-                       retry = false;
-                       goto again;
-               }
-               mutex_unlock(&sev_bitmap_lock);
-               return -EBUSY;
+       if (vgif_enabled(svm) || gif_set(svm)) {
+               /*
+                * IRQ window is not needed when AVIC is enabled,
+                * unless we have pending ExtINT since it cannot be injected
+                * via AVIC. In such case, we need to temporarily disable AVIC,
+                * and fallback to injecting IRQ via V_IRQ.
+                */
+               svm_toggle_avic_for_irq_window(vcpu, false);
+               svm_set_vintr(svm);
        }
-
-       __set_bit(pos, sev_asid_bitmap);
-
-       mutex_unlock(&sev_bitmap_lock);
-
-       return pos + 1;
 }
 
-static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
+static void enable_nmi_window(struct kvm_vcpu *vcpu)
 {
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-       int asid, ret;
+       struct vcpu_svm *svm = to_svm(vcpu);
 
-       ret = -EBUSY;
-       if (unlikely(sev->active))
-               return ret;
+       if ((svm->vcpu.arch.hflags & (HF_NMI_MASK | HF_IRET_MASK))
+           == HF_NMI_MASK)
+               return; /* IRET will cause a vm exit */
 
-       asid = sev_asid_new();
-       if (asid < 0)
-               return ret;
+       if (!gif_set(svm)) {
+               if (vgif_enabled(svm))
+                       set_intercept(svm, INTERCEPT_STGI);
+               return; /* STGI will cause a vm exit */
+       }
 
-       ret = sev_platform_init(&argp->error);
-       if (ret)
-               goto e_free;
+       if (svm->nested.exit_required)
+               return; /* we're not going to run the guest yet */
 
-       sev->active = true;
-       sev->asid = asid;
-       INIT_LIST_HEAD(&sev->regions_list);
+       /*
+        * Something prevents NMI from been injected. Single step over possible
+        * problem (IRET or exception injection or interrupt shadow)
+        */
+       svm->nmi_singlestep_guest_rflags = svm_get_rflags(vcpu);
+       svm->nmi_singlestep = true;
+       svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF);
+}
 
+static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr)
+{
        return 0;
+}
 
-e_free:
-       sev_asid_free(asid);
-       return ret;
+static int svm_set_identity_map_addr(struct kvm *kvm, u64 ident_addr)
+{
+       return 0;
 }
 
-static int sev_bind_asid(struct kvm *kvm, unsigned int handle, int *error)
+void svm_flush_tlb(struct kvm_vcpu *vcpu, bool invalidate_gpa)
 {
-       struct sev_data_activate *data;
-       int asid = sev_get_asid(kvm);
-       int ret;
+       struct vcpu_svm *svm = to_svm(vcpu);
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
-       if (!data)
-               return -ENOMEM;
+       if (static_cpu_has(X86_FEATURE_FLUSHBYASID))
+               svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ASID;
+       else
+               svm->asid_generation--;
+}
 
-       /* activate ASID on the given handle */
-       data->handle = handle;
-       data->asid   = asid;
-       ret = sev_guest_activate(data, error);
-       kfree(data);
+static void svm_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t gva)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
 
-       return ret;
+       invlpga(gva, svm->vmcb->control.asid);
 }
 
-static int __sev_issue_cmd(int fd, int id, void *data, int *error)
+static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu)
 {
-       struct fd f;
-       int ret;
+}
 
-       f = fdget(fd);
-       if (!f.file)
-               return -EBADF;
+static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
 
-       ret = sev_issue_cmd_external_user(f.file, id, data, error);
+       if (svm_nested_virtualize_tpr(vcpu))
+               return;
 
-       fdput(f);
-       return ret;
+       if (!is_cr_intercept(svm, INTERCEPT_CR8_WRITE)) {
+               int cr8 = svm->vmcb->control.int_ctl & V_TPR_MASK;
+               kvm_set_cr8(vcpu, cr8);
+       }
 }
 
-static int sev_issue_cmd(struct kvm *kvm, int id, void *data, int *error)
+static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu)
 {
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+       struct vcpu_svm *svm = to_svm(vcpu);
+       u64 cr8;
+
+       if (svm_nested_virtualize_tpr(vcpu) ||
+           kvm_vcpu_apicv_active(vcpu))
+               return;
 
-       return __sev_issue_cmd(sev->fd, id, data, error);
+       cr8 = kvm_get_cr8(vcpu);
+       svm->vmcb->control.int_ctl &= ~V_TPR_MASK;
+       svm->vmcb->control.int_ctl |= cr8 & V_TPR_MASK;
 }
 
-static int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
+static void svm_complete_interrupts(struct vcpu_svm *svm)
 {
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-       struct sev_data_launch_start *start;
-       struct kvm_sev_launch_start params;
-       void *dh_blob, *session_blob;
-       int *error = &argp->error;
-       int ret;
+       u8 vector;
+       int type;
+       u32 exitintinfo = svm->vmcb->control.exit_int_info;
+       unsigned int3_injected = svm->int3_injected;
 
-       if (!sev_guest(kvm))
-               return -ENOTTY;
+       svm->int3_injected = 0;
 
-       if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
-               return -EFAULT;
+       /*
+        * If we've made progress since setting HF_IRET_MASK, we've
+        * executed an IRET and can allow NMI injection.
+        */
+       if ((svm->vcpu.arch.hflags & HF_IRET_MASK)
+           && kvm_rip_read(&svm->vcpu) != svm->nmi_iret_rip) {
+               svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK);
+               kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
+       }
 
-       start = kzalloc(sizeof(*start), GFP_KERNEL_ACCOUNT);
-       if (!start)
-               return -ENOMEM;
+       svm->vcpu.arch.nmi_injected = false;
+       kvm_clear_exception_queue(&svm->vcpu);
+       kvm_clear_interrupt_queue(&svm->vcpu);
 
-       dh_blob = NULL;
-       if (params.dh_uaddr) {
-               dh_blob = psp_copy_user_blob(params.dh_uaddr, params.dh_len);
-               if (IS_ERR(dh_blob)) {
-                       ret = PTR_ERR(dh_blob);
-                       goto e_free;
-               }
+       if (!(exitintinfo & SVM_EXITINTINFO_VALID))
+               return;
 
-               start->dh_cert_address = __sme_set(__pa(dh_blob));
-               start->dh_cert_len = params.dh_len;
-       }
+       kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
 
-       session_blob = NULL;
-       if (params.session_uaddr) {
-               session_blob = psp_copy_user_blob(params.session_uaddr, params.session_len);
-               if (IS_ERR(session_blob)) {
-                       ret = PTR_ERR(session_blob);
-                       goto e_free_dh;
-               }
+       vector = exitintinfo & SVM_EXITINTINFO_VEC_MASK;
+       type = exitintinfo & SVM_EXITINTINFO_TYPE_MASK;
 
-               start->session_address = __sme_set(__pa(session_blob));
-               start->session_len = params.session_len;
-       }
+       switch (type) {
+       case SVM_EXITINTINFO_TYPE_NMI:
+               svm->vcpu.arch.nmi_injected = true;
+               break;
+       case SVM_EXITINTINFO_TYPE_EXEPT:
+               /*
+                * In case of software exceptions, do not reinject the vector,
+                * but re-execute the instruction instead. Rewind RIP first
+                * if we emulated INT3 before.
+                */
+               if (kvm_exception_is_soft(vector)) {
+                       if (vector == BP_VECTOR && int3_injected &&
+                           kvm_is_linear_rip(&svm->vcpu, svm->int3_rip))
+                               kvm_rip_write(&svm->vcpu,
+                                             kvm_rip_read(&svm->vcpu) -
+                                             int3_injected);
+                       break;
+               }
+               if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) {
+                       u32 err = svm->vmcb->control.exit_int_info_err;
+                       kvm_requeue_exception_e(&svm->vcpu, vector, err);
 
-       start->handle = params.handle;
-       start->policy = params.policy;
-
-       /* create memory encryption context */
-       ret = __sev_issue_cmd(argp->sev_fd, SEV_CMD_LAUNCH_START, start, error);
-       if (ret)
-               goto e_free_session;
-
-       /* Bind ASID to this guest */
-       ret = sev_bind_asid(kvm, start->handle, error);
-       if (ret)
-               goto e_free_session;
-
-       /* return handle to userspace */
-       params.handle = start->handle;
-       if (copy_to_user((void __user *)(uintptr_t)argp->data, &params, sizeof(params))) {
-               sev_unbind_asid(kvm, start->handle);
-               ret = -EFAULT;
-               goto e_free_session;
+               } else
+                       kvm_requeue_exception(&svm->vcpu, vector);
+               break;
+       case SVM_EXITINTINFO_TYPE_INTR:
+               kvm_queue_interrupt(&svm->vcpu, vector, false);
+               break;
+       default:
+               break;
        }
+}
 
-       sev->handle = start->handle;
-       sev->fd = argp->sev_fd;
+static void svm_cancel_injection(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       struct vmcb_control_area *control = &svm->vmcb->control;
 
-e_free_session:
-       kfree(session_blob);
-e_free_dh:
-       kfree(dh_blob);
-e_free:
-       kfree(start);
-       return ret;
+       control->exit_int_info = control->event_inj;
+       control->exit_int_info_err = control->event_inj_err;
+       control->event_inj = 0;
+       svm_complete_interrupts(svm);
 }
 
-static unsigned long get_num_contig_pages(unsigned long idx,
-                               struct page **inpages, unsigned long npages)
+bool __svm_vcpu_run(unsigned long vmcb_pa, unsigned long *regs);
+
+static void svm_vcpu_run(struct kvm_vcpu *vcpu)
 {
-       unsigned long paddr, next_paddr;
-       unsigned long i = idx + 1, pages = 1;
+       struct vcpu_svm *svm = to_svm(vcpu);
 
-       /* find the number of contiguous pages starting from idx */
-       paddr = __sme_page_pa(inpages[idx]);
-       while (i < npages) {
-               next_paddr = __sme_page_pa(inpages[i++]);
-               if ((paddr + PAGE_SIZE) == next_paddr) {
-                       pages++;
-                       paddr = next_paddr;
-                       continue;
-               }
-               break;
+       svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX];
+       svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP];
+       svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP];
+
+       /*
+        * A vmexit emulation is required before the vcpu can be executed
+        * again.
+        */
+       if (unlikely(svm->nested.exit_required))
+               return;
+
+       /*
+        * Disable singlestep if we're injecting an interrupt/exception.
+        * We don't want our modified rflags to be pushed on the stack where
+        * we might not be able to easily reset them if we disabled NMI
+        * singlestep later.
+        */
+       if (svm->nmi_singlestep && svm->vmcb->control.event_inj) {
+               /*
+                * Event injection happens before external interrupts cause a
+                * vmexit and interrupts are disabled here, so smp_send_reschedule
+                * is enough to force an immediate vmexit.
+                */
+               disable_nmi_singlestep(svm);
+               smp_send_reschedule(vcpu->cpu);
        }
 
-       return pages;
-}
-
-static int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
-{
-       unsigned long vaddr, vaddr_end, next_vaddr, npages, pages, size, i;
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-       struct kvm_sev_launch_update_data params;
-       struct sev_data_launch_update_data *data;
-       struct page **inpages;
-       int ret;
-
-       if (!sev_guest(kvm))
-               return -ENOTTY;
+       pre_svm_run(svm);
 
-       if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
-               return -EFAULT;
+       sync_lapic_to_cr8(vcpu);
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
-       if (!data)
-               return -ENOMEM;
+       svm->vmcb->save.cr2 = vcpu->arch.cr2;
 
-       vaddr = params.uaddr;
-       size = params.len;
-       vaddr_end = vaddr + size;
+       clgi();
+       kvm_load_guest_xsave_state(vcpu);
 
-       /* Lock the user memory. */
-       inpages = sev_pin_memory(kvm, vaddr, size, &npages, 1);
-       if (!inpages) {
-               ret = -ENOMEM;
-               goto e_free;
-       }
+       if (lapic_in_kernel(vcpu) &&
+               vcpu->arch.apic->lapic_timer.timer_advance_ns)
+               kvm_wait_lapic_expire(vcpu);
 
        /*
-        * The LAUNCH_UPDATE command will perform in-place encryption of the
-        * memory content (i.e it will write the same memory region with C=1).
-        * It's possible that the cache may contain the data with C=0, i.e.,
-        * unencrypted so invalidate it first.
+        * If this vCPU has touched SPEC_CTRL, restore the guest's value if
+        * it's non-zero. Since vmentry is serialising on affected CPUs, there
+        * is no need to worry about the conditional branch over the wrmsr
+        * being speculatively taken.
         */
-       sev_clflush_pages(inpages, npages);
-
-       for (i = 0; vaddr < vaddr_end; vaddr = next_vaddr, i += pages) {
-               int offset, len;
+       x86_spec_ctrl_set_guest(svm->spec_ctrl, svm->virt_spec_ctrl);
 
-               /*
-                * If the user buffer is not page-aligned, calculate the offset
-                * within the page.
-                */
-               offset = vaddr & (PAGE_SIZE - 1);
+       local_irq_enable();
 
-               /* Calculate the number of pages that can be encrypted in one go. */
-               pages = get_num_contig_pages(i, inpages, npages);
+       __svm_vcpu_run(svm->vmcb_pa, (unsigned long *)&svm->vcpu.arch.regs);
 
-               len = min_t(size_t, ((pages * PAGE_SIZE) - offset), size);
+       /* Eliminate branch target predictions from guest mode */
+       vmexit_fill_RSB();
 
-               data->handle = sev->handle;
-               data->len = len;
-               data->address = __sme_page_pa(inpages[i]) + offset;
-               ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_DATA, data, &argp->error);
-               if (ret)
-                       goto e_unpin;
+#ifdef CONFIG_X86_64
+       wrmsrl(MSR_GS_BASE, svm->host.gs_base);
+#else
+       loadsegment(fs, svm->host.fs);
+#ifndef CONFIG_X86_32_LAZY_GS
+       loadsegment(gs, svm->host.gs);
+#endif
+#endif
 
-               size -= len;
-               next_vaddr = vaddr + len;
-       }
+       /*
+        * We do not use IBRS in the kernel. If this vCPU has used the
+        * SPEC_CTRL MSR it may have left it on; save the value and
+        * turn it off. This is much more efficient than blindly adding
+        * it to the atomic save/restore list. Especially as the former
+        * (Saving guest MSRs on vmexit) doesn't even exist in KVM.
+        *
+        * For non-nested case:
+        * If the L01 MSR bitmap does not intercept the MSR, then we need to
+        * save it.
+        *
+        * For nested case:
+        * If the L02 MSR bitmap does not intercept the MSR, then we need to
+        * save it.
+        */
+       if (unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL)))
+               svm->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL);
 
-e_unpin:
-       /* content of memory is updated, mark pages dirty */
-       for (i = 0; i < npages; i++) {
-               set_page_dirty_lock(inpages[i]);
-               mark_page_accessed(inpages[i]);
-       }
-       /* unlock the user pages */
-       sev_unpin_memory(kvm, inpages, npages);
-e_free:
-       kfree(data);
-       return ret;
-}
+       reload_tss(vcpu);
 
-static int sev_launch_measure(struct kvm *kvm, struct kvm_sev_cmd *argp)
-{
-       void __user *measure = (void __user *)(uintptr_t)argp->data;
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-       struct sev_data_launch_measure *data;
-       struct kvm_sev_launch_measure params;
-       void __user *p = NULL;
-       void *blob = NULL;
-       int ret;
+       local_irq_disable();
 
-       if (!sev_guest(kvm))
-               return -ENOTTY;
+       x86_spec_ctrl_restore_host(svm->spec_ctrl, svm->virt_spec_ctrl);
 
-       if (copy_from_user(&params, measure, sizeof(params)))
-               return -EFAULT;
+       vcpu->arch.cr2 = svm->vmcb->save.cr2;
+       vcpu->arch.regs[VCPU_REGS_RAX] = svm->vmcb->save.rax;
+       vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
+       vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
-       if (!data)
-               return -ENOMEM;
+       if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
+               kvm_before_interrupt(&svm->vcpu);
 
-       /* User wants to query the blob length */
-       if (!params.len)
-               goto cmd;
+       kvm_load_host_xsave_state(vcpu);
+       stgi();
 
-       p = (void __user *)(uintptr_t)params.uaddr;
-       if (p) {
-               if (params.len > SEV_FW_BLOB_MAX_SIZE) {
-                       ret = -EINVAL;
-                       goto e_free;
-               }
+       /* Any pending NMI will happen here */
 
-               ret = -ENOMEM;
-               blob = kmalloc(params.len, GFP_KERNEL);
-               if (!blob)
-                       goto e_free;
+       if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
+               kvm_after_interrupt(&svm->vcpu);
 
-               data->address = __psp_pa(blob);
-               data->len = params.len;
-       }
+       sync_cr8_to_lapic(vcpu);
 
-cmd:
-       data->handle = sev->handle;
-       ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_MEASURE, data, &argp->error);
+       svm->next_rip = 0;
 
-       /*
-        * If we query the session length, FW responded with expected data.
-        */
-       if (!params.len)
-               goto done;
+       svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
 
-       if (ret)
-               goto e_free_blob;
+       /* if exit due to PF check for async PF */
+       if (svm->vmcb->control.exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR)
+               svm->vcpu.arch.apf.host_apf_reason = kvm_read_and_reset_pf_reason();
 
-       if (blob) {
-               if (copy_to_user(p, blob, params.len))
-                       ret = -EFAULT;
+       if (npt_enabled) {
+               vcpu->arch.regs_avail &= ~(1 << VCPU_EXREG_PDPTR);
+               vcpu->arch.regs_dirty &= ~(1 << VCPU_EXREG_PDPTR);
        }
 
-done:
-       params.len = data->len;
-       if (copy_to_user(measure, &params, sizeof(params)))
-               ret = -EFAULT;
-e_free_blob:
-       kfree(blob);
-e_free:
-       kfree(data);
-       return ret;
-}
-
-static int sev_launch_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
-{
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-       struct sev_data_launch_finish *data;
-       int ret;
-
-       if (!sev_guest(kvm))
-               return -ENOTTY;
-
-       data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
-       if (!data)
-               return -ENOMEM;
-
-       data->handle = sev->handle;
-       ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_FINISH, data, &argp->error);
+       /*
+        * We need to handle MC intercepts here before the vcpu has a chance to
+        * change the physical cpu
+        */
+       if (unlikely(svm->vmcb->control.exit_code ==
+                    SVM_EXIT_EXCP_BASE + MC_VECTOR))
+               svm_handle_mce(svm);
 
-       kfree(data);
-       return ret;
+       mark_all_clean(svm->vmcb);
 }
+STACK_FRAME_NON_STANDARD(svm_vcpu_run);
 
-static int sev_guest_status(struct kvm *kvm, struct kvm_sev_cmd *argp)
+static void svm_load_mmu_pgd(struct kvm_vcpu *vcpu, unsigned long root)
 {
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-       struct kvm_sev_guest_status params;
-       struct sev_data_guest_status *data;
-       int ret;
-
-       if (!sev_guest(kvm))
-               return -ENOTTY;
-
-       data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
-       if (!data)
-               return -ENOMEM;
+       struct vcpu_svm *svm = to_svm(vcpu);
+       bool update_guest_cr3 = true;
+       unsigned long cr3;
 
-       data->handle = sev->handle;
-       ret = sev_issue_cmd(kvm, SEV_CMD_GUEST_STATUS, data, &argp->error);
-       if (ret)
-               goto e_free;
+       cr3 = __sme_set(root);
+       if (npt_enabled) {
+               svm->vmcb->control.nested_cr3 = cr3;
+               mark_dirty(svm->vmcb, VMCB_NPT);
 
-       params.policy = data->policy;
-       params.state = data->state;
-       params.handle = data->handle;
+               /* Loading L2's CR3 is handled by enter_svm_guest_mode.  */
+               if (is_guest_mode(vcpu))
+                       update_guest_cr3 = false;
+               else if (test_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail))
+                       cr3 = vcpu->arch.cr3;
+               else /* CR3 is already up-to-date.  */
+                       update_guest_cr3 = false;
+       }
 
-       if (copy_to_user((void __user *)(uintptr_t)argp->data, &params, sizeof(params)))
-               ret = -EFAULT;
-e_free:
-       kfree(data);
-       return ret;
+       if (update_guest_cr3) {
+               svm->vmcb->save.cr3 = cr3;
+               mark_dirty(svm->vmcb, VMCB_CR);
+       }
 }
 
-static int __sev_issue_dbg_cmd(struct kvm *kvm, unsigned long src,
-                              unsigned long dst, int size,
-                              int *error, bool enc)
+static int is_disabled(void)
 {
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-       struct sev_data_dbg *data;
-       int ret;
-
-       data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
-       if (!data)
-               return -ENOMEM;
+       u64 vm_cr;
 
-       data->handle = sev->handle;
-       data->dst_addr = dst;
-       data->src_addr = src;
-       data->len = size;
+       rdmsrl(MSR_VM_CR, vm_cr);
+       if (vm_cr & (1 << SVM_VM_CR_SVM_DISABLE))
+               return 1;
 
-       ret = sev_issue_cmd(kvm,
-                           enc ? SEV_CMD_DBG_ENCRYPT : SEV_CMD_DBG_DECRYPT,
-                           data, error);
-       kfree(data);
-       return ret;
+       return 0;
 }
 
-static int __sev_dbg_decrypt(struct kvm *kvm, unsigned long src_paddr,
-                            unsigned long dst_paddr, int sz, int *err)
+static void
+svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
 {
-       int offset;
-
        /*
-        * Its safe to read more than we are asked, caller should ensure that
-        * destination has enough space.
+        * Patch in the VMMCALL instruction:
         */
-       src_paddr = round_down(src_paddr, 16);
-       offset = src_paddr & 15;
-       sz = round_up(sz + offset, 16);
-
-       return __sev_issue_dbg_cmd(kvm, src_paddr, dst_paddr, sz, err, false);
+       hypercall[0] = 0x0f;
+       hypercall[1] = 0x01;
+       hypercall[2] = 0xd9;
 }
 
-static int __sev_dbg_decrypt_user(struct kvm *kvm, unsigned long paddr,
-                                 unsigned long __user dst_uaddr,
-                                 unsigned long dst_paddr,
-                                 int size, int *err)
+static int __init svm_check_processor_compat(void)
 {
-       struct page *tpage = NULL;
-       int ret, offset;
-
-       /* if inputs are not 16-byte then use intermediate buffer */
-       if (!IS_ALIGNED(dst_paddr, 16) ||
-           !IS_ALIGNED(paddr,     16) ||
-           !IS_ALIGNED(size,      16)) {
-               tpage = (void *)alloc_page(GFP_KERNEL);
-               if (!tpage)
-                       return -ENOMEM;
-
-               dst_paddr = __sme_page_pa(tpage);
-       }
+       return 0;
+}
 
-       ret = __sev_dbg_decrypt(kvm, paddr, dst_paddr, size, err);
-       if (ret)
-               goto e_free;
+static bool svm_cpu_has_accelerated_tpr(void)
+{
+       return false;
+}
 
-       if (tpage) {
-               offset = paddr & 15;
-               if (copy_to_user((void __user *)(uintptr_t)dst_uaddr,
-                                page_address(tpage) + offset, size))
-                       ret = -EFAULT;
+static bool svm_has_emulated_msr(int index)
+{
+       switch (index) {
+       case MSR_IA32_MCG_EXT_CTL:
+       case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC:
+               return false;
+       default:
+               break;
        }
 
-e_free:
-       if (tpage)
-               __free_page(tpage);
+       return true;
+}
 
-       return ret;
+static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
+{
+       return 0;
 }
 
-static int __sev_dbg_encrypt_user(struct kvm *kvm, unsigned long paddr,
-                                 unsigned long __user vaddr,
-                                 unsigned long dst_paddr,
-                                 unsigned long __user dst_vaddr,
-                                 int size, int *error)
+static void svm_cpuid_update(struct kvm_vcpu *vcpu)
 {
-       struct page *src_tpage = NULL;
-       struct page *dst_tpage = NULL;
-       int ret, len = size;
+       struct vcpu_svm *svm = to_svm(vcpu);
 
-       /* If source buffer is not aligned then use an intermediate buffer */
-       if (!IS_ALIGNED(vaddr, 16)) {
-               src_tpage = alloc_page(GFP_KERNEL);
-               if (!src_tpage)
-                       return -ENOMEM;
+       vcpu->arch.xsaves_enabled = guest_cpuid_has(vcpu, X86_FEATURE_XSAVE) &&
+                                   boot_cpu_has(X86_FEATURE_XSAVE) &&
+                                   boot_cpu_has(X86_FEATURE_XSAVES);
 
-               if (copy_from_user(page_address(src_tpage),
-                               (void __user *)(uintptr_t)vaddr, size)) {
-                       __free_page(src_tpage);
-                       return -EFAULT;
-               }
+       /* Update nrips enabled cache */
+       svm->nrips_enabled = kvm_cpu_cap_has(X86_FEATURE_NRIPS) &&
+                            guest_cpuid_has(&svm->vcpu, X86_FEATURE_NRIPS);
 
-               paddr = __sme_page_pa(src_tpage);
-       }
+       if (!kvm_vcpu_apicv_active(vcpu))
+               return;
+
+       /*
+        * AVIC does not work with an x2APIC mode guest. If the X2APIC feature
+        * is exposed to the guest, disable AVIC.
+        */
+       if (guest_cpuid_has(vcpu, X86_FEATURE_X2APIC))
+               kvm_request_apicv_update(vcpu->kvm, false,
+                                        APICV_INHIBIT_REASON_X2APIC);
 
        /*
-        *  If destination buffer or length is not aligned then do read-modify-write:
-        *   - decrypt destination in an intermediate buffer
-        *   - copy the source buffer in an intermediate buffer
-        *   - use the intermediate buffer as source buffer
+        * Currently, AVIC does not work with nested virtualization.
+        * So, we disable AVIC when cpuid for SVM is set in the L1 guest.
         */
-       if (!IS_ALIGNED(dst_vaddr, 16) || !IS_ALIGNED(size, 16)) {
-               int dst_offset;
+       if (nested && guest_cpuid_has(vcpu, X86_FEATURE_SVM))
+               kvm_request_apicv_update(vcpu->kvm, false,
+                                        APICV_INHIBIT_REASON_NESTED);
+}
 
-               dst_tpage = alloc_page(GFP_KERNEL);
-               if (!dst_tpage) {
-                       ret = -ENOMEM;
-                       goto e_free;
-               }
+static bool svm_has_wbinvd_exit(void)
+{
+       return true;
+}
 
-               ret = __sev_dbg_decrypt(kvm, dst_paddr,
-                                       __sme_page_pa(dst_tpage), size, error);
-               if (ret)
-                       goto e_free;
+#define PRE_EX(exit)  { .exit_code = (exit), \
+                       .stage = X86_ICPT_PRE_EXCEPT, }
+#define POST_EX(exit) { .exit_code = (exit), \
+                       .stage = X86_ICPT_POST_EXCEPT, }
+#define POST_MEM(exit) { .exit_code = (exit), \
+                       .stage = X86_ICPT_POST_MEMACCESS, }
 
-               /*
-                *  If source is kernel buffer then use memcpy() otherwise
-                *  copy_from_user().
-                */
-               dst_offset = dst_paddr & 15;
+static const struct __x86_intercept {
+       u32 exit_code;
+       enum x86_intercept_stage stage;
+} x86_intercept_map[] = {
+       [x86_intercept_cr_read]         = POST_EX(SVM_EXIT_READ_CR0),
+       [x86_intercept_cr_write]        = POST_EX(SVM_EXIT_WRITE_CR0),
+       [x86_intercept_clts]            = POST_EX(SVM_EXIT_WRITE_CR0),
+       [x86_intercept_lmsw]            = POST_EX(SVM_EXIT_WRITE_CR0),
+       [x86_intercept_smsw]            = POST_EX(SVM_EXIT_READ_CR0),
+       [x86_intercept_dr_read]         = POST_EX(SVM_EXIT_READ_DR0),
+       [x86_intercept_dr_write]        = POST_EX(SVM_EXIT_WRITE_DR0),
+       [x86_intercept_sldt]            = POST_EX(SVM_EXIT_LDTR_READ),
+       [x86_intercept_str]             = POST_EX(SVM_EXIT_TR_READ),
+       [x86_intercept_lldt]            = POST_EX(SVM_EXIT_LDTR_WRITE),
+       [x86_intercept_ltr]             = POST_EX(SVM_EXIT_TR_WRITE),
+       [x86_intercept_sgdt]            = POST_EX(SVM_EXIT_GDTR_READ),
+       [x86_intercept_sidt]            = POST_EX(SVM_EXIT_IDTR_READ),
+       [x86_intercept_lgdt]            = POST_EX(SVM_EXIT_GDTR_WRITE),
+       [x86_intercept_lidt]            = POST_EX(SVM_EXIT_IDTR_WRITE),
+       [x86_intercept_vmrun]           = POST_EX(SVM_EXIT_VMRUN),
+       [x86_intercept_vmmcall]         = POST_EX(SVM_EXIT_VMMCALL),
+       [x86_intercept_vmload]          = POST_EX(SVM_EXIT_VMLOAD),
+       [x86_intercept_vmsave]          = POST_EX(SVM_EXIT_VMSAVE),
+       [x86_intercept_stgi]            = POST_EX(SVM_EXIT_STGI),
+       [x86_intercept_clgi]            = POST_EX(SVM_EXIT_CLGI),
+       [x86_intercept_skinit]          = POST_EX(SVM_EXIT_SKINIT),
+       [x86_intercept_invlpga]         = POST_EX(SVM_EXIT_INVLPGA),
+       [x86_intercept_rdtscp]          = POST_EX(SVM_EXIT_RDTSCP),
+       [x86_intercept_monitor]         = POST_MEM(SVM_EXIT_MONITOR),
+       [x86_intercept_mwait]           = POST_EX(SVM_EXIT_MWAIT),
+       [x86_intercept_invlpg]          = POST_EX(SVM_EXIT_INVLPG),
+       [x86_intercept_invd]            = POST_EX(SVM_EXIT_INVD),
+       [x86_intercept_wbinvd]          = POST_EX(SVM_EXIT_WBINVD),
+       [x86_intercept_wrmsr]           = POST_EX(SVM_EXIT_MSR),
+       [x86_intercept_rdtsc]           = POST_EX(SVM_EXIT_RDTSC),
+       [x86_intercept_rdmsr]           = POST_EX(SVM_EXIT_MSR),
+       [x86_intercept_rdpmc]           = POST_EX(SVM_EXIT_RDPMC),
+       [x86_intercept_cpuid]           = PRE_EX(SVM_EXIT_CPUID),
+       [x86_intercept_rsm]             = PRE_EX(SVM_EXIT_RSM),
+       [x86_intercept_pause]           = PRE_EX(SVM_EXIT_PAUSE),
+       [x86_intercept_pushf]           = PRE_EX(SVM_EXIT_PUSHF),
+       [x86_intercept_popf]            = PRE_EX(SVM_EXIT_POPF),
+       [x86_intercept_intn]            = PRE_EX(SVM_EXIT_SWINT),
+       [x86_intercept_iret]            = PRE_EX(SVM_EXIT_IRET),
+       [x86_intercept_icebp]           = PRE_EX(SVM_EXIT_ICEBP),
+       [x86_intercept_hlt]             = POST_EX(SVM_EXIT_HLT),
+       [x86_intercept_in]              = POST_EX(SVM_EXIT_IOIO),
+       [x86_intercept_ins]             = POST_EX(SVM_EXIT_IOIO),
+       [x86_intercept_out]             = POST_EX(SVM_EXIT_IOIO),
+       [x86_intercept_outs]            = POST_EX(SVM_EXIT_IOIO),
+       [x86_intercept_xsetbv]          = PRE_EX(SVM_EXIT_XSETBV),
+};
 
-               if (src_tpage)
-                       memcpy(page_address(dst_tpage) + dst_offset,
-                              page_address(src_tpage), size);
-               else {
-                       if (copy_from_user(page_address(dst_tpage) + dst_offset,
-                                          (void __user *)(uintptr_t)vaddr, size)) {
-                               ret = -EFAULT;
-                               goto e_free;
-                       }
-               }
+#undef PRE_EX
+#undef POST_EX
+#undef POST_MEM
 
-               paddr = __sme_page_pa(dst_tpage);
-               dst_paddr = round_down(dst_paddr, 16);
-               len = round_up(size, 16);
-       }
+static int svm_check_intercept(struct kvm_vcpu *vcpu,
+                              struct x86_instruction_info *info,
+                              enum x86_intercept_stage stage,
+                              struct x86_exception *exception)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       int vmexit, ret = X86EMUL_CONTINUE;
+       struct __x86_intercept icpt_info;
+       struct vmcb *vmcb = svm->vmcb;
 
-       ret = __sev_issue_dbg_cmd(kvm, paddr, dst_paddr, len, error, true);
+       if (info->intercept >= ARRAY_SIZE(x86_intercept_map))
+               goto out;
 
-e_free:
-       if (src_tpage)
-               __free_page(src_tpage);
-       if (dst_tpage)
-               __free_page(dst_tpage);
-       return ret;
-}
+       icpt_info = x86_intercept_map[info->intercept];
 
-static int sev_dbg_crypt(struct kvm *kvm, struct kvm_sev_cmd *argp, bool dec)
-{
-       unsigned long vaddr, vaddr_end, next_vaddr;
-       unsigned long dst_vaddr;
-       struct page **src_p, **dst_p;
-       struct kvm_sev_dbg debug;
-       unsigned long n;
-       unsigned int size;
-       int ret;
+       if (stage != icpt_info.stage)
+               goto out;
 
-       if (!sev_guest(kvm))
-               return -ENOTTY;
+       switch (icpt_info.exit_code) {
+       case SVM_EXIT_READ_CR0:
+               if (info->intercept == x86_intercept_cr_read)
+                       icpt_info.exit_code += info->modrm_reg;
+               break;
+       case SVM_EXIT_WRITE_CR0: {
+               unsigned long cr0, val;
+               u64 intercept;
 
-       if (copy_from_user(&debug, (void __user *)(uintptr_t)argp->data, sizeof(debug)))
-               return -EFAULT;
+               if (info->intercept == x86_intercept_cr_write)
+                       icpt_info.exit_code += info->modrm_reg;
 
-       if (!debug.len || debug.src_uaddr + debug.len < debug.src_uaddr)
-               return -EINVAL;
-       if (!debug.dst_uaddr)
-               return -EINVAL;
+               if (icpt_info.exit_code != SVM_EXIT_WRITE_CR0 ||
+                   info->intercept == x86_intercept_clts)
+                       break;
 
-       vaddr = debug.src_uaddr;
-       size = debug.len;
-       vaddr_end = vaddr + size;
-       dst_vaddr = debug.dst_uaddr;
+               intercept = svm->nested.intercept;
 
-       for (; vaddr < vaddr_end; vaddr = next_vaddr) {
-               int len, s_off, d_off;
+               if (!(intercept & (1ULL << INTERCEPT_SELECTIVE_CR0)))
+                       break;
 
-               /* lock userspace source and destination page */
-               src_p = sev_pin_memory(kvm, vaddr & PAGE_MASK, PAGE_SIZE, &n, 0);
-               if (!src_p)
-                       return -EFAULT;
+               cr0 = vcpu->arch.cr0 & ~SVM_CR0_SELECTIVE_MASK;
+               val = info->src_val  & ~SVM_CR0_SELECTIVE_MASK;
 
-               dst_p = sev_pin_memory(kvm, dst_vaddr & PAGE_MASK, PAGE_SIZE, &n, 1);
-               if (!dst_p) {
-                       sev_unpin_memory(kvm, src_p, n);
-                       return -EFAULT;
+               if (info->intercept == x86_intercept_lmsw) {
+                       cr0 &= 0xfUL;
+                       val &= 0xfUL;
+                       /* lmsw can't clear PE - catch this here */
+                       if (cr0 & X86_CR0_PE)
+                               val |= X86_CR0_PE;
                }
 
-               /*
-                * The DBG_{DE,EN}CRYPT commands will perform {dec,en}cryption of the
-                * memory content (i.e it will write the same memory region with C=1).
-                * It's possible that the cache may contain the data with C=0, i.e.,
-                * unencrypted so invalidate it first.
-                */
-               sev_clflush_pages(src_p, 1);
-               sev_clflush_pages(dst_p, 1);
+               if (cr0 ^ val)
+                       icpt_info.exit_code = SVM_EXIT_CR0_SEL_WRITE;
 
+               break;
+       }
+       case SVM_EXIT_READ_DR0:
+       case SVM_EXIT_WRITE_DR0:
+               icpt_info.exit_code += info->modrm_reg;
+               break;
+       case SVM_EXIT_MSR:
+               if (info->intercept == x86_intercept_wrmsr)
+                       vmcb->control.exit_info_1 = 1;
+               else
+                       vmcb->control.exit_info_1 = 0;
+               break;
+       case SVM_EXIT_PAUSE:
                /*
-                * Since user buffer may not be page aligned, calculate the
-                * offset within the page.
+                * We get this for NOP only, but pause
+                * is rep not, check this here
                 */
-               s_off = vaddr & ~PAGE_MASK;
-               d_off = dst_vaddr & ~PAGE_MASK;
-               len = min_t(size_t, (PAGE_SIZE - s_off), size);
-
-               if (dec)
-                       ret = __sev_dbg_decrypt_user(kvm,
-                                                    __sme_page_pa(src_p[0]) + s_off,
-                                                    dst_vaddr,
-                                                    __sme_page_pa(dst_p[0]) + d_off,
-                                                    len, &argp->error);
-               else
-                       ret = __sev_dbg_encrypt_user(kvm,
-                                                    __sme_page_pa(src_p[0]) + s_off,
-                                                    vaddr,
-                                                    __sme_page_pa(dst_p[0]) + d_off,
-                                                    dst_vaddr,
-                                                    len, &argp->error);
-
-               sev_unpin_memory(kvm, src_p, n);
-               sev_unpin_memory(kvm, dst_p, n);
-
-               if (ret)
-                       goto err;
-
-               next_vaddr = vaddr + len;
-               dst_vaddr = dst_vaddr + len;
-               size -= len;
-       }
-err:
-       return ret;
-}
+               if (info->rep_prefix != REPE_PREFIX)
+                       goto out;
+               break;
+       case SVM_EXIT_IOIO: {
+               u64 exit_info;
+               u32 bytes;
 
-static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp)
-{
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-       struct sev_data_launch_secret *data;
-       struct kvm_sev_launch_secret params;
-       struct page **pages;
-       void *blob, *hdr;
-       unsigned long n;
-       int ret, offset;
+               if (info->intercept == x86_intercept_in ||
+                   info->intercept == x86_intercept_ins) {
+                       exit_info = ((info->src_val & 0xffff) << 16) |
+                               SVM_IOIO_TYPE_MASK;
+                       bytes = info->dst_bytes;
+               } else {
+                       exit_info = (info->dst_val & 0xffff) << 16;
+                       bytes = info->src_bytes;
+               }
 
-       if (!sev_guest(kvm))
-               return -ENOTTY;
+               if (info->intercept == x86_intercept_outs ||
+                   info->intercept == x86_intercept_ins)
+                       exit_info |= SVM_IOIO_STR_MASK;
 
-       if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
-               return -EFAULT;
+               if (info->rep_prefix)
+                       exit_info |= SVM_IOIO_REP_MASK;
 
-       pages = sev_pin_memory(kvm, params.guest_uaddr, params.guest_len, &n, 1);
-       if (!pages)
-               return -ENOMEM;
+               bytes = min(bytes, 4u);
 
-       /*
-        * The secret must be copied into contiguous memory region, lets verify
-        * that userspace memory pages are contiguous before we issue command.
-        */
-       if (get_num_contig_pages(0, pages, n) != n) {
-               ret = -EINVAL;
-               goto e_unpin_memory;
-       }
+               exit_info |= bytes << SVM_IOIO_SIZE_SHIFT;
 
-       ret = -ENOMEM;
-       data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
-       if (!data)
-               goto e_unpin_memory;
+               exit_info |= (u32)info->ad_bytes << (SVM_IOIO_ASIZE_SHIFT - 1);
 
-       offset = params.guest_uaddr & (PAGE_SIZE - 1);
-       data->guest_address = __sme_page_pa(pages[0]) + offset;
-       data->guest_len = params.guest_len;
+               vmcb->control.exit_info_1 = exit_info;
+               vmcb->control.exit_info_2 = info->next_rip;
 
-       blob = psp_copy_user_blob(params.trans_uaddr, params.trans_len);
-       if (IS_ERR(blob)) {
-               ret = PTR_ERR(blob);
-               goto e_free;
+               break;
        }
-
-       data->trans_address = __psp_pa(blob);
-       data->trans_len = params.trans_len;
-
-       hdr = psp_copy_user_blob(params.hdr_uaddr, params.hdr_len);
-       if (IS_ERR(hdr)) {
-               ret = PTR_ERR(hdr);
-               goto e_free_blob;
+       default:
+               break;
        }
-       data->hdr_address = __psp_pa(hdr);
-       data->hdr_len = params.hdr_len;
 
-       data->handle = sev->handle;
-       ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_SECRET, data, &argp->error);
+       /* TODO: Advertise NRIPS to guest hypervisor unconditionally */
+       if (static_cpu_has(X86_FEATURE_NRIPS))
+               vmcb->control.next_rip  = info->next_rip;
+       vmcb->control.exit_code = icpt_info.exit_code;
+       vmexit = nested_svm_exit_handled(svm);
 
-       kfree(hdr);
+       ret = (vmexit == NESTED_EXIT_DONE) ? X86EMUL_INTERCEPTED
+                                          : X86EMUL_CONTINUE;
 
-e_free_blob:
-       kfree(blob);
-e_free:
-       kfree(data);
-e_unpin_memory:
-       sev_unpin_memory(kvm, pages, n);
+out:
        return ret;
 }
 
-static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
+static void svm_handle_exit_irqoff(struct kvm_vcpu *vcpu,
+       enum exit_fastpath_completion *exit_fastpath)
 {
-       struct kvm_sev_cmd sev_cmd;
-       int r;
+       if (!is_guest_mode(vcpu) &&
+           to_svm(vcpu)->vmcb->control.exit_code == SVM_EXIT_MSR &&
+           to_svm(vcpu)->vmcb->control.exit_info_1)
+               *exit_fastpath = handle_fastpath_set_msr_irqoff(vcpu);
+}
 
-       if (!svm_sev_enabled())
-               return -ENOTTY;
+static void svm_sched_in(struct kvm_vcpu *vcpu, int cpu)
+{
+       if (pause_filter_thresh)
+               shrink_ple_window(vcpu);
+}
 
-       if (!argp)
-               return 0;
+static void svm_setup_mce(struct kvm_vcpu *vcpu)
+{
+       /* [63:9] are reserved. */
+       vcpu->arch.mcg_cap &= 0x1ff;
+}
 
-       if (copy_from_user(&sev_cmd, argp, sizeof(struct kvm_sev_cmd)))
-               return -EFAULT;
+static int svm_smi_allowed(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
 
-       mutex_lock(&kvm->lock);
+       /* Per APM Vol.2 15.22.2 "Response to SMI" */
+       if (!gif_set(svm))
+               return 0;
 
-       switch (sev_cmd.id) {
-       case KVM_SEV_INIT:
-               r = sev_guest_init(kvm, &sev_cmd);
-               break;
-       case KVM_SEV_LAUNCH_START:
-               r = sev_launch_start(kvm, &sev_cmd);
-               break;
-       case KVM_SEV_LAUNCH_UPDATE_DATA:
-               r = sev_launch_update_data(kvm, &sev_cmd);
-               break;
-       case KVM_SEV_LAUNCH_MEASURE:
-               r = sev_launch_measure(kvm, &sev_cmd);
-               break;
-       case KVM_SEV_LAUNCH_FINISH:
-               r = sev_launch_finish(kvm, &sev_cmd);
-               break;
-       case KVM_SEV_GUEST_STATUS:
-               r = sev_guest_status(kvm, &sev_cmd);
-               break;
-       case KVM_SEV_DBG_DECRYPT:
-               r = sev_dbg_crypt(kvm, &sev_cmd, true);
-               break;
-       case KVM_SEV_DBG_ENCRYPT:
-               r = sev_dbg_crypt(kvm, &sev_cmd, false);
-               break;
-       case KVM_SEV_LAUNCH_SECRET:
-               r = sev_launch_secret(kvm, &sev_cmd);
-               break;
-       default:
-               r = -EINVAL;
-               goto out;
+       if (is_guest_mode(&svm->vcpu) &&
+           svm->nested.intercept & (1ULL << INTERCEPT_SMI)) {
+               /* TODO: Might need to set exit_info_1 and exit_info_2 here */
+               svm->vmcb->control.exit_code = SVM_EXIT_SMI;
+               svm->nested.exit_required = true;
+               return 0;
        }
 
-       if (copy_to_user(argp, &sev_cmd, sizeof(struct kvm_sev_cmd)))
-               r = -EFAULT;
-
-out:
-       mutex_unlock(&kvm->lock);
-       return r;
+       return 1;
 }
 
-static int svm_register_enc_region(struct kvm *kvm,
-                                  struct kvm_enc_region *range)
+static int svm_pre_enter_smm(struct kvm_vcpu *vcpu, char *smstate)
 {
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-       struct enc_region *region;
-       int ret = 0;
-
-       if (!sev_guest(kvm))
-               return -ENOTTY;
+       struct vcpu_svm *svm = to_svm(vcpu);
+       int ret;
 
-       if (range->addr > ULONG_MAX || range->size > ULONG_MAX)
-               return -EINVAL;
+       if (is_guest_mode(vcpu)) {
+               /* FED8h - SVM Guest */
+               put_smstate(u64, smstate, 0x7ed8, 1);
+               /* FEE0h - SVM Guest VMCB Physical Address */
+               put_smstate(u64, smstate, 0x7ee0, svm->nested.vmcb);
 
-       region = kzalloc(sizeof(*region), GFP_KERNEL_ACCOUNT);
-       if (!region)
-               return -ENOMEM;
+               svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX];
+               svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP];
+               svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP];
 
-       region->pages = sev_pin_memory(kvm, range->addr, range->size, &region->npages, 1);
-       if (!region->pages) {
-               ret = -ENOMEM;
-               goto e_free;
+               ret = nested_svm_vmexit(svm);
+               if (ret)
+                       return ret;
        }
-
-       /*
-        * The guest may change the memory encryption attribute from C=0 -> C=1
-        * or vice versa for this memory range. Lets make sure caches are
-        * flushed to ensure that guest data gets written into memory with
-        * correct C-bit.
-        */
-       sev_clflush_pages(region->pages, region->npages);
-
-       region->uaddr = range->addr;
-       region->size = range->size;
-
-       mutex_lock(&kvm->lock);
-       list_add_tail(&region->list, &sev->regions_list);
-       mutex_unlock(&kvm->lock);
-
-       return ret;
-
-e_free:
-       kfree(region);
-       return ret;
+       return 0;
 }
 
-static struct enc_region *
-find_enc_region(struct kvm *kvm, struct kvm_enc_region *range)
+static int svm_pre_leave_smm(struct kvm_vcpu *vcpu, const char *smstate)
 {
-       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
-       struct list_head *head = &sev->regions_list;
-       struct enc_region *i;
+       struct vcpu_svm *svm = to_svm(vcpu);
+       struct vmcb *nested_vmcb;
+       struct kvm_host_map map;
+       u64 guest;
+       u64 vmcb;
 
-       list_for_each_entry(i, head, list) {
-               if (i->uaddr == range->addr &&
-                   i->size == range->size)
-                       return i;
-       }
+       guest = GET_SMSTATE(u64, smstate, 0x7ed8);
+       vmcb = GET_SMSTATE(u64, smstate, 0x7ee0);
 
-       return NULL;
+       if (guest) {
+               if (kvm_vcpu_map(&svm->vcpu, gpa_to_gfn(vmcb), &map) == -EINVAL)
+                       return 1;
+               nested_vmcb = map.hva;
+               enter_svm_guest_mode(svm, vmcb, nested_vmcb, &map);
+       }
+       return 0;
 }
 
-
-static int svm_unregister_enc_region(struct kvm *kvm,
-                                    struct kvm_enc_region *range)
+static int enable_smi_window(struct kvm_vcpu *vcpu)
 {
-       struct enc_region *region;
-       int ret;
-
-       mutex_lock(&kvm->lock);
-
-       if (!sev_guest(kvm)) {
-               ret = -ENOTTY;
-               goto failed;
-       }
+       struct vcpu_svm *svm = to_svm(vcpu);
 
-       region = find_enc_region(kvm, range);
-       if (!region) {
-               ret = -EINVAL;
-               goto failed;
+       if (!gif_set(svm)) {
+               if (vgif_enabled(svm))
+                       set_intercept(svm, INTERCEPT_STGI);
+               /* STGI will cause a vm exit */
+               return 1;
        }
-
-       /*
-        * Ensure that all guest tagged cache entries are flushed before
-        * releasing the pages back to the system for use. CLFLUSH will
-        * not do this, so issue a WBINVD.
-        */
-       wbinvd_on_all_cpus();
-
-       __unregister_enc_region_locked(kvm, region);
-
-       mutex_unlock(&kvm->lock);
        return 0;
-
-failed:
-       mutex_unlock(&kvm->lock);
-       return ret;
 }
 
 static bool svm_need_emulation_on_page_fault(struct kvm_vcpu *vcpu)
@@ -7347,21 +3880,22 @@ static bool svm_apic_init_signal_blocked(struct kvm_vcpu *vcpu)
                   (svm->vmcb->control.intercept & (1ULL << INTERCEPT_INIT));
 }
 
-static bool svm_check_apicv_inhibit_reasons(ulong bit)
+static void svm_vm_destroy(struct kvm *kvm)
 {
-       ulong supported = BIT(APICV_INHIBIT_REASON_DISABLE) |
-                         BIT(APICV_INHIBIT_REASON_HYPERV) |
-                         BIT(APICV_INHIBIT_REASON_NESTED) |
-                         BIT(APICV_INHIBIT_REASON_IRQWIN) |
-                         BIT(APICV_INHIBIT_REASON_PIT_REINJ) |
-                         BIT(APICV_INHIBIT_REASON_X2APIC);
-
-       return supported & BIT(bit);
+       avic_vm_destroy(kvm);
+       sev_vm_destroy(kvm);
 }
 
-static void svm_pre_update_apicv_exec_ctrl(struct kvm *kvm, bool activate)
+static int svm_vm_init(struct kvm *kvm)
 {
-       avic_update_access_page(kvm, activate);
+       if (avic) {
+               int ret = avic_vm_init(kvm);
+               if (ret)
+                       return ret;
+       }
+
+       kvm_apicv_init(kvm, avic);
+       return 0;
 }
 
 static struct kvm_x86_ops svm_x86_ops __initdata = {
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
new file mode 100644 (file)
index 0000000..df3474f
--- /dev/null
@@ -0,0 +1,491 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * AMD SVM support
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
+ *
+ * Authors:
+ *   Yaniv Kamay  <yaniv@qumranet.com>
+ *   Avi Kivity   <avi@qumranet.com>
+ */
+
+#ifndef __SVM_SVM_H
+#define __SVM_SVM_H
+
+#include <linux/kvm_types.h>
+#include <linux/kvm_host.h>
+
+#include <asm/svm.h>
+
+static const u32 host_save_user_msrs[] = {
+#ifdef CONFIG_X86_64
+       MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
+       MSR_FS_BASE,
+#endif
+       MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
+       MSR_TSC_AUX,
+};
+
+#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
+
+#define MSRPM_OFFSETS  16
+extern u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
+extern bool npt_enabled;
+
+enum {
+       VMCB_INTERCEPTS, /* Intercept vectors, TSC offset,
+                           pause filter count */
+       VMCB_PERM_MAP,   /* IOPM Base and MSRPM Base */
+       VMCB_ASID,       /* ASID */
+       VMCB_INTR,       /* int_ctl, int_vector */
+       VMCB_NPT,        /* npt_en, nCR3, gPAT */
+       VMCB_CR,         /* CR0, CR3, CR4, EFER */
+       VMCB_DR,         /* DR6, DR7 */
+       VMCB_DT,         /* GDT, IDT */
+       VMCB_SEG,        /* CS, DS, SS, ES, CPL */
+       VMCB_CR2,        /* CR2 only */
+       VMCB_LBR,        /* DBGCTL, BR_FROM, BR_TO, LAST_EX_FROM, LAST_EX_TO */
+       VMCB_AVIC,       /* AVIC APIC_BAR, AVIC APIC_BACKING_PAGE,
+                         * AVIC PHYSICAL_TABLE pointer,
+                         * AVIC LOGICAL_TABLE pointer
+                         */
+       VMCB_DIRTY_MAX,
+};
+
+/* TPR and CR2 are always written before VMRUN */
+#define VMCB_ALWAYS_DIRTY_MASK ((1U << VMCB_INTR) | (1U << VMCB_CR2))
+
+struct kvm_sev_info {
+       bool active;            /* SEV enabled guest */
+       unsigned int asid;      /* ASID used for this guest */
+       unsigned int handle;    /* SEV firmware handle */
+       int fd;                 /* SEV device fd */
+       unsigned long pages_locked; /* Number of pages locked */
+       struct list_head regions_list;  /* List of registered regions */
+};
+
+struct kvm_svm {
+       struct kvm kvm;
+
+       /* Struct members for AVIC */
+       u32 avic_vm_id;
+       struct page *avic_logical_id_table_page;
+       struct page *avic_physical_id_table_page;
+       struct hlist_node hnode;
+
+       struct kvm_sev_info sev_info;
+};
+
+struct kvm_vcpu;
+
+struct nested_state {
+       struct vmcb *hsave;
+       u64 hsave_msr;
+       u64 vm_cr_msr;
+       u64 vmcb;
+
+       /* These are the merged vectors */
+       u32 *msrpm;
+
+       /* gpa pointers to the real vectors */
+       u64 vmcb_msrpm;
+       u64 vmcb_iopm;
+
+       /* A VMEXIT is required but not yet emulated */
+       bool exit_required;
+
+       /* cache for intercepts of the guest */
+       u32 intercept_cr;
+       u32 intercept_dr;
+       u32 intercept_exceptions;
+       u64 intercept;
+
+       /* Nested Paging related state */
+       u64 nested_cr3;
+};
+
+struct vcpu_svm {
+       struct kvm_vcpu vcpu;
+       struct vmcb *vmcb;
+       unsigned long vmcb_pa;
+       struct svm_cpu_data *svm_data;
+       uint64_t asid_generation;
+       uint64_t sysenter_esp;
+       uint64_t sysenter_eip;
+       uint64_t tsc_aux;
+
+       u64 msr_decfg;
+
+       u64 next_rip;
+
+       u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS];
+       struct {
+               u16 fs;
+               u16 gs;
+               u16 ldt;
+               u64 gs_base;
+       } host;
+
+       u64 spec_ctrl;
+       /*
+        * Contains guest-controlled bits of VIRT_SPEC_CTRL, which will be
+        * translated into the appropriate L2_CFG bits on the host to
+        * perform speculative control.
+        */
+       u64 virt_spec_ctrl;
+
+       u32 *msrpm;
+
+       ulong nmi_iret_rip;
+
+       struct nested_state nested;
+
+       bool nmi_singlestep;
+       u64 nmi_singlestep_guest_rflags;
+
+       unsigned int3_injected;
+       unsigned long int3_rip;
+
+       /* cached guest cpuid flags for faster access */
+       bool nrips_enabled      : 1;
+
+       u32 ldr_reg;
+       u32 dfr_reg;
+       struct page *avic_backing_page;
+       u64 *avic_physical_id_cache;
+       bool avic_is_running;
+
+       /*
+        * Per-vcpu list of struct amd_svm_iommu_ir:
+        * This is used mainly to store interrupt remapping information used
+        * when update the vcpu affinity. This avoids the need to scan for
+        * IRTE and try to match ga_tag in the IOMMU driver.
+        */
+       struct list_head ir_list;
+       spinlock_t ir_list_lock;
+
+       /* which host CPU was used for running this vcpu */
+       unsigned int last_cpu;
+};
+
+struct svm_cpu_data {
+       int cpu;
+
+       u64 asid_generation;
+       u32 max_asid;
+       u32 next_asid;
+       u32 min_asid;
+       struct kvm_ldttss_desc *tss_desc;
+
+       struct page *save_area;
+       struct vmcb *current_vmcb;
+
+       /* index = sev_asid, value = vmcb pointer */
+       struct vmcb **sev_vmcbs;
+};
+
+DECLARE_PER_CPU(struct svm_cpu_data *, svm_data);
+
+void recalc_intercepts(struct vcpu_svm *svm);
+
+static inline struct kvm_svm *to_kvm_svm(struct kvm *kvm)
+{
+       return container_of(kvm, struct kvm_svm, kvm);
+}
+
+static inline void mark_all_dirty(struct vmcb *vmcb)
+{
+       vmcb->control.clean = 0;
+}
+
+static inline void mark_all_clean(struct vmcb *vmcb)
+{
+       vmcb->control.clean = ((1 << VMCB_DIRTY_MAX) - 1)
+                              & ~VMCB_ALWAYS_DIRTY_MASK;
+}
+
+static inline void mark_dirty(struct vmcb *vmcb, int bit)
+{
+       vmcb->control.clean &= ~(1 << bit);
+}
+
+static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
+{
+       return container_of(vcpu, struct vcpu_svm, vcpu);
+}
+
+static inline struct vmcb *get_host_vmcb(struct vcpu_svm *svm)
+{
+       if (is_guest_mode(&svm->vcpu))
+               return svm->nested.hsave;
+       else
+               return svm->vmcb;
+}
+
+static inline void set_cr_intercept(struct vcpu_svm *svm, int bit)
+{
+       struct vmcb *vmcb = get_host_vmcb(svm);
+
+       vmcb->control.intercept_cr |= (1U << bit);
+
+       recalc_intercepts(svm);
+}
+
+static inline void clr_cr_intercept(struct vcpu_svm *svm, int bit)
+{
+       struct vmcb *vmcb = get_host_vmcb(svm);
+
+       vmcb->control.intercept_cr &= ~(1U << bit);
+
+       recalc_intercepts(svm);
+}
+
+static inline bool is_cr_intercept(struct vcpu_svm *svm, int bit)
+{
+       struct vmcb *vmcb = get_host_vmcb(svm);
+
+       return vmcb->control.intercept_cr & (1U << bit);
+}
+
+static inline void set_dr_intercepts(struct vcpu_svm *svm)
+{
+       struct vmcb *vmcb = get_host_vmcb(svm);
+
+       vmcb->control.intercept_dr = (1 << INTERCEPT_DR0_READ)
+               | (1 << INTERCEPT_DR1_READ)
+               | (1 << INTERCEPT_DR2_READ)
+               | (1 << INTERCEPT_DR3_READ)
+               | (1 << INTERCEPT_DR4_READ)
+               | (1 << INTERCEPT_DR5_READ)
+               | (1 << INTERCEPT_DR6_READ)
+               | (1 << INTERCEPT_DR7_READ)
+               | (1 << INTERCEPT_DR0_WRITE)
+               | (1 << INTERCEPT_DR1_WRITE)
+               | (1 << INTERCEPT_DR2_WRITE)
+               | (1 << INTERCEPT_DR3_WRITE)
+               | (1 << INTERCEPT_DR4_WRITE)
+               | (1 << INTERCEPT_DR5_WRITE)
+               | (1 << INTERCEPT_DR6_WRITE)
+               | (1 << INTERCEPT_DR7_WRITE);
+
+       recalc_intercepts(svm);
+}
+
+static inline void clr_dr_intercepts(struct vcpu_svm *svm)
+{
+       struct vmcb *vmcb = get_host_vmcb(svm);
+
+       vmcb->control.intercept_dr = 0;
+
+       recalc_intercepts(svm);
+}
+
+static inline void set_exception_intercept(struct vcpu_svm *svm, int bit)
+{
+       struct vmcb *vmcb = get_host_vmcb(svm);
+
+       vmcb->control.intercept_exceptions |= (1U << bit);
+
+       recalc_intercepts(svm);
+}
+
+static inline void clr_exception_intercept(struct vcpu_svm *svm, int bit)
+{
+       struct vmcb *vmcb = get_host_vmcb(svm);
+
+       vmcb->control.intercept_exceptions &= ~(1U << bit);
+
+       recalc_intercepts(svm);
+}
+
+static inline void set_intercept(struct vcpu_svm *svm, int bit)
+{
+       struct vmcb *vmcb = get_host_vmcb(svm);
+
+       vmcb->control.intercept |= (1ULL << bit);
+
+       recalc_intercepts(svm);
+}
+
+static inline void clr_intercept(struct vcpu_svm *svm, int bit)
+{
+       struct vmcb *vmcb = get_host_vmcb(svm);
+
+       vmcb->control.intercept &= ~(1ULL << bit);
+
+       recalc_intercepts(svm);
+}
+
+static inline bool is_intercept(struct vcpu_svm *svm, int bit)
+{
+       return (svm->vmcb->control.intercept & (1ULL << bit)) != 0;
+}
+
+static inline bool vgif_enabled(struct vcpu_svm *svm)
+{
+       return !!(svm->vmcb->control.int_ctl & V_GIF_ENABLE_MASK);
+}
+
+static inline void enable_gif(struct vcpu_svm *svm)
+{
+       if (vgif_enabled(svm))
+               svm->vmcb->control.int_ctl |= V_GIF_MASK;
+       else
+               svm->vcpu.arch.hflags |= HF_GIF_MASK;
+}
+
+static inline void disable_gif(struct vcpu_svm *svm)
+{
+       if (vgif_enabled(svm))
+               svm->vmcb->control.int_ctl &= ~V_GIF_MASK;
+       else
+               svm->vcpu.arch.hflags &= ~HF_GIF_MASK;
+}
+
+static inline bool gif_set(struct vcpu_svm *svm)
+{
+       if (vgif_enabled(svm))
+               return !!(svm->vmcb->control.int_ctl & V_GIF_MASK);
+       else
+               return !!(svm->vcpu.arch.hflags & HF_GIF_MASK);
+}
+
+/* svm.c */
+#define MSR_INVALID                    0xffffffffU
+
+u32 svm_msrpm_offset(u32 msr);
+void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer);
+void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
+int svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
+void svm_flush_tlb(struct kvm_vcpu *vcpu, bool invalidate_gpa);
+void disable_nmi_singlestep(struct vcpu_svm *svm);
+
+/* nested.c */
+
+#define NESTED_EXIT_HOST       0       /* Exit handled on host level */
+#define NESTED_EXIT_DONE       1       /* Exit caused nested vmexit  */
+#define NESTED_EXIT_CONTINUE   2       /* Further checks needed      */
+
+/* This function returns true if it is save to enable the nmi window */
+static inline bool nested_svm_nmi(struct vcpu_svm *svm)
+{
+       if (!is_guest_mode(&svm->vcpu))
+               return true;
+
+       if (!(svm->nested.intercept & (1ULL << INTERCEPT_NMI)))
+               return true;
+
+       svm->vmcb->control.exit_code = SVM_EXIT_NMI;
+       svm->nested.exit_required = true;
+
+       return false;
+}
+
+static inline bool svm_nested_virtualize_tpr(struct kvm_vcpu *vcpu)
+{
+       return is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK);
+}
+
+void enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb_gpa,
+                         struct vmcb *nested_vmcb, struct kvm_host_map *map);
+int nested_svm_vmrun(struct vcpu_svm *svm);
+void nested_svm_vmloadsave(struct vmcb *from_vmcb, struct vmcb *to_vmcb);
+int nested_svm_vmexit(struct vcpu_svm *svm);
+int nested_svm_exit_handled(struct vcpu_svm *svm);
+int nested_svm_check_permissions(struct vcpu_svm *svm);
+int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
+                              bool has_error_code, u32 error_code);
+int svm_check_nested_events(struct kvm_vcpu *vcpu);
+int nested_svm_exit_special(struct vcpu_svm *svm);
+
+/* avic.c */
+
+#define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK   (0xFF)
+#define AVIC_LOGICAL_ID_ENTRY_VALID_BIT                        31
+#define AVIC_LOGICAL_ID_ENTRY_VALID_MASK               (1 << 31)
+
+#define AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK   (0xFFULL)
+#define AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK       (0xFFFFFFFFFFULL << 12)
+#define AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK         (1ULL << 62)
+#define AVIC_PHYSICAL_ID_ENTRY_VALID_MASK              (1ULL << 63)
+
+#define VMCB_AVIC_APIC_BAR_MASK                0xFFFFFFFFFF000ULL
+
+extern int avic;
+
+static inline void avic_update_vapic_bar(struct vcpu_svm *svm, u64 data)
+{
+       svm->vmcb->control.avic_vapic_bar = data & VMCB_AVIC_APIC_BAR_MASK;
+       mark_dirty(svm->vmcb, VMCB_AVIC);
+}
+
+static inline bool avic_vcpu_is_running(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       u64 *entry = svm->avic_physical_id_cache;
+
+       if (!entry)
+               return false;
+
+       return (READ_ONCE(*entry) & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK);
+}
+
+int avic_ga_log_notifier(u32 ga_tag);
+void avic_vm_destroy(struct kvm *kvm);
+int avic_vm_init(struct kvm *kvm);
+void avic_init_vmcb(struct vcpu_svm *svm);
+void svm_toggle_avic_for_irq_window(struct kvm_vcpu *vcpu, bool activate);
+int avic_incomplete_ipi_interception(struct vcpu_svm *svm);
+int avic_unaccelerated_access_interception(struct vcpu_svm *svm);
+int avic_init_vcpu(struct vcpu_svm *svm);
+void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
+void avic_vcpu_put(struct kvm_vcpu *vcpu);
+void avic_post_state_restore(struct kvm_vcpu *vcpu);
+void svm_set_virtual_apic_mode(struct kvm_vcpu *vcpu);
+void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu);
+bool svm_check_apicv_inhibit_reasons(ulong bit);
+void svm_pre_update_apicv_exec_ctrl(struct kvm *kvm, bool activate);
+void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
+void svm_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr);
+void svm_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr);
+int svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec);
+bool svm_dy_apicv_has_pending_interrupt(struct kvm_vcpu *vcpu);
+int svm_update_pi_irte(struct kvm *kvm, unsigned int host_irq,
+                      uint32_t guest_irq, bool set);
+void svm_vcpu_blocking(struct kvm_vcpu *vcpu);
+void svm_vcpu_unblocking(struct kvm_vcpu *vcpu);
+
+/* sev.c */
+
+extern unsigned int max_sev_asid;
+
+static inline bool sev_guest(struct kvm *kvm)
+{
+#ifdef CONFIG_KVM_AMD_SEV
+       struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+
+       return sev->active;
+#else
+       return false;
+#endif
+}
+
+static inline bool svm_sev_enabled(void)
+{
+       return IS_ENABLED(CONFIG_KVM_AMD_SEV) ? max_sev_asid : 0;
+}
+
+void sev_vm_destroy(struct kvm *kvm);
+int svm_mem_enc_op(struct kvm *kvm, void __user *argp);
+int svm_register_enc_region(struct kvm *kvm,
+                           struct kvm_enc_region *range);
+int svm_unregister_enc_region(struct kvm *kvm,
+                             struct kvm_enc_region *range);
+void pre_sev_run(struct vcpu_svm *svm, int cpu);
+int __init sev_hardware_setup(void);
+void sev_hardware_teardown(void);
+
+#endif
diff --git a/arch/x86/kvm/svm/vmenter.S b/arch/x86/kvm/svm/vmenter.S
new file mode 100644 (file)
index 0000000..fa1af90
--- /dev/null
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/linkage.h>
+#include <asm/asm.h>
+#include <asm/bitsperlong.h>
+#include <asm/kvm_vcpu_regs.h>
+
+#define WORD_SIZE (BITS_PER_LONG / 8)
+
+/* Intentionally omit RAX as it's context switched by hardware */
+#define VCPU_RCX       __VCPU_REGS_RCX * WORD_SIZE
+#define VCPU_RDX       __VCPU_REGS_RDX * WORD_SIZE
+#define VCPU_RBX       __VCPU_REGS_RBX * WORD_SIZE
+/* Intentionally omit RSP as it's context switched by hardware */
+#define VCPU_RBP       __VCPU_REGS_RBP * WORD_SIZE
+#define VCPU_RSI       __VCPU_REGS_RSI * WORD_SIZE
+#define VCPU_RDI       __VCPU_REGS_RDI * WORD_SIZE
+
+#ifdef CONFIG_X86_64
+#define VCPU_R8                __VCPU_REGS_R8  * WORD_SIZE
+#define VCPU_R9                __VCPU_REGS_R9  * WORD_SIZE
+#define VCPU_R10       __VCPU_REGS_R10 * WORD_SIZE
+#define VCPU_R11       __VCPU_REGS_R11 * WORD_SIZE
+#define VCPU_R12       __VCPU_REGS_R12 * WORD_SIZE
+#define VCPU_R13       __VCPU_REGS_R13 * WORD_SIZE
+#define VCPU_R14       __VCPU_REGS_R14 * WORD_SIZE
+#define VCPU_R15       __VCPU_REGS_R15 * WORD_SIZE
+#endif
+
+       .text
+
+/**
+ * __svm_vcpu_run - Run a vCPU via a transition to SVM guest mode
+ * @vmcb_pa:   unsigned long
+ * @regs:      unsigned long * (to guest registers)
+ */
+SYM_FUNC_START(__svm_vcpu_run)
+       push %_ASM_BP
+       mov  %_ASM_SP, %_ASM_BP
+#ifdef CONFIG_X86_64
+       push %r15
+       push %r14
+       push %r13
+       push %r12
+#else
+       push %edi
+       push %esi
+#endif
+       push %_ASM_BX
+
+       /* Save @regs. */
+       push %_ASM_ARG2
+
+       /* Save @vmcb. */
+       push %_ASM_ARG1
+
+       /* Move @regs to RAX. */
+       mov %_ASM_ARG2, %_ASM_AX
+
+       /* Load guest registers. */
+       mov VCPU_RCX(%_ASM_AX), %_ASM_CX
+       mov VCPU_RDX(%_ASM_AX), %_ASM_DX
+       mov VCPU_RBX(%_ASM_AX), %_ASM_BX
+       mov VCPU_RBP(%_ASM_AX), %_ASM_BP
+       mov VCPU_RSI(%_ASM_AX), %_ASM_SI
+       mov VCPU_RDI(%_ASM_AX), %_ASM_DI
+#ifdef CONFIG_X86_64
+       mov VCPU_R8 (%_ASM_AX),  %r8
+       mov VCPU_R9 (%_ASM_AX),  %r9
+       mov VCPU_R10(%_ASM_AX), %r10
+       mov VCPU_R11(%_ASM_AX), %r11
+       mov VCPU_R12(%_ASM_AX), %r12
+       mov VCPU_R13(%_ASM_AX), %r13
+       mov VCPU_R14(%_ASM_AX), %r14
+       mov VCPU_R15(%_ASM_AX), %r15
+#endif
+
+       /* "POP" @vmcb to RAX. */
+       pop %_ASM_AX
+
+       /* Enter guest mode */
+1:     vmload %_ASM_AX
+       jmp 3f
+2:     cmpb $0, kvm_rebooting
+       jne 3f
+       ud2
+       _ASM_EXTABLE(1b, 2b)
+
+3:     vmrun %_ASM_AX
+       jmp 5f
+4:     cmpb $0, kvm_rebooting
+       jne 5f
+       ud2
+       _ASM_EXTABLE(3b, 4b)
+
+5:     vmsave %_ASM_AX
+       jmp 7f
+6:     cmpb $0, kvm_rebooting
+       jne 7f
+       ud2
+       _ASM_EXTABLE(5b, 6b)
+7:
+       /* "POP" @regs to RAX. */
+       pop %_ASM_AX
+
+       /* Save all guest registers.  */
+       mov %_ASM_CX,   VCPU_RCX(%_ASM_AX)
+       mov %_ASM_DX,   VCPU_RDX(%_ASM_AX)
+       mov %_ASM_BX,   VCPU_RBX(%_ASM_AX)
+       mov %_ASM_BP,   VCPU_RBP(%_ASM_AX)
+       mov %_ASM_SI,   VCPU_RSI(%_ASM_AX)
+       mov %_ASM_DI,   VCPU_RDI(%_ASM_AX)
+#ifdef CONFIG_X86_64
+       mov %r8,  VCPU_R8 (%_ASM_AX)
+       mov %r9,  VCPU_R9 (%_ASM_AX)
+       mov %r10, VCPU_R10(%_ASM_AX)
+       mov %r11, VCPU_R11(%_ASM_AX)
+       mov %r12, VCPU_R12(%_ASM_AX)
+       mov %r13, VCPU_R13(%_ASM_AX)
+       mov %r14, VCPU_R14(%_ASM_AX)
+       mov %r15, VCPU_R15(%_ASM_AX)
+#endif
+
+       /*
+        * Clear all general purpose registers except RSP and RAX to prevent
+        * speculative use of the guest's values, even those that are reloaded
+        * via the stack.  In theory, an L1 cache miss when restoring registers
+        * could lead to speculative execution with the guest's values.
+        * Zeroing XORs are dirt cheap, i.e. the extra paranoia is essentially
+        * free.  RSP and RAX are exempt as they are restored by hardware
+        * during VM-Exit.
+        */
+       xor %ecx, %ecx
+       xor %edx, %edx
+       xor %ebx, %ebx
+       xor %ebp, %ebp
+       xor %esi, %esi
+       xor %edi, %edi
+#ifdef CONFIG_X86_64
+       xor %r8d,  %r8d
+       xor %r9d,  %r9d
+       xor %r10d, %r10d
+       xor %r11d, %r11d
+       xor %r12d, %r12d
+       xor %r13d, %r13d
+       xor %r14d, %r14d
+       xor %r15d, %r15d
+#endif
+
+       pop %_ASM_BX
+
+#ifdef CONFIG_X86_64
+       pop %r12
+       pop %r13
+       pop %r14
+       pop %r15
+#else
+       pop %esi
+       pop %edi
+#endif
+       pop %_ASM_BP
+       ret
+SYM_FUNC_END(__svm_vcpu_run)
index de23230..cbc9ea2 100644 (file)
@@ -3645,7 +3645,8 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu)
         * Clear the MTF state. If a higher priority VM-exit is delivered first,
         * this state is discarded.
         */
-       vmx->nested.mtf_pending = false;
+       if (!block_nested_events)
+               vmx->nested.mtf_pending = false;
 
        if (lapic_in_kernel(vcpu) &&
                test_bit(KVM_APIC_INIT, &apic->pending_events)) {
index 9651ba3..87f3f24 100644 (file)
@@ -58,12 +58,8 @@ SYM_FUNC_START(vmx_vmenter)
        ret
 4:     ud2
 
-       .pushsection .fixup, "ax"
-5:     jmp 3b
-       .popsection
-
-       _ASM_EXTABLE(1b, 5b)
-       _ASM_EXTABLE(2b, 5b)
+       _ASM_EXTABLE(1b, 3b)
+       _ASM_EXTABLE(2b, 3b)
 
 SYM_FUNC_END(vmx_vmenter)
 
index 91749f1..8305097 100644 (file)
@@ -2261,10 +2261,6 @@ static int hardware_enable(void)
            !hv_get_vp_assist_page(cpu))
                return -EFAULT;
 
-       INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu));
-       INIT_LIST_HEAD(&per_cpu(blocked_vcpu_on_cpu, cpu));
-       spin_lock_init(&per_cpu(blocked_vcpu_on_cpu_lock, cpu));
-
        r = kvm_cpu_vmxon(phys_addr);
        if (r)
                return r;
@@ -4592,6 +4588,26 @@ static int handle_machine_check(struct kvm_vcpu *vcpu)
        return 1;
 }
 
+/*
+ * If the host has split lock detection disabled, then #AC is
+ * unconditionally injected into the guest, which is the pre split lock
+ * detection behaviour.
+ *
+ * If the host has split lock detection enabled then #AC is
+ * only injected into the guest when:
+ *  - Guest CPL == 3 (user mode)
+ *  - Guest has #AC detection enabled in CR0
+ *  - Guest EFLAGS has AC bit set
+ */
+static inline bool guest_inject_ac(struct kvm_vcpu *vcpu)
+{
+       if (!boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT))
+               return true;
+
+       return vmx_get_cpl(vcpu) == 3 && kvm_read_cr0_bits(vcpu, X86_CR0_AM) &&
+              (kvm_get_rflags(vcpu) & X86_EFLAGS_AC);
+}
+
 static int handle_exception_nmi(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -4657,9 +4673,6 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
                return handle_rmode_exception(vcpu, ex_no, error_code);
 
        switch (ex_no) {
-       case AC_VECTOR:
-               kvm_queue_exception_e(vcpu, AC_VECTOR, error_code);
-               return 1;
        case DB_VECTOR:
                dr6 = vmcs_readl(EXIT_QUALIFICATION);
                if (!(vcpu->guest_debug &
@@ -4688,6 +4701,20 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
                kvm_run->debug.arch.pc = vmcs_readl(GUEST_CS_BASE) + rip;
                kvm_run->debug.arch.exception = ex_no;
                break;
+       case AC_VECTOR:
+               if (guest_inject_ac(vcpu)) {
+                       kvm_queue_exception_e(vcpu, AC_VECTOR, error_code);
+                       return 1;
+               }
+
+               /*
+                * Handle split lock. Depending on detection mode this will
+                * either warn and disable split lock detection for this
+                * task or force SIGBUS on it.
+                */
+               if (handle_guest_split_lock(kvm_rip_read(vcpu)))
+                       return 1;
+               fallthrough;
        default:
                kvm_run->exit_reason = KVM_EXIT_EXCEPTION;
                kvm_run->ex.exception = ex_no;
@@ -8044,7 +8071,7 @@ module_exit(vmx_exit);
 
 static int __init vmx_init(void)
 {
-       int r;
+       int r, cpu;
 
 #if IS_ENABLED(CONFIG_HYPERV)
        /*
@@ -8098,6 +8125,12 @@ static int __init vmx_init(void)
                return r;
        }
 
+       for_each_possible_cpu(cpu) {
+               INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu));
+               INIT_LIST_HEAD(&per_cpu(blocked_vcpu_on_cpu, cpu));
+               spin_lock_init(&per_cpu(blocked_vcpu_on_cpu_lock, cpu));
+       }
+
 #ifdef CONFIG_KEXEC_CORE
        rcu_assign_pointer(crash_vmclear_loaded_vmcss,
                           crash_vmclear_local_loaded_vmcss);
index b8124b5..3bf2eca 100644 (file)
@@ -1586,7 +1586,8 @@ static int handle_fastpath_set_x2apic_icr_irqoff(struct kvm_vcpu *vcpu, u64 data
 
        if (((data & APIC_SHORT_MASK) == APIC_DEST_NOSHORT) &&
                ((data & APIC_DEST_MASK) == APIC_DEST_PHYSICAL) &&
-               ((data & APIC_MODE_MASK) == APIC_DM_FIXED)) {
+               ((data & APIC_MODE_MASK) == APIC_DM_FIXED) &&
+               ((u32)(data >> 32) != X2APIC_BROADCAST)) {
 
                data &= ~(1 << 12);
                kvm_apic_send_ipi(vcpu->arch.apic, (u32)data, (u32)(data >> 32));
@@ -5838,6 +5839,7 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
 {
        struct kvm_host_map map;
        struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
+       u64 page_line_mask;
        gpa_t gpa;
        char *kaddr;
        bool exchanged;
@@ -5852,7 +5854,16 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
            (gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
                goto emul_write;
 
-       if (((gpa + bytes - 1) & PAGE_MASK) != (gpa & PAGE_MASK))
+       /*
+        * Emulate the atomic as a straight write to avoid #AC if SLD is
+        * enabled in the host and the access splits a cache line.
+        */
+       if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT))
+               page_line_mask = ~(cache_line_size() - 1);
+       else
+               page_line_mask = PAGE_MASK;
+
+       if (((gpa + bytes - 1) & page_line_mask) != (gpa & page_line_mask))
                goto emul_write;
 
        if (kvm_vcpu_map(vcpu, gpa_to_gfn(gpa), &map))
index e7bb483..1bba16c 100644 (file)
@@ -467,7 +467,7 @@ bool pfn_range_is_mapped(unsigned long start_pfn, unsigned long end_pfn)
  * the physical memory. To access them they are temporarily mapped.
  */
 unsigned long __ref init_memory_mapping(unsigned long start,
-                                              unsigned long end)
+                                       unsigned long end, pgprot_t prot)
 {
        struct map_range mr[NR_RANGE_MR];
        unsigned long ret = 0;
@@ -481,7 +481,8 @@ unsigned long __ref init_memory_mapping(unsigned long start,
 
        for (i = 0; i < nr_range; i++)
                ret = kernel_physical_mapping_init(mr[i].start, mr[i].end,
-                                                  mr[i].page_size_mask);
+                                                  mr[i].page_size_mask,
+                                                  prot);
 
        add_pfn_range_mapped(start >> PAGE_SHIFT, ret >> PAGE_SHIFT);
 
@@ -521,7 +522,7 @@ static unsigned long __init init_range_memory_mapping(
                 */
                can_use_brk_pgt = max(start, (u64)pgt_buf_end<<PAGE_SHIFT) >=
                                    min(end, (u64)pgt_buf_top<<PAGE_SHIFT);
-               init_memory_mapping(start, end);
+               init_memory_mapping(start, end, PAGE_KERNEL);
                mapped_ram_size += end - start;
                can_use_brk_pgt = true;
        }
@@ -661,7 +662,7 @@ void __init init_mem_mapping(void)
 #endif
 
        /* the ISA range is always mapped regardless of memory holes */
-       init_memory_mapping(0, ISA_END_ADDRESS);
+       init_memory_mapping(0, ISA_END_ADDRESS, PAGE_KERNEL);
 
        /* Init the trampoline, possibly with KASLR memory offset */
        init_trampoline();
index de73992..4222a01 100644 (file)
@@ -257,7 +257,8 @@ static inline int __is_kernel_text(unsigned long addr)
 unsigned long __init
 kernel_physical_mapping_init(unsigned long start,
                             unsigned long end,
-                            unsigned long page_size_mask)
+                            unsigned long page_size_mask,
+                            pgprot_t prot)
 {
        int use_pse = page_size_mask == (1<<PG_LEVEL_2M);
        unsigned long last_map_addr = end;
@@ -819,12 +820,24 @@ void __init mem_init(void)
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 int arch_add_memory(int nid, u64 start, u64 size,
-                       struct mhp_restrictions *restrictions)
+                   struct mhp_params *params)
 {
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
+       int ret;
 
-       return __add_pages(nid, start_pfn, nr_pages, restrictions);
+       /*
+        * The page tables were already mapped at boot so if the caller
+        * requests a different mapping type then we must change all the
+        * pages with __set_memory_prot().
+        */
+       if (params->pgprot.pgprot != PAGE_KERNEL.pgprot) {
+               ret = __set_memory_prot(start, nr_pages, params->pgprot);
+               if (ret)
+                       return ret;
+       }
+
+       return __add_pages(nid, start_pfn, nr_pages, params);
 }
 
 void arch_remove_memory(int nid, u64 start, u64 size,
index 0a14711..3b289c2 100644 (file)
@@ -585,7 +585,7 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long paddr, unsigned long paddr_end,
  */
 static unsigned long __meminit
 phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end,
-             unsigned long page_size_mask, bool init)
+             unsigned long page_size_mask, pgprot_t _prot, bool init)
 {
        unsigned long pages = 0, paddr_next;
        unsigned long paddr_last = paddr_end;
@@ -595,7 +595,7 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end,
        for (; i < PTRS_PER_PUD; i++, paddr = paddr_next) {
                pud_t *pud;
                pmd_t *pmd;
-               pgprot_t prot = PAGE_KERNEL;
+               pgprot_t prot = _prot;
 
                vaddr = (unsigned long)__va(paddr);
                pud = pud_page + pud_index(vaddr);
@@ -644,9 +644,12 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end,
                if (page_size_mask & (1<<PG_LEVEL_1G)) {
                        pages++;
                        spin_lock(&init_mm.page_table_lock);
+
+                       prot = __pgprot(pgprot_val(prot) | __PAGE_KERNEL_LARGE);
+
                        set_pte_init((pte_t *)pud,
                                     pfn_pte((paddr & PUD_MASK) >> PAGE_SHIFT,
-                                            PAGE_KERNEL_LARGE),
+                                            prot),
                                     init);
                        spin_unlock(&init_mm.page_table_lock);
                        paddr_last = paddr_next;
@@ -669,7 +672,7 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end,
 
 static unsigned long __meminit
 phys_p4d_init(p4d_t *p4d_page, unsigned long paddr, unsigned long paddr_end,
-             unsigned long page_size_mask, bool init)
+             unsigned long page_size_mask, pgprot_t prot, bool init)
 {
        unsigned long vaddr, vaddr_end, vaddr_next, paddr_next, paddr_last;
 
@@ -679,7 +682,7 @@ phys_p4d_init(p4d_t *p4d_page, unsigned long paddr, unsigned long paddr_end,
 
        if (!pgtable_l5_enabled())
                return phys_pud_init((pud_t *) p4d_page, paddr, paddr_end,
-                                    page_size_mask, init);
+                                    page_size_mask, prot, init);
 
        for (; vaddr < vaddr_end; vaddr = vaddr_next) {
                p4d_t *p4d = p4d_page + p4d_index(vaddr);
@@ -702,13 +705,13 @@ phys_p4d_init(p4d_t *p4d_page, unsigned long paddr, unsigned long paddr_end,
                if (!p4d_none(*p4d)) {
                        pud = pud_offset(p4d, 0);
                        paddr_last = phys_pud_init(pud, paddr, __pa(vaddr_end),
-                                       page_size_mask, init);
+                                       page_size_mask, prot, init);
                        continue;
                }
 
                pud = alloc_low_page();
                paddr_last = phys_pud_init(pud, paddr, __pa(vaddr_end),
-                                          page_size_mask, init);
+                                          page_size_mask, prot, init);
 
                spin_lock(&init_mm.page_table_lock);
                p4d_populate_init(&init_mm, p4d, pud, init);
@@ -722,7 +725,7 @@ static unsigned long __meminit
 __kernel_physical_mapping_init(unsigned long paddr_start,
                               unsigned long paddr_end,
                               unsigned long page_size_mask,
-                              bool init)
+                              pgprot_t prot, bool init)
 {
        bool pgd_changed = false;
        unsigned long vaddr, vaddr_start, vaddr_end, vaddr_next, paddr_last;
@@ -743,13 +746,13 @@ __kernel_physical_mapping_init(unsigned long paddr_start,
                        paddr_last = phys_p4d_init(p4d, __pa(vaddr),
                                                   __pa(vaddr_end),
                                                   page_size_mask,
-                                                  init);
+                                                  prot, init);
                        continue;
                }
 
                p4d = alloc_low_page();
                paddr_last = phys_p4d_init(p4d, __pa(vaddr), __pa(vaddr_end),
-                                          page_size_mask, init);
+                                          page_size_mask, prot, init);
 
                spin_lock(&init_mm.page_table_lock);
                if (pgtable_l5_enabled())
@@ -778,10 +781,10 @@ __kernel_physical_mapping_init(unsigned long paddr_start,
 unsigned long __meminit
 kernel_physical_mapping_init(unsigned long paddr_start,
                             unsigned long paddr_end,
-                            unsigned long page_size_mask)
+                            unsigned long page_size_mask, pgprot_t prot)
 {
        return __kernel_physical_mapping_init(paddr_start, paddr_end,
-                                             page_size_mask, true);
+                                             page_size_mask, prot, true);
 }
 
 /*
@@ -796,7 +799,8 @@ kernel_physical_mapping_change(unsigned long paddr_start,
                               unsigned long page_size_mask)
 {
        return __kernel_physical_mapping_init(paddr_start, paddr_end,
-                                             page_size_mask, false);
+                                             page_size_mask, PAGE_KERNEL,
+                                             false);
 }
 
 #ifndef CONFIG_NUMA
@@ -843,11 +847,11 @@ static void update_end_of_memory_vars(u64 start, u64 size)
 }
 
 int add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
-                               struct mhp_restrictions *restrictions)
+             struct mhp_params *params)
 {
        int ret;
 
-       ret = __add_pages(nid, start_pfn, nr_pages, restrictions);
+       ret = __add_pages(nid, start_pfn, nr_pages, params);
        WARN_ON_ONCE(ret);
 
        /* update max_pfn, max_low_pfn and high_memory */
@@ -858,14 +862,14 @@ int add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
 }
 
 int arch_add_memory(int nid, u64 start, u64 size,
-                       struct mhp_restrictions *restrictions)
+                   struct mhp_params *params)
 {
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
 
-       init_memory_mapping(start, start + size);
+       init_memory_mapping(start, start + size, params->pgprot);
 
-       return add_pages(nid, start_pfn, nr_pages, restrictions);
+       return add_pages(nid, start_pfn, nr_pages, params);
 }
 
 #define PAGE_INUSE 0xFD
index eeae142..3f37b5c 100644 (file)
@@ -12,7 +12,8 @@ void early_ioremap_page_table_range_init(void);
 
 unsigned long kernel_physical_mapping_init(unsigned long start,
                                             unsigned long end,
-                                            unsigned long page_size_mask);
+                                            unsigned long page_size_mask,
+                                            pgprot_t prot);
 unsigned long kernel_physical_mapping_change(unsigned long start,
                                             unsigned long end,
                                             unsigned long page_size_mask);
index 99f7a68..59ba008 100644 (file)
@@ -25,11 +25,8 @@ nodemask_t numa_nodes_parsed __initdata;
 struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
 EXPORT_SYMBOL(node_data);
 
-static struct numa_meminfo numa_meminfo
-#ifndef CONFIG_MEMORY_HOTPLUG
-__initdata
-#endif
-;
+static struct numa_meminfo numa_meminfo __initdata_or_meminfo;
+static struct numa_meminfo numa_reserved_meminfo __initdata_or_meminfo;
 
 static int numa_distance_cnt;
 static u8 *numa_distance;
@@ -169,6 +166,19 @@ void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi)
 }
 
 /**
+ * numa_move_tail_memblk - Move a numa_memblk from one numa_meminfo to another
+ * @dst: numa_meminfo to append block to
+ * @idx: Index of memblk to remove
+ * @src: numa_meminfo to remove memblk from
+ */
+static void __init numa_move_tail_memblk(struct numa_meminfo *dst, int idx,
+                                        struct numa_meminfo *src)
+{
+       dst->blk[dst->nr_blks++] = src->blk[idx];
+       numa_remove_memblk_from(idx, src);
+}
+
+/**
  * numa_add_memblk - Add one numa_memblk to numa_meminfo
  * @nid: NUMA node ID of the new memblk
  * @start: Start address of the new memblk
@@ -237,14 +247,19 @@ int __init numa_cleanup_meminfo(struct numa_meminfo *mi)
        for (i = 0; i < mi->nr_blks; i++) {
                struct numa_memblk *bi = &mi->blk[i];
 
-               /* make sure all blocks are inside the limits */
+               /* move / save reserved memory ranges */
+               if (!memblock_overlaps_region(&memblock.memory,
+                                       bi->start, bi->end - bi->start)) {
+                       numa_move_tail_memblk(&numa_reserved_meminfo, i--, mi);
+                       continue;
+               }
+
+               /* make sure all non-reserved blocks are inside the limits */
                bi->start = max(bi->start, low);
                bi->end = min(bi->end, high);
 
-               /* and there's no empty or non-exist block */
-               if (bi->start >= bi->end ||
-                   !memblock_overlaps_region(&memblock.memory,
-                       bi->start, bi->end - bi->start))
+               /* and there's no empty block */
+               if (bi->start >= bi->end)
                        numa_remove_memblk_from(i--, mi);
        }
 
@@ -881,16 +896,38 @@ EXPORT_SYMBOL(cpumask_of_node);
 
 #endif /* !CONFIG_DEBUG_PER_CPU_MAPS */
 
-#ifdef CONFIG_MEMORY_HOTPLUG
-int memory_add_physaddr_to_nid(u64 start)
+#ifdef CONFIG_NUMA_KEEP_MEMINFO
+static int meminfo_to_nid(struct numa_meminfo *mi, u64 start)
 {
-       struct numa_meminfo *mi = &numa_meminfo;
-       int nid = mi->blk[0].nid;
        int i;
 
        for (i = 0; i < mi->nr_blks; i++)
                if (mi->blk[i].start <= start && mi->blk[i].end > start)
-                       nid = mi->blk[i].nid;
+                       return mi->blk[i].nid;
+       return NUMA_NO_NODE;
+}
+
+int phys_to_target_node(phys_addr_t start)
+{
+       int nid = meminfo_to_nid(&numa_meminfo, start);
+
+       /*
+        * Prefer online nodes, but if reserved memory might be
+        * hot-added continue the search with reserved ranges.
+        */
+       if (nid != NUMA_NO_NODE)
+               return nid;
+
+       return meminfo_to_nid(&numa_reserved_meminfo, start);
+}
+EXPORT_SYMBOL_GPL(phys_to_target_node);
+
+int memory_add_physaddr_to_nid(u64 start)
+{
+       int nid = meminfo_to_nid(&numa_meminfo, start);
+
+       if (nid == NUMA_NO_NODE)
+               nid = numa_meminfo.blk[0].nid;
        return nid;
 }
 EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
index 6d54240..59eca6a 100644 (file)
@@ -1795,6 +1795,19 @@ static inline int cpa_clear_pages_array(struct page **pages, int numpages,
                CPA_PAGES_ARRAY, pages);
 }
 
+/*
+ * _set_memory_prot is an internal helper for callers that have been passed
+ * a pgprot_t value from upper layers and a reservation has already been taken.
+ * If you want to set the pgprot to a specific page protocol, use the
+ * set_memory_xx() functions.
+ */
+int __set_memory_prot(unsigned long addr, int numpages, pgprot_t prot)
+{
+       return change_page_attr_set_clr(&addr, numpages, prot,
+                                       __pgprot(~pgprot_val(prot)), 0, 0,
+                                       NULL);
+}
+
 int _set_memory_uc(unsigned long addr, int numpages)
 {
        /*
index c6f84c0..8873ed1 100644 (file)
@@ -63,7 +63,7 @@ int __execute_only_pkey(struct mm_struct *mm)
 static inline bool vma_is_pkey_exec_only(struct vm_area_struct *vma)
 {
        /* Do this check first since the vm_flags should be hot */
-       if ((vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)) != VM_EXEC)
+       if ((vma->vm_flags & VM_ACCESS_FLAGS) != VM_EXEC)
                return false;
        if (vma_pkey(vma) != vma->vm_mm->context.execute_only_pkey)
                return false;
index 211bb93..c5e393f 100644 (file)
@@ -202,7 +202,7 @@ virt_to_phys_or_null_size(void *va, unsigned long size)
 
 int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
 {
-       unsigned long pfn, text, pf;
+       unsigned long pfn, text, pf, rodata;
        struct page *page;
        unsigned npages;
        pgd_t *pgd = efi_mm.pgd;
@@ -256,7 +256,7 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
 
        efi_scratch.phys_stack = page_to_phys(page + 1); /* stack grows down */
 
-       npages = (__end_rodata_aligned - _text) >> PAGE_SHIFT;
+       npages = (_etext - _text) >> PAGE_SHIFT;
        text = __pa(_text);
        pfn = text >> PAGE_SHIFT;
 
@@ -266,6 +266,14 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
                return 1;
        }
 
+       npages = (__end_rodata - __start_rodata) >> PAGE_SHIFT;
+       rodata = __pa(__start_rodata);
+       pfn = rodata >> PAGE_SHIFT;
+       if (kernel_map_pages_in_pgd(pgd, pfn, rodata, npages, pf)) {
+               pr_err("Failed to map kernel rodata 1:1\n");
+               return 1;
+       }
+
        return 0;
 }
 
@@ -638,7 +646,7 @@ efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
        phys_vendor = virt_to_phys_or_null(vnd);
        phys_data = virt_to_phys_or_null_size(data, data_size);
 
-       if (!phys_name || !phys_data)
+       if (!phys_name || (data && !phys_data))
                status = EFI_INVALID_PARAMETER;
        else
                status = efi_thunk(set_variable, phys_name, phys_vendor,
@@ -669,7 +677,7 @@ efi_thunk_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
        phys_vendor = virt_to_phys_or_null(vnd);
        phys_data = virt_to_phys_or_null_size(data, data_size);
 
-       if (!phys_name || !phys_data)
+       if (!phys_name || (data && !phys_data))
                status = EFI_INVALID_PARAMETER;
        else
                status = efi_thunk(set_variable, phys_name, phys_vendor,
index 607f581..c60255d 100644 (file)
@@ -352,7 +352,8 @@ void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
        if (type == EFI_MEMORY_MAPPED_IO)
                return ioremap(phys_addr, size);
 
-       last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size);
+       last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size,
+                                          PAGE_KERNEL);
        if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size) {
                unsigned long top = last_map_pfn << PAGE_SHIFT;
                efi_ioremap(top, size - (top - phys_addr), type, attribute);
index 7c297e9..df7a389 100644 (file)
@@ -9,17 +9,11 @@
 
 #ifdef CONFIG_X86_32
 
-#define VM_DATA_DEFAULT_FLAGS \
-       (VM_READ | VM_WRITE | \
-       ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \
-                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_TSK_EXEC
 
 #else
 
-#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
-       VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-#define VM_STACK_DEFAULT_FLAGS (VM_GROWSDOWN | VM_READ | VM_WRITE | \
-       VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_STACK_DEFAULT_FLAGS (VM_GROWSDOWN | VM_DATA_FLAGS_EXEC)
 
 #endif
 #endif
index 33b0e20..1a2d8a5 100644 (file)
@@ -985,7 +985,7 @@ void xen_enable_syscall(void)
 #endif /* CONFIG_X86_64 */
 }
 
-void __init xen_pvmmu_arch_setup(void)
+static void __init xen_pvmmu_arch_setup(void)
 {
        HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
        HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
index 7d1c4fc..1ba601d 100644 (file)
@@ -38,7 +38,7 @@ SYM_CODE_START(startup_xen)
 #ifdef CONFIG_X86_64
        mov initial_stack(%rip), %rsp
 #else
-       mov pa(initial_stack), %esp
+       mov initial_stack, %esp
 #endif
 
 #ifdef CONFIG_X86_64
index de22942..3a9f1e8 100644 (file)
@@ -122,7 +122,7 @@ config XTENSA_VARIANT_CUSTOM_NAME
        help
          Provide the name of a custom Xtensa processor variant.
          This CORENAME selects arch/xtensa/variant/CORENAME.
-         Dont forget you have to select MMU if you have one.
+         Don't forget you have to select MMU if you have one.
 
 config XTENSA_VARIANT_NAME
        string
index efb91bf..1a14d38 100644 (file)
@@ -14,7 +14,6 @@ HOSTFLAGS     += -Iarch/$(ARCH)/boot/include
 
 BIG_ENDIAN     := $(shell echo __XTENSA_EB__ | $(CC) -E - | grep -v "\#")
 
-export ccflags-y
 export BIG_ENDIAN
 
 subdir-y       := lib
index f4771c2..37ce25e 100644 (file)
@@ -203,8 +203,5 @@ static inline unsigned long ___pa(unsigned long va)
 
 #endif /* __ASSEMBLY__ */
 
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
 #include <asm-generic/memory_model.h>
 #endif /* _XTENSA_PAGE_H */
index 27ac17c..8be0c05 100644 (file)
@@ -266,7 +266,6 @@ static inline void paging_init(void) { }
 static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITABLE; }
 static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
-static inline int pte_special(pte_t pte) { return 0; }
 
 static inline pte_t pte_wrprotect(pte_t pte)   
        { pte_val(pte) &= ~(_PAGE_WRITABLE | _PAGE_HW_WRITE); return pte; }
@@ -280,8 +279,6 @@ static inline pte_t pte_mkyoung(pte_t pte)
        { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkwrite(pte_t pte)
        { pte_val(pte) |= _PAGE_WRITABLE; return pte; }
-static inline pte_t pte_mkspecial(pte_t pte)
-       { return pte; }
 
 #define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) & ~_PAGE_CA_MASK))
 
index 83b244c..cd85a7a 100644 (file)
@@ -53,16 +53,12 @@ static void system_flush_invalidate_dcache_range(unsigned long start,
 #define IPI_IRQ        0
 
 static irqreturn_t ipi_interrupt(int irq, void *dev_id);
-static struct irqaction ipi_irqaction = {
-       .handler =      ipi_interrupt,
-       .flags =        IRQF_PERCPU,
-       .name =         "ipi",
-};
 
 void ipi_init(void)
 {
        unsigned irq = irq_create_mapping(NULL, IPI_IRQ);
-       setup_irq(irq, &ipi_irqaction);
+       if (request_irq(irq, ipi_interrupt, IRQF_PERCPU, "ipi", NULL))
+               pr_err("Failed to request irq %u (ipi)\n", irq);
 }
 
 static inline unsigned int get_core_count(void)
index 69db8c9..77971fe 100644 (file)
@@ -128,12 +128,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction timer_irqaction = {
-       .handler =      timer_interrupt,
-       .flags =        IRQF_TIMER,
-       .name =         "timer",
-};
-
 void local_timer_setup(unsigned cpu)
 {
        struct ccount_timer *timer = &per_cpu(ccount_timer, cpu);
@@ -184,6 +178,8 @@ static inline void calibrate_ccount(void)
 
 void __init time_init(void)
 {
+       int irq;
+
        of_clk_init(NULL);
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
        pr_info("Calibrating CPU frequency ");
@@ -199,7 +195,9 @@ void __init time_init(void)
             __func__);
        clocksource_register_hz(&ccount_clocksource, ccount_freq);
        local_timer_setup(0);
-       setup_irq(this_cpu_ptr(&ccount_timer)->evt.irq, &timer_irqaction);
+       irq = this_cpu_ptr(&ccount_timer)->evt.irq;
+       if (request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL))
+               pr_err("Failed to request irq %d (timer)\n", irq);
        sched_clock_register(ccount_sched_clock_read, 32, ccount_freq);
        timer_probe();
 }
index c15a260..c5dc833 100644 (file)
@@ -883,8 +883,8 @@ static void blkcg_css_offline(struct cgroup_subsys_state *css)
        /* this prevents anyone from attaching or migrating to this blkcg */
        wb_blkcg_offline(blkcg);
 
-       /* put the base cgwb reference allowing step 2 to be triggered */
-       blkcg_cgwb_put(blkcg);
+       /* put the base online pin allowing step 2 to be triggered */
+       blkcg_unpin_online(blkcg);
 }
 
 /**
@@ -983,11 +983,11 @@ blkcg_css_alloc(struct cgroup_subsys_state *parent_css)
        }
 
        spin_lock_init(&blkcg->lock);
+       refcount_set(&blkcg->online_pin, 1);
        INIT_RADIX_TREE(&blkcg->blkg_tree, GFP_NOWAIT | __GFP_NOWARN);
        INIT_HLIST_HEAD(&blkcg->blkg_list);
 #ifdef CONFIG_CGROUP_WRITEBACK
        INIT_LIST_HEAD(&blkcg->cgwb_list);
-       refcount_set(&blkcg->cgwb_refcnt, 1);
 #endif
        list_add_tail(&blkcg->all_blkcgs_node, &all_blkcgs);
 
@@ -1006,6 +1006,21 @@ unlock:
        return ret;
 }
 
+static int blkcg_css_online(struct cgroup_subsys_state *css)
+{
+       struct blkcg *blkcg = css_to_blkcg(css);
+       struct blkcg *parent = blkcg_parent(blkcg);
+
+       /*
+        * blkcg_pin_online() is used to delay blkcg offline so that blkgs
+        * don't go offline while cgwbs are still active on them.  Pin the
+        * parent so that offline always happens towards the root.
+        */
+       if (parent)
+               blkcg_pin_online(parent);
+       return 0;
+}
+
 /**
  * blkcg_init_queue - initialize blkcg part of request queue
  * @q: request_queue to initialize
@@ -1199,6 +1214,7 @@ static void blkcg_exit(struct task_struct *tsk)
 
 struct cgroup_subsys io_cgrp_subsys = {
        .css_alloc = blkcg_css_alloc,
+       .css_online = blkcg_css_online,
        .css_offline = blkcg_css_offline,
        .css_free = blkcg_css_free,
        .can_attach = blkcg_can_attach,
index f6291ce..8e56884 100644 (file)
@@ -1289,7 +1289,7 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
                 * the driver there was more coming, but that turned out to
                 * be a lie.
                 */
-               if (q->mq_ops->commit_rqs)
+               if (q->mq_ops->commit_rqs && queued)
                        q->mq_ops->commit_rqs(hctx);
 
                spin_lock(&hctx->lock);
@@ -1911,6 +1911,8 @@ blk_status_t blk_mq_request_issue_directly(struct request *rq, bool last)
 void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx,
                struct list_head *list)
 {
+       int queued = 0;
+
        while (!list_empty(list)) {
                blk_status_t ret;
                struct request *rq = list_first_entry(list, struct request,
@@ -1926,7 +1928,8 @@ void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx,
                                break;
                        }
                        blk_mq_end_request(rq, ret);
-               }
+               } else
+                       queued++;
        }
 
        /*
@@ -1934,7 +1937,7 @@ 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)
+       if (!list_empty(list) && hctx->queue->mq_ops->commit_rqs && queued)
                hctx->queue->mq_ops->commit_rqs(hctx);
 }
 
index b79c451..bc1ded1 100644 (file)
@@ -496,7 +496,7 @@ int blk_drop_partitions(struct gendisk *disk, struct block_device *bdev)
 
        if (!disk_part_scan_enabled(disk))
                return 0;
-       if (bdev->bd_part_count || bdev->bd_super)
+       if (bdev->bd_part_count || bdev->bd_openers > 1)
                return -EBUSY;
        res = invalidate_partition(disk, 0);
        if (res)
index 74920bd..dcecc9f 100644 (file)
@@ -138,6 +138,10 @@ source "drivers/virt/Kconfig"
 
 source "drivers/virtio/Kconfig"
 
+source "drivers/vdpa/Kconfig"
+
+source "drivers/vhost/Kconfig"
+
 source "drivers/hv/Kconfig"
 
 source "drivers/xen/Kconfig"
index 7646549..c0cd1b9 100644 (file)
@@ -42,6 +42,7 @@ obj-$(CONFIG_DMADEVICES)      += dma/
 obj-y                          += soc/
 
 obj-$(CONFIG_VIRTIO)           += virtio/
+obj-$(CONFIG_VDPA)             += vdpa/
 obj-$(CONFIG_XEN)              += xen/
 
 # regulators early, since some subsystems rely on them to initialize
index ed3d2d1..7d04424 100644 (file)
@@ -1015,6 +1015,7 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
                return ops;
 
        if (dev_is_pci(dev)) {
+               struct iommu_fwspec *fwspec;
                struct pci_bus *bus = to_pci_dev(dev)->bus;
                struct iort_pci_alias_info info = { .dev = dev };
 
@@ -1027,8 +1028,9 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
                err = pci_for_each_dma_alias(to_pci_dev(dev),
                                             iort_pci_iommu_init, &info);
 
-               if (!err && iort_pci_rc_supports_ats(node))
-                       dev->iommu_fwspec->flags |= IOMMU_FWSPEC_PCI_RC_ATS;
+               fwspec = dev_iommu_fwspec_get(dev);
+               if (fwspec && iort_pci_rc_supports_ats(node))
+                       fwspec->flags |= IOMMU_FWSPEC_PCI_RC_ATS;
        } else {
                int i = 0;
 
index 4816df5..b4c0152 100644 (file)
@@ -1589,8 +1589,8 @@ static int acpi_ec_add(struct acpi_device *device)
        strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_EC_CLASS);
 
-       if ((boot_ec && boot_ec->handle == device->handle) ||
-           !strcmp(acpi_device_hid(device), ACPI_ECDT_HID)) {
+       if (boot_ec && (boot_ec->handle == device->handle ||
+           !strcmp(acpi_device_hid(device), ACPI_ECDT_HID))) {
                /* Fast path: this device corresponds to the boot EC. */
                ec = boot_ec;
        } else {
index a3320f9..fa4500f 100644 (file)
@@ -360,7 +360,7 @@ static union acpi_object *acpi_label_info(acpi_handle handle)
 
 static u8 nfit_dsm_revid(unsigned family, unsigned func)
 {
-       static const u8 revid_table[NVDIMM_FAMILY_MAX+1][32] = {
+       static const u8 revid_table[NVDIMM_FAMILY_MAX+1][NVDIMM_CMD_MAX+1] = {
                [NVDIMM_FAMILY_INTEL] = {
                        [NVDIMM_INTEL_GET_MODES] = 2,
                        [NVDIMM_INTEL_GET_FWINFO] = 2,
@@ -386,7 +386,7 @@ static u8 nfit_dsm_revid(unsigned family, unsigned func)
 
        if (family > NVDIMM_FAMILY_MAX)
                return 0;
-       if (func > 31)
+       if (func > NVDIMM_CMD_MAX)
                return 0;
        id = revid_table[family][func];
        if (id == 0)
@@ -492,7 +492,8 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
         * Check for a valid command.  For ND_CMD_CALL, we also have to
         * make sure that the DSM function is supported.
         */
-       if (cmd == ND_CMD_CALL && !test_bit(func, &dsm_mask))
+       if (cmd == ND_CMD_CALL &&
+           (func > NVDIMM_CMD_MAX || !test_bit(func, &dsm_mask)))
                return -ENOTTY;
        else if (!test_bit(cmd, &cmd_mask))
                return -ENOTTY;
@@ -2026,8 +2027,10 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
                        continue;
                }
 
-               if (nfit_mem->bdw && nfit_mem->memdev_pmem)
+               if (nfit_mem->bdw && nfit_mem->memdev_pmem) {
                        set_bit(NDD_ALIASING, &flags);
+                       set_bit(NDD_LABELING, &flags);
+               }
 
                /* collate flags across all memdevs for this dimm */
                list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
@@ -3492,7 +3495,8 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
        if (nvdimm && cmd == ND_CMD_CALL &&
                        call_pkg->nd_family == NVDIMM_FAMILY_INTEL) {
                func = call_pkg->nd_command;
-               if ((1 << func) & NVDIMM_INTEL_SECURITY_CMDMASK)
+               if (func > NVDIMM_CMD_MAX ||
+                   (1 << func) & NVDIMM_INTEL_SECURITY_CMDMASK)
                        return -EOPNOTSUPP;
        }
 
index 2424194..f5525f8 100644 (file)
@@ -34,6 +34,7 @@
                | ACPI_NFIT_MEM_NOT_ARMED | ACPI_NFIT_MEM_MAP_FAILED)
 
 #define NVDIMM_FAMILY_MAX NVDIMM_FAMILY_HYPERV
+#define NVDIMM_CMD_MAX 31
 
 #define NVDIMM_STANDARD_CMDMASK \
 (1 << ND_CMD_SMART | 1 << ND_CMD_SMART_THRESHOLD | 1 << ND_CMD_DIMM_FLAGS \
@@ -144,32 +145,32 @@ struct nfit_spa {
        unsigned long ars_state;
        u32 clear_err_unit;
        u32 max_ars;
-       struct acpi_nfit_system_address spa[0];
+       struct acpi_nfit_system_address spa[];
 };
 
 struct nfit_dcr {
        struct list_head list;
-       struct acpi_nfit_control_region dcr[0];
+       struct acpi_nfit_control_region dcr[];
 };
 
 struct nfit_bdw {
        struct list_head list;
-       struct acpi_nfit_data_region bdw[0];
+       struct acpi_nfit_data_region bdw[];
 };
 
 struct nfit_idt {
        struct list_head list;
-       struct acpi_nfit_interleave idt[0];
+       struct acpi_nfit_interleave idt[];
 };
 
 struct nfit_flush {
        struct list_head list;
-       struct acpi_nfit_flush_address flush[0];
+       struct acpi_nfit_flush_address flush[];
 };
 
 struct nfit_memdev {
        struct list_head list;
-       struct acpi_nfit_memory_map memdev[0];
+       struct acpi_nfit_memory_map memdev[];
 };
 
 enum nfit_mem_flags {
index eadbf90..47b4969 100644 (file)
@@ -72,47 +72,6 @@ int acpi_map_pxm_to_node(int pxm)
 }
 EXPORT_SYMBOL(acpi_map_pxm_to_node);
 
-/**
- * acpi_map_pxm_to_online_node - Map proximity ID to online node
- * @pxm: ACPI proximity ID
- *
- * This is similar to acpi_map_pxm_to_node(), but always returns an online
- * node.  When the mapped node from a given proximity ID is offline, it
- * looks up the node distance table and returns the nearest online node.
- *
- * ACPI device drivers, which are called after the NUMA initialization has
- * completed in the kernel, can call this interface to obtain their device
- * NUMA topology from ACPI tables.  Such drivers do not have to deal with
- * offline nodes.  A node may be offline when a device proximity ID is
- * unique, SRAT memory entry does not exist, or NUMA is disabled, ex.
- * "numa=off" on x86.
- */
-int acpi_map_pxm_to_online_node(int pxm)
-{
-       int node, min_node;
-
-       node = acpi_map_pxm_to_node(pxm);
-
-       if (node == NUMA_NO_NODE)
-               node = 0;
-
-       min_node = node;
-       if (!node_online(node)) {
-               int min_dist = INT_MAX, dist, n;
-
-               for_each_online_node(n) {
-                       dist = node_distance(node, n);
-                       if (dist < min_dist) {
-                               min_dist = dist;
-                               min_node = n;
-                       }
-               }
-       }
-
-       return min_node;
-}
-EXPORT_SYMBOL(acpi_map_pxm_to_online_node);
-
 static void __init
 acpi_table_print_srat_entry(struct acpi_subtable_header *header)
 {
index ad0185c..0101b65 100644 (file)
@@ -410,6 +410,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x22a3), board_ahci_mobile }, /* Cherry Tr. AHCI */
        { PCI_VDEVICE(INTEL, 0x5ae3), board_ahci_mobile }, /* ApolloLake AHCI */
        { PCI_VDEVICE(INTEL, 0x34d3), board_ahci_mobile }, /* Ice Lake LP AHCI */
+       { PCI_VDEVICE(INTEL, 0x02d7), board_ahci_mobile }, /* Comet Lake PCH RAID */
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -1495,7 +1496,7 @@ static irqreturn_t ahci_thunderx_irq_handler(int irq, void *dev_instance)
 static void ahci_remap_check(struct pci_dev *pdev, int bar,
                struct ahci_host_priv *hpriv)
 {
-       int i, count = 0;
+       int i;
        u32 cap;
 
        /*
@@ -1516,13 +1517,14 @@ static void ahci_remap_check(struct pci_dev *pdev, int bar,
                        continue;
 
                /* We've found a remapped device */
-               count++;
+               hpriv->remapped_nvme++;
        }
 
-       if (!count)
+       if (!hpriv->remapped_nvme)
                return;
 
-       dev_warn(&pdev->dev, "Found %d remapped NVMe devices.\n", count);
+       dev_warn(&pdev->dev, "Found %u remapped NVMe devices.\n",
+                hpriv->remapped_nvme);
        dev_warn(&pdev->dev,
                 "Switch your BIOS from RAID to AHCI mode to use them.\n");
 
@@ -1642,6 +1644,18 @@ static void ahci_intel_pcs_quirk(struct pci_dev *pdev, struct ahci_host_priv *hp
        }
 }
 
+static ssize_t remapped_nvme_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct ahci_host_priv *hpriv = host->private_data;
+
+       return sprintf(buf, "%u\n", hpriv->remapped_nvme);
+}
+
+static DEVICE_ATTR_RO(remapped_nvme);
+
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        unsigned int board_id = ent->driver_data;
@@ -1745,6 +1759,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* detect remapped nvme devices */
        ahci_remap_check(pdev, ahci_pci_bar, hpriv);
 
+       sysfs_add_file_to_group(&pdev->dev.kobj,
+                               &dev_attr_remapped_nvme.attr,
+                               NULL);
+
        /* must set flag prior to save config in order to take effect */
        if (ahci_broken_devslp(pdev))
                hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;
@@ -1896,6 +1914,9 @@ static void ahci_shutdown_one(struct pci_dev *pdev)
 
 static void ahci_remove_one(struct pci_dev *pdev)
 {
+       sysfs_remove_file_from_group(&pdev->dev.kobj,
+                                    &dev_attr_remapped_nvme.attr,
+                                    NULL);
        pm_runtime_get_noresume(&pdev->dev);
        ata_pci_remove_one(pdev);
 }
index 3dbf398..d991dd4 100644 (file)
@@ -336,6 +336,7 @@ struct ahci_host_priv {
        u32                     em_loc; /* enclosure management location */
        u32                     em_buf_sz;      /* EM buffer size in byte */
        u32                     em_msg_type;    /* EM message type */
+       u32                     remapped_nvme;  /* NVMe remapped device count */
        bool                    got_runtime_pm; /* Did we do pm_runtime_get? */
        struct clk              *clks[AHCI_MAX_CLKS]; /* Optional */
        struct reset_control    *rsts;          /* Optional */
index 948d2c6..388baf5 100644 (file)
@@ -782,7 +782,7 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
        struct ata_host *host = dev_get_drvdata(ap->dev);
        struct ahci_host_priv *hpriv = host->private_data;
        struct imx_ahci_priv *imxpriv = hpriv->plat_data;
-       int ret = -EIO;
+       int ret;
 
        if (imxpriv->type == AHCI_IMX53)
                ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline);
index 3ff1407..79f2aee 100644 (file)
@@ -763,6 +763,7 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
 
        if (dev->flags & ATA_DFLAG_DETACH) {
                detach = 1;
+               rc = -ENODEV;
                goto fail;
        }
 
index a42c49e..da693e6 100644 (file)
@@ -429,11 +429,12 @@ static int lo_fallocate(struct loop_device *lo, struct request *rq, loff_t pos,
         * information.
         */
        struct file *file = lo->lo_backing_file;
+       struct request_queue *q = lo->lo_queue;
        int ret;
 
        mode |= FALLOC_FL_KEEP_SIZE;
 
-       if ((!file->f_op->fallocate) || lo->lo_encrypt_key_size) {
+       if (!blk_queue_discard(q)) {
                ret = -EOPNOTSUPP;
                goto out;
        }
@@ -463,7 +464,7 @@ static void lo_complete_rq(struct request *rq)
        if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) ||
            req_op(rq) != REQ_OP_READ) {
                if (cmd->ret < 0)
-                       ret = BLK_STS_IOERR;
+                       ret = errno_to_blk_status(cmd->ret);
                goto end_io;
        }
 
@@ -868,27 +869,46 @@ static void loop_config_discard(struct loop_device *lo)
        struct request_queue *q = lo->lo_queue;
 
        /*
+        * If the backing device is a block device, mirror its zeroing
+        * capability. Set the discard sectors to the block device's zeroing
+        * capabilities because loop discards result in blkdev_issue_zeroout(),
+        * not blkdev_issue_discard(). This maintains consistent behavior with
+        * file-backed loop devices: discarded regions read back as zero.
+        */
+       if (S_ISBLK(inode->i_mode) && !lo->lo_encrypt_key_size) {
+               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);
+
+       /*
         * We use punch hole to reclaim the free space used by the
         * image a.k.a. discard. However we do not support discard if
         * encryption is enabled, because it may give an attacker
         * useful information.
         */
-       if ((!file->f_op->fallocate) ||
-           lo->lo_encrypt_key_size) {
+       } 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);
-               blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
-               return;
-       }
 
-       q->limits.discard_granularity = inode->i_sb->s_blocksize;
-       q->limits.discard_alignment = 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);
+       }
 
-       blk_queue_max_discard_sectors(q, UINT_MAX >> 9);
-       blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9);
-       blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
+       if (q->limits.max_write_zeroes_sectors)
+               blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
+       else
+               blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
 }
 
 static void loop_unprepare_queue(struct loop_device *lo)
@@ -1955,7 +1975,10 @@ static void loop_handle_cmd(struct loop_cmd *cmd)
  failed:
        /* complete non-aio request */
        if (!cmd->use_aio || ret) {
-               cmd->ret = ret ? -EIO : 0;
+               if (ret == -EOPNOTSUPP)
+                       cmd->ret = ret;
+               else
+                       cmd->ret = ret ? -EIO : 0;
                blk_mq_complete_request(rq);
        }
 }
index 6343402..67d65ac 100644 (file)
@@ -337,10 +337,7 @@ struct rbd_img_request {
                u64                     snap_id;        /* for reads */
                struct ceph_snap_context *snapc;        /* for writes */
        };
-       union {
-               struct request          *rq;            /* block request */
-               struct rbd_obj_request  *obj_request;   /* obj req initiator */
-       };
+       struct rbd_obj_request  *obj_request;   /* obj req initiator */
 
        struct list_head        lock_item;
        struct list_head        object_extents; /* obj_req.ex structs */
@@ -349,7 +346,6 @@ struct rbd_img_request {
        struct pending_result   pending;
        struct work_struct      work;
        int                     work_result;
-       struct kref             kref;
 };
 
 #define for_each_obj_request(ireq, oreq) \
@@ -1320,15 +1316,6 @@ static void rbd_obj_request_put(struct rbd_obj_request *obj_request)
        kref_put(&obj_request->kref, rbd_obj_request_destroy);
 }
 
-static void rbd_img_request_destroy(struct kref *kref);
-static void rbd_img_request_put(struct rbd_img_request *img_request)
-{
-       rbd_assert(img_request != NULL);
-       dout("%s: img %p (was %d)\n", __func__, img_request,
-               kref_read(&img_request->kref));
-       kref_put(&img_request->kref, rbd_img_request_destroy);
-}
-
 static inline void rbd_img_obj_request_add(struct rbd_img_request *img_request,
                                        struct rbd_obj_request *obj_request)
 {
@@ -1366,18 +1353,10 @@ static void rbd_osd_submit(struct ceph_osd_request *osd_req)
 static void img_request_layered_set(struct rbd_img_request *img_request)
 {
        set_bit(IMG_REQ_LAYERED, &img_request->flags);
-       smp_mb();
-}
-
-static void img_request_layered_clear(struct rbd_img_request *img_request)
-{
-       clear_bit(IMG_REQ_LAYERED, &img_request->flags);
-       smp_mb();
 }
 
 static bool img_request_layered_test(struct rbd_img_request *img_request)
 {
-       smp_mb();
        return test_bit(IMG_REQ_LAYERED, &img_request->flags) != 0;
 }
 
@@ -1619,10 +1598,8 @@ static bool rbd_dev_parent_get(struct rbd_device *rbd_dev)
        if (!rbd_dev->parent_spec)
                return false;
 
-       down_read(&rbd_dev->header_rwsem);
        if (rbd_dev->parent_overlap)
                counter = atomic_inc_return_safe(&rbd_dev->parent_ref);
-       up_read(&rbd_dev->header_rwsem);
 
        if (counter < 0)
                rbd_warn(rbd_dev, "parent reference overflow");
@@ -1630,63 +1607,54 @@ static bool rbd_dev_parent_get(struct rbd_device *rbd_dev)
        return counter > 0;
 }
 
-/*
- * Caller is responsible for filling in the list of object requests
- * that comprises the image request, and the Linux request pointer
- * (if there is one).
- */
-static struct rbd_img_request *rbd_img_request_create(
-                                       struct rbd_device *rbd_dev,
-                                       enum obj_operation_type op_type,
-                                       struct ceph_snap_context *snapc)
+static void rbd_img_request_init(struct rbd_img_request *img_request,
+                                struct rbd_device *rbd_dev,
+                                enum obj_operation_type op_type)
 {
-       struct rbd_img_request *img_request;
-
-       img_request = kmem_cache_zalloc(rbd_img_request_cache, GFP_NOIO);
-       if (!img_request)
-               return NULL;
+       memset(img_request, 0, sizeof(*img_request));
 
        img_request->rbd_dev = rbd_dev;
        img_request->op_type = op_type;
-       if (!rbd_img_is_write(img_request))
-               img_request->snap_id = rbd_dev->spec->snap_id;
-       else
-               img_request->snapc = snapc;
-
-       if (rbd_dev_parent_get(rbd_dev))
-               img_request_layered_set(img_request);
 
        INIT_LIST_HEAD(&img_request->lock_item);
        INIT_LIST_HEAD(&img_request->object_extents);
        mutex_init(&img_request->state_mutex);
-       kref_init(&img_request->kref);
+}
+
+static void rbd_img_capture_header(struct rbd_img_request *img_req)
+{
+       struct rbd_device *rbd_dev = img_req->rbd_dev;
 
-       return img_request;
+       lockdep_assert_held(&rbd_dev->header_rwsem);
+
+       if (rbd_img_is_write(img_req))
+               img_req->snapc = ceph_get_snap_context(rbd_dev->header.snapc);
+       else
+               img_req->snap_id = rbd_dev->spec->snap_id;
+
+       if (rbd_dev_parent_get(rbd_dev))
+               img_request_layered_set(img_req);
 }
 
-static void rbd_img_request_destroy(struct kref *kref)
+static void rbd_img_request_destroy(struct rbd_img_request *img_request)
 {
-       struct rbd_img_request *img_request;
        struct rbd_obj_request *obj_request;
        struct rbd_obj_request *next_obj_request;
 
-       img_request = container_of(kref, struct rbd_img_request, kref);
-
        dout("%s: img %p\n", __func__, img_request);
 
        WARN_ON(!list_empty(&img_request->lock_item));
        for_each_obj_request_safe(img_request, obj_request, next_obj_request)
                rbd_img_obj_request_del(img_request, obj_request);
 
-       if (img_request_layered_test(img_request)) {
-               img_request_layered_clear(img_request);
+       if (img_request_layered_test(img_request))
                rbd_dev_parent_put(img_request->rbd_dev);
-       }
 
        if (rbd_img_is_write(img_request))
                ceph_put_snap_context(img_request->snapc);
 
-       kmem_cache_free(rbd_img_request_cache, img_request);
+       if (test_bit(IMG_REQ_CHILD, &img_request->flags))
+               kmem_cache_free(rbd_img_request_cache, img_request);
 }
 
 #define BITS_PER_OBJ   2
@@ -2849,17 +2817,22 @@ static int rbd_obj_read_object(struct rbd_obj_request *obj_req)
 static int rbd_obj_read_from_parent(struct rbd_obj_request *obj_req)
 {
        struct rbd_img_request *img_req = obj_req->img_request;
+       struct rbd_device *parent = img_req->rbd_dev->parent;
        struct rbd_img_request *child_img_req;
        int ret;
 
-       child_img_req = rbd_img_request_create(img_req->rbd_dev->parent,
-                                              OBJ_OP_READ, NULL);
+       child_img_req = kmem_cache_alloc(rbd_img_request_cache, GFP_NOIO);
        if (!child_img_req)
                return -ENOMEM;
 
+       rbd_img_request_init(child_img_req, parent, OBJ_OP_READ);
        __set_bit(IMG_REQ_CHILD, &child_img_req->flags);
        child_img_req->obj_request = obj_req;
 
+       down_read(&parent->header_rwsem);
+       rbd_img_capture_header(child_img_req);
+       up_read(&parent->header_rwsem);
+
        dout("%s child_img_req %p for obj_req %p\n", __func__, child_img_req,
             obj_req);
 
@@ -2888,7 +2861,7 @@ static int rbd_obj_read_from_parent(struct rbd_obj_request *obj_req)
                                              obj_req->copyup_bvecs);
        }
        if (ret) {
-               rbd_img_request_put(child_img_req);
+               rbd_img_request_destroy(child_img_req);
                return ret;
        }
 
@@ -3647,15 +3620,15 @@ again:
        if (test_bit(IMG_REQ_CHILD, &img_req->flags)) {
                struct rbd_obj_request *obj_req = img_req->obj_request;
 
-               rbd_img_request_put(img_req);
+               rbd_img_request_destroy(img_req);
                if (__rbd_obj_handle_request(obj_req, &result)) {
                        img_req = obj_req->img_request;
                        goto again;
                }
        } else {
-               struct request *rq = img_req->rq;
+               struct request *rq = blk_mq_rq_from_pdu(img_req);
 
-               rbd_img_request_put(img_req);
+               rbd_img_request_destroy(img_req);
                blk_mq_end_request(rq, errno_to_blk_status(result));
        }
 }
@@ -3781,11 +3754,7 @@ static int __rbd_notify_op_lock(struct rbd_device *rbd_dev,
 static void rbd_notify_op_lock(struct rbd_device *rbd_dev,
                               enum rbd_notify_op notify_op)
 {
-       struct page **reply_pages;
-       size_t reply_len;
-
-       __rbd_notify_op_lock(rbd_dev, notify_op, &reply_pages, &reply_len);
-       ceph_release_page_vector(reply_pages, calc_pages_for(0, reply_len));
+       __rbd_notify_op_lock(rbd_dev, notify_op, NULL, NULL);
 }
 
 static void rbd_notify_acquired_lock(struct work_struct *work)
@@ -4554,6 +4523,10 @@ static void cancel_tasks_sync(struct rbd_device *rbd_dev)
        cancel_work_sync(&rbd_dev->unlock_work);
 }
 
+/*
+ * header_rwsem must not be held to avoid a deadlock with
+ * rbd_dev_refresh() when flushing notifies.
+ */
 static void rbd_unregister_watch(struct rbd_device *rbd_dev)
 {
        cancel_tasks_sync(rbd_dev);
@@ -4707,84 +4680,36 @@ static int rbd_obj_method_sync(struct rbd_device *rbd_dev,
 
 static void rbd_queue_workfn(struct work_struct *work)
 {
-       struct request *rq = blk_mq_rq_from_pdu(work);
-       struct rbd_device *rbd_dev = rq->q->queuedata;
-       struct rbd_img_request *img_request;
-       struct ceph_snap_context *snapc = NULL;
+       struct rbd_img_request *img_request =
+           container_of(work, struct rbd_img_request, work);
+       struct rbd_device *rbd_dev = img_request->rbd_dev;
+       enum obj_operation_type op_type = img_request->op_type;
+       struct request *rq = blk_mq_rq_from_pdu(img_request);
        u64 offset = (u64)blk_rq_pos(rq) << SECTOR_SHIFT;
        u64 length = blk_rq_bytes(rq);
-       enum obj_operation_type op_type;
        u64 mapping_size;
        int result;
 
-       switch (req_op(rq)) {
-       case REQ_OP_DISCARD:
-               op_type = OBJ_OP_DISCARD;
-               break;
-       case REQ_OP_WRITE_ZEROES:
-               op_type = OBJ_OP_ZEROOUT;
-               break;
-       case REQ_OP_WRITE:
-               op_type = OBJ_OP_WRITE;
-               break;
-       case REQ_OP_READ:
-               op_type = OBJ_OP_READ;
-               break;
-       default:
-               dout("%s: non-fs request type %d\n", __func__, req_op(rq));
-               result = -EIO;
-               goto err;
-       }
-
        /* Ignore/skip any zero-length requests */
-
        if (!length) {
                dout("%s: zero-length request\n", __func__);
                result = 0;
-               goto err_rq;
-       }
-
-       if (op_type != OBJ_OP_READ) {
-               if (rbd_is_ro(rbd_dev)) {
-                       rbd_warn(rbd_dev, "%s on read-only mapping",
-                                obj_op_name(op_type));
-                       result = -EIO;
-                       goto err;
-               }
-               rbd_assert(!rbd_is_snap(rbd_dev));
-       }
-
-       if (offset && length > U64_MAX - offset + 1) {
-               rbd_warn(rbd_dev, "bad request range (%llu~%llu)", offset,
-                        length);
-               result = -EINVAL;
-               goto err_rq;    /* Shouldn't happen */
+               goto err_img_request;
        }
 
        blk_mq_start_request(rq);
 
        down_read(&rbd_dev->header_rwsem);
        mapping_size = rbd_dev->mapping.size;
-       if (op_type != OBJ_OP_READ) {
-               snapc = rbd_dev->header.snapc;
-               ceph_get_snap_context(snapc);
-       }
+       rbd_img_capture_header(img_request);
        up_read(&rbd_dev->header_rwsem);
 
        if (offset + length > mapping_size) {
                rbd_warn(rbd_dev, "beyond EOD (%llu~%llu > %llu)", offset,
                         length, mapping_size);
                result = -EIO;
-               goto err_rq;
-       }
-
-       img_request = rbd_img_request_create(rbd_dev, op_type, snapc);
-       if (!img_request) {
-               result = -ENOMEM;
-               goto err_rq;
+               goto err_img_request;
        }
-       img_request->rq = rq;
-       snapc = NULL; /* img_request consumes a ref */
 
        dout("%s rbd_dev %p img_req %p %s %llu~%llu\n", __func__, rbd_dev,
             img_request, obj_op_name(op_type), offset, length);
@@ -4801,23 +4726,51 @@ static void rbd_queue_workfn(struct work_struct *work)
        return;
 
 err_img_request:
-       rbd_img_request_put(img_request);
-err_rq:
+       rbd_img_request_destroy(img_request);
        if (result)
                rbd_warn(rbd_dev, "%s %llx at %llx result %d",
                         obj_op_name(op_type), length, offset, result);
-       ceph_put_snap_context(snapc);
-err:
        blk_mq_end_request(rq, errno_to_blk_status(result));
 }
 
 static blk_status_t rbd_queue_rq(struct blk_mq_hw_ctx *hctx,
                const struct blk_mq_queue_data *bd)
 {
-       struct request *rq = bd->rq;
-       struct work_struct *work = blk_mq_rq_to_pdu(rq);
+       struct rbd_device *rbd_dev = hctx->queue->queuedata;
+       struct rbd_img_request *img_req = blk_mq_rq_to_pdu(bd->rq);
+       enum obj_operation_type op_type;
+
+       switch (req_op(bd->rq)) {
+       case REQ_OP_DISCARD:
+               op_type = OBJ_OP_DISCARD;
+               break;
+       case REQ_OP_WRITE_ZEROES:
+               op_type = OBJ_OP_ZEROOUT;
+               break;
+       case REQ_OP_WRITE:
+               op_type = OBJ_OP_WRITE;
+               break;
+       case REQ_OP_READ:
+               op_type = OBJ_OP_READ;
+               break;
+       default:
+               rbd_warn(rbd_dev, "unknown req_op %d", req_op(bd->rq));
+               return BLK_STS_IOERR;
+       }
+
+       rbd_img_request_init(img_req, rbd_dev, op_type);
 
-       queue_work(rbd_wq, work);
+       if (rbd_img_is_write(img_req)) {
+               if (rbd_is_ro(rbd_dev)) {
+                       rbd_warn(rbd_dev, "%s on read-only mapping",
+                                obj_op_name(img_req->op_type));
+                       return BLK_STS_IOERR;
+               }
+               rbd_assert(!rbd_is_snap(rbd_dev));
+       }
+
+       INIT_WORK(&img_req->work, rbd_queue_workfn);
+       queue_work(rbd_wq, &img_req->work);
        return BLK_STS_OK;
 }
 
@@ -4984,18 +4937,8 @@ out:
        return ret;
 }
 
-static int rbd_init_request(struct blk_mq_tag_set *set, struct request *rq,
-               unsigned int hctx_idx, unsigned int numa_node)
-{
-       struct work_struct *work = blk_mq_rq_to_pdu(rq);
-
-       INIT_WORK(work, rbd_queue_workfn);
-       return 0;
-}
-
 static const struct blk_mq_ops rbd_mq_ops = {
        .queue_rq       = rbd_queue_rq,
-       .init_request   = rbd_init_request,
 };
 
 static int rbd_init_disk(struct rbd_device *rbd_dev)
@@ -5027,8 +4970,8 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
        rbd_dev->tag_set.queue_depth = rbd_dev->opts->queue_depth;
        rbd_dev->tag_set.numa_node = NUMA_NO_NODE;
        rbd_dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
-       rbd_dev->tag_set.nr_hw_queues = 1;
-       rbd_dev->tag_set.cmd_size = sizeof(struct work_struct);
+       rbd_dev->tag_set.nr_hw_queues = num_present_cpus();
+       rbd_dev->tag_set.cmd_size = sizeof(struct rbd_img_request);
 
        err = blk_mq_alloc_tag_set(&rbd_dev->tag_set);
        if (err)
@@ -6951,9 +6894,10 @@ static void rbd_print_dne(struct rbd_device *rbd_dev, bool is_snap)
 
 static void rbd_dev_image_release(struct rbd_device *rbd_dev)
 {
-       rbd_dev_unprobe(rbd_dev);
-       if (rbd_dev->opts)
+       if (!rbd_is_ro(rbd_dev))
                rbd_unregister_watch(rbd_dev);
+
+       rbd_dev_unprobe(rbd_dev);
        rbd_dev->image_format = 0;
        kfree(rbd_dev->spec->image_id);
        rbd_dev->spec->image_id = NULL;
@@ -6964,6 +6908,9 @@ static void rbd_dev_image_release(struct rbd_device *rbd_dev)
  * device.  If this image is the one being mapped (i.e., not a
  * parent), initiate a watch on its header object before using that
  * object to get detailed information about the rbd image.
+ *
+ * On success, returns with header_rwsem held for write if called
+ * with @depth == 0.
  */
 static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
 {
@@ -6993,11 +6940,14 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
                }
        }
 
+       if (!depth)
+               down_write(&rbd_dev->header_rwsem);
+
        ret = rbd_dev_header_info(rbd_dev);
        if (ret) {
                if (ret == -ENOENT && !need_watch)
                        rbd_print_dne(rbd_dev, false);
-               goto err_out_watch;
+               goto err_out_probe;
        }
 
        /*
@@ -7042,10 +6992,11 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
        return 0;
 
 err_out_probe:
-       rbd_dev_unprobe(rbd_dev);
-err_out_watch:
+       if (!depth)
+               up_write(&rbd_dev->header_rwsem);
        if (need_watch)
                rbd_unregister_watch(rbd_dev);
+       rbd_dev_unprobe(rbd_dev);
 err_out_format:
        rbd_dev->image_format = 0;
        kfree(rbd_dev->spec->image_id);
@@ -7107,12 +7058,9 @@ static ssize_t do_rbd_add(struct bus_type *bus,
                goto err_out_rbd_dev;
        }
 
-       down_write(&rbd_dev->header_rwsem);
        rc = rbd_dev_image_probe(rbd_dev, 0);
-       if (rc < 0) {
-               up_write(&rbd_dev->header_rwsem);
+       if (rc < 0)
                goto err_out_rbd_dev;
-       }
 
        if (rbd_dev->opts->alloc_size > rbd_dev->layout.object_size) {
                rbd_warn(rbd_dev, "alloc_size adjusted to %u",
index 915cf5b..3b889ea 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/bitmap.h>
 #include <linux/list.h>
 #include <linux/workqueue.h>
+#include <linux/sched/mm.h>
 
 #include <xen/xen.h>
 #include <xen/xenbus.h>
@@ -2189,10 +2190,12 @@ static void blkfront_setup_discard(struct blkfront_info *info)
 
 static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo)
 {
-       unsigned int psegs, grants;
+       unsigned int psegs, grants, memflags;
        int err, i;
        struct blkfront_info *info = rinfo->dev_info;
 
+       memflags = memalloc_noio_save();
+
        if (info->max_indirect_segments == 0) {
                if (!HAS_EXTRA_REQ)
                        grants = BLKIF_MAX_SEGMENTS_PER_REQUEST;
@@ -2224,7 +2227,7 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo)
 
                BUG_ON(!list_empty(&rinfo->indirect_pages));
                for (i = 0; i < num; i++) {
-                       struct page *indirect_page = alloc_page(GFP_NOIO);
+                       struct page *indirect_page = alloc_page(GFP_KERNEL);
                        if (!indirect_page)
                                goto out_of_memory;
                        list_add(&indirect_page->lru, &rinfo->indirect_pages);
@@ -2235,15 +2238,15 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo)
                rinfo->shadow[i].grants_used =
                        kvcalloc(grants,
                                 sizeof(rinfo->shadow[i].grants_used[0]),
-                                GFP_NOIO);
+                                GFP_KERNEL);
                rinfo->shadow[i].sg = kvcalloc(psegs,
                                               sizeof(rinfo->shadow[i].sg[0]),
-                                              GFP_NOIO);
+                                              GFP_KERNEL);
                if (info->max_indirect_segments)
                        rinfo->shadow[i].indirect_grants =
                                kvcalloc(INDIRECT_GREFS(grants),
                                         sizeof(rinfo->shadow[i].indirect_grants[0]),
-                                        GFP_NOIO);
+                                        GFP_KERNEL);
                if ((rinfo->shadow[i].grants_used == NULL) ||
                        (rinfo->shadow[i].sg == NULL) ||
                     (info->max_indirect_segments &&
@@ -2252,6 +2255,7 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo)
                sg_init_table(rinfo->shadow[i].sg, psegs);
        }
 
+       memalloc_noio_restore(memflags);
 
        return 0;
 
@@ -2271,6 +2275,9 @@ out_of_memory:
                        __free_page(indirect_page);
                }
        }
+
+       memalloc_noio_restore(memflags);
+
        return -ENOMEM;
 }
 
index a431c5c..e0d77fa 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2009 Nokia Corporation
  * Author: Juha Yrjola <juha.yrjola@solidboot.com>
  *
- * Copyright (C) 2013 Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (C) 2013 Pali Rohár <pali@kernel.org>
  *
  * This file is licensed under  the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
@@ -178,5 +178,5 @@ module_platform_driver(omap3_rom_rng_driver);
 
 MODULE_ALIAS("platform:omap3-rom-rng");
 MODULE_AUTHOR("Juha Yrjola");
-MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
+MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
 MODULE_LICENSE("GPL");
index cad9563..c48d8f0 100644 (file)
@@ -618,6 +618,8 @@ static DEFINE_MUTEX(ipmidriver_mutex);
 
 static LIST_HEAD(ipmi_interfaces);
 static DEFINE_MUTEX(ipmi_interfaces_mutex);
+#define ipmi_interfaces_mutex_held() \
+       lockdep_is_held(&ipmi_interfaces_mutex)
 static struct srcu_struct ipmi_interfaces_srcu;
 
 /*
@@ -1321,7 +1323,8 @@ static void _ipmi_destroy_user(struct ipmi_user *user)
         * synchronize_srcu()) then free everything in that list.
         */
        mutex_lock(&intf->cmd_rcvrs_mutex);
-       list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
+       list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link,
+                               lockdep_is_held(&intf->cmd_rcvrs_mutex)) {
                if (rcvr->user == user) {
                        list_del_rcu(&rcvr->link);
                        rcvr->next = rcvrs;
@@ -1599,7 +1602,8 @@ static struct cmd_rcvr *find_cmd_rcvr(struct ipmi_smi *intf,
 {
        struct cmd_rcvr *rcvr;
 
-       list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
+       list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link,
+                               lockdep_is_held(&intf->cmd_rcvrs_mutex)) {
                if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
                                        && (rcvr->chans & (1 << chan)))
                        return rcvr;
@@ -1614,7 +1618,8 @@ static int is_cmd_rcvr_exclusive(struct ipmi_smi *intf,
 {
        struct cmd_rcvr *rcvr;
 
-       list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
+       list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link,
+                               lockdep_is_held(&intf->cmd_rcvrs_mutex)) {
                if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
                                        && (rcvr->chans & chans))
                        return 0;
@@ -3188,8 +3193,8 @@ static void __get_guid(struct ipmi_smi *intf)
        if (rv)
                /* Send failed, no GUID available. */
                bmc->dyn_guid_set = 0;
-
-       wait_event(intf->waitq, bmc->dyn_guid_set != 2);
+       else
+               wait_event(intf->waitq, bmc->dyn_guid_set != 2);
 
        /* dyn_guid_set makes the guid data available. */
        smp_rmb();
@@ -3450,7 +3455,8 @@ int ipmi_add_smi(struct module         *owner,
        /* Look for a hole in the numbers. */
        i = 0;
        link = &ipmi_interfaces;
-       list_for_each_entry_rcu(tintf, &ipmi_interfaces, link) {
+       list_for_each_entry_rcu(tintf, &ipmi_interfaces, link,
+                               ipmi_interfaces_mutex_held()) {
                if (tintf->intf_num != i) {
                        link = &tintf->link;
                        break;
index 8ac390c..b7145f3 100644 (file)
@@ -313,6 +313,7 @@ static int start_send(struct ssif_info *ssif_info,
 
 static unsigned long *ipmi_ssif_lock_cond(struct ssif_info *ssif_info,
                                          unsigned long *flags)
+       __acquires(&ssif_info->lock)
 {
        spin_lock_irqsave(&ssif_info->lock, *flags);
        return flags;
@@ -320,6 +321,7 @@ static unsigned long *ipmi_ssif_lock_cond(struct ssif_info *ssif_info,
 
 static void ipmi_ssif_unlock_cond(struct ssif_info *ssif_info,
                                  unsigned long *flags)
+       __releases(&ssif_info->lock)
 {
        spin_unlock_irqrestore(&ssif_info->lock, *flags);
 }
index 3c95594..a140203 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/poll.h>
 #include <linux/regmap.h>
@@ -233,58 +234,154 @@ static const struct kcs_ioreg ast_kcs_bmc_ioregs[KCS_CHANNEL_MAX] = {
        { .idr = LPC_IDR4, .odr = LPC_ODR4, .str = LPC_STR4 },
 };
 
-static int aspeed_kcs_probe(struct platform_device *pdev)
+static struct kcs_bmc *aspeed_kcs_probe_of_v1(struct platform_device *pdev)
 {
-       struct device *dev = &pdev->dev;
        struct aspeed_kcs_bmc *priv;
-       struct kcs_bmc *kcs_bmc;
-       u32 chan, addr;
+       struct device_node *np;
+       struct kcs_bmc *kcs;
+       u32 channel;
+       u32 slave;
        int rc;
 
-       rc = of_property_read_u32(dev->of_node, "kcs_chan", &chan);
-       if ((rc != 0) || (chan == 0 || chan > KCS_CHANNEL_MAX)) {
-               dev_err(dev, "no valid 'kcs_chan' configured\n");
-               return -ENODEV;
+       np = pdev->dev.of_node;
+
+       rc = of_property_read_u32(np, "kcs_chan", &channel);
+       if ((rc != 0) || (channel == 0 || channel > KCS_CHANNEL_MAX)) {
+               dev_err(&pdev->dev, "no valid 'kcs_chan' configured\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       kcs = kcs_bmc_alloc(&pdev->dev, sizeof(struct aspeed_kcs_bmc), channel);
+       if (!kcs)
+               return ERR_PTR(-ENOMEM);
+
+       priv = kcs_bmc_priv(kcs);
+       priv->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
+       if (IS_ERR(priv->map)) {
+               dev_err(&pdev->dev, "Couldn't get regmap\n");
+               return ERR_PTR(-ENODEV);
        }
 
-       rc = of_property_read_u32(dev->of_node, "kcs_addr", &addr);
+       rc = of_property_read_u32(np, "kcs_addr", &slave);
        if (rc) {
-               dev_err(dev, "no valid 'kcs_addr' configured\n");
-               return -ENODEV;
+               dev_err(&pdev->dev, "no valid 'kcs_addr' configured\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       kcs->ioreg = ast_kcs_bmc_ioregs[channel - 1];
+       aspeed_kcs_set_address(kcs, slave);
+
+       return kcs;
+}
+
+static int aspeed_kcs_calculate_channel(const struct kcs_ioreg *regs)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ast_kcs_bmc_ioregs); i++) {
+               if (!memcmp(&ast_kcs_bmc_ioregs[i], regs, sizeof(*regs)))
+                       return i + 1;
        }
 
-       kcs_bmc = kcs_bmc_alloc(dev, sizeof(*priv), chan);
-       if (!kcs_bmc)
-               return -ENOMEM;
+       return -EINVAL;
+}
+
+static struct kcs_bmc *aspeed_kcs_probe_of_v2(struct platform_device *pdev)
+{
+       struct aspeed_kcs_bmc *priv;
+       struct device_node *np;
+       struct kcs_ioreg ioreg;
+       struct kcs_bmc *kcs;
+       const __be32 *reg;
+       int channel;
+       u32 slave;
+       int rc;
+
+       np = pdev->dev.of_node;
+
+       /* Don't translate addresses, we want offsets for the regmaps */
+       reg = of_get_address(np, 0, NULL, NULL);
+       if (!reg)
+               return ERR_PTR(-EINVAL);
+       ioreg.idr = be32_to_cpup(reg);
+
+       reg = of_get_address(np, 1, NULL, NULL);
+       if (!reg)
+               return ERR_PTR(-EINVAL);
+       ioreg.odr = be32_to_cpup(reg);
+
+       reg = of_get_address(np, 2, NULL, NULL);
+       if (!reg)
+               return ERR_PTR(-EINVAL);
+       ioreg.str = be32_to_cpup(reg);
 
-       priv = kcs_bmc_priv(kcs_bmc);
-       priv->map = syscon_node_to_regmap(dev->parent->of_node);
+       channel = aspeed_kcs_calculate_channel(&ioreg);
+       if (channel < 0)
+               return ERR_PTR(channel);
+
+       kcs = kcs_bmc_alloc(&pdev->dev, sizeof(struct aspeed_kcs_bmc), channel);
+       if (!kcs)
+               return ERR_PTR(-ENOMEM);
+
+       kcs->ioreg = ioreg;
+
+       priv = kcs_bmc_priv(kcs);
+       priv->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
        if (IS_ERR(priv->map)) {
-               dev_err(dev, "Couldn't get regmap\n");
-               return -ENODEV;
+               dev_err(&pdev->dev, "Couldn't get regmap\n");
+               return ERR_PTR(-ENODEV);
        }
 
-       kcs_bmc->ioreg = ast_kcs_bmc_ioregs[chan - 1];
+       rc = of_property_read_u32(np, "aspeed,lpc-io-reg", &slave);
+       if (rc)
+               return ERR_PTR(rc);
+
+       aspeed_kcs_set_address(kcs, slave);
+
+       return kcs;
+}
+
+static int aspeed_kcs_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct kcs_bmc *kcs_bmc;
+       struct device_node *np;
+       int rc;
+
+       np = pdev->dev.of_node;
+       if (of_device_is_compatible(np, "aspeed,ast2400-kcs-bmc") ||
+                       of_device_is_compatible(np, "aspeed,ast2500-kcs-bmc"))
+               kcs_bmc = aspeed_kcs_probe_of_v1(pdev);
+       else if (of_device_is_compatible(np, "aspeed,ast2400-kcs-bmc-v2") ||
+                       of_device_is_compatible(np, "aspeed,ast2500-kcs-bmc-v2"))
+               kcs_bmc = aspeed_kcs_probe_of_v2(pdev);
+       else
+               return -EINVAL;
+
+       if (IS_ERR(kcs_bmc))
+               return PTR_ERR(kcs_bmc);
+
        kcs_bmc->io_inputb = aspeed_kcs_inb;
        kcs_bmc->io_outputb = aspeed_kcs_outb;
 
-       dev_set_drvdata(dev, kcs_bmc);
-
-       aspeed_kcs_set_address(kcs_bmc, addr);
-       aspeed_kcs_enable_channel(kcs_bmc, true);
        rc = aspeed_kcs_config_irq(kcs_bmc, pdev);
        if (rc)
                return rc;
 
+       dev_set_drvdata(dev, kcs_bmc);
+
+       aspeed_kcs_enable_channel(kcs_bmc, true);
+
        rc = misc_register(&kcs_bmc->miscdev);
        if (rc) {
                dev_err(dev, "Unable to register device\n");
                return rc;
        }
 
-       pr_info("channel=%u addr=0x%x idr=0x%x odr=0x%x str=0x%x\n",
-               chan, addr,
-               kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr, kcs_bmc->ioreg.str);
+       dev_dbg(&pdev->dev,
+               "Probed KCS device %d (IDR=0x%x, ODR=0x%x, STR=0x%x)\n",
+               kcs_bmc->channel, kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr,
+               kcs_bmc->ioreg.str);
 
        return 0;
 }
@@ -301,6 +398,8 @@ static int aspeed_kcs_remove(struct platform_device *pdev)
 static const struct of_device_id ast_kcs_bmc_match[] = {
        { .compatible = "aspeed,ast2400-kcs-bmc" },
        { .compatible = "aspeed,ast2500-kcs-bmc" },
+       { .compatible = "aspeed,ast2400-kcs-bmc-v2" },
+       { .compatible = "aspeed,ast2500-kcs-bmc-v2" },
        { }
 };
 MODULE_DEVICE_TABLE(of, ast_kcs_bmc_match);
index db124bc..fcc5321 100644 (file)
@@ -94,7 +94,7 @@ static void haltpoll_uninit(void)
        haltpoll_cpuidle_devices = NULL;
 }
 
-static bool haltpool_want(void)
+static bool haltpoll_want(void)
 {
        return kvm_para_has_hint(KVM_HINTS_REALTIME) || force;
 }
@@ -110,7 +110,7 @@ static int __init haltpoll_init(void)
 
        cpuidle_poll_state_init(drv);
 
-       if (!kvm_para_available() || !haltpool_want())
+       if (!kvm_para_available() || !haltpoll_want())
                return -ENODEV;
 
        ret = cpuidle_register_driver(drv);
index 095850d..f09c6cf 100644 (file)
@@ -27,6 +27,7 @@ config CRYPTO_DEV_HISI_SEC2
        select CRYPTO_SHA256
        select CRYPTO_SHA512
        depends on PCI && PCI_MSI
+       depends on UACCE || UACCE=n
        depends on ARM64 || (COMPILE_TEST && 64BIT)
        help
          Support for HiSilicon SEC Engine of version 2 in crypto subsystem.
@@ -58,6 +59,7 @@ config CRYPTO_DEV_HISI_ZIP
 config CRYPTO_DEV_HISI_HPRE
        tristate "Support for HISI HPRE accelerator"
        depends on PCI && PCI_MSI
+       depends on UACCE || UACCE=n
        depends on ARM64 || (COMPILE_TEST && 64BIT)
        select CRYPTO_DEV_HISI_QM
        select CRYPTO_DH
index 946fb62..06202bc 100644 (file)
@@ -1161,13 +1161,13 @@ static inline u32 create_aead_null_output_list(struct aead_request *req,
                                           inputlen);
                if (status != inputlen) {
                        status = -EINVAL;
-                       goto error;
+                       goto error_free;
                }
                status = sg_copy_from_buffer(req->dst, sg_nents(req->dst), ptr,
                                             inputlen);
                if (status != inputlen) {
                        status = -EINVAL;
-                       goto error;
+                       goto error_free;
                }
                kfree(ptr);
        }
@@ -1209,8 +1209,10 @@ static inline u32 create_aead_null_output_list(struct aead_request *req,
 
        req_info->outcnt = argcnt;
        return 0;
-error:
+
+error_free:
        kfree(ptr);
+error:
        return status;
 }
 
index 46e4604..df238c8 100644 (file)
@@ -421,8 +421,10 @@ struct dev_dax *__devm_create_dev_dax(struct dax_region *dax_region, int id,
         * device outside of mmap of the resulting character device.
         */
        dax_dev = alloc_dax(dev_dax, NULL, NULL, DAXDEV_F_SYNC);
-       if (!dax_dev)
+       if (IS_ERR(dax_dev)) {
+               rc = PTR_ERR(dax_dev);
                goto err;
+       }
 
        /* a device_dax instance is dead while the driver is not attached */
        kill_dax(dax_dev);
index 0aa4b6b..8e32345 100644 (file)
@@ -344,6 +344,23 @@ size_t dax_copy_to_iter(struct dax_device *dax_dev, pgoff_t pgoff, void *addr,
 }
 EXPORT_SYMBOL_GPL(dax_copy_to_iter);
 
+int dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
+                       size_t nr_pages)
+{
+       if (!dax_alive(dax_dev))
+               return -ENXIO;
+       /*
+        * There are no callers that want to zero more than one page as of now.
+        * Once users are there, this check can be removed after the
+        * device mapper code has been updated to split ranges across targets.
+        */
+       if (nr_pages != 1)
+               return -EIO;
+
+       return dax_dev->ops->zero_page_range(dax_dev, pgoff, nr_pages);
+}
+EXPORT_SYMBOL_GPL(dax_zero_page_range);
+
 #ifdef CONFIG_ARCH_HAS_PMEM_API
 void arch_wb_cache_pmem(void *addr, size_t size);
 void dax_flush(struct dax_device *dax_dev, void *addr, size_t size)
@@ -551,9 +568,16 @@ struct dax_device *alloc_dax(void *private, const char *__host,
        dev_t devt;
        int minor;
 
+       if (ops && !ops->zero_page_range) {
+               pr_debug("%s: error: device does not provide dax"
+                        " operation zero_page_range()\n",
+                        __host ? __host : "Unknown");
+               return ERR_PTR(-EINVAL);
+       }
+
        host = kstrdup(__host, GFP_KERNEL);
        if (__host && !host)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        minor = ida_simple_get(&dax_minor_ida, 0, MINORMASK+1, GFP_KERNEL);
        if (minor < 0)
@@ -576,7 +600,7 @@ struct dax_device *alloc_dax(void *private, const char *__host,
        ida_simple_remove(&dax_minor_ida, minor);
  err_minor:
        kfree(host);
-       return NULL;
+       return ERR_PTR(-ENOMEM);
 }
 EXPORT_SYMBOL_GPL(alloc_dax);
 
index ef73b67..9626673 100644 (file)
@@ -43,11 +43,12 @@ config DMABUF_MOVE_NOTIFY
        bool "Move notify between drivers (EXPERIMENTAL)"
        default n
        help
-         Don''t pin buffers if the dynamic DMA-buf interface is available on both the
-         exporter as well as the importer. This fixes a security problem where
-         userspace is able to pin unrestricted amounts of memory through DMA-buf.
-         But marked experimental because we don''t jet have a consistent execution
-         context and memory management between drivers.
+         Don't pin buffers if the dynamic DMA-buf interface is available on
+         both the exporter as well as the importer. This fixes a security
+         problem where userspace is able to pin unrestricted amounts of memory
+         through DMA-buf.
+         This is marked experimental because we don't yet have a consistent
+         execution context and memory management between drivers.
 
 config DMABUF_SELFTESTS
        tristate "Selftests for the dma-buf interfaces"
index 265303a..f6a2f42 100644 (file)
@@ -1493,7 +1493,6 @@ static int tegra_dma_probe(struct platform_device *pdev)
                irq = platform_get_irq(pdev, i);
                if (irq < 0) {
                        ret = irq;
-                       dev_err(&pdev->dev, "No irq resource for chan %d\n", i);
                        goto err_pm_disable;
                }
 
index 29906e3..14d0970 100644 (file)
@@ -341,7 +341,7 @@ edd_show_legacy_max_cylinder(struct edd_device *edev, char *buf)
        if (!info || !buf)
                return -EINVAL;
 
-       p += snprintf(p, left, "%u\n", info->legacy_max_cylinder);
+       p += scnprintf(p, left, "%u\n", info->legacy_max_cylinder);
        return (p - buf);
 }
 
@@ -356,7 +356,7 @@ edd_show_legacy_max_head(struct edd_device *edev, char *buf)
        if (!info || !buf)
                return -EINVAL;
 
-       p += snprintf(p, left, "%u\n", info->legacy_max_head);
+       p += scnprintf(p, left, "%u\n", info->legacy_max_head);
        return (p - buf);
 }
 
@@ -371,7 +371,7 @@ edd_show_legacy_sectors_per_track(struct edd_device *edev, char *buf)
        if (!info || !buf)
                return -EINVAL;
 
-       p += snprintf(p, left, "%u\n", info->legacy_sectors_per_track);
+       p += scnprintf(p, left, "%u\n", info->legacy_sectors_per_track);
        return (p - buf);
 }
 
index b1af0de..9d25129 100644 (file)
@@ -101,7 +101,7 @@ void cper_print_bits(const char *pfx, unsigned int bits,
                if (!len)
                        len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
                else
-                       len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
+                       len += scnprintf(buf+len, sizeof(buf)-len, ", %s", str);
        }
        if (len)
                printk("%s\n", buf);
index db0c1a9..fc9f8ab 100644 (file)
@@ -75,14 +75,12 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 
        if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) {
                /*
-                * If CONFIG_DEBUG_ALIGN_RODATA is not set, produce a
-                * displacement in the interval [0, MIN_KIMG_ALIGN) that
-                * doesn't violate this kernel's de-facto alignment
+                * Produce a displacement in the interval [0, MIN_KIMG_ALIGN)
+                * that doesn't violate this kernel's de-facto alignment
                 * constraints.
                 */
                u32 mask = (MIN_KIMG_ALIGN - 1) & ~(EFI_KIMG_ALIGN - 1);
-               u32 offset = !IS_ENABLED(CONFIG_DEBUG_ALIGN_RODATA) ?
-                            (phys_seed >> 32) & mask : TEXT_OFFSET;
+               u32 offset = (phys_seed >> 32) & mask;
 
                /*
                 * With CONFIG_RANDOMIZE_TEXT_OFFSET=y, TEXT_OFFSET may not
index cc90a74..67d2694 100644 (file)
@@ -25,7 +25,7 @@
 #define EFI_ALLOC_ALIGN                EFI_PAGE_SIZE
 #endif
 
-#ifdef CONFIG_ARM
+#if defined(CONFIG_ARM) || defined(CONFIG_X86)
 #define __efistub_global       __section(.data)
 #else
 #define __efistub_global
index d4c7e5f..ea66b1f 100644 (file)
  */
 #define EFI_READ_CHUNK_SIZE    SZ_1M
 
+struct finfo {
+       efi_file_info_t info;
+       efi_char16_t    filename[MAX_FILENAME_SIZE];
+};
+
 static efi_status_t efi_open_file(efi_file_protocol_t *volume,
-                                 efi_char16_t *filename_16,
+                                 struct finfo *fi,
                                  efi_file_protocol_t **handle,
                                  unsigned long *file_size)
 {
-       struct {
-               efi_file_info_t info;
-               efi_char16_t    filename[MAX_FILENAME_SIZE];
-       } finfo;
        efi_guid_t info_guid = EFI_FILE_INFO_ID;
        efi_file_protocol_t *fh;
        unsigned long info_sz;
        efi_status_t status;
 
-       status = volume->open(volume, &fh, filename_16, EFI_FILE_MODE_READ, 0);
+       status = volume->open(volume, &fh, fi->filename, EFI_FILE_MODE_READ, 0);
        if (status != EFI_SUCCESS) {
                pr_efi_err("Failed to open file: ");
-               efi_char16_printk(filename_16);
+               efi_char16_printk(fi->filename);
                efi_printk("\n");
                return status;
        }
 
-       info_sz = sizeof(finfo);
-       status = fh->get_info(fh, &info_guid, &info_sz, &finfo);
+       info_sz = sizeof(struct finfo);
+       status = fh->get_info(fh, &info_guid, &info_sz, fi);
        if (status != EFI_SUCCESS) {
                pr_efi_err("Failed to get file info\n");
                fh->close(fh);
@@ -60,7 +61,7 @@ static efi_status_t efi_open_file(efi_file_protocol_t *volume,
        }
 
        *handle = fh;
-       *file_size = finfo.info.file_size;
+       *file_size = fi->info.file_size;
        return EFI_SUCCESS;
 }
 
@@ -146,13 +147,13 @@ static efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
 
        alloc_addr = alloc_size = 0;
        do {
-               efi_char16_t filename[MAX_FILENAME_SIZE];
+               struct finfo fi;
                unsigned long size;
                void *addr;
 
                offset = find_file_option(cmdline, cmdline_len,
                                          optstr, optstr_size,
-                                         filename, ARRAY_SIZE(filename));
+                                         fi.filename, ARRAY_SIZE(fi.filename));
 
                if (!offset)
                        break;
@@ -166,7 +167,7 @@ static efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
                                return status;
                }
 
-               status = efi_open_file(volume, filename, &file, &size);
+               status = efi_open_file(volume, &fi, &file, &size);
                if (status != EFI_SUCCESS)
                        goto err_close_volume;
 
index 8d3a707..05ccb22 100644 (file)
@@ -20,7 +20,7 @@
 /* Maximum physical address for 64-bit kernel with 4-level paging */
 #define MAXMEM_X86_64_4LEVEL (1ull << 46)
 
-static efi_system_table_t *sys_table;
+static efi_system_table_t *sys_table __efistub_global;
 extern const bool efi_is64;
 extern u32 image_offset;
 
@@ -392,8 +392,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
        image_base = efi_table_attr(image, image_base);
        image_offset = (void *)startup_32 - image_base;
 
-       hdr = &((struct boot_params *)image_base)->hdr;
-
        status = efi_allocate_pages(0x4000, (unsigned long *)&boot_params, ULONG_MAX);
        if (status != EFI_SUCCESS) {
                efi_printk("Failed to allocate lowmem for boot params\n");
@@ -742,8 +740,15 @@ unsigned long efi_main(efi_handle_t handle,
         * now use KERNEL_IMAGE_SIZE, which will be 512MiB, the same as what
         * KASLR uses.
         *
-        * Also relocate it if image_offset is zero, i.e. we weren't loaded by
-        * LoadImage, but we are not aligned correctly.
+        * Also relocate it if image_offset is zero, i.e. the kernel wasn't
+        * loaded by LoadImage, but rather by a bootloader that called the
+        * handover entry. The reason we must always relocate in this case is
+        * to handle the case of systemd-boot booting a unified kernel image,
+        * which is a PE executable that contains the bzImage and an initrd as
+        * COFF sections. The initrd section is placed after the bzImage
+        * without ensuring that there are at least init_size bytes available
+        * for the bzImage, and thus the compressed kernel's startup code may
+        * overwrite the initrd unless it is moved out of the way.
         */
 
        buffer_start = ALIGN(bzimage_addr - image_offset,
@@ -753,8 +758,7 @@ unsigned long efi_main(efi_handle_t handle,
        if ((buffer_start < LOAD_PHYSICAL_ADDR)                              ||
            (IS_ENABLED(CONFIG_X86_32) && buffer_end > KERNEL_IMAGE_SIZE)    ||
            (IS_ENABLED(CONFIG_X86_64) && buffer_end > MAXMEM_X86_64_4LEVEL) ||
-           (image_offset == 0 && !IS_ALIGNED(bzimage_addr,
-                                             hdr->kernel_alignment))) {
+           (image_offset == 0)) {
                status = efi_relocate_kernel(&bzimage_addr,
                                             hdr->init_size, hdr->init_size,
                                             hdr->pref_address,
index faa3e71..559dc24 100644 (file)
@@ -2340,8 +2340,6 @@ static int amdgpu_device_ip_suspend_phase1(struct amdgpu_device *adev)
 {
        int i, r;
 
-       amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
-       amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE);
 
        for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
                if (!adev->ip_blocks[i].status.valid)
@@ -3356,6 +3354,9 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon)
                }
        }
 
+       amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
+       amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE);
+
        amdgpu_amdkfd_suspend(adev, !fbcon);
 
        amdgpu_ras_suspend(adev);
index f197f1b..abe94a5 100644 (file)
@@ -89,7 +89,8 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
                        adev->pm.ac_power = true;
                else
                        adev->pm.ac_power = false;
-               if (adev->powerplay.pp_funcs->enable_bapm)
+               if (adev->powerplay.pp_funcs &&
+                   adev->powerplay.pp_funcs->enable_bapm)
                        amdgpu_dpm_enable_bapm(adev, adev->pm.ac_power);
                mutex_unlock(&adev->pm.mutex);
 
index be50867..deaa268 100644 (file)
@@ -818,7 +818,7 @@ static int psp_ras_initialize(struct psp_context *psp)
 
        if (!psp->adev->psp.ta_ras_ucode_size ||
            !psp->adev->psp.ta_ras_start_addr) {
-               dev_warn(psp->adev->dev, "RAS: ras ta ucode is not available\n");
+               dev_info(psp->adev->dev, "RAS: optional ras ta ucode is not available\n");
                return 0;
        }
 
@@ -902,7 +902,7 @@ static int psp_hdcp_initialize(struct psp_context *psp)
 
        if (!psp->adev->psp.ta_hdcp_ucode_size ||
            !psp->adev->psp.ta_hdcp_start_addr) {
-               dev_warn(psp->adev->dev, "HDCP: hdcp ta ucode is not available\n");
+               dev_info(psp->adev->dev, "HDCP: optional hdcp ta ucode is not available\n");
                return 0;
        }
 
@@ -1048,7 +1048,7 @@ static int psp_dtm_initialize(struct psp_context *psp)
 
        if (!psp->adev->psp.ta_dtm_ucode_size ||
            !psp->adev->psp.ta_dtm_start_addr) {
-               dev_warn(psp->adev->dev, "DTM: dtm ta ucode is not available\n");
+               dev_info(psp->adev->dev, "DTM: optional dtm ta ucode is not available\n");
                return 0;
        }
 
index 3c32a94..ab379b4 100644 (file)
@@ -1424,12 +1424,22 @@ static void amdgpu_ras_do_recovery(struct work_struct *work)
 {
        struct amdgpu_ras *ras =
                container_of(work, struct amdgpu_ras, recovery_work);
+       struct amdgpu_device *remote_adev = NULL;
+       struct amdgpu_device *adev = ras->adev;
+       struct list_head device_list, *device_list_handle =  NULL;
+       struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev, false);
+
+       /* Build list of devices to query RAS related errors */
+       if  (hive && adev->gmc.xgmi.num_physical_nodes > 1) {
+               device_list_handle = &hive->device_list;
+       } else {
+               list_add_tail(&adev->gmc.xgmi.head, &device_list);
+               device_list_handle = &device_list;
+       }
 
-       /*
-        * Query and print non zero error counter per IP block for
-        * awareness before recovering GPU.
-        */
-       amdgpu_ras_log_on_err_counter(ras->adev);
+       list_for_each_entry(remote_adev, device_list_handle, gmc.xgmi.head) {
+               amdgpu_ras_log_on_err_counter(remote_adev);
+       }
 
        if (amdgpu_device_should_recover_gpu(ras->adev))
                amdgpu_device_gpu_recover(ras->adev, 0);
index c8f2aa1..d78059f 100644 (file)
@@ -279,7 +279,7 @@ static const struct soc15_reg_golden golden_settings_gc_10_1_2_nv12[] =
 
 #define DEFAULT_SH_MEM_CONFIG \
        ((SH_MEM_ADDRESS_MODE_64 << SH_MEM_CONFIG__ADDRESS_MODE__SHIFT) | \
-        (SH_MEM_ALIGNMENT_MODE_UNALIGNED << SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT) | \
+        (SH_MEM_ALIGNMENT_MODE_DWORD << SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT) | \
         (SH_MEM_RETRY_MODE_ALL << SH_MEM_CONFIG__RETRY_MODE__SHIFT) | \
         (3 << SH_MEM_CONFIG__INITIAL_INST_PREFETCH__SHIFT))
 
@@ -1113,7 +1113,7 @@ static int gfx_v10_0_mec_init(struct amdgpu_device *adev)
                return r;
        }
 
-       memset(hpd, 0, adev->gfx.mec.hpd_eop_obj->tbo.mem.size);
+       memset(hpd, 0, mec_hpd_size);
 
        amdgpu_bo_kunmap(adev->gfx.mec.hpd_eop_obj);
        amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj);
@@ -4104,6 +4104,12 @@ static void gfx_v10_0_update_medium_grain_clock_gating(struct amdgpu_device *ade
 
        /* It is disabled by HW by default */
        if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) {
+               /* 0 - Disable some blocks' MGCG */
+               WREG32_SOC15(GC, 0, mmGRBM_GFX_INDEX, 0xe0000000);
+               WREG32_SOC15(GC, 0, mmCGTT_WD_CLK_CTRL, 0xff000000);
+               WREG32_SOC15(GC, 0, mmCGTT_VGT_CLK_CTRL, 0xff000000);
+               WREG32_SOC15(GC, 0, mmCGTT_IA_CLK_CTRL, 0xff000000);
+
                /* 1 - RLC_CGTT_MGCG_OVERRIDE */
                def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE);
                data &= ~(RLC_CGTT_MGCG_OVERRIDE__GRBM_CGTT_SCLK_OVERRIDE_MASK |
@@ -4143,19 +4149,20 @@ static void gfx_v10_0_update_medium_grain_clock_gating(struct amdgpu_device *ade
                if (def != data)
                        WREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE, data);
 
-               /* 2 - disable MGLS in RLC */
+               /* 2 - disable MGLS in CP */
+               data = RREG32_SOC15(GC, 0, mmCP_MEM_SLP_CNTL);
+               if (data & CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK) {
+                       data &= ~CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK;
+                       WREG32_SOC15(GC, 0, mmCP_MEM_SLP_CNTL, data);
+               }
+
+               /* 3 - disable MGLS in RLC */
                data = RREG32_SOC15(GC, 0, mmRLC_MEM_SLP_CNTL);
                if (data & RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK) {
                        data &= ~RLC_MEM_SLP_CNTL__RLC_MEM_LS_EN_MASK;
                        WREG32_SOC15(GC, 0, mmRLC_MEM_SLP_CNTL, data);
                }
 
-               /* 3 - disable MGLS in CP */
-               data = RREG32_SOC15(GC, 0, mmCP_MEM_SLP_CNTL);
-               if (data & CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK) {
-                       data &= ~CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK;
-                       WREG32_SOC15(GC, 0, mmCP_MEM_SLP_CNTL, data);
-               }
        }
 }
 
@@ -4266,7 +4273,7 @@ static int gfx_v10_0_update_gfx_clock_gating(struct amdgpu_device *adev,
                /* ===  CGCG /CGLS for GFX 3D Only === */
                gfx_v10_0_update_3d_clock_gating(adev, enable);
                /* ===  MGCG + MGLS === */
-               gfx_v10_0_update_medium_grain_clock_gating(adev, enable);
+               /* gfx_v10_0_update_medium_grain_clock_gating(adev, enable); */
        }
 
        if (adev->cg_flags &
index 37c8231..e6b113e 100644 (file)
@@ -1217,6 +1217,8 @@ static void gfx_v9_0_check_fw_write_wait(struct amdgpu_device *adev)
                        adev->gfx.mec_fw_write_wait = true;
                break;
        default:
+               adev->gfx.me_fw_write_wait = true;
+               adev->gfx.mec_fw_write_wait = true;
                break;
        }
 }
@@ -1946,7 +1948,7 @@ static int gfx_v9_0_mec_init(struct amdgpu_device *adev)
                return r;
        }
 
-       memset(hpd, 0, adev->gfx.mec.hpd_eop_obj->tbo.mem.size);
+       memset(hpd, 0, mec_hpd_size);
 
        amdgpu_bo_kunmap(adev->gfx.mec.hpd_eop_obj);
        amdgpu_bo_unreserve(adev->gfx.mec.hpd_eop_obj);
index cceb46f..dce945e 100644 (file)
@@ -710,14 +710,16 @@ static int gfx_v9_4_query_utc_edc_status(struct amdgpu_device *adev,
 
                sec_count = REG_GET_FIELD(data, VML2_MEM_ECC_CNTL, SEC_COUNT);
                if (sec_count) {
-                       DRM_INFO("Instance[%d]: SubBlock %s, SEC %d\n", i,
+                       dev_info(adev->dev,
+                                "Instance[%d]: SubBlock %s, SEC %d\n", i,
                                 vml2_mems[i], sec_count);
                        err_data->ce_count += sec_count;
                }
 
                ded_count = REG_GET_FIELD(data, VML2_MEM_ECC_CNTL, DED_COUNT);
                if (ded_count) {
-                       DRM_INFO("Instance[%d]: SubBlock %s, DED %d\n", i,
+                       dev_info(adev->dev,
+                                "Instance[%d]: SubBlock %s, DED %d\n", i,
                                 vml2_mems[i], ded_count);
                        err_data->ue_count += ded_count;
                }
index 0d413fa..c0e3efc 100644 (file)
@@ -1539,8 +1539,11 @@ static const struct soc15_reg_entry mmhub_v9_4_edc_cnt_regs[] = {
        { SOC15_REG_ENTRY(MMHUB, 0, mmMMEA7_EDC_CNT3), 0, 0, 0 },
 };
 
-static int mmhub_v9_4_get_ras_error_count(const struct soc15_reg_entry *reg,
-       uint32_t value, uint32_t *sec_count, uint32_t *ded_count)
+static int mmhub_v9_4_get_ras_error_count(struct amdgpu_device *adev,
+                                         const struct soc15_reg_entry *reg,
+                                         uint32_t value,
+                                         uint32_t *sec_count,
+                                         uint32_t *ded_count)
 {
        uint32_t i;
        uint32_t sec_cnt, ded_cnt;
@@ -1553,7 +1556,7 @@ static int mmhub_v9_4_get_ras_error_count(const struct soc15_reg_entry *reg,
                                mmhub_v9_4_ras_fields[i].sec_count_mask) >>
                                mmhub_v9_4_ras_fields[i].sec_count_shift;
                if (sec_cnt) {
-                       DRM_INFO("MMHUB SubBlock %s, SEC %d\n",
+                       dev_info(adev->dev, "MMHUB SubBlock %s, SEC %d\n",
                                mmhub_v9_4_ras_fields[i].name,
                                sec_cnt);
                        *sec_count += sec_cnt;
@@ -1563,7 +1566,7 @@ static int mmhub_v9_4_get_ras_error_count(const struct soc15_reg_entry *reg,
                                mmhub_v9_4_ras_fields[i].ded_count_mask) >>
                                mmhub_v9_4_ras_fields[i].ded_count_shift;
                if (ded_cnt) {
-                       DRM_INFO("MMHUB SubBlock %s, DED %d\n",
+                       dev_info(adev->dev, "MMHUB SubBlock %s, DED %d\n",
                                mmhub_v9_4_ras_fields[i].name,
                                ded_cnt);
                        *ded_count += ded_cnt;
@@ -1588,7 +1591,7 @@ static void mmhub_v9_4_query_ras_error_count(struct amdgpu_device *adev,
                reg_value =
                        RREG32(SOC15_REG_ENTRY_OFFSET(mmhub_v9_4_edc_cnt_regs[i]));
                if (reg_value)
-                       mmhub_v9_4_get_ras_error_count(&mmhub_v9_4_edc_cnt_regs[i],
+                       mmhub_v9_4_get_ras_error_count(adev, &mmhub_v9_4_edc_cnt_regs[i],
                                reg_value, &sec_count, &ded_count);
        }
 
index d5386f1..05bc6d9 100644 (file)
@@ -1112,9 +1112,9 @@ kfd_gtt_out:
        return 0;
 
 kfd_gtt_no_free_chunk:
-       pr_debug("Allocation failed with mem_obj = %p\n", mem_obj);
+       pr_debug("Allocation failed with mem_obj = %p\n", *mem_obj);
        mutex_unlock(&kfd->gtt_sa_lock);
-       kfree(mem_obj);
+       kfree(*mem_obj);
        return -ENOMEM;
 }
 
index d3674d8..f7c5cdc 100644 (file)
@@ -3639,6 +3639,9 @@ fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
        case DRM_FORMAT_NV12:
                plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb;
                break;
+       case DRM_FORMAT_P010:
+               plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb;
+               break;
        default:
                DRM_ERROR(
                        "Unsupported screen format %s\n",
@@ -4720,10 +4723,10 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
 static int
 amdgpu_dm_connector_late_register(struct drm_connector *connector)
 {
+#if defined(CONFIG_DEBUG_FS)
        struct amdgpu_dm_connector *amdgpu_dm_connector =
                to_amdgpu_dm_connector(connector);
 
-#if defined(CONFIG_DEBUG_FS)
        connector_debugfs_init(amdgpu_dm_connector);
 #endif
 
@@ -5535,6 +5538,8 @@ static int get_plane_formats(const struct drm_plane *plane,
 
                if (plane_cap && plane_cap->pixel_format_support.nv12)
                        formats[num_formats++] = DRM_FORMAT_NV12;
+               if (plane_cap && plane_cap->pixel_format_support.p010)
+                       formats[num_formats++] = DRM_FORMAT_P010;
                break;
 
        case DRM_PLANE_TYPE_OVERLAY:
@@ -5587,12 +5592,15 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
        }
 
        if (plane->type == DRM_PLANE_TYPE_PRIMARY &&
-           plane_cap && plane_cap->pixel_format_support.nv12) {
+           plane_cap &&
+           (plane_cap->pixel_format_support.nv12 ||
+            plane_cap->pixel_format_support.p010)) {
                /* This only affects YUV formats. */
                drm_plane_create_color_properties(
                        plane,
                        BIT(DRM_COLOR_YCBCR_BT601) |
-                       BIT(DRM_COLOR_YCBCR_BT709),
+                       BIT(DRM_COLOR_YCBCR_BT709) |
+                       BIT(DRM_COLOR_YCBCR_BT2020),
                        BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
                        BIT(DRM_COLOR_YCBCR_FULL_RANGE),
                        DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE);
@@ -5921,7 +5929,8 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
                                adev->mode_info.underscan_vborder_property,
                                0);
 
-       drm_connector_attach_max_bpc_property(&aconnector->base, 8, 16);
+       if (!aconnector->mst_port)
+               drm_connector_attach_max_bpc_property(&aconnector->base, 8, 16);
 
        /* This defaults to the max in the range, but we want 8bpc for non-edp. */
        aconnector->base.state->max_bpc = (connector_type == DRM_MODE_CONNECTOR_eDP) ? 16 : 8;
@@ -5940,8 +5949,9 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
                        &aconnector->base.base,
                        dm->ddev->mode_config.hdr_output_metadata_property, 0);
 
-               drm_connector_attach_vrr_capable_property(
-                       &aconnector->base);
+               if (!aconnector->mst_port)
+                       drm_connector_attach_vrr_capable_property(&aconnector->base);
+
 #ifdef CONFIG_DRM_AMD_DC_HDCP
                if (adev->dm.hdcp_workqueue)
                        drm_connector_attach_content_protection_property(&aconnector->base, true);
@@ -6264,12 +6274,6 @@ static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
            y <= -amdgpu_crtc->max_cursor_height)
                return 0;
 
-       if (crtc->primary->state) {
-               /* avivo cursor are offset into the total surface */
-               x += crtc->primary->state->src_x >> 16;
-               y += crtc->primary->state->src_y >> 16;
-       }
-
        if (x < 0) {
                xorigin = min(-x, amdgpu_crtc->max_cursor_width - 1);
                x = 0;
@@ -6279,6 +6283,7 @@ static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
                y = 0;
        }
        position->enable = true;
+       position->translate_by_source = true;
        position->x = x;
        position->y = y;
        position->x_hotspot = xorigin;
index 5b70ed3..78e1c11 100644 (file)
@@ -192,10 +192,13 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
                                            &hdcp_work->srm_version);
 
                        display->adjust.disable = 0;
-                       if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0)
+                       if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0) {
+                               hdcp_w->link.adjust.hdcp1.disable = 0;
                                hdcp_w->link.adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_0;
-                       else if (content_type == DRM_MODE_HDCP_CONTENT_TYPE1)
+                       } else if (content_type == DRM_MODE_HDCP_CONTENT_TYPE1) {
+                               hdcp_w->link.adjust.hdcp1.disable = 1;
                                hdcp_w->link.adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_1;
+                       }
 
                        schedule_delayed_work(&hdcp_w->property_validate_dwork,
                                              msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS));
@@ -263,7 +266,7 @@ static void event_callback(struct work_struct *work)
 
        mutex_lock(&hdcp_work->mutex);
 
-       cancel_delayed_work(&hdcp_work->watchdog_timer_dwork);
+       cancel_delayed_work(&hdcp_work->callback_dwork);
 
        mod_hdcp_process_event(&hdcp_work->hdcp, MOD_HDCP_EVENT_CALLBACK,
                               &hdcp_work->output);
@@ -344,6 +347,8 @@ static void event_watchdog_timer(struct work_struct *work)
 
        mutex_lock(&hdcp_work->mutex);
 
+       cancel_delayed_work(&hdcp_work->watchdog_timer_dwork);
+
        mod_hdcp_process_event(&hdcp_work->hdcp,
                               MOD_HDCP_EVENT_WATCHDOG_TIMEOUT,
                               &hdcp_work->output);
@@ -414,7 +419,8 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
        link->dp.rev = aconnector->dc_link->dpcd_caps.dpcd_rev.raw;
        link->dp.mst_supported = config->mst_supported;
        display->adjust.disable = 1;
-       link->adjust.auth_delay = 2;
+       link->adjust.auth_delay = 3;
+       link->adjust.hdcp1.disable = 0;
 
        hdcp_update_display(hdcp_work, link_index, aconnector, DRM_MODE_HDCP_CONTENT_TYPE0, false);
 }
index e8208df..fabbe78 100644 (file)
@@ -410,6 +410,14 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
        drm_connector_attach_encoder(&aconnector->base,
                                     &aconnector->mst_encoder->base);
 
+       connector->max_bpc_property = master->base.max_bpc_property;
+       if (connector->max_bpc_property)
+               drm_connector_attach_max_bpc_property(connector, 8, 16);
+
+       connector->vrr_capable_property = master->base.vrr_capable_property;
+       if (connector->vrr_capable_property)
+               drm_connector_attach_vrr_capable_property(connector);
+
        drm_object_attach_property(
                &connector->base,
                dev->mode_config.path_property,
index ab267dd..24c5765 100644 (file)
@@ -643,7 +643,7 @@ static void rn_clk_mgr_helper_populate_bw_params(struct clk_bw_params *bw_params
        /* Find lowest DPM, FCLK is filled in reverse order*/
 
        for (i = PP_SMU_NUM_FCLK_DPM_LEVELS - 1; i >= 0; i--) {
-               if (clock_table->FClocks[i].Freq != 0) {
+               if (clock_table->FClocks[i].Freq != 0 && clock_table->FClocks[i].Vol != 0) {
                        j = i;
                        break;
                }
index 2ffb221..8489f1e 100644 (file)
@@ -283,6 +283,8 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
        int i = 0;
        bool ret = false;
 
+       stream->adjust = *adjust;
+
        for (i = 0; i < MAX_PIPES; i++) {
                struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
 
@@ -1360,6 +1362,26 @@ bool dc_commit_state(struct dc *dc, struct dc_state *context)
        return (result == DC_OK);
 }
 
+static bool is_flip_pending_in_pipes(struct dc *dc, struct dc_state *context)
+{
+       int i;
+       struct pipe_ctx *pipe;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               pipe = &context->res_ctx.pipe_ctx[i];
+
+               if (!pipe->plane_state)
+                       continue;
+
+               /* Must set to false to start with, due to OR in update function */
+               pipe->plane_state->status.is_flip_pending = false;
+               dc->hwss.update_pending_status(pipe);
+               if (pipe->plane_state->status.is_flip_pending)
+                       return true;
+       }
+       return false;
+}
+
 bool dc_post_update_surfaces_to_stream(struct dc *dc)
 {
        int i;
@@ -1370,6 +1392,9 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
 
        post_surface_trace(dc);
 
+       if (is_flip_pending_in_pipes(dc, context))
+               return true;
+
        for (i = 0; i < dc->res_pool->pipe_count; i++)
                if (context->res_ctx.pipe_ctx[i].stream == NULL ||
                    context->res_ctx.pipe_ctx[i].plane_state == NULL) {
@@ -1703,6 +1728,9 @@ static enum surface_update_type det_surface_update(const struct dc *dc,
        if (u->coeff_reduction_factor)
                update_flags->bits.coeff_reduction_change = 1;
 
+       if (u->gamut_remap_matrix)
+               update_flags->bits.gamut_remap_change = 1;
+
        if (u->gamma) {
                enum surface_pixel_format format = SURFACE_PIXEL_FORMAT_GRPH_BEGIN;
 
@@ -1728,7 +1756,8 @@ static enum surface_update_type det_surface_update(const struct dc *dc,
 
        if (update_flags->bits.input_csc_change
                        || update_flags->bits.coeff_reduction_change
-                       || update_flags->bits.gamma_change) {
+                       || update_flags->bits.gamma_change
+                       || update_flags->bits.gamut_remap_change) {
                type = UPDATE_TYPE_FULL;
                elevate_update_type(&overall_type, type);
        }
@@ -1832,8 +1861,9 @@ enum surface_update_type dc_check_update_surfaces_for_stream(
                // Else we fallback to mem compare.
                } else if (memcmp(&dc->current_state->bw_ctx.bw.dcn.clk, &dc->clk_mgr->clks, offsetof(struct dc_clocks, prev_p_state_change_support)) != 0) {
                        dc->optimized_required = true;
-               } else if (dc->wm_optimized_required)
-                       dc->optimized_required = true;
+               }
+
+               dc->optimized_required |= dc->wm_optimized_required;
        }
 
        return type;
@@ -1973,6 +2003,10 @@ static void copy_surface_update_to_plane(
        if (srf_update->coeff_reduction_factor)
                surface->coeff_reduction_factor =
                        *srf_update->coeff_reduction_factor;
+
+       if (srf_update->gamut_remap_matrix)
+               surface->gamut_remap_matrix =
+                       *srf_update->gamut_remap_matrix;
 }
 
 static void copy_stream_update_to_stream(struct dc *dc,
@@ -2431,7 +2465,7 @@ void dc_commit_updates_for_stream(struct dc *dc,
        enum surface_update_type update_type;
        struct dc_state *context;
        struct dc_context *dc_ctx = dc->ctx;
-       int i;
+       int i, j;
 
        stream_status = dc_stream_get_status(stream);
        context = dc->current_state;
@@ -2469,6 +2503,17 @@ void dc_commit_updates_for_stream(struct dc *dc,
 
                copy_surface_update_to_plane(surface, &srf_updates[i]);
 
+               if (update_type >= UPDATE_TYPE_MED) {
+                       for (j = 0; j < dc->res_pool->pipe_count; j++) {
+                               struct pipe_ctx *pipe_ctx =
+                                       &context->res_ctx.pipe_ctx[j];
+
+                               if (pipe_ctx->plane_state != surface)
+                                       continue;
+
+                               resource_build_scaling_params(pipe_ctx);
+                       }
+               }
        }
 
        copy_stream_update_to_stream(dc, context, stream, stream_update);
index 75c7ce4..f4bcc71 100644 (file)
@@ -1077,6 +1077,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
         * on certain displays, such as the Sharp 4k
         */
        pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
+       pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha;
 
        pipe_ctx->plane_res.scl_data.recout.x += timing->h_border_left;
        pipe_ctx->plane_res.scl_data.recout.y += timing->v_border_top;
index d3ceb39..1935cf6 100644 (file)
@@ -726,6 +726,7 @@ union surface_update_flags {
                uint32_t output_tf_change:1;
                uint32_t pixel_format_change:1;
                uint32_t plane_size_change:1;
+               uint32_t gamut_remap_change:1;
 
                /* Full updates */
                uint32_t new_plane:1;
@@ -760,6 +761,7 @@ struct dc_plane_state {
        struct dc_csc_transform input_csc_color_matrix;
        struct fixed31_32 coeff_reduction_factor;
        struct fixed31_32 hdr_mult;
+       struct colorspace_transform gamut_remap_matrix;
 
        // TODO: No longer used, remove
        struct dc_hdr_static_metadata hdr_static_ctx;
@@ -839,6 +841,7 @@ struct dc_surface_update {
        const struct dc_transfer_func *func_shaper;
        const struct dc_3dlut *lut3d_func;
        const struct dc_transfer_func *blend_tf;
+       const struct colorspace_transform *gamut_remap_matrix;
 };
 
 /*
index 25c50bc..a8dc308 100644 (file)
@@ -385,6 +385,8 @@ struct dc_cursor_position {
         */
        bool enable;
 
+       /* Translate cursor x/y by the source rectangle for each plane. */
+       bool translate_by_source;
 };
 
 struct dc_cursor_mi_param {
index 0976e37..c279982 100644 (file)
@@ -2685,6 +2685,23 @@ void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx)
                .mirror = pipe_ctx->plane_state->horizontal_mirror
        };
 
+       /**
+        * If the cursor's source viewport is clipped then we need to
+        * translate the cursor to appear in the correct position on
+        * the screen.
+        *
+        * This translation isn't affected by scaling so it needs to be
+        * done *after* we adjust the position for the scale factor.
+        *
+        * This is only done by opt-in for now since there are still
+        * some usecases like tiled display that might enable the
+        * cursor on both streams while expecting dc to clip it.
+        */
+       if (pos_cpy.translate_by_source) {
+               pos_cpy.x += pipe_ctx->plane_state->src_rect.x;
+               pos_cpy.y += pipe_ctx->plane_state->src_rect.y;
+       }
+
        if (pipe_ctx->plane_state->address.type
                        == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
                pos_cpy.enable = false;
index 9cc3314..b035754 100644 (file)
@@ -2004,6 +2004,12 @@ void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx)
                for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
                        adjust.temperature_matrix[i] =
                                pipe_ctx->stream->gamut_remap_matrix.matrix[i];
+       } else if (pipe_ctx->plane_state &&
+                  pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) {
+               adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
+               for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
+                       adjust.temperature_matrix[i] =
+                               pipe_ctx->plane_state->gamut_remap_matrix.matrix[i];
        }
 
        pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust);
@@ -3015,12 +3021,50 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx)
        int x_pos = pos_cpy.x;
        int y_pos = pos_cpy.y;
 
-       // translate cursor from stream space to plane space
+       /**
+        * DC cursor is stream space, HW cursor is plane space and drawn
+        * as part of the framebuffer.
+        *
+        * Cursor position can't be negative, but hotspot can be used to
+        * shift cursor out of the plane bounds. Hotspot must be smaller
+        * than the cursor size.
+        */
+
+       /**
+        * Translate cursor from stream space to plane space.
+        *
+        * If the cursor is scaled then we need to scale the position
+        * to be in the approximately correct place. We can't do anything
+        * about the actual size being incorrect, that's a limitation of
+        * the hardware.
+        */
        x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.width /
                        pipe_ctx->plane_state->dst_rect.width;
        y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.height /
                        pipe_ctx->plane_state->dst_rect.height;
 
+       /**
+        * If the cursor's source viewport is clipped then we need to
+        * translate the cursor to appear in the correct position on
+        * the screen.
+        *
+        * This translation isn't affected by scaling so it needs to be
+        * done *after* we adjust the position for the scale factor.
+        *
+        * This is only done by opt-in for now since there are still
+        * some usecases like tiled display that might enable the
+        * cursor on both streams while expecting dc to clip it.
+        */
+       if (pos_cpy.translate_by_source) {
+               x_pos += pipe_ctx->plane_state->src_rect.x;
+               y_pos += pipe_ctx->plane_state->src_rect.y;
+       }
+
+       /**
+        * If the position is negative then we need to add to the hotspot
+        * to shift the cursor outside the plane.
+        */
+
        if (x_pos < 0) {
                pos_cpy.x_hotspot -= x_pos;
                x_pos = 0;
index 63acb8f..17d96ec 100644 (file)
@@ -343,6 +343,23 @@ void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enab
 }
 
 /**
+ * optc1_set_timing_double_buffer() - DRR double buffering control
+ *
+ * Sets double buffer point for V_TOTAL, H_TOTAL, VTOTAL_MIN,
+ * VTOTAL_MAX, VTOTAL_MIN_SEL and VTOTAL_MAX_SEL registers.
+ *
+ * Options: any time,  start of frame, dp start of frame (range timing)
+ */
+void optc1_set_timing_double_buffer(struct timing_generator *optc, bool enable)
+{
+       struct optc *optc1 = DCN10TG_FROM_TG(optc);
+       uint32_t mode = enable ? 2 : 0;
+
+       REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL,
+                  OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mode);
+}
+
+/**
  * unblank_crtc
  * Call ASIC Control Object to UnBlank CRTC.
  */
@@ -1353,6 +1370,7 @@ void optc1_clear_optc_underflow(struct timing_generator *optc)
 void optc1_tg_init(struct timing_generator *optc)
 {
        optc1_set_blank_data_double_buffer(optc, true);
+       optc1_set_timing_double_buffer(optc, true);
        optc1_clear_optc_underflow(optc);
 }
 
index f277656..9a459a8 100644 (file)
@@ -185,6 +185,7 @@ struct dcn_optc_registers {
        SF(OTG0_OTG_GLOBAL_CONTROL0, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\
        SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\
        SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_BLANK_DATA_DOUBLE_BUFFER_EN, mask_sh),\
+       SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mask_sh),\
        SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\
        SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_START, mask_sh),\
        SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_END, mask_sh),\
@@ -643,6 +644,8 @@ bool optc1_is_optc_underflow_occurred(struct timing_generator *optc);
 
 void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enable);
 
+void optc1_set_timing_double_buffer(struct timing_generator *optc, bool enable);
+
 bool optc1_get_otg_active_size(struct timing_generator *optc,
                uint32_t *otg_active_width,
                uint32_t *otg_active_height);
index 261bdc3..07265ca 100644 (file)
@@ -552,7 +552,8 @@ static const struct dc_plane_cap plane_cap = {
        .pixel_format_support = {
                        .argb8888 = true,
                        .nv12 = true,
-                       .fp16 = true
+                       .fp16 = true,
+                       .p010 = true
        },
 
        .max_upscale_factor = {
@@ -584,7 +585,7 @@ static const struct dc_debug_options debug_defaults_drv = {
                .disable_pplib_clock_request = false,
                .disable_pplib_wm_range = false,
                .pplib_wm_report_mode = WM_REPORT_DEFAULT,
-               .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP,
+               .pipe_split_policy = MPC_SPLIT_DYNAMIC,
                .force_single_disp_pipe_split = true,
                .disable_dcc = DCC_ENABLE,
                .voltage_align_fclk = true,
index 2333182..22f421e 100644 (file)
@@ -1373,6 +1373,7 @@ static void dcn20_update_dchubp_dpp(
        }
 
        if (pipe_ctx->update_flags.bits.viewport ||
+                       (context == dc->current_state && plane_state->update_flags.bits.position_change) ||
                        (context == dc->current_state && plane_state->update_flags.bits.scaling_change) ||
                        (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) {
 
index a673952..5cdbba0 100644 (file)
@@ -1012,7 +1012,8 @@ static const struct dc_plane_cap plane_cap = {
        .pixel_format_support = {
                        .argb8888 = true,
                        .nv12 = true,
-                       .fp16 = true
+                       .fp16 = true,
+                       .p010 = true
        },
 
        .max_upscale_factor = {
@@ -3342,7 +3343,7 @@ void dcn20_cap_soc_clocks(
 void dcn20_update_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb,
                struct pp_smu_nv_clock_table *max_clocks, unsigned int *uclk_states, unsigned int num_states)
 {
-       struct _vcs_dpi_voltage_scaling_st calculated_states[MAX_CLOCK_LIMIT_STATES];
+       struct _vcs_dpi_voltage_scaling_st calculated_states[DC__VOLTAGE_STATES];
        int i;
        int num_calculated_states = 0;
        int min_dcfclk = 0;
index 51b5910..b25484a 100644 (file)
@@ -300,7 +300,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc = {
        .xfc_bus_transport_time_us = 4,
        .xfc_xbuf_latency_tolerance_us = 4,
        .use_urgent_burst_bw = 1,
-       .num_states = 9
+       .num_states = 8
 };
 
 #ifndef MAX
@@ -838,7 +838,8 @@ static const struct dc_plane_cap plane_cap = {
        .pixel_format_support = {
                        .argb8888 = true,
                        .nv12 = true,
-                       .fp16 = true
+                       .fp16 = true,
+                       .p010 = true
        },
 
        .max_upscale_factor = {
@@ -1376,21 +1377,8 @@ static void update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param
        unsigned int i, j, k;
        int closest_clk_lvl;
 
-       // diags does not retrieve proper values from SMU
-       // cap states to 5 and make state 5 the max state
-       if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) || IS_DIAG_DC(dc->ctx->dce_environment)) {
-               dcn2_1_soc.num_states = 5;
-
-               dcn2_1_soc.clock_limits[5].state = 5;
-               dcn2_1_soc.clock_limits[5].dcfclk_mhz = 810.0;
-               dcn2_1_soc.clock_limits[5].fabricclk_mhz = 1600.0;
-               dcn2_1_soc.clock_limits[5].dispclk_mhz = 1395.0;
-               dcn2_1_soc.clock_limits[5].dppclk_mhz = 1285.0;
-               dcn2_1_soc.clock_limits[5].phyclk_mhz = 1325.0;
-               dcn2_1_soc.clock_limits[5].socclk_mhz = 953.0;
-               dcn2_1_soc.clock_limits[5].dscclk_mhz = 489.0;
-               dcn2_1_soc.clock_limits[5].dram_speed_mts = 4266.0;
-       } else {
+       // Default clock levels are used for diags, which may lead to overclocking.
+       if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) && !IS_DIAG_DC(dc->ctx->dce_environment)) {
                dcn2_1_ip.max_num_otg = pool->base.res_cap->num_timing_generator;
                dcn2_1_ip.max_num_dpp = pool->base.pipe_count;
                dcn2_1_soc.num_chans = bw_params->num_channels;
@@ -1403,16 +1391,16 @@ static void update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param
                dcn2_1_soc.clock_limits[0].dram_speed_mts = clk_table->entries[0].memclk_mhz * 2;
 
                /*
-                * Other levels: find cloest DCN clocks that fit the given clock limit using dcfclk
-                * as indicater
+                * Other levels: find closest DCN clocks that fit the given clock limit using dcfclk
+                * as indicator
                 */
 
                closest_clk_lvl = -1;
                /* index currently being filled */
                k = 1;
                for (i = 1; i < clk_table->num_entries; i++) {
-                       /* loop backwards, skip duplicate state, +1 because SMU has precision issue */
-                       for (j = dcn2_1_soc.num_states - 2; j >= k; j--) {
+                       /* loop backwards, skip duplicate state*/
+                       for (j = dcn2_1_soc.num_states - 1; j >= k; j--) {
                                if ((unsigned int) dcn2_1_soc.clock_limits[j].dcfclk_mhz <= clk_table->entries[i].dcfclk_mhz) {
                                        closest_clk_lvl = j;
                                        break;
@@ -1437,13 +1425,13 @@ static void update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param
                                k++;
                        }
                }
-
-               /* duplicate last level */
-               dcn2_1_soc.clock_limits[k] = dcn2_1_soc.clock_limits[k - 1];
-               dcn2_1_soc.clock_limits[k].state = k;
-               dcn2_1_soc.num_states = k + 1;
+               dcn2_1_soc.num_states = k;
        }
 
+       /* duplicate last level */
+       dcn2_1_soc.clock_limits[dcn2_1_soc.num_states] = dcn2_1_soc.clock_limits[dcn2_1_soc.num_states - 1];
+       dcn2_1_soc.clock_limits[dcn2_1_soc.num_states].state = dcn2_1_soc.num_states;
+
        dml_init_instance(&dc->dml, &dcn2_1_soc, &dcn2_1_ip, DML_PROJECT_DCN21);
 }
 
index ea4cde9..2a19833 100644 (file)
@@ -29,7 +29,7 @@
 #define DC__PRESENT 1
 #define DC__PRESENT__1 1
 #define DC__NUM_DPP 4
-#define DC__VOLTAGE_STATES 7
+#define DC__VOLTAGE_STATES 9
 #define DC__NUM_DPP__4 1
 #define DC__NUM_DPP__0_PRESENT 1
 #define DC__NUM_DPP__1_PRESENT 1
index dfd3be4..687010c 100644 (file)
  * Authors: AMD
  *
  */
+
+#include "dc_features.h"
+
 #ifndef __DISPLAY_MODE_STRUCTS_H__
 #define __DISPLAY_MODE_STRUCTS_H__
 
-#define MAX_CLOCK_LIMIT_STATES 9
-
 typedef struct _vcs_dpi_voltage_scaling_st voltage_scaling_st;
 typedef struct _vcs_dpi_soc_bounding_box_st soc_bounding_box_st;
 typedef struct _vcs_dpi_ip_params_st ip_params_st;
@@ -68,7 +69,7 @@ struct _vcs_dpi_voltage_scaling_st {
 };
 
 struct _vcs_dpi_soc_bounding_box_st {
-       struct _vcs_dpi_voltage_scaling_st clock_limits[MAX_CLOCK_LIMIT_STATES];
+       struct _vcs_dpi_voltage_scaling_st clock_limits[DC__VOLTAGE_STATES];
        unsigned int num_states;
        double sr_exit_time_us;
        double sr_enter_plus_exit_time_us;
index 8a87d0e..2359e88 100644 (file)
 #define RAVEN2_A0 0x81
 #define RAVEN1_F0 0xF0
 #define RAVEN_UNKNOWN 0xFF
+#define RENOIR_A0 0x91
 #ifndef ASICREV_IS_RAVEN
 #define ASICREV_IS_RAVEN(eChipRev) ((eChipRev >= RAVEN_A0) && eChipRev < RAVEN_UNKNOWN)
 #endif
@@ -171,8 +172,6 @@ enum {
 #define ASICREV_IS_NAVI10_P(eChipRev)        (eChipRev < NV_NAVI12_P_A0)
 #define ASICREV_IS_NAVI12_P(eChipRev)        ((eChipRev >= NV_NAVI12_P_A0) && (eChipRev < NV_NAVI14_M_A0))
 #define ASICREV_IS_NAVI14_M(eChipRev)        ((eChipRev >= NV_NAVI14_M_A0) && (eChipRev < NV_UNKNOWN))
-#define RENOIR_A0 0x91
-#define DEVICE_ID_RENOIR_1636 0x1636   // Renoir
 #define ASICREV_IS_RENOIR(eChipRev) ((eChipRev >= RENOIR_A0) && (eChipRev < RAVEN1_F0))
 
 /*
@@ -183,6 +182,9 @@ enum {
 #define DEVICE_ID_TEMASH_9839 0x9839
 #define DEVICE_ID_TEMASH_983D 0x983D
 
+/* RENOIR */
+#define DEVICE_ID_RENOIR_1636 0x1636
+
 /* Asic Family IDs for different asic family. */
 #define FAMILY_CI 120 /* Sea Islands: Hawaii (P), Bonaire (M) */
 #define FAMILY_KV 125 /* Fusion => Kaveri: Spectre, Spooky; Kabini: Kalindi */
index 4e54282..c33454a 100644 (file)
@@ -734,6 +734,7 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
 {
        struct core_freesync *core_freesync = NULL;
        unsigned long long nominal_field_rate_in_uhz = 0;
+       unsigned long long rounded_nominal_in_uhz = 0;
        unsigned int refresh_range = 0;
        unsigned long long min_refresh_in_uhz = 0;
        unsigned long long max_refresh_in_uhz = 0;
@@ -750,17 +751,20 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
        min_refresh_in_uhz = in_config->min_refresh_in_uhz;
        max_refresh_in_uhz = in_config->max_refresh_in_uhz;
 
-       // Don't allow min > max
-       if (min_refresh_in_uhz > max_refresh_in_uhz)
-               min_refresh_in_uhz = max_refresh_in_uhz;
-
        // Full range may be larger than current video timing, so cap at nominal
        if (max_refresh_in_uhz > nominal_field_rate_in_uhz)
                max_refresh_in_uhz = nominal_field_rate_in_uhz;
 
        // Full range may be larger than current video timing, so cap at nominal
-       if (min_refresh_in_uhz > nominal_field_rate_in_uhz)
-               min_refresh_in_uhz = nominal_field_rate_in_uhz;
+       if (min_refresh_in_uhz > max_refresh_in_uhz)
+               min_refresh_in_uhz = max_refresh_in_uhz;
+
+       // If a monitor reports exactly max refresh of 2x of min, enforce it on nominal
+       rounded_nominal_in_uhz =
+                       div_u64(nominal_field_rate_in_uhz + 50000, 100000) * 100000;
+       if (in_config->max_refresh_in_uhz == (2 * in_config->min_refresh_in_uhz) &&
+               in_config->max_refresh_in_uhz == rounded_nominal_in_uhz)
+               min_refresh_in_uhz = div_u64(nominal_field_rate_in_uhz, 2);
 
        if (!vrr_settings_require_update(core_freesync,
                        in_config, (unsigned int)min_refresh_in_uhz, (unsigned int)max_refresh_in_uhz,
@@ -792,11 +796,6 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
                refresh_range = in_out_vrr->max_refresh_in_uhz -
                                in_out_vrr->min_refresh_in_uhz;
 
-               in_out_vrr->btr.margin_in_us = in_out_vrr->max_duration_in_us -
-                               2 * in_out_vrr->min_duration_in_us;
-               if (in_out_vrr->btr.margin_in_us > BTR_MAX_MARGIN)
-                       in_out_vrr->btr.margin_in_us = BTR_MAX_MARGIN;
-
                in_out_vrr->supported = true;
        }
 
@@ -804,9 +803,14 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync,
 
        in_out_vrr->btr.btr_enabled = in_config->btr;
 
-       if (in_out_vrr->max_refresh_in_uhz <
-                       2 * in_out_vrr->min_refresh_in_uhz)
+       if (in_out_vrr->max_refresh_in_uhz < (2 * in_out_vrr->min_refresh_in_uhz))
                in_out_vrr->btr.btr_enabled = false;
+       else {
+               in_out_vrr->btr.margin_in_us = in_out_vrr->max_duration_in_us -
+                               2 * in_out_vrr->min_duration_in_us;
+               if (in_out_vrr->btr.margin_in_us > BTR_MAX_MARGIN)
+                       in_out_vrr->btr.margin_in_us = BTR_MAX_MARGIN;
+       }
 
        in_out_vrr->btr.btr_active = false;
        in_out_vrr->btr.inserted_duration_in_us = 0;
@@ -1008,8 +1012,8 @@ unsigned long long mod_freesync_calc_nominal_field_rate(
        unsigned int total = stream->timing.h_total * stream->timing.v_total;
 
        /* Calculate nominal field rate for stream, rounded up to nearest integer */
-       nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz / 10;
-       nominal_field_rate_in_uhz *= 1000ULL * 1000ULL * 1000ULL;
+       nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz;
+       nominal_field_rate_in_uhz *= 100000000ULL;
 
        nominal_field_rate_in_uhz =     div_u64(nominal_field_rate_in_uhz, total);
 
index e9fbd94..cc1d3f4 100644 (file)
@@ -328,8 +328,7 @@ enum mod_hdcp_status mod_hdcp_add_display(struct mod_hdcp *hdcp,
        /* add display to connection */
        hdcp->connection.link = *link;
        *display_container = *display;
-       status = mod_hdcp_add_display_to_topology(hdcp, display_container);
-
+       status = mod_hdcp_add_display_to_topology(hdcp, display->index);
        if (status != MOD_HDCP_STATUS_SUCCESS)
                goto out;
 
@@ -375,7 +374,7 @@ enum mod_hdcp_status mod_hdcp_remove_display(struct mod_hdcp *hdcp,
        status = mod_hdcp_remove_display_from_topology(hdcp, index);
        if (status != MOD_HDCP_STATUS_SUCCESS)
                goto out;
-       memset(display, 0, sizeof(struct mod_hdcp_display));
+       display->state = MOD_HDCP_DISPLAY_INACTIVE;
 
        /* request authentication when connection is not reset */
        if (current_state(hdcp) != HDCP_UNINITIALIZED)
index 60ff1a0..5cb4546 100644 (file)
@@ -328,7 +328,7 @@ void mod_hdcp_dump_binary_message(uint8_t *msg, uint32_t msg_size,
 
 /* psp functions */
 enum mod_hdcp_status mod_hdcp_add_display_to_topology(
-               struct mod_hdcp *hdcp, struct mod_hdcp_display *display);
+               struct mod_hdcp *hdcp, uint8_t index);
 enum mod_hdcp_status mod_hdcp_remove_display_from_topology(
                struct mod_hdcp *hdcp, uint8_t index);
 enum mod_hdcp_status mod_hdcp_hdcp1_create_session(struct mod_hdcp *hdcp);
@@ -503,6 +503,11 @@ static inline uint8_t is_display_active(struct mod_hdcp_display *display)
        return display->state >= MOD_HDCP_DISPLAY_ACTIVE;
 }
 
+static inline uint8_t is_display_added(struct mod_hdcp_display *display)
+{
+       return display->state >= MOD_HDCP_DISPLAY_ACTIVE_AND_ADDED;
+}
+
 static inline uint8_t is_display_encryption_enabled(struct mod_hdcp_display *display)
 {
        return display->state >= MOD_HDCP_DISPLAY_ENCRYPTION_ENABLED;
@@ -510,23 +515,34 @@ static inline uint8_t is_display_encryption_enabled(struct mod_hdcp_display *dis
 
 static inline uint8_t get_active_display_count(struct mod_hdcp *hdcp)
 {
-       uint8_t active_count = 0;
+       uint8_t added_count = 0;
        uint8_t i;
 
        for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++)
                if (is_display_active(&hdcp->displays[i]))
-                       active_count++;
-       return active_count;
+                       added_count++;
+       return added_count;
+}
+
+static inline uint8_t get_added_display_count(struct mod_hdcp *hdcp)
+{
+       uint8_t added_count = 0;
+       uint8_t i;
+
+       for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++)
+               if (is_display_added(&hdcp->displays[i]))
+                       added_count++;
+       return added_count;
 }
 
-static inline struct mod_hdcp_display *get_first_active_display(
+static inline struct mod_hdcp_display *get_first_added_display(
                struct mod_hdcp *hdcp)
 {
        uint8_t i;
        struct mod_hdcp_display *display = NULL;
 
        for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++)
-               if (is_display_active(&hdcp->displays[i])) {
+               if (is_display_added(&hdcp->displays[i])) {
                        display = &hdcp->displays[i];
                        break;
                }
index f244b72..37c8c05 100644 (file)
@@ -129,7 +129,7 @@ static inline uint8_t get_device_count(struct mod_hdcp *hdcp)
 static inline enum mod_hdcp_status check_device_count(struct mod_hdcp *hdcp)
 {
        /* device count must be greater than or equal to tracked hdcp displays */
-       return (get_device_count(hdcp) < get_active_display_count(hdcp)) ?
+       return (get_device_count(hdcp) < get_added_display_count(hdcp)) ?
                        MOD_HDCP_STATUS_HDCP1_DEVICE_COUNT_MISMATCH_FAILURE :
                        MOD_HDCP_STATUS_SUCCESS;
 }
index 549c113..491c00f 100644 (file)
@@ -208,7 +208,7 @@ static inline uint8_t get_device_count(struct mod_hdcp *hdcp)
 static enum mod_hdcp_status check_device_count(struct mod_hdcp *hdcp)
 {
        /* device count must be greater than or equal to tracked hdcp displays */
-       return (get_device_count(hdcp) < get_active_display_count(hdcp)) ?
+       return (get_device_count(hdcp) < get_added_display_count(hdcp)) ?
                        MOD_HDCP_STATUS_HDCP2_DEVICE_COUNT_MISMATCH_FAILURE :
                        MOD_HDCP_STATUS_SUCCESS;
 }
index 836e479..c292981 100644 (file)
@@ -54,7 +54,7 @@ enum mod_hdcp_status mod_hdcp_remove_display_from_topology(
 
        dtm_cmd = (struct ta_dtm_shared_memory *)psp->dtm_context.dtm_shared_buf;
 
-       if (!display || !is_display_active(display))
+       if (!display || !is_display_added(display))
                return MOD_HDCP_STATUS_DISPLAY_NOT_FOUND;
 
        memset(dtm_cmd, 0, sizeof(struct ta_dtm_shared_memory));
@@ -73,21 +73,25 @@ enum mod_hdcp_status mod_hdcp_remove_display_from_topology(
        HDCP_TOP_REMOVE_DISPLAY_TRACE(hdcp, display->index);
  
        return MOD_HDCP_STATUS_SUCCESS;
- }
-
-enum mod_hdcp_status mod_hdcp_add_display_to_topology(
-               struct mod_hdcp *hdcp, struct mod_hdcp_display *display)
+}
+enum mod_hdcp_status mod_hdcp_add_display_to_topology(struct mod_hdcp *hdcp,
+                                                     uint8_t index)
 {
        struct psp_context *psp = hdcp->config.psp.handle;
        struct ta_dtm_shared_memory *dtm_cmd;
+       struct mod_hdcp_display *display =
+                       get_active_display_at_index(hdcp, index);
        struct mod_hdcp_link *link = &hdcp->connection.link;
 
        if (!psp->dtm_context.dtm_initialized) {
                DRM_ERROR("Failed to add display topology, DTM TA is not initialized.");
-               display->state = MOD_HDCP_DISPLAY_INACTIVE;
                return MOD_HDCP_STATUS_FAILURE;
        }
 
+       if (!display || is_display_added(display))
+               return MOD_HDCP_STATUS_UPDATE_TOPOLOGY_FAILURE;
+
        dtm_cmd = (struct ta_dtm_shared_memory *)psp->dtm_context.dtm_shared_buf;
 
        memset(dtm_cmd, 0, sizeof(struct ta_dtm_shared_memory));
@@ -109,11 +113,10 @@ enum mod_hdcp_status mod_hdcp_add_display_to_topology(
 
        psp_dtm_invoke(psp, dtm_cmd->cmd_id);
 
-       if (dtm_cmd->dtm_status != TA_DTM_STATUS__SUCCESS) {
-               display->state = MOD_HDCP_DISPLAY_INACTIVE;
+       if (dtm_cmd->dtm_status != TA_DTM_STATUS__SUCCESS)
                return MOD_HDCP_STATUS_UPDATE_TOPOLOGY_FAILURE;
-       }
 
+       display->state = MOD_HDCP_DISPLAY_ACTIVE_AND_ADDED;
        HDCP_TOP_ADD_DISPLAY_TRACE(hdcp, display->index);
 
        return MOD_HDCP_STATUS_SUCCESS;
@@ -123,7 +126,7 @@ enum mod_hdcp_status mod_hdcp_hdcp1_create_session(struct mod_hdcp *hdcp)
 {
 
        struct psp_context *psp = hdcp->config.psp.handle;
-       struct mod_hdcp_display *display = get_first_active_display(hdcp);
+       struct mod_hdcp_display *display = get_first_added_display(hdcp);
        struct ta_hdcp_shared_memory *hdcp_cmd;
 
        if (!psp->hdcp_context.hdcp_initialized) {
@@ -176,7 +179,7 @@ enum mod_hdcp_status mod_hdcp_hdcp1_destroy_session(struct mod_hdcp *hdcp)
                if (is_display_encryption_enabled(
                                &hdcp->displays[i])) {
                        hdcp->displays[i].state =
-                                                               MOD_HDCP_DISPLAY_ACTIVE;
+                                       MOD_HDCP_DISPLAY_ACTIVE_AND_ADDED;
                        HDCP_HDCP1_DISABLED_TRACE(hdcp,
                                        hdcp->displays[i].index);
                }
@@ -228,7 +231,7 @@ enum mod_hdcp_status mod_hdcp_hdcp1_enable_encryption(struct mod_hdcp *hdcp)
 {
        struct psp_context *psp = hdcp->config.psp.handle;
        struct ta_hdcp_shared_memory *hdcp_cmd;
-       struct mod_hdcp_display *display = get_first_active_display(hdcp);
+       struct mod_hdcp_display *display = get_first_added_display(hdcp);
 
        hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf;
        memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory));
@@ -298,7 +301,8 @@ enum mod_hdcp_status mod_hdcp_hdcp1_enable_dp_stream_encryption(struct mod_hdcp
 
        for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) {
 
-               if (hdcp->displays[i].adjust.disable)
+               if (hdcp->displays[i].state != MOD_HDCP_DISPLAY_ACTIVE_AND_ADDED ||
+                   hdcp->displays[i].adjust.disable)
                        continue;
 
                memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory));
@@ -360,7 +364,7 @@ enum mod_hdcp_status mod_hdcp_hdcp2_create_session(struct mod_hdcp *hdcp)
 {
        struct psp_context *psp = hdcp->config.psp.handle;
        struct ta_hdcp_shared_memory *hdcp_cmd;
-       struct mod_hdcp_display *display = get_first_active_display(hdcp);
+       struct mod_hdcp_display *display = get_first_added_display(hdcp);
 
        if (!psp->hdcp_context.hdcp_initialized) {
                DRM_ERROR("Failed to create hdcp session, HDCP TA is not initialized");
@@ -419,7 +423,7 @@ enum mod_hdcp_status mod_hdcp_hdcp2_destroy_session(struct mod_hdcp *hdcp)
                if (is_display_encryption_enabled(
                                &hdcp->displays[i])) {
                        hdcp->displays[i].state =
-                                                               MOD_HDCP_DISPLAY_ACTIVE;
+                                       MOD_HDCP_DISPLAY_ACTIVE_AND_ADDED;
                        HDCP_HDCP2_DISABLED_TRACE(hdcp,
                                        hdcp->displays[i].index);
                }
@@ -658,7 +662,7 @@ enum mod_hdcp_status mod_hdcp_hdcp2_enable_encryption(struct mod_hdcp *hdcp)
 {
        struct psp_context *psp = hdcp->config.psp.handle;
        struct ta_hdcp_shared_memory *hdcp_cmd;
-       struct mod_hdcp_display *display = get_first_active_display(hdcp);
+       struct mod_hdcp_display *display = get_first_added_display(hdcp);
 
        hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf;
        memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory));
@@ -743,7 +747,8 @@ enum mod_hdcp_status mod_hdcp_hdcp2_enable_dp_stream_encryption(struct mod_hdcp
 
 
        for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) {
-               if (hdcp->displays[i].adjust.disable)
+               if (hdcp->displays[i].state != MOD_HDCP_DISPLAY_ACTIVE_AND_ADDED ||
+                   hdcp->displays[i].adjust.disable)
                        continue;
                hdcp_cmd->in_msg.hdcp2_enable_dp_stream_encryption.display_handle = hdcp->displays[i].index;
                hdcp_cmd->in_msg.hdcp2_enable_dp_stream_encryption.session_handle = hdcp->auth.id;
index eae9309..c088602 100644 (file)
@@ -117,6 +117,7 @@ enum mod_hdcp_operation_mode {
 enum mod_hdcp_display_state {
        MOD_HDCP_DISPLAY_INACTIVE = 0,
        MOD_HDCP_DISPLAY_ACTIVE,
+       MOD_HDCP_DISPLAY_ACTIVE_AND_ADDED,
        MOD_HDCP_DISPLAY_ENCRYPTION_ENABLED
 };
 
index c195575..2a12614 100644 (file)
@@ -1452,7 +1452,8 @@ static int pp_get_asic_baco_state(void *handle, int *state)
        if (!hwmgr)
                return -EINVAL;
 
-       if (!hwmgr->pm_en || !hwmgr->hwmgr_func->get_asic_baco_state)
+       if (!(hwmgr->not_vf && amdgpu_dpm) ||
+               !hwmgr->hwmgr_func->get_asic_baco_state)
                return 0;
 
        mutex_lock(&hwmgr->smu_lock);
index c6d3bef..1ef0923 100644 (file)
@@ -35,6 +35,7 @@
 #include "arcturus_ppt.h"
 #include "smu_v11_0_pptable.h"
 #include "arcturus_ppsmc.h"
+#include "nbio/nbio_7_4_offset.h"
 #include "nbio/nbio_7_4_sh_mask.h"
 #include "amdgpu_xgmi.h"
 #include <linux/i2c.h>
@@ -793,8 +794,21 @@ static int arcturus_force_clk_levels(struct smu_context *smu,
        struct arcturus_dpm_table *dpm_table;
        struct arcturus_single_dpm_table *single_dpm_table;
        uint32_t soft_min_level, soft_max_level;
+       uint32_t smu_version;
        int ret = 0;
 
+       ret = smu_get_smc_version(smu, NULL, &smu_version);
+       if (ret) {
+               pr_err("Failed to get smu version!\n");
+               return ret;
+       }
+
+       if (smu_version >= 0x361200) {
+               pr_err("Forcing clock level is not supported with "
+                      "54.18 and onwards SMU firmwares\n");
+               return -EOPNOTSUPP;
+       }
+
        soft_min_level = mask ? (ffs(mask) - 1) : 0;
        soft_max_level = mask ? (fls(mask) - 1) : 0;
 
@@ -1511,6 +1525,38 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
        return 0;
 }
 
+static int arcturus_set_performance_level(struct smu_context *smu,
+                                         enum amd_dpm_forced_level level)
+{
+       uint32_t smu_version;
+       int ret;
+
+       ret = smu_get_smc_version(smu, NULL, &smu_version);
+       if (ret) {
+               pr_err("Failed to get smu version!\n");
+               return ret;
+       }
+
+       switch (level) {
+       case AMD_DPM_FORCED_LEVEL_HIGH:
+       case AMD_DPM_FORCED_LEVEL_LOW:
+       case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
+       case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
+       case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
+       case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
+               if (smu_version >= 0x361200) {
+                       pr_err("Forcing clock level is not supported with "
+                              "54.18 and onwards SMU firmwares\n");
+                       return -EOPNOTSUPP;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return smu_v11_0_set_performance_level(smu, level);
+}
+
 static void arcturus_dump_pptable(struct smu_context *smu)
 {
        struct smu_table_context *table_context = &smu->smu_table;
@@ -2210,6 +2256,18 @@ static void arcturus_i2c_eeprom_control_fini(struct i2c_adapter *control)
        i2c_del_adapter(control);
 }
 
+static bool arcturus_is_baco_supported(struct smu_context *smu)
+{
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t val;
+
+       if (!smu_v11_0_baco_is_support(smu))
+               return false;
+
+       val = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP0);
+       return (val & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) ? true : false;
+}
+
 static uint32_t arcturus_get_pptable_power_limit(struct smu_context *smu)
 {
        PPTable_t *pptable = smu->smu_table.driver_pptable;
@@ -2272,7 +2330,7 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
        .get_profiling_clk_mask = arcturus_get_profiling_clk_mask,
        .get_power_profile_mode = arcturus_get_power_profile_mode,
        .set_power_profile_mode = arcturus_set_power_profile_mode,
-       .set_performance_level = smu_v11_0_set_performance_level,
+       .set_performance_level = arcturus_set_performance_level,
        /* debug (internal used) */
        .dump_pptable = arcturus_dump_pptable,
        .get_power_limit = arcturus_get_power_limit,
@@ -2321,7 +2379,7 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
        .register_irq_handler = smu_v11_0_register_irq_handler,
        .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme,
        .get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc,
-       .baco_is_support= smu_v11_0_baco_is_support,
+       .baco_is_support= arcturus_is_baco_supported,
        .baco_get_state = smu_v11_0_baco_get_state,
        .baco_set_state = smu_v11_0_baco_set_state,
        .baco_enter = smu_v11_0_baco_enter,
index 9c60b38..1503028 100644 (file)
 #include "smu_internal.h"
 #include "atomfirmware.h"
 #include "amdgpu_atomfirmware.h"
+#include "soc15_common.h"
 #include "smu_v11_0.h"
 #include "smu11_driver_if_navi10.h"
 #include "atom.h"
 #include "navi10_ppt.h"
 #include "smu_v11_0_pptable.h"
 #include "smu_v11_0_ppsmc.h"
-#include "nbio/nbio_7_4_sh_mask.h"
+#include "nbio/nbio_2_3_offset.h"
+#include "nbio/nbio_2_3_sh_mask.h"
 
 #include "asic_reg/mp/mp_11_0_sh_mask.h"
 
@@ -1985,6 +1987,18 @@ static int navi10_setup_od_limits(struct smu_context *smu) {
        return 0;
 }
 
+static bool navi10_is_baco_supported(struct smu_context *smu)
+{
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t val;
+
+       if (!smu_v11_0_baco_is_support(smu))
+               return false;
+
+       val = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP0);
+       return (val & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) ? true : false;
+}
+
 static int navi10_set_default_od_settings(struct smu_context *smu, bool initialize) {
        OverDriveTable_t *od_table, *boot_od_table;
        int ret = 0;
@@ -2361,7 +2375,7 @@ static const struct pptable_funcs navi10_ppt_funcs = {
        .register_irq_handler = smu_v11_0_register_irq_handler,
        .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme,
        .get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc,
-       .baco_is_support= smu_v11_0_baco_is_support,
+       .baco_is_support= navi10_is_baco_supported,
        .baco_get_state = smu_v11_0_baco_get_state,
        .baco_set_state = smu_v11_0_baco_set_state,
        .baco_enter = smu_v11_0_baco_enter,
index 7bf52ec..ff73a73 100644 (file)
@@ -239,6 +239,7 @@ static int renoir_print_clk_levels(struct smu_context *smu,
        uint32_t cur_value = 0, value = 0, count = 0, min = 0, max = 0;
        DpmClocks_t *clk_table = smu->smu_table.clocks_table;
        SmuMetrics_t metrics;
+       bool cur_value_match_level = false;
 
        if (!clk_table || clk_type >= SMU_CLK_COUNT)
                return -EINVAL;
@@ -297,8 +298,13 @@ static int renoir_print_clk_levels(struct smu_context *smu,
                GET_DPM_CUR_FREQ(clk_table, clk_type, i, value);
                size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
                                cur_value == value ? "*" : "");
+               if (cur_value == value)
+                       cur_value_match_level = true;
        }
 
+       if (!cur_value_match_level)
+               size += sprintf(buf + size, "   %uMhz *\n", cur_value);
+
        return size;
 }
 
@@ -887,6 +893,17 @@ static int renoir_read_sensor(struct smu_context *smu,
        return ret;
 }
 
+static bool renoir_is_dpm_running(struct smu_context *smu)
+{
+       /*
+        * Util now, the pmfw hasn't exported the interface of SMU
+        * feature mask to APU SKU so just force on all the feature
+        * at early initial stage.
+        */
+       return true;
+
+}
+
 static const struct pptable_funcs renoir_ppt_funcs = {
        .get_smu_msg_index = renoir_get_smu_msg_index,
        .get_smu_clk_index = renoir_get_smu_clk_index,
@@ -927,6 +944,7 @@ static const struct pptable_funcs renoir_ppt_funcs = {
        .mode2_reset = smu_v12_0_mode2_reset,
        .set_soft_freq_limited_range = smu_v12_0_set_soft_freq_limited_range,
        .set_driver_table_location = smu_v12_0_set_driver_table_location,
+       .is_dpm_running = renoir_is_dpm_running,
 };
 
 void renoir_set_ppt_funcs(struct smu_context *smu)
index 2a390dd..89cd6da 100644 (file)
@@ -37,7 +37,7 @@ extern void renoir_set_ppt_funcs(struct smu_context *smu);
                        freq = table->SocClocks[dpm_level].Freq;        \
                        break;                                          \
                case SMU_MCLK:                                          \
-                       freq = table->MemClocks[dpm_level].Freq;        \
+                       freq = table->FClocks[dpm_level].Freq;  \
                        break;                                          \
                case SMU_DCEFCLK:                                       \
                        freq = table->DcfClocks[dpm_level].Freq;        \
index d19e1d0..541c932 100644 (file)
@@ -42,8 +42,6 @@
 #include "asic_reg/thm/thm_11_0_2_sh_mask.h"
 #include "asic_reg/mp/mp_11_0_offset.h"
 #include "asic_reg/mp/mp_11_0_sh_mask.h"
-#include "asic_reg/nbio/nbio_7_4_offset.h"
-#include "asic_reg/nbio/nbio_7_4_sh_mask.h"
 #include "asic_reg/smuio/smuio_11_0_0_offset.h"
 #include "asic_reg/smuio/smuio_11_0_0_sh_mask.h"
 
@@ -1662,9 +1660,7 @@ static int smu_v11_0_baco_set_armd3_sequence(struct smu_context *smu, enum smu_v
 
 bool smu_v11_0_baco_is_support(struct smu_context *smu)
 {
-       struct amdgpu_device *adev = smu->adev;
        struct smu_baco_context *smu_baco = &smu->smu_baco;
-       uint32_t val;
        bool baco_support;
 
        mutex_lock(&smu_baco->mutex);
@@ -1679,11 +1675,7 @@ bool smu_v11_0_baco_is_support(struct smu_context *smu)
           !smu_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT))
                return false;
 
-       val = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP0);
-       if (val & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK)
-               return true;
-
-       return false;
+       return true;
 }
 
 enum smu_baco_state smu_v11_0_baco_get_state(struct smu_context *smu)
@@ -1700,11 +1692,9 @@ enum smu_baco_state smu_v11_0_baco_get_state(struct smu_context *smu)
 
 int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state)
 {
-
        struct smu_baco_context *smu_baco = &smu->smu_baco;
        struct amdgpu_device *adev = smu->adev;
        struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
-       uint32_t bif_doorbell_intr_cntl;
        uint32_t data;
        int ret = 0;
 
@@ -1713,14 +1703,7 @@ int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state)
 
        mutex_lock(&smu_baco->mutex);
 
-       bif_doorbell_intr_cntl = RREG32_SOC15(NBIO, 0, mmBIF_DOORBELL_INT_CNTL);
-
        if (state == SMU_BACO_STATE_ENTER) {
-               bif_doorbell_intr_cntl = REG_SET_FIELD(bif_doorbell_intr_cntl,
-                                               BIF_DOORBELL_INT_CNTL,
-                                               DOORBELL_INTERRUPT_DISABLE, 1);
-               WREG32_SOC15(NBIO, 0, mmBIF_DOORBELL_INT_CNTL, bif_doorbell_intr_cntl);
-
                if (!ras || !ras->supported) {
                        data = RREG32_SOC15(THM, 0, mmTHM_BACO_CNTL);
                        data |= 0x80000000;
@@ -1735,11 +1718,6 @@ int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state)
                if (ret)
                        goto out;
 
-               bif_doorbell_intr_cntl = REG_SET_FIELD(bif_doorbell_intr_cntl,
-                                               BIF_DOORBELL_INT_CNTL,
-                                               DOORBELL_INTERRUPT_DISABLE, 0);
-               WREG32_SOC15(NBIO, 0, mmBIF_DOORBELL_INT_CNTL, bif_doorbell_intr_cntl);
-
                /* clear vbios scratch 6 and 7 for coming asic reinit */
                WREG32(adev->bios_scratch_reg_offset + 6, 0);
                WREG32(adev->bios_scratch_reg_offset + 7, 0);
index 49ff375..3f10443 100644 (file)
@@ -35,6 +35,7 @@
 #include "vega20_ppt.h"
 #include "vega20_pptable.h"
 #include "vega20_ppsmc.h"
+#include "nbio/nbio_7_4_offset.h"
 #include "nbio/nbio_7_4_sh_mask.h"
 #include "asic_reg/thm/thm_11_0_2_offset.h"
 #include "asic_reg/thm/thm_11_0_2_sh_mask.h"
@@ -3174,6 +3175,17 @@ static int vega20_update_pcie_parameters(struct smu_context *smu,
        return ret;
 }
 
+static bool vega20_is_baco_supported(struct smu_context *smu)
+{
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t val;
+
+       if (!smu_v11_0_baco_is_support(smu))
+               return false;
+
+       val = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP0);
+       return (val & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) ? true : false;
+}
 
 static const struct pptable_funcs vega20_ppt_funcs = {
        .tables_init = vega20_tables_init,
@@ -3262,7 +3274,7 @@ static const struct pptable_funcs vega20_ppt_funcs = {
        .register_irq_handler = smu_v11_0_register_irq_handler,
        .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme,
        .get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc,
-       .baco_is_support= smu_v11_0_baco_is_support,
+       .baco_is_support= vega20_is_baco_supported,
        .baco_get_state = smu_v11_0_baco_get_state,
        .baco_set_state = smu_v11_0_baco_set_state,
        .baco_enter = smu_v11_0_baco_enter,
index 9ded2ce..76736fb 100644 (file)
@@ -1652,8 +1652,7 @@ static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux,
 }
 
 struct analogix_dp_device *
-analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-                struct analogix_dp_plat_data *plat_data)
+analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct analogix_dp_device *dp;
@@ -1756,22 +1755,30 @@ analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
                                        irq_flags, "analogix-dp", dp);
        if (ret) {
                dev_err(&pdev->dev, "failed to request irq\n");
-               goto err_disable_pm_runtime;
+               return ERR_PTR(ret);
        }
        disable_irq(dp->irq);
 
+       return dp;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_probe);
+
+int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
+{
+       int ret;
+
        dp->drm_dev = drm_dev;
        dp->encoder = dp->plat_data->encoder;
 
        dp->aux.name = "DP-AUX";
        dp->aux.transfer = analogix_dpaux_transfer;
-       dp->aux.dev = &pdev->dev;
+       dp->aux.dev = dp->dev;
 
        ret = drm_dp_aux_register(&dp->aux);
        if (ret)
-               return ERR_PTR(ret);
+               return ret;
 
-       pm_runtime_enable(dev);
+       pm_runtime_enable(dp->dev);
 
        ret = analogix_dp_create_bridge(drm_dev, dp);
        if (ret) {
@@ -1779,13 +1786,12 @@ analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
                goto err_disable_pm_runtime;
        }
 
-       return dp;
+       return 0;
 
 err_disable_pm_runtime:
+       pm_runtime_disable(dp->dev);
 
-       pm_runtime_disable(dev);
-
-       return ERR_PTR(ret);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(analogix_dp_bind);
 
@@ -1802,10 +1808,15 @@ void analogix_dp_unbind(struct analogix_dp_device *dp)
 
        drm_dp_aux_unregister(&dp->aux);
        pm_runtime_disable(dp->dev);
-       clk_disable_unprepare(dp->clock);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_unbind);
 
+void analogix_dp_remove(struct analogix_dp_device *dp)
+{
+       clk_disable_unprepare(dp->clock);
+}
+EXPORT_SYMBOL_GPL(analogix_dp_remove);
+
 #ifdef CONFIG_PM
 int analogix_dp_suspend(struct analogix_dp_device *dp)
 {
index bc6e208..8981abe 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/export.h>
 #include <linux/interval_tree_generic.h>
 #include <linux/seq_file.h>
-#include <linux/sched/signal.h>
 #include <linux/slab.h>
 #include <linux/stacktrace.h>
 
@@ -367,11 +366,6 @@ next_hole(struct drm_mm *mm,
          struct drm_mm_node *node,
          enum drm_mm_insert_mode mode)
 {
-       /* Searching is slow; check if we ran out of time/patience */
-       cond_resched();
-       if (fatal_signal_pending(current))
-               return NULL;
-
        switch (mode) {
        default:
        case DRM_MM_INSERT_BEST:
@@ -563,7 +557,7 @@ int drm_mm_insert_node_in_range(struct drm_mm * const mm,
                return 0;
        }
 
-       return signal_pending(current) ? -ERESTARTSYS : -ENOSPC;
+       return -ENOSPC;
 }
 EXPORT_SYMBOL(drm_mm_insert_node_in_range);
 
index 1de2cde..282774e 100644 (file)
@@ -962,27 +962,40 @@ int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
        unsigned count;
        struct scatterlist *sg;
        struct page *page;
-       u32 len, index;
+       u32 page_len, page_index;
        dma_addr_t addr;
+       u32 dma_len, dma_index;
 
-       index = 0;
+       /*
+        * Scatterlist elements contains both pages and DMA addresses, but
+        * one shoud not assume 1:1 relation between them. The sg->length is
+        * the size of the physical memory chunk described by the sg->page,
+        * while sg_dma_len(sg) is the size of the DMA (IO virtual) chunk
+        * described by the sg_dma_address(sg).
+        */
+       page_index = 0;
+       dma_index = 0;
        for_each_sg(sgt->sgl, sg, sgt->nents, count) {
-               len = sg_dma_len(sg);
+               page_len = sg->length;
                page = sg_page(sg);
+               dma_len = sg_dma_len(sg);
                addr = sg_dma_address(sg);
 
-               while (len > 0) {
-                       if (WARN_ON(index >= max_entries))
+               while (pages && page_len > 0) {
+                       if (WARN_ON(page_index >= max_entries))
                                return -1;
-                       if (pages)
-                               pages[index] = page;
-                       if (addrs)
-                               addrs[index] = addr;
-
+                       pages[page_index] = page;
                        page++;
+                       page_len -= PAGE_SIZE;
+                       page_index++;
+               }
+               while (addrs && dma_len > 0) {
+                       if (WARN_ON(dma_index >= max_entries))
+                               return -1;
+                       addrs[dma_index] = addr;
                        addr += PAGE_SIZE;
-                       len -= PAGE_SIZE;
-                       index++;
+                       dma_len -= PAGE_SIZE;
+                       dma_index++;
                }
        }
        return 0;
index d23d350..5ee0906 100644 (file)
@@ -159,15 +159,8 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
        struct drm_device *drm_dev = data;
        int ret;
 
-       dp->dev = dev;
        dp->drm_dev = drm_dev;
 
-       dp->plat_data.dev_type = EXYNOS_DP;
-       dp->plat_data.power_on_start = exynos_dp_poweron;
-       dp->plat_data.power_off = exynos_dp_poweroff;
-       dp->plat_data.attach = exynos_dp_bridge_attach;
-       dp->plat_data.get_modes = exynos_dp_get_modes;
-
        if (!dp->plat_data.panel && !dp->ptn_bridge) {
                ret = exynos_dp_dt_parse_panel(dp);
                if (ret)
@@ -185,13 +178,11 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 
        dp->plat_data.encoder = encoder;
 
-       dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
-       if (IS_ERR(dp->adp)) {
+       ret = analogix_dp_bind(dp->adp, dp->drm_dev);
+       if (ret)
                dp->encoder.funcs->destroy(&dp->encoder);
-               return PTR_ERR(dp->adp);
-       }
 
-       return 0;
+       return ret;
 }
 
 static void exynos_dp_unbind(struct device *dev, struct device *master,
@@ -222,6 +213,7 @@ static int exynos_dp_probe(struct platform_device *pdev)
        if (!dp)
                return -ENOMEM;
 
+       dp->dev = dev;
        /*
         * We just use the drvdata until driver run into component
         * add function, and then we would set drvdata to null, so
@@ -247,16 +239,29 @@ static int exynos_dp_probe(struct platform_device *pdev)
 
        /* The remote port can be either a panel or a bridge */
        dp->plat_data.panel = panel;
+       dp->plat_data.dev_type = EXYNOS_DP;
+       dp->plat_data.power_on_start = exynos_dp_poweron;
+       dp->plat_data.power_off = exynos_dp_poweroff;
+       dp->plat_data.attach = exynos_dp_bridge_attach;
+       dp->plat_data.get_modes = exynos_dp_get_modes;
        dp->plat_data.skip_connector = !!bridge;
+
        dp->ptn_bridge = bridge;
 
 out:
+       dp->adp = analogix_dp_probe(dev, &dp->plat_data);
+       if (IS_ERR(dp->adp))
+               return PTR_ERR(dp->adp);
+
        return component_add(&pdev->dev, &exynos_dp_ops);
 }
 
 static int exynos_dp_remove(struct platform_device *pdev)
 {
+       struct exynos_dp_device *dp = platform_get_drvdata(pdev);
+
        component_del(&pdev->dev, &exynos_dp_ops);
+       analogix_dp_remove(dp->adp);
 
        return 0;
 }
index 9f887a8..6cd1f62 100644 (file)
@@ -28,9 +28,6 @@ subdir-ccflags-$(CONFIG_DRM_I915_WERROR) += -Werror
 CFLAGS_i915_pci.o = $(call cc-disable-warning, override-init)
 CFLAGS_display/intel_fbdev.o = $(call cc-disable-warning, override-init)
 
-subdir-ccflags-y += \
-       $(call as-instr,movntdqa (%eax)$(comma)%xmm0,-DCONFIG_AS_MOVNTDQA)
-
 subdir-ccflags-y += -I$(srctree)/$(src)
 
 # Please keep these build lists sorted!
index 73d0f46..2c617c9 100644 (file)
@@ -947,7 +947,8 @@ static const struct cnl_ddi_buf_trans *
 ehl_get_combo_buf_trans(struct drm_i915_private *dev_priv, int type, int rate,
                        int *n_entries)
 {
-       if (type == INTEL_OUTPUT_DP && rate > 270000) {
+       if (type != INTEL_OUTPUT_HDMI && type != INTEL_OUTPUT_EDP &&
+           rate > 270000) {
                *n_entries = ARRAY_SIZE(ehl_combo_phy_ddi_translations_hbr2_hbr3);
                return ehl_combo_phy_ddi_translations_hbr2_hbr3;
        }
@@ -959,7 +960,7 @@ static const struct cnl_ddi_buf_trans *
 tgl_get_combo_buf_trans(struct drm_i915_private *dev_priv, int type, int rate,
                        int *n_entries)
 {
-       if (type != INTEL_OUTPUT_DP) {
+       if (type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_EDP) {
                return icl_get_combo_buf_trans(dev_priv, type, rate, n_entries);
        } else if (rate > 270000) {
                *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr2);
@@ -1869,7 +1870,11 @@ static void intel_ddi_get_power_domains(struct intel_encoder *encoder,
                return;
 
        dig_port = enc_to_dig_port(encoder);
-       intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain);
+
+       if (!intel_phy_is_tc(dev_priv, phy) ||
+           dig_port->tc_mode != TC_PORT_TBT_ALT)
+               intel_display_power_get(dev_priv,
+                                       dig_port->ddi_io_power_domain);
 
        /*
         * AUX power is only needed for (e)DP mode, and for HDMI mode on TC
index 36d0695..b7440f0 100644 (file)
@@ -896,11 +896,13 @@ static inline struct i915_ggtt *cache_to_ggtt(struct reloc_cache *cache)
 
 static void reloc_gpu_flush(struct reloc_cache *cache)
 {
-       GEM_BUG_ON(cache->rq_size >= cache->rq->batch->obj->base.size / sizeof(u32));
+       struct drm_i915_gem_object *obj = cache->rq->batch->obj;
+
+       GEM_BUG_ON(cache->rq_size >= obj->base.size / sizeof(u32));
        cache->rq_cmd[cache->rq_size] = MI_BATCH_BUFFER_END;
 
-       __i915_gem_object_flush_map(cache->rq->batch->obj, 0, cache->rq_size);
-       i915_gem_object_unpin_map(cache->rq->batch->obj);
+       __i915_gem_object_flush_map(obj, 0, sizeof(u32) * (cache->rq_size + 1));
+       i915_gem_object_unpin_map(obj);
 
        intel_gt_chipset_flush(cache->rq->engine->gt);
 
@@ -1477,10 +1479,8 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev)
                                 * can read from this userspace address.
                                 */
                                offset = gen8_canonical_addr(offset & ~UPDATE);
-                               if (unlikely(__put_user(offset, &urelocs[r-stack].presumed_offset))) {
-                                       remain = -EFAULT;
-                                       goto out;
-                               }
+                               __put_user(offset,
+                                          &urelocs[r - stack].presumed_offset);
                        }
                } while (r++, --count);
                urelocs += ARRAY_SIZE(stack);
index aed498a..4c5a209 100644 (file)
@@ -191,10 +191,11 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
                                     enum i915_cache_level level,
                                     u32 flags)
 {
-       struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
-       struct sgt_iter sgt_iter;
-       gen8_pte_t __iomem *gtt_entries;
        const gen8_pte_t pte_encode = gen8_ggtt_pte_encode(0, level, 0);
+       struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
+       gen8_pte_t __iomem *gte;
+       gen8_pte_t __iomem *end;
+       struct sgt_iter iter;
        dma_addr_t addr;
 
        /*
@@ -202,10 +203,17 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
         * not to allow the user to override access to a read only page.
         */
 
-       gtt_entries = (gen8_pte_t __iomem *)ggtt->gsm;
-       gtt_entries += vma->node.start / I915_GTT_PAGE_SIZE;
-       for_each_sgt_daddr(addr, sgt_iter, vma->pages)
-               gen8_set_pte(gtt_entries++, pte_encode | addr);
+       gte = (gen8_pte_t __iomem *)ggtt->gsm;
+       gte += vma->node.start / I915_GTT_PAGE_SIZE;
+       end = gte + vma->node.size / I915_GTT_PAGE_SIZE;
+
+       for_each_sgt_daddr(addr, iter, vma->pages)
+               gen8_set_pte(gte++, pte_encode | addr);
+       GEM_BUG_ON(gte > end);
+
+       /* Fill the allocated but "unused" space beyond the end of the buffer */
+       while (gte < end)
+               gen8_set_pte(gte++, vm->scratch[0].encode);
 
        /*
         * We want to flush the TLBs only after we're certain all the PTE
@@ -241,13 +249,22 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
                                     u32 flags)
 {
        struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
-       gen6_pte_t __iomem *entries = (gen6_pte_t __iomem *)ggtt->gsm;
-       unsigned int i = vma->node.start / I915_GTT_PAGE_SIZE;
+       gen6_pte_t __iomem *gte;
+       gen6_pte_t __iomem *end;
        struct sgt_iter iter;
        dma_addr_t addr;
 
+       gte = (gen6_pte_t __iomem *)ggtt->gsm;
+       gte += vma->node.start / I915_GTT_PAGE_SIZE;
+       end = gte + vma->node.size / I915_GTT_PAGE_SIZE;
+
        for_each_sgt_daddr(addr, iter, vma->pages)
-               iowrite32(vm->pte_encode(addr, level, flags), &entries[i++]);
+               iowrite32(vm->pte_encode(addr, level, flags), gte++);
+       GEM_BUG_ON(gte > end);
+
+       /* Fill the allocated but "unused" space beyond the end of the buffer */
+       while (gte < end)
+               iowrite32(vm->scratch[0].encode, gte++);
 
        /*
         * We want to flush the TLBs only after we're certain all the PTE
index 9e065ad..a3cc080 100644 (file)
@@ -164,6 +164,7 @@ struct decode_info {
 #define OP_STATE_BASE_ADDRESS                   OP_3D_MEDIA(0x0, 0x1, 0x01)
 #define OP_STATE_SIP                            OP_3D_MEDIA(0x0, 0x1, 0x02)
 #define OP_3D_MEDIA_0_1_4                      OP_3D_MEDIA(0x0, 0x1, 0x04)
+#define OP_SWTESS_BASE_ADDRESS                 OP_3D_MEDIA(0x0, 0x1, 0x03)
 
 #define OP_3DSTATE_VF_STATISTICS_GM45           OP_3D_MEDIA(0x1, 0x0, 0x0B)
 
@@ -967,18 +968,6 @@ static int cmd_handler_lri(struct parser_exec_state *s)
 {
        int i, ret = 0;
        int cmd_len = cmd_length(s);
-       u32 valid_len = CMD_LEN(1);
-
-       /*
-        * Official intel docs are somewhat sloppy , check the definition of
-        * MI_LOAD_REGISTER_IMM.
-        */
-       #define MAX_VALID_LEN 127
-       if ((cmd_len < valid_len) || (cmd_len > MAX_VALID_LEN)) {
-               gvt_err("len is not valid:  len=%u  valid_len=%u\n",
-                       cmd_len, valid_len);
-               return -EFAULT;
-       }
 
        for (i = 1; i < cmd_len; i += 2) {
                if (IS_BROADWELL(s->engine->i915) && s->engine->id != RCS0) {
@@ -2485,6 +2474,9 @@ static const struct cmd_info cmd_info[] = {
        {"OP_3D_MEDIA_0_1_4", OP_3D_MEDIA_0_1_4, F_LEN_VAR, R_RCS, D_ALL,
                ADDR_FIX_1(1), 8, NULL},
 
+       {"OP_SWTESS_BASE_ADDRESS", OP_SWTESS_BASE_ADDRESS,
+               F_LEN_VAR, R_RCS, D_ALL, ADDR_FIX_2(1, 2), 3, NULL},
+
        {"3DSTATE_VS", OP_3DSTATE_VS, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
 
        {"3DSTATE_SF", OP_3DSTATE_SF, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
index 6e5c988..a83df2f 100644 (file)
@@ -221,7 +221,7 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu)
                        ~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK |
                        TRANS_DDI_PORT_MASK);
                vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) |=
-                       (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DVI |
+                       (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
                        (PORT_B << TRANS_DDI_PORT_SHIFT) |
                        TRANS_DDI_FUNC_ENABLE);
                if (IS_BROADWELL(dev_priv)) {
@@ -241,7 +241,7 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu)
                        ~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK |
                        TRANS_DDI_PORT_MASK);
                vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) |=
-                       (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DVI |
+                       (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
                        (PORT_C << TRANS_DDI_PORT_SHIFT) |
                        TRANS_DDI_FUNC_ENABLE);
                if (IS_BROADWELL(dev_priv)) {
@@ -261,7 +261,7 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu)
                        ~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK |
                        TRANS_DDI_PORT_MASK);
                vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) |=
-                       (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DVI |
+                       (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
                        (PORT_D << TRANS_DDI_PORT_SHIFT) |
                        TRANS_DDI_FUNC_ENABLE);
                if (IS_BROADWELL(dev_priv)) {
index 0182e2a..2faf50e 100644 (file)
@@ -462,11 +462,14 @@ static int pipeconf_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
        return 0;
 }
 
-/* ascendingly sorted */
+/* sorted in ascending order */
 static i915_reg_t force_nonpriv_white_list[] = {
+       _MMIO(0xd80),
        GEN9_CS_DEBUG_MODE1, //_MMIO(0x20ec)
        GEN9_CTX_PREEMPT_REG,//_MMIO(0x2248)
-       PS_INVOCATION_COUNT,//_MMIO(0x2348)
+       CL_PRIMITIVES_COUNT, //_MMIO(0x2340)
+       PS_INVOCATION_COUNT, //_MMIO(0x2348)
+       PS_DEPTH_COUNT, //_MMIO(0x2350)
        GEN8_CS_CHICKEN1,//_MMIO(0x2580)
        _MMIO(0x2690),
        _MMIO(0x2694),
@@ -491,6 +494,7 @@ static i915_reg_t force_nonpriv_white_list[] = {
        _MMIO(0xe18c),
        _MMIO(0xe48c),
        _MMIO(0xe5f4),
+       _MMIO(0x64844),
 };
 
 /* a simple bsearch */
index 1c95bf8..cb11c31 100644 (file)
@@ -296,8 +296,8 @@ shadow_context_descriptor_update(struct intel_context *ce,
         * Update bits 0-11 of the context descriptor which includes flags
         * like GEN8_CTX_* cached in desc_template
         */
-       desc &= ~(0x3 << GEN8_CTX_ADDRESSING_MODE_SHIFT);
-       desc |= workload->ctx_desc.addressing_mode <<
+       desc &= ~(0x3ull << GEN8_CTX_ADDRESSING_MODE_SHIFT);
+       desc |= (u64)workload->ctx_desc.addressing_mode <<
                GEN8_CTX_ADDRESSING_MODE_SHIFT;
 
        ce->lrc_desc = desc;
index fdd5504..7b3b83b 100644 (file)
@@ -35,7 +35,6 @@
 
 static DEFINE_STATIC_KEY_FALSE(has_movntdqa);
 
-#ifdef CONFIG_AS_MOVNTDQA
 static void __memcpy_ntdqa(void *dst, const void *src, unsigned long len)
 {
        kernel_fpu_begin();
@@ -93,10 +92,6 @@ static void __memcpy_ntdqu(void *dst, const void *src, unsigned long len)
 
        kernel_fpu_end();
 }
-#else
-static void __memcpy_ntdqa(void *dst, const void *src, unsigned long len) {}
-static void __memcpy_ntdqu(void *dst, const void *src, unsigned long len) {}
-#endif
 
 /**
  * i915_memcpy_from_wc: perform an accelerated *aligned* read from WC
index 6650f47..47b9898 100644 (file)
@@ -633,7 +633,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
 
        if (config->platform.iommu) {
                iommu_dev = &pdev->dev;
-               if (!iommu_dev->iommu_fwspec)
+               if (!dev_iommu_fwspec_get(iommu_dev))
                        iommu_dev = iommu_dev->parent;
 
                aspace = msm_gem_address_space_create(iommu_dev,
index e8eef88..ffdd447 100644 (file)
@@ -35,7 +35,8 @@
 
 #include <subdev/bios/gpio.h>
 #include <subdev/gpio.h>
-#include <subdev/timer.h>
+
+#include <nvif/timer.h>
 
 int nv04_dac_output_offset(struct drm_encoder *encoder)
 {
index 3fdfafa..b674d68 100644 (file)
@@ -26,6 +26,7 @@
 #include "hw.h"
 
 #include <subdev/bios/pll.h>
+#include <nvif/timer.h>
 
 #define CHIPSET_NFORCE 0x01a0
 #define CHIPSET_NFORCE2 0x01f0
index 00a85f1..ee78215 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <nvif/cl507c.h>
 #include <nvif/event.h>
+#include <nvif/timer.h>
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_fourcc.h>
index e7fcfa6..c5152c3 100644 (file)
@@ -23,6 +23,7 @@
 #include "head.h"
 
 #include <nvif/cl507d.h>
+#include <nvif/timer.h>
 
 #include "nouveau_bo.h"
 
index 3b36dc8..c03cb98 100644 (file)
@@ -24,6 +24,8 @@
 
 #include <nouveau_bo.h>
 
+#include <nvif/timer.h>
+
 void
 corec37d_wndw_owner(struct nv50_core *core)
 {
index 397143b..8c5cf09 100644 (file)
 #include "head.h"
 
 #include <nvif/cl507a.h>
+#include <nvif/timer.h>
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_plane_helper.h>
 
+bool
+curs507a_space(struct nv50_wndw *wndw)
+{
+       nvif_msec(&nouveau_drm(wndw->plane.dev)->client.device, 2,
+               if (nvif_rd32(&wndw->wimm.base.user, 0x0008) >= 4)
+                       return true;
+       );
+       WARN_ON(1);
+       return false;
+}
+
 static void
 curs507a_update(struct nv50_wndw *wndw, u32 *interlock)
 {
-       nvif_wr32(&wndw->wimm.base.user, 0x0080, 0x00000000);
+       if (curs507a_space(wndw))
+               nvif_wr32(&wndw->wimm.base.user, 0x0080, 0x00000000);
 }
 
 static void
 curs507a_point(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 {
-       nvif_wr32(&wndw->wimm.base.user, 0x0084, asyw->point.y << 16 |
-                                                asyw->point.x);
+       if (curs507a_space(wndw)) {
+               nvif_wr32(&wndw->wimm.base.user, 0x0084, asyw->point.y << 16 |
+                                                        asyw->point.x);
+       }
 }
 
 const struct nv50_wimm_func
index 23fb29d..96dff4f 100644 (file)
 static void
 cursc37a_update(struct nv50_wndw *wndw, u32 *interlock)
 {
-       nvif_wr32(&wndw->wimm.base.user, 0x0200, 0x00000001);
+       if (curs507a_space(wndw))
+               nvif_wr32(&wndw->wimm.base.user, 0x0200, 0x00000001);
 }
 
 static void
 cursc37a_point(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 {
-       nvif_wr32(&wndw->wimm.base.user, 0x0208, asyw->point.y << 16 |
-                                                asyw->point.x);
+       if (curs507a_space(wndw)) {
+               nvif_wr32(&wndw->wimm.base.user, 0x0208, asyw->point.y << 16 |
+                                                        asyw->point.x);
+       }
 }
 
 static const struct nv50_wimm_func
index 4d1c584..6be9df1 100644 (file)
@@ -45,6 +45,7 @@
 #include <nvif/cl5070.h>
 #include <nvif/cl507d.h>
 #include <nvif/event.h>
+#include <nvif/timer.h>
 
 #include "nouveau_drv.h"
 #include "nouveau_dma.h"
index 2e68fc7..4f7ce57 100644 (file)
@@ -24,6 +24,8 @@
 
 #include <nouveau_bo.h>
 
+#include <nvif/timer.h>
+
 static void
 ovly827e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 {
index caf3974..a7412b9 100644 (file)
@@ -97,6 +97,7 @@ struct nv50_wimm_func {
 };
 
 extern const struct nv50_wimm_func curs507a;
+bool curs507a_space(struct nv50_wndw *);
 
 int wndwc37e_new(struct nouveau_drm *, enum drm_plane_type, int, s32,
                 struct nv50_wndw **);
index 25d969d..c2a572c 100644 (file)
@@ -23,27 +23,6 @@ int  nvif_device_init(struct nvif_object *, u32 handle, s32 oclass, void *, u32,
 void nvif_device_fini(struct nvif_device *);
 u64  nvif_device_time(struct nvif_device *);
 
-/* Delay based on GPU time (ie. PTIMER).
- *
- * Will return -ETIMEDOUT unless the loop was terminated with 'break',
- * where it will return the number of nanoseconds taken instead.
- */
-#define nvif_nsec(d,n,cond...) ({                                              \
-       struct nvif_device *_device = (d);                                     \
-       u64 _nsecs = (n), _time0 = nvif_device_time(_device);                  \
-       s64 _taken = 0;                                                        \
-                                                                               \
-       do {                                                                   \
-               cond                                                           \
-       } while (_taken = nvif_device_time(_device) - _time0, _taken < _nsecs);\
-                                                                               \
-       if (_taken >= _nsecs)                                                  \
-               _taken = -ETIMEDOUT;                                           \
-       _taken;                                                                \
-})
-#define nvif_usec(d,u,cond...) nvif_nsec((d), (u) * 1000, ##cond)
-#define nvif_msec(d,m,cond...) nvif_usec((d), (m) * 1000, ##cond)
-
 /*XXX*/
 #include <subdev/bios.h>
 #include <subdev/fb.h>
diff --git a/drivers/gpu/drm/nouveau/include/nvif/timer.h b/drivers/gpu/drm/nouveau/include/nvif/timer.h
new file mode 100644 (file)
index 0000000..57587a9
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __NVIF_TIMER_H__
+#define __NVIF_TIMER_H__
+#include <nvif/os.h>
+
+struct nvif_timer_wait {
+       struct nvif_device *device;
+       u64 limit;
+       u64 time0;
+       u64 time1;
+       int reads;
+};
+
+void nvif_timer_wait_init(struct nvif_device *, u64 nsec,
+                         struct nvif_timer_wait *);
+s64 nvif_timer_wait_test(struct nvif_timer_wait *);
+
+/* Delay based on GPU time (ie. PTIMER).
+ *
+ * Will return -ETIMEDOUT unless the loop was terminated with 'break',
+ * where it will return the number of nanoseconds taken instead.
+ */
+#define nvif_nsec(d,n,cond...) ({                                              \
+       struct nvif_timer_wait _wait;                                          \
+       s64 _taken = 0;                                                        \
+                                                                               \
+       nvif_timer_wait_init((d), (n), &_wait);                                \
+       do {                                                                   \
+               cond                                                           \
+       } while ((_taken = nvif_timer_wait_test(&_wait)) >= 0);                \
+                                                                               \
+       _taken;                                                                \
+})
+#define nvif_usec(d,u,cond...) nvif_nsec((d), (u) * 1000, ##cond)
+#define nvif_msec(d,m,cond...) nvif_usec((d), (m) * 1000, ##cond)
+#endif
index 03c1182..6825574 100644 (file)
@@ -10,6 +10,7 @@ struct nvif_user {
 
 struct nvif_user_func {
        void (*doorbell)(struct nvif_user *, u32 token);
+       u64 (*time)(struct nvif_user *);
 };
 
 int nvif_user_init(struct nvif_device *);
index 2b4b21b..c40f127 100644 (file)
@@ -1494,8 +1494,13 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg)
                        ret = nvif_object_map_handle(&mem->mem.object,
                                                     &args, argc,
                                                     &handle, &length);
-                       if (ret != 1)
-                               return ret ? ret : -EINVAL;
+                       if (ret != 1) {
+                               if (WARN_ON(ret == 0))
+                                       return -EINVAL;
+                               if (ret == -ENOSPC)
+                                       return -EAGAIN;
+                               return ret;
+                       }
 
                        reg->bus.base = 0;
                        reg->bus.offset = handle;
index 7dfbbbc..15a3d40 100644 (file)
@@ -222,22 +222,18 @@ nouveau_drm_debugfs_init(struct drm_minor *minor)
 {
        struct nouveau_drm *drm = nouveau_drm(minor->dev);
        struct dentry *dentry;
-       int i, ret;
+       int i;
 
        for (i = 0; i < ARRAY_SIZE(nouveau_debugfs_files); i++) {
-               dentry = debugfs_create_file(nouveau_debugfs_files[i].name,
-                                            S_IRUGO | S_IWUSR,
-                                            minor->debugfs_root, minor->dev,
-                                            nouveau_debugfs_files[i].fops);
-               if (!dentry)
-                       return -ENOMEM;
+               debugfs_create_file(nouveau_debugfs_files[i].name,
+                                   S_IRUGO | S_IWUSR,
+                                   minor->debugfs_root, minor->dev,
+                                   nouveau_debugfs_files[i].fops);
        }
 
-       ret = drm_debugfs_create_files(nouveau_debugfs_list,
-                                      NOUVEAU_DEBUGFS_ENTRIES,
-                                      minor->debugfs_root, minor);
-       if (ret)
-               return ret;
+       drm_debugfs_create_files(nouveau_debugfs_list,
+                                NOUVEAU_DEBUGFS_ENTRIES,
+                                minor->debugfs_root, minor);
 
        /* Set the size of the vbios since we know it, and it's confusing to
         * userspace if it wants to seek() but the file has a length of 0
index 6b1629c..ca4087f 100644 (file)
@@ -618,6 +618,64 @@ nouveau_drm_device_fini(struct drm_device *dev)
        kfree(drm);
 }
 
+/*
+ * On some Intel PCIe bridge controllers doing a
+ * D0 -> D3hot -> D3cold -> D0 sequence causes Nvidia GPUs to not reappear.
+ * Skipping the intermediate D3hot step seems to make it work again. This is
+ * probably caused by not meeting the expectation the involved AML code has
+ * when the GPU is put into D3hot state before invoking it.
+ *
+ * This leads to various manifestations of this issue:
+ *  - AML code execution to power on the GPU hits an infinite loop (as the
+ *    code waits on device memory to change).
+ *  - kernel crashes, as all PCI reads return -1, which most code isn't able
+ *    to handle well enough.
+ *
+ * In all cases dmesg will contain at least one line like this:
+ * 'nouveau 0000:01:00.0: Refused to change power state, currently in D3'
+ * followed by a lot of nouveau timeouts.
+ *
+ * In the \_SB.PCI0.PEG0.PG00._OFF code deeper down writes bit 0x80 to the not
+ * documented PCI config space register 0x248 of the Intel PCIe bridge
+ * controller (0x1901) in order to change the state of the PCIe link between
+ * the PCIe port and the GPU. There are alternative code paths using other
+ * registers, which seem to work fine (executed pre Windows 8):
+ *  - 0xbc bit 0x20 (publicly available documentation claims 'reserved')
+ *  - 0xb0 bit 0x10 (link disable)
+ * Changing the conditions inside the firmware by poking into the relevant
+ * addresses does resolve the issue, but it seemed to be ACPI private memory
+ * and not any device accessible memory at all, so there is no portable way of
+ * changing the conditions.
+ * On a XPS 9560 that means bits [0,3] on \CPEX need to be cleared.
+ *
+ * The only systems where this behavior can be seen are hybrid graphics laptops
+ * with a secondary Nvidia Maxwell, Pascal or Turing GPU. It's unclear whether
+ * this issue only occurs in combination with listed Intel PCIe bridge
+ * controllers and the mentioned GPUs or other devices as well.
+ *
+ * documentation on the PCIe bridge controller can be found in the
+ * "7th Generation Intel® Processor Families for H Platforms Datasheet Volume 2"
+ * Section "12 PCI Express* Controller (x16) Registers"
+ */
+
+static void quirk_broken_nv_runpm(struct pci_dev *pdev)
+{
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct pci_dev *bridge = pci_upstream_bridge(pdev);
+
+       if (!bridge || bridge->vendor != PCI_VENDOR_ID_INTEL)
+               return;
+
+       switch (bridge->device) {
+       case 0x1901:
+               drm->old_pm_cap = pdev->pm_cap;
+               pdev->pm_cap = 0;
+               NV_INFO(drm, "Disabling PCI power management to avoid bug\n");
+               break;
+       }
+}
+
 static int nouveau_drm_probe(struct pci_dev *pdev,
                             const struct pci_device_id *pent)
 {
@@ -699,6 +757,7 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
        if (ret)
                goto fail_drm_dev_init;
 
+       quirk_broken_nv_runpm(pdev);
        return 0;
 
 fail_drm_dev_init:
@@ -734,7 +793,11 @@ static void
 nouveau_drm_remove(struct pci_dev *pdev)
 {
        struct drm_device *dev = pci_get_drvdata(pdev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
 
+       /* revert our workaround */
+       if (drm->old_pm_cap)
+               pdev->pm_cap = drm->old_pm_cap;
        nouveau_drm_device_remove(dev);
        pci_disable_device(pdev);
 }
index c2c332f..2a65197 100644 (file)
@@ -140,6 +140,8 @@ struct nouveau_drm {
 
        struct list_head clients;
 
+       u8 old_pm_cap;
+
        struct {
                struct agp_bridge_data *bridge;
                u32 base;
index e3797b2..645fedd 100644 (file)
@@ -171,6 +171,11 @@ nouveau_svmm_bind(struct drm_device *dev, void *data,
        mm = get_task_mm(current);
        down_read(&mm->mmap_sem);
 
+       if (!cli->svm.svmm) {
+               up_read(&mm->mmap_sem);
+               return -EINVAL;
+       }
+
        for (addr = args->va_start, end = args->va_start + size; addr < end;) {
                struct vm_area_struct *vma;
                unsigned long next;
@@ -179,6 +184,7 @@ nouveau_svmm_bind(struct drm_device *dev, void *data,
                if (!vma)
                        break;
 
+               addr = max(addr, vma->vm_start);
                next = min(vma->vm_end, end);
                /* This is a best effort so we ignore errors */
                nouveau_dmem_migrate_vma(cli->drm, vma, addr, next);
@@ -656,9 +662,6 @@ nouveau_svm_fault(struct nvif_notify *notify)
                limit = start + (ARRAY_SIZE(args.phys) << PAGE_SHIFT);
                if (start < svmm->unmanaged.limit)
                        limit = min_t(u64, limit, svmm->unmanaged.start);
-               else
-               if (limit > svmm->unmanaged.start)
-                       start = max_t(u64, start, svmm->unmanaged.limit);
                SVMM_DBG(svmm, "wndw %016llx-%016llx", start, limit);
 
                mm = svmm->notifier.mm;
index 50d583d..f194d35 100644 (file)
@@ -8,6 +8,7 @@ nvif-y += nvif/fifo.o
 nvif-y += nvif/mem.o
 nvif-y += nvif/mmu.o
 nvif-y += nvif/notify.o
+nvif-y += nvif/timer.o
 nvif-y += nvif/vmm.o
 
 # Usermode classes
index 1ec101b..0e92db4 100644 (file)
 u64
 nvif_device_time(struct nvif_device *device)
 {
-       struct nv_device_time_v0 args = {};
-       int ret = nvif_object_mthd(&device->object, NV_DEVICE_V0_TIME,
-                                  &args, sizeof(args));
-       WARN_ON_ONCE(ret != 0);
-       return args.time;
+       if (!device->user.func) {
+               struct nv_device_time_v0 args = {};
+               int ret = nvif_object_mthd(&device->object, NV_DEVICE_V0_TIME,
+                                          &args, sizeof(args));
+               WARN_ON_ONCE(ret != 0);
+               return args.time;
+       }
+
+       return device->user.func->time(&device->user);
 }
 
 void
diff --git a/drivers/gpu/drm/nouveau/nvif/timer.c b/drivers/gpu/drm/nouveau/nvif/timer.c
new file mode 100644 (file)
index 0000000..602c1a2
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2020 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <nvif/timer.h>
+#include <nvif/device.h>
+
+s64
+nvif_timer_wait_test(struct nvif_timer_wait *wait)
+{
+       u64 time = nvif_device_time(wait->device);
+
+       if (wait->reads == 0) {
+               wait->time0 = time;
+               wait->time1 = time;
+       }
+
+       if (wait->time1 == time) {
+               if (WARN_ON(wait->reads++ == 16))
+                       return -ETIMEDOUT;
+       } else {
+               wait->time1 = time;
+               wait->reads = 1;
+       }
+
+       if (wait->time1 - wait->time0 > wait->limit)
+               return -ETIMEDOUT;
+
+       return wait->time1 - wait->time0;
+}
+
+void
+nvif_timer_wait_init(struct nvif_device *device, u64 nsec,
+                    struct nvif_timer_wait *wait)
+{
+       wait->device = device;
+       wait->limit = nsec;
+       wait->reads = 0;
+}
index 19f9958..1116f87 100644 (file)
  */
 #include <nvif/user.h>
 
+static u64
+nvif_userc361_time(struct nvif_user *user)
+{
+       u32 hi, lo;
+
+       do {
+               hi = nvif_rd32(&user->object, 0x084);
+               lo = nvif_rd32(&user->object, 0x080);
+       } while (hi != nvif_rd32(&user->object, 0x084));
+
+       return ((u64)hi << 32 | lo);
+}
+
 static void
 nvif_userc361_doorbell(struct nvif_user *user, u32 token)
 {
@@ -30,4 +43,5 @@ nvif_userc361_doorbell(struct nvif_user *user, u32 token)
 const struct nvif_user_func
 nvif_userc361 = {
        .doorbell = nvif_userc361_doorbell,
+       .time = nvif_userc361_time,
 };
index dd8f85b..f2f5636 100644 (file)
@@ -1981,8 +1981,34 @@ gf100_gr_init_(struct nvkm_gr *base)
 {
        struct gf100_gr *gr = gf100_gr(base);
        struct nvkm_subdev *subdev = &base->engine.subdev;
+       struct nvkm_device *device = subdev->device;
+       bool reset = device->chipset == 0x137 || device->chipset == 0x138;
        u32 ret;
 
+       /* On certain GP107/GP108 boards, we trigger a weird issue where
+        * GR will stop responding to PRI accesses after we've asked the
+        * SEC2 RTOS to boot the GR falcons.  This happens with far more
+        * frequency when cold-booting a board (ie. returning from D3).
+        *
+        * The root cause for this is not known and has proven difficult
+        * to isolate, with many avenues being dead-ends.
+        *
+        * A workaround was discovered by Karol, whereby putting GR into
+        * reset for an extended period right before initialisation
+        * prevents the problem from occuring.
+        *
+        * XXX: As RM does not require any such workaround, this is more
+        *      of a hack than a true fix.
+        */
+       reset = nvkm_boolopt(device->cfgopt, "NvGrResetWar", reset);
+       if (reset) {
+               nvkm_mask(device, 0x000200, 0x00001000, 0x00000000);
+               nvkm_rd32(device, 0x000200);
+               msleep(50);
+               nvkm_mask(device, 0x000200, 0x00001000, 0x00001000);
+               nvkm_rd32(device, 0x000200);
+       }
+
        nvkm_pmu_pgob(gr->base.engine.subdev.device->pmu, false);
 
        ret = nvkm_falcon_get(&gr->fecs.falcon, subdev);
index 0ce81b1..3ad828e 100644 (file)
@@ -361,7 +361,6 @@ static int panel_dpi_probe(struct device *dev,
        struct panel_desc *desc;
        unsigned int bus_flags;
        struct videomode vm;
-       const char *mapping;
        int ret;
 
        np = dev->of_node;
@@ -386,16 +385,6 @@ static int panel_dpi_probe(struct device *dev,
        of_property_read_u32(np, "width-mm", &desc->size.width);
        of_property_read_u32(np, "height-mm", &desc->size.height);
 
-       of_property_read_string(np, "data-mapping", &mapping);
-       if (!strcmp(mapping, "rgb24"))
-               desc->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
-       else if (!strcmp(mapping, "rgb565"))
-               desc->bus_format = MEDIA_BUS_FMT_RGB565_1X16;
-       else if (!strcmp(mapping, "bgr666"))
-               desc->bus_format = MEDIA_BUS_FMT_RGB666_1X18;
-       else if (!strcmp(mapping, "lvds666"))
-               desc->bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI;
-
        /* Extract bus_flags from display_timing */
        bus_flags = 0;
        vm.flags = timing->flags;
index f38f5e1..ce98c08 100644 (file)
@@ -325,15 +325,9 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
                            void *data)
 {
        struct rockchip_dp_device *dp = dev_get_drvdata(dev);
-       const struct rockchip_dp_chip_data *dp_data;
        struct drm_device *drm_dev = data;
        int ret;
 
-       dp_data = of_device_get_match_data(dev);
-       if (!dp_data)
-               return -ENODEV;
-
-       dp->data = dp_data;
        dp->drm_dev = drm_dev;
 
        ret = rockchip_dp_drm_create_encoder(dp);
@@ -344,16 +338,9 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 
        dp->plat_data.encoder = &dp->encoder;
 
-       dp->plat_data.dev_type = dp->data->chip_type;
-       dp->plat_data.power_on_start = rockchip_dp_poweron_start;
-       dp->plat_data.power_off = rockchip_dp_powerdown;
-       dp->plat_data.get_modes = rockchip_dp_get_modes;
-
-       dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
-       if (IS_ERR(dp->adp)) {
-               ret = PTR_ERR(dp->adp);
+       ret = analogix_dp_bind(dp->adp, drm_dev);
+       if (ret)
                goto err_cleanup_encoder;
-       }
 
        return 0;
 err_cleanup_encoder:
@@ -368,8 +355,6 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
 
        analogix_dp_unbind(dp->adp);
        dp->encoder.funcs->destroy(&dp->encoder);
-
-       dp->adp = ERR_PTR(-ENODEV);
 }
 
 static const struct component_ops rockchip_dp_component_ops = {
@@ -380,10 +365,15 @@ static const struct component_ops rockchip_dp_component_ops = {
 static int rockchip_dp_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       const struct rockchip_dp_chip_data *dp_data;
        struct drm_panel *panel = NULL;
        struct rockchip_dp_device *dp;
        int ret;
 
+       dp_data = of_device_get_match_data(dev);
+       if (!dp_data)
+               return -ENODEV;
+
        ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
        if (ret < 0)
                return ret;
@@ -394,7 +384,12 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 
        dp->dev = dev;
        dp->adp = ERR_PTR(-ENODEV);
+       dp->data = dp_data;
        dp->plat_data.panel = panel;
+       dp->plat_data.dev_type = dp->data->chip_type;
+       dp->plat_data.power_on_start = rockchip_dp_poweron_start;
+       dp->plat_data.power_off = rockchip_dp_powerdown;
+       dp->plat_data.get_modes = rockchip_dp_get_modes;
 
        ret = rockchip_dp_of_probe(dp);
        if (ret < 0)
@@ -402,12 +397,19 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, dp);
 
+       dp->adp = analogix_dp_probe(dev, &dp->plat_data);
+       if (IS_ERR(dp->adp))
+               return PTR_ERR(dp->adp);
+
        return component_add(dev, &rockchip_dp_component_ops);
 }
 
 static int rockchip_dp_remove(struct platform_device *pdev)
 {
+       struct rockchip_dp_device *dp = platform_get_drvdata(pdev);
+
        component_del(&pdev->dev, &rockchip_dp_component_ops);
+       analogix_dp_remove(dp->adp);
 
        return 0;
 }
index 6ee3b96..0ad30b1 100644 (file)
@@ -442,66 +442,6 @@ vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf)
 }
 EXPORT_SYMBOL(ttm_bo_vm_fault);
 
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-/**
- * ttm_pgprot_is_wrprotecting - Is a page protection value write-protecting?
- * @prot: The page protection value
- *
- * Return: true if @prot is write-protecting. false otherwise.
- */
-static bool ttm_pgprot_is_wrprotecting(pgprot_t prot)
-{
-       /*
-        * This is meant to say "pgprot_wrprotect(prot) == prot" in a generic
-        * way. Unfortunately there is no generic pgprot_wrprotect.
-        */
-       return pte_val(pte_wrprotect(__pte(pgprot_val(prot)))) ==
-               pgprot_val(prot);
-}
-
-static vm_fault_t ttm_bo_vm_huge_fault(struct vm_fault *vmf,
-                                      enum page_entry_size pe_size)
-{
-       struct vm_area_struct *vma = vmf->vma;
-       pgprot_t prot;
-       struct ttm_buffer_object *bo = vma->vm_private_data;
-       vm_fault_t ret;
-       pgoff_t fault_page_size = 0;
-       bool write = vmf->flags & FAULT_FLAG_WRITE;
-
-       switch (pe_size) {
-       case PE_SIZE_PMD:
-               fault_page_size = HPAGE_PMD_SIZE >> PAGE_SHIFT;
-               break;
-#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
-       case PE_SIZE_PUD:
-               fault_page_size = HPAGE_PUD_SIZE >> PAGE_SHIFT;
-               break;
-#endif
-       default:
-               WARN_ON_ONCE(1);
-               return VM_FAULT_FALLBACK;
-       }
-
-       /* Fallback on write dirty-tracking or COW */
-       if (write && ttm_pgprot_is_wrprotecting(vma->vm_page_prot))
-               return VM_FAULT_FALLBACK;
-
-       ret = ttm_bo_vm_reserve(bo, vmf);
-       if (ret)
-               return ret;
-
-       prot = vm_get_page_prot(vma->vm_flags);
-       ret = ttm_bo_vm_fault_reserved(vmf, prot, 1, fault_page_size);
-       if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
-               return ret;
-
-       dma_resv_unlock(bo->base.resv);
-
-       return ret;
-}
-#endif
-
 void ttm_bo_vm_open(struct vm_area_struct *vma)
 {
        struct ttm_buffer_object *bo = vma->vm_private_data;
@@ -604,9 +544,6 @@ static const struct vm_operations_struct ttm_bo_vm_ops = {
        .open = ttm_bo_vm_open,
        .close = ttm_bo_vm_close,
        .access = ttm_bo_vm_access,
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-       .huge_fault = ttm_bo_vm_huge_fault,
-#endif
 };
 
 static struct ttm_buffer_object *ttm_bo_vm_lookup(struct ttm_bo_device *bdev,
index 8512d97..ac8f75d 100644 (file)
@@ -41,6 +41,10 @@ static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!vbox_check_supported(VBE_DISPI_ID_HGSMI))
                return -ENODEV;
 
+       ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "vboxvideodrmfb");
+       if (ret)
+               return ret;
+
        vbox = kzalloc(sizeof(*vbox), GFP_KERNEL);
        if (!vbox)
                return -ENOMEM;
index cea18dc..3407192 100644 (file)
@@ -681,11 +681,23 @@ static enum drm_mode_status
 vc4_hdmi_encoder_mode_valid(struct drm_encoder *crtc,
                            const struct drm_display_mode *mode)
 {
-       /* HSM clock must be 108% of the pixel clock.  Additionally,
-        * the AXI clock needs to be at least 25% of pixel clock, but
-        * HSM ends up being the limiting factor.
+       /*
+        * As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
+        * be faster than pixel clock, infinitesimally faster, tested in
+        * simulation. Otherwise, exact value is unimportant for HDMI
+        * operation." This conflicts with bcm2835's vc4 documentation, which
+        * states HSM's clock has to be at least 108% of the pixel clock.
+        *
+        * Real life tests reveal that vc4's firmware statement holds up, and
+        * users are able to use pixel clocks closer to HSM's, namely for
+        * 1920x1200@60Hz. So it was decided to have leave a 1% margin between
+        * both clocks. Which, for RPi0-3 implies a maximum pixel clock of
+        * 162MHz.
+        *
+        * Additionally, the AXI clock needs to be at least 25% of
+        * pixel clock, but HSM ends up being the limiting factor.
         */
-       if (mode->clock > HSM_CLOCK_FREQ / (1000 * 108 / 100))
+       if (mode->clock > HSM_CLOCK_FREQ / (1000 * 101 / 100))
                return MODE_CLOCK_HIGH;
 
        return MODE_OK;
index 2bfb13d..d9039bb 100644 (file)
@@ -123,15 +123,17 @@ bool virtio_gpu_is_shmem(struct virtio_gpu_object *bo)
 struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev,
                                                size_t size)
 {
-       struct virtio_gpu_object *bo;
+       struct virtio_gpu_object_shmem *shmem;
+       struct drm_gem_shmem_object *dshmem;
 
-       bo = kzalloc(sizeof(*bo), GFP_KERNEL);
-       if (!bo)
+       shmem = kzalloc(sizeof(*shmem), GFP_KERNEL);
+       if (!shmem)
                return NULL;
 
-       bo->base.base.funcs = &virtio_gpu_shmem_funcs;
-       bo->base.map_cached = true;
-       return &bo->base.base;
+       dshmem = &shmem->base.base;
+       dshmem->base.funcs = &virtio_gpu_shmem_funcs;
+       dshmem->map_cached = true;
+       return &dshmem->base;
 }
 
 static int virtio_gpu_object_shmem_init(struct virtio_gpu_device *vgdev,
index 4be49c1..3741420 100644 (file)
@@ -401,7 +401,7 @@ static int xen_drm_drv_dumb_create(struct drm_file *filp,
 
        obj = xen_drm_front_gem_create(dev, args->size);
        if (IS_ERR_OR_NULL(obj)) {
-               ret = PTR_ERR(obj);
+               ret = PTR_ERR_OR_ZERO(obj);
                goto fail;
        }
 
index 0370364..501c43c 100644 (file)
@@ -839,6 +839,9 @@ void vmbus_initiate_unload(bool crash)
 {
        struct vmbus_channel_message_header hdr;
 
+       if (xchg(&vmbus_connection.conn_state, DISCONNECTED) == DISCONNECTED)
+               return;
+
        /* Pre-Win2012R2 hosts don't support reconnect */
        if (vmbus_proto_version < VERSION_WIN8_1)
                return;
index 8a28785..ccf752b 100644 (file)
@@ -11,7 +11,7 @@
 
 #include "hyperv_vmbus.h"
 
-struct dentry *hv_debug_root;
+static struct dentry *hv_debug_root;
 
 static int hv_debugfs_delay_get(void *data, u64 *val)
 {
index f5fa3b3..70b30e2 100644 (file)
@@ -292,7 +292,7 @@ struct vmbus_msginfo {
        struct list_head msglist_entry;
 
        /* The message itself */
-       unsigned char msg[0];
+       unsigned char msg[];
 };
 
 
index 029378c..a68bce4 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/kdebug.h>
 #include <linux/efi.h>
 #include <linux/random.h>
+#include <linux/kernel.h>
 #include <linux/syscore_ops.h>
 #include <clocksource/hyperv_timer.h>
 #include "hyperv_vmbus.h"
@@ -48,14 +49,35 @@ static int hyperv_cpuhp_online;
 
 static void *hv_panic_page;
 
+/*
+ * Boolean to control whether to report panic messages over Hyper-V.
+ *
+ * It can be set via /proc/sys/kernel/hyperv/record_panic_msg
+ */
+static int sysctl_record_panic_msg = 1;
+
+static int hyperv_report_reg(void)
+{
+       return !sysctl_record_panic_msg || !hv_panic_page;
+}
+
 static int hyperv_panic_event(struct notifier_block *nb, unsigned long val,
                              void *args)
 {
        struct pt_regs *regs;
 
-       regs = current_pt_regs();
+       vmbus_initiate_unload(true);
 
-       hyperv_report_panic(regs, val);
+       /*
+        * Hyper-V should be notified only once about a panic.  If we will be
+        * doing hyperv_report_panic_msg() later with kmsg data, don't do
+        * the notification here.
+        */
+       if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE
+           && hyperv_report_reg()) {
+               regs = current_pt_regs();
+               hyperv_report_panic(regs, val, false);
+       }
        return NOTIFY_DONE;
 }
 
@@ -65,7 +87,13 @@ static int hyperv_die_event(struct notifier_block *nb, unsigned long val,
        struct die_args *die = (struct die_args *)args;
        struct pt_regs *regs = die->regs;
 
-       hyperv_report_panic(regs, val);
+       /*
+        * Hyper-V should be notified only once about a panic.  If we will be
+        * doing hyperv_report_panic_msg() later with kmsg data, don't do
+        * the notification here.
+        */
+       if (hyperv_report_reg())
+               hyperv_report_panic(regs, val, true);
        return NOTIFY_DONE;
 }
 
@@ -1253,13 +1281,6 @@ static void vmbus_isr(void)
 }
 
 /*
- * Boolean to control whether to report panic messages over Hyper-V.
- *
- * It can be set via /proc/sys/kernel/hyperv/record_panic_msg
- */
-static int sysctl_record_panic_msg = 1;
-
-/*
  * Callback from kmsg_dump. Grab as much as possible from the end of the kmsg
  * buffer and call into Hyper-V to transfer the data.
  */
@@ -1382,19 +1403,29 @@ static int vmbus_bus_init(void)
                        hv_panic_page = (void *)hv_alloc_hyperv_zeroed_page();
                        if (hv_panic_page) {
                                ret = kmsg_dump_register(&hv_kmsg_dumper);
-                               if (ret)
+                               if (ret) {
                                        pr_err("Hyper-V: kmsg dump register "
                                                "error 0x%x\n", ret);
+                                       hv_free_hyperv_page(
+                                           (unsigned long)hv_panic_page);
+                                       hv_panic_page = NULL;
+                               }
                        } else
                                pr_err("Hyper-V: panic message page memory "
                                        "allocation failed");
                }
 
                register_die_notifier(&hyperv_die_block);
-               atomic_notifier_chain_register(&panic_notifier_list,
-                                              &hyperv_panic_block);
        }
 
+       /*
+        * Always register the panic notifier because we need to unload
+        * the VMbus channel connection to prevent any VMbus
+        * activity after the VM panics.
+        */
+       atomic_notifier_chain_register(&panic_notifier_list,
+                              &hyperv_panic_block);
+
        vmbus_request_offers();
 
        return 0;
@@ -1407,7 +1438,6 @@ err_alloc:
        hv_remove_vmbus_irq();
 
        bus_unregister(&hv_bus);
-       hv_free_hyperv_page((unsigned long)hv_panic_page);
        unregister_sysctl_table(hv_ctl_table_hdr);
        hv_ctl_table_hdr = NULL;
        return ret;
@@ -2204,8 +2234,6 @@ static int vmbus_bus_suspend(struct device *dev)
 
        vmbus_initiate_unload(false);
 
-       vmbus_connection.conn_state = DISCONNECTED;
-
        /* Reset the event for the next resume. */
        reinit_completion(&vmbus_connection.ready_for_resume_event);
 
@@ -2289,7 +2317,6 @@ static void hv_kexec_handler(void)
 {
        hv_stimer_global_cleanup();
        vmbus_initiate_unload(false);
-       vmbus_connection.conn_state = DISCONNECTED;
        /* Make sure conn_state is set as hv_synic_cleanup checks for it */
        mb();
        cpuhp_remove_state(hyperv_cpuhp_online);
@@ -2306,7 +2333,6 @@ static void hv_crash_handler(struct pt_regs *regs)
         * doing the cleanup for current CPU only. This should be sufficient
         * for kdump.
         */
-       vmbus_connection.conn_state = DISCONNECTED;
        cpu = smp_processor_id();
        hv_stimer_cleanup(cpu);
        hv_synic_disable_regs(cpu);
index d4c8300..ab719d3 100644 (file)
@@ -7,7 +7,7 @@
  * Hwmon integration:
  * Copyright (C) 2011  Jean Delvare <jdelvare@suse.de>
  * Copyright (C) 2013, 2014  Guenter Roeck <linux@roeck-us.net>
- * Copyright (C) 2014, 2015  Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (C) 2014, 2015  Pali Rohár <pali@kernel.org>
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -86,7 +86,7 @@ static unsigned int auto_fan;
 #define I8K_HWMON_HAVE_FAN3    (1 << 12)
 
 MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
-MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
+MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
 MODULE_DESCRIPTION("Dell laptop SMM BIOS hwmon driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("i8k");
index 5bd5185..d5c073a 100644 (file)
@@ -88,6 +88,7 @@ source "drivers/iio/orientation/Kconfig"
 if IIO_TRIGGER
    source "drivers/iio/trigger/Kconfig"
 endif #IIO_TRIGGER
+source "drivers/iio/position/Kconfig"
 source "drivers/iio/potentiometer/Kconfig"
 source "drivers/iio/potentiostat/Kconfig"
 source "drivers/iio/pressure/Kconfig"
index bff682a..1712011 100644 (file)
@@ -31,6 +31,7 @@ obj-y += light/
 obj-y += magnetometer/
 obj-y += multiplexer/
 obj-y += orientation/
+obj-y += position/
 obj-y += potentiometer/
 obj-y += potentiostat/
 obj-y += pressure/
index 68e847c..2532b9a 100644 (file)
@@ -170,7 +170,8 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
        if (!indio_dev)
                return -ENOMEM;
 
-       ret = cros_ec_sensors_core_init(pdev, indio_dev, true);
+       ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
+                                       cros_ec_sensors_capture, NULL);
        if (ret)
                return ret;
 
@@ -190,11 +191,6 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
                state->sign[CROS_EC_SENSOR_Z] = -1;
        }
 
-       ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
-                       cros_ec_sensors_capture, NULL);
-       if (ret)
-               return ret;
-
        return devm_iio_device_register(dev, indio_dev);
 }
 
index f4da821..12bb8b7 100644 (file)
@@ -795,6 +795,16 @@ config RCAR_GYRO_ADC
          To compile this driver as a module, choose M here: the
          module will be called rcar-gyroadc.
 
+config RN5T618_ADC
+       tristate "ADC for the RN5T618/RC5T619 family of chips"
+       depends on MFD_RN5T618
+       help
+         Say yes here to build support for the integrated ADC inside the
+         RN5T618/619 series PMICs:
+
+         This driver can also be built as a module. If so, the module
+         will be called rn5t618-adc.
+
 config ROCKCHIP_SARADC
        tristate "Rockchip SARADC driver"
        depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST)
index 8462455..6378078 100644 (file)
@@ -75,6 +75,7 @@ obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
 obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
 obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
 obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
+obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o
 obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
 obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o
 obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
diff --git a/drivers/iio/adc/rn5t618-adc.c b/drivers/iio/adc/rn5t618-adc.c
new file mode 100644 (file)
index 0000000..f21027e
--- /dev/null
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ADC driver for the RICOH RN5T618 power management chip family
+ *
+ * Copyright (C) 2019 Andreas Kemnade
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mfd/rn5t618.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/slab.h>
+
+#define RN5T618_ADC_CONVERSION_TIMEOUT   (msecs_to_jiffies(500))
+#define RN5T618_REFERENCE_VOLT 2500
+
+/* mask for selecting channels for single conversion */
+#define RN5T618_ADCCNT3_CHANNEL_MASK 0x7
+/* average 4-time conversion mode */
+#define RN5T618_ADCCNT3_AVG BIT(3)
+/* set for starting a single conversion, gets cleared by hw when done */
+#define RN5T618_ADCCNT3_GODONE BIT(4)
+/* automatic conversion, period is in ADCCNT2, selected channels are
+ * in ADCCNT1
+ */
+#define RN5T618_ADCCNT3_AUTO BIT(5)
+#define RN5T618_ADCEND_IRQ BIT(0)
+
+struct rn5t618_adc_data {
+       struct device *dev;
+       struct rn5t618 *rn5t618;
+       struct completion conv_completion;
+       int irq;
+};
+
+struct rn5t618_channel_ratios {
+       u16 numerator;
+       u16 denominator;
+};
+
+enum rn5t618_channels {
+       LIMMON = 0,
+       VBAT,
+       VADP,
+       VUSB,
+       VSYS,
+       VTHM,
+       AIN1,
+       AIN0
+};
+
+static const struct rn5t618_channel_ratios rn5t618_ratios[8] = {
+       [LIMMON] = {50, 32}, /* measured across 20mOhm, amplified by 32 */
+       [VBAT] = {2, 1},
+       [VADP] = {3, 1},
+       [VUSB] = {3, 1},
+       [VSYS] = {3, 1},
+       [VTHM] = {1, 1},
+       [AIN1] = {1, 1},
+       [AIN0] = {1, 1},
+};
+
+static int rn5t618_read_adc_reg(struct rn5t618 *rn5t618, int reg, u16 *val)
+{
+       u8 data[2];
+       int ret;
+
+       ret = regmap_bulk_read(rn5t618->regmap, reg, data, sizeof(data));
+       if (ret < 0)
+               return ret;
+
+       *val = (data[0] << 4) | (data[1] & 0xF);
+
+       return 0;
+}
+
+static irqreturn_t rn5t618_adc_irq(int irq, void *data)
+{
+       struct rn5t618_adc_data *adc = data;
+       unsigned int r = 0;
+       int ret;
+
+       /* clear low & high threshold irqs */
+       regmap_write(adc->rn5t618->regmap, RN5T618_IR_ADC1, 0);
+       regmap_write(adc->rn5t618->regmap, RN5T618_IR_ADC2, 0);
+
+       ret = regmap_read(adc->rn5t618->regmap, RN5T618_IR_ADC3, &r);
+       if (ret < 0)
+               dev_err(adc->dev, "failed to read IRQ status: %d\n", ret);
+
+       regmap_write(adc->rn5t618->regmap, RN5T618_IR_ADC3, 0);
+
+       if (r & RN5T618_ADCEND_IRQ)
+               complete(&adc->conv_completion);
+
+       return IRQ_HANDLED;
+}
+
+static int rn5t618_adc_read(struct iio_dev *iio_dev,
+                           const struct iio_chan_spec *chan,
+                           int *val, int *val2, long mask)
+{
+       struct rn5t618_adc_data *adc = iio_priv(iio_dev);
+       u16 raw;
+       int ret;
+
+       if (mask == IIO_CHAN_INFO_SCALE) {
+               *val = RN5T618_REFERENCE_VOLT *
+                      rn5t618_ratios[chan->channel].numerator;
+               *val2 = rn5t618_ratios[chan->channel].denominator * 4095;
+
+               return IIO_VAL_FRACTIONAL;
+       }
+
+       /* select channel */
+       ret = regmap_update_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3,
+                                RN5T618_ADCCNT3_CHANNEL_MASK,
+                                chan->channel);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(adc->rn5t618->regmap, RN5T618_EN_ADCIR3,
+                          RN5T618_ADCEND_IRQ);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_update_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3,
+                                RN5T618_ADCCNT3_AVG,
+                                mask == IIO_CHAN_INFO_AVERAGE_RAW ?
+                                RN5T618_ADCCNT3_AVG : 0);
+       if (ret < 0)
+               return ret;
+
+       init_completion(&adc->conv_completion);
+       /* single conversion */
+       ret = regmap_update_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3,
+                                RN5T618_ADCCNT3_GODONE,
+                                RN5T618_ADCCNT3_GODONE);
+       if (ret < 0)
+               return ret;
+
+       ret = wait_for_completion_timeout(&adc->conv_completion,
+                                         RN5T618_ADC_CONVERSION_TIMEOUT);
+       if (ret == 0) {
+               dev_warn(adc->dev, "timeout waiting for adc result\n");
+               return -ETIMEDOUT;
+       }
+
+       ret = rn5t618_read_adc_reg(adc->rn5t618,
+                                  RN5T618_ILIMDATAH + 2 * chan->channel,
+                                  &raw);
+       if (ret < 0)
+               return ret;
+
+       *val = raw;
+
+       return IIO_VAL_INT;
+}
+
+static const struct iio_info rn5t618_adc_iio_info = {
+       .read_raw = &rn5t618_adc_read,
+};
+
+#define RN5T618_ADC_CHANNEL(_channel, _type, _name) { \
+       .type = _type, \
+       .channel = _channel, \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+                             BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \
+                             BIT(IIO_CHAN_INFO_SCALE), \
+       .datasheet_name = _name, \
+       .indexed = 1. \
+}
+
+static const struct iio_chan_spec rn5t618_adc_iio_channels[] = {
+       RN5T618_ADC_CHANNEL(LIMMON, IIO_CURRENT, "LIMMON"),
+       RN5T618_ADC_CHANNEL(VBAT, IIO_VOLTAGE, "VBAT"),
+       RN5T618_ADC_CHANNEL(VADP, IIO_VOLTAGE, "VADP"),
+       RN5T618_ADC_CHANNEL(VUSB, IIO_VOLTAGE, "VUSB"),
+       RN5T618_ADC_CHANNEL(VSYS, IIO_VOLTAGE, "VSYS"),
+       RN5T618_ADC_CHANNEL(VTHM, IIO_VOLTAGE, "VTHM"),
+       RN5T618_ADC_CHANNEL(AIN1, IIO_VOLTAGE, "AIN1"),
+       RN5T618_ADC_CHANNEL(AIN0, IIO_VOLTAGE, "AIN0")
+};
+
+static int rn5t618_adc_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct iio_dev *iio_dev;
+       struct rn5t618_adc_data *adc;
+       struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent);
+
+       iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
+       if (!iio_dev) {
+               dev_err(&pdev->dev, "failed allocating iio device\n");
+               return -ENOMEM;
+       }
+
+       adc = iio_priv(iio_dev);
+       adc->dev = &pdev->dev;
+       adc->rn5t618 = rn5t618;
+
+       if (rn5t618->irq_data)
+               adc->irq = regmap_irq_get_virq(rn5t618->irq_data,
+                                              RN5T618_IRQ_ADC);
+
+       if (adc->irq <= 0) {
+               dev_err(&pdev->dev, "get virq failed\n");
+               return -EINVAL;
+       }
+
+       init_completion(&adc->conv_completion);
+
+       iio_dev->name = dev_name(&pdev->dev);
+       iio_dev->dev.parent = &pdev->dev;
+       iio_dev->info = &rn5t618_adc_iio_info;
+       iio_dev->modes = INDIO_DIRECT_MODE;
+       iio_dev->channels = rn5t618_adc_iio_channels;
+       iio_dev->num_channels = ARRAY_SIZE(rn5t618_adc_iio_channels);
+
+       /* stop any auto-conversion */
+       ret = regmap_write(rn5t618->regmap, RN5T618_ADCCNT3, 0);
+       if (ret < 0)
+               return ret;
+
+       platform_set_drvdata(pdev, iio_dev);
+
+       ret = devm_request_threaded_irq(adc->dev, adc->irq, NULL,
+                                       rn5t618_adc_irq,
+                                       IRQF_ONESHOT, dev_name(adc->dev),
+                                       adc);
+       if (ret < 0) {
+               dev_err(adc->dev, "request irq %d failed: %d\n", adc->irq, ret);
+               return ret;
+       }
+
+       return devm_iio_device_register(adc->dev, iio_dev);
+}
+
+static struct platform_driver rn5t618_adc_driver = {
+       .driver = {
+               .name   = "rn5t618-adc",
+       },
+       .probe = rn5t618_adc_probe,
+};
+
+module_platform_driver(rn5t618_adc_driver);
+MODULE_ALIAS("platform:rn5t618-adc");
+MODULE_DESCRIPTION("RICOH RN5T618 ADC driver");
+MODULE_LICENSE("GPL");
index 1dcc2a1..af801e2 100644 (file)
@@ -97,7 +97,7 @@ static int cros_ec_lid_angle_probe(struct platform_device *pdev)
        if (!indio_dev)
                return -ENOMEM;
 
-       ret = cros_ec_sensors_core_init(pdev, indio_dev, false);
+       ret = cros_ec_sensors_core_init(pdev, indio_dev, false, NULL, NULL);
        if (ret)
                return ret;
 
@@ -127,7 +127,6 @@ MODULE_DEVICE_TABLE(platform, cros_ec_lid_angle_ids);
 static struct platform_driver cros_ec_lid_angle_platform_driver = {
        .driver = {
                .name   = DRV_NAME,
-               .pm     = &cros_ec_sensors_pm_ops,
        },
        .probe          = cros_ec_lid_angle_probe,
        .id_table       = cros_ec_lid_angle_ids,
index 576e45f..a66941f 100644 (file)
@@ -230,10 +230,14 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
        if (!indio_dev)
                return -ENOMEM;
 
-       ret = cros_ec_sensors_core_init(pdev, indio_dev, true);
+       ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
+                                       cros_ec_sensors_capture,
+                                       cros_ec_sensors_push_data);
        if (ret)
                return ret;
 
+       iio_buffer_set_attrs(indio_dev->buffer, cros_ec_sensor_fifo_attributes);
+
        indio_dev->info = &ec_sensors_info;
        state = iio_priv(indio_dev);
        for (channel = state->channels, i = CROS_EC_SENSOR_X;
@@ -245,7 +249,6 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
                        BIT(IIO_CHAN_INFO_CALIBSCALE);
                channel->info_mask_shared_by_all =
                        BIT(IIO_CHAN_INFO_SCALE) |
-                       BIT(IIO_CHAN_INFO_FREQUENCY) |
                        BIT(IIO_CHAN_INFO_SAMP_FREQ);
                channel->info_mask_shared_by_all_available =
                        BIT(IIO_CHAN_INFO_SAMP_FREQ);
@@ -292,11 +295,6 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
        else
                state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
 
-       ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
-                       cros_ec_sensors_capture, NULL);
-       if (ret)
-               return ret;
-
        return devm_iio_device_register(dev, indio_dev);
 }
 
@@ -317,7 +315,6 @@ MODULE_DEVICE_TABLE(platform, cros_ec_sensors_ids);
 static struct platform_driver cros_ec_sensors_platform_driver = {
        .driver = {
                .name   = "cros-ec-sensors",
-               .pm     = &cros_ec_sensors_pm_ops,
        },
        .probe          = cros_ec_sensors_probe,
        .id_table       = cros_ec_sensors_ids,
index d3a3626..c831915 100644 (file)
@@ -11,7 +11,9 @@
 #include <linux/iio/common/cros_ec_sensors_core.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/kfifo_buf.h>
+#include <linux/iio/sysfs.h>
 #include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/platform_data/cros_ec_sensorhub.h>
 #include <linux/platform_device.h>
 
+/*
+ * Hard coded to the first device to support sensor fifo.  The EC has a 2048
+ * byte fifo and will trigger an interrupt when fifo is 2/3 full.
+ */
+#define CROS_EC_FIFO_SIZE (2048 * 2 / 3)
+
 static char *cros_ec_loc[] = {
        [MOTIONSENSE_LOC_BASE] = "base",
        [MOTIONSENSE_LOC_LID] = "lid",
@@ -53,8 +61,15 @@ static int cros_ec_get_host_cmd_version_mask(struct cros_ec_device *ec_dev,
 
 static void get_default_min_max_freq(enum motionsensor_type type,
                                     u32 *min_freq,
-                                    u32 *max_freq)
+                                    u32 *max_freq,
+                                    u32 *max_fifo_events)
 {
+       /*
+        * We don't know fifo size, set to size previously used by older
+        * hardware.
+        */
+       *max_fifo_events = CROS_EC_FIFO_SIZE;
+
        switch (type) {
        case MOTIONSENSE_TYPE_ACCEL:
        case MOTIONSENSE_TYPE_GYRO:
@@ -82,9 +97,155 @@ static void get_default_min_max_freq(enum motionsensor_type type,
        }
 }
 
+static int cros_ec_sensor_set_ec_rate(struct cros_ec_sensors_core_state *st,
+                                     int rate)
+{
+       int ret;
+
+       if (rate > U16_MAX)
+               rate = U16_MAX;
+
+       mutex_lock(&st->cmd_lock);
+       st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
+       st->param.ec_rate.data = rate;
+       ret = cros_ec_motion_send_host_cmd(st, 0);
+       mutex_unlock(&st->cmd_lock);
+       return ret;
+}
+
+static ssize_t cros_ec_sensor_set_report_latency(struct device *dev,
+                                                struct device_attribute *attr,
+                                                const char *buf, size_t len)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
+       int integer, fract, ret;
+       int latency;
+
+       ret = iio_str_to_fixpoint(buf, 100000, &integer, &fract);
+       if (ret)
+               return ret;
+
+       /* EC rate is in ms. */
+       latency = integer * 1000 + fract / 1000;
+       ret = cros_ec_sensor_set_ec_rate(st, latency);
+       if (ret < 0)
+               return ret;
+
+       return len;
+}
+
+static ssize_t cros_ec_sensor_get_report_latency(struct device *dev,
+                                                struct device_attribute *attr,
+                                                char *buf)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
+       int latency, ret;
+
+       mutex_lock(&st->cmd_lock);
+       st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
+       st->param.ec_rate.data = EC_MOTION_SENSE_NO_VALUE;
+
+       ret = cros_ec_motion_send_host_cmd(st, 0);
+       latency = st->resp->ec_rate.ret;
+       mutex_unlock(&st->cmd_lock);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%d.%06u\n",
+                      latency / 1000,
+                      (latency % 1000) * 1000);
+}
+
+static IIO_DEVICE_ATTR(hwfifo_timeout, 0644,
+                      cros_ec_sensor_get_report_latency,
+                      cros_ec_sensor_set_report_latency, 0);
+
+static ssize_t hwfifo_watermark_max_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
+
+       return sprintf(buf, "%d\n", st->fifo_max_event_count);
+}
+
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
+
+const struct attribute *cros_ec_sensor_fifo_attributes[] = {
+       &iio_dev_attr_hwfifo_timeout.dev_attr.attr,
+       &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr,
+       NULL,
+};
+EXPORT_SYMBOL_GPL(cros_ec_sensor_fifo_attributes);
+
+int cros_ec_sensors_push_data(struct iio_dev *indio_dev,
+                             s16 *data,
+                             s64 timestamp)
+{
+       struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
+       s16 *out;
+       s64 delta;
+       unsigned int i;
+
+       /*
+        * Ignore samples if the buffer is not set: it is needed if the ODR is
+        * set but the buffer is not enabled yet.
+        */
+       if (!iio_buffer_enabled(indio_dev))
+               return 0;
+
+       out = (s16 *)st->samples;
+       for_each_set_bit(i,
+                        indio_dev->active_scan_mask,
+                        indio_dev->masklength) {
+               *out = data[i];
+               out++;
+       }
+
+       if (iio_device_get_clock(indio_dev) != CLOCK_BOOTTIME)
+               delta = iio_get_time_ns(indio_dev) - cros_ec_get_time_ns();
+       else
+               delta = 0;
+
+       iio_push_to_buffers_with_timestamp(indio_dev, st->samples,
+                                          timestamp + delta);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cros_ec_sensors_push_data);
+
+static void cros_ec_sensors_core_clean(void *arg)
+{
+       struct platform_device *pdev = (struct platform_device *)arg;
+       struct cros_ec_sensorhub *sensor_hub =
+               dev_get_drvdata(pdev->dev.parent);
+       struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+       struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
+       u8 sensor_num = st->param.info.sensor_num;
+
+       cros_ec_sensorhub_unregister_push_data(sensor_hub, sensor_num);
+}
+
+/**
+ * cros_ec_sensors_core_init() - basic initialization of the core structure
+ * @pdev:              platform device created for the sensors
+ * @indio_dev:         iio device structure of the device
+ * @physical_device:   true if the device refers to a physical device
+ * @trigger_capture:    function pointer to call buffer is triggered,
+ *    for backward compatibility.
+ * @push_data:          function to call when cros_ec_sensorhub receives
+ *    a sample for that sensor.
+ *
+ * Return: 0 on success, -errno on failure.
+ */
 int cros_ec_sensors_core_init(struct platform_device *pdev,
                              struct iio_dev *indio_dev,
-                             bool physical_device)
+                             bool physical_device,
+                             cros_ec_sensors_capture_t trigger_capture,
+                             cros_ec_sensorhub_push_data_cb_t push_data)
 {
        struct device *dev = &pdev->dev;
        struct cros_ec_sensors_core_state *state = iio_priv(indio_dev);
@@ -92,6 +253,7 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
        struct cros_ec_dev *ec = sensor_hub->ec;
        struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev);
        u32 ver_mask;
+       int frequencies[ARRAY_SIZE(state->frequencies) / 2] = { 0 };
        int ret, i;
 
        platform_set_drvdata(pdev, indio_dev);
@@ -123,8 +285,6 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
        indio_dev->name = pdev->name;
 
        if (physical_device) {
-               indio_dev->modes = INDIO_DIRECT_MODE;
-
                state->param.cmd = MOTIONSENSE_CMD_INFO;
                state->param.info.sensor_num = sensor_platform->sensor_num;
                ret = cros_ec_motion_send_host_cmd(state, 0);
@@ -142,16 +302,63 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
                        state->calib[i].scale = MOTION_SENSE_DEFAULT_SCALE;
 
                /* 0 is a correct value used to stop the device */
-               state->frequencies[0] = 0;
                if (state->msg->version < 3) {
                        get_default_min_max_freq(state->resp->info.type,
-                                                &state->frequencies[1],
-                                                &state->frequencies[2]);
+                                                &frequencies[1],
+                                                &frequencies[2],
+                                                &state->fifo_max_event_count);
                } else {
-                       state->frequencies[1] =
-                           state->resp->info_3.min_frequency;
-                       state->frequencies[2] =
-                           state->resp->info_3.max_frequency;
+                       frequencies[1] = state->resp->info_3.min_frequency;
+                       frequencies[2] = state->resp->info_3.max_frequency;
+                       state->fifo_max_event_count =
+                           state->resp->info_3.fifo_max_event_count;
+               }
+               for (i = 0; i < ARRAY_SIZE(frequencies); i++) {
+                       state->frequencies[2 * i] = frequencies[i] / 1000;
+                       state->frequencies[2 * i + 1] =
+                               (frequencies[i] % 1000) * 1000;
+               }
+
+               if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) {
+                       /*
+                        * Create a software buffer, feed by the EC FIFO.
+                        * We can not use trigger here, as events are generated
+                        * as soon as sample_frequency is set.
+                        */
+                       struct iio_buffer *buffer;
+
+                       buffer = devm_iio_kfifo_allocate(dev);
+                       if (!buffer)
+                               return -ENOMEM;
+
+                       iio_device_attach_buffer(indio_dev, buffer);
+                       indio_dev->modes = INDIO_BUFFER_SOFTWARE;
+
+                       ret = cros_ec_sensorhub_register_push_data(
+                                       sensor_hub, sensor_platform->sensor_num,
+                                       indio_dev, push_data);
+                       if (ret)
+                               return ret;
+
+                       ret = devm_add_action_or_reset(
+                                       dev, cros_ec_sensors_core_clean, pdev);
+                       if (ret)
+                               return ret;
+
+                       /* Timestamp coming from FIFO are in ns since boot. */
+                       ret = iio_device_set_clock(indio_dev, CLOCK_BOOTTIME);
+                       if (ret)
+                               return ret;
+               } else {
+                       /*
+                        * The only way to get samples in buffer is to set a
+                        * software tigger (systrig, hrtimer).
+                        */
+                       ret = devm_iio_triggered_buffer_setup(
+                                       dev, indio_dev, NULL, trigger_capture,
+                                       NULL);
+                       if (ret)
+                               return ret;
                }
        }
 
@@ -159,6 +366,16 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
 }
 EXPORT_SYMBOL_GPL(cros_ec_sensors_core_init);
 
+/**
+ * cros_ec_motion_send_host_cmd() - send motion sense host command
+ * @state:             pointer to state information for device
+ * @opt_length:        optional length to reduce the response size, useful on the data
+ *             path. Otherwise, the maximal allowed response size is used
+ *
+ * When called, the sub-command is assumed to be set in param->cmd.
+ *
+ * Return: 0 on success, -errno on failure.
+ */
 int cros_ec_motion_send_host_cmd(struct cros_ec_sensors_core_state *state,
                                 u16 opt_length)
 {
@@ -421,6 +638,14 @@ int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev,
 }
 EXPORT_SYMBOL_GPL(cros_ec_sensors_read_lpc);
 
+/**
+ * cros_ec_sensors_read_cmd() - retrieve data using the EC command protocol
+ * @indio_dev: pointer to IIO device
+ * @scan_mask: bitmap of the sensor indices to scan
+ * @data:      location to store data
+ *
+ * Return: 0 on success, -errno on failure.
+ */
 int cros_ec_sensors_read_cmd(struct iio_dev *indio_dev,
                             unsigned long scan_mask, s16 *data)
 {
@@ -445,6 +670,18 @@ int cros_ec_sensors_read_cmd(struct iio_dev *indio_dev,
 }
 EXPORT_SYMBOL_GPL(cros_ec_sensors_read_cmd);
 
+/**
+ * cros_ec_sensors_capture() - the trigger handler function
+ * @irq:       the interrupt number.
+ * @p:         a pointer to the poll function.
+ *
+ * On a trigger event occurring, if the pollfunc is attached then this
+ * handler is called as a threaded interrupt (and hence may sleep). It
+ * is responsible for grabbing data from the device and pushing it into
+ * the associated buffer.
+ *
+ * Return: IRQ_HANDLED
+ */
 irqreturn_t cros_ec_sensors_capture(int irq, void *p)
 {
        struct iio_poll_func *pf = p;
@@ -480,26 +717,24 @@ done:
 }
 EXPORT_SYMBOL_GPL(cros_ec_sensors_capture);
 
+/**
+ * cros_ec_sensors_core_read() - function to request a value from the sensor
+ * @st:                pointer to state information for device
+ * @chan:      channel specification structure table
+ * @val:       will contain one element making up the returned value
+ * @val2:      will contain another element making up the returned value
+ * @mask:      specifies which values to be requested
+ *
+ * Return:     the type of value returned by the device
+ */
 int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st,
                          struct iio_chan_spec const *chan,
                          int *val, int *val2, long mask)
 {
-       int ret;
+       int ret, frequency;
 
        switch (mask) {
        case IIO_CHAN_INFO_SAMP_FREQ:
-               st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
-               st->param.ec_rate.data =
-                       EC_MOTION_SENSE_NO_VALUE;
-
-               ret = cros_ec_motion_send_host_cmd(st, 0);
-               if (ret)
-                       break;
-
-               *val = st->resp->ec_rate.ret;
-               ret = IIO_VAL_INT;
-               break;
-       case IIO_CHAN_INFO_FREQUENCY:
                st->param.cmd = MOTIONSENSE_CMD_SENSOR_ODR;
                st->param.sensor_odr.data =
                        EC_MOTION_SENSE_NO_VALUE;
@@ -508,8 +743,10 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st,
                if (ret)
                        break;
 
-               *val = st->resp->sensor_odr.ret;
-               ret = IIO_VAL_INT;
+               frequency = st->resp->sensor_odr.ret;
+               *val = frequency / 1000;
+               *val2 = (frequency % 1000) * 1000;
+               ret = IIO_VAL_INT_PLUS_MICRO;
                break;
        default:
                ret = -EINVAL;
@@ -520,6 +757,17 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st,
 }
 EXPORT_SYMBOL_GPL(cros_ec_sensors_core_read);
 
+/**
+ * cros_ec_sensors_core_read_avail() - get available values
+ * @indio_dev:         pointer to state information for device
+ * @chan:      channel specification structure table
+ * @vals:      list of available values
+ * @type:      type of data returned
+ * @length:    number of data returned in the array
+ * @mask:      specifies which values to be requested
+ *
+ * Return:     an error code, IIO_AVAIL_RANGE or IIO_AVAIL_LIST
+ */
 int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev,
                                    struct iio_chan_spec const *chan,
                                    const int **vals,
@@ -533,7 +781,7 @@ int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev,
        case IIO_CHAN_INFO_SAMP_FREQ:
                *length = ARRAY_SIZE(state->frequencies);
                *vals = (const int *)&state->frequencies;
-               *type = IIO_VAL_INT;
+               *type = IIO_VAL_INT_PLUS_MICRO;
                return IIO_AVAIL_LIST;
        }
 
@@ -541,31 +789,33 @@ int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev,
 }
 EXPORT_SYMBOL_GPL(cros_ec_sensors_core_read_avail);
 
+/**
+ * cros_ec_sensors_core_write() - function to write a value to the sensor
+ * @st:                pointer to state information for device
+ * @chan:      channel specification structure table
+ * @val:       first part of value to write
+ * @val2:      second part of value to write
+ * @mask:      specifies which values to write
+ *
+ * Return:     the type of value returned by the device
+ */
 int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st,
                               struct iio_chan_spec const *chan,
                               int val, int val2, long mask)
 {
-       int ret;
+       int ret, frequency;
 
        switch (mask) {
-       case IIO_CHAN_INFO_FREQUENCY:
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               frequency = val * 1000 + val2 / 1000;
                st->param.cmd = MOTIONSENSE_CMD_SENSOR_ODR;
-               st->param.sensor_odr.data = val;
+               st->param.sensor_odr.data = frequency;
 
                /* Always roundup, so caller gets at least what it asks for. */
                st->param.sensor_odr.roundup = 1;
 
                ret = cros_ec_motion_send_host_cmd(st, 0);
                break;
-       case IIO_CHAN_INFO_SAMP_FREQ:
-               st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
-               st->param.ec_rate.data = val;
-
-               ret = cros_ec_motion_send_host_cmd(st, 0);
-               if (ret)
-                       break;
-               st->curr_sampl_freq = val;
-               break;
        default:
                ret = -EINVAL;
                break;
@@ -574,52 +824,5 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st,
 }
 EXPORT_SYMBOL_GPL(cros_ec_sensors_core_write);
 
-static int __maybe_unused cros_ec_sensors_prepare(struct device *dev)
-{
-       struct iio_dev *indio_dev = dev_get_drvdata(dev);
-       struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
-
-       if (st->curr_sampl_freq == 0)
-               return 0;
-
-       /*
-        * If the sensors are sampled at high frequency, we will not be able to
-        * sleep. Set sampling to a long period if necessary.
-        */
-       if (st->curr_sampl_freq < CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY) {
-               mutex_lock(&st->cmd_lock);
-               st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
-               st->param.ec_rate.data = CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY;
-               cros_ec_motion_send_host_cmd(st, 0);
-               mutex_unlock(&st->cmd_lock);
-       }
-       return 0;
-}
-
-static void __maybe_unused cros_ec_sensors_complete(struct device *dev)
-{
-       struct iio_dev *indio_dev = dev_get_drvdata(dev);
-       struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
-
-       if (st->curr_sampl_freq == 0)
-               return;
-
-       if (st->curr_sampl_freq < CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY) {
-               mutex_lock(&st->cmd_lock);
-               st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
-               st->param.ec_rate.data = st->curr_sampl_freq;
-               cros_ec_motion_send_host_cmd(st, 0);
-               mutex_unlock(&st->cmd_lock);
-       }
-}
-
-const struct dev_pm_ops cros_ec_sensors_pm_ops = {
-#ifdef CONFIG_PM_SLEEP
-       .prepare = cros_ec_sensors_prepare,
-       .complete = cros_ec_sensors_complete
-#endif
-};
-EXPORT_SYMBOL_GPL(cros_ec_sensors_pm_ops);
-
 MODULE_DESCRIPTION("ChromeOS EC sensor hub core functions");
 MODULE_LICENSE("GPL v2");
index eac63c1..2352c42 100644 (file)
@@ -189,7 +189,12 @@ ssize_t iio_read_const_attr(struct device *dev,
 }
 EXPORT_SYMBOL(iio_read_const_attr);
 
-static int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
+/**
+ * iio_device_set_clock() - Set current timestamping clock for the device
+ * @indio_dev: IIO device structure containing the device
+ * @clock_id: timestamping clock posix identifier to set.
+ */
+int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
 {
        int ret;
        const struct iio_event_interface *ev_int = indio_dev->event_interface;
@@ -207,6 +212,7 @@ static int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
 
        return 0;
 }
+EXPORT_SYMBOL(iio_device_set_clock);
 
 /**
  * iio_get_time_ns() - utility function to get a time stamp for events etc
index 74970f1..b27719c 100644 (file)
@@ -194,6 +194,16 @@ config GP2AP020A00F
          To compile this driver as a module, choose M here: the
          module will be called gp2ap020a00f.
 
+config IQS621_ALS
+       tristate "Azoteq IQS621/622 ambient light sensors"
+       depends on MFD_IQS62X || COMPILE_TEST
+       help
+         Say Y here if you want to build support for the Azoteq IQS621
+         and IQS622 ambient light sensors.
+
+         To compile this driver as a module, choose M here: the module
+         will be called iqs621-als.
+
 config SENSORS_ISL29018
        tristate "Intersil 29018 light and proximity sensor"
        depends on I2C
index 5c1ebaf..d1c8aa3 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_GP2AP002)                += gp2ap002.o
 obj-$(CONFIG_GP2AP020A00F)     += gp2ap020a00f.o
 obj-$(CONFIG_HID_SENSOR_ALS)   += hid-sensor-als.o
 obj-$(CONFIG_HID_SENSOR_PROX)  += hid-sensor-prox.o
+obj-$(CONFIG_IQS621_ALS)       += iqs621-als.o
 obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o
 obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o
 obj-$(CONFIG_ISL29125)         += isl29125.o
index 7a838e2..2198b50 100644 (file)
@@ -177,10 +177,14 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev)
        if (!indio_dev)
                return -ENOMEM;
 
-       ret = cros_ec_sensors_core_init(pdev, indio_dev, true);
+       ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
+                                       cros_ec_sensors_capture,
+                                       cros_ec_sensors_push_data);
        if (ret)
                return ret;
 
+       iio_buffer_set_attrs(indio_dev->buffer, cros_ec_sensor_fifo_attributes);
+
        indio_dev->info = &cros_ec_light_prox_info;
        state = iio_priv(indio_dev);
        state->core.type = state->core.resp->info.type;
@@ -189,8 +193,7 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev)
 
        /* Common part */
        channel->info_mask_shared_by_all =
-               BIT(IIO_CHAN_INFO_SAMP_FREQ) |
-               BIT(IIO_CHAN_INFO_FREQUENCY);
+               BIT(IIO_CHAN_INFO_SAMP_FREQ);
        channel->info_mask_shared_by_all_available =
                BIT(IIO_CHAN_INFO_SAMP_FREQ);
        channel->scan_type.realbits = CROS_EC_SENSOR_BITS;
@@ -236,11 +239,6 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev)
 
        state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
 
-       ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
-                                             cros_ec_sensors_capture, NULL);
-       if (ret)
-               return ret;
-
        return devm_iio_device_register(dev, indio_dev);
 }
 
@@ -258,7 +256,6 @@ MODULE_DEVICE_TABLE(platform, cros_ec_light_prox_ids);
 static struct platform_driver cros_ec_light_prox_platform_driver = {
        .driver = {
                .name   = "cros-ec-light-prox",
-               .pm     = &cros_ec_sensors_pm_ops,
        },
        .probe          = cros_ec_light_prox_probe,
        .id_table       = cros_ec_light_prox_ids,
diff --git a/drivers/iio/light/iqs621-als.c b/drivers/iio/light/iqs621-als.c
new file mode 100644 (file)
index 0000000..b2988a7
--- /dev/null
@@ -0,0 +1,617 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS621/622 Ambient Light Sensors
+ *
+ * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
+ */
+
+#include <linux/device.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/mfd/iqs62x.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define IQS621_ALS_FLAGS_LIGHT                 BIT(7)
+#define IQS621_ALS_FLAGS_RANGE                 GENMASK(3, 0)
+
+#define IQS621_ALS_UI_OUT                      0x17
+
+#define IQS621_ALS_THRESH_DARK                 0x80
+#define IQS621_ALS_THRESH_LIGHT                        0x81
+
+#define IQS622_IR_RANGE                                0x15
+#define IQS622_IR_FLAGS                                0x16
+#define IQS622_IR_FLAGS_TOUCH                  BIT(1)
+#define IQS622_IR_FLAGS_PROX                   BIT(0)
+
+#define IQS622_IR_UI_OUT                       0x17
+
+#define IQS622_IR_THRESH_PROX                  0x91
+#define IQS622_IR_THRESH_TOUCH                 0x92
+
+struct iqs621_als_private {
+       struct iqs62x_core *iqs62x;
+       struct notifier_block notifier;
+       struct mutex lock;
+       bool light_en;
+       bool range_en;
+       bool prox_en;
+       u8 als_flags;
+       u8 ir_flags_mask;
+       u8 ir_flags;
+       u8 thresh_light;
+       u8 thresh_dark;
+       u8 thresh_prox;
+};
+
+static int iqs621_als_init(struct iqs621_als_private *iqs621_als)
+{
+       struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
+       unsigned int event_mask = 0;
+       int ret;
+
+       switch (iqs621_als->ir_flags_mask) {
+       case IQS622_IR_FLAGS_TOUCH:
+               ret = regmap_write(iqs62x->regmap, IQS622_IR_THRESH_TOUCH,
+                                  iqs621_als->thresh_prox);
+               break;
+
+       case IQS622_IR_FLAGS_PROX:
+               ret = regmap_write(iqs62x->regmap, IQS622_IR_THRESH_PROX,
+                                  iqs621_als->thresh_prox);
+               break;
+
+       default:
+               ret = regmap_write(iqs62x->regmap, IQS621_ALS_THRESH_LIGHT,
+                                  iqs621_als->thresh_light);
+               if (ret)
+                       return ret;
+
+               ret = regmap_write(iqs62x->regmap, IQS621_ALS_THRESH_DARK,
+                                  iqs621_als->thresh_dark);
+       }
+
+       if (ret)
+               return ret;
+
+       if (iqs621_als->light_en || iqs621_als->range_en)
+               event_mask |= iqs62x->dev_desc->als_mask;
+
+       if (iqs621_als->prox_en)
+               event_mask |= iqs62x->dev_desc->ir_mask;
+
+       return regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
+                                 event_mask, 0);
+}
+
+static int iqs621_als_notifier(struct notifier_block *notifier,
+                              unsigned long event_flags, void *context)
+{
+       struct iqs62x_event_data *event_data = context;
+       struct iqs621_als_private *iqs621_als;
+       struct iio_dev *indio_dev;
+       bool light_new, light_old;
+       bool prox_new, prox_old;
+       u8 range_new, range_old;
+       s64 timestamp;
+       int ret;
+
+       iqs621_als = container_of(notifier, struct iqs621_als_private,
+                                 notifier);
+       indio_dev = iio_priv_to_dev(iqs621_als);
+       timestamp = iio_get_time_ns(indio_dev);
+
+       mutex_lock(&iqs621_als->lock);
+
+       if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {
+               ret = iqs621_als_init(iqs621_als);
+               if (ret) {
+                       dev_err(indio_dev->dev.parent,
+                               "Failed to re-initialize device: %d\n", ret);
+                       ret = NOTIFY_BAD;
+               } else {
+                       ret = NOTIFY_OK;
+               }
+
+               goto err_mutex;
+       }
+
+       if (!iqs621_als->light_en && !iqs621_als->range_en &&
+           !iqs621_als->prox_en) {
+               ret = NOTIFY_DONE;
+               goto err_mutex;
+       }
+
+       /* IQS621 only */
+       light_new = event_data->als_flags & IQS621_ALS_FLAGS_LIGHT;
+       light_old = iqs621_als->als_flags & IQS621_ALS_FLAGS_LIGHT;
+
+       if (iqs621_als->light_en && light_new && !light_old)
+               iio_push_event(indio_dev,
+                              IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
+                                                   IIO_EV_TYPE_THRESH,
+                                                   IIO_EV_DIR_RISING),
+                              timestamp);
+       else if (iqs621_als->light_en && !light_new && light_old)
+               iio_push_event(indio_dev,
+                              IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
+                                                   IIO_EV_TYPE_THRESH,
+                                                   IIO_EV_DIR_FALLING),
+                              timestamp);
+
+       /* IQS621 and IQS622 */
+       range_new = event_data->als_flags & IQS621_ALS_FLAGS_RANGE;
+       range_old = iqs621_als->als_flags & IQS621_ALS_FLAGS_RANGE;
+
+       if (iqs621_als->range_en && (range_new > range_old))
+               iio_push_event(indio_dev,
+                              IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
+                                                   IIO_EV_TYPE_CHANGE,
+                                                   IIO_EV_DIR_RISING),
+                              timestamp);
+       else if (iqs621_als->range_en && (range_new < range_old))
+               iio_push_event(indio_dev,
+                              IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
+                                                   IIO_EV_TYPE_CHANGE,
+                                                   IIO_EV_DIR_FALLING),
+                              timestamp);
+
+       /* IQS622 only */
+       prox_new = event_data->ir_flags & iqs621_als->ir_flags_mask;
+       prox_old = iqs621_als->ir_flags & iqs621_als->ir_flags_mask;
+
+       if (iqs621_als->prox_en && prox_new && !prox_old)
+               iio_push_event(indio_dev,
+                              IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
+                                                   IIO_EV_TYPE_THRESH,
+                                                   IIO_EV_DIR_RISING),
+                              timestamp);
+       else if (iqs621_als->prox_en && !prox_new && prox_old)
+               iio_push_event(indio_dev,
+                              IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
+                                                   IIO_EV_TYPE_THRESH,
+                                                   IIO_EV_DIR_FALLING),
+                              timestamp);
+
+       iqs621_als->als_flags = event_data->als_flags;
+       iqs621_als->ir_flags = event_data->ir_flags;
+       ret = NOTIFY_OK;
+
+err_mutex:
+       mutex_unlock(&iqs621_als->lock);
+
+       return ret;
+}
+
+static void iqs621_als_notifier_unregister(void *context)
+{
+       struct iqs621_als_private *iqs621_als = context;
+       struct iio_dev *indio_dev = iio_priv_to_dev(iqs621_als);
+       int ret;
+
+       ret = blocking_notifier_chain_unregister(&iqs621_als->iqs62x->nh,
+                                                &iqs621_als->notifier);
+       if (ret)
+               dev_err(indio_dev->dev.parent,
+                       "Failed to unregister notifier: %d\n", ret);
+}
+
+static int iqs621_als_read_raw(struct iio_dev *indio_dev,
+                              struct iio_chan_spec const *chan,
+                              int *val, int *val2, long mask)
+{
+       struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
+       struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
+       int ret;
+       __le16 val_buf;
+
+       switch (chan->type) {
+       case IIO_INTENSITY:
+               ret = regmap_read(iqs62x->regmap, chan->address, val);
+               if (ret)
+                       return ret;
+
+               *val &= IQS621_ALS_FLAGS_RANGE;
+               return IIO_VAL_INT;
+
+       case IIO_PROXIMITY:
+       case IIO_LIGHT:
+               ret = regmap_raw_read(iqs62x->regmap, chan->address, &val_buf,
+                                     sizeof(val_buf));
+               if (ret)
+                       return ret;
+
+               *val = le16_to_cpu(val_buf);
+               return IIO_VAL_INT;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int iqs621_als_read_event_config(struct iio_dev *indio_dev,
+                                       const struct iio_chan_spec *chan,
+                                       enum iio_event_type type,
+                                       enum iio_event_direction dir)
+{
+       struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
+       int ret;
+
+       mutex_lock(&iqs621_als->lock);
+
+       switch (chan->type) {
+       case IIO_LIGHT:
+               ret = iqs621_als->light_en;
+               break;
+
+       case IIO_INTENSITY:
+               ret = iqs621_als->range_en;
+               break;
+
+       case IIO_PROXIMITY:
+               ret = iqs621_als->prox_en;
+               break;
+
+       default:
+               ret = -EINVAL;
+       }
+
+       mutex_unlock(&iqs621_als->lock);
+
+       return ret;
+}
+
+static int iqs621_als_write_event_config(struct iio_dev *indio_dev,
+                                        const struct iio_chan_spec *chan,
+                                        enum iio_event_type type,
+                                        enum iio_event_direction dir,
+                                        int state)
+{
+       struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
+       struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
+       unsigned int val;
+       int ret;
+
+       mutex_lock(&iqs621_als->lock);
+
+       ret = regmap_read(iqs62x->regmap, iqs62x->dev_desc->als_flags, &val);
+       if (ret)
+               goto err_mutex;
+       iqs621_als->als_flags = val;
+
+       switch (chan->type) {
+       case IIO_LIGHT:
+               ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
+                                        iqs62x->dev_desc->als_mask,
+                                        iqs621_als->range_en || state ? 0 :
+                                                                        0xFF);
+               if (!ret)
+                       iqs621_als->light_en = state;
+               break;
+
+       case IIO_INTENSITY:
+               ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
+                                        iqs62x->dev_desc->als_mask,
+                                        iqs621_als->light_en || state ? 0 :
+                                                                        0xFF);
+               if (!ret)
+                       iqs621_als->range_en = state;
+               break;
+
+       case IIO_PROXIMITY:
+               ret = regmap_read(iqs62x->regmap, IQS622_IR_FLAGS, &val);
+               if (ret)
+                       goto err_mutex;
+               iqs621_als->ir_flags = val;
+
+               ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
+                                        iqs62x->dev_desc->ir_mask,
+                                        state ? 0 : 0xFF);
+               if (!ret)
+                       iqs621_als->prox_en = state;
+               break;
+
+       default:
+               ret = -EINVAL;
+       }
+
+err_mutex:
+       mutex_unlock(&iqs621_als->lock);
+
+       return ret;
+}
+
+static int iqs621_als_read_event_value(struct iio_dev *indio_dev,
+                                      const struct iio_chan_spec *chan,
+                                      enum iio_event_type type,
+                                      enum iio_event_direction dir,
+                                      enum iio_event_info info,
+                                      int *val, int *val2)
+{
+       struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
+       int ret = IIO_VAL_INT;
+
+       mutex_lock(&iqs621_als->lock);
+
+       switch (dir) {
+       case IIO_EV_DIR_RISING:
+               *val = iqs621_als->thresh_light * 16;
+               break;
+
+       case IIO_EV_DIR_FALLING:
+               *val = iqs621_als->thresh_dark * 4;
+               break;
+
+       case IIO_EV_DIR_EITHER:
+               if (iqs621_als->ir_flags_mask == IQS622_IR_FLAGS_TOUCH)
+                       *val = iqs621_als->thresh_prox * 4;
+               else
+                       *val = iqs621_als->thresh_prox;
+               break;
+
+       default:
+               ret = -EINVAL;
+       }
+
+       mutex_unlock(&iqs621_als->lock);
+
+       return ret;
+}
+
+static int iqs621_als_write_event_value(struct iio_dev *indio_dev,
+                                       const struct iio_chan_spec *chan,
+                                       enum iio_event_type type,
+                                       enum iio_event_direction dir,
+                                       enum iio_event_info info,
+                                       int val, int val2)
+{
+       struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
+       struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
+       unsigned int thresh_reg, thresh_val;
+       u8 ir_flags_mask, *thresh_cache;
+       int ret = -EINVAL;
+
+       mutex_lock(&iqs621_als->lock);
+
+       switch (dir) {
+       case IIO_EV_DIR_RISING:
+               thresh_reg = IQS621_ALS_THRESH_LIGHT;
+               thresh_val = val / 16;
+
+               thresh_cache = &iqs621_als->thresh_light;
+               ir_flags_mask = 0;
+               break;
+
+       case IIO_EV_DIR_FALLING:
+               thresh_reg = IQS621_ALS_THRESH_DARK;
+               thresh_val = val / 4;
+
+               thresh_cache = &iqs621_als->thresh_dark;
+               ir_flags_mask = 0;
+               break;
+
+       case IIO_EV_DIR_EITHER:
+               /*
+                * The IQS622 supports two detection thresholds, both measured
+                * in the same arbitrary units reported by read_raw: proximity
+                * (0 through 255 in steps of 1), and touch (0 through 1020 in
+                * steps of 4).
+                *
+                * Based on the single detection threshold chosen by the user,
+                * select the hardware threshold that gives the best trade-off
+                * between range and resolution.
+                *
+                * By default, the close-range (but coarse) touch threshold is
+                * chosen during probe.
+                */
+               switch (val) {
+               case 0 ... 255:
+                       thresh_reg = IQS622_IR_THRESH_PROX;
+                       thresh_val = val;
+
+                       ir_flags_mask = IQS622_IR_FLAGS_PROX;
+                       break;
+
+               case 256 ... 1020:
+                       thresh_reg = IQS622_IR_THRESH_TOUCH;
+                       thresh_val = val / 4;
+
+                       ir_flags_mask = IQS622_IR_FLAGS_TOUCH;
+                       break;
+
+               default:
+                       goto err_mutex;
+               }
+
+               thresh_cache = &iqs621_als->thresh_prox;
+               break;
+
+       default:
+               goto err_mutex;
+       }
+
+       if (thresh_val > 0xFF)
+               goto err_mutex;
+
+       ret = regmap_write(iqs62x->regmap, thresh_reg, thresh_val);
+       if (ret)
+               goto err_mutex;
+
+       *thresh_cache = thresh_val;
+       iqs621_als->ir_flags_mask = ir_flags_mask;
+
+err_mutex:
+       mutex_unlock(&iqs621_als->lock);
+
+       return ret;
+}
+
+static const struct iio_info iqs621_als_info = {
+       .read_raw = &iqs621_als_read_raw,
+       .read_event_config = iqs621_als_read_event_config,
+       .write_event_config = iqs621_als_write_event_config,
+       .read_event_value = iqs621_als_read_event_value,
+       .write_event_value = iqs621_als_write_event_value,
+};
+
+static const struct iio_event_spec iqs621_als_range_events[] = {
+       {
+               .type = IIO_EV_TYPE_CHANGE,
+               .dir = IIO_EV_DIR_EITHER,
+               .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+       },
+};
+
+static const struct iio_event_spec iqs621_als_light_events[] = {
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_EITHER,
+               .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+       },
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_RISING,
+               .mask_separate = BIT(IIO_EV_INFO_VALUE),
+       },
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_FALLING,
+               .mask_separate = BIT(IIO_EV_INFO_VALUE),
+       },
+};
+
+static const struct iio_chan_spec iqs621_als_channels[] = {
+       {
+               .type = IIO_INTENSITY,
+               .address = IQS621_ALS_FLAGS,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .event_spec = iqs621_als_range_events,
+               .num_event_specs = ARRAY_SIZE(iqs621_als_range_events),
+       },
+       {
+               .type = IIO_LIGHT,
+               .address = IQS621_ALS_UI_OUT,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+               .event_spec = iqs621_als_light_events,
+               .num_event_specs = ARRAY_SIZE(iqs621_als_light_events),
+       },
+};
+
+static const struct iio_event_spec iqs622_als_prox_events[] = {
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_EITHER,
+               .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+                                BIT(IIO_EV_INFO_VALUE),
+       },
+};
+
+static const struct iio_chan_spec iqs622_als_channels[] = {
+       {
+               .type = IIO_INTENSITY,
+               .channel2 = IIO_MOD_LIGHT_BOTH,
+               .address = IQS622_ALS_FLAGS,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .event_spec = iqs621_als_range_events,
+               .num_event_specs = ARRAY_SIZE(iqs621_als_range_events),
+               .modified = true,
+       },
+       {
+               .type = IIO_INTENSITY,
+               .channel2 = IIO_MOD_LIGHT_IR,
+               .address = IQS622_IR_RANGE,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .modified = true,
+       },
+       {
+               .type = IIO_PROXIMITY,
+               .address = IQS622_IR_UI_OUT,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .event_spec = iqs622_als_prox_events,
+               .num_event_specs = ARRAY_SIZE(iqs622_als_prox_events),
+       },
+};
+
+static int iqs621_als_probe(struct platform_device *pdev)
+{
+       struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
+       struct iqs621_als_private *iqs621_als;
+       struct iio_dev *indio_dev;
+       unsigned int val;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*iqs621_als));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       iqs621_als = iio_priv(indio_dev);
+       iqs621_als->iqs62x = iqs62x;
+
+       if (iqs62x->dev_desc->prod_num == IQS622_PROD_NUM) {
+               ret = regmap_read(iqs62x->regmap, IQS622_IR_THRESH_TOUCH,
+                                 &val);
+               if (ret)
+                       return ret;
+               iqs621_als->thresh_prox = val;
+               iqs621_als->ir_flags_mask = IQS622_IR_FLAGS_TOUCH;
+
+               indio_dev->channels = iqs622_als_channels;
+               indio_dev->num_channels = ARRAY_SIZE(iqs622_als_channels);
+       } else {
+               ret = regmap_read(iqs62x->regmap, IQS621_ALS_THRESH_LIGHT,
+                                 &val);
+               if (ret)
+                       return ret;
+               iqs621_als->thresh_light = val;
+
+               ret = regmap_read(iqs62x->regmap, IQS621_ALS_THRESH_DARK,
+                                 &val);
+               if (ret)
+                       return ret;
+               iqs621_als->thresh_dark = val;
+
+               indio_dev->channels = iqs621_als_channels;
+               indio_dev->num_channels = ARRAY_SIZE(iqs621_als_channels);
+       }
+
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->dev.parent = &pdev->dev;
+       indio_dev->name = iqs62x->dev_desc->dev_name;
+       indio_dev->info = &iqs621_als_info;
+
+       mutex_init(&iqs621_als->lock);
+
+       iqs621_als->notifier.notifier_call = iqs621_als_notifier;
+       ret = blocking_notifier_chain_register(&iqs621_als->iqs62x->nh,
+                                              &iqs621_als->notifier);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_add_action_or_reset(&pdev->dev,
+                                      iqs621_als_notifier_unregister,
+                                      iqs621_als);
+       if (ret)
+               return ret;
+
+       return devm_iio_device_register(&pdev->dev, indio_dev);
+}
+
+static struct platform_driver iqs621_als_platform_driver = {
+       .driver = {
+               .name = "iqs621-als",
+       },
+       .probe = iqs621_als_probe,
+};
+module_platform_driver(iqs621_als_platform_driver);
+
+MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
+MODULE_DESCRIPTION("Azoteq IQS621/622 Ambient Light Sensors");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:iqs621-als");
diff --git a/drivers/iio/position/Kconfig b/drivers/iio/position/Kconfig
new file mode 100644 (file)
index 0000000..eda67f0
--- /dev/null
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Linear and angular position sensors
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Linear and angular position sensors"
+
+config IQS624_POS
+       tristate "Azoteq IQS624/625 angular position sensors"
+       depends on MFD_IQS62X || COMPILE_TEST
+       help
+         Say Y here if you want to build support for the Azoteq IQS624
+         and IQS625 angular position sensors.
+
+         To compile this driver as a module, choose M here: the module
+         will be called iqs624-pos.
+
+endmenu
diff --git a/drivers/iio/position/Makefile b/drivers/iio/position/Makefile
new file mode 100644 (file)
index 0000000..3cbe7a7
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for IIO linear and angular position sensors
+#
+
+# When adding new entries keep the list in alphabetical order
+
+obj-$(CONFIG_IQS624_POS)       += iqs624-pos.o
diff --git a/drivers/iio/position/iqs624-pos.c b/drivers/iio/position/iqs624-pos.c
new file mode 100644 (file)
index 0000000..77096c3
--- /dev/null
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS624/625 Angular Position Sensors
+ *
+ * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
+ */
+
+#include <linux/device.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/mfd/iqs62x.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define IQS624_POS_DEG_OUT                     0x16
+
+#define IQS624_POS_SCALE1                      (314159 / 180)
+#define IQS624_POS_SCALE2                      100000
+
+struct iqs624_pos_private {
+       struct iqs62x_core *iqs62x;
+       struct notifier_block notifier;
+       struct mutex lock;
+       bool angle_en;
+       u16 angle;
+};
+
+static int iqs624_pos_angle_en(struct iqs62x_core *iqs62x, bool angle_en)
+{
+       unsigned int event_mask = IQS624_HALL_UI_WHL_EVENT;
+
+       /*
+        * The IQS625 reports angular position in the form of coarse intervals,
+        * so only interval change events are unmasked. Conversely, the IQS624
+        * reports angular position down to one degree of resolution, so wheel
+        * movement events are unmasked instead.
+        */
+       if (iqs62x->dev_desc->prod_num == IQS625_PROD_NUM)
+               event_mask = IQS624_HALL_UI_INT_EVENT;
+
+       return regmap_update_bits(iqs62x->regmap, IQS624_HALL_UI, event_mask,
+                                 angle_en ? 0 : 0xFF);
+}
+
+static int iqs624_pos_notifier(struct notifier_block *notifier,
+                              unsigned long event_flags, void *context)
+{
+       struct iqs62x_event_data *event_data = context;
+       struct iqs624_pos_private *iqs624_pos;
+       struct iqs62x_core *iqs62x;
+       struct iio_dev *indio_dev;
+       u16 angle = event_data->ui_data;
+       s64 timestamp;
+       int ret;
+
+       iqs624_pos = container_of(notifier, struct iqs624_pos_private,
+                                 notifier);
+       indio_dev = iio_priv_to_dev(iqs624_pos);
+       timestamp = iio_get_time_ns(indio_dev);
+
+       iqs62x = iqs624_pos->iqs62x;
+       if (iqs62x->dev_desc->prod_num == IQS625_PROD_NUM)
+               angle = event_data->interval;
+
+       mutex_lock(&iqs624_pos->lock);
+
+       if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {
+               ret = iqs624_pos_angle_en(iqs62x, iqs624_pos->angle_en);
+               if (ret) {
+                       dev_err(indio_dev->dev.parent,
+                               "Failed to re-initialize device: %d\n", ret);
+                       ret = NOTIFY_BAD;
+               } else {
+                       ret = NOTIFY_OK;
+               }
+       } else if (iqs624_pos->angle_en && (angle != iqs624_pos->angle)) {
+               iio_push_event(indio_dev,
+                              IIO_UNMOD_EVENT_CODE(IIO_ANGL, 0,
+                                                   IIO_EV_TYPE_CHANGE,
+                                                   IIO_EV_DIR_NONE),
+                              timestamp);
+
+               iqs624_pos->angle = angle;
+               ret = NOTIFY_OK;
+       } else {
+               ret = NOTIFY_DONE;
+       }
+
+       mutex_unlock(&iqs624_pos->lock);
+
+       return ret;
+}
+
+static void iqs624_pos_notifier_unregister(void *context)
+{
+       struct iqs624_pos_private *iqs624_pos = context;
+       struct iio_dev *indio_dev = iio_priv_to_dev(iqs624_pos);
+       int ret;
+
+       ret = blocking_notifier_chain_unregister(&iqs624_pos->iqs62x->nh,
+                                                &iqs624_pos->notifier);
+       if (ret)
+               dev_err(indio_dev->dev.parent,
+                       "Failed to unregister notifier: %d\n", ret);
+}
+
+static int iqs624_pos_angle_get(struct iqs62x_core *iqs62x, unsigned int *val)
+{
+       int ret;
+       __le16 val_buf;
+
+       if (iqs62x->dev_desc->prod_num == IQS625_PROD_NUM)
+               return regmap_read(iqs62x->regmap, iqs62x->dev_desc->interval,
+                                  val);
+
+       ret = regmap_raw_read(iqs62x->regmap, IQS624_POS_DEG_OUT, &val_buf,
+                             sizeof(val_buf));
+       if (ret)
+               return ret;
+
+       *val = le16_to_cpu(val_buf);
+
+       return 0;
+}
+
+static int iqs624_pos_read_raw(struct iio_dev *indio_dev,
+                              struct iio_chan_spec const *chan,
+                              int *val, int *val2, long mask)
+{
+       struct iqs624_pos_private *iqs624_pos = iio_priv(indio_dev);
+       struct iqs62x_core *iqs62x = iqs624_pos->iqs62x;
+       unsigned int scale = 1;
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = iqs624_pos_angle_get(iqs62x, val);
+               if (ret)
+                       return ret;
+
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_SCALE:
+               if (iqs62x->dev_desc->prod_num == IQS625_PROD_NUM) {
+                       ret = regmap_read(iqs62x->regmap, IQS624_INTERVAL_DIV,
+                                         &scale);
+                       if (ret)
+                               return ret;
+               }
+
+               *val = scale * IQS624_POS_SCALE1;
+               *val2 = IQS624_POS_SCALE2;
+               return IIO_VAL_FRACTIONAL;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int iqs624_pos_read_event_config(struct iio_dev *indio_dev,
+                                       const struct iio_chan_spec *chan,
+                                       enum iio_event_type type,
+                                       enum iio_event_direction dir)
+{
+       struct iqs624_pos_private *iqs624_pos = iio_priv(indio_dev);
+       int ret;
+
+       mutex_lock(&iqs624_pos->lock);
+       ret = iqs624_pos->angle_en;
+       mutex_unlock(&iqs624_pos->lock);
+
+       return ret;
+}
+
+static int iqs624_pos_write_event_config(struct iio_dev *indio_dev,
+                                        const struct iio_chan_spec *chan,
+                                        enum iio_event_type type,
+                                        enum iio_event_direction dir,
+                                        int state)
+{
+       struct iqs624_pos_private *iqs624_pos = iio_priv(indio_dev);
+       struct iqs62x_core *iqs62x = iqs624_pos->iqs62x;
+       unsigned int val;
+       int ret;
+
+       mutex_lock(&iqs624_pos->lock);
+
+       ret = iqs624_pos_angle_get(iqs62x, &val);
+       if (ret)
+               goto err_mutex;
+
+       ret = iqs624_pos_angle_en(iqs62x, state);
+       if (ret)
+               goto err_mutex;
+
+       iqs624_pos->angle = val;
+       iqs624_pos->angle_en = state;
+
+err_mutex:
+       mutex_unlock(&iqs624_pos->lock);
+
+       return ret;
+}
+
+static const struct iio_info iqs624_pos_info = {
+       .read_raw = &iqs624_pos_read_raw,
+       .read_event_config = iqs624_pos_read_event_config,
+       .write_event_config = iqs624_pos_write_event_config,
+};
+
+static const struct iio_event_spec iqs624_pos_events[] = {
+       {
+               .type = IIO_EV_TYPE_CHANGE,
+               .dir = IIO_EV_DIR_NONE,
+               .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+       },
+};
+
+static const struct iio_chan_spec iqs624_pos_channels[] = {
+       {
+               .type = IIO_ANGL,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SCALE),
+               .event_spec = iqs624_pos_events,
+               .num_event_specs = ARRAY_SIZE(iqs624_pos_events),
+       },
+};
+
+static int iqs624_pos_probe(struct platform_device *pdev)
+{
+       struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
+       struct iqs624_pos_private *iqs624_pos;
+       struct iio_dev *indio_dev;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*iqs624_pos));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       iqs624_pos = iio_priv(indio_dev);
+       iqs624_pos->iqs62x = iqs62x;
+
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->dev.parent = &pdev->dev;
+       indio_dev->channels = iqs624_pos_channels;
+       indio_dev->num_channels = ARRAY_SIZE(iqs624_pos_channels);
+       indio_dev->name = iqs62x->dev_desc->dev_name;
+       indio_dev->info = &iqs624_pos_info;
+
+       mutex_init(&iqs624_pos->lock);
+
+       iqs624_pos->notifier.notifier_call = iqs624_pos_notifier;
+       ret = blocking_notifier_chain_register(&iqs624_pos->iqs62x->nh,
+                                              &iqs624_pos->notifier);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_add_action_or_reset(&pdev->dev,
+                                      iqs624_pos_notifier_unregister,
+                                      iqs624_pos);
+       if (ret)
+               return ret;
+
+       return devm_iio_device_register(&pdev->dev, indio_dev);
+}
+
+static struct platform_driver iqs624_pos_platform_driver = {
+       .driver = {
+               .name = "iqs624-pos",
+       },
+       .probe = iqs624_pos_probe,
+};
+module_platform_driver(iqs624_pos_platform_driver);
+
+MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
+MODULE_DESCRIPTION("Azoteq IQS624/625 Angular Position Sensors");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:iqs624-pos");
index b521beb..c079b89 100644 (file)
@@ -134,10 +134,14 @@ static int cros_ec_baro_probe(struct platform_device *pdev)
        if (!indio_dev)
                return -ENOMEM;
 
-       ret = cros_ec_sensors_core_init(pdev, indio_dev, true);
+       ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
+                                       cros_ec_sensors_capture,
+                                       cros_ec_sensors_push_data);
        if (ret)
                return ret;
 
+       iio_buffer_set_attrs(indio_dev->buffer, cros_ec_sensor_fifo_attributes);
+
        indio_dev->info = &cros_ec_baro_info;
        state = iio_priv(indio_dev);
        state->core.type = state->core.resp->info.type;
@@ -147,8 +151,7 @@ static int cros_ec_baro_probe(struct platform_device *pdev)
        channel->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
        channel->info_mask_shared_by_all =
                BIT(IIO_CHAN_INFO_SCALE) |
-               BIT(IIO_CHAN_INFO_SAMP_FREQ) |
-               BIT(IIO_CHAN_INFO_FREQUENCY);
+               BIT(IIO_CHAN_INFO_SAMP_FREQ);
        channel->info_mask_shared_by_all_available =
                BIT(IIO_CHAN_INFO_SAMP_FREQ);
        channel->scan_type.realbits = CROS_EC_SENSOR_BITS;
@@ -182,11 +185,6 @@ static int cros_ec_baro_probe(struct platform_device *pdev)
 
        state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
 
-       ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
-                                             cros_ec_sensors_capture, NULL);
-       if (ret)
-               return ret;
-
        return devm_iio_device_register(dev, indio_dev);
 }
 
index e1ccb40..f1f2a14 100644 (file)
@@ -4,6 +4,16 @@
 #
 menu "Temperature sensors"
 
+config IQS620AT_TEMP
+       tristate "Azoteq IQS620AT temperature sensor"
+       depends on MFD_IQS62X || COMPILE_TEST
+       help
+         Say Y here if you want to build support for the Azoteq IQS620AT
+         temperature sensor.
+
+         To compile this driver as a module, choose M here: the module
+         will be called iqs620at-temp.
+
 config LTC2983
        tristate "Analog Devices Multi-Sensor Digital Temperature Measurement System"
        depends on SPI
index d6b850b..90c1131 100644 (file)
@@ -3,6 +3,7 @@
 # Makefile for industrial I/O temperature drivers
 #
 
+obj-$(CONFIG_IQS620AT_TEMP) += iqs620at-temp.o
 obj-$(CONFIG_LTC2983) += ltc2983.o
 obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o
 obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o
diff --git a/drivers/iio/temperature/iqs620at-temp.c b/drivers/iio/temperature/iqs620at-temp.c
new file mode 100644 (file)
index 0000000..3fd52b3
--- /dev/null
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS620AT Temperature Sensor
+ *
+ * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
+ */
+
+#include <linux/device.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/mfd/iqs62x.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define IQS620_TEMP_UI_OUT                     0x1A
+
+#define IQS620_TEMP_SCALE                      1000
+#define IQS620_TEMP_OFFSET                     (-100)
+
+static int iqs620_temp_read_raw(struct iio_dev *indio_dev,
+                               struct iio_chan_spec const *chan,
+                               int *val, int *val2, long mask)
+{
+       struct iqs62x_core *iqs62x = iio_device_get_drvdata(indio_dev);
+       int ret;
+       __le16 val_buf;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = regmap_raw_read(iqs62x->regmap, IQS620_TEMP_UI_OUT,
+                                     &val_buf, sizeof(val_buf));
+               if (ret)
+                       return ret;
+
+               *val = le16_to_cpu(val_buf);
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_SCALE:
+               *val = IQS620_TEMP_SCALE;
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_OFFSET:
+               *val = IQS620_TEMP_OFFSET;
+               return IIO_VAL_INT;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct iio_info iqs620_temp_info = {
+       .read_raw = &iqs620_temp_read_raw,
+};
+
+static const struct iio_chan_spec iqs620_temp_channels[] = {
+       {
+               .type = IIO_TEMP,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SCALE) |
+                                     BIT(IIO_CHAN_INFO_OFFSET),
+       },
+};
+
+static int iqs620_temp_probe(struct platform_device *pdev)
+{
+       struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
+       struct iio_dev *indio_dev;
+
+       indio_dev = devm_iio_device_alloc(&pdev->dev, 0);
+       if (!indio_dev)
+               return -ENOMEM;
+
+       iio_device_set_drvdata(indio_dev, iqs62x);
+
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->dev.parent = &pdev->dev;
+       indio_dev->channels = iqs620_temp_channels;
+       indio_dev->num_channels = ARRAY_SIZE(iqs620_temp_channels);
+       indio_dev->name = iqs62x->dev_desc->dev_name;
+       indio_dev->info = &iqs620_temp_info;
+
+       return devm_iio_device_register(&pdev->dev, indio_dev);
+}
+
+static struct platform_driver iqs620_temp_platform_driver = {
+       .driver = {
+               .name = "iqs620at-temp",
+       },
+       .probe = iqs620_temp_probe,
+};
+module_platform_driver(iqs620_temp_platform_driver);
+
+MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
+MODULE_DESCRIPTION("Azoteq IQS620AT Temperature Sensor");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:iqs620at-temp");
index 4706ff0..28de965 100644 (file)
@@ -663,6 +663,16 @@ config KEYBOARD_IPAQ_MICRO
          To compile this driver as a module, choose M here: the
          module will be called ipaq-micro-keys.
 
+config KEYBOARD_IQS62X
+       tristate "Azoteq IQS620A/621/622/624/625 keys and switches"
+       depends on MFD_IQS62X
+       help
+         Say Y here to enable key and switch support for the Azoteq IQS620A,
+         IQS621, IQS622, IQS624 and IQS625 multi-function sensors.
+
+         To compile this driver as a module, choose M here: the module will
+         be called iqs62x-keys.
+
 config KEYBOARD_OMAP
        tristate "TI OMAP keypad support"
        depends on ARCH_OMAP1
index f5b1752..1d689fd 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_KEYBOARD_TCA8418)                += tca8418_keypad.o
 obj-$(CONFIG_KEYBOARD_HIL)             += hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD)         += hilkbd.o
 obj-$(CONFIG_KEYBOARD_IPAQ_MICRO)      += ipaq-micro-keys.o
+obj-$(CONFIG_KEYBOARD_IQS62X)          += iqs62x-keys.o
 obj-$(CONFIG_KEYBOARD_IMX)             += imx_keypad.o
 obj-$(CONFIG_KEYBOARD_IMX_SC_KEY)      += imx_sc_key.o
 obj-$(CONFIG_KEYBOARD_HP6XX)           += jornada680_kbd.o
diff --git a/drivers/input/keyboard/iqs62x-keys.c b/drivers/input/keyboard/iqs62x-keys.c
new file mode 100644 (file)
index 0000000..93446b2
--- /dev/null
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS620A/621/622/624/625 Keys and Switches
+ *
+ * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/mfd/iqs62x.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+enum {
+       IQS62X_SW_HALL_N,
+       IQS62X_SW_HALL_S,
+};
+
+static const char * const iqs62x_switch_names[] = {
+       [IQS62X_SW_HALL_N] = "hall-switch-north",
+       [IQS62X_SW_HALL_S] = "hall-switch-south",
+};
+
+struct iqs62x_switch_desc {
+       enum iqs62x_event_flag flag;
+       unsigned int code;
+       bool enabled;
+};
+
+struct iqs62x_keys_private {
+       struct iqs62x_core *iqs62x;
+       struct input_dev *input;
+       struct notifier_block notifier;
+       struct iqs62x_switch_desc switches[ARRAY_SIZE(iqs62x_switch_names)];
+       unsigned int keycode[IQS62X_NUM_KEYS];
+       unsigned int keycodemax;
+       u8 interval;
+};
+
+static int iqs62x_keys_parse_prop(struct platform_device *pdev,
+                                 struct iqs62x_keys_private *iqs62x_keys)
+{
+       struct fwnode_handle *child;
+       unsigned int val;
+       int ret, i;
+
+       ret = device_property_count_u32(&pdev->dev, "linux,keycodes");
+       if (ret > IQS62X_NUM_KEYS) {
+               dev_err(&pdev->dev, "Too many keycodes present\n");
+               return -EINVAL;
+       } else if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to count keycodes: %d\n", ret);
+               return ret;
+       }
+       iqs62x_keys->keycodemax = ret;
+
+       ret = device_property_read_u32_array(&pdev->dev, "linux,keycodes",
+                                            iqs62x_keys->keycode,
+                                            iqs62x_keys->keycodemax);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to read keycodes: %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++) {
+               child = device_get_named_child_node(&pdev->dev,
+                                                   iqs62x_switch_names[i]);
+               if (!child)
+                       continue;
+
+               ret = fwnode_property_read_u32(child, "linux,code", &val);
+               if (ret) {
+                       dev_err(&pdev->dev, "Failed to read switch code: %d\n",
+                               ret);
+                       return ret;
+               }
+               iqs62x_keys->switches[i].code = val;
+               iqs62x_keys->switches[i].enabled = true;
+
+               if (fwnode_property_present(child, "azoteq,use-prox"))
+                       iqs62x_keys->switches[i].flag = (i == IQS62X_SW_HALL_N ?
+                                                        IQS62X_EVENT_HALL_N_P :
+                                                        IQS62X_EVENT_HALL_S_P);
+               else
+                       iqs62x_keys->switches[i].flag = (i == IQS62X_SW_HALL_N ?
+                                                        IQS62X_EVENT_HALL_N_T :
+                                                        IQS62X_EVENT_HALL_S_T);
+       }
+
+       return 0;
+}
+
+static int iqs62x_keys_init(struct iqs62x_keys_private *iqs62x_keys)
+{
+       struct iqs62x_core *iqs62x = iqs62x_keys->iqs62x;
+       enum iqs62x_event_flag flag;
+       unsigned int event_reg, val;
+       unsigned int event_mask = 0;
+       int ret, i;
+
+       switch (iqs62x->dev_desc->prod_num) {
+       case IQS620_PROD_NUM:
+       case IQS621_PROD_NUM:
+       case IQS622_PROD_NUM:
+               event_reg = IQS620_GLBL_EVENT_MASK;
+
+               /*
+                * Discreet button, hysteresis and SAR UI flags represent keys
+                * and are unmasked if mapped to a valid keycode.
+                */
+               for (i = 0; i < iqs62x_keys->keycodemax; i++) {
+                       if (iqs62x_keys->keycode[i] == KEY_RESERVED)
+                               continue;
+
+                       if (iqs62x_events[i].reg == IQS62X_EVENT_PROX)
+                               event_mask |= iqs62x->dev_desc->prox_mask;
+                       else if (iqs62x_events[i].reg == IQS62X_EVENT_HYST)
+                               event_mask |= (iqs62x->dev_desc->hyst_mask |
+                                              iqs62x->dev_desc->sar_mask);
+               }
+
+               ret = regmap_read(iqs62x->regmap, iqs62x->dev_desc->hall_flags,
+                                 &val);
+               if (ret)
+                       return ret;
+
+               /*
+                * Hall UI flags represent switches and are unmasked if their
+                * corresponding child nodes are present.
+                */
+               for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++) {
+                       if (!(iqs62x_keys->switches[i].enabled))
+                               continue;
+
+                       flag = iqs62x_keys->switches[i].flag;
+
+                       if (iqs62x_events[flag].reg != IQS62X_EVENT_HALL)
+                               continue;
+
+                       event_mask |= iqs62x->dev_desc->hall_mask;
+
+                       input_report_switch(iqs62x_keys->input,
+                                           iqs62x_keys->switches[i].code,
+                                           (val & iqs62x_events[flag].mask) ==
+                                           iqs62x_events[flag].val);
+               }
+
+               input_sync(iqs62x_keys->input);
+               break;
+
+       case IQS624_PROD_NUM:
+               event_reg = IQS624_HALL_UI;
+
+               /*
+                * Interval change events represent keys and are unmasked if
+                * either wheel movement flag is mapped to a valid keycode.
+                */
+               if (iqs62x_keys->keycode[IQS62X_EVENT_WHEEL_UP] != KEY_RESERVED)
+                       event_mask |= IQS624_HALL_UI_INT_EVENT;
+
+               if (iqs62x_keys->keycode[IQS62X_EVENT_WHEEL_DN] != KEY_RESERVED)
+                       event_mask |= IQS624_HALL_UI_INT_EVENT;
+
+               ret = regmap_read(iqs62x->regmap, iqs62x->dev_desc->interval,
+                                 &val);
+               if (ret)
+                       return ret;
+
+               iqs62x_keys->interval = val;
+               break;
+
+       default:
+               return 0;
+       }
+
+       return regmap_update_bits(iqs62x->regmap, event_reg, event_mask, 0);
+}
+
+static int iqs62x_keys_notifier(struct notifier_block *notifier,
+                               unsigned long event_flags, void *context)
+{
+       struct iqs62x_event_data *event_data = context;
+       struct iqs62x_keys_private *iqs62x_keys;
+       int ret, i;
+
+       iqs62x_keys = container_of(notifier, struct iqs62x_keys_private,
+                                  notifier);
+
+       if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {
+               ret = iqs62x_keys_init(iqs62x_keys);
+               if (ret) {
+                       dev_err(iqs62x_keys->input->dev.parent,
+                               "Failed to re-initialize device: %d\n", ret);
+                       return NOTIFY_BAD;
+               }
+
+               return NOTIFY_OK;
+       }
+
+       for (i = 0; i < iqs62x_keys->keycodemax; i++) {
+               if (iqs62x_events[i].reg == IQS62X_EVENT_WHEEL &&
+                   event_data->interval == iqs62x_keys->interval)
+                       continue;
+
+               input_report_key(iqs62x_keys->input, iqs62x_keys->keycode[i],
+                                event_flags & BIT(i));
+       }
+
+       for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++)
+               if (iqs62x_keys->switches[i].enabled)
+                       input_report_switch(iqs62x_keys->input,
+                                           iqs62x_keys->switches[i].code,
+                                           event_flags &
+                                           BIT(iqs62x_keys->switches[i].flag));
+
+       input_sync(iqs62x_keys->input);
+
+       if (event_data->interval == iqs62x_keys->interval)
+               return NOTIFY_OK;
+
+       /*
+        * Each frame contains at most one wheel event (up or down), in which
+        * case a complementary release cycle is emulated.
+        */
+       if (event_flags & BIT(IQS62X_EVENT_WHEEL_UP)) {
+               input_report_key(iqs62x_keys->input,
+                                iqs62x_keys->keycode[IQS62X_EVENT_WHEEL_UP],
+                                0);
+               input_sync(iqs62x_keys->input);
+       } else if (event_flags & BIT(IQS62X_EVENT_WHEEL_DN)) {
+               input_report_key(iqs62x_keys->input,
+                                iqs62x_keys->keycode[IQS62X_EVENT_WHEEL_DN],
+                                0);
+               input_sync(iqs62x_keys->input);
+       }
+
+       iqs62x_keys->interval = event_data->interval;
+
+       return NOTIFY_OK;
+}
+
+static int iqs62x_keys_probe(struct platform_device *pdev)
+{
+       struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
+       struct iqs62x_keys_private *iqs62x_keys;
+       struct input_dev *input;
+       int ret, i;
+
+       iqs62x_keys = devm_kzalloc(&pdev->dev, sizeof(*iqs62x_keys),
+                                  GFP_KERNEL);
+       if (!iqs62x_keys)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, iqs62x_keys);
+
+       ret = iqs62x_keys_parse_prop(pdev, iqs62x_keys);
+       if (ret)
+               return ret;
+
+       input = devm_input_allocate_device(&pdev->dev);
+       if (!input)
+               return -ENOMEM;
+
+       input->keycodemax = iqs62x_keys->keycodemax;
+       input->keycode = iqs62x_keys->keycode;
+       input->keycodesize = sizeof(*iqs62x_keys->keycode);
+
+       input->name = iqs62x->dev_desc->dev_name;
+       input->id.bustype = BUS_I2C;
+
+       for (i = 0; i < iqs62x_keys->keycodemax; i++)
+               if (iqs62x_keys->keycode[i] != KEY_RESERVED)
+                       input_set_capability(input, EV_KEY,
+                                            iqs62x_keys->keycode[i]);
+
+       for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++)
+               if (iqs62x_keys->switches[i].enabled)
+                       input_set_capability(input, EV_SW,
+                                            iqs62x_keys->switches[i].code);
+
+       iqs62x_keys->iqs62x = iqs62x;
+       iqs62x_keys->input = input;
+
+       ret = iqs62x_keys_init(iqs62x_keys);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to initialize device: %d\n", ret);
+               return ret;
+       }
+
+       ret = input_register_device(iqs62x_keys->input);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register device: %d\n", ret);
+               return ret;
+       }
+
+       iqs62x_keys->notifier.notifier_call = iqs62x_keys_notifier;
+       ret = blocking_notifier_chain_register(&iqs62x_keys->iqs62x->nh,
+                                              &iqs62x_keys->notifier);
+       if (ret)
+               dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret);
+
+       return ret;
+}
+
+static int iqs62x_keys_remove(struct platform_device *pdev)
+{
+       struct iqs62x_keys_private *iqs62x_keys = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = blocking_notifier_chain_unregister(&iqs62x_keys->iqs62x->nh,
+                                                &iqs62x_keys->notifier);
+       if (ret)
+               dev_err(&pdev->dev, "Failed to unregister notifier: %d\n", ret);
+
+       return ret;
+}
+
+static struct platform_driver iqs62x_keys_platform_driver = {
+       .driver = {
+               .name = "iqs62x-keys",
+       },
+       .probe = iqs62x_keys_probe,
+       .remove = iqs62x_keys_remove,
+};
+module_platform_driver(iqs62x_keys_platform_driver);
+
+MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
+MODULE_DESCRIPTION("Azoteq IQS620A/621/622/624/625 Keys and Switches");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:iqs62x-keys");
index dc974c2..08e919d 100644 (file)
@@ -530,6 +530,17 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
                        DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo LaVie Z"),
                },
        },
+       {
+               /*
+                * Acer Aspire 5738z
+                * Touchpad stops working in mux mode when dis- + re-enabled
+                * with the touchpad enable/disable toggle hotkey
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"),
+               },
+       },
        { }
 };
 
index 4911799..14c577c 100644 (file)
@@ -1309,6 +1309,7 @@ static int elants_i2c_probe(struct i2c_client *client,
        input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
        input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res);
        input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res);
+       input_abs_set_res(ts->input, ABS_MT_TOUCH_MAJOR, 1);
 
        error = input_register_device(ts->input);
        if (error) {
index 0403102..02c75ea 100644 (file)
 #include <linux/of.h>
 #include <asm/unaligned.h>
 
-struct goodix_ts_data;
-
-struct goodix_chip_data {
-       u16 config_addr;
-       int config_len;
-       int (*check_config)(struct goodix_ts_data *, const struct firmware *);
-};
-
-struct goodix_ts_data {
-       struct i2c_client *client;
-       struct input_dev *input_dev;
-       const struct goodix_chip_data *chip;
-       struct touchscreen_properties prop;
-       unsigned int max_touch_num;
-       unsigned int int_trigger_type;
-       struct regulator *avdd28;
-       struct regulator *vddio;
-       struct gpio_desc *gpiod_int;
-       struct gpio_desc *gpiod_rst;
-       u16 id;
-       u16 version;
-       const char *cfg_name;
-       struct completion firmware_loading_complete;
-       unsigned long irq_flags;
-       unsigned int contact_size;
-};
-
 #define GOODIX_GPIO_INT_NAME           "irq"
 #define GOODIX_GPIO_RST_NAME           "reset"
 
@@ -65,10 +38,13 @@ struct goodix_ts_data {
 #define GOODIX_CONTACT_SIZE            8
 #define GOODIX_MAX_CONTACT_SIZE                9
 #define GOODIX_MAX_CONTACTS            10
+#define GOODIX_MAX_KEYS                        7
 
-#define GOODIX_CONFIG_MAX_LENGTH       240
+#define GOODIX_CONFIG_MIN_LENGTH       186
 #define GOODIX_CONFIG_911_LENGTH       186
 #define GOODIX_CONFIG_967_LENGTH       228
+#define GOODIX_CONFIG_GT9X_LENGTH      240
+#define GOODIX_CONFIG_MAX_LENGTH       240
 
 /* Register defines */
 #define GOODIX_REG_COMMAND             0x8040
@@ -80,39 +56,118 @@ struct goodix_ts_data {
 #define GOODIX_REG_ID                  0x8140
 
 #define GOODIX_BUFFER_STATUS_READY     BIT(7)
+#define GOODIX_HAVE_KEY                        BIT(4)
 #define GOODIX_BUFFER_STATUS_TIMEOUT   20
 
 #define RESOLUTION_LOC         1
 #define MAX_CONTACTS_LOC       5
 #define TRIGGER_LOC            6
 
+/* Our special handling for GPIO accesses through ACPI is x86 specific */
+#if defined CONFIG_X86 && defined CONFIG_ACPI
+#define ACPI_GPIO_SUPPORT
+#endif
+
+struct goodix_ts_data;
+
+enum goodix_irq_pin_access_method {
+       IRQ_PIN_ACCESS_NONE,
+       IRQ_PIN_ACCESS_GPIO,
+       IRQ_PIN_ACCESS_ACPI_GPIO,
+       IRQ_PIN_ACCESS_ACPI_METHOD,
+};
+
+struct goodix_chip_data {
+       u16 config_addr;
+       int config_len;
+       int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len);
+       void (*calc_config_checksum)(struct goodix_ts_data *ts);
+};
+
+struct goodix_chip_id {
+       const char *id;
+       const struct goodix_chip_data *data;
+};
+
+#define GOODIX_ID_MAX_LEN      4
+
+struct goodix_ts_data {
+       struct i2c_client *client;
+       struct input_dev *input_dev;
+       const struct goodix_chip_data *chip;
+       struct touchscreen_properties prop;
+       unsigned int max_touch_num;
+       unsigned int int_trigger_type;
+       struct regulator *avdd28;
+       struct regulator *vddio;
+       struct gpio_desc *gpiod_int;
+       struct gpio_desc *gpiod_rst;
+       int gpio_count;
+       int gpio_int_idx;
+       char id[GOODIX_ID_MAX_LEN + 1];
+       u16 version;
+       const char *cfg_name;
+       bool reset_controller_at_probe;
+       bool load_cfg_from_disk;
+       struct completion firmware_loading_complete;
+       unsigned long irq_flags;
+       enum goodix_irq_pin_access_method irq_pin_access_method;
+       unsigned int contact_size;
+       u8 config[GOODIX_CONFIG_MAX_LENGTH];
+       unsigned short keymap[GOODIX_MAX_KEYS];
+};
+
 static int goodix_check_cfg_8(struct goodix_ts_data *ts,
-                       const struct firmware *cfg);
+                             const u8 *cfg, int len);
 static int goodix_check_cfg_16(struct goodix_ts_data *ts,
-                       const struct firmware *cfg);
+                              const u8 *cfg, int len);
+static void goodix_calc_cfg_checksum_8(struct goodix_ts_data *ts);
+static void goodix_calc_cfg_checksum_16(struct goodix_ts_data *ts);
 
 static const struct goodix_chip_data gt1x_chip_data = {
        .config_addr            = GOODIX_GT1X_REG_CONFIG_DATA,
-       .config_len             = GOODIX_CONFIG_MAX_LENGTH,
+       .config_len             = GOODIX_CONFIG_GT9X_LENGTH,
        .check_config           = goodix_check_cfg_16,
+       .calc_config_checksum   = goodix_calc_cfg_checksum_16,
 };
 
 static const struct goodix_chip_data gt911_chip_data = {
        .config_addr            = GOODIX_GT9X_REG_CONFIG_DATA,
        .config_len             = GOODIX_CONFIG_911_LENGTH,
        .check_config           = goodix_check_cfg_8,
+       .calc_config_checksum   = goodix_calc_cfg_checksum_8,
 };
 
 static const struct goodix_chip_data gt967_chip_data = {
        .config_addr            = GOODIX_GT9X_REG_CONFIG_DATA,
        .config_len             = GOODIX_CONFIG_967_LENGTH,
        .check_config           = goodix_check_cfg_8,
+       .calc_config_checksum   = goodix_calc_cfg_checksum_8,
 };
 
 static const struct goodix_chip_data gt9x_chip_data = {
        .config_addr            = GOODIX_GT9X_REG_CONFIG_DATA,
-       .config_len             = GOODIX_CONFIG_MAX_LENGTH,
+       .config_len             = GOODIX_CONFIG_GT9X_LENGTH,
        .check_config           = goodix_check_cfg_8,
+       .calc_config_checksum   = goodix_calc_cfg_checksum_8,
+};
+
+static const struct goodix_chip_id goodix_chip_ids[] = {
+       { .id = "1151", .data = &gt1x_chip_data },
+       { .id = "5663", .data = &gt1x_chip_data },
+       { .id = "5688", .data = &gt1x_chip_data },
+       { .id = "917S", .data = &gt1x_chip_data },
+
+       { .id = "911", .data = &gt911_chip_data },
+       { .id = "9271", .data = &gt911_chip_data },
+       { .id = "9110", .data = &gt911_chip_data },
+       { .id = "927", .data = &gt911_chip_data },
+       { .id = "928", .data = &gt911_chip_data },
+
+       { .id = "912", .data = &gt967_chip_data },
+       { .id = "9147", .data = &gt967_chip_data },
+       { .id = "967", .data = &gt967_chip_data },
+       { }
 };
 
 static const unsigned long goodix_irq_flags[] = {
@@ -168,6 +223,22 @@ static const struct dmi_system_id nine_bytes_report[] = {
        {}
 };
 
+/*
+ * Those tablets have their x coordinate inverted
+ */
+static const struct dmi_system_id inverted_x_screen[] = {
+#if defined(CONFIG_DMI) && defined(CONFIG_X86)
+       {
+               .ident = "Cube I15-TC",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Cube"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "I15-TC")
+               },
+       },
+#endif
+       {}
+};
+
 /**
  * goodix_i2c_read - read data from a register of the i2c slave device.
  *
@@ -235,28 +306,16 @@ static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
        return goodix_i2c_write(client, reg, &value, sizeof(value));
 }
 
-static const struct goodix_chip_data *goodix_get_chip_data(u16 id)
+static const struct goodix_chip_data *goodix_get_chip_data(const char *id)
 {
-       switch (id) {
-       case 1151:
-       case 5663:
-       case 5688:
-               return &gt1x_chip_data;
-
-       case 911:
-       case 9271:
-       case 9110:
-       case 927:
-       case 928:
-               return &gt911_chip_data;
-
-       case 912:
-       case 967:
-               return &gt967_chip_data;
+       unsigned int i;
 
-       default:
-               return &gt9x_chip_data;
+       for (i = 0; goodix_chip_ids[i].id; i++) {
+               if (!strcmp(goodix_chip_ids[i].id, id))
+                       return goodix_chip_ids[i].data;
        }
+
+       return &gt9x_chip_data;
 }
 
 static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
@@ -264,6 +323,13 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
        unsigned long max_timeout;
        int touch_num;
        int error;
+       u16 addr = GOODIX_READ_COOR_ADDR;
+       /*
+        * We are going to read 1-byte header,
+        * ts->contact_size * max(1, touch_num) bytes of coordinates
+        * and 1-byte footer which contains the touch-key code.
+        */
+       const int header_contact_keycode_size = 1 + ts->contact_size + 1;
 
        /*
         * The 'buffer status' bit, which indicates that the data is valid, is
@@ -272,8 +338,8 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
         */
        max_timeout = jiffies + msecs_to_jiffies(GOODIX_BUFFER_STATUS_TIMEOUT);
        do {
-               error = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR,
-                                       data, ts->contact_size + 1);
+               error = goodix_i2c_read(ts->client, addr, data,
+                                       header_contact_keycode_size);
                if (error) {
                        dev_err(&ts->client->dev, "I2C transfer error: %d\n",
                                        error);
@@ -286,11 +352,10 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
                                return -EPROTO;
 
                        if (touch_num > 1) {
-                               data += 1 + ts->contact_size;
+                               addr += header_contact_keycode_size;
+                               data += header_contact_keycode_size;
                                error = goodix_i2c_read(ts->client,
-                                               GOODIX_READ_COOR_ADDR +
-                                                       1 + ts->contact_size,
-                                               data,
+                                               addr, data,
                                                ts->contact_size *
                                                        (touch_num - 1));
                                if (error)
@@ -307,7 +372,7 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
         * The Goodix panel will send spurious interrupts after a
         * 'finger up' event, which will always cause a timeout.
         */
-       return 0;
+       return -ENOMSG;
 }
 
 static void goodix_ts_report_touch_8b(struct goodix_ts_data *ts, u8 *coor_data)
@@ -340,6 +405,25 @@ static void goodix_ts_report_touch_9b(struct goodix_ts_data *ts, u8 *coor_data)
        input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
 }
 
+static void goodix_ts_report_key(struct goodix_ts_data *ts, u8 *data)
+{
+       int touch_num;
+       u8 key_value;
+       int i;
+
+       if (data[0] & GOODIX_HAVE_KEY) {
+               touch_num = data[0] & 0x0f;
+               key_value = data[1 + ts->contact_size * touch_num];
+               for (i = 0; i < GOODIX_MAX_KEYS; i++)
+                       if (key_value & BIT(i))
+                               input_report_key(ts->input_dev,
+                                                ts->keymap[i], 1);
+       } else {
+               for (i = 0; i < GOODIX_MAX_KEYS; i++)
+                       input_report_key(ts->input_dev, ts->keymap[i], 0);
+       }
+}
+
 /**
  * goodix_process_events - Process incoming events
  *
@@ -350,7 +434,7 @@ static void goodix_ts_report_touch_9b(struct goodix_ts_data *ts, u8 *coor_data)
  */
 static void goodix_process_events(struct goodix_ts_data *ts)
 {
-       u8  point_data[1 + GOODIX_MAX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
+       u8  point_data[2 + GOODIX_MAX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
        int touch_num;
        int i;
 
@@ -358,11 +442,7 @@ static void goodix_process_events(struct goodix_ts_data *ts)
        if (touch_num < 0)
                return;
 
-       /*
-        * Bit 4 of the first byte reports the status of the capacitive
-        * Windows/Home button.
-        */
-       input_report_key(ts->input_dev, KEY_LEFTMETA, point_data[0] & BIT(4));
+       goodix_ts_report_key(ts, point_data);
 
        for (i = 0; i < touch_num; i++)
                if (ts->contact_size == 9)
@@ -406,22 +486,21 @@ static int goodix_request_irq(struct goodix_ts_data *ts)
                                         ts->irq_flags, ts->client->name, ts);
 }
 
-static int goodix_check_cfg_8(struct goodix_ts_data *ts,
-                       const struct firmware *cfg)
+static int goodix_check_cfg_8(struct goodix_ts_data *ts, const u8 *cfg, int len)
 {
-       int i, raw_cfg_len = cfg->size - 2;
+       int i, raw_cfg_len = len - 2;
        u8 check_sum = 0;
 
        for (i = 0; i < raw_cfg_len; i++)
-               check_sum += cfg->data[i];
+               check_sum += cfg[i];
        check_sum = (~check_sum) + 1;
-       if (check_sum != cfg->data[raw_cfg_len]) {
+       if (check_sum != cfg[raw_cfg_len]) {
                dev_err(&ts->client->dev,
                        "The checksum of the config fw is not correct");
                return -EINVAL;
        }
 
-       if (cfg->data[raw_cfg_len + 1] != 1) {
+       if (cfg[raw_cfg_len + 1] != 1) {
                dev_err(&ts->client->dev,
                        "Config fw must have Config_Fresh register set");
                return -EINVAL;
@@ -430,22 +509,35 @@ static int goodix_check_cfg_8(struct goodix_ts_data *ts,
        return 0;
 }
 
-static int goodix_check_cfg_16(struct goodix_ts_data *ts,
-                       const struct firmware *cfg)
+static void goodix_calc_cfg_checksum_8(struct goodix_ts_data *ts)
 {
-       int i, raw_cfg_len = cfg->size - 3;
+       int i, raw_cfg_len = ts->chip->config_len - 2;
+       u8 check_sum = 0;
+
+       for (i = 0; i < raw_cfg_len; i++)
+               check_sum += ts->config[i];
+       check_sum = (~check_sum) + 1;
+
+       ts->config[raw_cfg_len] = check_sum;
+       ts->config[raw_cfg_len + 1] = 1; /* Set "config_fresh" bit */
+}
+
+static int goodix_check_cfg_16(struct goodix_ts_data *ts, const u8 *cfg,
+                              int len)
+{
+       int i, raw_cfg_len = len - 3;
        u16 check_sum = 0;
 
        for (i = 0; i < raw_cfg_len; i += 2)
-               check_sum += get_unaligned_be16(&cfg->data[i]);
+               check_sum += get_unaligned_be16(&cfg[i]);
        check_sum = (~check_sum) + 1;
-       if (check_sum != get_unaligned_be16(&cfg->data[raw_cfg_len])) {
+       if (check_sum != get_unaligned_be16(&cfg[raw_cfg_len])) {
                dev_err(&ts->client->dev,
                        "The checksum of the config fw is not correct");
                return -EINVAL;
        }
 
-       if (cfg->data[raw_cfg_len + 2] != 1) {
+       if (cfg[raw_cfg_len + 2] != 1) {
                dev_err(&ts->client->dev,
                        "Config fw must have Config_Fresh register set");
                return -EINVAL;
@@ -454,22 +546,35 @@ static int goodix_check_cfg_16(struct goodix_ts_data *ts,
        return 0;
 }
 
+static void goodix_calc_cfg_checksum_16(struct goodix_ts_data *ts)
+{
+       int i, raw_cfg_len = ts->chip->config_len - 3;
+       u16 check_sum = 0;
+
+       for (i = 0; i < raw_cfg_len; i += 2)
+               check_sum += get_unaligned_be16(&ts->config[i]);
+       check_sum = (~check_sum) + 1;
+
+       put_unaligned_be16(check_sum, &ts->config[raw_cfg_len]);
+       ts->config[raw_cfg_len + 2] = 1; /* Set "config_fresh" bit */
+}
+
 /**
  * goodix_check_cfg - Checks if config fw is valid
  *
  * @ts: goodix_ts_data pointer
  * @cfg: firmware config data
  */
-static int goodix_check_cfg(struct goodix_ts_data *ts,
-                           const struct firmware *cfg)
+static int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
 {
-       if (cfg->size > GOODIX_CONFIG_MAX_LENGTH) {
+       if (len < GOODIX_CONFIG_MIN_LENGTH ||
+           len > GOODIX_CONFIG_MAX_LENGTH) {
                dev_err(&ts->client->dev,
                        "The length of the config fw is not correct");
                return -EINVAL;
        }
 
-       return ts->chip->check_config(ts, cfg);
+       return ts->chip->check_config(ts, cfg, len);
 }
 
 /**
@@ -478,17 +583,15 @@ static int goodix_check_cfg(struct goodix_ts_data *ts,
  * @ts: goodix_ts_data pointer
  * @cfg: config firmware to write to device
  */
-static int goodix_send_cfg(struct goodix_ts_data *ts,
-                          const struct firmware *cfg)
+static int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
 {
        int error;
 
-       error = goodix_check_cfg(ts, cfg);
+       error = goodix_check_cfg(ts, cfg, len);
        if (error)
                return error;
 
-       error = goodix_i2c_write(ts->client, ts->chip->config_addr, cfg->data,
-                                cfg->size);
+       error = goodix_i2c_write(ts->client, ts->chip->config_addr, cfg, len);
        if (error) {
                dev_err(&ts->client->dev, "Failed to write config data: %d",
                        error);
@@ -502,17 +605,93 @@ static int goodix_send_cfg(struct goodix_ts_data *ts,
        return 0;
 }
 
+#ifdef ACPI_GPIO_SUPPORT
+static int goodix_pin_acpi_direction_input(struct goodix_ts_data *ts)
+{
+       acpi_handle handle = ACPI_HANDLE(&ts->client->dev);
+       acpi_status status;
+
+       status = acpi_evaluate_object(handle, "INTI", NULL, NULL);
+       return ACPI_SUCCESS(status) ? 0 : -EIO;
+}
+
+static int goodix_pin_acpi_output_method(struct goodix_ts_data *ts, int value)
+{
+       acpi_handle handle = ACPI_HANDLE(&ts->client->dev);
+       acpi_status status;
+
+       status = acpi_execute_simple_method(handle, "INTO", value);
+       return ACPI_SUCCESS(status) ? 0 : -EIO;
+}
+#else
+static int goodix_pin_acpi_direction_input(struct goodix_ts_data *ts)
+{
+       dev_err(&ts->client->dev,
+               "%s called on device without ACPI support\n", __func__);
+       return -EINVAL;
+}
+
+static int goodix_pin_acpi_output_method(struct goodix_ts_data *ts, int value)
+{
+       dev_err(&ts->client->dev,
+               "%s called on device without ACPI support\n", __func__);
+       return -EINVAL;
+}
+#endif
+
+static int goodix_irq_direction_output(struct goodix_ts_data *ts, int value)
+{
+       switch (ts->irq_pin_access_method) {
+       case IRQ_PIN_ACCESS_NONE:
+               dev_err(&ts->client->dev,
+                       "%s called without an irq_pin_access_method set\n",
+                       __func__);
+               return -EINVAL;
+       case IRQ_PIN_ACCESS_GPIO:
+               return gpiod_direction_output(ts->gpiod_int, value);
+       case IRQ_PIN_ACCESS_ACPI_GPIO:
+               /*
+                * The IRQ pin triggers on a falling edge, so its gets marked
+                * as active-low, use output_raw to avoid the value inversion.
+                */
+               return gpiod_direction_output_raw(ts->gpiod_int, value);
+       case IRQ_PIN_ACCESS_ACPI_METHOD:
+               return goodix_pin_acpi_output_method(ts, value);
+       }
+
+       return -EINVAL; /* Never reached */
+}
+
+static int goodix_irq_direction_input(struct goodix_ts_data *ts)
+{
+       switch (ts->irq_pin_access_method) {
+       case IRQ_PIN_ACCESS_NONE:
+               dev_err(&ts->client->dev,
+                       "%s called without an irq_pin_access_method set\n",
+                       __func__);
+               return -EINVAL;
+       case IRQ_PIN_ACCESS_GPIO:
+               return gpiod_direction_input(ts->gpiod_int);
+       case IRQ_PIN_ACCESS_ACPI_GPIO:
+               return gpiod_direction_input(ts->gpiod_int);
+       case IRQ_PIN_ACCESS_ACPI_METHOD:
+               return goodix_pin_acpi_direction_input(ts);
+       }
+
+       return -EINVAL; /* Never reached */
+}
+
 static int goodix_int_sync(struct goodix_ts_data *ts)
 {
        int error;
 
-       error = gpiod_direction_output(ts->gpiod_int, 0);
+       error = goodix_irq_direction_output(ts, 0);
        if (error)
                return error;
 
        msleep(50);                             /* T5: 50ms */
 
-       error = gpiod_direction_input(ts->gpiod_int);
+       error = goodix_irq_direction_input(ts);
        if (error)
                return error;
 
@@ -536,7 +715,7 @@ static int goodix_reset(struct goodix_ts_data *ts)
        msleep(20);                             /* T2: > 10ms */
 
        /* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
-       error = gpiod_direction_output(ts->gpiod_int, ts->client->addr == 0x14);
+       error = goodix_irq_direction_output(ts, ts->client->addr == 0x14);
        if (error)
                return error;
 
@@ -560,6 +739,124 @@ static int goodix_reset(struct goodix_ts_data *ts)
        return 0;
 }
 
+#ifdef ACPI_GPIO_SUPPORT
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+
+static const struct x86_cpu_id baytrail_cpu_ids[] = {
+       { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT, X86_FEATURE_ANY, },
+       {}
+};
+
+static inline bool is_byt(void)
+{
+       const struct x86_cpu_id *id = x86_match_cpu(baytrail_cpu_ids);
+
+       return !!id;
+}
+
+static const struct acpi_gpio_params first_gpio = { 0, 0, false };
+static const struct acpi_gpio_params second_gpio = { 1, 0, false };
+
+static const struct acpi_gpio_mapping acpi_goodix_int_first_gpios[] = {
+       { GOODIX_GPIO_INT_NAME "-gpios", &first_gpio, 1 },
+       { GOODIX_GPIO_RST_NAME "-gpios", &second_gpio, 1 },
+       { },
+};
+
+static const struct acpi_gpio_mapping acpi_goodix_int_last_gpios[] = {
+       { GOODIX_GPIO_RST_NAME "-gpios", &first_gpio, 1 },
+       { GOODIX_GPIO_INT_NAME "-gpios", &second_gpio, 1 },
+       { },
+};
+
+static const struct acpi_gpio_mapping acpi_goodix_reset_only_gpios[] = {
+       { GOODIX_GPIO_RST_NAME "-gpios", &first_gpio, 1 },
+       { },
+};
+
+static int goodix_resource(struct acpi_resource *ares, void *data)
+{
+       struct goodix_ts_data *ts = data;
+       struct device *dev = &ts->client->dev;
+       struct acpi_resource_gpio *gpio;
+
+       switch (ares->type) {
+       case ACPI_RESOURCE_TYPE_GPIO:
+               gpio = &ares->data.gpio;
+               if (gpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT) {
+                       if (ts->gpio_int_idx == -1) {
+                               ts->gpio_int_idx = ts->gpio_count;
+                       } else {
+                               dev_err(dev, "More then one GpioInt resource, ignoring ACPI GPIO resources\n");
+                               ts->gpio_int_idx = -2;
+                       }
+               }
+               ts->gpio_count++;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * This function gets called in case we fail to get the irq GPIO directly
+ * because the ACPI tables lack GPIO-name to APCI _CRS index mappings
+ * (no _DSD UUID daffd814-6eba-4d8c-8a91-bc9bbf4aa301 data).
+ * In that case we add our own mapping and then goodix_get_gpio_config()
+ * retries to get the GPIOs based on the added mapping.
+ */
+static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
+{
+       const struct acpi_gpio_mapping *gpio_mapping = NULL;
+       struct device *dev = &ts->client->dev;
+       LIST_HEAD(resources);
+       int ret;
+
+       ts->gpio_count = 0;
+       ts->gpio_int_idx = -1;
+       ret = acpi_dev_get_resources(ACPI_COMPANION(dev), &resources,
+                                    goodix_resource, ts);
+       if (ret < 0) {
+               dev_err(dev, "Error getting ACPI resources: %d\n", ret);
+               return ret;
+       }
+
+       acpi_dev_free_resource_list(&resources);
+
+       if (ts->gpio_count == 2 && ts->gpio_int_idx == 0) {
+               ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
+               gpio_mapping = acpi_goodix_int_first_gpios;
+       } else if (ts->gpio_count == 2 && ts->gpio_int_idx == 1) {
+               ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
+               gpio_mapping = acpi_goodix_int_last_gpios;
+       } else if (ts->gpio_count == 1 && ts->gpio_int_idx == -1 &&
+                  acpi_has_method(ACPI_HANDLE(dev), "INTI") &&
+                  acpi_has_method(ACPI_HANDLE(dev), "INTO")) {
+               dev_info(dev, "Using ACPI INTI and INTO methods for IRQ pin access\n");
+               ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_METHOD;
+               gpio_mapping = acpi_goodix_reset_only_gpios;
+       } else if (is_byt() && ts->gpio_count == 2 && ts->gpio_int_idx == -1) {
+               dev_info(dev, "No ACPI GpioInt resource, assuming that the GPIO order is reset, int\n");
+               ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
+               gpio_mapping = acpi_goodix_int_last_gpios;
+       } else {
+               dev_warn(dev, "Unexpected ACPI resources: gpio_count %d, gpio_int_idx %d\n",
+                        ts->gpio_count, ts->gpio_int_idx);
+               return -EINVAL;
+       }
+
+       return devm_acpi_dev_add_driver_gpios(dev, gpio_mapping);
+}
+#else
+static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
+{
+       return -EINVAL;
+}
+#endif /* CONFIG_X86 && CONFIG_ACPI */
+
 /**
  * goodix_get_gpio_config - Get GPIO config from ACPI/DT
  *
@@ -570,6 +867,7 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
        int error;
        struct device *dev;
        struct gpio_desc *gpiod;
+       bool added_acpi_mappings = false;
 
        if (!ts->client)
                return -EINVAL;
@@ -593,6 +891,7 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
                return error;
        }
 
+retry_get_irq_gpio:
        /* Get the interrupt GPIO pin number */
        gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
        if (IS_ERR(gpiod)) {
@@ -602,6 +901,11 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
                                GOODIX_GPIO_INT_NAME, error);
                return error;
        }
+       if (!gpiod && has_acpi_companion(dev) && !added_acpi_mappings) {
+               added_acpi_mappings = true;
+               if (goodix_add_acpi_gpio_mappings(ts) == 0)
+                       goto retry_get_irq_gpio;
+       }
 
        ts->gpiod_int = gpiod;
 
@@ -617,6 +921,31 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
 
        ts->gpiod_rst = gpiod;
 
+       switch (ts->irq_pin_access_method) {
+       case IRQ_PIN_ACCESS_ACPI_GPIO:
+               /*
+                * We end up here if goodix_add_acpi_gpio_mappings() has
+                * called devm_acpi_dev_add_driver_gpios() because the ACPI
+                * tables did not contain name to index mappings.
+                * Check that we successfully got both GPIOs after we've
+                * added our own acpi_gpio_mapping and if we did not get both
+                * GPIOs reset irq_pin_access_method to IRQ_PIN_ACCESS_NONE.
+                */
+               if (!ts->gpiod_int || !ts->gpiod_rst)
+                       ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE;
+               break;
+       case IRQ_PIN_ACCESS_ACPI_METHOD:
+               if (!ts->gpiod_rst)
+                       ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE;
+               break;
+       default:
+               if (ts->gpiod_int && ts->gpiod_rst) {
+                       ts->reset_controller_at_probe = true;
+                       ts->load_cfg_from_disk = true;
+                       ts->irq_pin_access_method = IRQ_PIN_ACCESS_GPIO;
+               }
+       }
+
        return 0;
 }
 
@@ -629,12 +958,11 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
  */
 static void goodix_read_config(struct goodix_ts_data *ts)
 {
-       u8 config[GOODIX_CONFIG_MAX_LENGTH];
        int x_max, y_max;
        int error;
 
        error = goodix_i2c_read(ts->client, ts->chip->config_addr,
-                               config, ts->chip->config_len);
+                               ts->config, ts->chip->config_len);
        if (error) {
                dev_warn(&ts->client->dev, "Error reading config: %d\n",
                         error);
@@ -643,15 +971,17 @@ static void goodix_read_config(struct goodix_ts_data *ts)
                return;
        }
 
-       ts->int_trigger_type = config[TRIGGER_LOC] & 0x03;
-       ts->max_touch_num = config[MAX_CONTACTS_LOC] & 0x0f;
+       ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03;
+       ts->max_touch_num = ts->config[MAX_CONTACTS_LOC] & 0x0f;
 
-       x_max = get_unaligned_le16(&config[RESOLUTION_LOC]);
-       y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]);
+       x_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC]);
+       y_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC + 2]);
        if (x_max && y_max) {
                input_abs_set_max(ts->input_dev, ABS_MT_POSITION_X, x_max - 1);
                input_abs_set_max(ts->input_dev, ABS_MT_POSITION_Y, y_max - 1);
        }
+
+       ts->chip->calc_config_checksum(ts);
 }
 
 /**
@@ -663,7 +993,7 @@ static int goodix_read_version(struct goodix_ts_data *ts)
 {
        int error;
        u8 buf[6];
-       char id_str[5];
+       char id_str[GOODIX_ID_MAX_LEN + 1];
 
        error = goodix_i2c_read(ts->client, GOODIX_REG_ID, buf, sizeof(buf));
        if (error) {
@@ -671,14 +1001,13 @@ static int goodix_read_version(struct goodix_ts_data *ts)
                return error;
        }
 
-       memcpy(id_str, buf, 4);
-       id_str[4] = 0;
-       if (kstrtou16(id_str, 10, &ts->id))
-               ts->id = 0x1001;
+       memcpy(id_str, buf, GOODIX_ID_MAX_LEN);
+       id_str[GOODIX_ID_MAX_LEN] = 0;
+       strscpy(ts->id, id_str, GOODIX_ID_MAX_LEN + 1);
 
        ts->version = get_unaligned_le16(&buf[4]);
 
-       dev_info(&ts->client->dev, "ID %d, version: %04x\n", ts->id,
+       dev_info(&ts->client->dev, "ID %s, version: %04x\n", ts->id,
                 ts->version);
 
        return 0;
@@ -722,6 +1051,7 @@ static int goodix_i2c_test(struct i2c_client *client)
 static int goodix_configure_dev(struct goodix_ts_data *ts)
 {
        int error;
+       int i;
 
        ts->int_trigger_type = GOODIX_INT_TRIGGER;
        ts->max_touch_num = GOODIX_MAX_CONTACTS;
@@ -736,11 +1066,23 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
        ts->input_dev->phys = "input/ts";
        ts->input_dev->id.bustype = BUS_I2C;
        ts->input_dev->id.vendor = 0x0416;
-       ts->input_dev->id.product = ts->id;
+       if (kstrtou16(ts->id, 10, &ts->input_dev->id.product))
+               ts->input_dev->id.product = 0x1001;
        ts->input_dev->id.version = ts->version;
 
+       ts->input_dev->keycode = ts->keymap;
+       ts->input_dev->keycodesize = sizeof(ts->keymap[0]);
+       ts->input_dev->keycodemax = GOODIX_MAX_KEYS;
+
        /* Capacitive Windows/Home button on some devices */
-       input_set_capability(ts->input_dev, EV_KEY, KEY_LEFTMETA);
+       for (i = 0; i < GOODIX_MAX_KEYS; ++i) {
+               if (i == 0)
+                       ts->keymap[i] = KEY_LEFTMETA;
+               else
+                       ts->keymap[i] = KEY_F1 + (i - 1);
+
+               input_set_capability(ts->input_dev, EV_KEY, ts->keymap[i]);
+       }
 
        input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_X);
        input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_Y);
@@ -780,6 +1122,12 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
                        "Non-standard 9-bytes report format quirk\n");
        }
 
+       if (dmi_check_system(inverted_x_screen)) {
+               ts->prop.invert_x = true;
+               dev_dbg(&ts->client->dev,
+                       "Applying 'inverted x screen' quirk\n");
+       }
+
        error = input_mt_init_slots(ts->input_dev, ts->max_touch_num,
                                    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
        if (error) {
@@ -820,7 +1168,7 @@ static void goodix_config_cb(const struct firmware *cfg, void *ctx)
 
        if (cfg) {
                /* send device configuration to the firmware */
-               error = goodix_send_cfg(ts, cfg);
+               error = goodix_send_cfg(ts, cfg->data, cfg->size);
                if (error)
                        goto err_release_cfg;
        }
@@ -889,7 +1237,8 @@ static int goodix_ts_probe(struct i2c_client *client,
        if (error)
                return error;
 
-       if (ts->gpiod_int && ts->gpiod_rst) {
+reset:
+       if (ts->reset_controller_at_probe) {
                /* reset the controller */
                error = goodix_reset(ts);
                if (error) {
@@ -900,6 +1249,12 @@ static int goodix_ts_probe(struct i2c_client *client,
 
        error = goodix_i2c_test(client);
        if (error) {
+               if (!ts->reset_controller_at_probe &&
+                   ts->irq_pin_access_method != IRQ_PIN_ACCESS_NONE) {
+                       /* Retry after a controller reset */
+                       ts->reset_controller_at_probe = true;
+                       goto reset;
+               }
                dev_err(&client->dev, "I2C communication failure: %d\n", error);
                return error;
        }
@@ -912,10 +1267,10 @@ static int goodix_ts_probe(struct i2c_client *client,
 
        ts->chip = goodix_get_chip_data(ts->id);
 
-       if (ts->gpiod_int && ts->gpiod_rst) {
+       if (ts->load_cfg_from_disk) {
                /* update device config */
                ts->cfg_name = devm_kasprintf(&client->dev, GFP_KERNEL,
-                                             "goodix_%d_cfg.bin", ts->id);
+                                             "goodix_%s_cfg.bin", ts->id);
                if (!ts->cfg_name)
                        return -ENOMEM;
 
@@ -943,7 +1298,7 @@ static int goodix_ts_remove(struct i2c_client *client)
 {
        struct goodix_ts_data *ts = i2c_get_clientdata(client);
 
-       if (ts->gpiod_int && ts->gpiod_rst)
+       if (ts->load_cfg_from_disk)
                wait_for_completion(&ts->firmware_loading_complete);
 
        return 0;
@@ -955,19 +1310,20 @@ static int __maybe_unused goodix_suspend(struct device *dev)
        struct goodix_ts_data *ts = i2c_get_clientdata(client);
        int error;
 
+       if (ts->load_cfg_from_disk)
+               wait_for_completion(&ts->firmware_loading_complete);
+
        /* We need gpio pins to suspend/resume */
-       if (!ts->gpiod_int || !ts->gpiod_rst) {
+       if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
                disable_irq(client->irq);
                return 0;
        }
 
-       wait_for_completion(&ts->firmware_loading_complete);
-
        /* Free IRQ as IRQ pin is used as output in the suspend sequence */
        goodix_free_irq(ts);
 
        /* Output LOW on the INT pin for 5 ms */
-       error = gpiod_direction_output(ts->gpiod_int, 0);
+       error = goodix_irq_direction_output(ts, 0);
        if (error) {
                goodix_request_irq(ts);
                return error;
@@ -979,7 +1335,7 @@ static int __maybe_unused goodix_suspend(struct device *dev)
                                    GOODIX_CMD_SCREEN_OFF);
        if (error) {
                dev_err(&ts->client->dev, "Screen off command failed\n");
-               gpiod_direction_input(ts->gpiod_int);
+               goodix_irq_direction_input(ts);
                goodix_request_irq(ts);
                return -EAGAIN;
        }
@@ -997,9 +1353,10 @@ static int __maybe_unused goodix_resume(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct goodix_ts_data *ts = i2c_get_clientdata(client);
+       u8 config_ver;
        int error;
 
-       if (!ts->gpiod_int || !ts->gpiod_rst) {
+       if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
                enable_irq(client->irq);
                return 0;
        }
@@ -1008,7 +1365,7 @@ static int __maybe_unused goodix_resume(struct device *dev)
         * Exit sleep mode by outputting HIGH level to INT pin
         * for 2ms~5ms.
         */
-       error = gpiod_direction_output(ts->gpiod_int, 1);
+       error = goodix_irq_direction_output(ts, 1);
        if (error)
                return error;
 
@@ -1018,6 +1375,27 @@ static int __maybe_unused goodix_resume(struct device *dev)
        if (error)
                return error;
 
+       error = goodix_i2c_read(ts->client, ts->chip->config_addr,
+                               &config_ver, 1);
+       if (error)
+               dev_warn(dev, "Error reading config version: %d, resetting controller\n",
+                        error);
+       else if (config_ver != ts->config[0])
+               dev_info(dev, "Config version mismatch %d != %d, resetting controller\n",
+                        config_ver, ts->config[0]);
+
+       if (error != 0 || config_ver != ts->config[0]) {
+               error = goodix_reset(ts);
+               if (error) {
+                       dev_err(dev, "Controller reset failed.\n");
+                       return error;
+               }
+
+               error = goodix_send_cfg(ts, ts->config, ts->chip->config_len);
+               if (error)
+                       return error;
+       }
+
        error = goodix_request_irq(ts);
        if (error)
                return error;
@@ -1050,6 +1428,8 @@ static const struct of_device_id goodix_of_match[] = {
        { .compatible = "goodix,gt911" },
        { .compatible = "goodix,gt9110" },
        { .compatible = "goodix,gt912" },
+       { .compatible = "goodix,gt9147" },
+       { .compatible = "goodix,gt917s" },
        { .compatible = "goodix,gt927" },
        { .compatible = "goodix,gt9271" },
        { .compatible = "goodix,gt928" },
index e16ec4c..97342e1 100644 (file)
@@ -66,7 +66,7 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
 {
        struct device *dev = input->dev.parent;
        struct input_absinfo *absinfo;
-       unsigned int axis;
+       unsigned int axis, axis_x, axis_y;
        unsigned int minimum, maximum, fuzz;
        bool data_present;
 
@@ -74,33 +74,34 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
        if (!input->absinfo)
                return;
 
-       axis = multitouch ? ABS_MT_POSITION_X : ABS_X;
+       axis_x = multitouch ? ABS_MT_POSITION_X : ABS_X;
+       axis_y = multitouch ? ABS_MT_POSITION_Y : ABS_Y;
+
        data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-x",
-                                               input_abs_get_min(input, axis),
+                                               input_abs_get_min(input, axis_x),
                                                &minimum) |
                       touchscreen_get_prop_u32(dev, "touchscreen-size-x",
                                                input_abs_get_max(input,
-                                                                 axis) + 1,
+                                                                 axis_x) + 1,
                                                &maximum) |
                       touchscreen_get_prop_u32(dev, "touchscreen-fuzz-x",
-                                               input_abs_get_fuzz(input, axis),
+                                               input_abs_get_fuzz(input, axis_x),
                                                &fuzz);
        if (data_present)
-               touchscreen_set_params(input, axis, minimum, maximum - 1, fuzz);
+               touchscreen_set_params(input, axis_x, minimum, maximum - 1, fuzz);
 
-       axis = multitouch ? ABS_MT_POSITION_Y : ABS_Y;
        data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-y",
-                                               input_abs_get_min(input, axis),
+                                               input_abs_get_min(input, axis_y),
                                                &minimum) |
                       touchscreen_get_prop_u32(dev, "touchscreen-size-y",
                                                input_abs_get_max(input,
-                                                                 axis) + 1,
+                                                                 axis_y) + 1,
                                                &maximum) |
                       touchscreen_get_prop_u32(dev, "touchscreen-fuzz-y",
-                                               input_abs_get_fuzz(input, axis),
+                                               input_abs_get_fuzz(input, axis_y),
                                                &fuzz);
        if (data_present)
-               touchscreen_set_params(input, axis, minimum, maximum - 1, fuzz);
+               touchscreen_set_params(input, axis_y, minimum, maximum - 1, fuzz);
 
        axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE;
        data_present = touchscreen_get_prop_u32(dev,
@@ -117,15 +118,13 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
        if (!prop)
                return;
 
-       axis = multitouch ? ABS_MT_POSITION_X : ABS_X;
-
-       prop->max_x = input_abs_get_max(input, axis);
-       prop->max_y = input_abs_get_max(input, axis + 1);
+       prop->max_x = input_abs_get_max(input, axis_x);
+       prop->max_y = input_abs_get_max(input, axis_y);
 
        prop->invert_x =
                device_property_read_bool(dev, "touchscreen-inverted-x");
        if (prop->invert_x) {
-               absinfo = &input->absinfo[axis];
+               absinfo = &input->absinfo[axis_x];
                absinfo->maximum -= absinfo->minimum;
                absinfo->minimum = 0;
        }
@@ -133,7 +132,7 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
        prop->invert_y =
                device_property_read_bool(dev, "touchscreen-inverted-y");
        if (prop->invert_y) {
-               absinfo = &input->absinfo[axis + 1];
+               absinfo = &input->absinfo[axis_y];
                absinfo->maximum -= absinfo->minimum;
                absinfo->minimum = 0;
        }
@@ -141,7 +140,7 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
        prop->swap_x_y =
                device_property_read_bool(dev, "touchscreen-swapped-x-y");
        if (prop->swap_x_y)
-               swap(input->absinfo[axis], input->absinfo[axis + 1]);
+               swap(input->absinfo[axis_x], input->absinfo[axis_y]);
 }
 EXPORT_SYMBOL(touchscreen_parse_properties);
 
index d2fade9..58b4a4d 100644 (file)
@@ -188,6 +188,7 @@ config INTEL_IOMMU
        select NEED_DMA_MAP_STATE
        select DMAR_TABLE
        select SWIOTLB
+       select IOASID
        help
          DMA remapping (DMAR) devices support enables independent address
          translations for Direct Memory Access (DMA) from devices.
@@ -273,7 +274,7 @@ config IRQ_REMAP
 # OMAP IOMMU support
 config OMAP_IOMMU
        bool "OMAP IOMMU Support"
-       depends on ARM && MMU
+       depends on ARM && MMU || (COMPILE_TEST && (ARM || ARM64 || IA64 || SPARC))
        depends on ARCH_OMAP2PLUS || COMPILE_TEST
        select IOMMU_API
        ---help---
@@ -291,7 +292,7 @@ config OMAP_IOMMU_DEBUG
 
 config ROCKCHIP_IOMMU
        bool "Rockchip IOMMU Support"
-       depends on ARM || ARM64
+       depends on ARM || ARM64 || (COMPILE_TEST && (ARM64 || IA64 || SPARC))
        depends on ARCH_ROCKCHIP || COMPILE_TEST
        select IOMMU_API
        select ARM_DMA_USE_IOMMU
@@ -325,7 +326,7 @@ config TEGRA_IOMMU_SMMU
 
 config EXYNOS_IOMMU
        bool "Exynos IOMMU Support"
-       depends on ARCH_EXYNOS && MMU
+       depends on ARCH_EXYNOS && MMU || (COMPILE_TEST && (ARM || ARM64 || IA64 || SPARC))
        depends on !CPU_BIG_ENDIAN # revisit driver if we can enable big-endian ptes
        select IOMMU_API
        select ARM_DMA_USE_IOMMU
@@ -361,7 +362,7 @@ config IPMMU_VMSA
 
 config SPAPR_TCE_IOMMU
        bool "sPAPR TCE IOMMU Support"
-       depends on PPC_POWERNV || PPC_PSERIES
+       depends on PPC_POWERNV || PPC_PSERIES || (PPC && COMPILE_TEST)
        select IOMMU_API
        help
          Enables bits of IOMMU API required by VFIO. The iommu_ops
@@ -370,7 +371,7 @@ config SPAPR_TCE_IOMMU
 # ARM IOMMU support
 config ARM_SMMU
        tristate "ARM Ltd. System MMU (SMMU) Support"
-       depends on (ARM64 || ARM) && MMU
+       depends on (ARM64 || ARM || (COMPILE_TEST && !GENERIC_ATOMIC64)) && MMU
        select IOMMU_API
        select IOMMU_IO_PGTABLE_LPAE
        select ARM_DMA_USE_IOMMU if ARM
@@ -440,7 +441,7 @@ config S390_IOMMU
 
 config S390_CCW_IOMMU
        bool "S390 CCW IOMMU Support"
-       depends on S390 && CCW
+       depends on S390 && CCW || COMPILE_TEST
        select IOMMU_API
        help
          Enables bits of IOMMU API required by VFIO. The iommu_ops
@@ -448,7 +449,7 @@ config S390_CCW_IOMMU
 
 config S390_AP_IOMMU
        bool "S390 AP IOMMU Support"
-       depends on S390 && ZCRYPT
+       depends on S390 && ZCRYPT || COMPILE_TEST
        select IOMMU_API
        help
          Enables bits of IOMMU API required by VFIO. The iommu_ops
@@ -456,7 +457,7 @@ config S390_AP_IOMMU
 
 config MTK_IOMMU
        bool "MTK IOMMU Support"
-       depends on ARM || ARM64
+       depends on ARM || ARM64 || COMPILE_TEST
        depends on ARCH_MEDIATEK || COMPILE_TEST
        select ARM_DMA_USE_IOMMU
        select IOMMU_API
@@ -506,8 +507,8 @@ config HYPERV_IOMMU
          guests to run with x2APIC mode enabled.
 
 config VIRTIO_IOMMU
-       bool "Virtio IOMMU driver"
-       depends on VIRTIO=y
+       tristate "Virtio IOMMU driver"
+       depends on VIRTIO
        depends on ARM64
        select IOMMU_API
        select INTERVAL_TREE
index f8d01d6..ca8c452 100644 (file)
 
 #define DTE_GCR3_VAL_A(x)      (((x) >> 12) & 0x00007ULL)
 #define DTE_GCR3_VAL_B(x)      (((x) >> 15) & 0x0ffffULL)
-#define DTE_GCR3_VAL_C(x)      (((x) >> 31) & 0xfffffULL)
+#define DTE_GCR3_VAL_C(x)      (((x) >> 31) & 0x1fffffULL)
 
 #define DTE_GCR3_INDEX_A       0
 #define DTE_GCR3_INDEX_B       1
index aa3ac2a..8250873 100644 (file)
@@ -69,6 +69,9 @@
 #define IDR1_SSIDSIZE                  GENMASK(10, 6)
 #define IDR1_SIDSIZE                   GENMASK(5, 0)
 
+#define ARM_SMMU_IDR3                  0xc
+#define IDR3_RIL                       (1 << 10)
+
 #define ARM_SMMU_IDR5                  0x14
 #define IDR5_STALL_MAX                 GENMASK(31, 16)
 #define IDR5_GRAN64K                   (1 << 6)
 #define CMDQ_CFGI_1_LEAF               (1UL << 0)
 #define CMDQ_CFGI_1_RANGE              GENMASK_ULL(4, 0)
 
+#define CMDQ_TLBI_0_NUM                        GENMASK_ULL(16, 12)
+#define CMDQ_TLBI_RANGE_NUM_MAX                31
+#define CMDQ_TLBI_0_SCALE              GENMASK_ULL(24, 20)
 #define CMDQ_TLBI_0_VMID               GENMASK_ULL(47, 32)
 #define CMDQ_TLBI_0_ASID               GENMASK_ULL(63, 48)
 #define CMDQ_TLBI_1_LEAF               (1UL << 0)
+#define CMDQ_TLBI_1_TTL                        GENMASK_ULL(9, 8)
+#define CMDQ_TLBI_1_TG                 GENMASK_ULL(11, 10)
 #define CMDQ_TLBI_1_VA_MASK            GENMASK_ULL(63, 12)
 #define CMDQ_TLBI_1_IPA_MASK           GENMASK_ULL(51, 12)
 
@@ -473,9 +481,13 @@ struct arm_smmu_cmdq_ent {
                #define CMDQ_OP_TLBI_S2_IPA     0x2a
                #define CMDQ_OP_TLBI_NSNH_ALL   0x30
                struct {
+                       u8                      num;
+                       u8                      scale;
                        u16                     asid;
                        u16                     vmid;
                        bool                    leaf;
+                       u8                      ttl;
+                       u8                      tg;
                        u64                     addr;
                } tlbi;
 
@@ -548,6 +560,11 @@ struct arm_smmu_cmdq {
        atomic_t                        lock;
 };
 
+struct arm_smmu_cmdq_batch {
+       u64                             cmds[CMDQ_BATCH_ENTRIES * CMDQ_ENT_DWORDS];
+       int                             num;
+};
+
 struct arm_smmu_evtq {
        struct arm_smmu_queue           q;
        u32                             max_stalls;
@@ -627,6 +644,7 @@ struct arm_smmu_device {
 #define ARM_SMMU_FEAT_HYP              (1 << 12)
 #define ARM_SMMU_FEAT_STALL_FORCE      (1 << 13)
 #define ARM_SMMU_FEAT_VAX              (1 << 14)
+#define ARM_SMMU_FEAT_RANGE_INV                (1 << 15)
        u32                             features;
 
 #define ARM_SMMU_OPT_SKIP_PREFETCH     (1 << 0)
@@ -895,14 +913,22 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
                cmd[1] |= FIELD_PREP(CMDQ_CFGI_1_RANGE, 31);
                break;
        case CMDQ_OP_TLBI_NH_VA:
+               cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_NUM, ent->tlbi.num);
+               cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_SCALE, ent->tlbi.scale);
                cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid);
                cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_ASID, ent->tlbi.asid);
                cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_LEAF, ent->tlbi.leaf);
+               cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_TTL, ent->tlbi.ttl);
+               cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_TG, ent->tlbi.tg);
                cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_VA_MASK;
                break;
        case CMDQ_OP_TLBI_S2_IPA:
+               cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_NUM, ent->tlbi.num);
+               cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_SCALE, ent->tlbi.scale);
                cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid);
                cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_LEAF, ent->tlbi.leaf);
+               cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_TTL, ent->tlbi.ttl);
+               cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_TG, ent->tlbi.tg);
                cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_IPA_MASK;
                break;
        case CMDQ_OP_TLBI_NH_ASID:
@@ -1482,6 +1508,24 @@ static int arm_smmu_cmdq_issue_sync(struct arm_smmu_device *smmu)
        return arm_smmu_cmdq_issue_cmdlist(smmu, NULL, 0, true);
 }
 
+static void arm_smmu_cmdq_batch_add(struct arm_smmu_device *smmu,
+                                   struct arm_smmu_cmdq_batch *cmds,
+                                   struct arm_smmu_cmdq_ent *cmd)
+{
+       if (cmds->num == CMDQ_BATCH_ENTRIES) {
+               arm_smmu_cmdq_issue_cmdlist(smmu, cmds->cmds, cmds->num, false);
+               cmds->num = 0;
+       }
+       arm_smmu_cmdq_build_cmd(&cmds->cmds[cmds->num * CMDQ_ENT_DWORDS], cmd);
+       cmds->num++;
+}
+
+static int arm_smmu_cmdq_batch_submit(struct arm_smmu_device *smmu,
+                                     struct arm_smmu_cmdq_batch *cmds)
+{
+       return arm_smmu_cmdq_issue_cmdlist(smmu, cmds->cmds, cmds->num, true);
+}
+
 /* Context descriptor manipulation functions */
 static void arm_smmu_sync_cd(struct arm_smmu_domain *smmu_domain,
                             int ssid, bool leaf)
@@ -1489,6 +1533,7 @@ static void arm_smmu_sync_cd(struct arm_smmu_domain *smmu_domain,
        size_t i;
        unsigned long flags;
        struct arm_smmu_master *master;
+       struct arm_smmu_cmdq_batch cmds = {};
        struct arm_smmu_device *smmu = smmu_domain->smmu;
        struct arm_smmu_cmdq_ent cmd = {
                .opcode = CMDQ_OP_CFGI_CD,
@@ -1502,12 +1547,12 @@ static void arm_smmu_sync_cd(struct arm_smmu_domain *smmu_domain,
        list_for_each_entry(master, &smmu_domain->devices, domain_head) {
                for (i = 0; i < master->num_sids; i++) {
                        cmd.cfgi.sid = master->sids[i];
-                       arm_smmu_cmdq_issue_cmd(smmu, &cmd);
+                       arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
                }
        }
        spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
 
-       arm_smmu_cmdq_issue_sync(smmu);
+       arm_smmu_cmdq_batch_submit(smmu, &cmds);
 }
 
 static int arm_smmu_alloc_cd_leaf_table(struct arm_smmu_device *smmu,
@@ -1531,6 +1576,7 @@ static void arm_smmu_write_cd_l1_desc(__le64 *dst,
        u64 val = (l1_desc->l2ptr_dma & CTXDESC_L1_DESC_L2PTR_MASK) |
                  CTXDESC_L1_DESC_V;
 
+       /* See comment in arm_smmu_write_ctx_desc() */
        WRITE_ONCE(*dst, cpu_to_le64(val));
 }
 
@@ -1726,7 +1772,8 @@ arm_smmu_write_strtab_l1_desc(__le64 *dst, struct arm_smmu_strtab_l1_desc *desc)
        val |= FIELD_PREP(STRTAB_L1_DESC_SPAN, desc->span);
        val |= desc->l2ptr_dma & STRTAB_L1_DESC_L2PTR_MASK;
 
-       *dst = cpu_to_le64(val);
+       /* See comment in arm_smmu_write_ctx_desc() */
+       WRITE_ONCE(*dst, cpu_to_le64(val));
 }
 
 static void arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid)
@@ -2132,17 +2179,16 @@ arm_smmu_atc_inv_to_cmd(int ssid, unsigned long iova, size_t size,
        cmd->atc.size   = log2_span;
 }
 
-static int arm_smmu_atc_inv_master(struct arm_smmu_master *master,
-                                  struct arm_smmu_cmdq_ent *cmd)
+static int arm_smmu_atc_inv_master(struct arm_smmu_master *master)
 {
        int i;
+       struct arm_smmu_cmdq_ent cmd;
 
-       if (!master->ats_enabled)
-               return 0;
+       arm_smmu_atc_inv_to_cmd(0, 0, 0, &cmd);
 
        for (i = 0; i < master->num_sids; i++) {
-               cmd->atc.sid = master->sids[i];
-               arm_smmu_cmdq_issue_cmd(master->smmu, cmd);
+               cmd.atc.sid = master->sids[i];
+               arm_smmu_cmdq_issue_cmd(master->smmu, &cmd);
        }
 
        return arm_smmu_cmdq_issue_sync(master->smmu);
@@ -2151,10 +2197,11 @@ static int arm_smmu_atc_inv_master(struct arm_smmu_master *master,
 static int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
                                   int ssid, unsigned long iova, size_t size)
 {
-       int ret = 0;
+       int i;
        unsigned long flags;
        struct arm_smmu_cmdq_ent cmd;
        struct arm_smmu_master *master;
+       struct arm_smmu_cmdq_batch cmds = {};
 
        if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_ATS))
                return 0;
@@ -2179,11 +2226,18 @@ static int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
        arm_smmu_atc_inv_to_cmd(ssid, iova, size, &cmd);
 
        spin_lock_irqsave(&smmu_domain->devices_lock, flags);
-       list_for_each_entry(master, &smmu_domain->devices, domain_head)
-               ret |= arm_smmu_atc_inv_master(master, &cmd);
+       list_for_each_entry(master, &smmu_domain->devices, domain_head) {
+               if (!master->ats_enabled)
+                       continue;
+
+               for (i = 0; i < master->num_sids; i++) {
+                       cmd.atc.sid = master->sids[i];
+                       arm_smmu_cmdq_batch_add(smmu_domain->smmu, &cmds, &cmd);
+               }
+       }
        spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
 
-       return ret ? -ETIMEDOUT : 0;
+       return arm_smmu_cmdq_batch_submit(smmu_domain->smmu, &cmds);
 }
 
 /* IO_PGTABLE API */
@@ -2218,10 +2272,10 @@ static void arm_smmu_tlb_inv_range(unsigned long iova, size_t size,
                                   size_t granule, bool leaf,
                                   struct arm_smmu_domain *smmu_domain)
 {
-       u64 cmds[CMDQ_BATCH_ENTRIES * CMDQ_ENT_DWORDS];
        struct arm_smmu_device *smmu = smmu_domain->smmu;
-       unsigned long start = iova, end = iova + size;
-       int i = 0;
+       unsigned long start = iova, end = iova + size, num_pages = 0, tg = 0;
+       size_t inv_range = granule;
+       struct arm_smmu_cmdq_batch cmds = {};
        struct arm_smmu_cmdq_ent cmd = {
                .tlbi = {
                        .leaf   = leaf,
@@ -2239,19 +2293,50 @@ static void arm_smmu_tlb_inv_range(unsigned long iova, size_t size,
                cmd.tlbi.vmid   = smmu_domain->s2_cfg.vmid;
        }
 
+       if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
+               /* Get the leaf page size */
+               tg = __ffs(smmu_domain->domain.pgsize_bitmap);
+
+               /* Convert page size of 12,14,16 (log2) to 1,2,3 */
+               cmd.tlbi.tg = (tg - 10) / 2;
+
+               /* Determine what level the granule is at */
+               cmd.tlbi.ttl = 4 - ((ilog2(granule) - 3) / (tg - 3));
+
+               num_pages = size >> tg;
+       }
+
        while (iova < end) {
-               if (i == CMDQ_BATCH_ENTRIES) {
-                       arm_smmu_cmdq_issue_cmdlist(smmu, cmds, i, false);
-                       i = 0;
+               if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
+                       /*
+                        * On each iteration of the loop, the range is 5 bits
+                        * worth of the aligned size remaining.
+                        * The range in pages is:
+                        *
+                        * range = (num_pages & (0x1f << __ffs(num_pages)))
+                        */
+                       unsigned long scale, num;
+
+                       /* Determine the power of 2 multiple number of pages */
+                       scale = __ffs(num_pages);
+                       cmd.tlbi.scale = scale;
+
+                       /* Determine how many chunks of 2^scale size we have */
+                       num = (num_pages >> scale) & CMDQ_TLBI_RANGE_NUM_MAX;
+                       cmd.tlbi.num = num - 1;
+
+                       /* range is num * 2^scale * pgsize */
+                       inv_range = num << (scale + tg);
+
+                       /* Clear out the lower order bits for the next iteration */
+                       num_pages -= num << scale;
                }
 
                cmd.tlbi.addr = iova;
-               arm_smmu_cmdq_build_cmd(&cmds[i * CMDQ_ENT_DWORDS], &cmd);
-               iova += granule;
-               i++;
+               arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
+               iova += inv_range;
        }
-
-       arm_smmu_cmdq_issue_cmdlist(smmu, cmds, i, true);
+       arm_smmu_cmdq_batch_submit(smmu, &cmds);
 
        /*
         * Unfortunately, this can't be leaf-only since we may have
@@ -2611,7 +2696,6 @@ static void arm_smmu_enable_ats(struct arm_smmu_master *master)
 
 static void arm_smmu_disable_ats(struct arm_smmu_master *master)
 {
-       struct arm_smmu_cmdq_ent cmd;
        struct arm_smmu_domain *smmu_domain = master->domain;
 
        if (!master->ats_enabled)
@@ -2623,11 +2707,57 @@ static void arm_smmu_disable_ats(struct arm_smmu_master *master)
         * ATC invalidation via the SMMU.
         */
        wmb();
-       arm_smmu_atc_inv_to_cmd(0, 0, 0, &cmd);
-       arm_smmu_atc_inv_master(master, &cmd);
+       arm_smmu_atc_inv_master(master);
        atomic_dec(&smmu_domain->nr_ats_masters);
 }
 
+static int arm_smmu_enable_pasid(struct arm_smmu_master *master)
+{
+       int ret;
+       int features;
+       int num_pasids;
+       struct pci_dev *pdev;
+
+       if (!dev_is_pci(master->dev))
+               return -ENODEV;
+
+       pdev = to_pci_dev(master->dev);
+
+       features = pci_pasid_features(pdev);
+       if (features < 0)
+               return features;
+
+       num_pasids = pci_max_pasids(pdev);
+       if (num_pasids <= 0)
+               return num_pasids;
+
+       ret = pci_enable_pasid(pdev, features);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to enable PASID\n");
+               return ret;
+       }
+
+       master->ssid_bits = min_t(u8, ilog2(num_pasids),
+                                 master->smmu->ssid_bits);
+       return 0;
+}
+
+static void arm_smmu_disable_pasid(struct arm_smmu_master *master)
+{
+       struct pci_dev *pdev;
+
+       if (!dev_is_pci(master->dev))
+               return;
+
+       pdev = to_pci_dev(master->dev);
+
+       if (!pdev->pasid_enabled)
+               return;
+
+       master->ssid_bits = 0;
+       pci_disable_pasid(pdev);
+}
+
 static void arm_smmu_detach_dev(struct arm_smmu_master *master)
 {
        unsigned long flags;
@@ -2659,7 +2789,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
        if (!fwspec)
                return -ENOENT;
 
-       master = fwspec->iommu_priv;
+       master = dev_iommu_priv_get(dev);
        smmu = master->smmu;
 
        arm_smmu_detach_dev(master);
@@ -2795,7 +2925,7 @@ static int arm_smmu_add_device(struct device *dev)
        if (!fwspec || fwspec->ops != &arm_smmu_ops)
                return -ENODEV;
 
-       if (WARN_ON_ONCE(fwspec->iommu_priv))
+       if (WARN_ON_ONCE(dev_iommu_priv_get(dev)))
                return -EBUSY;
 
        smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
@@ -2810,7 +2940,7 @@ static int arm_smmu_add_device(struct device *dev)
        master->smmu = smmu;
        master->sids = fwspec->ids;
        master->num_sids = fwspec->num_ids;
-       fwspec->iommu_priv = master;
+       dev_iommu_priv_set(dev, master);
 
        /* Check the SIDs are in range of the SMMU and our stream table */
        for (i = 0; i < master->num_sids; i++) {
@@ -2831,13 +2961,23 @@ static int arm_smmu_add_device(struct device *dev)
 
        master->ssid_bits = min(smmu->ssid_bits, fwspec->num_pasid_bits);
 
+       /*
+        * Note that PASID must be enabled before, and disabled after ATS:
+        * PCI Express Base 4.0r1.0 - 10.5.1.3 ATS Control Register
+        *
+        *   Behavior is undefined if this bit is Set and the value of the PASID
+        *   Enable, Execute Requested Enable, or Privileged Mode Requested bits
+        *   are changed.
+        */
+       arm_smmu_enable_pasid(master);
+
        if (!(smmu->features & ARM_SMMU_FEAT_2_LVL_CDTAB))
                master->ssid_bits = min_t(u8, master->ssid_bits,
                                          CTXDESC_LINEAR_CDMAX);
 
        ret = iommu_device_link(&smmu->iommu, dev);
        if (ret)
-               goto err_free_master;
+               goto err_disable_pasid;
 
        group = iommu_group_get_for_dev(dev);
        if (IS_ERR(group)) {
@@ -2850,9 +2990,11 @@ static int arm_smmu_add_device(struct device *dev)
 
 err_unlink:
        iommu_device_unlink(&smmu->iommu, dev);
+err_disable_pasid:
+       arm_smmu_disable_pasid(master);
 err_free_master:
        kfree(master);
-       fwspec->iommu_priv = NULL;
+       dev_iommu_priv_set(dev, NULL);
        return ret;
 }
 
@@ -2865,11 +3007,12 @@ static void arm_smmu_remove_device(struct device *dev)
        if (!fwspec || fwspec->ops != &arm_smmu_ops)
                return;
 
-       master = fwspec->iommu_priv;
+       master = dev_iommu_priv_get(dev);
        smmu = master->smmu;
        arm_smmu_detach_dev(master);
        iommu_group_remove_device(dev);
        iommu_device_unlink(&smmu->iommu, dev);
+       arm_smmu_disable_pasid(master);
        kfree(master);
        iommu_fwspec_free(dev);
 }
@@ -3700,6 +3843,11 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
        if (smmu->sid_bits <= STRTAB_SPLIT)
                smmu->features &= ~ARM_SMMU_FEAT_2_LVL_STRTAB;
 
+       /* IDR3 */
+       reg = readl_relaxed(smmu->base + ARM_SMMU_IDR3);
+       if (FIELD_GET(IDR3_RIL, reg))
+               smmu->features |= ARM_SMMU_FEAT_RANGE_INV;
+
        /* IDR5 */
        reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5);
 
index 16c4b87..a6a5796 100644 (file)
@@ -98,12 +98,10 @@ struct arm_smmu_master_cfg {
        s16                             smendx[];
 };
 #define INVALID_SMENDX                 -1
-#define __fwspec_cfg(fw) ((struct arm_smmu_master_cfg *)fw->iommu_priv)
-#define fwspec_smmu(fw)  (__fwspec_cfg(fw)->smmu)
-#define fwspec_smendx(fw, i) \
-       (i >= fw->num_ids ? INVALID_SMENDX : __fwspec_cfg(fw)->smendx[i])
-#define for_each_cfg_sme(fw, i, idx) \
-       for (i = 0; idx = fwspec_smendx(fw, i), i < fw->num_ids; ++i)
+#define cfg_smendx(cfg, fw, i) \
+       (i >= fw->num_ids ? INVALID_SMENDX : cfg->smendx[i])
+#define for_each_cfg_sme(cfg, fw, i, idx) \
+       for (i = 0; idx = cfg_smendx(cfg, fw, i), i < fw->num_ids; ++i)
 
 static bool using_legacy_binding, using_generic_binding;
 
@@ -1061,7 +1059,7 @@ static bool arm_smmu_free_sme(struct arm_smmu_device *smmu, int idx)
 static int arm_smmu_master_alloc_smes(struct device *dev)
 {
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-       struct arm_smmu_master_cfg *cfg = fwspec->iommu_priv;
+       struct arm_smmu_master_cfg *cfg = dev_iommu_priv_get(dev);
        struct arm_smmu_device *smmu = cfg->smmu;
        struct arm_smmu_smr *smrs = smmu->smrs;
        struct iommu_group *group;
@@ -1069,7 +1067,7 @@ static int arm_smmu_master_alloc_smes(struct device *dev)
 
        mutex_lock(&smmu->stream_map_mutex);
        /* Figure out a viable stream map entry allocation */
-       for_each_cfg_sme(fwspec, i, idx) {
+       for_each_cfg_sme(cfg, fwspec, i, idx) {
                u16 sid = FIELD_GET(ARM_SMMU_SMR_ID, fwspec->ids[i]);
                u16 mask = FIELD_GET(ARM_SMMU_SMR_MASK, fwspec->ids[i]);
 
@@ -1100,7 +1098,7 @@ static int arm_smmu_master_alloc_smes(struct device *dev)
        iommu_group_put(group);
 
        /* It worked! Now, poke the actual hardware */
-       for_each_cfg_sme(fwspec, i, idx) {
+       for_each_cfg_sme(cfg, fwspec, i, idx) {
                arm_smmu_write_sme(smmu, idx);
                smmu->s2crs[idx].group = group;
        }
@@ -1117,14 +1115,14 @@ out_err:
        return ret;
 }
 
-static void arm_smmu_master_free_smes(struct iommu_fwspec *fwspec)
+static void arm_smmu_master_free_smes(struct arm_smmu_master_cfg *cfg,
+                                     struct iommu_fwspec *fwspec)
 {
-       struct arm_smmu_device *smmu = fwspec_smmu(fwspec);
-       struct arm_smmu_master_cfg *cfg = fwspec->iommu_priv;
+       struct arm_smmu_device *smmu = cfg->smmu;
        int i, idx;
 
        mutex_lock(&smmu->stream_map_mutex);
-       for_each_cfg_sme(fwspec, i, idx) {
+       for_each_cfg_sme(cfg, fwspec, i, idx) {
                if (arm_smmu_free_sme(smmu, idx))
                        arm_smmu_write_sme(smmu, idx);
                cfg->smendx[i] = INVALID_SMENDX;
@@ -1133,6 +1131,7 @@ static void arm_smmu_master_free_smes(struct iommu_fwspec *fwspec)
 }
 
 static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
+                                     struct arm_smmu_master_cfg *cfg,
                                      struct iommu_fwspec *fwspec)
 {
        struct arm_smmu_device *smmu = smmu_domain->smmu;
@@ -1146,7 +1145,7 @@ static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
        else
                type = S2CR_TYPE_TRANS;
 
-       for_each_cfg_sme(fwspec, i, idx) {
+       for_each_cfg_sme(cfg, fwspec, i, idx) {
                if (type == s2cr[idx].type && cbndx == s2cr[idx].cbndx)
                        continue;
 
@@ -1160,10 +1159,11 @@ static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
 
 static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 {
-       int ret;
+       struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+       struct arm_smmu_master_cfg *cfg;
        struct arm_smmu_device *smmu;
-       struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+       int ret;
 
        if (!fwspec || fwspec->ops != &arm_smmu_ops) {
                dev_err(dev, "cannot attach to SMMU, is it on the same bus?\n");
@@ -1177,10 +1177,11 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
         * domains, just say no (but more politely than by dereferencing NULL).
         * This should be at least a WARN_ON once that's sorted.
         */
-       if (!fwspec->iommu_priv)
+       cfg = dev_iommu_priv_get(dev);
+       if (!cfg)
                return -ENODEV;
 
-       smmu = fwspec_smmu(fwspec);
+       smmu = cfg->smmu;
 
        ret = arm_smmu_rpm_get(smmu);
        if (ret < 0)
@@ -1204,7 +1205,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
        }
 
        /* Looks ok, so add the device to the domain */
-       ret = arm_smmu_domain_add_master(smmu_domain, fwspec);
+       ret = arm_smmu_domain_add_master(smmu_domain, cfg, fwspec);
 
        /*
         * Setup an autosuspend delay to avoid bouncing runpm state.
@@ -1383,7 +1384,7 @@ struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
 
 static int arm_smmu_add_device(struct device *dev)
 {
-       struct arm_smmu_device *smmu;
+       struct arm_smmu_device *smmu = NULL;
        struct arm_smmu_master_cfg *cfg;
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
        int i, ret;
@@ -1429,7 +1430,7 @@ static int arm_smmu_add_device(struct device *dev)
                goto out_free;
 
        cfg->smmu = smmu;
-       fwspec->iommu_priv = cfg;
+       dev_iommu_priv_set(dev, cfg);
        while (i--)
                cfg->smendx[i] = INVALID_SMENDX;
 
@@ -1467,7 +1468,7 @@ static void arm_smmu_remove_device(struct device *dev)
        if (!fwspec || fwspec->ops != &arm_smmu_ops)
                return;
 
-       cfg  = fwspec->iommu_priv;
+       cfg  = dev_iommu_priv_get(dev);
        smmu = cfg->smmu;
 
        ret = arm_smmu_rpm_get(smmu);
@@ -1475,23 +1476,25 @@ static void arm_smmu_remove_device(struct device *dev)
                return;
 
        iommu_device_unlink(&smmu->iommu, dev);
-       arm_smmu_master_free_smes(fwspec);
+       arm_smmu_master_free_smes(cfg, fwspec);
 
        arm_smmu_rpm_put(smmu);
 
+       dev_iommu_priv_set(dev, NULL);
        iommu_group_remove_device(dev);
-       kfree(fwspec->iommu_priv);
+       kfree(cfg);
        iommu_fwspec_free(dev);
 }
 
 static struct iommu_group *arm_smmu_device_group(struct device *dev)
 {
+       struct arm_smmu_master_cfg *cfg = dev_iommu_priv_get(dev);
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-       struct arm_smmu_device *smmu = fwspec_smmu(fwspec);
+       struct arm_smmu_device *smmu = cfg->smmu;
        struct iommu_group *group = NULL;
        int i, idx;
 
-       for_each_cfg_sme(fwspec, i, idx) {
+       for_each_cfg_sme(cfg, fwspec, i, idx) {
                if (group && smmu->s2crs[idx].group &&
                    group != smmu->s2crs[idx].group)
                        return ERR_PTR(-EINVAL);
index 4be5494..ef0a524 100644 (file)
@@ -4501,7 +4501,8 @@ static struct dmar_atsr_unit *dmar_find_atsr(struct acpi_dmar_atsr *atsr)
        struct dmar_atsr_unit *atsru;
        struct acpi_dmar_atsr *tmp;
 
-       list_for_each_entry_rcu(atsru, &dmar_atsr_units, list) {
+       list_for_each_entry_rcu(atsru, &dmar_atsr_units, list,
+                               dmar_rcu_check()) {
                tmp = (struct acpi_dmar_atsr *)atsru->hdr;
                if (atsr->segment != tmp->segment)
                        continue;
index d7f2a53..2998418 100644 (file)
@@ -531,7 +531,7 @@ struct page_req_dsc {
        u64 priv_data[2];
 };
 
-#define PRQ_RING_MASK ((0x1000 << PRQ_ORDER) - 0x10)
+#define PRQ_RING_MASK  ((0x1000 << PRQ_ORDER) - 0x20)
 
 static bool access_error(struct vm_area_struct *vma, struct page_req_dsc *req)
 {
@@ -611,14 +611,15 @@ static irqreturn_t prq_event_thread(int irq, void *d)
                 * any faults on kernel addresses. */
                if (!svm->mm)
                        goto bad_req;
-               /* If the mm is already defunct, don't handle faults. */
-               if (!mmget_not_zero(svm->mm))
-                       goto bad_req;
 
                /* If address is not canonical, return invalid response */
                if (!is_canonical_address(address))
                        goto bad_req;
 
+               /* If the mm is already defunct, don't handle faults. */
+               if (!mmget_not_zero(svm->mm))
+                       goto bad_req;
+
                down_read(&svm->mm->mmap_sem);
                vma = find_extend_vma(svm->mm, address);
                if (!vma || address < vma->vm_start)
index 3e35284..2b47141 100644 (file)
@@ -152,9 +152,9 @@ void iommu_device_unregister(struct iommu_device *iommu)
 }
 EXPORT_SYMBOL_GPL(iommu_device_unregister);
 
-static struct iommu_param *iommu_get_dev_param(struct device *dev)
+static struct dev_iommu *dev_iommu_get(struct device *dev)
 {
-       struct iommu_param *param = dev->iommu_param;
+       struct dev_iommu *param = dev->iommu;
 
        if (param)
                return param;
@@ -164,14 +164,14 @@ static struct iommu_param *iommu_get_dev_param(struct device *dev)
                return NULL;
 
        mutex_init(&param->lock);
-       dev->iommu_param = param;
+       dev->iommu = param;
        return param;
 }
 
-static void iommu_free_dev_param(struct device *dev)
+static void dev_iommu_free(struct device *dev)
 {
-       kfree(dev->iommu_param);
-       dev->iommu_param = NULL;
+       kfree(dev->iommu);
+       dev->iommu = NULL;
 }
 
 int iommu_probe_device(struct device *dev)
@@ -183,7 +183,7 @@ int iommu_probe_device(struct device *dev)
        if (!ops)
                return -EINVAL;
 
-       if (!iommu_get_dev_param(dev))
+       if (!dev_iommu_get(dev))
                return -ENOMEM;
 
        if (!try_module_get(ops->owner)) {
@@ -200,7 +200,7 @@ int iommu_probe_device(struct device *dev)
 err_module_put:
        module_put(ops->owner);
 err_free_dev_param:
-       iommu_free_dev_param(dev);
+       dev_iommu_free(dev);
        return ret;
 }
 
@@ -211,9 +211,9 @@ void iommu_release_device(struct device *dev)
        if (dev->iommu_group)
                ops->remove_device(dev);
 
-       if (dev->iommu_param) {
+       if (dev->iommu) {
                module_put(ops->owner);
-               iommu_free_dev_param(dev);
+               dev_iommu_free(dev);
        }
 }
 
@@ -972,7 +972,7 @@ int iommu_register_device_fault_handler(struct device *dev,
                                        iommu_dev_fault_handler_t handler,
                                        void *data)
 {
-       struct iommu_param *param = dev->iommu_param;
+       struct dev_iommu *param = dev->iommu;
        int ret = 0;
 
        if (!param)
@@ -1015,7 +1015,7 @@ EXPORT_SYMBOL_GPL(iommu_register_device_fault_handler);
  */
 int iommu_unregister_device_fault_handler(struct device *dev)
 {
-       struct iommu_param *param = dev->iommu_param;
+       struct dev_iommu *param = dev->iommu;
        int ret = 0;
 
        if (!param)
@@ -1055,7 +1055,7 @@ EXPORT_SYMBOL_GPL(iommu_unregister_device_fault_handler);
  */
 int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt)
 {
-       struct iommu_param *param = dev->iommu_param;
+       struct dev_iommu *param = dev->iommu;
        struct iommu_fault_event *evt_pending = NULL;
        struct iommu_fault_param *fparam;
        int ret = 0;
@@ -1104,7 +1104,7 @@ int iommu_page_response(struct device *dev,
        int ret = -EINVAL;
        struct iommu_fault_event *evt;
        struct iommu_fault_page_request *prm;
-       struct iommu_param *param = dev->iommu_param;
+       struct dev_iommu *param = dev->iommu;
        struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
 
        if (!domain || !domain->ops->page_response)
@@ -2405,7 +2405,11 @@ int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
        if (fwspec)
                return ops == fwspec->ops ? 0 : -EINVAL;
 
-       fwspec = kzalloc(sizeof(*fwspec), GFP_KERNEL);
+       if (!dev_iommu_get(dev))
+               return -ENOMEM;
+
+       /* Preallocate for the overwhelmingly common case of 1 ID */
+       fwspec = kzalloc(struct_size(fwspec, ids, 1), GFP_KERNEL);
        if (!fwspec)
                return -ENOMEM;
 
@@ -2432,15 +2436,15 @@ EXPORT_SYMBOL_GPL(iommu_fwspec_free);
 int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
 {
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-       size_t size;
-       int i;
+       int i, new_num;
 
        if (!fwspec)
                return -EINVAL;
 
-       size = offsetof(struct iommu_fwspec, ids[fwspec->num_ids + num_ids]);
-       if (size > sizeof(*fwspec)) {
-               fwspec = krealloc(fwspec, size, GFP_KERNEL);
+       new_num = fwspec->num_ids + num_ids;
+       if (new_num > 1) {
+               fwspec = krealloc(fwspec, struct_size(fwspec, ids, new_num),
+                                 GFP_KERNEL);
                if (!fwspec)
                        return -ENOMEM;
 
@@ -2450,7 +2454,7 @@ int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
        for (i = 0; i < num_ids; i++)
                fwspec->ids[fwspec->num_ids + i] = ids[i];
 
-       fwspec->num_ids += num_ids;
+       fwspec->num_ids = new_num;
        return 0;
 }
 EXPORT_SYMBOL_GPL(iommu_fwspec_add_ids);
index ecb3f94..310cf09 100644 (file)
@@ -89,9 +89,7 @@ static struct ipmmu_vmsa_domain *to_vmsa_domain(struct iommu_domain *dom)
 
 static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev)
 {
-       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-
-       return fwspec ? fwspec->iommu_priv : NULL;
+       return dev_iommu_priv_get(dev);
 }
 
 #define TLB_LOOP_TIMEOUT               100     /* 100us */
@@ -727,14 +725,13 @@ static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain,
 static int ipmmu_init_platform_device(struct device *dev,
                                      struct of_phandle_args *args)
 {
-       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
        struct platform_device *ipmmu_pdev;
 
        ipmmu_pdev = of_find_device_by_node(args->np);
        if (!ipmmu_pdev)
                return -ENODEV;
 
-       fwspec->iommu_priv = platform_get_drvdata(ipmmu_pdev);
+       dev_iommu_priv_set(dev, platform_get_drvdata(ipmmu_pdev));
 
        return 0;
 }
index 95945f4..5f4d6df 100644 (file)
@@ -358,8 +358,8 @@ static void mtk_iommu_domain_free(struct iommu_domain *domain)
 static int mtk_iommu_attach_device(struct iommu_domain *domain,
                                   struct device *dev)
 {
+       struct mtk_iommu_data *data = dev_iommu_priv_get(dev);
        struct mtk_iommu_domain *dom = to_mtk_domain(domain);
-       struct mtk_iommu_data *data = dev_iommu_fwspec_get(dev)->iommu_priv;
 
        if (!data)
                return -ENODEV;
@@ -378,7 +378,7 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain,
 static void mtk_iommu_detach_device(struct iommu_domain *domain,
                                    struct device *dev)
 {
-       struct mtk_iommu_data *data = dev_iommu_fwspec_get(dev)->iommu_priv;
+       struct mtk_iommu_data *data = dev_iommu_priv_get(dev);
 
        if (!data)
                return;
@@ -450,7 +450,7 @@ static int mtk_iommu_add_device(struct device *dev)
        if (!fwspec || fwspec->ops != &mtk_iommu_ops)
                return -ENODEV; /* Not a iommu client device */
 
-       data = fwspec->iommu_priv;
+       data = dev_iommu_priv_get(dev);
        iommu_device_link(&data->iommu, dev);
 
        group = iommu_group_get_for_dev(dev);
@@ -469,7 +469,7 @@ static void mtk_iommu_remove_device(struct device *dev)
        if (!fwspec || fwspec->ops != &mtk_iommu_ops)
                return;
 
-       data = fwspec->iommu_priv;
+       data = dev_iommu_priv_get(dev);
        iommu_device_unlink(&data->iommu, dev);
 
        iommu_group_remove_device(dev);
@@ -496,7 +496,6 @@ static struct iommu_group *mtk_iommu_device_group(struct device *dev)
 
 static int mtk_iommu_of_xlate(struct device *dev, struct of_phandle_args *args)
 {
-       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
        struct platform_device *m4updev;
 
        if (args->args_count != 1) {
@@ -505,13 +504,13 @@ static int mtk_iommu_of_xlate(struct device *dev, struct of_phandle_args *args)
                return -EINVAL;
        }
 
-       if (!fwspec->iommu_priv) {
+       if (!dev_iommu_priv_get(dev)) {
                /* Get the m4u device */
                m4updev = of_find_device_by_node(args->np);
                if (WARN_ON(!m4updev))
                        return -EINVAL;
 
-               fwspec->iommu_priv = platform_get_drvdata(m4updev);
+               dev_iommu_priv_set(dev, platform_get_drvdata(m4updev));
        }
 
        return iommu_fwspec_add_ids(dev, args->args, 1);
index e93b94e..a31be05 100644 (file)
@@ -263,8 +263,8 @@ static void mtk_iommu_domain_free(struct iommu_domain *domain)
 static int mtk_iommu_attach_device(struct iommu_domain *domain,
                                   struct device *dev)
 {
+       struct mtk_iommu_data *data = dev_iommu_priv_get(dev);
        struct mtk_iommu_domain *dom = to_mtk_domain(domain);
-       struct mtk_iommu_data *data = dev_iommu_fwspec_get(dev)->iommu_priv;
        int ret;
 
        if (!data)
@@ -286,7 +286,7 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain,
 static void mtk_iommu_detach_device(struct iommu_domain *domain,
                                    struct device *dev)
 {
-       struct mtk_iommu_data *data = dev_iommu_fwspec_get(dev)->iommu_priv;
+       struct mtk_iommu_data *data = dev_iommu_priv_get(dev);
 
        if (!data)
                return;
@@ -387,20 +387,20 @@ static int mtk_iommu_create_mapping(struct device *dev,
                return -EINVAL;
        }
 
-       if (!fwspec->iommu_priv) {
+       if (!dev_iommu_priv_get(dev)) {
                /* Get the m4u device */
                m4updev = of_find_device_by_node(args->np);
                if (WARN_ON(!m4updev))
                        return -EINVAL;
 
-               fwspec->iommu_priv = platform_get_drvdata(m4updev);
+               dev_iommu_priv_set(dev, platform_get_drvdata(m4updev));
        }
 
        ret = iommu_fwspec_add_ids(dev, args->args, 1);
        if (ret)
                return ret;
 
-       data = fwspec->iommu_priv;
+       data = dev_iommu_priv_get(dev);
        m4udev = data->dev;
        mtk_mapping = m4udev->archdata.iommu;
        if (!mtk_mapping) {
@@ -459,7 +459,7 @@ static int mtk_iommu_add_device(struct device *dev)
        if (err)
                return err;
 
-       data = fwspec->iommu_priv;
+       data = dev_iommu_priv_get(dev);
        mtk_mapping = data->dev->archdata.iommu;
        err = arm_iommu_attach_device(dev, mtk_mapping);
        if (err) {
@@ -478,7 +478,7 @@ static void mtk_iommu_remove_device(struct device *dev)
        if (!fwspec || fwspec->ops != &mtk_iommu_ops)
                return;
 
-       data = fwspec->iommu_priv;
+       data = dev_iommu_priv_get(dev);
        iommu_device_unlink(&data->iommu, dev);
 
        iommu_group_remove_device(dev);
index be551cc..887fefc 100644 (file)
@@ -167,7 +167,7 @@ static int omap2_iommu_enable(struct omap_iommu *obj)
 {
        u32 l, pa;
 
-       if (!obj->iopgd || !IS_ALIGNED((u32)obj->iopgd,  SZ_16K))
+       if (!obj->iopgd || !IS_ALIGNED((unsigned long)obj->iopgd,  SZ_16K))
                return -EINVAL;
 
        pa = virt_to_phys(obj->iopgd);
@@ -434,7 +434,7 @@ static void flush_iotlb_page(struct omap_iommu *obj, u32 da)
                bytes = iopgsz_to_bytes(cr.cam & 3);
 
                if ((start <= da) && (da < start + bytes)) {
-                       dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n",
+                       dev_dbg(obj->dev, "%s: %08x<=%08x(%zx)\n",
                                __func__, start, da, bytes);
                        iotlb_load_cr(obj, &cr);
                        iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
@@ -1352,11 +1352,11 @@ static int omap_iommu_map(struct iommu_domain *domain, unsigned long da,
 
        omap_pgsz = bytes_to_iopgsz(bytes);
        if (omap_pgsz < 0) {
-               dev_err(dev, "invalid size to map: %d\n", bytes);
+               dev_err(dev, "invalid size to map: %zu\n", bytes);
                return -EINVAL;
        }
 
-       dev_dbg(dev, "mapping da 0x%lx to pa %pa size 0x%x\n", da, &pa, bytes);
+       dev_dbg(dev, "mapping da 0x%lx to pa %pa size 0x%zx\n", da, &pa, bytes);
 
        iotlb_init_entry(&e, da, pa, omap_pgsz);
 
@@ -1393,7 +1393,7 @@ static size_t omap_iommu_unmap(struct iommu_domain *domain, unsigned long da,
        size_t bytes = 0;
        int i;
 
-       dev_dbg(dev, "unmapping da 0x%lx size %u\n", da, size);
+       dev_dbg(dev, "unmapping da 0x%lx size %zu\n", da, size);
 
        iommu = omap_domain->iommus;
        for (i = 0; i < omap_domain->num_iommus; i++, iommu++) {
index 1a4adb5..51d7400 100644 (file)
@@ -63,7 +63,8 @@
  *
  * va to pa translation
  */
-static inline phys_addr_t omap_iommu_translate(u32 d, u32 va, u32 mask)
+static inline phys_addr_t omap_iommu_translate(unsigned long d, dma_addr_t va,
+                                              dma_addr_t mask)
 {
        return (d & mask) | (va & (~mask));
 }
index 4328da0..0e2a964 100644 (file)
@@ -48,7 +48,7 @@ struct qcom_iommu_dev {
        void __iomem            *local_base;
        u32                      sec_id;
        u8                       num_ctxs;
-       struct qcom_iommu_ctx   *ctxs[0];   /* indexed by asid-1 */
+       struct qcom_iommu_ctx   *ctxs[];   /* indexed by asid-1 */
 };
 
 struct qcom_iommu_ctx {
@@ -74,16 +74,19 @@ static struct qcom_iommu_domain *to_qcom_iommu_domain(struct iommu_domain *dom)
 
 static const struct iommu_ops qcom_iommu_ops;
 
-static struct qcom_iommu_dev * to_iommu(struct iommu_fwspec *fwspec)
+static struct qcom_iommu_dev * to_iommu(struct device *dev)
 {
+       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+
        if (!fwspec || fwspec->ops != &qcom_iommu_ops)
                return NULL;
-       return fwspec->iommu_priv;
+
+       return dev_iommu_priv_get(dev);
 }
 
-static struct qcom_iommu_ctx * to_ctx(struct iommu_fwspec *fwspec, unsigned asid)
+static struct qcom_iommu_ctx * to_ctx(struct device *dev, unsigned asid)
 {
-       struct qcom_iommu_dev *qcom_iommu = to_iommu(fwspec);
+       struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
        if (!qcom_iommu)
                return NULL;
        return qcom_iommu->ctxs[asid - 1];
@@ -115,11 +118,14 @@ iommu_readq(struct qcom_iommu_ctx *ctx, unsigned reg)
 
 static void qcom_iommu_tlb_sync(void *cookie)
 {
-       struct iommu_fwspec *fwspec = cookie;
+       struct iommu_fwspec *fwspec;
+       struct device *dev = cookie;
        unsigned i;
 
+       fwspec = dev_iommu_fwspec_get(dev);
+
        for (i = 0; i < fwspec->num_ids; i++) {
-               struct qcom_iommu_ctx *ctx = to_ctx(fwspec, fwspec->ids[i]);
+               struct qcom_iommu_ctx *ctx = to_ctx(dev, fwspec->ids[i]);
                unsigned int val, ret;
 
                iommu_writel(ctx, ARM_SMMU_CB_TLBSYNC, 0);
@@ -133,11 +139,14 @@ static void qcom_iommu_tlb_sync(void *cookie)
 
 static void qcom_iommu_tlb_inv_context(void *cookie)
 {
-       struct iommu_fwspec *fwspec = cookie;
+       struct device *dev = cookie;
+       struct iommu_fwspec *fwspec;
        unsigned i;
 
+       fwspec = dev_iommu_fwspec_get(dev);
+
        for (i = 0; i < fwspec->num_ids; i++) {
-               struct qcom_iommu_ctx *ctx = to_ctx(fwspec, fwspec->ids[i]);
+               struct qcom_iommu_ctx *ctx = to_ctx(dev, fwspec->ids[i]);
                iommu_writel(ctx, ARM_SMMU_CB_S1_TLBIASID, ctx->asid);
        }
 
@@ -147,13 +156,16 @@ static void qcom_iommu_tlb_inv_context(void *cookie)
 static void qcom_iommu_tlb_inv_range_nosync(unsigned long iova, size_t size,
                                            size_t granule, bool leaf, void *cookie)
 {
-       struct iommu_fwspec *fwspec = cookie;
+       struct device *dev = cookie;
+       struct iommu_fwspec *fwspec;
        unsigned i, reg;
 
        reg = leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA;
 
+       fwspec = dev_iommu_fwspec_get(dev);
+
        for (i = 0; i < fwspec->num_ids; i++) {
-               struct qcom_iommu_ctx *ctx = to_ctx(fwspec, fwspec->ids[i]);
+               struct qcom_iommu_ctx *ctx = to_ctx(dev, fwspec->ids[i]);
                size_t s = size;
 
                iova = (iova >> 12) << 12;
@@ -222,9 +234,10 @@ static irqreturn_t qcom_iommu_fault(int irq, void *dev)
 
 static int qcom_iommu_init_domain(struct iommu_domain *domain,
                                  struct qcom_iommu_dev *qcom_iommu,
-                                 struct iommu_fwspec *fwspec)
+                                 struct device *dev)
 {
        struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
+       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
        struct io_pgtable_ops *pgtbl_ops;
        struct io_pgtable_cfg pgtbl_cfg;
        int i, ret = 0;
@@ -243,7 +256,7 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
        };
 
        qcom_domain->iommu = qcom_iommu;
-       pgtbl_ops = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &pgtbl_cfg, fwspec);
+       pgtbl_ops = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &pgtbl_cfg, dev);
        if (!pgtbl_ops) {
                dev_err(qcom_iommu->dev, "failed to allocate pagetable ops\n");
                ret = -ENOMEM;
@@ -256,7 +269,7 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
        domain->geometry.force_aperture = true;
 
        for (i = 0; i < fwspec->num_ids; i++) {
-               struct qcom_iommu_ctx *ctx = to_ctx(fwspec, fwspec->ids[i]);
+               struct qcom_iommu_ctx *ctx = to_ctx(dev, fwspec->ids[i]);
 
                if (!ctx->secure_init) {
                        ret = qcom_scm_restore_sec_cfg(qcom_iommu->sec_id, ctx->asid);
@@ -363,8 +376,7 @@ static void qcom_iommu_domain_free(struct iommu_domain *domain)
 
 static int qcom_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
 {
-       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-       struct qcom_iommu_dev *qcom_iommu = to_iommu(fwspec);
+       struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
        struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
        int ret;
 
@@ -375,7 +387,7 @@ static int qcom_iommu_attach_dev(struct iommu_domain *domain, struct device *dev
 
        /* Ensure that the domain is finalized */
        pm_runtime_get_sync(qcom_iommu->dev);
-       ret = qcom_iommu_init_domain(domain, qcom_iommu, fwspec);
+       ret = qcom_iommu_init_domain(domain, qcom_iommu, dev);
        pm_runtime_put_sync(qcom_iommu->dev);
        if (ret < 0)
                return ret;
@@ -397,9 +409,9 @@ static int qcom_iommu_attach_dev(struct iommu_domain *domain, struct device *dev
 
 static void qcom_iommu_detach_dev(struct iommu_domain *domain, struct device *dev)
 {
-       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-       struct qcom_iommu_dev *qcom_iommu = to_iommu(fwspec);
        struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
+       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+       struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
        unsigned i;
 
        if (WARN_ON(!qcom_domain->iommu))
@@ -407,7 +419,7 @@ static void qcom_iommu_detach_dev(struct iommu_domain *domain, struct device *de
 
        pm_runtime_get_sync(qcom_iommu->dev);
        for (i = 0; i < fwspec->num_ids; i++) {
-               struct qcom_iommu_ctx *ctx = to_ctx(fwspec, fwspec->ids[i]);
+               struct qcom_iommu_ctx *ctx = to_ctx(dev, fwspec->ids[i]);
 
                /* Disable the context bank: */
                iommu_writel(ctx, ARM_SMMU_CB_SCTLR, 0);
@@ -514,7 +526,7 @@ static bool qcom_iommu_capable(enum iommu_cap cap)
 
 static int qcom_iommu_add_device(struct device *dev)
 {
-       struct qcom_iommu_dev *qcom_iommu = to_iommu(dev_iommu_fwspec_get(dev));
+       struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
        struct iommu_group *group;
        struct device_link *link;
 
@@ -545,7 +557,7 @@ static int qcom_iommu_add_device(struct device *dev)
 
 static void qcom_iommu_remove_device(struct device *dev)
 {
-       struct qcom_iommu_dev *qcom_iommu = to_iommu(dev_iommu_fwspec_get(dev));
+       struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
 
        if (!qcom_iommu)
                return;
@@ -557,7 +569,6 @@ static void qcom_iommu_remove_device(struct device *dev)
 
 static int qcom_iommu_of_xlate(struct device *dev, struct of_phandle_args *args)
 {
-       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
        struct qcom_iommu_dev *qcom_iommu;
        struct platform_device *iommu_pdev;
        unsigned asid = args->args[0];
@@ -583,14 +594,14 @@ static int qcom_iommu_of_xlate(struct device *dev, struct of_phandle_args *args)
            WARN_ON(asid > qcom_iommu->num_ctxs))
                return -EINVAL;
 
-       if (!fwspec->iommu_priv) {
-               fwspec->iommu_priv = qcom_iommu;
+       if (!dev_iommu_priv_get(dev)) {
+               dev_iommu_priv_set(dev, qcom_iommu);
        } else {
                /* make sure devices iommus dt node isn't referring to
                 * multiple different iommu devices.  Multiple context
                 * banks are ok, but multiple devices are not:
                 */
-               if (WARN_ON(qcom_iommu != fwspec->iommu_priv))
+               if (WARN_ON(qcom_iommu != dev_iommu_priv_get(dev)))
                        return -EINVAL;
        }
 
index 3fb7ba7..db6559e 100644 (file)
@@ -247,7 +247,7 @@ static int gart_iommu_add_device(struct device *dev)
 {
        struct iommu_group *group;
 
-       if (!dev->iommu_fwspec)
+       if (!dev_iommu_fwspec_get(dev))
                return -ENODEV;
 
        group = iommu_group_get_for_dev(dev);
index cce329d..d5cac4f 100644 (file)
@@ -466,7 +466,7 @@ static int viommu_probe_endpoint(struct viommu_dev *viommu, struct device *dev)
        struct virtio_iommu_req_probe *probe;
        struct virtio_iommu_probe_property *prop;
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-       struct viommu_endpoint *vdev = fwspec->iommu_priv;
+       struct viommu_endpoint *vdev = dev_iommu_priv_get(dev);
 
        if (!fwspec->num_ids)
                return -EINVAL;
@@ -607,24 +607,36 @@ static struct iommu_domain *viommu_domain_alloc(unsigned type)
        return &vdomain->domain;
 }
 
-static int viommu_domain_finalise(struct viommu_dev *viommu,
+static int viommu_domain_finalise(struct viommu_endpoint *vdev,
                                  struct iommu_domain *domain)
 {
        int ret;
+       unsigned long viommu_page_size;
+       struct viommu_dev *viommu = vdev->viommu;
        struct viommu_domain *vdomain = to_viommu_domain(domain);
 
-       vdomain->viommu         = viommu;
-       vdomain->map_flags      = viommu->map_flags;
+       viommu_page_size = 1UL << __ffs(viommu->pgsize_bitmap);
+       if (viommu_page_size > PAGE_SIZE) {
+               dev_err(vdev->dev,
+                       "granule 0x%lx larger than system page size 0x%lx\n",
+                       viommu_page_size, PAGE_SIZE);
+               return -EINVAL;
+       }
+
+       ret = ida_alloc_range(&viommu->domain_ids, viommu->first_domain,
+                             viommu->last_domain, GFP_KERNEL);
+       if (ret < 0)
+               return ret;
+
+       vdomain->id             = (unsigned int)ret;
 
        domain->pgsize_bitmap   = viommu->pgsize_bitmap;
        domain->geometry        = viommu->geometry;
 
-       ret = ida_alloc_range(&viommu->domain_ids, viommu->first_domain,
-                             viommu->last_domain, GFP_KERNEL);
-       if (ret >= 0)
-               vdomain->id = (unsigned int)ret;
+       vdomain->map_flags      = viommu->map_flags;
+       vdomain->viommu         = viommu;
 
-       return ret > 0 ? 0 : ret;
+       return 0;
 }
 
 static void viommu_domain_free(struct iommu_domain *domain)
@@ -648,7 +660,7 @@ static int viommu_attach_dev(struct iommu_domain *domain, struct device *dev)
        int ret = 0;
        struct virtio_iommu_req_attach req;
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-       struct viommu_endpoint *vdev = fwspec->iommu_priv;
+       struct viommu_endpoint *vdev = dev_iommu_priv_get(dev);
        struct viommu_domain *vdomain = to_viommu_domain(domain);
 
        mutex_lock(&vdomain->mutex);
@@ -657,7 +669,7 @@ static int viommu_attach_dev(struct iommu_domain *domain, struct device *dev)
                 * Properly initialize the domain now that we know which viommu
                 * owns it.
                 */
-               ret = viommu_domain_finalise(vdev->viommu, domain);
+               ret = viommu_domain_finalise(vdev, domain);
        } else if (vdomain->viommu != vdev->viommu) {
                dev_err(dev, "cannot attach to foreign vIOMMU\n");
                ret = -EXDEV;
@@ -807,8 +819,7 @@ static void viommu_iotlb_sync(struct iommu_domain *domain,
 static void viommu_get_resv_regions(struct device *dev, struct list_head *head)
 {
        struct iommu_resv_region *entry, *new_entry, *msi = NULL;
-       struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-       struct viommu_endpoint *vdev = fwspec->iommu_priv;
+       struct viommu_endpoint *vdev = dev_iommu_priv_get(dev);
        int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
 
        list_for_each_entry(entry, &vdev->resv_regions, list) {
@@ -876,7 +887,7 @@ static int viommu_add_device(struct device *dev)
        vdev->dev = dev;
        vdev->viommu = viommu;
        INIT_LIST_HEAD(&vdev->resv_regions);
-       fwspec->iommu_priv = vdev;
+       dev_iommu_priv_set(dev, vdev);
 
        if (viommu->probe_size) {
                /* Get additional information for this endpoint */
@@ -920,7 +931,7 @@ static void viommu_remove_device(struct device *dev)
        if (!fwspec || fwspec->ops != &viommu_ops)
                return;
 
-       vdev = fwspec->iommu_priv;
+       vdev = dev_iommu_priv_get(dev);
 
        iommu_group_remove_device(dev);
        iommu_device_unlink(&vdev->viommu->iommu, dev);
@@ -1082,7 +1093,6 @@ static int viommu_probe(struct virtio_device *vdev)
 
 #ifdef CONFIG_PCI
        if (pci_bus_type.iommu_ops != &viommu_ops) {
-               pci_request_acs();
                ret = bus_set_iommu(&pci_bus_type, &viommu_ops);
                if (ret)
                        goto err_unregister;
index d82f1de..c664d84 100644 (file)
@@ -846,6 +846,17 @@ config LEDS_TPS6105X
          It is a single boost converter primarily for white LEDs and
          audio amplifiers.
 
+config LEDS_IP30
+       tristate "LED support for SGI Octane machines"
+       depends on LEDS_CLASS
+       depends on SGI_MFD_IOC3
+       help
+         This option enables support for the Red and White LEDs of
+         SGI Octane machines.
+
+         To compile this driver as a module, choose M here: the module
+         will be called leds-ip30.
+
 comment "LED Triggers"
 source "drivers/leds/trigger/Kconfig"
 
index d7e1107..45235d5 100644 (file)
@@ -6,91 +6,92 @@ obj-$(CONFIG_LEDS_CLASS)              += led-class.o
 obj-$(CONFIG_LEDS_CLASS_FLASH)         += led-class-flash.o
 obj-$(CONFIG_LEDS_TRIGGERS)            += led-triggers.o
 
-# LED Platform Drivers
+# LED Platform Drivers (keep this sorted, M-| sort)
 obj-$(CONFIG_LEDS_88PM860X)            += leds-88pm860x.o
 obj-$(CONFIG_LEDS_AAT1290)             += leds-aat1290.o
+obj-$(CONFIG_LEDS_ADP5520)             += leds-adp5520.o
+obj-$(CONFIG_LEDS_AN30259A)            += leds-an30259a.o
 obj-$(CONFIG_LEDS_APU)                 += leds-apu.o
 obj-$(CONFIG_LEDS_AS3645A)             += leds-as3645a.o
-obj-$(CONFIG_LEDS_AN30259A)            += leds-an30259a.o
+obj-$(CONFIG_LEDS_ASIC3)               += leds-asic3.o
 obj-$(CONFIG_LEDS_BCM6328)             += leds-bcm6328.o
 obj-$(CONFIG_LEDS_BCM6358)             += leds-bcm6358.o
 obj-$(CONFIG_LEDS_BD2802)              += leds-bd2802.o
+obj-$(CONFIG_LEDS_BLINKM)              += leds-blinkm.o
+obj-$(CONFIG_LEDS_CLEVO_MAIL)          += leds-clevo-mail.o
+obj-$(CONFIG_LEDS_COBALT_QUBE)         += leds-cobalt-qube.o
+obj-$(CONFIG_LEDS_COBALT_RAQ)          += leds-cobalt-raq.o
 obj-$(CONFIG_LEDS_CPCAP)               += leds-cpcap.o
-obj-$(CONFIG_LEDS_LOCOMO)              += leds-locomo.o
+obj-$(CONFIG_LEDS_DA903X)              += leds-da903x.o
+obj-$(CONFIG_LEDS_DA9052)              += leds-da9052.o
+obj-$(CONFIG_LEDS_FSG)                 += leds-fsg.o
+obj-$(CONFIG_LEDS_GPIO)                        += leds-gpio.o
+obj-$(CONFIG_LEDS_GPIO_REGISTER)       += leds-gpio-register.o
+obj-$(CONFIG_LEDS_HP6XX)               += leds-hp6xx.o
+obj-$(CONFIG_LEDS_INTEL_SS4200)                += leds-ss4200.o
+obj-$(CONFIG_LEDS_IP30)                        += leds-ip30.o
+obj-$(CONFIG_LEDS_IPAQ_MICRO)          += leds-ipaq-micro.o
+obj-$(CONFIG_LEDS_IS31FL319X)          += leds-is31fl319x.o
+obj-$(CONFIG_LEDS_IS31FL32XX)          += leds-is31fl32xx.o
+obj-$(CONFIG_LEDS_KTD2692)             += leds-ktd2692.o
 obj-$(CONFIG_LEDS_LM3530)              += leds-lm3530.o
 obj-$(CONFIG_LEDS_LM3532)              += leds-lm3532.o
 obj-$(CONFIG_LEDS_LM3533)              += leds-lm3533.o
+obj-$(CONFIG_LEDS_LM355x)              += leds-lm355x.o
+obj-$(CONFIG_LEDS_LM3601X)             += leds-lm3601x.o
+obj-$(CONFIG_LEDS_LM36274)             += leds-lm36274.o
 obj-$(CONFIG_LEDS_LM3642)              += leds-lm3642.o
-obj-$(CONFIG_LEDS_MIKROTIK_RB532)      += leds-rb532.o
-obj-$(CONFIG_LEDS_S3C24XX)             += leds-s3c24xx.o
-obj-$(CONFIG_LEDS_NET48XX)             += leds-net48xx.o
-obj-$(CONFIG_LEDS_WRAP)                        += leds-wrap.o
-obj-$(CONFIG_LEDS_COBALT_QUBE)         += leds-cobalt-qube.o
-obj-$(CONFIG_LEDS_COBALT_RAQ)          += leds-cobalt-raq.o
-obj-$(CONFIG_LEDS_SUNFIRE)             += leds-sunfire.o
-obj-$(CONFIG_LEDS_PCA9532)             += leds-pca9532.o
-obj-$(CONFIG_LEDS_GPIO_REGISTER)       += leds-gpio-register.o
-obj-$(CONFIG_LEDS_GPIO)                        += leds-gpio.o
+obj-$(CONFIG_LEDS_LM3692X)             += leds-lm3692x.o
+obj-$(CONFIG_LEDS_LM3697)              += leds-lm3697.o
+obj-$(CONFIG_LEDS_LOCOMO)              += leds-locomo.o
 obj-$(CONFIG_LEDS_LP3944)              += leds-lp3944.o
 obj-$(CONFIG_LEDS_LP3952)              += leds-lp3952.o
-obj-$(CONFIG_LEDS_LP55XX_COMMON)       += leds-lp55xx-common.o
 obj-$(CONFIG_LEDS_LP5521)              += leds-lp5521.o
 obj-$(CONFIG_LEDS_LP5523)              += leds-lp5523.o
 obj-$(CONFIG_LEDS_LP5562)              += leds-lp5562.o
+obj-$(CONFIG_LEDS_LP55XX_COMMON)       += leds-lp55xx-common.o
 obj-$(CONFIG_LEDS_LP8501)              += leds-lp8501.o
 obj-$(CONFIG_LEDS_LP8788)              += leds-lp8788.o
 obj-$(CONFIG_LEDS_LP8860)              += leds-lp8860.o
-obj-$(CONFIG_LEDS_TCA6507)             += leds-tca6507.o
-obj-$(CONFIG_LEDS_TLC591XX)            += leds-tlc591xx.o
-obj-$(CONFIG_LEDS_CLEVO_MAIL)          += leds-clevo-mail.o
-obj-$(CONFIG_LEDS_IPAQ_MICRO)          += leds-ipaq-micro.o
-obj-$(CONFIG_LEDS_HP6XX)               += leds-hp6xx.o
-obj-$(CONFIG_LEDS_OT200)               += leds-ot200.o
-obj-$(CONFIG_LEDS_FSG)                 += leds-fsg.o
-obj-$(CONFIG_LEDS_PCA955X)             += leds-pca955x.o
-obj-$(CONFIG_LEDS_PCA963X)             += leds-pca963x.o
-obj-$(CONFIG_LEDS_DA903X)              += leds-da903x.o
-obj-$(CONFIG_LEDS_DA9052)              += leds-da9052.o
-obj-$(CONFIG_LEDS_WM831X_STATUS)       += leds-wm831x-status.o
-obj-$(CONFIG_LEDS_WM8350)              += leds-wm8350.o
-obj-$(CONFIG_LEDS_PWM)                 += leds-pwm.o
-obj-$(CONFIG_LEDS_REGULATOR)           += leds-regulator.o
-obj-$(CONFIG_LEDS_INTEL_SS4200)                += leds-ss4200.o
 obj-$(CONFIG_LEDS_LT3593)              += leds-lt3593.o
-obj-$(CONFIG_LEDS_ADP5520)             += leds-adp5520.o
-obj-$(CONFIG_LEDS_MC13783)             += leds-mc13783.o
-obj-$(CONFIG_LEDS_NS2)                 += leds-ns2.o
-obj-$(CONFIG_LEDS_NETXBIG)             += leds-netxbig.o
-obj-$(CONFIG_LEDS_ASIC3)               += leds-asic3.o
 obj-$(CONFIG_LEDS_MAX77650)            += leds-max77650.o
 obj-$(CONFIG_LEDS_MAX77693)            += leds-max77693.o
 obj-$(CONFIG_LEDS_MAX8997)             += leds-max8997.o
-obj-$(CONFIG_LEDS_LM355x)              += leds-lm355x.o
-obj-$(CONFIG_LEDS_BLINKM)              += leds-blinkm.o
-obj-$(CONFIG_LEDS_SYSCON)              += leds-syscon.o
+obj-$(CONFIG_LEDS_MC13783)             += leds-mc13783.o
 obj-$(CONFIG_LEDS_MENF21BMC)           += leds-menf21bmc.o
-obj-$(CONFIG_LEDS_KTD2692)             += leds-ktd2692.o
-obj-$(CONFIG_LEDS_POWERNV)             += leds-powernv.o
-obj-$(CONFIG_LEDS_IS31FL319X)          += leds-is31fl319x.o
-obj-$(CONFIG_LEDS_IS31FL32XX)          += leds-is31fl32xx.o
-obj-$(CONFIG_LEDS_PM8058)              += leds-pm8058.o
+obj-$(CONFIG_LEDS_MIKROTIK_RB532)      += leds-rb532.o
 obj-$(CONFIG_LEDS_MLXCPLD)             += leds-mlxcpld.o
 obj-$(CONFIG_LEDS_MLXREG)              += leds-mlxreg.o
-obj-$(CONFIG_LEDS_NIC78BX)             += leds-nic78bx.o
-obj-$(CONFIG_LEDS_SPI_BYTE)            += leds-spi-byte.o
 obj-$(CONFIG_LEDS_MT6323)              += leds-mt6323.o
-obj-$(CONFIG_LEDS_LM3692X)             += leds-lm3692x.o
+obj-$(CONFIG_LEDS_NET48XX)             += leds-net48xx.o
+obj-$(CONFIG_LEDS_NETXBIG)             += leds-netxbig.o
+obj-$(CONFIG_LEDS_NIC78BX)             += leds-nic78bx.o
+obj-$(CONFIG_LEDS_NS2)                 += leds-ns2.o
+obj-$(CONFIG_LEDS_OT200)               += leds-ot200.o
+obj-$(CONFIG_LEDS_PCA9532)             += leds-pca9532.o
+obj-$(CONFIG_LEDS_PCA955X)             += leds-pca955x.o
+obj-$(CONFIG_LEDS_PCA963X)             += leds-pca963x.o
+obj-$(CONFIG_LEDS_PM8058)              += leds-pm8058.o
+obj-$(CONFIG_LEDS_POWERNV)             += leds-powernv.o
+obj-$(CONFIG_LEDS_PWM)                 += leds-pwm.o
+obj-$(CONFIG_LEDS_REGULATOR)           += leds-regulator.o
+obj-$(CONFIG_LEDS_S3C24XX)             += leds-s3c24xx.o
 obj-$(CONFIG_LEDS_SC27XX_BLTC)         += leds-sc27xx-bltc.o
-obj-$(CONFIG_LEDS_LM3601X)             += leds-lm3601x.o
+obj-$(CONFIG_LEDS_SUNFIRE)             += leds-sunfire.o
+obj-$(CONFIG_LEDS_SYSCON)              += leds-syscon.o
+obj-$(CONFIG_LEDS_TCA6507)             += leds-tca6507.o
 obj-$(CONFIG_LEDS_TI_LMU_COMMON)       += leds-ti-lmu-common.o
-obj-$(CONFIG_LEDS_LM3697)              += leds-lm3697.o
-obj-$(CONFIG_LEDS_LM36274)             += leds-lm36274.o
+obj-$(CONFIG_LEDS_TLC591XX)            += leds-tlc591xx.o
 obj-$(CONFIG_LEDS_TPS6105X)            += leds-tps6105x.o
+obj-$(CONFIG_LEDS_WM831X_STATUS)       += leds-wm831x-status.o
+obj-$(CONFIG_LEDS_WM8350)              += leds-wm8350.o
+obj-$(CONFIG_LEDS_WRAP)                        += leds-wrap.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_CR0014114)           += leds-cr0014114.o
 obj-$(CONFIG_LEDS_DAC124S085)          += leds-dac124s085.o
 obj-$(CONFIG_LEDS_EL15203000)          += leds-el15203000.o
+obj-$(CONFIG_LEDS_SPI_BYTE)            += leds-spi-byte.o
 
 # LED Userspace Drivers
 obj-$(CONFIG_LEDS_USER)                        += uleds.o
index 1fc40e8..3363a65 100644 (file)
@@ -376,7 +376,7 @@ int led_classdev_register_ext(struct device *parent,
 
        if (ret)
                dev_warn(parent, "Led %s renamed to %s due to name collision",
-                               led_cdev->name, dev_name(led_cdev->dev));
+                               proposed_name, dev_name(led_cdev->dev));
 
        if (led_cdev->flags & LED_BRIGHT_HW_CHANGED) {
                ret = led_add_brightness_hw_changed(led_cdev);
index bd61a82..8bbaef5 100644 (file)
@@ -660,7 +660,6 @@ static int bd2802_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct bd2802_led *led;
-       struct bd2802_led_platform_data *pdata;
        int ret, i;
 
        led = devm_kzalloc(&client->dev, sizeof(struct bd2802_led), GFP_KERNEL);
@@ -668,7 +667,6 @@ static int bd2802_probe(struct i2c_client *client,
                return -ENOMEM;
 
        led->client = client;
-       pdata = led->pdata = dev_get_platdata(&client->dev);
        i2c_set_clientdata(client, led);
 
        /*
diff --git a/drivers/leds/leds-ip30.c b/drivers/leds/leds-ip30.c
new file mode 100644 (file)
index 0000000..d4ec736
--- /dev/null
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * LED Driver for SGI Octane machines
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+
+#define IP30_LED_SYSTEM        0
+#define IP30_LED_FAULT 1
+
+struct ip30_led {
+       struct led_classdev cdev;
+       u32 __iomem *reg;
+};
+
+static void ip30led_set(struct led_classdev *led_cdev,
+                       enum led_brightness value)
+{
+       struct ip30_led *led = container_of(led_cdev, struct ip30_led, cdev);
+
+       writel(value, led->reg);
+}
+
+static int ip30led_create(struct platform_device *pdev, int num)
+{
+       struct resource *res;
+       struct ip30_led *data;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, num);
+       if (!res)
+               return -EBUSY;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->reg = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(data->reg))
+               return PTR_ERR(data->reg);
+
+
+       switch (num) {
+       case IP30_LED_SYSTEM:
+               data->cdev.name = "white:power";
+               break;
+       case IP30_LED_FAULT:
+               data->cdev.name = "red:fault";
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       data->cdev.brightness = readl(data->reg);
+       data->cdev.max_brightness = 1;
+       data->cdev.brightness_set = ip30led_set;
+
+       return devm_led_classdev_register(&pdev->dev, &data->cdev);
+}
+
+static int ip30led_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       ret = ip30led_create(pdev, IP30_LED_SYSTEM);
+       if (ret < 0)
+               return ret;
+
+       return ip30led_create(pdev, IP30_LED_FAULT);
+}
+
+static struct platform_driver ip30led_driver = {
+       .probe          = ip30led_probe,
+       .driver         = {
+               .name           = "ip30-leds",
+       },
+};
+
+module_platform_driver(ip30led_driver);
+
+MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>");
+MODULE_DESCRIPTION("SGI Octane LED driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ip30-leds");
index 6f29b89..cd768f9 100644 (file)
@@ -44,7 +44,7 @@ struct is31fl32xx_priv {
        const struct is31fl32xx_chipdef *cdef;
        struct i2c_client *client;
        unsigned int num_leds;
-       struct is31fl32xx_led_data leds[0];
+       struct is31fl32xx_led_data leds[];
 };
 
 /**
index 188a57d..aa9bf8c 100644 (file)
@@ -140,7 +140,7 @@ struct lm3532_led {
        int ctrl_brt_pointer;
        int num_leds;
        int full_scale_current;
-       int enabled:1;
+       unsigned int enabled:1;
        u32 led_strings[LM3532_MAX_CONTROL_BANKS];
        char label[LED_MAX_NAME_SIZE];
 };
index b71711a..872d26f 100644 (file)
@@ -246,7 +246,7 @@ static int lm3697_probe_dt(struct lm3697 *priv)
 
                led->num_leds = fwnode_property_count_u32(child, "led-sources");
                if (led->num_leds > LM3697_MAX_LED_STRINGS) {
-                       dev_err(&priv->client->dev, "To many LED strings defined\n");
+                       dev_err(&priv->client->dev, "Too many LED strings defined\n");
                        continue;
                }
 
index 7c500df..538ca57 100644 (file)
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/leds.h>
 #include <linux/module.h>
-#include <linux/platform_data/leds-kirkwood-ns2.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include "leds.h"
 
+enum ns2_led_modes {
+       NS_V2_LED_OFF,
+       NS_V2_LED_ON,
+       NS_V2_LED_SATA,
+};
+
+struct ns2_led_modval {
+       enum ns2_led_modes      mode;
+       int                     cmd_level;
+       int                     slow_level;
+};
+
+struct ns2_led {
+       const char      *name;
+       const char      *default_trigger;
+       struct gpio_desc *cmd;
+       struct gpio_desc *slow;
+       int             num_modes;
+       struct ns2_led_modval *modval;
+};
+
+struct ns2_led_platform_data {
+       int             num_leds;
+       struct ns2_led  *leds;
+};
+
 /*
  * The Network Space v2 dual-GPIO LED is wired to a CPLD. Three different LED
  * modes are available: off, on and SATA activity blinking. The LED modes are
@@ -29,8 +53,8 @@
 
 struct ns2_led_data {
        struct led_classdev     cdev;
-       unsigned int            cmd;
-       unsigned int            slow;
+       struct gpio_desc        *cmd;
+       struct gpio_desc        *slow;
        bool                    can_sleep;
        unsigned char           sata; /* True when SATA mode active. */
        rwlock_t                rw_lock; /* Lock GPIOs. */
@@ -46,8 +70,8 @@ static int ns2_led_get_mode(struct ns2_led_data *led_dat,
        int cmd_level;
        int slow_level;
 
-       cmd_level = gpio_get_value_cansleep(led_dat->cmd);
-       slow_level = gpio_get_value_cansleep(led_dat->slow);
+       cmd_level = gpiod_get_value_cansleep(led_dat->cmd);
+       slow_level = gpiod_get_value_cansleep(led_dat->slow);
 
        for (i = 0; i < led_dat->num_modes; i++) {
                if (cmd_level == led_dat->modval[i].cmd_level &&
@@ -80,15 +104,15 @@ static void ns2_led_set_mode(struct ns2_led_data *led_dat,
        write_lock_irqsave(&led_dat->rw_lock, flags);
 
        if (!led_dat->can_sleep) {
-               gpio_set_value(led_dat->cmd,
-                              led_dat->modval[i].cmd_level);
-               gpio_set_value(led_dat->slow,
-                              led_dat->modval[i].slow_level);
+               gpiod_set_value(led_dat->cmd,
+                               led_dat->modval[i].cmd_level);
+               gpiod_set_value(led_dat->slow,
+                               led_dat->modval[i].slow_level);
                goto exit_unlock;
        }
 
-       gpio_set_value_cansleep(led_dat->cmd, led_dat->modval[i].cmd_level);
-       gpio_set_value_cansleep(led_dat->slow, led_dat->modval[i].slow_level);
+       gpiod_set_value_cansleep(led_dat->cmd, led_dat->modval[i].cmd_level);
+       gpiod_set_value_cansleep(led_dat->slow, led_dat->modval[i].slow_level);
 
 exit_unlock:
        write_unlock_irqrestore(&led_dat->rw_lock, flags);
@@ -176,26 +200,6 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
        int ret;
        enum ns2_led_modes mode;
 
-       ret = devm_gpio_request_one(&pdev->dev, template->cmd,
-                       gpio_get_value_cansleep(template->cmd) ?
-                       GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
-                       template->name);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to setup command GPIO\n",
-                       template->name);
-               return ret;
-       }
-
-       ret = devm_gpio_request_one(&pdev->dev, template->slow,
-                       gpio_get_value_cansleep(template->slow) ?
-                       GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
-                       template->name);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to setup slow GPIO\n",
-                       template->name);
-               return ret;
-       }
-
        rwlock_init(&led_dat->rw_lock);
 
        led_dat->cdev.name = template->name;
@@ -205,8 +209,8 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
        led_dat->cdev.groups = ns2_led_groups;
        led_dat->cmd = template->cmd;
        led_dat->slow = template->slow;
-       led_dat->can_sleep = gpio_cansleep(led_dat->cmd) |
-                               gpio_cansleep(led_dat->slow);
+       led_dat->can_sleep = gpiod_cansleep(led_dat->cmd) |
+                               gpiod_cansleep(led_dat->slow);
        if (led_dat->can_sleep)
                led_dat->cdev.brightness_set_blocking = ns2_led_set_blocking;
        else
@@ -261,17 +265,26 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata)
                const char *string;
                int i, num_modes;
                struct ns2_led_modval *modval;
+               struct gpio_desc *gd;
 
-               ret = of_get_named_gpio(child, "cmd-gpio", 0);
-               if (ret < 0)
-                       goto err_node_put;
-               led->cmd = ret;
-               ret = of_get_named_gpio(child, "slow-gpio", 0);
-               if (ret < 0)
-                       goto err_node_put;
-               led->slow = ret;
                ret = of_property_read_string(child, "label", &string);
                led->name = (ret == 0) ? string : child->name;
+
+               gd = gpiod_get_from_of_node(child, "cmd-gpio", 0,
+                                           GPIOD_ASIS, led->name);
+               if (IS_ERR(gd)) {
+                       ret = PTR_ERR(gd);
+                       goto err_node_put;
+               }
+               led->cmd = gd;
+               gd = gpiod_get_from_of_node(child, "slow-gpio", 0,
+                                           GPIOD_ASIS, led->name);
+               if (IS_ERR(gd)) {
+                       ret = PTR_ERR(gd);
+                       goto err_node_put;
+               }
+               led->slow = gd;
+
                ret = of_property_read_string(child, "linux,default-trigger",
                                              &string);
                if (ret == 0)
index 8b6965a..6c8a724 100644 (file)
 #include <linux/leds.h>
 #include <linux/err.h>
 #include <linux/pwm.h>
-#include <linux/leds_pwm.h>
 #include <linux/slab.h>
 
+struct led_pwm {
+       const char      *name;
+       const char      *default_trigger;
+       u8              active_low;
+       unsigned int    max_brightness;
+};
+
+struct led_pwm_platform_data {
+       int             num_leds;
+       struct led_pwm  *leds;
+};
+
 struct led_pwm_data {
        struct led_classdev     cdev;
        struct pwm_device       *pwm;
+       struct pwm_state        pwmstate;
        unsigned int            active_low;
-       unsigned int            period;
-       int                     duty;
 };
 
 struct led_pwm_priv {
        int num_leds;
-       struct led_pwm_data leds[0];
+       struct led_pwm_data leds[];
 };
 
-static void __led_pwm_set(struct led_pwm_data *led_dat)
-{
-       int new_duty = led_dat->duty;
-
-       pwm_config(led_dat->pwm, new_duty, led_dat->period);
-
-       if (new_duty == 0)
-               pwm_disable(led_dat->pwm);
-       else
-               pwm_enable(led_dat->pwm);
-}
-
 static int led_pwm_set(struct led_classdev *led_cdev,
                       enum led_brightness brightness)
 {
        struct led_pwm_data *led_dat =
                container_of(led_cdev, struct led_pwm_data, cdev);
        unsigned int max = led_dat->cdev.max_brightness;
-       unsigned long long duty =  led_dat->period;
+       unsigned long long duty = led_dat->pwmstate.period;
 
        duty *= brightness;
        do_div(duty, max);
 
        if (led_dat->active_low)
-               duty = led_dat->period - duty;
-
-       led_dat->duty = duty;
-
-       __led_pwm_set(led_dat);
+               duty = led_dat->pwmstate.period - duty;
 
-       return 0;
+       led_dat->pwmstate.duty_cycle = duty;
+       led_dat->pwmstate.enabled = duty > 0;
+       return pwm_apply_state(led_dat->pwm, &led_dat->pwmstate);
 }
 
 static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
                       struct led_pwm *led, struct fwnode_handle *fwnode)
 {
        struct led_pwm_data *led_data = &priv->leds[priv->num_leds];
-       struct pwm_args pargs;
        int ret;
 
        led_data->active_low = led->active_low;
@@ -93,17 +88,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
 
        led_data->cdev.brightness_set_blocking = led_pwm_set;
 
-       /*
-        * FIXME: pwm_apply_args() should be removed when switching to the
-        * atomic PWM API.
-        */
-       pwm_apply_args(led_data->pwm);
-
-       pwm_get_args(led_data->pwm, &pargs);
-
-       led_data->period = pargs.period;
-       if (!led_data->period && (led->pwm_period_ns > 0))
-               led_data->period = led->pwm_period_ns;
+       pwm_init_state(led_data->pwm, &led_data->pwmstate);
 
        ret = devm_led_classdev_register(dev, &led_data->cdev);
        if (ret == 0) {
index 8d07fdf..e1db434 100644 (file)
@@ -201,10 +201,27 @@ static size_t linear_dax_copy_to_iter(struct dm_target *ti, pgoff_t pgoff,
        return dax_copy_to_iter(dax_dev, pgoff, addr, bytes, i);
 }
 
+static int linear_dax_zero_page_range(struct dm_target *ti, pgoff_t pgoff,
+                                     size_t nr_pages)
+{
+       int ret;
+       struct linear_c *lc = ti->private;
+       struct block_device *bdev = lc->dev->bdev;
+       struct dax_device *dax_dev = lc->dev->dax_dev;
+       sector_t dev_sector, sector = pgoff * PAGE_SECTORS;
+
+       dev_sector = linear_map_sector(ti, sector);
+       ret = bdev_dax_pgoff(bdev, dev_sector, nr_pages << PAGE_SHIFT, &pgoff);
+       if (ret)
+               return ret;
+       return dax_zero_page_range(dax_dev, pgoff, nr_pages);
+}
+
 #else
 #define linear_dax_direct_access NULL
 #define linear_dax_copy_from_iter NULL
 #define linear_dax_copy_to_iter NULL
+#define linear_dax_zero_page_range NULL
 #endif
 
 static struct target_type linear_target = {
@@ -226,6 +243,7 @@ static struct target_type linear_target = {
        .direct_access = linear_dax_direct_access,
        .dax_copy_from_iter = linear_dax_copy_from_iter,
        .dax_copy_to_iter = linear_dax_copy_to_iter,
+       .dax_zero_page_range = linear_dax_zero_page_range,
 };
 
 int __init dm_linear_init(void)
index 99721c7..8ea20b5 100644 (file)
@@ -994,10 +994,26 @@ static size_t log_writes_dax_copy_to_iter(struct dm_target *ti,
        return dax_copy_to_iter(lc->dev->dax_dev, pgoff, addr, bytes, i);
 }
 
+static int log_writes_dax_zero_page_range(struct dm_target *ti, pgoff_t pgoff,
+                                         size_t nr_pages)
+{
+       int ret;
+       struct log_writes_c *lc = ti->private;
+       sector_t sector = pgoff * PAGE_SECTORS;
+
+       ret = bdev_dax_pgoff(lc->dev->bdev, sector, nr_pages << PAGE_SHIFT,
+                            &pgoff);
+       if (ret)
+               return ret;
+       return dax_zero_page_range(lc->dev->dax_dev, pgoff,
+                                  nr_pages << PAGE_SHIFT);
+}
+
 #else
 #define log_writes_dax_direct_access NULL
 #define log_writes_dax_copy_from_iter NULL
 #define log_writes_dax_copy_to_iter NULL
+#define log_writes_dax_zero_page_range NULL
 #endif
 
 static struct target_type log_writes_target = {
@@ -1016,6 +1032,7 @@ static struct target_type log_writes_target = {
        .direct_access = log_writes_dax_direct_access,
        .dax_copy_from_iter = log_writes_dax_copy_from_iter,
        .dax_copy_to_iter = log_writes_dax_copy_to_iter,
+       .dax_zero_page_range = log_writes_dax_zero_page_range,
 };
 
 static int __init dm_log_writes_init(void)
index 63bbcc2..fa813c0 100644 (file)
@@ -360,10 +360,32 @@ static size_t stripe_dax_copy_to_iter(struct dm_target *ti, pgoff_t pgoff,
        return dax_copy_to_iter(dax_dev, pgoff, addr, bytes, i);
 }
 
+static int stripe_dax_zero_page_range(struct dm_target *ti, pgoff_t pgoff,
+                                     size_t nr_pages)
+{
+       int ret;
+       sector_t dev_sector, sector = pgoff * PAGE_SECTORS;
+       struct stripe_c *sc = ti->private;
+       struct dax_device *dax_dev;
+       struct block_device *bdev;
+       uint32_t stripe;
+
+       stripe_map_sector(sc, sector, &stripe, &dev_sector);
+       dev_sector += sc->stripe[stripe].physical_start;
+       dax_dev = sc->stripe[stripe].dev->dax_dev;
+       bdev = sc->stripe[stripe].dev->bdev;
+
+       ret = bdev_dax_pgoff(bdev, dev_sector, nr_pages << PAGE_SHIFT, &pgoff);
+       if (ret)
+               return ret;
+       return dax_zero_page_range(dax_dev, pgoff, nr_pages);
+}
+
 #else
 #define stripe_dax_direct_access NULL
 #define stripe_dax_copy_from_iter NULL
 #define stripe_dax_copy_to_iter NULL
+#define stripe_dax_zero_page_range NULL
 #endif
 
 /*
@@ -486,6 +508,7 @@ static struct target_type stripe_target = {
        .direct_access = stripe_dax_direct_access,
        .dax_copy_from_iter = stripe_dax_copy_from_iter,
        .dax_copy_to_iter = stripe_dax_copy_to_iter,
+       .dax_zero_page_range = stripe_dax_zero_page_range,
 };
 
 int __init dm_stripe_init(void)
index 21c0207..db9e461 100644 (file)
@@ -1199,6 +1199,35 @@ static size_t dm_dax_copy_to_iter(struct dax_device *dax_dev, pgoff_t pgoff,
        return ret;
 }
 
+static int dm_dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
+                                 size_t nr_pages)
+{
+       struct mapped_device *md = dax_get_private(dax_dev);
+       sector_t sector = pgoff * PAGE_SECTORS;
+       struct dm_target *ti;
+       int ret = -EIO;
+       int srcu_idx;
+
+       ti = dm_dax_get_live_target(md, sector, &srcu_idx);
+
+       if (!ti)
+               goto out;
+       if (WARN_ON(!ti->type->dax_zero_page_range)) {
+               /*
+                * ->zero_page_range() is mandatory dax operation. If we are
+                *  here, something is wrong.
+                */
+               dm_put_live_table(md, srcu_idx);
+               goto out;
+       }
+       ret = ti->type->dax_zero_page_range(ti, pgoff, nr_pages);
+
+ out:
+       dm_put_live_table(md, srcu_idx);
+
+       return ret;
+}
+
 /*
  * A target may call dm_accept_partial_bio only from the map routine.  It is
  * allowed for all bio types except REQ_PREFLUSH, REQ_OP_ZONE_RESET,
@@ -1969,7 +1998,7 @@ static struct mapped_device *alloc_dev(int minor)
        if (IS_ENABLED(CONFIG_DAX_DRIVER)) {
                md->dax_dev = alloc_dax(md, md->disk->disk_name,
                                        &dm_dax_ops, 0);
-               if (!md->dax_dev)
+               if (IS_ERR(md->dax_dev))
                        goto bad;
        }
 
@@ -3200,6 +3229,7 @@ static const struct dax_operations dm_dax_ops = {
        .dax_supported = dm_dax_supported,
        .copy_from_iter = dm_dax_copy_from_iter,
        .copy_to_iter = dm_dax_copy_to_iter,
+       .zero_page_range = dm_dax_zero_page_range,
 };
 
 /*
index 2b20329..0a59249 100644 (file)
@@ -642,6 +642,19 @@ config MFD_IPAQ_MICRO
          AT90LS8535 microcontroller flashed with a special iPAQ
          firmware using the custom protocol implemented in this driver.
 
+config MFD_IQS62X
+       tristate "Azoteq IQS620A/621/622/624/625 core support"
+       depends on I2C
+       select MFD_CORE
+       select REGMAP_I2C
+       help
+         Say Y here if you want to build core support for the Azoteq IQS620A,
+         IQS621, IQS622, IQS624 and IQS625 multi-function sensors. Additional
+         options must be selected to enable device-specific functions.
+
+         To compile this driver as a module, choose M here: the module will
+         be called iqs62x.
+
 config MFD_JANZ_CMODIO
        tristate "Janz CMOD-IO PCI MODULbus Carrier Board"
        select MFD_CORE
@@ -893,6 +906,7 @@ config MFD_CPCAP
        tristate "Support for Motorola CPCAP"
        depends on SPI
        depends on OF || COMPILE_TEST
+       select MFD_CORE
        select REGMAP_SPI
        select REGMAP_IRQ
        help
@@ -1058,6 +1072,7 @@ config MFD_RN5T618
        depends on OF
        select MFD_CORE
        select REGMAP_I2C
+       select REGMAP_IRQ
        help
          Say yes here to add support for the Ricoh RN5T567,
          RN5T618, RC5T619 PMIC.
@@ -1201,7 +1216,7 @@ config AB8500_CORE
          chip. This connects to U8500 either on the SSP/SPI bus (deprecated
          since hardware version v1.0) or the I2C bus via PRCMU. It also adds
          the irq_chip parts for handling the Mixed Signal chip events.
-         This chip embeds various other multimedia funtionalities as well.
+         This chip embeds various other multimedia functionalities as well.
 
 config AB8500_DEBUG
        bool "Enable debug info via debugfs"
@@ -1851,7 +1866,7 @@ config MFD_WM8994
          has on board GPIO and regulator functionality which is
          supported via the relevant subsystems.  This driver provides
          core support for the WM8994, in order to use the actual
-         functionaltiy of the device other drivers must be enabled.
+         functionality of the device other drivers must be enabled.
 
 config MFD_WM97xx
        tristate "Wolfson Microelectronics WM97xx"
@@ -1864,7 +1879,7 @@ config MFD_WM97xx
          designed for smartphone applications.  As well as audio functionality
          it has on board GPIO and a touchscreen functionality which is
          supported via the relevant subsystems.  This driver provides core
-         support for the WM97xx, in order to use the actual functionaltiy of
+         support for the WM97xx, in order to use the actual functionality of
          the device other drivers must be enabled.
 
 config MFD_STW481X
@@ -1957,7 +1972,7 @@ config MFD_STPMIC1
          Support for ST Microelectronics STPMIC1 PMIC. STPMIC1 has power on
          key, watchdog and regulator functionalities which are supported via
          the relevant subsystems. This driver provides core support for the
-         STPMIC1. In order to use the actual functionaltiy of the device other
+         STPMIC1. In order to use the actual functionality of the device other
          drivers must be enabled.
 
          To compile this driver as a module, choose M here: the
index b83f172..f935d10 100644 (file)
@@ -226,6 +226,7 @@ obj-$(CONFIG_MFD_AS3711)    += as3711.o
 obj-$(CONFIG_MFD_AS3722)       += as3722.o
 obj-$(CONFIG_MFD_STW481X)      += stw481x.o
 obj-$(CONFIG_MFD_IPAQ_MICRO)   += ipaq-micro.o
+obj-$(CONFIG_MFD_IQS62X)       += iqs62x.o
 obj-$(CONFIG_MFD_MENF21BMC)    += menf21bmc.o
 obj-$(CONFIG_MFD_HI6421_PMIC)  += hi6421-pmic-core.o
 obj-$(CONFIG_MFD_HI655X_PMIC)   += hi655x-pmic.o
index 78ee4b2..a17cf75 100644 (file)
@@ -221,7 +221,7 @@ static ssize_t aat2870_dump_reg(struct aat2870_data *aat2870, char *buf)
 
        count += sprintf(buf, "aat2870 registers\n");
        for (addr = 0; addr < AAT2870_REG_NUM; addr++) {
-               count += sprintf(buf + count, "0x%02x: ", addr);
+               count += snprintf(buf + count, PAGE_SIZE - count, "0x%02x: ", addr);
                if (count >= PAGE_SIZE - 1)
                        break;
 
index 39e6116..32c2b91 100644 (file)
@@ -211,7 +211,7 @@ static int ec_device_probe(struct platform_device *pdev)
         * explicitly added on platforms that don't have the PD notifier ACPI
         * device entry defined.
         */
-       if (IS_ENABLED(CONFIG_OF)) {
+       if (IS_ENABLED(CONFIG_OF) && ec->ec_dev->dev->of_node) {
                if (cros_ec_check_features(ec, EC_FEATURE_USB_PD)) {
                        retval = mfd_add_hotplug_devices(ec->dev,
                                        cros_usbpd_notify_cells,
index 419c735..fc30726 100644 (file)
@@ -21,6 +21,9 @@
 #define        DA9062_REG_EVENT_B_OFFSET       1
 #define        DA9062_REG_EVENT_C_OFFSET       2
 
+#define        DA9062_IRQ_LOW  0
+#define        DA9062_IRQ_HIGH 1
+
 static struct regmap_irq da9061_irqs[] = {
        /* EVENT A */
        [DA9061_IRQ_ONKEY] = {
@@ -369,6 +372,33 @@ static int da9062_get_device_type(struct da9062 *chip)
        return ret;
 }
 
+static u32 da9062_configure_irq_type(struct da9062 *chip, int irq, u32 *trigger)
+{
+       u32 irq_type = 0;
+       struct irq_data *irq_data = irq_get_irq_data(irq);
+
+       if (!irq_data) {
+               dev_err(chip->dev, "Invalid IRQ: %d\n", irq);
+               return -EINVAL;
+       }
+       *trigger = irqd_get_trigger_type(irq_data);
+
+       switch (*trigger) {
+       case IRQ_TYPE_LEVEL_HIGH:
+               irq_type = DA9062_IRQ_HIGH;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               irq_type = DA9062_IRQ_LOW;
+               break;
+       default:
+               dev_warn(chip->dev, "Unsupported IRQ type: %d\n", *trigger);
+               return -EINVAL;
+       }
+       return regmap_update_bits(chip->regmap, DA9062AA_CONFIG_A,
+                       DA9062AA_IRQ_TYPE_MASK,
+                       irq_type << DA9062AA_IRQ_TYPE_SHIFT);
+}
+
 static const struct regmap_range da9061_aa_readable_ranges[] = {
        regmap_reg_range(DA9062AA_PAGE_CON, DA9062AA_STATUS_B),
        regmap_reg_range(DA9062AA_STATUS_D, DA9062AA_EVENT_C),
@@ -388,6 +418,7 @@ static const struct regmap_range da9061_aa_readable_ranges[] = {
        regmap_reg_range(DA9062AA_VBUCK1_A, DA9062AA_VBUCK4_A),
        regmap_reg_range(DA9062AA_VBUCK3_A, DA9062AA_VBUCK3_A),
        regmap_reg_range(DA9062AA_VLDO1_A, DA9062AA_VLDO4_A),
+       regmap_reg_range(DA9062AA_CONFIG_A, DA9062AA_CONFIG_A),
        regmap_reg_range(DA9062AA_VBUCK1_B, DA9062AA_VBUCK4_B),
        regmap_reg_range(DA9062AA_VBUCK3_B, DA9062AA_VBUCK3_B),
        regmap_reg_range(DA9062AA_VLDO1_B, DA9062AA_VLDO4_B),
@@ -417,6 +448,7 @@ static const struct regmap_range da9061_aa_writeable_ranges[] = {
        regmap_reg_range(DA9062AA_VBUCK1_A, DA9062AA_VBUCK4_A),
        regmap_reg_range(DA9062AA_VBUCK3_A, DA9062AA_VBUCK3_A),
        regmap_reg_range(DA9062AA_VLDO1_A, DA9062AA_VLDO4_A),
+       regmap_reg_range(DA9062AA_CONFIG_A, DA9062AA_CONFIG_A),
        regmap_reg_range(DA9062AA_VBUCK1_B, DA9062AA_VBUCK4_B),
        regmap_reg_range(DA9062AA_VBUCK3_B, DA9062AA_VBUCK3_B),
        regmap_reg_range(DA9062AA_VLDO1_B, DA9062AA_VLDO4_B),
@@ -596,6 +628,7 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
        const struct regmap_irq_chip *irq_chip;
        const struct regmap_config *config;
        int cell_num;
+       u32 trigger_type = 0;
        int ret;
 
        chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
@@ -654,10 +687,15 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
        if (ret)
                return ret;
 
+       ret = da9062_configure_irq_type(chip, i2c->irq, &trigger_type);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to configure IRQ type\n");
+               return ret;
+       }
+
        ret = regmap_add_irq_chip(chip->regmap, i2c->irq,
-                       IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
-                       -1, irq_chip,
-                       &chip->regmap_irq);
+                       trigger_type | IRQF_SHARED | IRQF_ONESHOT,
+                       -1, irq_chip, &chip->regmap_irq);
        if (ret) {
                dev_err(chip->dev, "Failed to request IRQ %d: %d\n",
                        i2c->irq, ret);
index 7841c11..39276fa 100644 (file)
@@ -90,6 +90,11 @@ struct dln2_mod_rx_slots {
        spinlock_t lock;
 };
 
+enum dln2_endpoint {
+       DLN2_EP_OUT     = 0,
+       DLN2_EP_IN      = 1,
+};
+
 struct dln2_dev {
        struct usb_device *usb_dev;
        struct usb_interface *interface;
@@ -640,35 +645,56 @@ static int dln2_start_rx_urbs(struct dln2_dev *dln2, gfp_t gfp)
        return 0;
 }
 
+enum {
+       DLN2_ACPI_MATCH_GPIO    = 0,
+       DLN2_ACPI_MATCH_I2C     = 1,
+       DLN2_ACPI_MATCH_SPI     = 2,
+};
+
 static struct dln2_platform_data dln2_pdata_gpio = {
        .handle = DLN2_HANDLE_GPIO,
 };
 
+static struct mfd_cell_acpi_match dln2_acpi_match_gpio = {
+       .adr = DLN2_ACPI_MATCH_GPIO,
+};
+
 /* Only one I2C port seems to be supported on current hardware */
 static struct dln2_platform_data dln2_pdata_i2c = {
        .handle = DLN2_HANDLE_I2C,
        .port = 0,
 };
 
+static struct mfd_cell_acpi_match dln2_acpi_match_i2c = {
+       .adr = DLN2_ACPI_MATCH_I2C,
+};
+
 /* Only one SPI port supported */
 static struct dln2_platform_data dln2_pdata_spi = {
        .handle = DLN2_HANDLE_SPI,
        .port = 0,
 };
 
+static struct mfd_cell_acpi_match dln2_acpi_match_spi = {
+       .adr = DLN2_ACPI_MATCH_SPI,
+};
+
 static const struct mfd_cell dln2_devs[] = {
        {
                .name = "dln2-gpio",
+               .acpi_match = &dln2_acpi_match_gpio,
                .platform_data = &dln2_pdata_gpio,
                .pdata_size = sizeof(struct dln2_platform_data),
        },
        {
                .name = "dln2-i2c",
+               .acpi_match = &dln2_acpi_match_i2c,
                .platform_data = &dln2_pdata_i2c,
                .pdata_size = sizeof(struct dln2_platform_data),
        },
        {
                .name = "dln2-spi",
+               .acpi_match = &dln2_acpi_match_spi,
                .platform_data = &dln2_pdata_spi,
                .pdata_size = sizeof(struct dln2_platform_data),
        },
@@ -733,10 +759,10 @@ static int dln2_probe(struct usb_interface *interface,
            hostif->desc.bNumEndpoints < 2)
                return -ENODEV;
 
-       epin = &hostif->endpoint[0].desc;
-       epout = &hostif->endpoint[1].desc;
+       epout = &hostif->endpoint[DLN2_EP_OUT].desc;
        if (!usb_endpoint_is_bulk_out(epout))
                return -ENODEV;
+       epin = &hostif->endpoint[DLN2_EP_IN].desc;
        if (!usb_endpoint_is_bulk_in(epin))
                return -ENODEV;
 
index c40a6c7..7fc0c5d 100644 (file)
@@ -139,6 +139,11 @@ static const struct intel_lpss_platform_info cnl_i2c_info = {
        .properties = spt_i2c_properties,
 };
 
+static const struct intel_lpss_platform_info ehl_i2c_info = {
+       .clk_rate = 100000000,
+       .properties = bxt_i2c_properties,
+};
+
 static const struct pci_device_id intel_lpss_pci_ids[] = {
        /* CML-LP */
        { PCI_VDEVICE(INTEL, 0x02a8), (kernel_ulong_t)&spt_uart_info },
@@ -231,15 +236,15 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0x4b2a), (kernel_ulong_t)&bxt_info },
        { PCI_VDEVICE(INTEL, 0x4b2b), (kernel_ulong_t)&bxt_info },
        { PCI_VDEVICE(INTEL, 0x4b37), (kernel_ulong_t)&bxt_info },
-       { PCI_VDEVICE(INTEL, 0x4b44), (kernel_ulong_t)&bxt_i2c_info },
-       { PCI_VDEVICE(INTEL, 0x4b45), (kernel_ulong_t)&bxt_i2c_info },
-       { PCI_VDEVICE(INTEL, 0x4b4b), (kernel_ulong_t)&bxt_i2c_info },
-       { PCI_VDEVICE(INTEL, 0x4b4c), (kernel_ulong_t)&bxt_i2c_info },
+       { PCI_VDEVICE(INTEL, 0x4b44), (kernel_ulong_t)&ehl_i2c_info },
+       { PCI_VDEVICE(INTEL, 0x4b45), (kernel_ulong_t)&ehl_i2c_info },
+       { PCI_VDEVICE(INTEL, 0x4b4b), (kernel_ulong_t)&ehl_i2c_info },
+       { PCI_VDEVICE(INTEL, 0x4b4c), (kernel_ulong_t)&ehl_i2c_info },
        { PCI_VDEVICE(INTEL, 0x4b4d), (kernel_ulong_t)&bxt_uart_info },
-       { PCI_VDEVICE(INTEL, 0x4b78), (kernel_ulong_t)&bxt_i2c_info },
-       { PCI_VDEVICE(INTEL, 0x4b79), (kernel_ulong_t)&bxt_i2c_info },
-       { PCI_VDEVICE(INTEL, 0x4b7a), (kernel_ulong_t)&bxt_i2c_info },
-       { PCI_VDEVICE(INTEL, 0x4b7b), (kernel_ulong_t)&bxt_i2c_info },
+       { PCI_VDEVICE(INTEL, 0x4b78), (kernel_ulong_t)&ehl_i2c_info },
+       { PCI_VDEVICE(INTEL, 0x4b79), (kernel_ulong_t)&ehl_i2c_info },
+       { PCI_VDEVICE(INTEL, 0x4b7a), (kernel_ulong_t)&ehl_i2c_info },
+       { PCI_VDEVICE(INTEL, 0x4b7b), (kernel_ulong_t)&ehl_i2c_info },
        /* JSL */
        { PCI_VDEVICE(INTEL, 0x4da8), (kernel_ulong_t)&spt_uart_info },
        { PCI_VDEVICE(INTEL, 0x4da9), (kernel_ulong_t)&spt_uart_info },
@@ -347,6 +352,16 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0xa36a), (kernel_ulong_t)&cnl_i2c_info },
        { PCI_VDEVICE(INTEL, 0xa36b), (kernel_ulong_t)&cnl_i2c_info },
        { PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&spt_info },
+       /* CML-V */
+       { PCI_VDEVICE(INTEL, 0xa3a7), (kernel_ulong_t)&spt_uart_info },
+       { PCI_VDEVICE(INTEL, 0xa3a8), (kernel_ulong_t)&spt_uart_info },
+       { PCI_VDEVICE(INTEL, 0xa3a9), (kernel_ulong_t)&spt_info },
+       { PCI_VDEVICE(INTEL, 0xa3aa), (kernel_ulong_t)&spt_info },
+       { PCI_VDEVICE(INTEL, 0xa3e0), (kernel_ulong_t)&spt_i2c_info },
+       { PCI_VDEVICE(INTEL, 0xa3e1), (kernel_ulong_t)&spt_i2c_info },
+       { PCI_VDEVICE(INTEL, 0xa3e2), (kernel_ulong_t)&spt_i2c_info },
+       { PCI_VDEVICE(INTEL, 0xa3e3), (kernel_ulong_t)&spt_i2c_info },
+       { PCI_VDEVICE(INTEL, 0xa3e6), (kernel_ulong_t)&spt_uart_info },
        { }
 };
 MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids);
diff --git a/drivers/mfd/iqs62x.c b/drivers/mfd/iqs62x.c
new file mode 100644 (file)
index 0000000..af764bc
--- /dev/null
@@ -0,0 +1,1063 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS620A/621/622/624/625 Multi-Function Sensors
+ *
+ * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
+ *
+ * These devices rely on application-specific register settings and calibration
+ * data developed in and exported from a suite of GUIs offered by the vendor. A
+ * separate tool converts the GUIs' ASCII-based output into a standard firmware
+ * file parsed by the driver.
+ *
+ * Link to datasheets and GUIs: https://www.azoteq.com/
+ *
+ * Link to conversion tool: https://github.com/jlabundy/iqs62x-h2bin.git
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/iqs62x.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/of_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#define IQS62X_PROD_NUM                                0x00
+
+#define IQS62X_SYS_FLAGS                       0x10
+#define IQS62X_SYS_FLAGS_IN_ATI                        BIT(2)
+
+#define IQS620_HALL_FLAGS                      0x16
+#define IQS621_HALL_FLAGS                      0x19
+#define IQS622_HALL_FLAGS                      IQS621_HALL_FLAGS
+
+#define IQS624_INTERVAL_NUM                    0x18
+#define IQS625_INTERVAL_NUM                    0x12
+
+#define IQS622_PROX_SETTINGS_4                 0x48
+#define IQS620_PROX_SETTINGS_4                 0x50
+#define IQS620_PROX_SETTINGS_4_SAR_EN          BIT(7)
+
+#define IQS621_ALS_CAL_DIV_LUX                 0x82
+#define IQS621_ALS_CAL_DIV_IR                  0x83
+
+#define IQS620_TEMP_CAL_MULT                   0xC2
+#define IQS620_TEMP_CAL_DIV                    0xC3
+#define IQS620_TEMP_CAL_OFFS                   0xC4
+
+#define IQS62X_SYS_SETTINGS                    0xD0
+#define IQS62X_SYS_SETTINGS_SOFT_RESET         BIT(7)
+#define IQS62X_SYS_SETTINGS_ACK_RESET          BIT(6)
+#define IQS62X_SYS_SETTINGS_EVENT_MODE         BIT(5)
+#define IQS62X_SYS_SETTINGS_CLK_DIV            BIT(4)
+#define IQS62X_SYS_SETTINGS_REDO_ATI           BIT(1)
+
+#define IQS62X_PWR_SETTINGS                    0xD2
+#define IQS62X_PWR_SETTINGS_DIS_AUTO           BIT(5)
+#define IQS62X_PWR_SETTINGS_PWR_MODE_MASK      (BIT(4) | BIT(3))
+#define IQS62X_PWR_SETTINGS_PWR_MODE_HALT      (BIT(4) | BIT(3))
+#define IQS62X_PWR_SETTINGS_PWR_MODE_NORM      0
+
+#define IQS62X_OTP_CMD                         0xF0
+#define IQS62X_OTP_CMD_FG3                     0x13
+#define IQS62X_OTP_DATA                                0xF1
+#define IQS62X_MAX_REG                         0xFF
+
+#define IQS62X_HALL_CAL_MASK                   GENMASK(3, 0)
+
+#define IQS62X_FW_REC_TYPE_INFO                        0
+#define IQS62X_FW_REC_TYPE_PROD                        1
+#define IQS62X_FW_REC_TYPE_HALL                        2
+#define IQS62X_FW_REC_TYPE_MASK                        3
+#define IQS62X_FW_REC_TYPE_DATA                        4
+
+#define IQS62X_ATI_POLL_SLEEP_US               10000
+#define IQS62X_ATI_POLL_TIMEOUT_US             500000
+#define IQS62X_ATI_STABLE_DELAY_MS             150
+
+struct iqs62x_fw_rec {
+       u8 type;
+       u8 addr;
+       u8 len;
+       u8 data;
+} __packed;
+
+struct iqs62x_fw_blk {
+       struct list_head list;
+       u8 addr;
+       u8 mask;
+       u8 len;
+       u8 data[];
+};
+
+struct iqs62x_info {
+       u8 prod_num;
+       u8 sw_num;
+       u8 hw_num;
+} __packed;
+
+static int iqs62x_dev_init(struct iqs62x_core *iqs62x)
+{
+       struct iqs62x_fw_blk *fw_blk;
+       unsigned int val;
+       int ret;
+       u8 clk_div = 1;
+
+       list_for_each_entry(fw_blk, &iqs62x->fw_blk_head, list) {
+               if (fw_blk->mask)
+                       ret = regmap_update_bits(iqs62x->regmap, fw_blk->addr,
+                                                fw_blk->mask, *fw_blk->data);
+               else
+                       ret = regmap_raw_write(iqs62x->regmap, fw_blk->addr,
+                                              fw_blk->data, fw_blk->len);
+               if (ret)
+                       return ret;
+       }
+
+       switch (iqs62x->dev_desc->prod_num) {
+       case IQS620_PROD_NUM:
+       case IQS622_PROD_NUM:
+               ret = regmap_read(iqs62x->regmap,
+                                 iqs62x->dev_desc->prox_settings, &val);
+               if (ret)
+                       return ret;
+
+               if (val & IQS620_PROX_SETTINGS_4_SAR_EN)
+                       iqs62x->ui_sel = IQS62X_UI_SAR1;
+
+               /* fall through */
+
+       case IQS621_PROD_NUM:
+               ret = regmap_write(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
+                                  IQS620_GLBL_EVENT_MASK_PMU |
+                                  iqs62x->dev_desc->prox_mask |
+                                  iqs62x->dev_desc->sar_mask |
+                                  iqs62x->dev_desc->hall_mask |
+                                  iqs62x->dev_desc->hyst_mask |
+                                  iqs62x->dev_desc->temp_mask |
+                                  iqs62x->dev_desc->als_mask |
+                                  iqs62x->dev_desc->ir_mask);
+               if (ret)
+                       return ret;
+               break;
+
+       default:
+               ret = regmap_write(iqs62x->regmap, IQS624_HALL_UI,
+                                  IQS624_HALL_UI_WHL_EVENT |
+                                  IQS624_HALL_UI_INT_EVENT |
+                                  IQS624_HALL_UI_AUTO_CAL);
+               if (ret)
+                       return ret;
+
+               /*
+                * The IQS625 default interval divider is below the minimum
+                * permissible value, and the datasheet mandates that it is
+                * corrected during initialization (unless an updated value
+                * has already been provided by firmware).
+                *
+                * To protect against an unacceptably low user-entered value
+                * stored in the firmware, the same check is extended to the
+                * IQS624 as well.
+                */
+               ret = regmap_read(iqs62x->regmap, IQS624_INTERVAL_DIV, &val);
+               if (ret)
+                       return ret;
+
+               if (val >= iqs62x->dev_desc->interval_div)
+                       break;
+
+               ret = regmap_write(iqs62x->regmap, IQS624_INTERVAL_DIV,
+                                  iqs62x->dev_desc->interval_div);
+               if (ret)
+                       return ret;
+       }
+
+       ret = regmap_read(iqs62x->regmap, IQS62X_SYS_SETTINGS, &val);
+       if (ret)
+               return ret;
+
+       if (val & IQS62X_SYS_SETTINGS_CLK_DIV)
+               clk_div = iqs62x->dev_desc->clk_div;
+
+       ret = regmap_write(iqs62x->regmap, IQS62X_SYS_SETTINGS, val |
+                          IQS62X_SYS_SETTINGS_ACK_RESET |
+                          IQS62X_SYS_SETTINGS_EVENT_MODE |
+                          IQS62X_SYS_SETTINGS_REDO_ATI);
+       if (ret)
+               return ret;
+
+       ret = regmap_read_poll_timeout(iqs62x->regmap, IQS62X_SYS_FLAGS, val,
+                                      !(val & IQS62X_SYS_FLAGS_IN_ATI),
+                                      IQS62X_ATI_POLL_SLEEP_US,
+                                      IQS62X_ATI_POLL_TIMEOUT_US * clk_div);
+       if (ret)
+               return ret;
+
+       msleep(IQS62X_ATI_STABLE_DELAY_MS * clk_div);
+
+       return 0;
+}
+
+static int iqs62x_firmware_parse(struct iqs62x_core *iqs62x,
+                                const struct firmware *fw)
+{
+       struct i2c_client *client = iqs62x->client;
+       struct iqs62x_fw_rec *fw_rec;
+       struct iqs62x_fw_blk *fw_blk;
+       unsigned int val;
+       size_t pos = 0;
+       int ret = 0;
+       u8 mask, len, *data;
+       u8 hall_cal_index = 0;
+
+       while (pos < fw->size) {
+               if (pos + sizeof(*fw_rec) > fw->size) {
+                       ret = -EINVAL;
+                       break;
+               }
+               fw_rec = (struct iqs62x_fw_rec *)(fw->data + pos);
+               pos += sizeof(*fw_rec);
+
+               if (pos + fw_rec->len - 1 > fw->size) {
+                       ret = -EINVAL;
+                       break;
+               }
+               pos += fw_rec->len - 1;
+
+               switch (fw_rec->type) {
+               case IQS62X_FW_REC_TYPE_INFO:
+                       continue;
+
+               case IQS62X_FW_REC_TYPE_PROD:
+                       if (fw_rec->data == iqs62x->dev_desc->prod_num)
+                               continue;
+
+                       dev_err(&client->dev,
+                               "Incompatible product number: 0x%02X\n",
+                               fw_rec->data);
+                       ret = -EINVAL;
+                       break;
+
+               case IQS62X_FW_REC_TYPE_HALL:
+                       if (!hall_cal_index) {
+                               ret = regmap_write(iqs62x->regmap,
+                                                  IQS62X_OTP_CMD,
+                                                  IQS62X_OTP_CMD_FG3);
+                               if (ret)
+                                       break;
+
+                               ret = regmap_read(iqs62x->regmap,
+                                                 IQS62X_OTP_DATA, &val);
+                               if (ret)
+                                       break;
+
+                               hall_cal_index = val & IQS62X_HALL_CAL_MASK;
+                               if (!hall_cal_index) {
+                                       dev_err(&client->dev,
+                                               "Uncalibrated device\n");
+                                       ret = -ENODATA;
+                                       break;
+                               }
+                       }
+
+                       if (hall_cal_index > fw_rec->len) {
+                               ret = -EINVAL;
+                               break;
+                       }
+
+                       mask = 0;
+                       data = &fw_rec->data + hall_cal_index - 1;
+                       len = sizeof(*data);
+                       break;
+
+               case IQS62X_FW_REC_TYPE_MASK:
+                       if (fw_rec->len < (sizeof(mask) + sizeof(*data))) {
+                               ret = -EINVAL;
+                               break;
+                       }
+
+                       mask = fw_rec->data;
+                       data = &fw_rec->data + sizeof(mask);
+                       len = sizeof(*data);
+                       break;
+
+               case IQS62X_FW_REC_TYPE_DATA:
+                       mask = 0;
+                       data = &fw_rec->data;
+                       len = fw_rec->len;
+                       break;
+
+               default:
+                       dev_err(&client->dev,
+                               "Unrecognized record type: 0x%02X\n",
+                               fw_rec->type);
+                       ret = -EINVAL;
+               }
+
+               if (ret)
+                       break;
+
+               fw_blk = devm_kzalloc(&client->dev,
+                                     struct_size(fw_blk, data, len),
+                                     GFP_KERNEL);
+               if (!fw_blk) {
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               fw_blk->addr = fw_rec->addr;
+               fw_blk->mask = mask;
+               fw_blk->len = len;
+               memcpy(fw_blk->data, data, len);
+
+               list_add(&fw_blk->list, &iqs62x->fw_blk_head);
+       }
+
+       release_firmware(fw);
+
+       return ret;
+}
+
+const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS] = {
+       [IQS62X_EVENT_PROX_CH0_T] = {
+               .reg    = IQS62X_EVENT_PROX,
+               .mask   = BIT(4),
+               .val    = BIT(4),
+       },
+       [IQS62X_EVENT_PROX_CH0_P] = {
+               .reg    = IQS62X_EVENT_PROX,
+               .mask   = BIT(0),
+               .val    = BIT(0),
+       },
+       [IQS62X_EVENT_PROX_CH1_T] = {
+               .reg    = IQS62X_EVENT_PROX,
+               .mask   = BIT(5),
+               .val    = BIT(5),
+       },
+       [IQS62X_EVENT_PROX_CH1_P] = {
+               .reg    = IQS62X_EVENT_PROX,
+               .mask   = BIT(1),
+               .val    = BIT(1),
+       },
+       [IQS62X_EVENT_PROX_CH2_T] = {
+               .reg    = IQS62X_EVENT_PROX,
+               .mask   = BIT(6),
+               .val    = BIT(6),
+       },
+       [IQS62X_EVENT_PROX_CH2_P] = {
+               .reg    = IQS62X_EVENT_PROX,
+               .mask   = BIT(2),
+               .val    = BIT(2),
+       },
+       [IQS62X_EVENT_HYST_POS_T] = {
+               .reg    = IQS62X_EVENT_HYST,
+               .mask   = BIT(6) | BIT(7),
+               .val    = BIT(6),
+       },
+       [IQS62X_EVENT_HYST_POS_P] = {
+               .reg    = IQS62X_EVENT_HYST,
+               .mask   = BIT(5) | BIT(7),
+               .val    = BIT(5),
+       },
+       [IQS62X_EVENT_HYST_NEG_T] = {
+               .reg    = IQS62X_EVENT_HYST,
+               .mask   = BIT(6) | BIT(7),
+               .val    = BIT(6) | BIT(7),
+       },
+       [IQS62X_EVENT_HYST_NEG_P] = {
+               .reg    = IQS62X_EVENT_HYST,
+               .mask   = BIT(5) | BIT(7),
+               .val    = BIT(5) | BIT(7),
+       },
+       [IQS62X_EVENT_SAR1_ACT] = {
+               .reg    = IQS62X_EVENT_HYST,
+               .mask   = BIT(4),
+               .val    = BIT(4),
+       },
+       [IQS62X_EVENT_SAR1_QRD] = {
+               .reg    = IQS62X_EVENT_HYST,
+               .mask   = BIT(2),
+               .val    = BIT(2),
+       },
+       [IQS62X_EVENT_SAR1_MOVE] = {
+               .reg    = IQS62X_EVENT_HYST,
+               .mask   = BIT(1),
+               .val    = BIT(1),
+       },
+       [IQS62X_EVENT_SAR1_HALT] = {
+               .reg    = IQS62X_EVENT_HYST,
+               .mask   = BIT(0),
+               .val    = BIT(0),
+       },
+       [IQS62X_EVENT_WHEEL_UP] = {
+               .reg    = IQS62X_EVENT_WHEEL,
+               .mask   = BIT(7) | BIT(6),
+               .val    = BIT(7),
+       },
+       [IQS62X_EVENT_WHEEL_DN] = {
+               .reg    = IQS62X_EVENT_WHEEL,
+               .mask   = BIT(7) | BIT(6),
+               .val    = BIT(7) | BIT(6),
+       },
+       [IQS62X_EVENT_HALL_N_T] = {
+               .reg    = IQS62X_EVENT_HALL,
+               .mask   = BIT(2) | BIT(0),
+               .val    = BIT(2),
+       },
+       [IQS62X_EVENT_HALL_N_P] = {
+               .reg    = IQS62X_EVENT_HALL,
+               .mask   = BIT(1) | BIT(0),
+               .val    = BIT(1),
+       },
+       [IQS62X_EVENT_HALL_S_T] = {
+               .reg    = IQS62X_EVENT_HALL,
+               .mask   = BIT(2) | BIT(0),
+               .val    = BIT(2) | BIT(0),
+       },
+       [IQS62X_EVENT_HALL_S_P] = {
+               .reg    = IQS62X_EVENT_HALL,
+               .mask   = BIT(1) | BIT(0),
+               .val    = BIT(1) | BIT(0),
+       },
+       [IQS62X_EVENT_SYS_RESET] = {
+               .reg    = IQS62X_EVENT_SYS,
+               .mask   = BIT(7),
+               .val    = BIT(7),
+       },
+};
+EXPORT_SYMBOL_GPL(iqs62x_events);
+
+static irqreturn_t iqs62x_irq(int irq, void *context)
+{
+       struct iqs62x_core *iqs62x = context;
+       struct i2c_client *client = iqs62x->client;
+       struct iqs62x_event_data event_data;
+       struct iqs62x_event_desc event_desc;
+       enum iqs62x_event_reg event_reg;
+       unsigned long event_flags = 0;
+       int ret, i, j;
+       u8 event_map[IQS62X_EVENT_SIZE];
+
+       /*
+        * The device asserts the RDY output to signal the beginning of a
+        * communication window, which is closed by an I2C stop condition.
+        * As such, all interrupt status is captured in a single read and
+        * broadcast to any interested sub-device drivers.
+        */
+       ret = regmap_raw_read(iqs62x->regmap, IQS62X_SYS_FLAGS, event_map,
+                             sizeof(event_map));
+       if (ret) {
+               dev_err(&client->dev, "Failed to read device status: %d\n",
+                       ret);
+               return IRQ_NONE;
+       }
+
+       for (i = 0; i < sizeof(event_map); i++) {
+               event_reg = iqs62x->dev_desc->event_regs[iqs62x->ui_sel][i];
+
+               switch (event_reg) {
+               case IQS62X_EVENT_UI_LO:
+                       event_data.ui_data = get_unaligned_le16(&event_map[i]);
+
+                       /* fall through */
+
+               case IQS62X_EVENT_UI_HI:
+               case IQS62X_EVENT_NONE:
+                       continue;
+
+               case IQS62X_EVENT_ALS:
+                       event_data.als_flags = event_map[i];
+                       continue;
+
+               case IQS62X_EVENT_IR:
+                       event_data.ir_flags = event_map[i];
+                       continue;
+
+               case IQS62X_EVENT_INTER:
+                       event_data.interval = event_map[i];
+                       continue;
+
+               case IQS62X_EVENT_HYST:
+                       event_map[i] <<= iqs62x->dev_desc->hyst_shift;
+
+                       /* fall through */
+
+               case IQS62X_EVENT_WHEEL:
+               case IQS62X_EVENT_HALL:
+               case IQS62X_EVENT_PROX:
+               case IQS62X_EVENT_SYS:
+                       break;
+               }
+
+               for (j = 0; j < IQS62X_NUM_EVENTS; j++) {
+                       event_desc = iqs62x_events[j];
+
+                       if (event_desc.reg != event_reg)
+                               continue;
+
+                       if ((event_map[i] & event_desc.mask) == event_desc.val)
+                               event_flags |= BIT(j);
+               }
+       }
+
+       /*
+        * The device resets itself in response to the I2C master stalling
+        * communication past a fixed timeout. In this case, all registers
+        * are restored and any interested sub-device drivers are notified.
+        */
+       if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {
+               dev_err(&client->dev, "Unexpected device reset\n");
+
+               ret = iqs62x_dev_init(iqs62x);
+               if (ret) {
+                       dev_err(&client->dev,
+                               "Failed to re-initialize device: %d\n", ret);
+                       return IRQ_NONE;
+               }
+       }
+
+       ret = blocking_notifier_call_chain(&iqs62x->nh, event_flags,
+                                          &event_data);
+       if (ret & NOTIFY_STOP_MASK)
+               return IRQ_NONE;
+
+       /*
+        * Once the communication window is closed, a small delay is added to
+        * ensure the device's RDY output has been deasserted by the time the
+        * interrupt handler returns.
+        */
+       usleep_range(50, 100);
+
+       return IRQ_HANDLED;
+}
+
+static void iqs62x_firmware_load(const struct firmware *fw, void *context)
+{
+       struct iqs62x_core *iqs62x = context;
+       struct i2c_client *client = iqs62x->client;
+       int ret;
+
+       if (fw) {
+               ret = iqs62x_firmware_parse(iqs62x, fw);
+               if (ret) {
+                       dev_err(&client->dev, "Failed to parse firmware: %d\n",
+                               ret);
+                       goto err_out;
+               }
+       }
+
+       ret = iqs62x_dev_init(iqs62x);
+       if (ret) {
+               dev_err(&client->dev, "Failed to initialize device: %d\n", ret);
+               goto err_out;
+       }
+
+       ret = devm_request_threaded_irq(&client->dev, client->irq,
+                                       NULL, iqs62x_irq, IRQF_ONESHOT,
+                                       client->name, iqs62x);
+       if (ret) {
+               dev_err(&client->dev, "Failed to request IRQ: %d\n", ret);
+               goto err_out;
+       }
+
+       ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
+                                  iqs62x->dev_desc->sub_devs,
+                                  iqs62x->dev_desc->num_sub_devs,
+                                  NULL, 0, NULL);
+       if (ret)
+               dev_err(&client->dev, "Failed to add sub-devices: %d\n", ret);
+
+err_out:
+       complete_all(&iqs62x->fw_done);
+}
+
+static const struct mfd_cell iqs620at_sub_devs[] = {
+       {
+               .name = "iqs62x-keys",
+               .of_compatible = "azoteq,iqs620a-keys",
+       },
+       {
+               .name = "iqs620a-pwm",
+               .of_compatible = "azoteq,iqs620a-pwm",
+       },
+       { .name = "iqs620at-temp", },
+};
+
+static const struct mfd_cell iqs620a_sub_devs[] = {
+       {
+               .name = "iqs62x-keys",
+               .of_compatible = "azoteq,iqs620a-keys",
+       },
+       {
+               .name = "iqs620a-pwm",
+               .of_compatible = "azoteq,iqs620a-pwm",
+       },
+};
+
+static const struct mfd_cell iqs621_sub_devs[] = {
+       {
+               .name = "iqs62x-keys",
+               .of_compatible = "azoteq,iqs621-keys",
+       },
+       { .name = "iqs621-als", },
+};
+
+static const struct mfd_cell iqs622_sub_devs[] = {
+       {
+               .name = "iqs62x-keys",
+               .of_compatible = "azoteq,iqs622-keys",
+       },
+       { .name = "iqs621-als", },
+};
+
+static const struct mfd_cell iqs624_sub_devs[] = {
+       {
+               .name = "iqs62x-keys",
+               .of_compatible = "azoteq,iqs624-keys",
+       },
+       { .name = "iqs624-pos", },
+};
+
+static const struct mfd_cell iqs625_sub_devs[] = {
+       {
+               .name = "iqs62x-keys",
+               .of_compatible = "azoteq,iqs625-keys",
+       },
+       { .name = "iqs624-pos", },
+};
+
+static const u8 iqs620at_cal_regs[] = {
+       IQS620_TEMP_CAL_MULT,
+       IQS620_TEMP_CAL_DIV,
+       IQS620_TEMP_CAL_OFFS,
+};
+
+static const u8 iqs621_cal_regs[] = {
+       IQS621_ALS_CAL_DIV_LUX,
+       IQS621_ALS_CAL_DIV_IR,
+};
+
+static const enum iqs62x_event_reg iqs620a_event_regs[][IQS62X_EVENT_SIZE] = {
+       [IQS62X_UI_PROX] = {
+               IQS62X_EVENT_SYS,       /* 0x10 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_PROX,      /* 0x12 */
+               IQS62X_EVENT_HYST,      /* 0x13 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_HALL,      /* 0x16 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+       },
+       [IQS62X_UI_SAR1] = {
+               IQS62X_EVENT_SYS,       /* 0x10 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_HYST,      /* 0x13 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_HALL,      /* 0x16 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+       },
+};
+
+static const enum iqs62x_event_reg iqs621_event_regs[][IQS62X_EVENT_SIZE] = {
+       [IQS62X_UI_PROX] = {
+               IQS62X_EVENT_SYS,       /* 0x10 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_PROX,      /* 0x12 */
+               IQS62X_EVENT_HYST,      /* 0x13 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_ALS,       /* 0x16 */
+               IQS62X_EVENT_UI_LO,     /* 0x17 */
+               IQS62X_EVENT_UI_HI,     /* 0x18 */
+               IQS62X_EVENT_HALL,      /* 0x19 */
+       },
+};
+
+static const enum iqs62x_event_reg iqs622_event_regs[][IQS62X_EVENT_SIZE] = {
+       [IQS62X_UI_PROX] = {
+               IQS62X_EVENT_SYS,       /* 0x10 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_PROX,      /* 0x12 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_ALS,       /* 0x14 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_IR,        /* 0x16 */
+               IQS62X_EVENT_UI_LO,     /* 0x17 */
+               IQS62X_EVENT_UI_HI,     /* 0x18 */
+               IQS62X_EVENT_HALL,      /* 0x19 */
+       },
+       [IQS62X_UI_SAR1] = {
+               IQS62X_EVENT_SYS,       /* 0x10 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_HYST,      /* 0x13 */
+               IQS62X_EVENT_ALS,       /* 0x14 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_IR,        /* 0x16 */
+               IQS62X_EVENT_UI_LO,     /* 0x17 */
+               IQS62X_EVENT_UI_HI,     /* 0x18 */
+               IQS62X_EVENT_HALL,      /* 0x19 */
+       },
+};
+
+static const enum iqs62x_event_reg iqs624_event_regs[][IQS62X_EVENT_SIZE] = {
+       [IQS62X_UI_PROX] = {
+               IQS62X_EVENT_SYS,       /* 0x10 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_PROX,      /* 0x12 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_WHEEL,     /* 0x14 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_UI_LO,     /* 0x16 */
+               IQS62X_EVENT_UI_HI,     /* 0x17 */
+               IQS62X_EVENT_INTER,     /* 0x18 */
+               IQS62X_EVENT_NONE,
+       },
+};
+
+static const enum iqs62x_event_reg iqs625_event_regs[][IQS62X_EVENT_SIZE] = {
+       [IQS62X_UI_PROX] = {
+               IQS62X_EVENT_SYS,       /* 0x10 */
+               IQS62X_EVENT_PROX,      /* 0x11 */
+               IQS62X_EVENT_INTER,     /* 0x12 */
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+               IQS62X_EVENT_NONE,
+       },
+};
+
+static const struct iqs62x_dev_desc iqs62x_devs[] = {
+       {
+               .dev_name       = "iqs620at",
+               .sub_devs       = iqs620at_sub_devs,
+               .num_sub_devs   = ARRAY_SIZE(iqs620at_sub_devs),
+
+               .prod_num       = IQS620_PROD_NUM,
+               .sw_num         = 0x08,
+               .cal_regs       = iqs620at_cal_regs,
+               .num_cal_regs   = ARRAY_SIZE(iqs620at_cal_regs),
+
+               .prox_mask      = BIT(0),
+               .sar_mask       = BIT(1) | BIT(7),
+               .hall_mask      = BIT(2),
+               .hyst_mask      = BIT(3),
+               .temp_mask      = BIT(4),
+
+               .prox_settings  = IQS620_PROX_SETTINGS_4,
+               .hall_flags     = IQS620_HALL_FLAGS,
+
+               .clk_div        = 4,
+               .fw_name        = "iqs620a.bin",
+               .event_regs     = &iqs620a_event_regs[IQS62X_UI_PROX],
+       },
+       {
+               .dev_name       = "iqs620a",
+               .sub_devs       = iqs620a_sub_devs,
+               .num_sub_devs   = ARRAY_SIZE(iqs620a_sub_devs),
+
+               .prod_num       = IQS620_PROD_NUM,
+               .sw_num         = 0x08,
+
+               .prox_mask      = BIT(0),
+               .sar_mask       = BIT(1) | BIT(7),
+               .hall_mask      = BIT(2),
+               .hyst_mask      = BIT(3),
+               .temp_mask      = BIT(4),
+
+               .prox_settings  = IQS620_PROX_SETTINGS_4,
+               .hall_flags     = IQS620_HALL_FLAGS,
+
+               .clk_div        = 4,
+               .fw_name        = "iqs620a.bin",
+               .event_regs     = &iqs620a_event_regs[IQS62X_UI_PROX],
+       },
+       {
+               .dev_name       = "iqs621",
+               .sub_devs       = iqs621_sub_devs,
+               .num_sub_devs   = ARRAY_SIZE(iqs621_sub_devs),
+
+               .prod_num       = IQS621_PROD_NUM,
+               .sw_num         = 0x09,
+               .cal_regs       = iqs621_cal_regs,
+               .num_cal_regs   = ARRAY_SIZE(iqs621_cal_regs),
+
+               .prox_mask      = BIT(0),
+               .hall_mask      = BIT(1),
+               .als_mask       = BIT(2),
+               .hyst_mask      = BIT(3),
+               .temp_mask      = BIT(4),
+
+               .als_flags      = IQS621_ALS_FLAGS,
+               .hall_flags     = IQS621_HALL_FLAGS,
+               .hyst_shift     = 5,
+
+               .clk_div        = 2,
+               .fw_name        = "iqs621.bin",
+               .event_regs     = &iqs621_event_regs[IQS62X_UI_PROX],
+       },
+       {
+               .dev_name       = "iqs622",
+               .sub_devs       = iqs622_sub_devs,
+               .num_sub_devs   = ARRAY_SIZE(iqs622_sub_devs),
+
+               .prod_num       = IQS622_PROD_NUM,
+               .sw_num         = 0x06,
+
+               .prox_mask      = BIT(0),
+               .sar_mask       = BIT(1),
+               .hall_mask      = BIT(2),
+               .als_mask       = BIT(3),
+               .ir_mask        = BIT(4),
+
+               .prox_settings  = IQS622_PROX_SETTINGS_4,
+               .als_flags      = IQS622_ALS_FLAGS,
+               .hall_flags     = IQS622_HALL_FLAGS,
+
+               .clk_div        = 2,
+               .fw_name        = "iqs622.bin",
+               .event_regs     = &iqs622_event_regs[IQS62X_UI_PROX],
+       },
+       {
+               .dev_name       = "iqs624",
+               .sub_devs       = iqs624_sub_devs,
+               .num_sub_devs   = ARRAY_SIZE(iqs624_sub_devs),
+
+               .prod_num       = IQS624_PROD_NUM,
+               .sw_num         = 0x0B,
+
+               .interval       = IQS624_INTERVAL_NUM,
+               .interval_div   = 3,
+
+               .clk_div        = 2,
+               .fw_name        = "iqs624.bin",
+               .event_regs     = &iqs624_event_regs[IQS62X_UI_PROX],
+       },
+       {
+               .dev_name       = "iqs625",
+               .sub_devs       = iqs625_sub_devs,
+               .num_sub_devs   = ARRAY_SIZE(iqs625_sub_devs),
+
+               .prod_num       = IQS625_PROD_NUM,
+               .sw_num         = 0x0B,
+
+               .interval       = IQS625_INTERVAL_NUM,
+               .interval_div   = 10,
+
+               .clk_div        = 2,
+               .fw_name        = "iqs625.bin",
+               .event_regs     = &iqs625_event_regs[IQS62X_UI_PROX],
+       },
+};
+
+static const struct regmap_config iqs62x_map_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = IQS62X_MAX_REG,
+};
+
+static int iqs62x_probe(struct i2c_client *client)
+{
+       struct iqs62x_core *iqs62x;
+       struct iqs62x_info info;
+       unsigned int val;
+       int ret, i, j;
+       u8 sw_num = 0;
+       const char *fw_name = NULL;
+
+       iqs62x = devm_kzalloc(&client->dev, sizeof(*iqs62x), GFP_KERNEL);
+       if (!iqs62x)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, iqs62x);
+       iqs62x->client = client;
+
+       BLOCKING_INIT_NOTIFIER_HEAD(&iqs62x->nh);
+       INIT_LIST_HEAD(&iqs62x->fw_blk_head);
+       init_completion(&iqs62x->fw_done);
+
+       iqs62x->regmap = devm_regmap_init_i2c(client, &iqs62x_map_config);
+       if (IS_ERR(iqs62x->regmap)) {
+               ret = PTR_ERR(iqs62x->regmap);
+               dev_err(&client->dev, "Failed to initialize register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       ret = regmap_raw_read(iqs62x->regmap, IQS62X_PROD_NUM, &info,
+                             sizeof(info));
+       if (ret)
+               return ret;
+
+       /*
+        * The following sequence validates the device's product and software
+        * numbers. It then determines if the device is factory-calibrated by
+        * checking for nonzero values in the device's designated calibration
+        * registers (if applicable). Depending on the device, the absence of
+        * calibration data indicates a reduced feature set or invalid device.
+        *
+        * For devices given in both calibrated and uncalibrated versions, the
+        * calibrated version (e.g. IQS620AT) appears first in the iqs62x_devs
+        * array. The uncalibrated version (e.g. IQS620A) appears next and has
+        * the same product and software numbers, but no calibration registers
+        * are specified.
+        */
+       for (i = 0; i < ARRAY_SIZE(iqs62x_devs); i++) {
+               if (info.prod_num != iqs62x_devs[i].prod_num)
+                       continue;
+
+               iqs62x->dev_desc = &iqs62x_devs[i];
+
+               if (info.sw_num < iqs62x->dev_desc->sw_num)
+                       continue;
+
+               sw_num = info.sw_num;
+
+               /*
+                * Read each of the device's designated calibration registers,
+                * if any, and exit from the inner loop early if any are equal
+                * to zero (indicating the device is uncalibrated). This could
+                * be acceptable depending on the device (e.g. IQS620A instead
+                * of IQS620AT).
+                */
+               for (j = 0; j < iqs62x->dev_desc->num_cal_regs; j++) {
+                       ret = regmap_read(iqs62x->regmap,
+                                         iqs62x->dev_desc->cal_regs[j], &val);
+                       if (ret)
+                               return ret;
+
+                       if (!val)
+                               break;
+               }
+
+               /*
+                * If the number of nonzero values read from the device equals
+                * the number of designated calibration registers (which could
+                * be zero), exit from the outer loop early to signal that the
+                * device's product and software numbers match a known device,
+                * and the device is calibrated (if applicable).
+                */
+               if (j == iqs62x->dev_desc->num_cal_regs)
+                       break;
+       }
+
+       if (!iqs62x->dev_desc) {
+               dev_err(&client->dev, "Unrecognized product number: 0x%02X\n",
+                       info.prod_num);
+               return -EINVAL;
+       }
+
+       if (!sw_num) {
+               dev_err(&client->dev, "Unrecognized software number: 0x%02X\n",
+                       info.sw_num);
+               return -EINVAL;
+       }
+
+       if (i == ARRAY_SIZE(iqs62x_devs)) {
+               dev_err(&client->dev, "Uncalibrated device\n");
+               return -ENODATA;
+       }
+
+       device_property_read_string(&client->dev, "firmware-name", &fw_name);
+
+       ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+                                     fw_name ? : iqs62x->dev_desc->fw_name,
+                                     &client->dev, GFP_KERNEL, iqs62x,
+                                     iqs62x_firmware_load);
+       if (ret)
+               dev_err(&client->dev, "Failed to request firmware: %d\n", ret);
+
+       return ret;
+}
+
+static int iqs62x_remove(struct i2c_client *client)
+{
+       struct iqs62x_core *iqs62x = i2c_get_clientdata(client);
+
+       wait_for_completion(&iqs62x->fw_done);
+
+       return 0;
+}
+
+static int __maybe_unused iqs62x_suspend(struct device *dev)
+{
+       struct iqs62x_core *iqs62x = dev_get_drvdata(dev);
+       int ret;
+
+       wait_for_completion(&iqs62x->fw_done);
+
+       /*
+        * As per the datasheet, automatic mode switching must be disabled
+        * before the device is placed in or taken out of halt mode.
+        */
+       ret = regmap_update_bits(iqs62x->regmap, IQS62X_PWR_SETTINGS,
+                                IQS62X_PWR_SETTINGS_DIS_AUTO, 0xFF);
+       if (ret)
+               return ret;
+
+       return regmap_update_bits(iqs62x->regmap, IQS62X_PWR_SETTINGS,
+                                 IQS62X_PWR_SETTINGS_PWR_MODE_MASK,
+                                 IQS62X_PWR_SETTINGS_PWR_MODE_HALT);
+}
+
+static int __maybe_unused iqs62x_resume(struct device *dev)
+{
+       struct iqs62x_core *iqs62x = dev_get_drvdata(dev);
+       int ret;
+
+       ret = regmap_update_bits(iqs62x->regmap, IQS62X_PWR_SETTINGS,
+                                IQS62X_PWR_SETTINGS_PWR_MODE_MASK,
+                                IQS62X_PWR_SETTINGS_PWR_MODE_NORM);
+       if (ret)
+               return ret;
+
+       return regmap_update_bits(iqs62x->regmap, IQS62X_PWR_SETTINGS,
+                                 IQS62X_PWR_SETTINGS_DIS_AUTO, 0);
+}
+
+static SIMPLE_DEV_PM_OPS(iqs62x_pm, iqs62x_suspend, iqs62x_resume);
+
+static const struct of_device_id iqs62x_of_match[] = {
+       { .compatible = "azoteq,iqs620a" },
+       { .compatible = "azoteq,iqs621" },
+       { .compatible = "azoteq,iqs622" },
+       { .compatible = "azoteq,iqs624" },
+       { .compatible = "azoteq,iqs625" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, iqs62x_of_match);
+
+static struct i2c_driver iqs62x_i2c_driver = {
+       .driver = {
+               .name = "iqs62x",
+               .of_match_table = iqs62x_of_match,
+               .pm = &iqs62x_pm,
+       },
+       .probe_new = iqs62x_probe,
+       .remove = iqs62x_remove,
+};
+module_i2c_driver(iqs62x_i2c_driver);
+
+MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
+MODULE_DESCRIPTION("Azoteq IQS620A/621/622/624/625 Multi-Function Sensors");
+MODULE_LICENSE("GPL");
index 4798d9f..1f4f01b 100644 (file)
@@ -840,7 +840,7 @@ MODULE_DEVICE_TABLE(of, usbhs_omap_dt_ids);
 
 static struct platform_driver usbhs_omap_driver = {
        .driver = {
-               .name           = (char *)usbhs_driver_name,
+               .name           = usbhs_driver_name,
                .pm             = &usbhsomap_dev_pm_ops,
                .of_match_table = usbhs_omap_dt_ids,
        },
index 265f5e3..4b7f73c 100644 (file)
@@ -99,7 +99,7 @@
 struct usbtll_omap {
        void __iomem    *base;
        int             nch;            /* num. of channels */
-       struct clk      *ch_clk[0];     /* must be the last member */
+       struct clk      *ch_clk[];      /* must be the last member */
 };
 
 /*-------------------------------------------------------------------------*/
@@ -304,7 +304,7 @@ MODULE_DEVICE_TABLE(of, usbtll_omap_dt_ids);
 
 static struct platform_driver usbtll_omap_driver = {
        .driver = {
-               .name           = (char *)usbtll_driver_name,
+               .name           = usbtll_driver_name,
                .of_match_table = usbtll_omap_dt_ids,
        },
        .probe          = usbtll_omap_probe,
index 2913332..acd172d 100644 (file)
@@ -76,7 +76,7 @@ struct pm_irq_chip {
        unsigned int            num_masters;
        const struct pm_irq_data *pm_irq_data;
        /* MUST BE AT THE END OF THIS STRUCT */
-       u8                      config[0];
+       u8                      config[];
 };
 
 static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp,
index a69a674..d109b9f 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/regmap.h>
-#include <linux/syscore_ops.h>
 
 struct rk808_reg_data {
        int addr;
@@ -186,7 +185,6 @@ static const struct rk808_reg_data rk805_pre_init_reg[] = {
        {RK805_BUCK4_CONFIG_REG, RK805_BUCK3_4_ILMAX_MASK,
                                 RK805_BUCK4_ILMAX_3500MA},
        {RK805_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_400MA},
-       {RK805_GPIO_IO_POL_REG, SLP_SD_MSK, SLEEP_FUN},
        {RK805_THERMAL_REG, TEMP_HOTDIE_MSK, TEMP115C},
 };
 
@@ -449,88 +447,60 @@ static const struct regmap_irq_chip rk818_irq_chip = {
 
 static struct i2c_client *rk808_i2c_client;
 
-static void rk805_device_shutdown(void)
+static void rk808_pm_power_off(void)
 {
        int ret;
+       unsigned int reg, bit;
        struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
 
-       if (!rk808)
-               return;
-
-       ret = regmap_update_bits(rk808->regmap,
-                                RK805_DEV_CTRL_REG,
-                                DEV_OFF, DEV_OFF);
-       if (ret)
-               dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
-}
-
-static void rk805_device_shutdown_prepare(void)
-{
-       int ret;
-       struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
-
-       if (!rk808)
-               return;
-
-       ret = regmap_update_bits(rk808->regmap,
-                                RK805_GPIO_IO_POL_REG,
-                                SLP_SD_MSK, SHUTDOWN_FUN);
-       if (ret)
-               dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
-}
-
-static void rk808_device_shutdown(void)
-{
-       int ret;
-       struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
-
-       if (!rk808)
-               return;
-
-       ret = regmap_update_bits(rk808->regmap,
-                                RK808_DEVCTRL_REG,
-                                DEV_OFF_RST, DEV_OFF_RST);
-       if (ret)
-               dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
-}
-
-static void rk818_device_shutdown(void)
-{
-       int ret;
-       struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
-
-       if (!rk808)
+       switch (rk808->variant) {
+       case RK805_ID:
+               reg = RK805_DEV_CTRL_REG;
+               bit = DEV_OFF;
+               break;
+       case RK808_ID:
+               reg = RK808_DEVCTRL_REG,
+               bit = DEV_OFF_RST;
+               break;
+       case RK818_ID:
+               reg = RK818_DEVCTRL_REG;
+               bit = DEV_OFF;
+               break;
+       default:
                return;
-
-       ret = regmap_update_bits(rk808->regmap,
-                                RK818_DEVCTRL_REG,
-                                DEV_OFF, DEV_OFF);
+       }
+       ret = regmap_update_bits(rk808->regmap, reg, bit, bit);
        if (ret)
                dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
 }
 
-static void rk8xx_syscore_shutdown(void)
+static void rk8xx_shutdown(struct i2c_client *client)
 {
-       struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
+       struct rk808 *rk808 = i2c_get_clientdata(client);
        int ret;
 
-       if (system_state == SYSTEM_POWER_OFF &&
-           (rk808->variant == RK809_ID || rk808->variant == RK817_ID)) {
+       switch (rk808->variant) {
+       case RK805_ID:
+               ret = regmap_update_bits(rk808->regmap,
+                                        RK805_GPIO_IO_POL_REG,
+                                        SLP_SD_MSK,
+                                        SHUTDOWN_FUN);
+               break;
+       case RK809_ID:
+       case RK817_ID:
                ret = regmap_update_bits(rk808->regmap,
                                         RK817_SYS_CFG(3),
                                         RK817_SLPPIN_FUNC_MSK,
                                         SLPPIN_DN_FUN);
-               if (ret) {
-                       dev_warn(&rk808_i2c_client->dev,
-                                "Cannot switch to power down function\n");
-               }
+               break;
+       default:
+               return;
        }
+       if (ret)
+               dev_warn(&client->dev,
+                        "Cannot switch to power down function\n");
 }
 
-static struct syscore_ops rk808_syscore_ops = {
-       .shutdown = rk8xx_syscore_shutdown,
-};
-
 static const struct of_device_id rk808_of_match[] = {
        { .compatible = "rockchip,rk805" },
        { .compatible = "rockchip,rk808" },
@@ -550,7 +520,7 @@ static int rk808_probe(struct i2c_client *client,
        const struct mfd_cell *cells;
        int nr_pre_init_regs;
        int nr_cells;
-       int pm_off = 0, msb, lsb;
+       int msb, lsb;
        unsigned char pmic_id_msb, pmic_id_lsb;
        int ret;
        int i;
@@ -594,8 +564,6 @@ static int rk808_probe(struct i2c_client *client,
                nr_pre_init_regs = ARRAY_SIZE(rk805_pre_init_reg);
                cells = rk805s;
                nr_cells = ARRAY_SIZE(rk805s);
-               rk808->pm_pwroff_fn = rk805_device_shutdown;
-               rk808->pm_pwroff_prep_fn = rk805_device_shutdown_prepare;
                break;
        case RK808_ID:
                rk808->regmap_cfg = &rk808_regmap_config;
@@ -604,7 +572,6 @@ static int rk808_probe(struct i2c_client *client,
                nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg);
                cells = rk808s;
                nr_cells = ARRAY_SIZE(rk808s);
-               rk808->pm_pwroff_fn = rk808_device_shutdown;
                break;
        case RK818_ID:
                rk808->regmap_cfg = &rk818_regmap_config;
@@ -613,7 +580,6 @@ static int rk808_probe(struct i2c_client *client,
                nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg);
                cells = rk818s;
                nr_cells = ARRAY_SIZE(rk818s);
-               rk808->pm_pwroff_fn = rk818_device_shutdown;
                break;
        case RK809_ID:
        case RK817_ID:
@@ -623,7 +589,6 @@ static int rk808_probe(struct i2c_client *client,
                nr_pre_init_regs = ARRAY_SIZE(rk817_pre_init_reg);
                cells = rk817s;
                nr_cells = ARRAY_SIZE(rk817s);
-               register_syscore_ops(&rk808_syscore_ops);
                break;
        default:
                dev_err(&client->dev, "Unsupported RK8XX ID %lu\n",
@@ -674,17 +639,9 @@ static int rk808_probe(struct i2c_client *client,
                goto err_irq;
        }
 
-       pm_off = of_property_read_bool(np,
-                               "rockchip,system-power-controller");
-       if (pm_off && !pm_power_off) {
+       if (of_property_read_bool(np, "rockchip,system-power-controller")) {
                rk808_i2c_client = client;
-               pm_power_off = rk808->pm_pwroff_fn;
-       }
-
-       if (pm_off && !pm_power_off_prepare) {
-               if (!rk808_i2c_client)
-                       rk808_i2c_client = client;
-               pm_power_off_prepare = rk808->pm_pwroff_prep_fn;
+               pm_power_off = rk808_pm_power_off;
        }
 
        return 0;
@@ -704,25 +661,24 @@ static int rk808_remove(struct i2c_client *client)
         * pm_power_off may points to a function from another module.
         * Check if the pointer is set by us and only then overwrite it.
         */
-       if (rk808->pm_pwroff_fn && pm_power_off == rk808->pm_pwroff_fn)
+       if (pm_power_off == rk808_pm_power_off)
                pm_power_off = NULL;
 
-       /**
-        * As above, check if the pointer is set by us before overwrite.
-        */
-       if (rk808->pm_pwroff_prep_fn &&
-           pm_power_off_prepare == rk808->pm_pwroff_prep_fn)
-               pm_power_off_prepare = NULL;
-
        return 0;
 }
 
 static int __maybe_unused rk8xx_suspend(struct device *dev)
 {
-       struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
+       struct rk808 *rk808 = i2c_get_clientdata(to_i2c_client(dev));
        int ret = 0;
 
        switch (rk808->variant) {
+       case RK805_ID:
+               ret = regmap_update_bits(rk808->regmap,
+                                        RK805_GPIO_IO_POL_REG,
+                                        SLP_SD_MSK,
+                                        SLEEP_FUN);
+               break;
        case RK809_ID:
        case RK817_ID:
                ret = regmap_update_bits(rk808->regmap,
@@ -739,7 +695,7 @@ static int __maybe_unused rk8xx_suspend(struct device *dev)
 
 static int __maybe_unused rk8xx_resume(struct device *dev)
 {
-       struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
+       struct rk808 *rk808 = i2c_get_clientdata(to_i2c_client(dev));
        int ret = 0;
 
        switch (rk808->variant) {
@@ -766,6 +722,7 @@ static struct i2c_driver rk808_i2c_driver = {
        },
        .probe    = rk808_probe,
        .remove   = rk808_remove,
+       .shutdown = rk8xx_shutdown,
 };
 
 module_i2c_driver(rk808_i2c_driver);
index ead2e79..232de50 100644 (file)
@@ -8,10 +8,13 @@
 
 #include <linux/delay.h>
 #include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/rn5t618.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/platform_device.h>
 #include <linux/reboot.h>
 #include <linux/regmap.h>
 
@@ -20,6 +23,13 @@ static const struct mfd_cell rn5t618_cells[] = {
        { .name = "rn5t618-wdt" },
 };
 
+static const struct mfd_cell rc5t619_cells[] = {
+       { .name = "rn5t618-adc" },
+       { .name = "rn5t618-regulator" },
+       { .name = "rc5t619-rtc" },
+       { .name = "rn5t618-wdt" },
+};
+
 static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -32,6 +42,8 @@ static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg)
        case RN5T618_IR_GPF:
        case RN5T618_MON_IOIN:
        case RN5T618_INTMON:
+       case RN5T618_RTC_CTRL1 ... RN5T618_RTC_CTRL2:
+       case RN5T618_RTC_SECONDS ... RN5T618_RTC_YEAR:
                return true;
        default:
                return false;
@@ -46,9 +58,56 @@ static const struct regmap_config rn5t618_regmap_config = {
        .cache_type     = REGCACHE_RBTREE,
 };
 
+static const struct regmap_irq rc5t619_irqs[] = {
+       REGMAP_IRQ_REG(RN5T618_IRQ_SYS, 0, BIT(0)),
+       REGMAP_IRQ_REG(RN5T618_IRQ_DCDC, 0, BIT(1)),
+       REGMAP_IRQ_REG(RN5T618_IRQ_RTC, 0, BIT(2)),
+       REGMAP_IRQ_REG(RN5T618_IRQ_ADC, 0, BIT(3)),
+       REGMAP_IRQ_REG(RN5T618_IRQ_GPIO, 0, BIT(4)),
+       REGMAP_IRQ_REG(RN5T618_IRQ_CHG, 0, BIT(6)),
+};
+
+static const struct regmap_irq_chip rc5t619_irq_chip = {
+       .name = "rc5t619",
+       .irqs = rc5t619_irqs,
+       .num_irqs = ARRAY_SIZE(rc5t619_irqs),
+       .num_regs = 1,
+       .status_base = RN5T618_INTMON,
+       .mask_base = RN5T618_INTEN,
+       .mask_invert = true,
+};
+
 static struct rn5t618 *rn5t618_pm_power_off;
 static struct notifier_block rn5t618_restart_handler;
 
+static int rn5t618_irq_init(struct rn5t618 *rn5t618)
+{
+       const struct regmap_irq_chip *irq_chip = NULL;
+       int ret;
+
+       if (!rn5t618->irq)
+               return 0;
+
+       switch (rn5t618->variant) {
+       case RC5T619:
+               irq_chip = &rc5t619_irq_chip;
+               break;
+       default:
+               dev_err(rn5t618->dev, "Currently no IRQ support for variant %d\n",
+                       (int)rn5t618->variant);
+               return -ENOENT;
+       }
+
+       ret = devm_regmap_add_irq_chip(rn5t618->dev, rn5t618->regmap,
+                                      rn5t618->irq,
+                                      IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                      0, irq_chip, &rn5t618->irq_data);
+       if (ret)
+               dev_err(rn5t618->dev, "Failed to register IRQ chip\n");
+
+       return ret;
+}
+
 static void rn5t618_trigger_poweroff_sequence(bool repower)
 {
        /* disable automatic repower-on */
@@ -87,8 +146,7 @@ static const struct of_device_id rn5t618_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, rn5t618_of_match);
 
-static int rn5t618_i2c_probe(struct i2c_client *i2c,
-                            const struct i2c_device_id *id)
+static int rn5t618_i2c_probe(struct i2c_client *i2c)
 {
        const struct of_device_id *of_id;
        struct rn5t618 *priv;
@@ -106,6 +164,8 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c,
 
        i2c_set_clientdata(i2c, priv);
        priv->variant = (long)of_id->data;
+       priv->irq = i2c->irq;
+       priv->dev = &i2c->dev;
 
        priv->regmap = devm_regmap_init_i2c(i2c, &rn5t618_regmap_config);
        if (IS_ERR(priv->regmap)) {
@@ -114,8 +174,16 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
 
-       ret = devm_mfd_add_devices(&i2c->dev, -1, rn5t618_cells,
-                                  ARRAY_SIZE(rn5t618_cells), NULL, 0, NULL);
+       if (priv->variant == RC5T619)
+               ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_NONE,
+                                          rc5t619_cells,
+                                          ARRAY_SIZE(rc5t619_cells),
+                                          NULL, 0, NULL);
+       else
+               ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_NONE,
+                                          rn5t618_cells,
+                                          ARRAY_SIZE(rn5t618_cells),
+                                          NULL, 0, NULL);
        if (ret) {
                dev_err(&i2c->dev, "failed to add sub-devices: %d\n", ret);
                return ret;
@@ -138,7 +206,7 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
 
-       return 0;
+       return rn5t618_irq_init(priv);
 }
 
 static int rn5t618_i2c_remove(struct i2c_client *i2c)
@@ -155,19 +223,38 @@ static int rn5t618_i2c_remove(struct i2c_client *i2c)
        return 0;
 }
 
-static const struct i2c_device_id rn5t618_i2c_id[] = {
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, rn5t618_i2c_id);
+static int __maybe_unused rn5t618_i2c_suspend(struct device *dev)
+{
+       struct rn5t618 *priv = dev_get_drvdata(dev);
+
+       if (priv->irq)
+               disable_irq(priv->irq);
+
+       return 0;
+}
+
+static int __maybe_unused rn5t618_i2c_resume(struct device *dev)
+{
+       struct rn5t618 *priv = dev_get_drvdata(dev);
+
+       if (priv->irq)
+               enable_irq(priv->irq);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rn5t618_i2c_dev_pm_ops,
+                       rn5t618_i2c_suspend,
+                       rn5t618_i2c_resume);
 
 static struct i2c_driver rn5t618_i2c_driver = {
        .driver = {
                .name = "rn5t618",
                .of_match_table = of_match_ptr(rn5t618_of_match),
+               .pm = &rn5t618_i2c_dev_pm_ops,
        },
-       .probe = rn5t618_i2c_probe,
+       .probe_new = rn5t618_i2c_probe,
        .remove = rn5t618_i2c_remove,
-       .id_table = rn5t618_i2c_id,
 };
 
 module_i2c_driver(rn5t618_i2c_driver);
index c0529a1..ebdf2f1 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/of_device.h>
 #include <linux/regmap.h>
 #include <linux/spi/spi.h>
+#include <uapi/linux/usb/charger.h>
 
 #define SPRD_PMIC_INT_MASK_STATUS      0x0
 #define SPRD_PMIC_INT_RAW_STATUS       0x4
 
 #define SPRD_SC2731_IRQ_BASE           0x140
 #define SPRD_SC2731_IRQ_NUMS           16
+#define SPRD_SC2731_CHG_DET            0xedc
+
+/* PMIC charger detection definition */
+#define SPRD_PMIC_CHG_DET_DELAY_US     200000
+#define SPRD_PMIC_CHG_DET_TIMEOUT      2000000
+#define SPRD_PMIC_CHG_DET_DONE         BIT(11)
+#define SPRD_PMIC_SDP_TYPE             BIT(7)
+#define SPRD_PMIC_DCP_TYPE             BIT(6)
+#define SPRD_PMIC_CDP_TYPE             BIT(5)
+#define SPRD_PMIC_CHG_TYPE_MASK                GENMASK(7, 5)
 
 struct sprd_pmic {
        struct regmap *regmap;
@@ -24,12 +35,14 @@ struct sprd_pmic {
        struct regmap_irq *irqs;
        struct regmap_irq_chip irq_chip;
        struct regmap_irq_chip_data *irq_data;
+       const struct sprd_pmic_data *pdata;
        int irq;
 };
 
 struct sprd_pmic_data {
        u32 irq_base;
        u32 num_irqs;
+       u32 charger_det;
 };
 
 /*
@@ -40,8 +53,46 @@ struct sprd_pmic_data {
 static const struct sprd_pmic_data sc2731_data = {
        .irq_base = SPRD_SC2731_IRQ_BASE,
        .num_irqs = SPRD_SC2731_IRQ_NUMS,
+       .charger_det = SPRD_SC2731_CHG_DET,
 };
 
+enum usb_charger_type sprd_pmic_detect_charger_type(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct sprd_pmic *ddata = spi_get_drvdata(spi);
+       const struct sprd_pmic_data *pdata = ddata->pdata;
+       enum usb_charger_type type;
+       u32 val;
+       int ret;
+
+       ret = regmap_read_poll_timeout(ddata->regmap, pdata->charger_det, val,
+                                      (val & SPRD_PMIC_CHG_DET_DONE),
+                                      SPRD_PMIC_CHG_DET_DELAY_US,
+                                      SPRD_PMIC_CHG_DET_TIMEOUT);
+       if (ret) {
+               dev_err(&spi->dev, "failed to detect charger type\n");
+               return UNKNOWN_TYPE;
+       }
+
+       switch (val & SPRD_PMIC_CHG_TYPE_MASK) {
+       case SPRD_PMIC_CDP_TYPE:
+               type = CDP_TYPE;
+               break;
+       case SPRD_PMIC_DCP_TYPE:
+               type = DCP_TYPE;
+               break;
+       case SPRD_PMIC_SDP_TYPE:
+               type = SDP_TYPE;
+               break;
+       default:
+               type = UNKNOWN_TYPE;
+               break;
+       }
+
+       return type;
+}
+EXPORT_SYMBOL_GPL(sprd_pmic_detect_charger_type);
+
 static const struct mfd_cell sprd_pmic_devs[] = {
        {
                .name = "sc27xx-wdt",
@@ -181,6 +232,7 @@ static int sprd_pmic_probe(struct spi_device *spi)
        spi_set_drvdata(spi, ddata);
        ddata->dev = &spi->dev;
        ddata->irq = spi->irq;
+       ddata->pdata = pdata;
 
        ddata->irq_chip.name = dev_name(&spi->dev);
        ddata->irq_chip.status_base =
index b6841ba..8f201d0 100644 (file)
@@ -133,8 +133,4 @@ config VOP
          OS and tools for MIC to use with this driver are available from
          <http://software.intel.com/en-us/mic-developer>.
 
-if VOP
-source "drivers/vhost/Kconfig.vringh"
-endif
-
 endmenu
index e74e2bb..9db0570 100644 (file)
@@ -58,8 +58,4 @@ config CAIF_VIRTIO
        ---help---
          The CAIF driver for CAIF over Virtio.
 
-if CAIF_VIRTIO
-source "drivers/vhost/Kconfig.vringh"
-endif
-
 endif # CAIF_DRIVERS
index a8b5159..09087c3 100644 (file)
@@ -1042,8 +1042,10 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
                        return -EFAULT;
        }
 
-       if (!desc || (desc->out_num + desc->in_num == 0) ||
-                       !test_bit(cmd, &cmd_mask))
+       if (!desc ||
+           (desc->out_num + desc->in_num == 0) ||
+           cmd > ND_CMD_CALL ||
+           !test_bit(cmd, &cmd_mask))
                return -ENOTTY;
 
        /* fail write commands (when read-only) */
index 64776ed..7d4ddc4 100644 (file)
@@ -99,7 +99,7 @@ static int nvdimm_probe(struct device *dev)
        if (ndd->ns_current >= 0) {
                rc = nd_label_reserve_dpa(ndd);
                if (rc == 0)
-                       nvdimm_set_aliasing(dev);
+                       nvdimm_set_labeling(dev);
        }
        nvdimm_bus_unlock(dev);
 
index 94ea6db..b7b77e8 100644 (file)
@@ -32,7 +32,7 @@ int nvdimm_check_config_data(struct device *dev)
 
        if (!nvdimm->cmd_mask ||
            !test_bit(ND_CMD_GET_CONFIG_DATA, &nvdimm->cmd_mask)) {
-               if (test_bit(NDD_ALIASING, &nvdimm->flags))
+               if (test_bit(NDD_LABELING, &nvdimm->flags))
                        return -ENXIO;
                else
                        return -ENOTTY;
@@ -173,11 +173,11 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
        return rc;
 }
 
-void nvdimm_set_aliasing(struct device *dev)
+void nvdimm_set_labeling(struct device *dev)
 {
        struct nvdimm *nvdimm = to_nvdimm(dev);
 
-       set_bit(NDD_ALIASING, &nvdimm->flags);
+       set_bit(NDD_LABELING, &nvdimm->flags);
 }
 
 void nvdimm_set_locked(struct device *dev)
@@ -312,8 +312,9 @@ static ssize_t flags_show(struct device *dev,
 {
        struct nvdimm *nvdimm = to_nvdimm(dev);
 
-       return sprintf(buf, "%s%s\n",
+       return sprintf(buf, "%s%s%s\n",
                        test_bit(NDD_ALIASING, &nvdimm->flags) ? "alias " : "",
+                       test_bit(NDD_LABELING, &nvdimm->flags) ? "label " : "",
                        test_bit(NDD_LOCKED, &nvdimm->flags) ? "lock " : "");
 }
 static DEVICE_ATTR_RO(flags);
@@ -562,6 +563,21 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm)
        return rc;
 }
 
+static unsigned long dpa_align(struct nd_region *nd_region)
+{
+       struct device *dev = &nd_region->dev;
+
+       if (dev_WARN_ONCE(dev, !is_nvdimm_bus_locked(dev),
+                               "bus lock required for capacity provision\n"))
+               return 0;
+       if (dev_WARN_ONCE(dev, !nd_region->ndr_mappings || nd_region->align
+                               % nd_region->ndr_mappings,
+                               "invalid region align %#lx mappings: %d\n",
+                               nd_region->align, nd_region->ndr_mappings))
+               return 0;
+       return nd_region->align / nd_region->ndr_mappings;
+}
+
 int alias_dpa_busy(struct device *dev, void *data)
 {
        resource_size_t map_end, blk_start, new;
@@ -570,6 +586,7 @@ int alias_dpa_busy(struct device *dev, void *data)
        struct nd_region *nd_region;
        struct nvdimm_drvdata *ndd;
        struct resource *res;
+       unsigned long align;
        int i;
 
        if (!is_memory(dev))
@@ -607,13 +624,21 @@ int alias_dpa_busy(struct device *dev, void *data)
         * Find the free dpa from the end of the last pmem allocation to
         * the end of the interleave-set mapping.
         */
+       align = dpa_align(nd_region);
+       if (!align)
+               return 0;
+
        for_each_dpa_resource(ndd, res) {
+               resource_size_t start, end;
+
                if (strncmp(res->name, "pmem", 4) != 0)
                        continue;
-               if ((res->start >= blk_start && res->start < map_end)
-                               || (res->end >= blk_start
-                                       && res->end <= map_end)) {
-                       new = max(blk_start, min(map_end + 1, res->end + 1));
+
+               start = ALIGN_DOWN(res->start, align);
+               end = ALIGN(res->end + 1, align) - 1;
+               if ((start >= blk_start && start < map_end)
+                               || (end >= blk_start && end <= map_end)) {
+                       new = max(blk_start, min(map_end, end) + 1);
                        if (new != blk_start) {
                                blk_start = new;
                                goto retry;
@@ -653,6 +678,7 @@ resource_size_t nd_blk_available_dpa(struct nd_region *nd_region)
                .res = NULL,
        };
        struct resource *res;
+       unsigned long align;
 
        if (!ndd)
                return 0;
@@ -660,10 +686,20 @@ resource_size_t nd_blk_available_dpa(struct nd_region *nd_region)
        device_for_each_child(&nvdimm_bus->dev, &info, alias_dpa_busy);
 
        /* now account for busy blk allocations in unaliased dpa */
+       align = dpa_align(nd_region);
+       if (!align)
+               return 0;
        for_each_dpa_resource(ndd, res) {
+               resource_size_t start, end, size;
+
                if (strncmp(res->name, "blk", 3) != 0)
                        continue;
-               info.available -= resource_size(res);
+               start = ALIGN_DOWN(res->start, align);
+               end = ALIGN(res->end + 1, align) - 1;
+               size = end - start + 1;
+               if (size >= info.available)
+                       return 0;
+               info.available -= size;
        }
 
        return info.available;
@@ -682,19 +718,31 @@ resource_size_t nd_pmem_max_contiguous_dpa(struct nd_region *nd_region,
        struct nvdimm_bus *nvdimm_bus;
        resource_size_t max = 0;
        struct resource *res;
+       unsigned long align;
 
        /* if a dimm is disabled the available capacity is zero */
        if (!ndd)
                return 0;
 
+       align = dpa_align(nd_region);
+       if (!align)
+               return 0;
+
        nvdimm_bus = walk_to_nvdimm_bus(ndd->dev);
        if (__reserve_free_pmem(&nd_region->dev, nd_mapping->nvdimm))
                return 0;
        for_each_dpa_resource(ndd, res) {
+               resource_size_t start, end;
+
                if (strcmp(res->name, "pmem-reserve") != 0)
                        continue;
-               if (resource_size(res) > max)
-                       max = resource_size(res);
+               /* trim free space relative to current alignment setting */
+               start = ALIGN(res->start, align);
+               end = ALIGN_DOWN(res->end + 1, align) - 1;
+               if (end < start)
+                       continue;
+               if (end - start + 1 > max)
+                       max = end - start + 1;
        }
        release_free_pmem(nvdimm_bus, nd_mapping);
        return max;
@@ -722,24 +770,33 @@ resource_size_t nd_pmem_available_dpa(struct nd_region *nd_region,
        struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
        struct resource *res;
        const char *reason;
+       unsigned long align;
 
        if (!ndd)
                return 0;
 
+       align = dpa_align(nd_region);
+       if (!align)
+               return 0;
+
        map_start = nd_mapping->start;
        map_end = map_start + nd_mapping->size - 1;
        blk_start = max(map_start, map_end + 1 - *overlap);
        for_each_dpa_resource(ndd, res) {
-               if (res->start >= map_start && res->start < map_end) {
+               resource_size_t start, end;
+
+               start = ALIGN_DOWN(res->start, align);
+               end = ALIGN(res->end + 1, align) - 1;
+               if (start >= map_start && start < map_end) {
                        if (strncmp(res->name, "blk", 3) == 0)
                                blk_start = min(blk_start,
-                                               max(map_start, res->start));
-                       else if (res->end > map_end) {
+                                               max(map_start, start));
+                       else if (end > map_end) {
                                reason = "misaligned to iset";
                                goto err;
                        } else
-                               busy += resource_size(res);
-               } else if (res->end >= map_start && res->end <= map_end) {
+                               busy += end - start + 1;
+               } else if (end >= map_start && end <= map_end) {
                        if (strncmp(res->name, "blk", 3) == 0) {
                                /*
                                 * If a BLK allocation overlaps the start of
@@ -748,8 +805,8 @@ resource_size_t nd_pmem_available_dpa(struct nd_region *nd_region,
                                 */
                                blk_start = map_start;
                        } else
-                               busy += resource_size(res);
-               } else if (map_start > res->start && map_start < res->end) {
+                               busy += end - start + 1;
+               } else if (map_start > start && map_start < end) {
                        /* total eclipse of the mapping */
                        busy += nd_mapping->size;
                        blk_start = map_start;
@@ -759,7 +816,7 @@ resource_size_t nd_pmem_available_dpa(struct nd_region *nd_region,
        *overlap = map_end + 1 - blk_start;
        available = blk_start - map_start;
        if (busy < available)
-               return available - busy;
+               return ALIGN_DOWN(available - busy, align);
        return 0;
 
  err:
index e02f60a..4cd18be 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/memory_hotplug.h>
 #include <linux/libnvdimm.h>
 #include <linux/module.h>
+#include <linux/numa.h>
 
 static int e820_pmem_remove(struct platform_device *pdev)
 {
@@ -16,27 +17,16 @@ static int e820_pmem_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_MEMORY_HOTPLUG
-static int e820_range_to_nid(resource_size_t addr)
-{
-       return memory_add_physaddr_to_nid(addr);
-}
-#else
-static int e820_range_to_nid(resource_size_t addr)
-{
-       return NUMA_NO_NODE;
-}
-#endif
-
 static int e820_register_one(struct resource *res, void *data)
 {
        struct nd_region_desc ndr_desc;
        struct nvdimm_bus *nvdimm_bus = data;
+       int nid = phys_to_target_node(res->start);
 
        memset(&ndr_desc, 0, sizeof(ndr_desc));
        ndr_desc.res = res;
-       ndr_desc.numa_node = e820_range_to_nid(res->start);
-       ndr_desc.target_node = ndr_desc.numa_node;
+       ndr_desc.numa_node = numa_map_to_online_node(nid);
+       ndr_desc.target_node = nid;
        set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
        if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc))
                return -ENXIO;
index 4c7b775..956b6d1 100644 (file)
@@ -62,7 +62,7 @@ struct nd_namespace_index {
        __le16 major;
        __le16 minor;
        __le64 checksum;
-       u8 free[0];
+       u8 free[];
 };
 
 /**
index 032dc61..ae155e8 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/nd.h>
 #include "nd-core.h"
 #include "pmem.h"
+#include "pfn.h"
 #include "nd.h"
 
 static void namespace_io_release(struct device *dev)
@@ -541,6 +542,11 @@ static void space_valid(struct nd_region *nd_region, struct nvdimm_drvdata *ndd,
 {
        bool is_reserve = strcmp(label_id->id, "pmem-reserve") == 0;
        bool is_pmem = strncmp(label_id->id, "pmem", 4) == 0;
+       unsigned long align;
+
+       align = nd_region->align / nd_region->ndr_mappings;
+       valid->start = ALIGN(valid->start, align);
+       valid->end = ALIGN_DOWN(valid->end + 1, align) - 1;
 
        if (valid->start >= valid->end)
                goto invalid;
@@ -980,10 +986,10 @@ static ssize_t __size_store(struct device *dev, unsigned long long val)
                return -ENXIO;
        }
 
-       div_u64_rem(val, PAGE_SIZE * nd_region->ndr_mappings, &remainder);
+       div_u64_rem(val, nd_region->align, &remainder);
        if (remainder) {
                dev_dbg(dev, "%llu is not %ldK aligned\n", val,
-                               (PAGE_SIZE * nd_region->ndr_mappings) / SZ_1K);
+                               nd_region->align / SZ_1K);
                return -EINVAL;
        }
 
@@ -1739,6 +1745,22 @@ struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev)
                return ERR_PTR(-ENODEV);
        }
 
+       /*
+        * Note, alignment validation for fsdax and devdax mode
+        * namespaces happens in nd_pfn_validate() where infoblock
+        * padding parameters can be applied.
+        */
+       if (pmem_should_map_pages(dev)) {
+               struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+               struct resource *res = &nsio->res;
+
+               if (!IS_ALIGNED(res->start | (res->end + 1),
+                                       memremap_compat_align())) {
+                       dev_err(&ndns->dev, "%pr misaligned, unable to map\n", res);
+                       return ERR_PTR(-EOPNOTSUPP);
+               }
+       }
+
        if (is_namespace_pmem(&ndns->dev)) {
                struct nd_namespace_pmem *nspm;
 
@@ -2521,7 +2543,7 @@ static int init_active_labels(struct nd_region *nd_region)
                if (!ndd) {
                        if (test_bit(NDD_LOCKED, &nvdimm->flags))
                                /* fail, label data may be unreadable */;
-                       else if (test_bit(NDD_ALIASING, &nvdimm->flags))
+                       else if (test_bit(NDD_LABELING, &nvdimm->flags))
                                /* fail, labels needed to disambiguate dpa */;
                        else
                                return 0;
index c9f6a5b..85dbb2a 100644 (file)
@@ -39,7 +39,7 @@ struct nd_region_data {
        int ns_count;
        int ns_active;
        unsigned int hints_shift;
-       void __iomem *flush_wpq[0];
+       void __iomem *flush_wpq[];
 };
 
 static inline void __iomem *ndrd_get_flush_wpq(struct nd_region_data *ndrd,
@@ -146,6 +146,7 @@ struct nd_region {
        struct device *btt_seed;
        struct device *pfn_seed;
        struct device *dax_seed;
+       unsigned long align;
        u16 ndr_mappings;
        u64 ndr_size;
        u64 ndr_start;
@@ -156,7 +157,7 @@ struct nd_region {
        struct nd_interleave_set *nd_set;
        struct nd_percpu_lane __percpu *lane;
        int (*flush)(struct nd_region *nd_region, struct bio *bio);
-       struct nd_mapping mapping[0];
+       struct nd_mapping mapping[];
 };
 
 struct nd_blk_region {
@@ -252,7 +253,7 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
                void *buf, size_t len);
 long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
                unsigned int len);
-void nvdimm_set_aliasing(struct device *dev);
+void nvdimm_set_labeling(struct device *dev);
 void nvdimm_set_locked(struct device *dev);
 void nvdimm_clear_locked(struct device *dev);
 int nvdimm_security_setup_events(struct device *dev);
index 8224d14..6826a27 100644 (file)
@@ -62,8 +62,10 @@ static int of_pmem_region_probe(struct platform_device *pdev)
 
                if (is_volatile)
                        region = nvdimm_volatile_region_create(bus, &ndr_desc);
-               else
+               else {
+                       set_bit(ND_REGION_PERSIST_MEMCTRL, &ndr_desc.flags);
                        region = nvdimm_pmem_region_create(bus, &ndr_desc);
+               }
 
                if (!region)
                        dev_warn(&pdev->dev, "Unable to register region %pR from %pOF\n",
index acb1951..37cb1b8 100644 (file)
@@ -24,6 +24,18 @@ struct nd_pfn_sb {
        __le64 npfns;
        __le32 mode;
        /* minor-version-1 additions for section alignment */
+       /**
+        * @start_pad: Deprecated attribute to pad start-misaligned namespaces
+        *
+        * start_pad is deprecated because the original definition did
+        * not comprehend that dataoff is relative to the base address
+        * of the namespace not the start_pad adjusted base. The result
+        * is that the dax path is broken, but the block-I/O path is
+        * not. The kernel will no longer create namespaces using start
+        * padding, but it still supports block-I/O for legacy
+        * configurations mainly to allow a backup, reconfigure the
+        * namespace, and restore flow to repair dax operation.
+        */
        __le32 start_pad;
        __le32 end_trunc;
        /* minor-version-2 record the base alignment of the mapping */
index b94f7a7..34db557 100644 (file)
@@ -446,6 +446,7 @@ static bool nd_supported_alignment(unsigned long align)
 int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
 {
        u64 checksum, offset;
+       struct resource *res;
        enum nd_pfn_mode mode;
        struct nd_namespace_io *nsio;
        unsigned long align, start_pad;
@@ -561,14 +562,14 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
                        dev_dbg(&nd_pfn->dev, "align: %lx:%lx mode: %d:%d\n",
                                        nd_pfn->align, align, nd_pfn->mode,
                                        mode);
-                       return -EINVAL;
+                       return -EOPNOTSUPP;
                }
        }
 
        if (align > nvdimm_namespace_capacity(ndns)) {
                dev_err(&nd_pfn->dev, "alignment: %lx exceeds capacity %llx\n",
                                align, nvdimm_namespace_capacity(ndns));
-               return -EINVAL;
+               return -EOPNOTSUPP;
        }
 
        /*
@@ -578,18 +579,31 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
         * established.
         */
        nsio = to_nd_namespace_io(&ndns->dev);
-       if (offset >= resource_size(&nsio->res)) {
+       res = &nsio->res;
+       if (offset >= resource_size(res)) {
                dev_err(&nd_pfn->dev, "pfn array size exceeds capacity of %s\n",
                                dev_name(&ndns->dev));
-               return -EBUSY;
+               return -EOPNOTSUPP;
        }
 
-       if ((align && !IS_ALIGNED(nsio->res.start + offset + start_pad, align))
+       if ((align && !IS_ALIGNED(res->start + offset + start_pad, align))
                        || !IS_ALIGNED(offset, PAGE_SIZE)) {
                dev_err(&nd_pfn->dev,
                                "bad offset: %#llx dax disabled align: %#lx\n",
                                offset, align);
-               return -ENXIO;
+               return -EOPNOTSUPP;
+       }
+
+       if (!IS_ALIGNED(res->start + le32_to_cpu(pfn_sb->start_pad),
+                               memremap_compat_align())) {
+               dev_err(&nd_pfn->dev, "resource start misaligned\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (!IS_ALIGNED(res->end + 1 - le32_to_cpu(pfn_sb->end_trunc),
+                               memremap_compat_align())) {
+               dev_err(&nd_pfn->dev, "resource end misaligned\n");
+               return -EOPNOTSUPP;
        }
 
        return 0;
@@ -750,7 +764,19 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
        start = nsio->res.start;
        size = resource_size(&nsio->res);
        npfns = PHYS_PFN(size - SZ_8K);
-       align = max(nd_pfn->align, (1UL << SUBSECTION_SHIFT));
+       align = max(nd_pfn->align, memremap_compat_align());
+
+       /*
+        * When @start is misaligned fail namespace creation. See
+        * the 'struct nd_pfn_sb' commentary on why ->start_pad is not
+        * an option.
+        */
+       if (!IS_ALIGNED(start, memremap_compat_align())) {
+               dev_err(&nd_pfn->dev, "%s: start %pa misaligned to %#lx\n",
+                               dev_name(&ndns->dev), &start,
+                               memremap_compat_align());
+               return -EINVAL;
+       }
        end_trunc = start + size - ALIGN_DOWN(start + size, align);
        if (nd_pfn->mode == PFN_MODE_PMEM) {
                /*
index 4ffc6f7..2df6994 100644 (file)
@@ -136,9 +136,25 @@ static blk_status_t read_pmem(struct page *page, unsigned int off,
        return BLK_STS_OK;
 }
 
-static blk_status_t pmem_do_bvec(struct pmem_device *pmem, struct page *page,
-                       unsigned int len, unsigned int off, unsigned int op,
-                       sector_t sector)
+static blk_status_t pmem_do_read(struct pmem_device *pmem,
+                       struct page *page, unsigned int page_off,
+                       sector_t sector, unsigned int len)
+{
+       blk_status_t rc;
+       phys_addr_t pmem_off = sector * 512 + pmem->data_offset;
+       void *pmem_addr = pmem->virt_addr + pmem_off;
+
+       if (unlikely(is_bad_pmem(&pmem->bb, sector, len)))
+               return BLK_STS_IOERR;
+
+       rc = read_pmem(page, page_off, pmem_addr, len);
+       flush_dcache_page(page);
+       return rc;
+}
+
+static blk_status_t pmem_do_write(struct pmem_device *pmem,
+                       struct page *page, unsigned int page_off,
+                       sector_t sector, unsigned int len)
 {
        blk_status_t rc = BLK_STS_OK;
        bool bad_pmem = false;
@@ -148,34 +164,25 @@ static blk_status_t pmem_do_bvec(struct pmem_device *pmem, struct page *page,
        if (unlikely(is_bad_pmem(&pmem->bb, sector, len)))
                bad_pmem = true;
 
-       if (!op_is_write(op)) {
-               if (unlikely(bad_pmem))
-                       rc = BLK_STS_IOERR;
-               else {
-                       rc = read_pmem(page, off, pmem_addr, len);
-                       flush_dcache_page(page);
-               }
-       } else {
-               /*
-                * Note that we write the data both before and after
-                * clearing poison.  The write before clear poison
-                * handles situations where the latest written data is
-                * preserved and the clear poison operation simply marks
-                * the address range as valid without changing the data.
-                * In this case application software can assume that an
-                * interrupted write will either return the new good
-                * data or an error.
-                *
-                * However, if pmem_clear_poison() leaves the data in an
-                * indeterminate state we need to perform the write
-                * after clear poison.
-                */
-               flush_dcache_page(page);
-               write_pmem(pmem_addr, page, off, len);
-               if (unlikely(bad_pmem)) {
-                       rc = pmem_clear_poison(pmem, pmem_off, len);
-                       write_pmem(pmem_addr, page, off, len);
-               }
+       /*
+        * Note that we write the data both before and after
+        * clearing poison.  The write before clear poison
+        * handles situations where the latest written data is
+        * preserved and the clear poison operation simply marks
+        * the address range as valid without changing the data.
+        * In this case application software can assume that an
+        * interrupted write will either return the new good
+        * data or an error.
+        *
+        * However, if pmem_clear_poison() leaves the data in an
+        * indeterminate state we need to perform the write
+        * after clear poison.
+        */
+       flush_dcache_page(page);
+       write_pmem(pmem_addr, page, page_off, len);
+       if (unlikely(bad_pmem)) {
+               rc = pmem_clear_poison(pmem, pmem_off, len);
+               write_pmem(pmem_addr, page, page_off, len);
        }
 
        return rc;
@@ -197,8 +204,12 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
 
        do_acct = nd_iostat_start(bio, &start);
        bio_for_each_segment(bvec, bio, iter) {
-               rc = pmem_do_bvec(pmem, bvec.bv_page, bvec.bv_len,
-                               bvec.bv_offset, bio_op(bio), iter.bi_sector);
+               if (op_is_write(bio_op(bio)))
+                       rc = pmem_do_write(pmem, bvec.bv_page, bvec.bv_offset,
+                               iter.bi_sector, bvec.bv_len);
+               else
+                       rc = pmem_do_read(pmem, bvec.bv_page, bvec.bv_offset,
+                               iter.bi_sector, bvec.bv_len);
                if (rc) {
                        bio->bi_status = rc;
                        break;
@@ -223,9 +234,12 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector,
        struct pmem_device *pmem = bdev->bd_queue->queuedata;
        blk_status_t rc;
 
-       rc = pmem_do_bvec(pmem, page, hpage_nr_pages(page) * PAGE_SIZE,
-                         0, op, sector);
-
+       if (op_is_write(op))
+               rc = pmem_do_write(pmem, page, 0, sector,
+                                  hpage_nr_pages(page) * PAGE_SIZE);
+       else
+               rc = pmem_do_read(pmem, page, 0, sector,
+                                  hpage_nr_pages(page) * PAGE_SIZE);
        /*
         * The ->rw_page interface is subtle and tricky.  The core
         * retries on any error, so we can only invoke page_endio() in
@@ -268,6 +282,16 @@ static const struct block_device_operations pmem_fops = {
        .revalidate_disk =      nvdimm_revalidate_disk,
 };
 
+static int pmem_dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
+                                   size_t nr_pages)
+{
+       struct pmem_device *pmem = dax_get_private(dax_dev);
+
+       return blk_status_to_errno(pmem_do_write(pmem, ZERO_PAGE(0), 0,
+                                  PFN_PHYS(pgoff) >> SECTOR_SHIFT,
+                                  PAGE_SIZE));
+}
+
 static long pmem_dax_direct_access(struct dax_device *dax_dev,
                pgoff_t pgoff, long nr_pages, void **kaddr, pfn_t *pfn)
 {
@@ -299,6 +323,7 @@ static const struct dax_operations pmem_dax_ops = {
        .dax_supported = generic_fsdax_supported,
        .copy_from_iter = pmem_copy_from_iter,
        .copy_to_iter = pmem_copy_to_iter,
+       .zero_page_range = pmem_dax_zero_page_range,
 };
 
 static const struct attribute_group *pmem_attribute_groups[] = {
@@ -461,9 +486,9 @@ static int pmem_attach_disk(struct device *dev,
        if (is_nvdimm_sync(nd_region))
                flags = DAXDEV_F_SYNC;
        dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops, flags);
-       if (!dax_dev) {
+       if (IS_ERR(dax_dev)) {
                put_disk(disk);
-               return -ENOMEM;
+               return PTR_ERR(dax_dev);
        }
        dax_write_cache(dax_dev, nvdimm_has_cache(nd_region));
        pmem->dax_dev = dax_dev;
index a19e535..ccbb5b4 100644 (file)
@@ -195,16 +195,16 @@ EXPORT_SYMBOL_GPL(nd_blk_region_set_provider_data);
 int nd_region_to_nstype(struct nd_region *nd_region)
 {
        if (is_memory(&nd_region->dev)) {
-               u16 i, alias;
+               u16 i, label;
 
-               for (i = 0, alias = 0; i < nd_region->ndr_mappings; i++) {
+               for (i = 0, label = 0; i < nd_region->ndr_mappings; i++) {
                        struct nd_mapping *nd_mapping = &nd_region->mapping[i];
                        struct nvdimm *nvdimm = nd_mapping->nvdimm;
 
-                       if (test_bit(NDD_ALIASING, &nvdimm->flags))
-                               alias++;
+                       if (test_bit(NDD_LABELING, &nvdimm->flags))
+                               label++;
                }
-               if (alias)
+               if (label)
                        return ND_DEVICE_NAMESPACE_PMEM;
                else
                        return ND_DEVICE_NAMESPACE_IO;
@@ -216,21 +216,25 @@ int nd_region_to_nstype(struct nd_region *nd_region)
 }
 EXPORT_SYMBOL(nd_region_to_nstype);
 
-static ssize_t size_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static unsigned long long region_size(struct nd_region *nd_region)
 {
-       struct nd_region *nd_region = to_nd_region(dev);
-       unsigned long long size = 0;
-
-       if (is_memory(dev)) {
-               size = nd_region->ndr_size;
+       if (is_memory(&nd_region->dev)) {
+               return nd_region->ndr_size;
        } else if (nd_region->ndr_mappings == 1) {
                struct nd_mapping *nd_mapping = &nd_region->mapping[0];
 
-               size = nd_mapping->size;
+               return nd_mapping->size;
        }
 
-       return sprintf(buf, "%llu\n", size);
+       return 0;
+}
+
+static ssize_t size_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nd_region *nd_region = to_nd_region(dev);
+
+       return sprintf(buf, "%llu\n", region_size(nd_region));
 }
 static DEVICE_ATTR_RO(size);
 
@@ -529,6 +533,54 @@ static ssize_t read_only_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(read_only);
 
+static ssize_t align_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nd_region *nd_region = to_nd_region(dev);
+
+       return sprintf(buf, "%#lx\n", nd_region->align);
+}
+
+static ssize_t align_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       struct nd_region *nd_region = to_nd_region(dev);
+       unsigned long val, dpa;
+       u32 remainder;
+       int rc;
+
+       rc = kstrtoul(buf, 0, &val);
+       if (rc)
+               return rc;
+
+       if (!nd_region->ndr_mappings)
+               return -ENXIO;
+
+       /*
+        * Ensure space-align is evenly divisible by the region
+        * interleave-width because the kernel typically has no facility
+        * to determine which DIMM(s), dimm-physical-addresses, would
+        * contribute to the tail capacity in system-physical-address
+        * space for the namespace.
+        */
+       dpa = div_u64_rem(val, nd_region->ndr_mappings, &remainder);
+       if (!is_power_of_2(dpa) || dpa < PAGE_SIZE
+                       || val > region_size(nd_region) || remainder)
+               return -EINVAL;
+
+       /*
+        * Given that space allocation consults this value multiple
+        * times ensure it does not change for the duration of the
+        * allocation.
+        */
+       nvdimm_bus_lock(dev);
+       nd_region->align = val;
+       nvdimm_bus_unlock(dev);
+
+       return len;
+}
+static DEVICE_ATTR_RW(align);
+
 static ssize_t region_badblocks_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
@@ -571,6 +623,7 @@ static DEVICE_ATTR_RO(persistence_domain);
 
 static struct attribute *nd_region_attributes[] = {
        &dev_attr_size.attr,
+       &dev_attr_align.attr,
        &dev_attr_nstype.attr,
        &dev_attr_mappings.attr,
        &dev_attr_btt_seed.attr,
@@ -626,6 +679,19 @@ static umode_t region_visible(struct kobject *kobj, struct attribute *a, int n)
                return a->mode;
        }
 
+       if (a == &dev_attr_align.attr) {
+               int i;
+
+               for (i = 0; i < nd_region->ndr_mappings; i++) {
+                       struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+                       struct nvdimm *nvdimm = nd_mapping->nvdimm;
+
+                       if (test_bit(NDD_LABELING, &nvdimm->flags))
+                               return a->mode;
+               }
+               return 0;
+       }
+
        if (a != &dev_attr_set_cookie.attr
                        && a != &dev_attr_available_size.attr)
                return a->mode;
@@ -935,6 +1001,41 @@ void nd_region_release_lane(struct nd_region *nd_region, unsigned int lane)
 }
 EXPORT_SYMBOL(nd_region_release_lane);
 
+/*
+ * PowerPC requires this alignment for memremap_pages(). All other archs
+ * should be ok with SUBSECTION_SIZE (see memremap_compat_align()).
+ */
+#define MEMREMAP_COMPAT_ALIGN_MAX SZ_16M
+
+static unsigned long default_align(struct nd_region *nd_region)
+{
+       unsigned long align;
+       int i, mappings;
+       u32 remainder;
+
+       if (is_nd_blk(&nd_region->dev))
+               align = PAGE_SIZE;
+       else
+               align = MEMREMAP_COMPAT_ALIGN_MAX;
+
+       for (i = 0; i < nd_region->ndr_mappings; i++) {
+               struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+               struct nvdimm *nvdimm = nd_mapping->nvdimm;
+
+               if (test_bit(NDD_ALIASING, &nvdimm->flags)) {
+                       align = MEMREMAP_COMPAT_ALIGN_MAX;
+                       break;
+               }
+       }
+
+       mappings = max_t(u16, 1, nd_region->ndr_mappings);
+       div_u64_rem(align, mappings, &remainder);
+       if (remainder)
+               align *= mappings;
+
+       return align;
+}
+
 static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
                struct nd_region_desc *ndr_desc,
                const struct device_type *dev_type, const char *caller)
@@ -1039,6 +1140,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
        dev->of_node = ndr_desc->of_node;
        nd_region->ndr_size = resource_size(ndr_desc->res);
        nd_region->ndr_start = ndr_desc->res->start;
+       nd_region->align = default_align(nd_region);
        if (ndr_desc->flush)
                nd_region->flush = ndr_desc->flush;
        else
index 4f907e3..91c1bd6 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/blkdev.h>
 #include <linux/blk-mq.h>
+#include <linux/compat.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/hdreg.h>
@@ -1252,6 +1253,18 @@ static void nvme_enable_aen(struct nvme_ctrl *ctrl)
        queue_work(nvme_wq, &ctrl->async_event_work);
 }
 
+/*
+ * Convert integer values from ioctl structures to user pointers, silently
+ * ignoring the upper bits in the compat case to match behaviour of 32-bit
+ * kernels.
+ */
+static void __user *nvme_to_user_ptr(uintptr_t ptrval)
+{
+       if (in_compat_syscall())
+               ptrval = (compat_uptr_t)ptrval;
+       return (void __user *)ptrval;
+}
+
 static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 {
        struct nvme_user_io io;
@@ -1275,7 +1288,7 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 
        length = (io.nblocks + 1) << ns->lba_shift;
        meta_len = (io.nblocks + 1) * ns->ms;
-       metadata = (void __user *)(uintptr_t)io.metadata;
+       metadata = nvme_to_user_ptr(io.metadata);
 
        if (ns->ext) {
                length += meta_len;
@@ -1298,7 +1311,7 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
        c.rw.appmask = cpu_to_le16(io.appmask);
 
        return nvme_submit_user_cmd(ns->queue, &c,
-                       (void __user *)(uintptr_t)io.addr, length,
+                       nvme_to_user_ptr(io.addr), length,
                        metadata, meta_len, lower_32_bits(io.slba), NULL, 0);
 }
 
@@ -1418,9 +1431,9 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
 
        effects = nvme_passthru_start(ctrl, ns, cmd.opcode);
        status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c,
-                       (void __user *)(uintptr_t)cmd.addr, cmd.data_len,
-                       (void __user *)(uintptr_t)cmd.metadata,
-                       cmd.metadata_len, 0, &result, timeout);
+                       nvme_to_user_ptr(cmd.addr), cmd.data_len,
+                       nvme_to_user_ptr(cmd.metadata), cmd.metadata_len,
+                       0, &result, timeout);
        nvme_passthru_end(ctrl, effects);
 
        if (status >= 0) {
@@ -1465,8 +1478,8 @@ static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
 
        effects = nvme_passthru_start(ctrl, ns, cmd.opcode);
        status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c,
-                       (void __user *)(uintptr_t)cmd.addr, cmd.data_len,
-                       (void __user *)(uintptr_t)cmd.metadata, cmd.metadata_len,
+                       nvme_to_user_ptr(cmd.addr), cmd.data_len,
+                       nvme_to_user_ptr(cmd.metadata), cmd.metadata_len,
                        0, &cmd.result, timeout);
        nvme_passthru_end(ctrl, effects);
 
@@ -1884,6 +1897,13 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
        if (ns->head->disk) {
                nvme_update_disk_info(ns->head->disk, ns, id);
                blk_queue_stack_limits(ns->head->disk->queue, ns->queue);
+               if (bdi_cap_stable_pages_required(ns->queue->backing_dev_info)) {
+                       struct backing_dev_info *info =
+                               ns->head->disk->queue->backing_dev_info;
+
+                        info->capabilities |= BDI_CAP_STABLE_WRITES;
+               }
+
                revalidate_disk(ns->head->disk);
        }
 #endif
index a8bf2fb..7dfc4a2 100644 (file)
@@ -342,8 +342,7 @@ nvme_fc_register_localport(struct nvme_fc_port_info *pinfo,
            !template->ls_req || !template->fcp_io ||
            !template->ls_abort || !template->fcp_abort ||
            !template->max_hw_queues || !template->max_sgl_segments ||
-           !template->max_dif_sgl_segments || !template->dma_boundary ||
-           !template->module) {
+           !template->max_dif_sgl_segments || !template->dma_boundary) {
                ret = -EINVAL;
                goto out_reghost_failed;
        }
@@ -2016,7 +2015,6 @@ nvme_fc_ctrl_free(struct kref *ref)
 {
        struct nvme_fc_ctrl *ctrl =
                container_of(ref, struct nvme_fc_ctrl, ref);
-       struct nvme_fc_lport *lport = ctrl->lport;
        unsigned long flags;
 
        if (ctrl->ctrl.tagset) {
@@ -2043,7 +2041,6 @@ nvme_fc_ctrl_free(struct kref *ref)
        if (ctrl->ctrl.opts)
                nvmf_free_options(ctrl->ctrl.opts);
        kfree(ctrl);
-       module_put(lport->ops->module);
 }
 
 static void
@@ -3074,15 +3071,10 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
                goto out_fail;
        }
 
-       if (!try_module_get(lport->ops->module)) {
-               ret = -EUNATCH;
-               goto out_free_ctrl;
-       }
-
        idx = ida_simple_get(&nvme_fc_ctrl_cnt, 0, 0, GFP_KERNEL);
        if (idx < 0) {
                ret = -ENOSPC;
-               goto out_mod_put;
+               goto out_free_ctrl;
        }
 
        ctrl->ctrl.opts = opts;
@@ -3232,8 +3224,6 @@ out_free_queues:
 out_free_ida:
        put_device(ctrl->dev);
        ida_simple_remove(&nvme_fc_ctrl_cnt, ctrl->cnum);
-out_mod_put:
-       module_put(lport->ops->module);
 out_free_ctrl:
        kfree(ctrl);
 out_fail:
index 61bf875..54603bd 100644 (file)
@@ -510,7 +510,7 @@ static int nvme_update_ana_state(struct nvme_ctrl *ctrl,
        if (!nr_nsids)
                return 0;
 
-       down_write(&ctrl->namespaces_rwsem);
+       down_read(&ctrl->namespaces_rwsem);
        list_for_each_entry(ns, &ctrl->namespaces, list) {
                unsigned nsid = le32_to_cpu(desc->nsids[n]);
 
@@ -521,7 +521,7 @@ static int nvme_update_ana_state(struct nvme_ctrl *ctrl,
                if (++n == nr_nsids)
                        break;
        }
-       up_write(&ctrl->namespaces_rwsem);
+       up_read(&ctrl->namespaces_rwsem);
        return 0;
 }
 
index 76dbb55..cac8a93 100644 (file)
@@ -1342,7 +1342,7 @@ static int nvme_rdma_post_send(struct nvme_rdma_queue *queue,
        int ret;
 
        sge->addr   = qe->dma;
-       sge->length = sizeof(struct nvme_command),
+       sge->length = sizeof(struct nvme_command);
        sge->lkey   = queue->device->pd->local_dma_lkey;
 
        wr.next       = NULL;
index 0ef14f0..c15a921 100644 (file)
@@ -174,16 +174,14 @@ static inline bool nvme_tcp_async_req(struct nvme_tcp_request *req)
 static inline bool nvme_tcp_has_inline_data(struct nvme_tcp_request *req)
 {
        struct request *rq;
-       unsigned int bytes;
 
        if (unlikely(nvme_tcp_async_req(req)))
                return false; /* async events don't have a request */
 
        rq = blk_mq_rq_from_pdu(req);
-       bytes = blk_rq_payload_bytes(rq);
 
-       return rq_data_dir(rq) == WRITE && bytes &&
-               bytes <= nvme_tcp_inline_data_size(req->queue);
+       return rq_data_dir(rq) == WRITE && req->data_len &&
+               req->data_len <= nvme_tcp_inline_data_size(req->queue);
 }
 
 static inline struct page *nvme_tcp_req_cur_page(struct nvme_tcp_request *req)
@@ -1075,7 +1073,7 @@ static void nvme_tcp_io_work(struct work_struct *w)
                if (result > 0)
                        pending = true;
                else if (unlikely(result < 0))
-                       break;
+                       return;
 
                if (!pending)
                        return;
@@ -2164,7 +2162,9 @@ static blk_status_t nvme_tcp_map_data(struct nvme_tcp_queue *queue,
 
        c->common.flags |= NVME_CMD_SGL_METABUF;
 
-       if (rq_data_dir(rq) == WRITE && req->data_len &&
+       if (!blk_rq_nr_phys_segments(rq))
+               nvme_tcp_set_sg_null(c);
+       else if (rq_data_dir(rq) == WRITE &&
            req->data_len <= nvme_tcp_inline_data_size(queue))
                nvme_tcp_set_sg_inline(queue, c, req->data_len);
        else
@@ -2191,7 +2191,8 @@ static blk_status_t nvme_tcp_setup_cmd_pdu(struct nvme_ns *ns,
        req->data_sent = 0;
        req->pdu_len = 0;
        req->pdu_sent = 0;
-       req->data_len = blk_rq_payload_bytes(rq);
+       req->data_len = blk_rq_nr_phys_segments(rq) ?
+                               blk_rq_payload_bytes(rq) : 0;
        req->curr_bio = rq->bio;
 
        if (rq_data_dir(rq) == WRITE &&
@@ -2298,6 +2299,9 @@ static int nvme_tcp_poll(struct blk_mq_hw_ctx *hctx)
        struct nvme_tcp_queue *queue = hctx->driver_data;
        struct sock *sk = queue->sock->sk;
 
+       if (!test_bit(NVME_TCP_Q_LIVE, &queue->flags))
+               return 0;
+
        if (sk_can_busy_loop(sk) && skb_queue_empty_lockless(&sk->sk_receive_queue))
                sk_busy_loop(sk, true);
        nvme_tcp_try_recv(queue);
index 7aa1078..58cabd7 100644 (file)
@@ -1098,12 +1098,19 @@ static struct configfs_attribute *nvmet_referral_attrs[] = {
        NULL,
 };
 
-static void nvmet_referral_release(struct config_item *item)
+static void nvmet_referral_notify(struct config_group *group,
+               struct config_item *item)
 {
        struct nvmet_port *parent = to_nvmet_port(item->ci_parent->ci_parent);
        struct nvmet_port *port = to_nvmet_port(item);
 
        nvmet_referral_disable(parent, port);
+}
+
+static void nvmet_referral_release(struct config_item *item)
+{
+       struct nvmet_port *port = to_nvmet_port(item);
+
        kfree(port);
 }
 
@@ -1134,6 +1141,7 @@ static struct config_group *nvmet_referral_make(
 
 static struct configfs_group_operations nvmet_referral_group_ops = {
        .make_group             = nvmet_referral_make,
+       .disconnect_notify      = nvmet_referral_notify,
 };
 
 static const struct config_item_type nvmet_referrals_type = {
index a0db637..a8ceb77 100644 (file)
@@ -684,7 +684,7 @@ nvmet_fc_delete_target_queue(struct nvmet_fc_tgt_queue *queue)
        disconnect = atomic_xchg(&queue->connected, 0);
 
        spin_lock_irqsave(&queue->qlock, flags);
-       /* about outstanding io's */
+       /* abort outstanding io's */
        for (i = 0; i < queue->sqsize; fod++, i++) {
                if (fod->active) {
                        spin_lock(&fod->flock);
index 1c50af6..f69ce66 100644 (file)
@@ -198,10 +198,13 @@ struct fcloop_lport_priv {
 };
 
 struct fcloop_rport {
-       struct nvme_fc_remote_port *remoteport;
-       struct nvmet_fc_target_port *targetport;
-       struct fcloop_nport *nport;
-       struct fcloop_lport *lport;
+       struct nvme_fc_remote_port      *remoteport;
+       struct nvmet_fc_target_port     *targetport;
+       struct fcloop_nport             *nport;
+       struct fcloop_lport             *lport;
+       spinlock_t                      lock;
+       struct list_head                ls_list;
+       struct work_struct              ls_work;
 };
 
 struct fcloop_tport {
@@ -224,11 +227,10 @@ struct fcloop_nport {
 };
 
 struct fcloop_lsreq {
-       struct fcloop_tport             *tport;
        struct nvmefc_ls_req            *lsreq;
-       struct work_struct              work;
        struct nvmefc_tgt_ls_req        tgt_ls_req;
        int                             status;
+       struct list_head                ls_list; /* fcloop_rport->ls_list */
 };
 
 struct fcloop_rscn {
@@ -292,21 +294,32 @@ fcloop_delete_queue(struct nvme_fc_local_port *localport,
 {
 }
 
-
-/*
- * Transmit of LS RSP done (e.g. buffers all set). call back up
- * initiator "done" flows.
- */
 static void
-fcloop_tgt_lsrqst_done_work(struct work_struct *work)
+fcloop_rport_lsrqst_work(struct work_struct *work)
 {
-       struct fcloop_lsreq *tls_req =
-               container_of(work, struct fcloop_lsreq, work);
-       struct fcloop_tport *tport = tls_req->tport;
-       struct nvmefc_ls_req *lsreq = tls_req->lsreq;
+       struct fcloop_rport *rport =
+               container_of(work, struct fcloop_rport, ls_work);
+       struct fcloop_lsreq *tls_req;
 
-       if (!tport || tport->remoteport)
-               lsreq->done(lsreq, tls_req->status);
+       spin_lock(&rport->lock);
+       for (;;) {
+               tls_req = list_first_entry_or_null(&rport->ls_list,
+                               struct fcloop_lsreq, ls_list);
+               if (!tls_req)
+                       break;
+
+               list_del(&tls_req->ls_list);
+               spin_unlock(&rport->lock);
+
+               tls_req->lsreq->done(tls_req->lsreq, tls_req->status);
+               /*
+                * callee may free memory containing tls_req.
+                * do not reference lsreq after this.
+                */
+
+               spin_lock(&rport->lock);
+       }
+       spin_unlock(&rport->lock);
 }
 
 static int
@@ -319,17 +332,18 @@ fcloop_ls_req(struct nvme_fc_local_port *localport,
        int ret = 0;
 
        tls_req->lsreq = lsreq;
-       INIT_WORK(&tls_req->work, fcloop_tgt_lsrqst_done_work);
+       INIT_LIST_HEAD(&tls_req->ls_list);
 
        if (!rport->targetport) {
                tls_req->status = -ECONNREFUSED;
-               tls_req->tport = NULL;
-               schedule_work(&tls_req->work);
+               spin_lock(&rport->lock);
+               list_add_tail(&rport->ls_list, &tls_req->ls_list);
+               spin_unlock(&rport->lock);
+               schedule_work(&rport->ls_work);
                return ret;
        }
 
        tls_req->status = 0;
-       tls_req->tport = rport->targetport->private;
        ret = nvmet_fc_rcv_ls_req(rport->targetport, &tls_req->tgt_ls_req,
                                 lsreq->rqstaddr, lsreq->rqstlen);
 
@@ -337,18 +351,28 @@ fcloop_ls_req(struct nvme_fc_local_port *localport,
 }
 
 static int
-fcloop_xmt_ls_rsp(struct nvmet_fc_target_port *tport,
+fcloop_xmt_ls_rsp(struct nvmet_fc_target_port *targetport,
                        struct nvmefc_tgt_ls_req *tgt_lsreq)
 {
        struct fcloop_lsreq *tls_req = tgt_ls_req_to_lsreq(tgt_lsreq);
        struct nvmefc_ls_req *lsreq = tls_req->lsreq;
+       struct fcloop_tport *tport = targetport->private;
+       struct nvme_fc_remote_port *remoteport = tport->remoteport;
+       struct fcloop_rport *rport;
 
        memcpy(lsreq->rspaddr, tgt_lsreq->rspbuf,
                ((lsreq->rsplen < tgt_lsreq->rsplen) ?
                                lsreq->rsplen : tgt_lsreq->rsplen));
+
        tgt_lsreq->done(tgt_lsreq);
 
-       schedule_work(&tls_req->work);
+       if (remoteport) {
+               rport = remoteport->private;
+               spin_lock(&rport->lock);
+               list_add_tail(&rport->ls_list, &tls_req->ls_list);
+               spin_unlock(&rport->lock);
+               schedule_work(&rport->ls_work);
+       }
 
        return 0;
 }
@@ -834,6 +858,7 @@ fcloop_remoteport_delete(struct nvme_fc_remote_port *remoteport)
 {
        struct fcloop_rport *rport = remoteport->private;
 
+       flush_work(&rport->ls_work);
        fcloop_nport_put(rport->nport);
 }
 
@@ -850,7 +875,6 @@ fcloop_targetport_delete(struct nvmet_fc_target_port *targetport)
 #define FCLOOP_DMABOUND_4G             0xFFFFFFFF
 
 static struct nvme_fc_port_template fctemplate = {
-       .module                 = THIS_MODULE,
        .localport_delete       = fcloop_localport_delete,
        .remoteport_delete      = fcloop_remoteport_delete,
        .create_queue           = fcloop_create_queue,
@@ -1136,6 +1160,9 @@ fcloop_create_remote_port(struct device *dev, struct device_attribute *attr,
        rport->nport = nport;
        rport->lport = nport->lport;
        nport->rport = rport;
+       spin_lock_init(&rport->lock);
+       INIT_WORK(&rport->ls_work, fcloop_rport_lsrqst_work);
+       INIT_LIST_HEAD(&rport->ls_list);
 
        return count;
 }
index c90c068..fd47de0 100644 (file)
@@ -78,6 +78,7 @@ enum nvmet_rdma_queue_state {
 
 struct nvmet_rdma_queue {
        struct rdma_cm_id       *cm_id;
+       struct ib_qp            *qp;
        struct nvmet_port       *port;
        struct ib_cq            *cq;
        atomic_t                sq_wr_avail;
@@ -105,6 +106,13 @@ struct nvmet_rdma_queue {
        struct list_head        queue_list;
 };
 
+struct nvmet_rdma_port {
+       struct nvmet_port       *nport;
+       struct sockaddr_storage addr;
+       struct rdma_cm_id       *cm_id;
+       struct delayed_work     repair_work;
+};
+
 struct nvmet_rdma_device {
        struct ib_device        *device;
        struct ib_pd            *pd;
@@ -461,7 +469,7 @@ static int nvmet_rdma_post_recv(struct nvmet_rdma_device *ndev,
        if (ndev->srq)
                ret = ib_post_srq_recv(ndev->srq, &cmd->wr, NULL);
        else
-               ret = ib_post_recv(cmd->queue->cm_id->qp, &cmd->wr, NULL);
+               ret = ib_post_recv(cmd->queue->qp, &cmd->wr, NULL);
 
        if (unlikely(ret))
                pr_err("post_recv cmd failed\n");
@@ -500,7 +508,7 @@ static void nvmet_rdma_release_rsp(struct nvmet_rdma_rsp *rsp)
        atomic_add(1 + rsp->n_rdma, &queue->sq_wr_avail);
 
        if (rsp->n_rdma) {
-               rdma_rw_ctx_destroy(&rsp->rw, queue->cm_id->qp,
+               rdma_rw_ctx_destroy(&rsp->rw, queue->qp,
                                queue->cm_id->port_num, rsp->req.sg,
                                rsp->req.sg_cnt, nvmet_data_dir(&rsp->req));
        }
@@ -584,7 +592,7 @@ static void nvmet_rdma_read_data_done(struct ib_cq *cq, struct ib_wc *wc)
 
        WARN_ON(rsp->n_rdma <= 0);
        atomic_add(rsp->n_rdma, &queue->sq_wr_avail);
-       rdma_rw_ctx_destroy(&rsp->rw, queue->cm_id->qp,
+       rdma_rw_ctx_destroy(&rsp->rw, queue->qp,
                        queue->cm_id->port_num, rsp->req.sg,
                        rsp->req.sg_cnt, nvmet_data_dir(&rsp->req));
        rsp->n_rdma = 0;
@@ -739,7 +747,7 @@ static bool nvmet_rdma_execute_command(struct nvmet_rdma_rsp *rsp)
        }
 
        if (nvmet_rdma_need_data_in(rsp)) {
-               if (rdma_rw_ctx_post(&rsp->rw, queue->cm_id->qp,
+               if (rdma_rw_ctx_post(&rsp->rw, queue->qp,
                                queue->cm_id->port_num, &rsp->read_cqe, NULL))
                        nvmet_req_complete(&rsp->req, NVME_SC_DATA_XFER_ERROR);
        } else {
@@ -911,7 +919,8 @@ static void nvmet_rdma_free_dev(struct kref *ref)
 static struct nvmet_rdma_device *
 nvmet_rdma_find_get_device(struct rdma_cm_id *cm_id)
 {
-       struct nvmet_port *port = cm_id->context;
+       struct nvmet_rdma_port *port = cm_id->context;
+       struct nvmet_port *nport = port->nport;
        struct nvmet_rdma_device *ndev;
        int inline_page_count;
        int inline_sge_count;
@@ -928,17 +937,17 @@ nvmet_rdma_find_get_device(struct rdma_cm_id *cm_id)
        if (!ndev)
                goto out_err;
 
-       inline_page_count = num_pages(port->inline_data_size);
+       inline_page_count = num_pages(nport->inline_data_size);
        inline_sge_count = max(cm_id->device->attrs.max_sge_rd,
                                cm_id->device->attrs.max_recv_sge) - 1;
        if (inline_page_count > inline_sge_count) {
                pr_warn("inline_data_size %d cannot be supported by device %s. Reducing to %lu.\n",
-                       port->inline_data_size, cm_id->device->name,
+                       nport->inline_data_size, cm_id->device->name,
                        inline_sge_count * PAGE_SIZE);
-               port->inline_data_size = inline_sge_count * PAGE_SIZE;
+               nport->inline_data_size = inline_sge_count * PAGE_SIZE;
                inline_page_count = inline_sge_count;
        }
-       ndev->inline_data_size = port->inline_data_size;
+       ndev->inline_data_size = nport->inline_data_size;
        ndev->inline_page_count = inline_page_count;
        ndev->device = cm_id->device;
        kref_init(&ndev->ref);
@@ -1024,6 +1033,7 @@ static int nvmet_rdma_create_queue_ib(struct nvmet_rdma_queue *queue)
                pr_err("failed to create_qp ret= %d\n", ret);
                goto err_destroy_cq;
        }
+       queue->qp = queue->cm_id->qp;
 
        atomic_set(&queue->sq_wr_avail, qp_attr.cap.max_send_wr);
 
@@ -1052,11 +1062,10 @@ err_destroy_cq:
 
 static void nvmet_rdma_destroy_queue_ib(struct nvmet_rdma_queue *queue)
 {
-       struct ib_qp *qp = queue->cm_id->qp;
-
-       ib_drain_qp(qp);
-       rdma_destroy_id(queue->cm_id);
-       ib_destroy_qp(qp);
+       ib_drain_qp(queue->qp);
+       if (queue->cm_id)
+               rdma_destroy_id(queue->cm_id);
+       ib_destroy_qp(queue->qp);
        ib_free_cq(queue->cq);
 }
 
@@ -1266,6 +1275,7 @@ static int nvmet_rdma_cm_accept(struct rdma_cm_id *cm_id,
 static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id,
                struct rdma_cm_event *event)
 {
+       struct nvmet_rdma_port *port = cm_id->context;
        struct nvmet_rdma_device *ndev;
        struct nvmet_rdma_queue *queue;
        int ret = -EINVAL;
@@ -1281,7 +1291,7 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id,
                ret = -ENOMEM;
                goto put_device;
        }
-       queue->port = cm_id->context;
+       queue->port = port->nport;
 
        if (queue->host_qid == 0) {
                /* Let inflight controller teardown complete */
@@ -1290,9 +1300,12 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id,
 
        ret = nvmet_rdma_cm_accept(cm_id, queue, &event->param.conn);
        if (ret) {
-               schedule_work(&queue->release_work);
-               /* Destroying rdma_cm id is not needed here */
-               return 0;
+               /*
+                * Don't destroy the cm_id in free path, as we implicitly
+                * destroy the cm_id here with non-zero ret code.
+                */
+               queue->cm_id = NULL;
+               goto free_queue;
        }
 
        mutex_lock(&nvmet_rdma_queue_mutex);
@@ -1301,6 +1314,8 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id,
 
        return 0;
 
+free_queue:
+       nvmet_rdma_free_queue(queue);
 put_device:
        kref_put(&ndev->ref, nvmet_rdma_free_dev);
 
@@ -1406,7 +1421,7 @@ static void nvmet_rdma_queue_connect_fail(struct rdma_cm_id *cm_id,
 static int nvmet_rdma_device_removal(struct rdma_cm_id *cm_id,
                struct nvmet_rdma_queue *queue)
 {
-       struct nvmet_port *port;
+       struct nvmet_rdma_port *port;
 
        if (queue) {
                /*
@@ -1425,7 +1440,7 @@ static int nvmet_rdma_device_removal(struct rdma_cm_id *cm_id,
         * cm_id destroy. use atomic xchg to make sure
         * we don't compete with remove_port.
         */
-       if (xchg(&port->priv, NULL) != cm_id)
+       if (xchg(&port->cm_id, NULL) != cm_id)
                return 0;
 
        /*
@@ -1456,6 +1471,13 @@ static int nvmet_rdma_cm_handler(struct rdma_cm_id *cm_id,
                nvmet_rdma_queue_established(queue);
                break;
        case RDMA_CM_EVENT_ADDR_CHANGE:
+               if (!queue) {
+                       struct nvmet_rdma_port *port = cm_id->context;
+
+                       schedule_delayed_work(&port->repair_work, 0);
+                       break;
+               }
+               /* FALLTHROUGH */
        case RDMA_CM_EVENT_DISCONNECTED:
        case RDMA_CM_EVENT_TIMEWAIT_EXIT:
                nvmet_rdma_queue_disconnect(queue);
@@ -1498,42 +1520,19 @@ restart:
        mutex_unlock(&nvmet_rdma_queue_mutex);
 }
 
-static int nvmet_rdma_add_port(struct nvmet_port *port)
+static void nvmet_rdma_disable_port(struct nvmet_rdma_port *port)
 {
-       struct rdma_cm_id *cm_id;
-       struct sockaddr_storage addr = { };
-       __kernel_sa_family_t af;
-       int ret;
+       struct rdma_cm_id *cm_id = xchg(&port->cm_id, NULL);
 
-       switch (port->disc_addr.adrfam) {
-       case NVMF_ADDR_FAMILY_IP4:
-               af = AF_INET;
-               break;
-       case NVMF_ADDR_FAMILY_IP6:
-               af = AF_INET6;
-               break;
-       default:
-               pr_err("address family %d not supported\n",
-                               port->disc_addr.adrfam);
-               return -EINVAL;
-       }
-
-       if (port->inline_data_size < 0) {
-               port->inline_data_size = NVMET_RDMA_DEFAULT_INLINE_DATA_SIZE;
-       } else if (port->inline_data_size > NVMET_RDMA_MAX_INLINE_DATA_SIZE) {
-               pr_warn("inline_data_size %u is too large, reducing to %u\n",
-                       port->inline_data_size,
-                       NVMET_RDMA_MAX_INLINE_DATA_SIZE);
-               port->inline_data_size = NVMET_RDMA_MAX_INLINE_DATA_SIZE;
-       }
+       if (cm_id)
+               rdma_destroy_id(cm_id);
+}
 
-       ret = inet_pton_with_scope(&init_net, af, port->disc_addr.traddr,
-                       port->disc_addr.trsvcid, &addr);
-       if (ret) {
-               pr_err("malformed ip/port passed: %s:%s\n",
-                       port->disc_addr.traddr, port->disc_addr.trsvcid);
-               return ret;
-       }
+static int nvmet_rdma_enable_port(struct nvmet_rdma_port *port)
+{
+       struct sockaddr *addr = (struct sockaddr *)&port->addr;
+       struct rdma_cm_id *cm_id;
+       int ret;
 
        cm_id = rdma_create_id(&init_net, nvmet_rdma_cm_handler, port,
                        RDMA_PS_TCP, IB_QPT_RC);
@@ -1552,23 +1551,19 @@ static int nvmet_rdma_add_port(struct nvmet_port *port)
                goto out_destroy_id;
        }
 
-       ret = rdma_bind_addr(cm_id, (struct sockaddr *)&addr);
+       ret = rdma_bind_addr(cm_id, addr);
        if (ret) {
-               pr_err("binding CM ID to %pISpcs failed (%d)\n",
-                       (struct sockaddr *)&addr, ret);
+               pr_err("binding CM ID to %pISpcs failed (%d)\n", addr, ret);
                goto out_destroy_id;
        }
 
        ret = rdma_listen(cm_id, 128);
        if (ret) {
-               pr_err("listening to %pISpcs failed (%d)\n",
-                       (struct sockaddr *)&addr, ret);
+               pr_err("listening to %pISpcs failed (%d)\n", addr, ret);
                goto out_destroy_id;
        }
 
-       pr_info("enabling port %d (%pISpcs)\n",
-               le16_to_cpu(port->disc_addr.portid), (struct sockaddr *)&addr);
-       port->priv = cm_id;
+       port->cm_id = cm_id;
        return 0;
 
 out_destroy_id:
@@ -1576,18 +1571,92 @@ out_destroy_id:
        return ret;
 }
 
-static void nvmet_rdma_remove_port(struct nvmet_port *port)
+static void nvmet_rdma_repair_port_work(struct work_struct *w)
 {
-       struct rdma_cm_id *cm_id = xchg(&port->priv, NULL);
+       struct nvmet_rdma_port *port = container_of(to_delayed_work(w),
+                       struct nvmet_rdma_port, repair_work);
+       int ret;
 
-       if (cm_id)
-               rdma_destroy_id(cm_id);
+       nvmet_rdma_disable_port(port);
+       ret = nvmet_rdma_enable_port(port);
+       if (ret)
+               schedule_delayed_work(&port->repair_work, 5 * HZ);
+}
+
+static int nvmet_rdma_add_port(struct nvmet_port *nport)
+{
+       struct nvmet_rdma_port *port;
+       __kernel_sa_family_t af;
+       int ret;
+
+       port = kzalloc(sizeof(*port), GFP_KERNEL);
+       if (!port)
+               return -ENOMEM;
+
+       nport->priv = port;
+       port->nport = nport;
+       INIT_DELAYED_WORK(&port->repair_work, nvmet_rdma_repair_port_work);
+
+       switch (nport->disc_addr.adrfam) {
+       case NVMF_ADDR_FAMILY_IP4:
+               af = AF_INET;
+               break;
+       case NVMF_ADDR_FAMILY_IP6:
+               af = AF_INET6;
+               break;
+       default:
+               pr_err("address family %d not supported\n",
+                       nport->disc_addr.adrfam);
+               ret = -EINVAL;
+               goto out_free_port;
+       }
+
+       if (nport->inline_data_size < 0) {
+               nport->inline_data_size = NVMET_RDMA_DEFAULT_INLINE_DATA_SIZE;
+       } else if (nport->inline_data_size > NVMET_RDMA_MAX_INLINE_DATA_SIZE) {
+               pr_warn("inline_data_size %u is too large, reducing to %u\n",
+                       nport->inline_data_size,
+                       NVMET_RDMA_MAX_INLINE_DATA_SIZE);
+               nport->inline_data_size = NVMET_RDMA_MAX_INLINE_DATA_SIZE;
+       }
+
+       ret = inet_pton_with_scope(&init_net, af, nport->disc_addr.traddr,
+                       nport->disc_addr.trsvcid, &port->addr);
+       if (ret) {
+               pr_err("malformed ip/port passed: %s:%s\n",
+                       nport->disc_addr.traddr, nport->disc_addr.trsvcid);
+               goto out_free_port;
+       }
+
+       ret = nvmet_rdma_enable_port(port);
+       if (ret)
+               goto out_free_port;
+
+       pr_info("enabling port %d (%pISpcs)\n",
+               le16_to_cpu(nport->disc_addr.portid),
+               (struct sockaddr *)&port->addr);
+
+       return 0;
+
+out_free_port:
+       kfree(port);
+       return ret;
+}
+
+static void nvmet_rdma_remove_port(struct nvmet_port *nport)
+{
+       struct nvmet_rdma_port *port = nport->priv;
+
+       cancel_delayed_work_sync(&port->repair_work);
+       nvmet_rdma_disable_port(port);
+       kfree(port);
 }
 
 static void nvmet_rdma_disc_port_addr(struct nvmet_req *req,
-               struct nvmet_port *port, char *traddr)
+               struct nvmet_port *nport, char *traddr)
 {
-       struct rdma_cm_id *cm_id = port->priv;
+       struct nvmet_rdma_port *port = nport->priv;
+       struct rdma_cm_id *cm_id = port->cm_id;
 
        if (inet_addr_is_any((struct sockaddr *)&cm_id->route.addr.src_addr)) {
                struct nvmet_rdma_rsp *rsp =
@@ -1597,7 +1666,7 @@ static void nvmet_rdma_disc_port_addr(struct nvmet_req *req,
 
                sprintf(traddr, "%pISc", addr);
        } else {
-               memcpy(traddr, port->disc_addr.traddr, NVMF_TRADDR_SIZE);
+               memcpy(traddr, nport->disc_addr.traddr, NVMF_TRADDR_SIZE);
        }
 }
 
index 3ef0bb2..390e92f 100644 (file)
@@ -366,6 +366,7 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(pci_enable_pasid);
 
 /**
  * pci_disable_pasid - Disable the PASID capability
@@ -390,6 +391,7 @@ void pci_disable_pasid(struct pci_dev *pdev)
 
        pdev->pasid_enabled = 0;
 }
+EXPORT_SYMBOL_GPL(pci_disable_pasid);
 
 /**
  * pci_restore_pasid_state - Restore PASID capabilities
@@ -441,6 +443,7 @@ int pci_pasid_features(struct pci_dev *pdev)
 
        return supported;
 }
+EXPORT_SYMBOL_GPL(pci_pasid_features);
 
 #define PASID_NUMBER_SHIFT     8
 #define PASID_NUMBER_MASK      (0x1f << PASID_NUMBER_SHIFT)
@@ -469,4 +472,5 @@ int pci_max_pasids(struct pci_dev *pdev)
 
        return (1 << supported);
 }
+EXPORT_SYMBOL_GPL(pci_max_pasids);
 #endif /* CONFIG_PCI_PASID */
index 5f57282..03ea512 100644 (file)
@@ -7,7 +7,7 @@ config MFD_CROS_EC
        tristate "Platform support for Chrome hardware (transitional)"
        select CHROME_PLATFORMS
        select CROS_EC
-       select CONFIG_MFD_CROS_EC_DEV
+       select MFD_CROS_EC_DEV
        depends on X86 || ARM || ARM64 || COMPILE_TEST
        help
          This is a transitional Kconfig option and will be removed after
@@ -214,6 +214,17 @@ config CROS_EC_SYSFS
          To compile this driver as a module, choose M here: the
          module will be called cros_ec_sysfs.
 
+config CROS_EC_TYPEC
+       tristate "ChromeOS EC Type-C Connector Control"
+       depends on MFD_CROS_EC_DEV && TYPEC
+       default MFD_CROS_EC_DEV
+       help
+         If you say Y here, you get support for accessing Type C connector
+         information from the Chrome OS EC.
+
+         To compile this driver as a module, choose M here: the module will be
+         called cros_ec_typec.
+
 config CROS_USBPD_LOGGER
        tristate "Logging driver for USB PD charger"
        depends on CHARGER_CROS_USBPD
@@ -226,6 +237,20 @@ config CROS_USBPD_LOGGER
          To compile this driver as a module, choose M here: the
          module will be called cros_usbpd_logger.
 
+config CROS_USBPD_NOTIFY
+       tristate "ChromeOS Type-C power delivery event notifier"
+       depends on MFD_CROS_EC_DEV
+       default MFD_CROS_EC_DEV
+       help
+         If you say Y here, you get support for Type-C PD event notifications
+         from the ChromeOS EC. On ACPI platorms this driver will bind to the
+         GOOG0003 ACPI device, and on platforms which don't have this device it
+         will get initialized on ECs which support the feature
+         EC_FEATURE_USB_PD.
+
+         To compile this driver as a module, choose M here: the
+         module will be called cros_usbpd_notify.
+
 source "drivers/platform/chrome/wilco_ec/Kconfig"
 
 endif # CHROMEOS_PLATFORMS
index aacd592..41baccb 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_CROS_EC_ISHTP)           += cros_ec_ishtp.o
 obj-$(CONFIG_CROS_EC_RPMSG)            += cros_ec_rpmsg.o
 obj-$(CONFIG_CROS_EC_SPI)              += cros_ec_spi.o
 cros_ec_lpcs-objs                      := cros_ec_lpc.o cros_ec_lpc_mec.o
+obj-$(CONFIG_CROS_EC_TYPEC)            += cros_ec_typec.o
 obj-$(CONFIG_CROS_EC_LPC)              += cros_ec_lpcs.o
 obj-$(CONFIG_CROS_EC_PROTO)            += cros_ec_proto.o cros_ec_trace.o
 obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT)   += cros_kbd_led_backlight.o
@@ -19,8 +20,10 @@ obj-$(CONFIG_CROS_EC_CHARDEV)                += cros_ec_chardev.o
 obj-$(CONFIG_CROS_EC_LIGHTBAR)         += cros_ec_lightbar.o
 obj-$(CONFIG_CROS_EC_VBC)              += cros_ec_vbc.o
 obj-$(CONFIG_CROS_EC_DEBUGFS)          += cros_ec_debugfs.o
-obj-$(CONFIG_CROS_EC_SENSORHUB)                += cros_ec_sensorhub.o
+cros-ec-sensorhub-objs                 := cros_ec_sensorhub.o cros_ec_sensorhub_ring.o
+obj-$(CONFIG_CROS_EC_SENSORHUB)                += cros-ec-sensorhub.o
 obj-$(CONFIG_CROS_EC_SYSFS)            += cros_ec_sysfs.o
 obj-$(CONFIG_CROS_USBPD_LOGGER)                += cros_usbpd_logger.o
+obj-$(CONFIG_CROS_USBPD_NOTIFY)                += cros_usbpd_notify.o
 
 obj-$(CONFIG_WILCO_EC)                 += wilco_ec/
index 4f3651f..472a03d 100644 (file)
@@ -103,7 +103,7 @@ chromes_laptop_instantiate_i2c_device(struct i2c_adapter *adapter,
                        pr_debug("%d-%02x is probed at %02x\n",
                                 adapter->nr, info->addr, dummy->addr);
                        i2c_unregister_device(dummy);
-                       client = i2c_new_device(adapter, info);
+                       client = i2c_new_client_device(adapter, info);
                }
        }
 
index 6fc8f2c..3104680 100644 (file)
@@ -120,7 +120,7 @@ static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
 
        buf.msg.command = EC_CMD_HOST_SLEEP_EVENT;
 
-       ret = cros_ec_cmd_xfer(ec_dev, &buf.msg);
+       ret = cros_ec_cmd_xfer_status(ec_dev, &buf.msg);
 
        /* For now, report failure to transition to S0ix with a warning. */
        if (ret >= 0 && ec_dev->host_sleep_v1 &&
@@ -138,6 +138,24 @@ static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
        return ret;
 }
 
+static int cros_ec_ready_event(struct notifier_block *nb,
+                              unsigned long queued_during_suspend,
+                              void *_notify)
+{
+       struct cros_ec_device *ec_dev = container_of(nb, struct cros_ec_device,
+                                                    notifier_ready);
+       u32 host_event = cros_ec_get_host_event(ec_dev);
+
+       if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_INTERFACE_READY)) {
+               mutex_lock(&ec_dev->lock);
+               cros_ec_query_all(ec_dev);
+               mutex_unlock(&ec_dev->lock);
+               return NOTIFY_OK;
+       }
+
+       return NOTIFY_DONE;
+}
+
 /**
  * cros_ec_register() - Register a new ChromeOS EC, using the provided info.
  * @ec_dev: Device to register.
@@ -237,6 +255,18 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
                dev_dbg(ec_dev->dev, "Error %d clearing sleep event to ec",
                        err);
 
+       if (ec_dev->mkbp_event_supported) {
+               /*
+                * Register the notifier for EC_HOST_EVENT_INTERFACE_READY
+                * event.
+                */
+               ec_dev->notifier_ready.notifier_call = cros_ec_ready_event;
+               err = blocking_notifier_chain_register(&ec_dev->event_notifier,
+                                                     &ec_dev->notifier_ready);
+               if (err)
+                       return err;
+       }
+
        dev_info(dev, "Chrome EC device registered\n");
 
        return 0;
index c65e70b..e0bce86 100644 (file)
@@ -48,7 +48,7 @@ struct ec_event {
        struct list_head node;
        size_t size;
        u8 event_type;
-       u8 data[0];
+       u8 data[];
 };
 
 static int ec_get_version(struct cros_ec_dev *ec, char *str, int maxlen)
@@ -301,7 +301,7 @@ static long cros_ec_chardev_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg)
        }
 
        s_cmd->command += ec->cmd_offset;
-       ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd);
+       ret = cros_ec_cmd_xfer_status(ec->ec_dev, s_cmd);
        /* Only copy data to userland if data was received. */
        if (ret < 0)
                goto exit;
index b4c110c..b59180b 100644 (file)
@@ -116,7 +116,7 @@ static int get_lightbar_version(struct cros_ec_dev *ec,
 
        param = (struct ec_params_lightbar *)msg->data;
        param->cmd = LIGHTBAR_CMD_VERSION;
-       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
+       ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
        if (ret < 0) {
                ret = 0;
                goto exit;
@@ -193,15 +193,10 @@ static ssize_t brightness_store(struct device *dev,
        if (ret)
                goto exit;
 
-       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
+       ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
        if (ret < 0)
                goto exit;
 
-       if (msg->result != EC_RES_SUCCESS) {
-               ret = -EINVAL;
-               goto exit;
-       }
-
        ret = count;
 exit:
        kfree(msg);
@@ -258,13 +253,10 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr,
                                        goto exit;
                        }
 
-                       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
+                       ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
                        if (ret < 0)
                                goto exit;
 
-                       if (msg->result != EC_RES_SUCCESS)
-                               goto exit;
-
                        i = 0;
                        ok = 1;
                }
@@ -305,14 +297,13 @@ static ssize_t sequence_show(struct device *dev,
        if (ret)
                goto exit;
 
-       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
-       if (ret < 0)
-               goto exit;
-
-       if (msg->result != EC_RES_SUCCESS) {
+       ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
+       if (ret == -EPROTO) {
                ret = scnprintf(buf, PAGE_SIZE,
                                "ERROR: EC returned %d\n", msg->result);
                goto exit;
+       } else if (ret < 0) {
+               goto exit;
        }
 
        resp = (struct ec_response_lightbar *)msg->data;
@@ -344,13 +335,10 @@ static int lb_send_empty_cmd(struct cros_ec_dev *ec, uint8_t cmd)
        if (ret)
                goto error;
 
-       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
+       ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
        if (ret < 0)
                goto error;
-       if (msg->result != EC_RES_SUCCESS) {
-               ret = -EINVAL;
-               goto error;
-       }
+
        ret = 0;
 error:
        kfree(msg);
@@ -377,13 +365,10 @@ static int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
        if (ret)
                goto error;
 
-       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
+       ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
        if (ret < 0)
                goto error;
-       if (msg->result != EC_RES_SUCCESS) {
-               ret = -EINVAL;
-               goto error;
-       }
+
        ret = 0;
 error:
        kfree(msg);
@@ -425,15 +410,10 @@ static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
        if (ret)
                goto exit;
 
-       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
+       ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
        if (ret < 0)
                goto exit;
 
-       if (msg->result != EC_RES_SUCCESS) {
-               ret = -EINVAL;
-               goto exit;
-       }
-
        ret = count;
 exit:
        kfree(msg);
@@ -487,13 +467,9 @@ static ssize_t program_store(struct device *dev, struct device_attribute *attr,
         */
        msg->outsize = count + extra_bytes;
 
-       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
+       ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
        if (ret < 0)
                goto exit;
-       if (msg->result != EC_RES_SUCCESS) {
-               ret = -EINVAL;
-               goto exit;
-       }
 
        ret = count;
 exit:
index 3cfa643..3e745e0 100644 (file)
@@ -553,7 +553,10 @@ EXPORT_SYMBOL(cros_ec_cmd_xfer);
  * replied with success status. It's not necessary to check msg->result when
  * using this function.
  *
- * Return: The number of bytes transferred on success or negative error code.
+ * Return:
+ * >=0 - The number of bytes transferred
+ * -ENOTSUPP - Operation not supported
+ * -EPROTO - Protocol error
  */
 int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
                            struct cros_ec_command *msg)
@@ -563,6 +566,10 @@ int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
        ret = cros_ec_cmd_xfer(ec_dev, msg);
        if (ret < 0) {
                dev_err(ec_dev->dev, "Command xfer error (err:%d)\n", ret);
+       } else if (msg->result == EC_RES_INVALID_VERSION) {
+               dev_dbg(ec_dev->dev, "Command invalid version (err:%d)\n",
+                       msg->result);
+               return -ENOTSUPP;
        } else if (msg->result != EC_RES_SUCCESS) {
                dev_dbg(ec_dev->dev, "Command result (err: %d)\n", msg->result);
                return -EPROTO;
index dbc3f55..7e8629e 100644 (file)
@@ -44,6 +44,8 @@ struct cros_ec_rpmsg {
        struct completion xfer_ack;
        struct work_struct host_event_work;
        struct rpmsg_endpoint *ept;
+       bool has_pending_host_event;
+       bool probe_done;
 };
 
 /**
@@ -177,7 +179,14 @@ static int cros_ec_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
                memcpy(ec_dev->din, resp->data, len);
                complete(&ec_rpmsg->xfer_ack);
        } else if (resp->type == HOST_EVENT_MARK) {
-               schedule_work(&ec_rpmsg->host_event_work);
+               /*
+                * If the host event is sent before cros_ec_register is
+                * finished, queue the host event.
+                */
+               if (ec_rpmsg->probe_done)
+                       schedule_work(&ec_rpmsg->host_event_work);
+               else
+                       ec_rpmsg->has_pending_host_event = true;
        } else {
                dev_warn(ec_dev->dev, "rpmsg received invalid type = %d",
                         resp->type);
@@ -240,6 +249,11 @@ static int cros_ec_rpmsg_probe(struct rpmsg_device *rpdev)
                return ret;
        }
 
+       ec_rpmsg->probe_done = true;
+
+       if (ec_rpmsg->has_pending_host_event)
+               schedule_work(&ec_rpmsg->host_event_work);
+
        return 0;
 }
 
index 79fefd3..b7f2c00 100644 (file)
@@ -50,10 +50,8 @@ static int cros_ec_sensorhub_register(struct device *dev,
                                      struct cros_ec_sensorhub *sensorhub)
 {
        int sensor_type[MOTIONSENSE_TYPE_MAX] = { 0 };
+       struct cros_ec_command *msg = sensorhub->msg;
        struct cros_ec_dev *ec = sensorhub->ec;
-       struct ec_params_motion_sense *params;
-       struct ec_response_motion_sense *resp;
-       struct cros_ec_command *msg;
        int ret, i, sensor_num;
        char *name;
 
@@ -65,27 +63,19 @@ static int cros_ec_sensorhub_register(struct device *dev,
                return sensor_num;
        }
 
+       sensorhub->sensor_num = sensor_num;
        if (sensor_num == 0) {
                dev_err(dev, "Zero sensors reported.\n");
                return -EINVAL;
        }
 
-       /* Prepare a message to send INFO command to each sensor. */
-       msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*resp)),
-                     GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
-
        msg->version = 1;
-       msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
-       msg->outsize = sizeof(*params);
-       msg->insize = sizeof(*resp);
-       params = (struct ec_params_motion_sense *)msg->data;
-       resp = (struct ec_response_motion_sense *)msg->data;
+       msg->insize = sizeof(struct ec_response_motion_sense);
+       msg->outsize = sizeof(struct ec_params_motion_sense);
 
        for (i = 0; i < sensor_num; i++) {
-               params->cmd = MOTIONSENSE_CMD_INFO;
-               params->info.sensor_num = i;
+               sensorhub->params->cmd = MOTIONSENSE_CMD_INFO;
+               sensorhub->params->info.sensor_num = i;
 
                ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
                if (ret < 0) {
@@ -94,7 +84,7 @@ static int cros_ec_sensorhub_register(struct device *dev,
                        continue;
                }
 
-               switch (resp->info.type) {
+               switch (sensorhub->resp->info.type) {
                case MOTIONSENSE_TYPE_ACCEL:
                        name = "cros-ec-accel";
                        break;
@@ -117,15 +107,16 @@ static int cros_ec_sensorhub_register(struct device *dev,
                        name = "cros-ec-activity";
                        break;
                default:
-                       dev_warn(dev, "unknown type %d\n", resp->info.type);
+                       dev_warn(dev, "unknown type %d\n",
+                                sensorhub->resp->info.type);
                        continue;
                }
 
                ret = cros_ec_sensorhub_allocate_sensor(dev, name, i);
                if (ret)
-                       goto error;
+                       return ret;
 
-               sensor_type[resp->info.type]++;
+               sensor_type[sensorhub->resp->info.type]++;
        }
 
        if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2)
@@ -137,29 +128,41 @@ static int cros_ec_sensorhub_register(struct device *dev,
                                                        "cros-ec-lid-angle",
                                                        0);
                if (ret)
-                       goto error;
+                       return ret;
        }
 
-       kfree(msg);
        return 0;
-
-error:
-       kfree(msg);
-       return ret;
 }
 
 static int cros_ec_sensorhub_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       struct cros_ec_dev *ec = dev_get_drvdata(dev->parent);
        struct cros_ec_sensorhub *data;
+       struct cros_ec_command *msg;
        int ret;
        int i;
 
+       msg = devm_kzalloc(dev, sizeof(struct cros_ec_command) +
+                          max((u16)sizeof(struct ec_params_motion_sense),
+                              ec->ec_dev->max_response), GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
+
        data = devm_kzalloc(dev, sizeof(struct cros_ec_sensorhub), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       data->ec = dev_get_drvdata(dev->parent);
+       mutex_init(&data->cmd_lock);
+
+       data->dev = dev;
+       data->ec = ec;
+       data->msg = msg;
+       data->params = (struct ec_params_motion_sense *)msg->data;
+       data->resp = (struct ec_response_motion_sense *)msg->data;
+
        dev_set_drvdata(dev, data);
 
        /* Check whether this EC is a sensor hub. */
@@ -172,7 +175,8 @@ static int cros_ec_sensorhub_probe(struct platform_device *pdev)
                 * If the device has sensors but does not claim to
                 * be a sensor hub, we are in legacy mode.
                 */
-               for (i = 0; i < 2; i++) {
+               data->sensor_num = 2;
+               for (i = 0; i < data->sensor_num; i++) {
                        ret = cros_ec_sensorhub_allocate_sensor(dev,
                                                "cros-ec-accel-legacy", i);
                        if (ret)
@@ -180,12 +184,63 @@ static int cros_ec_sensorhub_probe(struct platform_device *pdev)
                }
        }
 
+       /*
+        * If the EC does not have a FIFO, the sensors will query their data
+        * themselves via sysfs or a software trigger.
+        */
+       if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) {
+               ret = cros_ec_sensorhub_ring_add(data);
+               if (ret)
+                       return ret;
+               /*
+                * The msg and its data is not under the control of the ring
+                * handler.
+                */
+               return devm_add_action_or_reset(dev,
+                                               cros_ec_sensorhub_ring_remove,
+                                               data);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+/*
+ * When the EC is suspending, we must stop sending interrupt,
+ * we may use the same interrupt line for waking up the device.
+ * Tell the EC to stop sending non-interrupt event on the iio ring.
+ */
+static int cros_ec_sensorhub_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct cros_ec_sensorhub *sensorhub = platform_get_drvdata(pdev);
+       struct cros_ec_dev *ec = sensorhub->ec;
+
+       if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO))
+               return cros_ec_sensorhub_ring_fifo_enable(sensorhub, false);
        return 0;
 }
 
+static int cros_ec_sensorhub_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct cros_ec_sensorhub *sensorhub = platform_get_drvdata(pdev);
+       struct cros_ec_dev *ec = sensorhub->ec;
+
+       if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO))
+               return cros_ec_sensorhub_ring_fifo_enable(sensorhub, true);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(cros_ec_sensorhub_pm_ops,
+               cros_ec_sensorhub_suspend,
+               cros_ec_sensorhub_resume);
+
 static struct platform_driver cros_ec_sensorhub_driver = {
        .driver = {
                .name = DRV_NAME,
+               .pm = &cros_ec_sensorhub_pm_ops,
        },
        .probe = cros_ec_sensorhub_probe,
 };
diff --git a/drivers/platform/chrome/cros_ec_sensorhub_ring.c b/drivers/platform/chrome/cros_ec_sensorhub_ring.c
new file mode 100644 (file)
index 0000000..230e6cf
--- /dev/null
@@ -0,0 +1,1046 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for Chrome OS EC Sensor hub FIFO.
+ *
+ * Copyright 2020 Google LLC
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_data/cros_ec_commands.h>
+#include <linux/platform_data/cros_ec_proto.h>
+#include <linux/platform_data/cros_ec_sensorhub.h>
+#include <linux/platform_device.h>
+#include <linux/sort.h>
+#include <linux/slab.h>
+
+/* Precision of fixed point for the m values from the filter */
+#define M_PRECISION BIT(23)
+
+/* Only activate the filter once we have at least this many elements. */
+#define TS_HISTORY_THRESHOLD 8
+
+/*
+ * If we don't have any history entries for this long, empty the filter to
+ * make sure there are no big discontinuities.
+ */
+#define TS_HISTORY_BORED_US 500000
+
+/* To measure by how much the filter is overshooting, if it happens. */
+#define FUTURE_TS_ANALYTICS_COUNT_MAX 100
+
+static inline int
+cros_sensorhub_send_sample(struct cros_ec_sensorhub *sensorhub,
+                          struct cros_ec_sensors_ring_sample *sample)
+{
+       cros_ec_sensorhub_push_data_cb_t cb;
+       int id = sample->sensor_id;
+       struct iio_dev *indio_dev;
+
+       if (id > sensorhub->sensor_num)
+               return -EINVAL;
+
+       cb = sensorhub->push_data[id].push_data_cb;
+       if (!cb)
+               return 0;
+
+       indio_dev = sensorhub->push_data[id].indio_dev;
+
+       if (sample->flag & MOTIONSENSE_SENSOR_FLAG_FLUSH)
+               return 0;
+
+       return cb(indio_dev, sample->vector, sample->timestamp);
+}
+
+/**
+ * cros_ec_sensorhub_register_push_data() - register the callback to the hub.
+ *
+ * @sensorhub : Sensor Hub object
+ * @sensor_num : The sensor the caller is interested in.
+ * @indio_dev : The iio device to use when a sample arrives.
+ * @cb : The callback to call when a sample arrives.
+ *
+ * The callback cb will be used by cros_ec_sensorhub_ring to distribute events
+ * from the EC.
+ *
+ * Return: 0 when callback is registered.
+ *         EINVAL is the sensor number is invalid or the slot already used.
+ */
+int cros_ec_sensorhub_register_push_data(struct cros_ec_sensorhub *sensorhub,
+                                        u8 sensor_num,
+                                        struct iio_dev *indio_dev,
+                                        cros_ec_sensorhub_push_data_cb_t cb)
+{
+       if (sensor_num >= sensorhub->sensor_num)
+               return -EINVAL;
+       if (sensorhub->push_data[sensor_num].indio_dev)
+               return -EINVAL;
+
+       sensorhub->push_data[sensor_num].indio_dev = indio_dev;
+       sensorhub->push_data[sensor_num].push_data_cb = cb;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cros_ec_sensorhub_register_push_data);
+
+void cros_ec_sensorhub_unregister_push_data(struct cros_ec_sensorhub *sensorhub,
+                                           u8 sensor_num)
+{
+       sensorhub->push_data[sensor_num].indio_dev = NULL;
+       sensorhub->push_data[sensor_num].push_data_cb = NULL;
+}
+EXPORT_SYMBOL_GPL(cros_ec_sensorhub_unregister_push_data);
+
+/**
+ * cros_ec_sensorhub_ring_fifo_enable() - Enable or disable interrupt generation
+ *                                       for FIFO events.
+ * @sensorhub: Sensor Hub object
+ * @on: true when events are requested.
+ *
+ * To be called before sleeping or when noone is listening.
+ * Return: 0 on success, or an error when we can not communicate with the EC.
+ *
+ */
+int cros_ec_sensorhub_ring_fifo_enable(struct cros_ec_sensorhub *sensorhub,
+                                      bool on)
+{
+       int ret, i;
+
+       mutex_lock(&sensorhub->cmd_lock);
+       if (sensorhub->tight_timestamps)
+               for (i = 0; i < sensorhub->sensor_num; i++)
+                       sensorhub->batch_state[i].last_len = 0;
+
+       sensorhub->params->cmd = MOTIONSENSE_CMD_FIFO_INT_ENABLE;
+       sensorhub->params->fifo_int_enable.enable = on;
+
+       sensorhub->msg->outsize = sizeof(struct ec_params_motion_sense);
+       sensorhub->msg->insize = sizeof(struct ec_response_motion_sense);
+
+       ret = cros_ec_cmd_xfer_status(sensorhub->ec->ec_dev, sensorhub->msg);
+       mutex_unlock(&sensorhub->cmd_lock);
+
+       /* We expect to receive a payload of 4 bytes, ignore. */
+       if (ret > 0)
+               ret = 0;
+
+       return ret;
+}
+
+static int cros_ec_sensor_ring_median_cmp(const void *pv1, const void *pv2)
+{
+       s64 v1 = *(s64 *)pv1;
+       s64 v2 = *(s64 *)pv2;
+
+       if (v1 > v2)
+               return 1;
+       else if (v1 < v2)
+               return -1;
+       else
+               return 0;
+}
+
+/*
+ * cros_ec_sensor_ring_median: Gets median of an array of numbers
+ *
+ * For now it's implemented using an inefficient > O(n) sort then return
+ * the middle element. A more optimal method would be something like
+ * quickselect, but given that n = 64 we can probably live with it in the
+ * name of clarity.
+ *
+ * Warning: the input array gets modified (sorted)!
+ */
+static s64 cros_ec_sensor_ring_median(s64 *array, size_t length)
+{
+       sort(array, length, sizeof(s64), cros_ec_sensor_ring_median_cmp, NULL);
+       return array[length / 2];
+}
+
+/*
+ * IRQ Timestamp Filtering
+ *
+ * Lower down in cros_ec_sensor_ring_process_event(), for each sensor event
+ * we have to calculate it's timestamp in the AP timebase. There are 3 time
+ * points:
+ *   a - EC timebase, sensor event
+ *   b - EC timebase, IRQ
+ *   c - AP timebase, IRQ
+ *   a' - what we want: sensor even in AP timebase
+ *
+ * While a and b are recorded at accurate times (due to the EC real time
+ * nature); c is pretty untrustworthy, even though it's recorded the
+ * first thing in ec_irq_handler(). There is a very good change we'll get
+ * added lantency due to:
+ *   other irqs
+ *   ddrfreq
+ *   cpuidle
+ *
+ * Normally a' = c - b + a, but if we do that naive math any jitter in c
+ * will get coupled in a', which we don't want. We want a function
+ * a' = cros_ec_sensor_ring_ts_filter(a) which will filter out outliers in c.
+ *
+ * Think of a graph of AP time(b) on the y axis vs EC time(c) on the x axis.
+ * The slope of the line won't be exactly 1, there will be some clock drift
+ * between the 2 chips for various reasons (mechanical stress, temperature,
+ * voltage). We need to extrapolate values for a future x, without trusting
+ * recent y values too much.
+ *
+ * We use a median filter for the slope, then another median filter for the
+ * y-intercept to calculate this function:
+ *   dx[n] = x[n-1] - x[n]
+ *   dy[n] = x[n-1] - x[n]
+ *   m[n] = dy[n] / dx[n]
+ *   median_m = median(m[n-k:n])
+ *   error[i] = y[n-i] - median_m * x[n-i]
+ *   median_error = median(error[:k])
+ *   predicted_y = median_m * x + median_error
+ *
+ * Implementation differences from above:
+ * - Redefined y to be actually c - b, this gives us a lot more precision
+ * to do the math. (c-b)/b variations are more obvious than c/b variations.
+ * - Since we don't have floating point, any operations involving slope are
+ * done using fixed point math (*M_PRECISION)
+ * - Since x and y grow with time, we keep zeroing the graph (relative to
+ * the last sample), this way math involving *x[n-i] will not overflow
+ * - EC timestamps are kept in us, it improves the slope calculation precision
+ */
+
+/**
+ * cros_ec_sensor_ring_ts_filter_update() - Update filter history.
+ *
+ * @state: Filter information.
+ * @b: IRQ timestamp, EC timebase (us)
+ * @c: IRQ timestamp, AP timebase (ns)
+ *
+ * Given a new IRQ timestamp pair (EC and AP timebases), add it to the filter
+ * history.
+ */
+static void
+cros_ec_sensor_ring_ts_filter_update(struct cros_ec_sensors_ts_filter_state
+                                    *state,
+                                    s64 b, s64 c)
+{
+       s64 x, y;
+       s64 dx, dy;
+       s64 m; /* stored as *M_PRECISION */
+       s64 *m_history_copy = state->temp_buf;
+       s64 *error = state->temp_buf;
+       int i;
+
+       /* we trust b the most, that'll be our independent variable */
+       x = b;
+       /* y is the offset between AP and EC times, in ns */
+       y = c - b * 1000;
+
+       dx = (state->x_history[0] + state->x_offset) - x;
+       if (dx == 0)
+               return; /* we already have this irq in the history */
+       dy = (state->y_history[0] + state->y_offset) - y;
+       m = div64_s64(dy * M_PRECISION, dx);
+
+       /* Empty filter if we haven't seen any action in a while. */
+       if (-dx > TS_HISTORY_BORED_US)
+               state->history_len = 0;
+
+       /* Move everything over, also update offset to all absolute coords .*/
+       for (i = state->history_len - 1; i >= 1; i--) {
+               state->x_history[i] = state->x_history[i - 1] + dx;
+               state->y_history[i] = state->y_history[i - 1] + dy;
+
+               state->m_history[i] = state->m_history[i - 1];
+               /*
+                * Also use the same loop to copy m_history for future
+                * median extraction.
+                */
+               m_history_copy[i] = state->m_history[i - 1];
+       }
+
+       /* Store the x and y, but remember offset is actually last sample. */
+       state->x_offset = x;
+       state->y_offset = y;
+       state->x_history[0] = 0;
+       state->y_history[0] = 0;
+
+       state->m_history[0] = m;
+       m_history_copy[0] = m;
+
+       if (state->history_len < CROS_EC_SENSORHUB_TS_HISTORY_SIZE)
+               state->history_len++;
+
+       /* Precalculate things for the filter. */
+       if (state->history_len > TS_HISTORY_THRESHOLD) {
+               state->median_m =
+                   cros_ec_sensor_ring_median(m_history_copy,
+                                              state->history_len - 1);
+
+               /*
+                * Calculate y-intercepts as if m_median is the slope and
+                * points in the history are on the line. median_error will
+                * still be in the offset coordinate system.
+                */
+               for (i = 0; i < state->history_len; i++)
+                       error[i] = state->y_history[i] -
+                               div_s64(state->median_m * state->x_history[i],
+                                       M_PRECISION);
+               state->median_error =
+                       cros_ec_sensor_ring_median(error, state->history_len);
+       } else {
+               state->median_m = 0;
+               state->median_error = 0;
+       }
+}
+
+/**
+ * cros_ec_sensor_ring_ts_filter() - Translate EC timebase timestamp to AP
+ *                                   timebase
+ *
+ * @state: filter information.
+ * @x: any ec timestamp (us):
+ *
+ * cros_ec_sensor_ring_ts_filter(a) => a' event timestamp, AP timebase
+ * cros_ec_sensor_ring_ts_filter(b) => calculated timestamp when the EC IRQ
+ *                           should have happened on the AP, with low jitter
+ *
+ * Note: The filter will only activate once state->history_len goes
+ * over TS_HISTORY_THRESHOLD. Otherwise it'll just do the naive c - b + a
+ * transform.
+ *
+ * How to derive the formula, starting from:
+ *   f(x) = median_m * x + median_error
+ * That's the calculated AP - EC offset (at the x point in time)
+ * Undo the coordinate system transform:
+ *   f(x) = median_m * (x - x_offset) + median_error + y_offset
+ * Remember to undo the "y = c - b * 1000" modification:
+ *   f(x) = median_m * (x - x_offset) + median_error + y_offset + x * 1000
+ *
+ * Return: timestamp in AP timebase (ns)
+ */
+static s64
+cros_ec_sensor_ring_ts_filter(struct cros_ec_sensors_ts_filter_state *state,
+                             s64 x)
+{
+       return div_s64(state->median_m * (x - state->x_offset), M_PRECISION)
+              + state->median_error + state->y_offset + x * 1000;
+}
+
+/*
+ * Since a and b were originally 32 bit values from the EC,
+ * they overflow relatively often, casting is not enough, so we need to
+ * add an offset.
+ */
+static void
+cros_ec_sensor_ring_fix_overflow(s64 *ts,
+                                const s64 overflow_period,
+                                struct cros_ec_sensors_ec_overflow_state
+                                *state)
+{
+       s64 adjust;
+
+       *ts += state->offset;
+       if (abs(state->last - *ts) > (overflow_period / 2)) {
+               adjust = state->last > *ts ? overflow_period : -overflow_period;
+               state->offset += adjust;
+               *ts += adjust;
+       }
+       state->last = *ts;
+}
+
+static void
+cros_ec_sensor_ring_check_for_past_timestamp(struct cros_ec_sensorhub
+                                            *sensorhub,
+                                            struct cros_ec_sensors_ring_sample
+                                            *sample)
+{
+       const u8 sensor_id = sample->sensor_id;
+
+       /* If this event is earlier than one we saw before... */
+       if (sensorhub->batch_state[sensor_id].newest_sensor_event >
+           sample->timestamp)
+               /* mark it for spreading. */
+               sample->timestamp =
+                       sensorhub->batch_state[sensor_id].last_ts;
+       else
+               sensorhub->batch_state[sensor_id].newest_sensor_event =
+                       sample->timestamp;
+}
+
+/**
+ * cros_ec_sensor_ring_process_event() - Process one EC FIFO event
+ *
+ * @sensorhub: Sensor Hub object.
+ * @fifo_info: FIFO information from the EC (includes b point, EC timebase).
+ * @fifo_timestamp: EC IRQ, kernel timebase (aka c).
+ * @current_timestamp: calculated event timestamp, kernel timebase (aka a').
+ * @in: incoming FIFO event from EC (includes a point, EC timebase).
+ * @out: outgoing event to user space (includes a').
+ *
+ * Process one EC event, add it in the ring if necessary.
+ *
+ * Return: true if out event has been populated.
+ */
+static bool
+cros_ec_sensor_ring_process_event(struct cros_ec_sensorhub *sensorhub,
+                               const struct ec_response_motion_sense_fifo_info
+                               *fifo_info,
+                               const ktime_t fifo_timestamp,
+                               ktime_t *current_timestamp,
+                               struct ec_response_motion_sensor_data *in,
+                               struct cros_ec_sensors_ring_sample *out)
+{
+       const s64 now = cros_ec_get_time_ns();
+       int axis, async_flags;
+
+       /* Do not populate the filter based on asynchronous events. */
+       async_flags = in->flags &
+               (MOTIONSENSE_SENSOR_FLAG_ODR | MOTIONSENSE_SENSOR_FLAG_FLUSH);
+
+       if (in->flags & MOTIONSENSE_SENSOR_FLAG_TIMESTAMP && !async_flags) {
+               s64 a = in->timestamp;
+               s64 b = fifo_info->timestamp;
+               s64 c = fifo_timestamp;
+
+               cros_ec_sensor_ring_fix_overflow(&a, 1LL << 32,
+                                         &sensorhub->overflow_a);
+               cros_ec_sensor_ring_fix_overflow(&b, 1LL << 32,
+                                         &sensorhub->overflow_b);
+
+               if (sensorhub->tight_timestamps) {
+                       cros_ec_sensor_ring_ts_filter_update(
+                                       &sensorhub->filter, b, c);
+                       *current_timestamp = cros_ec_sensor_ring_ts_filter(
+                                       &sensorhub->filter, a);
+               } else {
+                       s64 new_timestamp;
+
+                       /*
+                        * Disable filtering since we might add more jitter
+                        * if b is in a random point in time.
+                        */
+                       new_timestamp = fifo_timestamp -
+                                       fifo_info->timestamp  * 1000 +
+                                       in->timestamp * 1000;
+                       /*
+                        * The timestamp can be stale if we had to use the fifo
+                        * info timestamp.
+                        */
+                       if (new_timestamp - *current_timestamp > 0)
+                               *current_timestamp = new_timestamp;
+               }
+       }
+
+       if (in->flags & MOTIONSENSE_SENSOR_FLAG_ODR) {
+               if (sensorhub->tight_timestamps) {
+                       sensorhub->batch_state[in->sensor_num].last_len = 0;
+                       sensorhub->batch_state[in->sensor_num].penul_len = 0;
+               }
+               /*
+                * ODR change is only useful for the sensor_ring, it does not
+                * convey information to clients.
+                */
+               return false;
+       }
+
+       if (in->flags & MOTIONSENSE_SENSOR_FLAG_FLUSH) {
+               out->sensor_id = in->sensor_num;
+               out->timestamp = *current_timestamp;
+               out->flag = in->flags;
+               if (sensorhub->tight_timestamps)
+                       sensorhub->batch_state[out->sensor_id].last_len = 0;
+               /*
+                * No other payload information provided with
+                * flush ack.
+                */
+               return true;
+       }
+
+       if (in->flags & MOTIONSENSE_SENSOR_FLAG_TIMESTAMP)
+               /* If we just have a timestamp, skip this entry. */
+               return false;
+
+       /* Regular sample */
+       out->sensor_id = in->sensor_num;
+       if (*current_timestamp - now > 0) {
+               /*
+                * This fix is needed to overcome the timestamp filter putting
+                * events in the future.
+                */
+               sensorhub->future_timestamp_total_ns +=
+                       *current_timestamp - now;
+               if (++sensorhub->future_timestamp_count ==
+                               FUTURE_TS_ANALYTICS_COUNT_MAX) {
+                       s64 avg = div_s64(sensorhub->future_timestamp_total_ns,
+                                       sensorhub->future_timestamp_count);
+                       dev_warn_ratelimited(sensorhub->dev,
+                                            "100 timestamps in the future, %lldns shaved on average\n",
+                                            avg);
+                       sensorhub->future_timestamp_count = 0;
+                       sensorhub->future_timestamp_total_ns = 0;
+               }
+               out->timestamp = now;
+       } else {
+               out->timestamp = *current_timestamp;
+       }
+
+       out->flag = in->flags;
+       for (axis = 0; axis < 3; axis++)
+               out->vector[axis] = in->data[axis];
+
+       if (sensorhub->tight_timestamps)
+               cros_ec_sensor_ring_check_for_past_timestamp(sensorhub, out);
+       return true;
+}
+
+/*
+ * cros_ec_sensor_ring_spread_add: Calculate proper timestamps then add to
+ *                                 ringbuffer.
+ *
+ * This is the new spreading code, assumes every sample's timestamp
+ * preceeds the sample. Run if tight_timestamps == true.
+ *
+ * Sometimes the EC receives only one interrupt (hence timestamp) for
+ * a batch of samples. Only the first sample will have the correct
+ * timestamp. So we must interpolate the other samples.
+ * We use the previous batch timestamp and our current batch timestamp
+ * as a way to calculate period, then spread the samples evenly.
+ *
+ * s0 int, 0ms
+ * s1 int, 10ms
+ * s2 int, 20ms
+ * 30ms point goes by, no interrupt, previous one is still asserted
+ * downloading s2 and s3
+ * s3 sample, 20ms (incorrect timestamp)
+ * s4 int, 40ms
+ *
+ * The batches are [(s0), (s1), (s2, s3), (s4)]. Since the 3rd batch
+ * has 2 samples in them, we adjust the timestamp of s3.
+ * s2 - s1 = 10ms, so s3 must be s2 + 10ms => 20ms. If s1 would have
+ * been part of a bigger batch things would have gotten a little
+ * more complicated.
+ *
+ * Note: we also assume another sensor sample doesn't break up a batch
+ * in 2 or more partitions. Example, there can't ever be a sync sensor
+ * in between S2 and S3. This simplifies the following code.
+ */
+static void
+cros_ec_sensor_ring_spread_add(struct cros_ec_sensorhub *sensorhub,
+                              unsigned long sensor_mask,
+                              struct cros_ec_sensors_ring_sample *last_out)
+{
+       struct cros_ec_sensors_ring_sample *batch_start, *next_batch_start;
+       int id;
+
+       for_each_set_bit(id, &sensor_mask, sensorhub->sensor_num) {
+               for (batch_start = sensorhub->ring; batch_start < last_out;
+                    batch_start = next_batch_start) {
+                       /*
+                        * For each batch (where all samples have the same
+                        * timestamp).
+                        */
+                       int batch_len, sample_idx;
+                       struct cros_ec_sensors_ring_sample *batch_end =
+                               batch_start;
+                       struct cros_ec_sensors_ring_sample *s;
+                       s64 batch_timestamp = batch_start->timestamp;
+                       s64 sample_period;
+
+                       /*
+                        * Skip over batches that start with the sensor types
+                        * we're not looking at right now.
+                        */
+                       if (batch_start->sensor_id != id) {
+                               next_batch_start = batch_start + 1;
+                               continue;
+                       }
+
+                       /*
+                        * Do not start a batch
+                        * from a flush, as it happens asynchronously to the
+                        * regular flow of events.
+                        */
+                       if (batch_start->flag & MOTIONSENSE_SENSOR_FLAG_FLUSH) {
+                               cros_sensorhub_send_sample(sensorhub,
+                                                          batch_start);
+                               next_batch_start = batch_start + 1;
+                               continue;
+                       }
+
+                       if (batch_start->timestamp <=
+                           sensorhub->batch_state[id].last_ts) {
+                               batch_timestamp =
+                                       sensorhub->batch_state[id].last_ts;
+                               batch_len = sensorhub->batch_state[id].last_len;
+
+                               sample_idx = batch_len;
+
+                               sensorhub->batch_state[id].last_ts =
+                                 sensorhub->batch_state[id].penul_ts;
+                               sensorhub->batch_state[id].last_len =
+                                 sensorhub->batch_state[id].penul_len;
+                       } else {
+                               /*
+                                * Push first sample in the batch to the,
+                                * kifo, it's guaranteed to be correct, the
+                                * rest will follow later on.
+                                */
+                               sample_idx = 1;
+                               batch_len = 1;
+                               cros_sensorhub_send_sample(sensorhub,
+                                                          batch_start);
+                               batch_start++;
+                       }
+
+                       /* Find all samples have the same timestamp. */
+                       for (s = batch_start; s < last_out; s++) {
+                               if (s->sensor_id != id)
+                                       /*
+                                        * Skip over other sensor types that
+                                        * are interleaved, don't count them.
+                                        */
+                                       continue;
+                               if (s->timestamp != batch_timestamp)
+                                       /* we discovered the next batch */
+                                       break;
+                               if (s->flag & MOTIONSENSE_SENSOR_FLAG_FLUSH)
+                                       /* break on flush packets */
+                                       break;
+                               batch_end = s;
+                               batch_len++;
+                       }
+
+                       if (batch_len == 1)
+                               goto done_with_this_batch;
+
+                       /* Can we calculate period? */
+                       if (sensorhub->batch_state[id].last_len == 0) {
+                               dev_warn(sensorhub->dev, "Sensor %d: lost %d samples when spreading\n",
+                                        id, batch_len - 1);
+                               goto done_with_this_batch;
+                               /*
+                                * Note: we're dropping the rest of the samples
+                                * in this batch since we have no idea where
+                                * they're supposed to go without a period
+                                * calculation.
+                                */
+                       }
+
+                       sample_period = div_s64(batch_timestamp -
+                               sensorhub->batch_state[id].last_ts,
+                               sensorhub->batch_state[id].last_len);
+                       dev_dbg(sensorhub->dev,
+                               "Adjusting %d samples, sensor %d last_batch @%lld (%d samples) batch_timestamp=%lld => period=%lld\n",
+                               batch_len, id,
+                               sensorhub->batch_state[id].last_ts,
+                               sensorhub->batch_state[id].last_len,
+                               batch_timestamp,
+                               sample_period);
+
+                       /*
+                        * Adjust timestamps of the samples then push them to
+                        * kfifo.
+                        */
+                       for (s = batch_start; s <= batch_end; s++) {
+                               if (s->sensor_id != id)
+                                       /*
+                                        * Skip over other sensor types that
+                                        * are interleaved, don't change them.
+                                        */
+                                       continue;
+
+                               s->timestamp = batch_timestamp +
+                                       sample_period * sample_idx;
+                               sample_idx++;
+
+                               cros_sensorhub_send_sample(sensorhub, s);
+                       }
+
+done_with_this_batch:
+                       sensorhub->batch_state[id].penul_ts =
+                               sensorhub->batch_state[id].last_ts;
+                       sensorhub->batch_state[id].penul_len =
+                               sensorhub->batch_state[id].last_len;
+
+                       sensorhub->batch_state[id].last_ts =
+                               batch_timestamp;
+                       sensorhub->batch_state[id].last_len = batch_len;
+
+                       next_batch_start = batch_end + 1;
+               }
+       }
+}
+
+/*
+ * cros_ec_sensor_ring_spread_add_legacy: Calculate proper timestamps then
+ * add to ringbuffer (legacy).
+ *
+ * Note: This assumes we're running old firmware, where every sample's timestamp
+ * is after the sample. Run if tight_timestamps == false.
+ *
+ * If there is a sample with a proper timestamp
+ *
+ *                        timestamp | count
+ *                        -----------------
+ * older_unprocess_out --> TS1      | 1
+ *                         TS1      | 2
+ *                out -->  TS1      | 3
+ *           next_out -->  TS2      |
+ *
+ * We spread time for the samples [older_unprocess_out .. out]
+ * between TS1 and TS2: [TS1+1/4, TS1+2/4, TS1+3/4, TS2].
+ *
+ * If we reach the end of the samples, we compare with the
+ * current timestamp:
+ *
+ * older_unprocess_out --> TS1      | 1
+ *                         TS1      | 2
+ *                 out --> TS1      | 3
+ *
+ * We know have [TS1+1/3, TS1+2/3, current timestamp]
+ */
+static void
+cros_ec_sensor_ring_spread_add_legacy(struct cros_ec_sensorhub *sensorhub,
+                                     unsigned long sensor_mask,
+                                     s64 current_timestamp,
+                                     struct cros_ec_sensors_ring_sample
+                                     *last_out)
+{
+       struct cros_ec_sensors_ring_sample *out;
+       int i;
+
+       for_each_set_bit(i, &sensor_mask, sensorhub->sensor_num) {
+               s64 older_timestamp;
+               s64 timestamp;
+               struct cros_ec_sensors_ring_sample *older_unprocess_out =
+                       sensorhub->ring;
+               struct cros_ec_sensors_ring_sample *next_out;
+               int count = 1;
+
+               for (out = sensorhub->ring; out < last_out; out = next_out) {
+                       s64 time_period;
+
+                       next_out = out + 1;
+                       if (out->sensor_id != i)
+                               continue;
+
+                       /* Timestamp to start with */
+                       older_timestamp = out->timestamp;
+
+                       /* Find next sample. */
+                       while (next_out < last_out && next_out->sensor_id != i)
+                               next_out++;
+
+                       if (next_out >= last_out) {
+                               timestamp = current_timestamp;
+                       } else {
+                               timestamp = next_out->timestamp;
+                               if (timestamp == older_timestamp) {
+                                       count++;
+                                       continue;
+                               }
+                       }
+
+                       /*
+                        * The next sample has a new timestamp, spread the
+                        * unprocessed samples.
+                        */
+                       if (next_out < last_out)
+                               count++;
+                       time_period = div_s64(timestamp - older_timestamp,
+                                             count);
+
+                       for (; older_unprocess_out <= out;
+                                       older_unprocess_out++) {
+                               if (older_unprocess_out->sensor_id != i)
+                                       continue;
+                               older_timestamp += time_period;
+                               older_unprocess_out->timestamp =
+                                       older_timestamp;
+                       }
+                       count = 1;
+                       /* The next_out sample has a valid timestamp, skip. */
+                       next_out++;
+                       older_unprocess_out = next_out;
+               }
+       }
+
+       /* Push the event into the kfifo */
+       for (out = sensorhub->ring; out < last_out; out++)
+               cros_sensorhub_send_sample(sensorhub, out);
+}
+
+/**
+ * cros_ec_sensorhub_ring_handler() - The trigger handler function
+ *
+ * @sensorhub: Sensor Hub object.
+ *
+ * Called by the notifier, process the EC sensor FIFO queue.
+ */
+static void cros_ec_sensorhub_ring_handler(struct cros_ec_sensorhub *sensorhub)
+{
+       struct ec_response_motion_sense_fifo_info *fifo_info =
+               sensorhub->fifo_info;
+       struct cros_ec_dev *ec = sensorhub->ec;
+       ktime_t fifo_timestamp, current_timestamp;
+       int i, j, number_data, ret;
+       unsigned long sensor_mask = 0;
+       struct ec_response_motion_sensor_data *in;
+       struct cros_ec_sensors_ring_sample *out, *last_out;
+
+       mutex_lock(&sensorhub->cmd_lock);
+
+       /* Get FIFO information if there are lost vectors. */
+       if (fifo_info->total_lost) {
+               int fifo_info_length =
+                       sizeof(struct ec_response_motion_sense_fifo_info) +
+                       sizeof(u16) * sensorhub->sensor_num;
+
+               /* Need to retrieve the number of lost vectors per sensor */
+               sensorhub->params->cmd = MOTIONSENSE_CMD_FIFO_INFO;
+               sensorhub->msg->outsize = 1;
+               sensorhub->msg->insize = fifo_info_length;
+
+               if (cros_ec_cmd_xfer_status(ec->ec_dev, sensorhub->msg) < 0)
+                       goto error;
+
+               memcpy(fifo_info, &sensorhub->resp->fifo_info,
+                      fifo_info_length);
+
+               /*
+                * Update collection time, will not be as precise as the
+                * non-error case.
+                */
+               fifo_timestamp = cros_ec_get_time_ns();
+       } else {
+               fifo_timestamp = sensorhub->fifo_timestamp[
+                       CROS_EC_SENSOR_NEW_TS];
+       }
+
+       if (fifo_info->count > sensorhub->fifo_size ||
+           fifo_info->size != sensorhub->fifo_size) {
+               dev_warn(sensorhub->dev,
+                        "Mismatch EC data: count %d, size %d - expected %d",
+                        fifo_info->count, fifo_info->size,
+                        sensorhub->fifo_size);
+               goto error;
+       }
+
+       /* Copy elements in the main fifo */
+       current_timestamp = sensorhub->fifo_timestamp[CROS_EC_SENSOR_LAST_TS];
+       out = sensorhub->ring;
+       for (i = 0; i < fifo_info->count; i += number_data) {
+               sensorhub->params->cmd = MOTIONSENSE_CMD_FIFO_READ;
+               sensorhub->params->fifo_read.max_data_vector =
+                       fifo_info->count - i;
+               sensorhub->msg->outsize =
+                       sizeof(struct ec_params_motion_sense);
+               sensorhub->msg->insize =
+                       sizeof(sensorhub->resp->fifo_read) +
+                       sensorhub->params->fifo_read.max_data_vector *
+                         sizeof(struct ec_response_motion_sensor_data);
+               ret = cros_ec_cmd_xfer_status(ec->ec_dev, sensorhub->msg);
+               if (ret < 0) {
+                       dev_warn(sensorhub->dev, "Fifo error: %d\n", ret);
+                       break;
+               }
+               number_data = sensorhub->resp->fifo_read.number_data;
+               if (number_data == 0) {
+                       dev_dbg(sensorhub->dev, "Unexpected empty FIFO\n");
+                       break;
+               }
+               if (number_data > fifo_info->count - i) {
+                       dev_warn(sensorhub->dev,
+                                "Invalid EC data: too many entry received: %d, expected %d",
+                                number_data, fifo_info->count - i);
+                       break;
+               }
+               if (out + number_data >
+                   sensorhub->ring + fifo_info->count) {
+                       dev_warn(sensorhub->dev,
+                                "Too many samples: %d (%zd data) to %d entries for expected %d entries",
+                                i, out - sensorhub->ring, i + number_data,
+                                fifo_info->count);
+                       break;
+               }
+
+               for (in = sensorhub->resp->fifo_read.data, j = 0;
+                    j < number_data; j++, in++) {
+                       if (cros_ec_sensor_ring_process_event(
+                                               sensorhub, fifo_info,
+                                               fifo_timestamp,
+                                               &current_timestamp,
+                                               in, out)) {
+                               sensor_mask |= BIT(in->sensor_num);
+                               out++;
+                       }
+               }
+       }
+       mutex_unlock(&sensorhub->cmd_lock);
+       last_out = out;
+
+       if (out == sensorhub->ring)
+               /* Unexpected empty FIFO. */
+               goto ring_handler_end;
+
+       /*
+        * Check if current_timestamp is ahead of the last sample. Normally,
+        * the EC appends a timestamp after the last sample, but if the AP
+        * is slow to respond to the IRQ, the EC may have added new samples.
+        * Use the FIFO info timestamp as last timestamp then.
+        */
+       if (!sensorhub->tight_timestamps &&
+           (last_out - 1)->timestamp == current_timestamp)
+               current_timestamp = fifo_timestamp;
+
+       /* Warn on lost samples. */
+       if (fifo_info->total_lost)
+               for (i = 0; i < sensorhub->sensor_num; i++) {
+                       if (fifo_info->lost[i]) {
+                               dev_warn_ratelimited(sensorhub->dev,
+                                                    "Sensor %d: lost: %d out of %d\n",
+                                                    i, fifo_info->lost[i],
+                                                    fifo_info->total_lost);
+                               if (sensorhub->tight_timestamps)
+                                       sensorhub->batch_state[i].last_len = 0;
+                       }
+               }
+
+       /*
+        * Spread samples in case of batching, then add them to the
+        * ringbuffer.
+        */
+       if (sensorhub->tight_timestamps)
+               cros_ec_sensor_ring_spread_add(sensorhub, sensor_mask,
+                                              last_out);
+       else
+               cros_ec_sensor_ring_spread_add_legacy(sensorhub, sensor_mask,
+                                                     current_timestamp,
+                                                     last_out);
+
+ring_handler_end:
+       sensorhub->fifo_timestamp[CROS_EC_SENSOR_LAST_TS] = current_timestamp;
+       return;
+
+error:
+       mutex_unlock(&sensorhub->cmd_lock);
+}
+
+static int cros_ec_sensorhub_event(struct notifier_block *nb,
+                                  unsigned long queued_during_suspend,
+                                  void *_notify)
+{
+       struct cros_ec_sensorhub *sensorhub;
+       struct cros_ec_device *ec_dev;
+
+       sensorhub = container_of(nb, struct cros_ec_sensorhub, notifier);
+       ec_dev = sensorhub->ec->ec_dev;
+
+       if (ec_dev->event_data.event_type != EC_MKBP_EVENT_SENSOR_FIFO)
+               return NOTIFY_DONE;
+
+       if (ec_dev->event_size != sizeof(ec_dev->event_data.data.sensor_fifo)) {
+               dev_warn(ec_dev->dev, "Invalid fifo info size\n");
+               return NOTIFY_DONE;
+       }
+
+       if (queued_during_suspend)
+               return NOTIFY_OK;
+
+       memcpy(sensorhub->fifo_info, &ec_dev->event_data.data.sensor_fifo.info,
+              sizeof(*sensorhub->fifo_info));
+       sensorhub->fifo_timestamp[CROS_EC_SENSOR_NEW_TS] =
+               ec_dev->last_event_time;
+       cros_ec_sensorhub_ring_handler(sensorhub);
+
+       return NOTIFY_OK;
+}
+
+/**
+ * cros_ec_sensorhub_ring_add() - Add the FIFO functionality if the EC
+ *                               supports it.
+ *
+ * @sensorhub : Sensor Hub object.
+ *
+ * Return: 0 on success.
+ */
+int cros_ec_sensorhub_ring_add(struct cros_ec_sensorhub *sensorhub)
+{
+       struct cros_ec_dev *ec = sensorhub->ec;
+       int ret;
+       int fifo_info_length =
+               sizeof(struct ec_response_motion_sense_fifo_info) +
+               sizeof(u16) * sensorhub->sensor_num;
+
+       /* Allocate the array for lost events. */
+       sensorhub->fifo_info = devm_kzalloc(sensorhub->dev, fifo_info_length,
+                                           GFP_KERNEL);
+       if (!sensorhub->fifo_info)
+               return -ENOMEM;
+
+       /* Retrieve FIFO information */
+       sensorhub->msg->version = 2;
+       sensorhub->params->cmd = MOTIONSENSE_CMD_FIFO_INFO;
+       sensorhub->msg->outsize = 1;
+       sensorhub->msg->insize = fifo_info_length;
+
+       ret = cros_ec_cmd_xfer_status(ec->ec_dev, sensorhub->msg);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Allocate the full fifo. We need to copy the whole FIFO to set
+        * timestamps properly.
+        */
+       sensorhub->fifo_size = sensorhub->resp->fifo_info.size;
+       sensorhub->ring = devm_kcalloc(sensorhub->dev, sensorhub->fifo_size,
+                                      sizeof(*sensorhub->ring), GFP_KERNEL);
+       if (!sensorhub->ring)
+               return -ENOMEM;
+
+       /*
+        * Allocate the callback area based on the number of sensors.
+        */
+       sensorhub->push_data = devm_kcalloc(
+                       sensorhub->dev, sensorhub->sensor_num,
+                       sizeof(*sensorhub->push_data),
+                       GFP_KERNEL);
+       if (!sensorhub->push_data)
+               return -ENOMEM;
+
+       sensorhub->fifo_timestamp[CROS_EC_SENSOR_LAST_TS] =
+               cros_ec_get_time_ns();
+
+       sensorhub->tight_timestamps = cros_ec_check_features(
+                       ec, EC_FEATURE_MOTION_SENSE_TIGHT_TIMESTAMPS);
+
+       if (sensorhub->tight_timestamps) {
+               sensorhub->batch_state = devm_kcalloc(sensorhub->dev,
+                               sensorhub->sensor_num,
+                               sizeof(*sensorhub->batch_state),
+                               GFP_KERNEL);
+               if (!sensorhub->batch_state)
+                       return -ENOMEM;
+       }
+
+       /* Register the notifier that will act as a top half interrupt. */
+       sensorhub->notifier.notifier_call = cros_ec_sensorhub_event;
+       ret = blocking_notifier_chain_register(&ec->ec_dev->event_notifier,
+                                              &sensorhub->notifier);
+       if (ret < 0)
+               return ret;
+
+       /* Start collection samples. */
+       return cros_ec_sensorhub_ring_fifo_enable(sensorhub, true);
+}
+
+void cros_ec_sensorhub_ring_remove(void *arg)
+{
+       struct cros_ec_sensorhub *sensorhub = arg;
+       struct cros_ec_device *ec_dev = sensorhub->ec->ec_dev;
+
+       /* Disable the ring, prevent EC interrupt to the AP for nothing. */
+       cros_ec_sensorhub_ring_fifo_enable(sensorhub, false);
+       blocking_notifier_chain_unregister(&ec_dev->event_notifier,
+                                          &sensorhub->notifier);
+}
index 46786d2..debea5c 100644 (file)
@@ -127,7 +127,8 @@ static int terminate_request(struct cros_ec_device *ec_dev)
         */
        spi_message_init(&msg);
        memset(&trans, 0, sizeof(trans));
-       trans.delay_usecs = ec_spi->end_of_msg_delay;
+       trans.delay.value = ec_spi->end_of_msg_delay;
+       trans.delay.unit = SPI_DELAY_UNIT_USECS;
        spi_message_add_tail(&trans, &msg);
 
        ret = spi_sync_locked(ec_spi->spi, &msg);
@@ -416,7 +417,8 @@ static int do_cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
        spi_message_init(&msg);
        if (ec_spi->start_of_msg_delay) {
                memset(&trans_delay, 0, sizeof(trans_delay));
-               trans_delay.delay_usecs = ec_spi->start_of_msg_delay;
+               trans_delay.delay.value = ec_spi->start_of_msg_delay;
+               trans_delay.delay.unit = SPI_DELAY_UNIT_USECS;
                spi_message_add_tail(&trans_delay, &msg);
        }
 
index 07dac97..d45ea5d 100644 (file)
@@ -149,14 +149,14 @@ static ssize_t version_show(struct device *dev,
        /* Get build info. */
        msg->command = EC_CMD_GET_BUILD_INFO + ec->cmd_offset;
        msg->insize = EC_HOST_PARAM_SIZE;
-       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
-       if (ret < 0)
-               count += scnprintf(buf + count, PAGE_SIZE - count,
-                                  "Build info:    XFER ERROR %d\n", ret);
-       else if (msg->result != EC_RES_SUCCESS)
+       ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
+       if (ret == -EPROTO) {
                count += scnprintf(buf + count, PAGE_SIZE - count,
                                   "Build info:    EC error %d\n", msg->result);
-       else {
+       } else if (ret < 0) {
+               count += scnprintf(buf + count, PAGE_SIZE - count,
+                                  "Build info:    XFER ERROR %d\n", ret);
+       } else {
                msg->data[EC_HOST_PARAM_SIZE - 1] = '\0';
                count += scnprintf(buf + count, PAGE_SIZE - count,
                                   "Build info:    %s\n", msg->data);
@@ -165,14 +165,14 @@ static ssize_t version_show(struct device *dev,
        /* Get chip info. */
        msg->command = EC_CMD_GET_CHIP_INFO + ec->cmd_offset;
        msg->insize = sizeof(*r_chip);
-       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
-       if (ret < 0)
-               count += scnprintf(buf + count, PAGE_SIZE - count,
-                                  "Chip info:     XFER ERROR %d\n", ret);
-       else if (msg->result != EC_RES_SUCCESS)
+       ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
+       if (ret == -EPROTO) {
                count += scnprintf(buf + count, PAGE_SIZE - count,
                                   "Chip info:     EC error %d\n", msg->result);
-       else {
+       } else if (ret < 0) {
+               count += scnprintf(buf + count, PAGE_SIZE - count,
+                                  "Chip info:     XFER ERROR %d\n", ret);
+       } else {
                r_chip = (struct ec_response_get_chip_info *)msg->data;
 
                r_chip->vendor[sizeof(r_chip->vendor) - 1] = '\0';
@@ -189,14 +189,14 @@ static ssize_t version_show(struct device *dev,
        /* Get board version */
        msg->command = EC_CMD_GET_BOARD_VERSION + ec->cmd_offset;
        msg->insize = sizeof(*r_board);
-       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
-       if (ret < 0)
-               count += scnprintf(buf + count, PAGE_SIZE - count,
-                                  "Board version: XFER ERROR %d\n", ret);
-       else if (msg->result != EC_RES_SUCCESS)
+       ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
+       if (ret == -EPROTO) {
                count += scnprintf(buf + count, PAGE_SIZE - count,
                                   "Board version: EC error %d\n", msg->result);
-       else {
+       } else if (ret < 0) {
+               count += scnprintf(buf + count, PAGE_SIZE - count,
+                                  "Board version: XFER ERROR %d\n", ret);
+       } else {
                r_board = (struct ec_response_board_version *)msg->data;
 
                count += scnprintf(buf + count, PAGE_SIZE - count,
diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
new file mode 100644 (file)
index 0000000..874269c
--- /dev/null
@@ -0,0 +1,357 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2020 Google LLC
+ *
+ * This driver provides the ability to view and manage Type C ports through the
+ * Chrome OS EC.
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_data/cros_ec_commands.h>
+#include <linux/platform_data/cros_ec_proto.h>
+#include <linux/platform_device.h>
+#include <linux/usb/typec.h>
+
+#define DRV_NAME "cros-ec-typec"
+
+/* Platform-specific data for the Chrome OS EC Type C controller. */
+struct cros_typec_data {
+       struct device *dev;
+       struct cros_ec_device *ec;
+       int num_ports;
+       unsigned int cmd_ver;
+       /* Array of ports, indexed by port number. */
+       struct typec_port *ports[EC_USB_PD_MAX_PORTS];
+       /* Initial capabilities for each port. */
+       struct typec_capability *caps[EC_USB_PD_MAX_PORTS];
+};
+
+static int cros_typec_parse_port_props(struct typec_capability *cap,
+                                      struct fwnode_handle *fwnode,
+                                      struct device *dev)
+{
+       const char *buf;
+       int ret;
+
+       memset(cap, 0, sizeof(*cap));
+       ret = fwnode_property_read_string(fwnode, "power-role", &buf);
+       if (ret) {
+               dev_err(dev, "power-role not found: %d\n", ret);
+               return ret;
+       }
+
+       ret = typec_find_port_power_role(buf);
+       if (ret < 0)
+               return ret;
+       cap->type = ret;
+
+       ret = fwnode_property_read_string(fwnode, "data-role", &buf);
+       if (ret) {
+               dev_err(dev, "data-role not found: %d\n", ret);
+               return ret;
+       }
+
+       ret = typec_find_port_data_role(buf);
+       if (ret < 0)
+               return ret;
+       cap->data = ret;
+
+       ret = fwnode_property_read_string(fwnode, "try-power-role", &buf);
+       if (ret) {
+               dev_err(dev, "try-power-role not found: %d\n", ret);
+               return ret;
+       }
+
+       ret = typec_find_power_role(buf);
+       if (ret < 0)
+               return ret;
+       cap->prefer_role = ret;
+
+       cap->fwnode = fwnode;
+
+       return 0;
+}
+
+static int cros_typec_init_ports(struct cros_typec_data *typec)
+{
+       struct device *dev = typec->dev;
+       struct typec_capability *cap;
+       struct fwnode_handle *fwnode;
+       const char *port_prop;
+       int ret;
+       int i;
+       int nports;
+       u32 port_num = 0;
+
+       nports = device_get_child_node_count(dev);
+       if (nports == 0) {
+               dev_err(dev, "No port entries found.\n");
+               return -ENODEV;
+       }
+
+       if (nports > typec->num_ports) {
+               dev_err(dev, "More ports listed than can be supported.\n");
+               return -EINVAL;
+       }
+
+       /* DT uses "reg" to specify port number. */
+       port_prop = dev->of_node ? "reg" : "port-number";
+       device_for_each_child_node(dev, fwnode) {
+               if (fwnode_property_read_u32(fwnode, port_prop, &port_num)) {
+                       ret = -EINVAL;
+                       dev_err(dev, "No port-number for port, aborting.\n");
+                       goto unregister_ports;
+               }
+
+               if (port_num >= typec->num_ports) {
+                       dev_err(dev, "Invalid port number.\n");
+                       ret = -EINVAL;
+                       goto unregister_ports;
+               }
+
+               dev_dbg(dev, "Registering port %d\n", port_num);
+
+               cap = devm_kzalloc(dev, sizeof(*cap), GFP_KERNEL);
+               if (!cap) {
+                       ret = -ENOMEM;
+                       goto unregister_ports;
+               }
+
+               typec->caps[port_num] = cap;
+
+               ret = cros_typec_parse_port_props(cap, fwnode, dev);
+               if (ret < 0)
+                       goto unregister_ports;
+
+               typec->ports[port_num] = typec_register_port(dev, cap);
+               if (IS_ERR(typec->ports[port_num])) {
+                       dev_err(dev, "Failed to register port %d\n", port_num);
+                       ret = PTR_ERR(typec->ports[port_num]);
+                       goto unregister_ports;
+               }
+       }
+
+       return 0;
+
+unregister_ports:
+       for (i = 0; i < typec->num_ports; i++)
+               typec_unregister_port(typec->ports[i]);
+       return ret;
+}
+
+static int cros_typec_ec_command(struct cros_typec_data *typec,
+                                unsigned int version,
+                                unsigned int command,
+                                void *outdata,
+                                unsigned int outsize,
+                                void *indata,
+                                unsigned int insize)
+{
+       struct cros_ec_command *msg;
+       int ret;
+
+       msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       msg->version = version;
+       msg->command = command;
+       msg->outsize = outsize;
+       msg->insize = insize;
+
+       if (outsize)
+               memcpy(msg->data, outdata, outsize);
+
+       ret = cros_ec_cmd_xfer_status(typec->ec, msg);
+       if (ret >= 0 && insize)
+               memcpy(indata, msg->data, insize);
+
+       kfree(msg);
+       return ret;
+}
+
+static void cros_typec_set_port_params_v0(struct cros_typec_data *typec,
+               int port_num, struct ec_response_usb_pd_control *resp)
+{
+       struct typec_port *port = typec->ports[port_num];
+       enum typec_orientation polarity;
+
+       if (!resp->enabled)
+               polarity = TYPEC_ORIENTATION_NONE;
+       else if (!resp->polarity)
+               polarity = TYPEC_ORIENTATION_NORMAL;
+       else
+               polarity = TYPEC_ORIENTATION_REVERSE;
+
+       typec_set_pwr_role(port, resp->role ? TYPEC_SOURCE : TYPEC_SINK);
+       typec_set_orientation(port, polarity);
+}
+
+static void cros_typec_set_port_params_v1(struct cros_typec_data *typec,
+               int port_num, struct ec_response_usb_pd_control_v1 *resp)
+{
+       struct typec_port *port = typec->ports[port_num];
+       enum typec_orientation polarity;
+
+       if (!(resp->enabled & PD_CTRL_RESP_ENABLED_CONNECTED))
+               polarity = TYPEC_ORIENTATION_NONE;
+       else if (!resp->polarity)
+               polarity = TYPEC_ORIENTATION_NORMAL;
+       else
+               polarity = TYPEC_ORIENTATION_REVERSE;
+       typec_set_orientation(port, polarity);
+       typec_set_data_role(port, resp->role & PD_CTRL_RESP_ROLE_DATA ?
+                       TYPEC_HOST : TYPEC_DEVICE);
+       typec_set_pwr_role(port, resp->role & PD_CTRL_RESP_ROLE_POWER ?
+                       TYPEC_SOURCE : TYPEC_SINK);
+       typec_set_vconn_role(port, resp->role & PD_CTRL_RESP_ROLE_VCONN ?
+                       TYPEC_SOURCE : TYPEC_SINK);
+}
+
+static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
+{
+       struct ec_params_usb_pd_control req;
+       struct ec_response_usb_pd_control_v1 resp;
+       int ret;
+
+       if (port_num < 0 || port_num >= typec->num_ports) {
+               dev_err(typec->dev, "cannot get status for invalid port %d\n",
+                       port_num);
+               return -EINVAL;
+       }
+
+       req.port = port_num;
+       req.role = USB_PD_CTRL_ROLE_NO_CHANGE;
+       req.mux = USB_PD_CTRL_MUX_NO_CHANGE;
+       req.swap = USB_PD_CTRL_SWAP_NONE;
+
+       ret = cros_typec_ec_command(typec, typec->cmd_ver,
+                                   EC_CMD_USB_PD_CONTROL, &req, sizeof(req),
+                                   &resp, sizeof(resp));
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(typec->dev, "Enabled %d: 0x%hhx\n", port_num, resp.enabled);
+       dev_dbg(typec->dev, "Role %d: 0x%hhx\n", port_num, resp.role);
+       dev_dbg(typec->dev, "Polarity %d: 0x%hhx\n", port_num, resp.polarity);
+       dev_dbg(typec->dev, "State %d: %s\n", port_num, resp.state);
+
+       if (typec->cmd_ver == 1)
+               cros_typec_set_port_params_v1(typec, port_num, &resp);
+       else
+               cros_typec_set_port_params_v0(typec, port_num,
+                       (struct ec_response_usb_pd_control *) &resp);
+
+       return 0;
+}
+
+static int cros_typec_get_cmd_version(struct cros_typec_data *typec)
+{
+       struct ec_params_get_cmd_versions_v1 req_v1;
+       struct ec_response_get_cmd_versions resp;
+       int ret;
+
+       /* We're interested in the PD control command version. */
+       req_v1.cmd = EC_CMD_USB_PD_CONTROL;
+       ret = cros_typec_ec_command(typec, 1, EC_CMD_GET_CMD_VERSIONS,
+                                   &req_v1, sizeof(req_v1), &resp,
+                                   sizeof(resp));
+       if (ret < 0)
+               return ret;
+
+       if (resp.version_mask & EC_VER_MASK(1))
+               typec->cmd_ver = 1;
+       else
+               typec->cmd_ver = 0;
+
+       dev_dbg(typec->dev, "PD Control has version mask 0x%hhx\n",
+               typec->cmd_ver);
+
+       return 0;
+}
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id cros_typec_acpi_id[] = {
+       { "GOOG0014", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(acpi, cros_typec_acpi_id);
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id cros_typec_of_match[] = {
+       { .compatible = "google,cros-ec-typec", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, cros_typec_of_match);
+#endif
+
+static int cros_typec_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct cros_typec_data *typec;
+       struct ec_response_usb_pd_ports resp;
+       int ret, i;
+
+       typec = devm_kzalloc(dev, sizeof(*typec), GFP_KERNEL);
+       if (!typec)
+               return -ENOMEM;
+
+       typec->dev = dev;
+       typec->ec = dev_get_drvdata(pdev->dev.parent);
+       platform_set_drvdata(pdev, typec);
+
+       ret = cros_typec_get_cmd_version(typec);
+       if (ret < 0) {
+               dev_err(dev, "failed to get PD command version info\n");
+               return ret;
+       }
+
+       ret = cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_PORTS, NULL, 0,
+                                   &resp, sizeof(resp));
+       if (ret < 0)
+               return ret;
+
+       typec->num_ports = resp.num_ports;
+       if (typec->num_ports > EC_USB_PD_MAX_PORTS) {
+               dev_warn(typec->dev,
+                        "Too many ports reported: %d, limiting to max: %d\n",
+                        typec->num_ports, EC_USB_PD_MAX_PORTS);
+               typec->num_ports = EC_USB_PD_MAX_PORTS;
+       }
+
+       ret = cros_typec_init_ports(typec);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < typec->num_ports; i++) {
+               ret = cros_typec_port_update(typec, i);
+               if (ret < 0)
+                       goto unregister_ports;
+       }
+
+       return 0;
+
+unregister_ports:
+       for (i = 0; i < typec->num_ports; i++)
+               if (typec->ports[i])
+                       typec_unregister_port(typec->ports[i]);
+       return ret;
+}
+
+static struct platform_driver cros_typec_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .acpi_match_table = ACPI_PTR(cros_typec_acpi_id),
+               .of_match_table = of_match_ptr(cros_typec_of_match),
+       },
+       .probe = cros_typec_probe,
+};
+
+module_platform_driver(cros_typec_driver);
+
+MODULE_AUTHOR("Prashant Malani <pmalani@chromium.org>");
+MODULE_DESCRIPTION("Chrome OS EC Type C control");
+MODULE_LICENSE("GPL");
index 8edae46..46482d1 100644 (file)
@@ -40,7 +40,7 @@ static ssize_t vboot_context_read(struct file *filp, struct kobject *kobj,
        msg->outsize = para_sz;
        msg->insize = resp_sz;
 
-       err = cros_ec_cmd_xfer(ecdev, msg);
+       err = cros_ec_cmd_xfer_status(ecdev, msg);
        if (err < 0) {
                dev_err(dev, "Error sending read request: %d\n", err);
                kfree(msg);
@@ -83,7 +83,7 @@ static ssize_t vboot_context_write(struct file *filp, struct kobject *kobj,
        msg->outsize = para_sz;
        msg->insize = 0;
 
-       err = cros_ec_cmd_xfer(ecdev, msg);
+       err = cros_ec_cmd_xfer_status(ecdev, msg);
        if (err < 0) {
                dev_err(dev, "Error sending write request: %d\n", err);
                kfree(msg);
diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c
new file mode 100644 (file)
index 0000000..7f36142
--- /dev/null
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2020 Google LLC
+ *
+ * This driver serves as the receiver of cros_ec PD host events.
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/platform_data/cros_ec_proto.h>
+#include <linux/platform_data/cros_usbpd_notify.h>
+#include <linux/platform_device.h>
+
+#define DRV_NAME "cros-usbpd-notify"
+#define DRV_NAME_PLAT_ACPI "cros-usbpd-notify-acpi"
+#define ACPI_DRV_NAME "GOOG0003"
+
+static BLOCKING_NOTIFIER_HEAD(cros_usbpd_notifier_list);
+
+struct cros_usbpd_notify_data {
+       struct device *dev;
+       struct cros_ec_device *ec;
+       struct notifier_block nb;
+};
+
+/**
+ * cros_usbpd_register_notify - Register a notifier callback for PD events.
+ * @nb: Notifier block pointer to register
+ *
+ * On ACPI platforms this corresponds to host events on the ECPD
+ * "GOOG0003" ACPI device. On non-ACPI platforms this will filter mkbp events
+ * for USB PD events.
+ *
+ * Return: 0 on success or negative error code.
+ */
+int cros_usbpd_register_notify(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&cros_usbpd_notifier_list,
+                                               nb);
+}
+EXPORT_SYMBOL_GPL(cros_usbpd_register_notify);
+
+/**
+ * cros_usbpd_unregister_notify - Unregister notifier callback for PD events.
+ * @nb: Notifier block pointer to unregister
+ *
+ * Unregister a notifier callback that was previously registered with
+ * cros_usbpd_register_notify().
+ */
+void cros_usbpd_unregister_notify(struct notifier_block *nb)
+{
+       blocking_notifier_chain_unregister(&cros_usbpd_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(cros_usbpd_unregister_notify);
+
+/**
+ * cros_ec_pd_command - Send a command to the EC.
+ *
+ * @ec_dev: EC device
+ * @command: EC command
+ * @outdata: EC command output data
+ * @outsize: Size of outdata
+ * @indata: EC command input data
+ * @insize: Size of indata
+ *
+ * Return: >= 0 on success, negative error number on failure.
+ */
+static int cros_ec_pd_command(struct cros_ec_device *ec_dev,
+                             int command,
+                             uint8_t *outdata,
+                             int outsize,
+                             uint8_t *indata,
+                             int insize)
+{
+       struct cros_ec_command *msg;
+       int ret;
+
+       msg = kzalloc(sizeof(*msg) + max(insize, outsize), GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       msg->command = command;
+       msg->outsize = outsize;
+       msg->insize = insize;
+
+       if (outsize)
+               memcpy(msg->data, outdata, outsize);
+
+       ret = cros_ec_cmd_xfer_status(ec_dev, msg);
+       if (ret < 0)
+               goto error;
+
+       if (insize)
+               memcpy(indata, msg->data, insize);
+error:
+       kfree(msg);
+       return ret;
+}
+
+static void cros_usbpd_get_event_and_notify(struct device  *dev,
+                                           struct cros_ec_device *ec_dev)
+{
+       struct ec_response_host_event_status host_event_status;
+       u32 event = 0;
+       int ret;
+
+       /*
+        * We still send a 0 event out to older devices which don't
+        * have the updated device heirarchy.
+        */
+       if (!ec_dev) {
+               dev_dbg(dev,
+                       "EC device inaccessible; sending 0 event status.\n");
+               goto send_notify;
+       }
+
+       /* Check for PD host events on EC. */
+       ret = cros_ec_pd_command(ec_dev, EC_CMD_PD_HOST_EVENT_STATUS,
+                                NULL, 0,
+                                (uint8_t *)&host_event_status,
+                                sizeof(host_event_status));
+       if (ret < 0) {
+               dev_warn(dev, "Can't get host event status (err: %d)\n", ret);
+               goto send_notify;
+       }
+
+       event = host_event_status.status;
+
+send_notify:
+       blocking_notifier_call_chain(&cros_usbpd_notifier_list, event, NULL);
+}
+
+#ifdef CONFIG_ACPI
+
+static void cros_usbpd_notify_acpi(acpi_handle device, u32 event, void *data)
+{
+       struct cros_usbpd_notify_data *pdnotify = data;
+
+       cros_usbpd_get_event_and_notify(pdnotify->dev, pdnotify->ec);
+}
+
+static int cros_usbpd_notify_probe_acpi(struct platform_device *pdev)
+{
+       struct cros_usbpd_notify_data *pdnotify;
+       struct device *dev = &pdev->dev;
+       struct acpi_device *adev;
+       struct cros_ec_device *ec_dev;
+       acpi_status status;
+
+       adev = ACPI_COMPANION(dev);
+
+       pdnotify = devm_kzalloc(dev, sizeof(*pdnotify), GFP_KERNEL);
+       if (!pdnotify)
+               return -ENOMEM;
+
+       /* Get the EC device pointer needed to talk to the EC. */
+       ec_dev = dev_get_drvdata(dev->parent);
+       if (!ec_dev) {
+               /*
+                * We continue even for older devices which don't have the
+                * correct device heirarchy, namely, GOOG0003 is a child
+                * of GOOG0004.
+                */
+               dev_warn(dev, "Couldn't get Chrome EC device pointer.\n");
+       }
+
+       pdnotify->dev = dev;
+       pdnotify->ec = ec_dev;
+
+       status = acpi_install_notify_handler(adev->handle,
+                                            ACPI_ALL_NOTIFY,
+                                            cros_usbpd_notify_acpi,
+                                            pdnotify);
+       if (ACPI_FAILURE(status)) {
+               dev_warn(dev, "Failed to register notify handler %08x\n",
+                        status);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cros_usbpd_notify_remove_acpi(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+
+       acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY,
+                                  cros_usbpd_notify_acpi);
+
+       return 0;
+}
+
+static const struct acpi_device_id cros_usbpd_notify_acpi_device_ids[] = {
+       { ACPI_DRV_NAME, 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, cros_usbpd_notify_acpi_device_ids);
+
+static struct platform_driver cros_usbpd_notify_acpi_driver = {
+       .driver = {
+               .name = DRV_NAME_PLAT_ACPI,
+               .acpi_match_table = cros_usbpd_notify_acpi_device_ids,
+       },
+       .probe = cros_usbpd_notify_probe_acpi,
+       .remove = cros_usbpd_notify_remove_acpi,
+};
+
+#endif /* CONFIG_ACPI */
+
+static int cros_usbpd_notify_plat(struct notifier_block *nb,
+                                 unsigned long queued_during_suspend,
+                                 void *data)
+{
+       struct cros_usbpd_notify_data *pdnotify = container_of(nb,
+                       struct cros_usbpd_notify_data, nb);
+       struct cros_ec_device *ec_dev = (struct cros_ec_device *)data;
+       u32 host_event = cros_ec_get_host_event(ec_dev);
+
+       if (!host_event)
+               return NOTIFY_DONE;
+
+       if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU)) {
+               cros_usbpd_get_event_and_notify(pdnotify->dev, ec_dev);
+               return NOTIFY_OK;
+       }
+       return NOTIFY_DONE;
+}
+
+static int cros_usbpd_notify_probe_plat(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct cros_ec_dev *ecdev = dev_get_drvdata(dev->parent);
+       struct cros_usbpd_notify_data *pdnotify;
+       int ret;
+
+       pdnotify = devm_kzalloc(dev, sizeof(*pdnotify), GFP_KERNEL);
+       if (!pdnotify)
+               return -ENOMEM;
+
+       pdnotify->dev = dev;
+       pdnotify->ec = ecdev->ec_dev;
+       pdnotify->nb.notifier_call = cros_usbpd_notify_plat;
+
+       dev_set_drvdata(dev, pdnotify);
+
+       ret = blocking_notifier_chain_register(&ecdev->ec_dev->event_notifier,
+                                              &pdnotify->nb);
+       if (ret < 0) {
+               dev_err(dev, "Failed to register notifier\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int cros_usbpd_notify_remove_plat(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct cros_ec_dev *ecdev = dev_get_drvdata(dev->parent);
+       struct cros_usbpd_notify_data *pdnotify =
+               (struct cros_usbpd_notify_data *)dev_get_drvdata(dev);
+
+       blocking_notifier_chain_unregister(&ecdev->ec_dev->event_notifier,
+                                          &pdnotify->nb);
+
+       return 0;
+}
+
+static struct platform_driver cros_usbpd_notify_plat_driver = {
+       .driver = {
+               .name = DRV_NAME,
+       },
+       .probe = cros_usbpd_notify_probe_plat,
+       .remove = cros_usbpd_notify_remove_plat,
+};
+
+static int __init cros_usbpd_notify_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&cros_usbpd_notify_plat_driver);
+       if (ret < 0)
+               return ret;
+
+#ifdef CONFIG_ACPI
+       platform_driver_register(&cros_usbpd_notify_acpi_driver);
+#endif
+       return 0;
+}
+
+static void __exit cros_usbpd_notify_exit(void)
+{
+#ifdef CONFIG_ACPI
+       platform_driver_unregister(&cros_usbpd_notify_acpi_driver);
+#endif
+       platform_driver_unregister(&cros_usbpd_notify_plat_driver);
+}
+
+module_init(cros_usbpd_notify_init);
+module_exit(cros_usbpd_notify_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ChromeOS power delivery notifier device");
+MODULE_AUTHOR("Jon Flatley <jflat@chromium.org>");
+MODULE_ALIAS("platform:" DRV_NAME);
index dba3d44..8145185 100644 (file)
@@ -79,7 +79,7 @@ static DEFINE_IDA(event_ida);
 struct ec_event {
        u16 size;
        u16 type;
-       u16 event[0];
+       u16 event[];
 } __packed;
 
 #define ec_event_num_words(ev) (ev->size - 1)
@@ -96,7 +96,7 @@ struct ec_event_queue {
        int capacity;
        int head;
        int tail;
-       struct ec_event *entries[0];
+       struct ec_event *entries[];
 };
 
 /* Maximum number of events to store in ec_event_queue */
index 62f2761..c2bf4c9 100644 (file)
@@ -3,8 +3,11 @@
  * Copyright 2019 Google LLC
  */
 
+#include <linux/errno.h>
+#include <linux/export.h>
 #include <linux/platform_data/wilco-ec.h>
 #include <linux/string.h>
+#include <linux/types.h>
 #include <asm/unaligned.h>
 
 /* Operation code; what the EC should do with the property */
index f0d174b..3c587b4 100644 (file)
@@ -8,8 +8,12 @@
  * See Documentation/ABI/testing/sysfs-platform-wilco-ec for more information.
  */
 
+#include <linux/device.h>
+#include <linux/kernel.h>
 #include <linux/platform_data/wilco-ec.h>
+#include <linux/string.h>
 #include <linux/sysfs.h>
+#include <linux/types.h>
 
 #define CMD_KB_CMOS                    0x7C
 #define SUB_CMD_KB_CMOS_AUTO_ON                0x03
index 74e988f..f8d3e3b 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  Copyright (c) Red Hat <mjg@redhat.com>
  *  Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com>
- *  Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com>
+ *  Copyright (c) 2014 Pali Rohár <pali@kernel.org>
  *
  *  Based on documentation in the libsmbios package:
  *  Copyright (C) 2005-2014 Dell Inc.
@@ -2295,6 +2295,6 @@ module_exit(dell_exit);
 
 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
 MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>");
-MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
+MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
 MODULE_DESCRIPTION("Dell laptop driver");
 MODULE_LICENSE("GPL");
index a6b856c..a89fad4 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
     Dell Airplane Mode Switch driver
-    Copyright (C) 2014-2015  Pali Rohár <pali.rohar@gmail.com>
+    Copyright (C) 2014-2015  Pali Rohár <pali@kernel.org>
 
 */
 
@@ -495,5 +495,5 @@ MODULE_PARM_DESC(auto_remove_rfkill, "Automatically remove rfkill devices when "
                                     "(default true)");
 MODULE_DEVICE_TABLE(acpi, rbtn_ids);
 MODULE_DESCRIPTION("Dell Airplane Mode Switch driver");
-MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
+MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
 MODULE_LICENSE("GPL");
index 0fdc816..5e030f9 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
     Dell Airplane Mode Switch driver
-    Copyright (C) 2014-2015  Pali Rohár <pali.rohar@gmail.com>
+    Copyright (C) 2014-2015  Pali Rohár <pali@kernel.org>
 
 */
 
index fe59b0e..2e2cd56 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  Copyright (c) Red Hat <mjg@redhat.com>
  *  Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com>
- *  Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com>
+ *  Copyright (c) 2014 Pali Rohár <pali@kernel.org>
  *
  *  Based on documentation in the libsmbios package:
  *  Copyright (C) 2005-2014 Dell Inc.
@@ -645,7 +645,7 @@ module_exit(dell_smbios_exit);
 
 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
 MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>");
-MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
+MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
 MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
 MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS");
 MODULE_LICENSE("GPL");
index d6854d1..97c52a8 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  Copyright (c) Red Hat <mjg@redhat.com>
  *  Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com>
- *  Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com>
+ *  Copyright (c) 2014 Pali Rohár <pali@kernel.org>
  *  Copyright (c) 2017 Dell Inc.
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index a7ff980..75fa8ea 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  Copyright (c) Red Hat <mjg@redhat.com>
  *  Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com>
- *  Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com>
+ *  Copyright (c) 2014 Pali Rohár <pali@kernel.org>
  *
  *  Based on documentation in the libsmbios package:
  *  Copyright (C) 2005-2014 Dell Inc.
index b531fe8..5d9304a 100644 (file)
@@ -3,7 +3,7 @@
  *  dell-smo8800.c - Dell Latitude ACPI SMO88XX freefall sensor driver
  *
  *  Copyright (C) 2012 Sonal Santan <sonal.santan@gmail.com>
- *  Copyright (C) 2014 Pali Rohár <pali.rohar@gmail.com>
+ *  Copyright (C) 2014 Pali Rohár <pali@kernel.org>
  *
  *  This is loosely based on lis3lv02d driver.
  */
index 6669db2..86e8dd6 100644 (file)
@@ -3,7 +3,7 @@
  * Dell WMI hotkeys
  *
  * Copyright (C) 2008 Red Hat <mjg@redhat.com>
- * Copyright (C) 2014-2015 Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (C) 2014-2015 Pali Rohár <pali@kernel.org>
  *
  * Portions based on wistron_btns.c:
  * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
@@ -29,7 +29,7 @@
 #include "dell-wmi-descriptor.h"
 
 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
-MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
+MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
 MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
 MODULE_LICENSE("GPL");
 
index 195bc04..f3424fd 100644 (file)
@@ -659,7 +659,7 @@ config CHARGER_RT9455
 
 config CHARGER_CROS_USBPD
        tristate "ChromeOS EC based USBPD charger"
-       depends on CROS_EC
+       depends on CROS_USBPD_NOTIFY
        default n
        help
          Say Y here to enable ChromeOS EC based USBPD charger
index 532f6e4..a1f00ae 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * bq2415x charger driver
  *
- * Copyright (C) 2011-2013  Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (C) 2011-2013  Pali Rohár <pali@kernel.org>
  *
  * Datasheets:
  * http://www.ti.com/product/bq24150
@@ -1788,6 +1788,6 @@ static struct i2c_driver bq2415x_driver = {
 };
 module_i2c_driver(bq2415x_driver);
 
-MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
+MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
 MODULE_DESCRIPTION("bq2415x charger driver");
 MODULE_LICENSE("GPL");
index 664e501..942c921 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it>
  * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
  * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de>
- * Copyright (C) 2011 Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (C) 2011 Pali Rohár <pali@kernel.org>
  * Copyright (C) 2017 Liam Breck <kernel@networkimprov.net>
  *
  * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
index 30c3d37..2a45e84 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <linux/platform_data/cros_ec_commands.h>
 #include <linux/platform_data/cros_ec_proto.h>
+#include <linux/platform_data/cros_usbpd_notify.h>
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
 #include <linux/slab.h>
@@ -517,32 +518,21 @@ static int cros_usbpd_charger_property_is_writeable(struct power_supply *psy,
 }
 
 static int cros_usbpd_charger_ec_event(struct notifier_block *nb,
-                                      unsigned long queued_during_suspend,
+                                      unsigned long host_event,
                                       void *_notify)
 {
-       struct cros_ec_device *ec_device;
-       struct charger_data *charger;
-       u32 host_event;
+       struct charger_data *charger = container_of(nb, struct charger_data,
+                                                   notifier);
 
-       charger = container_of(nb, struct charger_data, notifier);
-       ec_device = charger->ec_device;
-
-       host_event = cros_ec_get_host_event(ec_device);
-       if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU)) {
-               cros_usbpd_charger_power_changed(charger->ports[0]->psy);
-               return NOTIFY_OK;
-       } else {
-               return NOTIFY_DONE;
-       }
+       cros_usbpd_charger_power_changed(charger->ports[0]->psy);
+       return NOTIFY_OK;
 }
 
 static void cros_usbpd_charger_unregister_notifier(void *data)
 {
        struct charger_data *charger = data;
-       struct cros_ec_device *ec_device = charger->ec_device;
 
-       blocking_notifier_chain_unregister(&ec_device->event_notifier,
-                                          &charger->notifier);
+       cros_usbpd_unregister_notify(&charger->notifier);
 }
 
 static int cros_usbpd_charger_probe(struct platform_device *pd)
@@ -676,21 +666,17 @@ static int cros_usbpd_charger_probe(struct platform_device *pd)
                goto fail;
        }
 
-       if (ec_device->mkbp_event_supported) {
-               /* Get PD events from the EC */
-               charger->notifier.notifier_call = cros_usbpd_charger_ec_event;
-               ret = blocking_notifier_chain_register(
-                                               &ec_device->event_notifier,
-                                               &charger->notifier);
-               if (ret < 0) {
-                       dev_warn(dev, "failed to register notifier\n");
-               } else {
-                       ret = devm_add_action_or_reset(dev,
-                                       cros_usbpd_charger_unregister_notifier,
-                                       charger);
-                       if (ret < 0)
-                               goto fail;
-               }
+       /* Get PD events from the EC */
+       charger->notifier.notifier_call = cros_usbpd_charger_ec_event;
+       ret = cros_usbpd_register_notify(&charger->notifier);
+       if (ret < 0) {
+               dev_warn(dev, "failed to register notifier\n");
+       } else {
+               ret = devm_add_action_or_reset(dev,
+                               cros_usbpd_charger_unregister_notifier,
+                               charger);
+               if (ret < 0)
+                       goto fail;
        }
 
        return 0;
index 4812ac1..b6efc45 100644 (file)
@@ -3,7 +3,7 @@
  * ISP1704 USB Charger Detection driver
  *
  * Copyright (C) 2010 Nokia Corporation
- * Copyright (C) 2012 - 2013 Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (C) 2012 - 2013 Pali Rohár <pali@kernel.org>
  */
 
 #include <linux/kernel.h>
index 8548b63..6e488ec 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Nokia RX-51 battery driver
  *
- * Copyright (C) 2012  Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (C) 2012  Pali Rohár <pali@kernel.org>
  */
 
 #include <linux/module.h>
@@ -278,6 +278,6 @@ static struct platform_driver rx51_battery_driver = {
 module_platform_driver(rx51_battery_driver);
 
 MODULE_ALIAS("platform:rx51-battery");
-MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
+MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
 MODULE_DESCRIPTION("Nokia RX-51 battery driver");
 MODULE_LICENSE("GPL");
index 24709c5..e061b7d 100644 (file)
@@ -31,7 +31,7 @@ void ps3_sys_manager_register_ops(const struct ps3_sys_manager_ops *ops)
 {
        BUG_ON(!ops);
        BUG_ON(!ops->dev);
-       ps3_sys_manager_ops = ops ? *ops : ps3_sys_manager_ops;
+       ps3_sys_manager_ops = *ops;
 }
 EXPORT_SYMBOL_GPL(ps3_sys_manager_register_ops);
 
index 30190be..eebbc91 100644 (file)
@@ -33,6 +33,15 @@ config PWM_SYSFS
        bool
        default y if SYSFS
 
+config PWM_DEBUG
+       bool "PWM lowlevel drivers additional checks and debug messages"
+       depends on DEBUG_KERNEL
+       help
+         This option enables some additional checks to help lowlevel driver
+         authors to get their callbacks implemented correctly.
+         It is expected to introduce some runtime overhead and diagnostic
+         output to the kernel log, so only enable while working on a driver.
+
 config PWM_AB8500
        tristate "AB8500 PWM support"
        depends on AB8500_CORE && ARCH_U8500
@@ -44,7 +53,8 @@ config PWM_AB8500
 
 config PWM_ATMEL
        tristate "Atmel PWM support"
-       depends on ARCH_AT91 && OF
+       depends on OF
+       depends on ARCH_AT91 || COMPILE_TEST
        help
          Generic PWM framework driver for Atmel SoC.
 
@@ -100,7 +110,7 @@ config PWM_BCM_KONA
 
 config PWM_BCM2835
        tristate "BCM2835 PWM support"
-       depends on ARCH_BCM2835 || ARCH_BRCMSTB
+       depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
        help
          PWM framework driver for BCM2835 controller (Raspberry Pi)
 
@@ -109,7 +119,7 @@ config PWM_BCM2835
 
 config PWM_BERLIN
        tristate "Marvell Berlin PWM support"
-       depends on ARCH_BERLIN
+       depends on ARCH_BERLIN || COMPILE_TEST
        help
          PWM framework driver for Marvell Berlin SoCs.
 
@@ -118,7 +128,7 @@ config PWM_BERLIN
 
 config PWM_BRCMSTB
        tristate "Broadcom STB PWM support"
-       depends on ARCH_BRCMSTB || BMIPS_GENERIC
+       depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
        help
          Generic PWM framework driver for the Broadcom Set-top-Box
          SoCs (BCM7xxx).
@@ -152,7 +162,7 @@ config PWM_CROS_EC
 
 config PWM_EP93XX
        tristate "Cirrus Logic EP93xx PWM support"
-       depends on ARCH_EP93XX
+       depends on ARCH_EP93XX || COMPILE_TEST
        help
          Generic PWM framework driver for Cirrus Logic EP93xx.
 
@@ -195,7 +205,7 @@ config PWM_IMG
 
 config PWM_IMX1
        tristate "i.MX1 PWM support"
-       depends on ARCH_MXC
+       depends on ARCH_MXC || COMPILE_TEST
        help
          Generic PWM framework driver for i.MX1 and i.MX21
 
@@ -204,7 +214,7 @@ config PWM_IMX1
 
 config PWM_IMX27
        tristate "i.MX27 PWM support"
-       depends on ARCH_MXC
+       depends on ARCH_MXC || COMPILE_TEST
        help
          Generic PWM framework driver for i.MX27 and later i.MX SoCs.
 
@@ -225,6 +235,8 @@ config PWM_IMX_TPM
 config PWM_JZ4740
        tristate "Ingenic JZ47xx PWM support"
        depends on MACH_INGENIC
+       depends on COMMON_CLK
+       select MFD_SYSCON
        help
          Generic PWM framework driver for Ingenic JZ47xx based
          machines.
@@ -244,7 +256,7 @@ config PWM_LP3943
 
 config PWM_LPC18XX_SCT
        tristate "LPC18xx/43xx PWM/SCT support"
-       depends on ARCH_LPC18XX
+       depends on ARCH_LPC18XX || COMPILE_TEST
        help
          Generic PWM framework driver for NXP LPC18xx PWM/SCT which
          supports 16 channels.
@@ -256,7 +268,7 @@ config PWM_LPC18XX_SCT
 
 config PWM_LPC32XX
        tristate "LPC32XX PWM support"
-       depends on ARCH_LPC32XX
+       depends on ARCH_LPC32XX || COMPILE_TEST
        help
          Generic PWM framework driver for LPC32XX. The LPC32XX SOC has two
          PWM controllers.
@@ -289,7 +301,8 @@ config PWM_LPSS_PLATFORM
 
 config PWM_MESON
        tristate "Amlogic Meson PWM driver"
-       depends on ARCH_MESON
+       depends on ARCH_MESON || COMPILE_TEST
+       depends on COMMON_CLK
        help
          The platform driver for Amlogic Meson PWM controller.
 
@@ -318,7 +331,8 @@ config PWM_MEDIATEK
 
 config PWM_MXS
        tristate "Freescale MXS PWM support"
-       depends on ARCH_MXS && OF
+       depends on OF
+       depends on ARCH_MXS || COMPILE_TEST
        select STMP_DEVICE
        help
          Generic PWM framework driver for Freescale MXS.
@@ -357,7 +371,7 @@ config PWM_PUV3
 
 config PWM_PXA
        tristate "PXA PWM support"
-       depends on ARCH_PXA
+       depends on ARCH_PXA || COMPILE_TEST
        help
          Generic PWM framework driver for PXA.
 
@@ -388,14 +402,14 @@ config PWM_RENESAS_TPU
 
 config PWM_ROCKCHIP
        tristate "Rockchip PWM support"
-       depends on ARCH_ROCKCHIP
+       depends on ARCH_ROCKCHIP || COMPILE_TEST
        help
          Generic PWM framework driver for the PWM controller found on
          Rockchip SoCs.
 
 config PWM_SAMSUNG
        tristate "Samsung PWM support"
-       depends on PLAT_SAMSUNG || ARCH_EXYNOS
+       depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST
        help
          Generic PWM framework driver for Samsung.
 
@@ -415,7 +429,7 @@ config PWM_SIFIVE
 
 config PWM_SPEAR
        tristate "STMicroelectronics SPEAr PWM support"
-       depends on PLAT_SPEAR
+       depends on PLAT_SPEAR || COMPILE_TEST
        depends on OF
        help
          Generic PWM framework driver for the PWM controller on ST
@@ -437,7 +451,7 @@ config PWM_SPRD
 
 config PWM_STI
        tristate "STiH4xx PWM support"
-       depends on ARCH_STI
+       depends on ARCH_STI || COMPILE_TEST
        depends on OF
        help
          Generic PWM framework driver for STiH4xx SoCs.
@@ -447,7 +461,7 @@ config PWM_STI
 
 config PWM_STM32
        tristate "STMicroelectronics STM32 PWM"
-       depends on MFD_STM32_TIMERS
+       depends on MFD_STM32_TIMERS || COMPILE_TEST
        help
          Generic PWM framework driver for STM32 SoCs.
 
@@ -483,7 +497,7 @@ config PWM_SUN4I
 
 config PWM_TEGRA
        tristate "NVIDIA Tegra PWM support"
-       depends on ARCH_TEGRA
+       depends on ARCH_TEGRA || COMPILE_TEST
        help
          Generic PWM framework driver for the PWFM controller found on NVIDIA
          Tegra SoCs.
@@ -493,7 +507,7 @@ config PWM_TEGRA
 
 config PWM_TIECAP
        tristate "ECAP PWM support"
-       depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3
+       depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
        help
          PWM driver support for the ECAP APWM controller found on TI SOCs
 
@@ -502,7 +516,7 @@ config PWM_TIECAP
 
 config PWM_TIEHRPWM
        tristate "EHRPWM PWM support"
-       depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_K3
+       depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_K3 || COMPILE_TEST
        help
          PWM driver support for the EHRPWM controller found on TI SOCs
 
@@ -529,7 +543,7 @@ config PWM_TWL_LED
 
 config PWM_VT8500
        tristate "vt8500 PWM support"
-       depends on ARCH_VT8500
+       depends on ARCH_VT8500 || COMPILE_TEST
        help
          Generic PWM framework driver for vt8500.
 
@@ -538,7 +552,7 @@ config PWM_VT8500
 
 config PWM_ZX
        tristate "ZTE ZX PWM support"
-       depends on ARCH_ZX
+       depends on ARCH_ZX || COMPILE_TEST
        help
          Generic PWM framework driver for ZTE ZX family SoCs.
 
index 5a7f659..9973c44 100644 (file)
@@ -120,6 +120,9 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
        if (pwm->chip->ops->get_state) {
                pwm->chip->ops->get_state(pwm->chip, pwm, &pwm->state);
                trace_pwm_get(pwm, &pwm->state);
+
+               if (IS_ENABLED(PWM_DEBUG))
+                       pwm->last = pwm->state;
        }
 
        set_bit(PWMF_REQUESTED, &pwm->flags);
@@ -232,17 +235,28 @@ void *pwm_get_chip_data(struct pwm_device *pwm)
 }
 EXPORT_SYMBOL_GPL(pwm_get_chip_data);
 
-static bool pwm_ops_check(const struct pwm_ops *ops)
+static bool pwm_ops_check(const struct pwm_chip *chip)
 {
+
+       const struct pwm_ops *ops = chip->ops;
+
        /* driver supports legacy, non-atomic operation */
-       if (ops->config && ops->enable && ops->disable)
-               return true;
+       if (ops->config && ops->enable && ops->disable) {
+               if (IS_ENABLED(CONFIG_PWM_DEBUG))
+                       dev_warn(chip->dev,
+                                "Driver needs updating to atomic API\n");
 
-       /* driver supports atomic operation */
-       if (ops->apply)
                return true;
+       }
 
-       return false;
+       if (!ops->apply)
+               return false;
+
+       if (IS_ENABLED(CONFIG_PWM_DEBUG) && !ops->get_state)
+               dev_warn(chip->dev,
+                        "Please implement the .get_state() callback\n");
+
+       return true;
 }
 
 /**
@@ -266,7 +280,7 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
        if (!chip || !chip->dev || !chip->ops || !chip->npwm)
                return -EINVAL;
 
-       if (!pwm_ops_check(chip->ops))
+       if (!pwm_ops_check(chip))
                return -EINVAL;
 
        mutex_lock(&pwm_lock);
@@ -450,6 +464,107 @@ void pwm_free(struct pwm_device *pwm)
 }
 EXPORT_SYMBOL_GPL(pwm_free);
 
+static void pwm_apply_state_debug(struct pwm_device *pwm,
+                                 const struct pwm_state *state)
+{
+       struct pwm_state *last = &pwm->last;
+       struct pwm_chip *chip = pwm->chip;
+       struct pwm_state s1, s2;
+       int err;
+
+       if (!IS_ENABLED(CONFIG_PWM_DEBUG))
+               return;
+
+       /* No reasonable diagnosis possible without .get_state() */
+       if (!chip->ops->get_state)
+               return;
+
+       /*
+        * *state was just applied. Read out the hardware state and do some
+        * checks.
+        */
+
+       chip->ops->get_state(chip, pwm, &s1);
+       trace_pwm_get(pwm, &s1);
+
+       /*
+        * The lowlevel driver either ignored .polarity (which is a bug) or as
+        * best effort inverted .polarity and fixed .duty_cycle respectively.
+        * Undo this inversion and fixup for further tests.
+        */
+       if (s1.enabled && s1.polarity != state->polarity) {
+               s2.polarity = state->polarity;
+               s2.duty_cycle = s1.period - s1.duty_cycle;
+               s2.period = s1.period;
+               s2.enabled = s1.enabled;
+       } else {
+               s2 = s1;
+       }
+
+       if (s2.polarity != state->polarity &&
+           state->duty_cycle < state->period)
+               dev_warn(chip->dev, ".apply ignored .polarity\n");
+
+       if (state->enabled &&
+           last->polarity == state->polarity &&
+           last->period > s2.period &&
+           last->period <= state->period)
+               dev_warn(chip->dev,
+                        ".apply didn't pick the best available period (requested: %u, applied: %u, possible: %u)\n",
+                        state->period, s2.period, last->period);
+
+       if (state->enabled && state->period < s2.period)
+               dev_warn(chip->dev,
+                        ".apply is supposed to round down period (requested: %u, applied: %u)\n",
+                        state->period, s2.period);
+
+       if (state->enabled &&
+           last->polarity == state->polarity &&
+           last->period == s2.period &&
+           last->duty_cycle > s2.duty_cycle &&
+           last->duty_cycle <= state->duty_cycle)
+               dev_warn(chip->dev,
+                        ".apply didn't pick the best available duty cycle (requested: %u/%u, applied: %u/%u, possible: %u/%u)\n",
+                        state->duty_cycle, state->period,
+                        s2.duty_cycle, s2.period,
+                        last->duty_cycle, last->period);
+
+       if (state->enabled && state->duty_cycle < s2.duty_cycle)
+               dev_warn(chip->dev,
+                        ".apply is supposed to round down duty_cycle (requested: %u/%u, applied: %u/%u)\n",
+                        state->duty_cycle, state->period,
+                        s2.duty_cycle, s2.period);
+
+       if (!state->enabled && s2.enabled && s2.duty_cycle > 0)
+               dev_warn(chip->dev,
+                        "requested disabled, but yielded enabled with duty > 0");
+
+       /* reapply the state that the driver reported being configured. */
+       err = chip->ops->apply(chip, pwm, &s1);
+       if (err) {
+               *last = s1;
+               dev_err(chip->dev, "failed to reapply current setting\n");
+               return;
+       }
+
+       trace_pwm_apply(pwm, &s1);
+
+       chip->ops->get_state(chip, pwm, last);
+       trace_pwm_get(pwm, last);
+
+       /* reapplication of the current state should give an exact match */
+       if (s1.enabled != last->enabled ||
+           s1.polarity != last->polarity ||
+           (s1.enabled && s1.period != last->period) ||
+           (s1.enabled && s1.duty_cycle != last->duty_cycle)) {
+               dev_err(chip->dev,
+                       ".apply is not idempotent (ena=%d pol=%d %u/%u) -> (ena=%d pol=%d %u/%u)\n",
+                       s1.enabled, s1.polarity, s1.duty_cycle, s1.period,
+                       last->enabled, last->polarity, last->duty_cycle,
+                       last->period);
+       }
+}
+
 /**
  * pwm_apply_state() - atomically apply a new state to a PWM device
  * @pwm: PWM device
@@ -480,6 +595,12 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
                trace_pwm_apply(pwm, state);
 
                pwm->state = *state;
+
+               /*
+                * only do this after pwm->state was applied as some
+                * implementations of .get_state depend on this
+                */
+               pwm_apply_state_debug(pwm, state);
        } else {
                /*
                 * FIXME: restore the initial state in case of error.
index 91e24f0..d78f86f 100644 (file)
@@ -166,6 +166,7 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
 
        pc->chip.dev = &pdev->dev;
        pc->chip.ops = &bcm2835_pwm_ops;
+       pc->chip.base = -1;
        pc->chip.npwm = 2;
        pc->chip.of_xlate = of_pwm_xlate_with_flags;
        pc->chip.of_pwm_n_cells = 3;
index 9145f61..5f3d7f7 100644 (file)
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
-#include <linux/log2.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 #include <linux/slab.h>
index 35a7ac4..a6e40d4 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 #include <linux/slab.h>
@@ -96,9 +95,8 @@ struct pwm_imx27_chip {
 
 #define to_pwm_imx27_chip(chip)        container_of(chip, struct pwm_imx27_chip, chip)
 
-static int pwm_imx27_clk_prepare_enable(struct pwm_chip *chip)
+static int pwm_imx27_clk_prepare_enable(struct pwm_imx27_chip *imx)
 {
-       struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
        int ret;
 
        ret = clk_prepare_enable(imx->clk_ipg);
@@ -114,10 +112,8 @@ static int pwm_imx27_clk_prepare_enable(struct pwm_chip *chip)
        return 0;
 }
 
-static void pwm_imx27_clk_disable_unprepare(struct pwm_chip *chip)
+static void pwm_imx27_clk_disable_unprepare(struct pwm_imx27_chip *imx)
 {
-       struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
-
        clk_disable_unprepare(imx->clk_per);
        clk_disable_unprepare(imx->clk_ipg);
 }
@@ -130,7 +126,7 @@ static void pwm_imx27_get_state(struct pwm_chip *chip,
        u64 tmp;
        int ret;
 
-       ret = pwm_imx27_clk_prepare_enable(chip);
+       ret = pwm_imx27_clk_prepare_enable(imx);
        if (ret < 0)
                return;
 
@@ -174,8 +170,7 @@ static void pwm_imx27_get_state(struct pwm_chip *chip,
        tmp = NSEC_PER_SEC * (u64)(val);
        state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk);
 
-       if (!state->enabled)
-               pwm_imx27_clk_disable_unprepare(chip);
+       pwm_imx27_clk_disable_unprepare(imx);
 }
 
 static void pwm_imx27_sw_reset(struct pwm_chip *chip)
@@ -259,7 +254,7 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        if (cstate.enabled) {
                pwm_imx27_wait_fifo_slot(chip, pwm);
        } else {
-               ret = pwm_imx27_clk_prepare_enable(chip);
+               ret = pwm_imx27_clk_prepare_enable(imx);
                if (ret)
                        return ret;
 
@@ -289,8 +284,8 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 
        writel(cr, imx->mmio_base + MX3_PWMCR);
 
-       if (!state->enabled && cstate.enabled)
-               pwm_imx27_clk_disable_unprepare(chip);
+       if (!state->enabled)
+               pwm_imx27_clk_disable_unprepare(imx);
 
        return 0;
 }
@@ -310,6 +305,8 @@ MODULE_DEVICE_TABLE(of, pwm_imx27_dt_ids);
 static int pwm_imx27_probe(struct platform_device *pdev)
 {
        struct pwm_imx27_chip *imx;
+       int ret;
+       u32 pwmcr;
 
        imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
        if (imx == NULL)
@@ -352,6 +349,15 @@ static int pwm_imx27_probe(struct platform_device *pdev)
        if (IS_ERR(imx->mmio_base))
                return PTR_ERR(imx->mmio_base);
 
+       ret = pwm_imx27_clk_prepare_enable(imx);
+       if (ret)
+               return ret;
+
+       /* keep clks on if pwm is running */
+       pwmcr = readl(imx->mmio_base + MX3_PWMCR);
+       if (!(pwmcr & MX3_PWMCR_EN))
+               pwm_imx27_clk_disable_unprepare(imx);
+
        return pwmchip_add(&imx->chip);
 }
 
@@ -361,8 +367,6 @@ static int pwm_imx27_remove(struct platform_device *pdev)
 
        imx = platform_get_drvdata(pdev);
 
-       pwm_imx27_clk_disable_unprepare(&imx->chip);
-
        return pwmchip_remove(&imx->chip);
 }
 
index 9d78cc2..3cd5c05 100644 (file)
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/kernel.h>
+#include <linux/mfd/ingenic-tcu.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
-
-#include <asm/mach-jz4740/timer.h>
+#include <linux/regmap.h>
 
 #define NUM_PWM 8
 
 struct jz4740_pwm_chip {
        struct pwm_chip chip;
-       struct clk *clk;
+       struct regmap *map;
 };
 
 static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
@@ -32,82 +33,134 @@ static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
        return container_of(chip, struct jz4740_pwm_chip, chip);
 }
 
+static bool jz4740_pwm_can_use_chn(struct jz4740_pwm_chip *jz,
+                                  unsigned int channel)
+{
+       /* Enable all TCU channels for PWM use by default except channels 0/1 */
+       u32 pwm_channels_mask = GENMASK(NUM_PWM - 1, 2);
+
+       device_property_read_u32(jz->chip.dev->parent,
+                                "ingenic,pwm-channels-mask",
+                                &pwm_channels_mask);
+
+       return !!(pwm_channels_mask & BIT(channel));
+}
+
 static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-       /*
-        * Timers 0 and 1 are used for system tasks, so they are unavailable
-        * for use as PWMs.
-        */
-       if (pwm->hwpwm < 2)
+       struct jz4740_pwm_chip *jz = to_jz4740(chip);
+       struct clk *clk;
+       char name[16];
+       int err;
+
+       if (!jz4740_pwm_can_use_chn(jz, pwm->hwpwm))
                return -EBUSY;
 
-       jz4740_timer_start(pwm->hwpwm);
+       snprintf(name, sizeof(name), "timer%u", pwm->hwpwm);
+
+       clk = clk_get(chip->dev, name);
+       if (IS_ERR(clk)) {
+               if (PTR_ERR(clk) != -EPROBE_DEFER)
+                       dev_err(chip->dev, "Failed to get clock: %pe", clk);
+
+               return PTR_ERR(clk);
+       }
+
+       err = clk_prepare_enable(clk);
+       if (err < 0) {
+               clk_put(clk);
+               return err;
+       }
+
+       pwm_set_chip_data(pwm, clk);
 
        return 0;
 }
 
 static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-       jz4740_timer_set_ctrl(pwm->hwpwm, 0);
+       struct clk *clk = pwm_get_chip_data(pwm);
 
-       jz4740_timer_stop(pwm->hwpwm);
+       clk_disable_unprepare(clk);
+       clk_put(clk);
 }
 
 static int jz4740_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-       uint32_t ctrl = jz4740_timer_get_ctrl(pwm->pwm);
+       struct jz4740_pwm_chip *jz = to_jz4740(chip);
+
+       /* Enable PWM output */
+       regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm),
+                          TCU_TCSR_PWM_EN, TCU_TCSR_PWM_EN);
 
-       ctrl |= JZ_TIMER_CTRL_PWM_ENABLE;
-       jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
-       jz4740_timer_enable(pwm->hwpwm);
+       /* Start counter */
+       regmap_write(jz->map, TCU_REG_TESR, BIT(pwm->hwpwm));
 
        return 0;
 }
 
 static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-       uint32_t ctrl = jz4740_timer_get_ctrl(pwm->hwpwm);
+       struct jz4740_pwm_chip *jz = to_jz4740(chip);
 
        /*
         * Set duty > period. This trick allows the TCU channels in TCU2 mode to
         * properly return to their init level.
         */
-       jz4740_timer_set_duty(pwm->hwpwm, 0xffff);
-       jz4740_timer_set_period(pwm->hwpwm, 0x0);
+       regmap_write(jz->map, TCU_REG_TDHRc(pwm->hwpwm), 0xffff);
+       regmap_write(jz->map, TCU_REG_TDFRc(pwm->hwpwm), 0x0);
 
        /*
         * Disable PWM output.
         * In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the
         * counter is stopped, while in TCU1 mode the order does not matter.
         */
-       ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE;
-       jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
+       regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm),
+                          TCU_TCSR_PWM_EN, 0);
 
        /* Stop counter */
-       jz4740_timer_disable(pwm->hwpwm);
+       regmap_write(jz->map, TCU_REG_TECR, BIT(pwm->hwpwm));
 }
 
 static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
                            const struct pwm_state *state)
 {
        struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip);
-       unsigned long long tmp;
+       unsigned long long tmp = 0xffffull * NSEC_PER_SEC;
+       struct clk *clk = pwm_get_chip_data(pwm);
        unsigned long period, duty;
-       unsigned int prescaler = 0;
-       uint16_t ctrl;
+       long rate;
+       int err;
 
-       tmp = (unsigned long long)clk_get_rate(jz4740->clk) * state->period;
-       do_div(tmp, 1000000000);
-       period = tmp;
+       /*
+        * Limit the clock to a maximum rate that still gives us a period value
+        * which fits in 16 bits.
+        */
+       do_div(tmp, state->period);
 
-       while (period > 0xffff && prescaler < 6) {
-               period >>= 2;
-               ++prescaler;
+       /*
+        * /!\ IMPORTANT NOTE:
+        * -------------------
+        * This code relies on the fact that clk_round_rate() will always round
+        * down, which is not a valid assumption given by the clk API, but only
+        * happens to be true with the clk drivers used for Ingenic SoCs.
+        *
+        * Right now, there is no alternative as the clk API does not have a
+        * round-down function (and won't have one for a while), but if it ever
+        * comes to light, a round-down function should be used instead.
+        */
+       rate = clk_round_rate(clk, tmp);
+       if (rate < 0) {
+               dev_err(chip->dev, "Unable to round rate: %ld", rate);
+               return rate;
        }
 
-       if (prescaler == 6)
-               return -EINVAL;
+       /* Calculate period value */
+       tmp = (unsigned long long)rate * state->period;
+       do_div(tmp, NSEC_PER_SEC);
+       period = (unsigned long)tmp;
 
+       /* Calculate duty value */
        tmp = (unsigned long long)period * state->duty_cycle;
        do_div(tmp, state->period);
        duty = period - tmp;
@@ -117,26 +170,38 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 
        jz4740_pwm_disable(chip, pwm);
 
-       jz4740_timer_set_count(pwm->hwpwm, 0);
-       jz4740_timer_set_duty(pwm->hwpwm, duty);
-       jz4740_timer_set_period(pwm->hwpwm, period);
+       err = clk_set_rate(clk, rate);
+       if (err) {
+               dev_err(chip->dev, "Unable to set rate: %d", err);
+               return err;
+       }
+
+       /* Reset counter to 0 */
+       regmap_write(jz4740->map, TCU_REG_TCNTc(pwm->hwpwm), 0);
 
-       ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT |
-               JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN;
+       /* Set duty */
+       regmap_write(jz4740->map, TCU_REG_TDHRc(pwm->hwpwm), duty);
 
-       jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
+       /* Set period */
+       regmap_write(jz4740->map, TCU_REG_TDFRc(pwm->hwpwm), period);
 
+       /* Set abrupt shutdown */
+       regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
+                          TCU_TCSR_PWM_SD, TCU_TCSR_PWM_SD);
+
+       /* Set polarity */
        switch (state->polarity) {
        case PWM_POLARITY_NORMAL:
-               ctrl &= ~JZ_TIMER_CTRL_PWM_ACTIVE_LOW;
+               regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
+                                  TCU_TCSR_PWM_INITL_HIGH, 0);
                break;
        case PWM_POLARITY_INVERSED:
-               ctrl |= JZ_TIMER_CTRL_PWM_ACTIVE_LOW;
+               regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
+                                  TCU_TCSR_PWM_INITL_HIGH,
+                                  TCU_TCSR_PWM_INITL_HIGH);
                break;
        }
 
-       jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
-
        if (state->enabled)
                jz4740_pwm_enable(chip, pwm);
 
@@ -152,17 +217,20 @@ static const struct pwm_ops jz4740_pwm_ops = {
 
 static int jz4740_pwm_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct jz4740_pwm_chip *jz4740;
 
-       jz4740 = devm_kzalloc(&pdev->dev, sizeof(*jz4740), GFP_KERNEL);
+       jz4740 = devm_kzalloc(dev, sizeof(*jz4740), GFP_KERNEL);
        if (!jz4740)
                return -ENOMEM;
 
-       jz4740->clk = devm_clk_get(&pdev->dev, "ext");
-       if (IS_ERR(jz4740->clk))
-               return PTR_ERR(jz4740->clk);
+       jz4740->map = device_node_to_regmap(dev->parent->of_node);
+       if (IS_ERR(jz4740->map)) {
+               dev_err(dev, "regmap not found: %ld\n", PTR_ERR(jz4740->map));
+               return PTR_ERR(jz4740->map);
+       }
 
-       jz4740->chip.dev = &pdev->dev;
+       jz4740->chip.dev = dev;
        jz4740->chip.ops = &jz4740_pwm_ops;
        jz4740->chip.npwm = NUM_PWM;
        jz4740->chip.base = -1;
index 6245bbd..bd0d733 100644 (file)
@@ -136,7 +136,7 @@ static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
                        dev_err(dev, "failed to set parent %s for %s: %d\n",
                                __clk_get_name(channel->clk_parent),
                                __clk_get_name(channel->clk), err);
-                               return err;
+                       return err;
                }
        }
 
@@ -163,7 +163,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
 {
        struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
        unsigned int duty, period, pre_div, cnt, duty_cnt;
-       unsigned long fin_freq = -1;
+       unsigned long fin_freq;
 
        duty = state->duty_cycle;
        period = state->period;
index f2e57fc..7ce6169 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 #include <linux/slab.h>
index 9e4378d..0d31833 100644 (file)
  *
  * Description:
  *   This file is the core OMAP support for the generic, Linux
- *   PWM driver / controller, using the OMAP's dual-mode timers.
+ *   PWM driver / controller, using the OMAP's dual-mode timers
+ *   with a timer counter that goes up. When it overflows it gets
+ *   reloaded with the load value and the pwm output goes up.
+ *   When counter matches with match register, the output goes down.
+ *   Reference Manual: http://www.ti.com/lit/ug/spruh73q/spruh73q.pdf
+ *
+ * Limitations:
+ * - When PWM is stopped, timer counter gets stopped immediately. This
+ *   doesn't allow the current PWM period to complete and stops abruptly.
+ * - When PWM is running and changing both duty cycle and period,
+ *   we cannot prevent in software that the output might produce
+ *   a period with mixed settings. Especially when period/duty_cyle
+ *   is updated while the pwm pin is high, current pwm period/duty_cycle
+ *   can get updated as below based on the current timer counter:
+ *     - period for current cycle =  current_period + new period
+ *     - duty_cycle for current period = current period + new duty_cycle.
+ * - PWM OMAP DM timer cannot change the polarity when pwm is active. When
+ *   user requests a change in polarity when in active state:
+ *     - PWM is stopped abruptly(without completing the current cycle)
+ *     - Polarity is changed
+ *     - A fresh cycle is started.
  */
 
 #include <linux/clk.h>
@@ -20,8 +40,8 @@
 #include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <clocksource/timer-ti-dm.h>
 #include <linux/platform_data/dmtimer-omap.h>
-#include <linux/platform_data/pwm_omap_dmtimer.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/pwm.h>
 #define DM_TIMER_LOAD_MIN 0xfffffffe
 #define DM_TIMER_MAX      0xffffffff
 
+/**
+ * struct pwm_omap_dmtimer_chip - Structure representing a pwm chip
+ *                               corresponding to omap dmtimer.
+ * @chip:              PWM chip structure representing PWM controller
+ * @mutex:             Mutex to protect pwm apply state
+ * @dm_timer:          Pointer to omap dm timer.
+ * @pdata:             Pointer to omap dm timer ops.
+ * dm_timer_pdev:      Pointer to omap dm timer platform device
+ */
 struct pwm_omap_dmtimer_chip {
        struct pwm_chip chip;
+       /* Mutex to protect pwm apply state */
        struct mutex mutex;
-       pwm_omap_dmtimer *dm_timer;
+       struct omap_dm_timer *dm_timer;
        const struct omap_dm_timer_ops *pdata;
        struct platform_device *dm_timer_pdev;
 };
@@ -45,11 +75,22 @@ to_pwm_omap_dmtimer_chip(struct pwm_chip *chip)
        return container_of(chip, struct pwm_omap_dmtimer_chip, chip);
 }
 
+/**
+ * pwm_omap_dmtimer_get_clock_cycles() - Get clock cycles in a time frame
+ * @clk_rate:  pwm timer clock rate
+ * @ns:                time frame in nano seconds.
+ *
+ * Return number of clock cycles in a given period(ins ns).
+ */
 static u32 pwm_omap_dmtimer_get_clock_cycles(unsigned long clk_rate, int ns)
 {
        return DIV_ROUND_CLOSEST_ULL((u64)clk_rate * ns, NSEC_PER_SEC);
 }
 
+/**
+ * pwm_omap_dmtimer_start() - Start the pwm omap dm timer in pwm mode
+ * @omap:      Pointer to pwm omap dm timer chip
+ */
 static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap)
 {
        /*
@@ -67,28 +108,46 @@ static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap)
        omap->pdata->start(omap->dm_timer);
 }
 
-static int pwm_omap_dmtimer_enable(struct pwm_chip *chip,
-                                  struct pwm_device *pwm)
+/**
+ * pwm_omap_dmtimer_is_enabled() -  Detect if the pwm is enabled.
+ * @omap:      Pointer to pwm omap dm timer chip
+ *
+ * Return true if pwm is enabled else false.
+ */
+static bool pwm_omap_dmtimer_is_enabled(struct pwm_omap_dmtimer_chip *omap)
 {
-       struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
+       u32 status;
 
-       mutex_lock(&omap->mutex);
-       pwm_omap_dmtimer_start(omap);
-       mutex_unlock(&omap->mutex);
+       status = omap->pdata->get_pwm_status(omap->dm_timer);
 
-       return 0;
+       return !!(status & OMAP_TIMER_CTRL_ST);
 }
 
-static void pwm_omap_dmtimer_disable(struct pwm_chip *chip,
-                                    struct pwm_device *pwm)
+/**
+ * pwm_omap_dmtimer_polarity() -  Detect the polarity of pwm.
+ * @omap:      Pointer to pwm omap dm timer chip
+ *
+ * Return the polarity of pwm.
+ */
+static int pwm_omap_dmtimer_polarity(struct pwm_omap_dmtimer_chip *omap)
 {
-       struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
+       u32 status;
 
-       mutex_lock(&omap->mutex);
-       omap->pdata->stop(omap->dm_timer);
-       mutex_unlock(&omap->mutex);
+       status = omap->pdata->get_pwm_status(omap->dm_timer);
+
+       return !!(status & OMAP_TIMER_CTRL_SCPWM);
 }
 
+/**
+ * pwm_omap_dmtimer_config() - Update the configuration of pwm omap dm timer
+ * @chip:      Pointer to PWM controller
+ * @pwm:       Pointer to PWM channel
+ * @duty_ns:   New duty cycle in nano seconds
+ * @period_ns: New period in nano seconds
+ *
+ * Return 0 if successfully changed the period/duty_cycle else appropriate
+ * error.
+ */
 static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
                                   struct pwm_device *pwm,
                                   int duty_ns, int period_ns)
@@ -96,31 +155,26 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
        struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
        u32 period_cycles, duty_cycles;
        u32 load_value, match_value;
-       struct clk *fclk;
        unsigned long clk_rate;
-       bool timer_active;
+       struct clk *fclk;
 
        dev_dbg(chip->dev, "requested duty cycle: %d ns, period: %d ns\n",
                duty_ns, period_ns);
 
-       mutex_lock(&omap->mutex);
        if (duty_ns == pwm_get_duty_cycle(pwm) &&
-           period_ns == pwm_get_period(pwm)) {
-               /* No change - don't cause any transients. */
-               mutex_unlock(&omap->mutex);
+           period_ns == pwm_get_period(pwm))
                return 0;
-       }
 
        fclk = omap->pdata->get_fclk(omap->dm_timer);
        if (!fclk) {
                dev_err(chip->dev, "invalid pmtimer fclk\n");
-               goto err_einval;
+               return -EINVAL;
        }
 
        clk_rate = clk_get_rate(fclk);
        if (!clk_rate) {
                dev_err(chip->dev, "invalid pmtimer fclk rate\n");
-               goto err_einval;
+               return -EINVAL;
        }
 
        dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate);
@@ -148,7 +202,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
                dev_info(chip->dev,
                         "period %d ns too short for clock rate %lu Hz\n",
                         period_ns, clk_rate);
-               goto err_einval;
+               return -EINVAL;
        }
 
        if (duty_cycles < 1) {
@@ -174,81 +228,103 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
        load_value = (DM_TIMER_MAX - period_cycles) + 1;
        match_value = load_value + duty_cycles - 1;
 
-       /*
-        * We MUST stop the associated dual-mode timer before attempting to
-        * write its registers, but calls to omap_dm_timer_start/stop must
-        * be balanced so check if timer is active before calling timer_stop.
-        */
-       timer_active = pm_runtime_active(&omap->dm_timer_pdev->dev);
-       if (timer_active)
-               omap->pdata->stop(omap->dm_timer);
-
        omap->pdata->set_load(omap->dm_timer, load_value);
        omap->pdata->set_match(omap->dm_timer, true, match_value);
 
        dev_dbg(chip->dev, "load value: %#08x (%d), match value: %#08x (%d)\n",
                load_value, load_value, match_value, match_value);
 
-       omap->pdata->set_pwm(omap->dm_timer,
-                             pwm_get_polarity(pwm) == PWM_POLARITY_INVERSED,
-                             true,
-                             PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE,
-                             true);
-
-       /* If config was called while timer was running it must be reenabled. */
-       if (timer_active)
-               pwm_omap_dmtimer_start(omap);
+       return 0;
+}
 
-       mutex_unlock(&omap->mutex);
+/**
+ * pwm_omap_dmtimer_set_polarity() - Changes the polarity of the pwm dm timer.
+ * @chip:      Pointer to PWM controller
+ * @pwm:       Pointer to PWM channel
+ * @polarity:  New pwm polarity to be set
+ */
+static void pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip,
+                                         struct pwm_device *pwm,
+                                         enum pwm_polarity polarity)
+{
+       struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
+       bool enabled;
 
-       return 0;
+       /* Disable the PWM before changing the polarity. */
+       enabled = pwm_omap_dmtimer_is_enabled(omap);
+       if (enabled)
+               omap->pdata->stop(omap->dm_timer);
 
-err_einval:
-       mutex_unlock(&omap->mutex);
+       omap->pdata->set_pwm(omap->dm_timer,
+                            polarity == PWM_POLARITY_INVERSED,
+                            true, OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE,
+                            true);
 
-       return -EINVAL;
+       if (enabled)
+               pwm_omap_dmtimer_start(omap);
 }
 
-static int pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip,
-                                        struct pwm_device *pwm,
-                                        enum pwm_polarity polarity)
+/**
+ * pwm_omap_dmtimer_apply() - Changes the state of the pwm omap dm timer.
+ * @chip:      Pointer to PWM controller
+ * @pwm:       Pointer to PWM channel
+ * @state:     New state to apply
+ *
+ * Return 0 if successfully changed the state else appropriate error.
+ */
+static int pwm_omap_dmtimer_apply(struct pwm_chip *chip,
+                                 struct pwm_device *pwm,
+                                 const struct pwm_state *state)
 {
        struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
+       int ret = 0;
 
-       /*
-        * PWM core will not call set_polarity while PWM is enabled so it's
-        * safe to reconfigure the timer here without stopping it first.
-        */
        mutex_lock(&omap->mutex);
-       omap->pdata->set_pwm(omap->dm_timer,
-                             polarity == PWM_POLARITY_INVERSED,
-                             true,
-                             PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE,
-                             true);
+
+       if (pwm_omap_dmtimer_is_enabled(omap) && !state->enabled) {
+               omap->pdata->stop(omap->dm_timer);
+               goto unlock_mutex;
+       }
+
+       if (pwm_omap_dmtimer_polarity(omap) != state->polarity)
+               pwm_omap_dmtimer_set_polarity(chip, pwm, state->polarity);
+
+       ret = pwm_omap_dmtimer_config(chip, pwm, state->duty_cycle,
+                                     state->period);
+       if (ret)
+               goto unlock_mutex;
+
+       if (!pwm_omap_dmtimer_is_enabled(omap) && state->enabled) {
+               omap->pdata->set_pwm(omap->dm_timer,
+                                    state->polarity == PWM_POLARITY_INVERSED,
+                                    true,
+                                    OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE,
+                                    true);
+               pwm_omap_dmtimer_start(omap);
+       }
+
+unlock_mutex:
        mutex_unlock(&omap->mutex);
 
-       return 0;
+       return ret;
 }
 
 static const struct pwm_ops pwm_omap_dmtimer_ops = {
-       .enable = pwm_omap_dmtimer_enable,
-       .disable = pwm_omap_dmtimer_disable,
-       .config = pwm_omap_dmtimer_config,
-       .set_polarity = pwm_omap_dmtimer_set_polarity,
+       .apply = pwm_omap_dmtimer_apply,
        .owner = THIS_MODULE,
 };
 
 static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       struct device_node *timer;
-       struct platform_device *timer_pdev;
-       struct pwm_omap_dmtimer_chip *omap;
        struct dmtimer_platform_data *timer_pdata;
        const struct omap_dm_timer_ops *pdata;
-       pwm_omap_dmtimer *dm_timer;
-       u32 v;
+       struct platform_device *timer_pdev;
+       struct pwm_omap_dmtimer_chip *omap;
+       struct omap_dm_timer *dm_timer;
+       struct device_node *timer;
        int ret = 0;
+       u32 v;
 
        timer = of_parse_phandle(np, "ti,timers", 0);
        if (!timer)
@@ -281,6 +357,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
            !pdata->set_load ||
            !pdata->set_match ||
            !pdata->set_pwm ||
+           !pdata->get_pwm_status ||
            !pdata->set_prescaler ||
            !pdata->write_counter) {
                dev_err(&pdev->dev, "Incomplete dmtimer pdata structure\n");
index b07bdca..76cd22b 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/pm_runtime.h>
+#include <linux/bitmap.h>
 
 /*
  * Because the PCA9685 has only one prescaler per chip, changing the period of
 struct pca9685 {
        struct pwm_chip chip;
        struct regmap *regmap;
-       int duty_ns;
        int period_ns;
 #if IS_ENABLED(CONFIG_GPIOLIB)
        struct mutex lock;
        struct gpio_chip gpio;
+       DECLARE_BITMAP(pwms_inuse, PCA9685_MAXCHAN + 1);
 #endif
 };
 
@@ -83,51 +84,51 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
 }
 
 #if IS_ENABLED(CONFIG_GPIOLIB)
-static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
+static bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, int pwm_idx)
 {
-       struct pca9685 *pca = gpiochip_get_data(gpio);
-       struct pwm_device *pwm;
+       bool is_inuse;
 
        mutex_lock(&pca->lock);
-
-       pwm = &pca->chip.pwms[offset];
-
-       if (pwm->flags & (PWMF_REQUESTED | PWMF_EXPORTED)) {
-               mutex_unlock(&pca->lock);
-               return -EBUSY;
+       if (pwm_idx >= PCA9685_MAXCHAN) {
+               /*
+                * "all LEDs" channel:
+                * pretend already in use if any of the PWMs are requested
+                */
+               if (!bitmap_empty(pca->pwms_inuse, PCA9685_MAXCHAN)) {
+                       is_inuse = true;
+                       goto out;
+               }
+       } else {
+               /*
+                * regular channel:
+                * pretend already in use if the "all LEDs" channel is requested
+                */
+               if (test_bit(PCA9685_MAXCHAN, pca->pwms_inuse)) {
+                       is_inuse = true;
+                       goto out;
+               }
        }
-
-       pwm_set_chip_data(pwm, (void *)1);
-
+       is_inuse = test_and_set_bit(pwm_idx, pca->pwms_inuse);
+out:
        mutex_unlock(&pca->lock);
-       pm_runtime_get_sync(pca->chip.dev);
-       return 0;
+       return is_inuse;
 }
 
-static bool pca9685_pwm_is_gpio(struct pca9685 *pca, struct pwm_device *pwm)
+static void pca9685_pwm_clear_inuse(struct pca9685 *pca, int pwm_idx)
 {
-       bool is_gpio = false;
-
        mutex_lock(&pca->lock);
+       clear_bit(pwm_idx, pca->pwms_inuse);
+       mutex_unlock(&pca->lock);
+}
 
-       if (pwm->hwpwm >= PCA9685_MAXCHAN) {
-               unsigned int i;
-
-               /*
-                * Check if any of the GPIOs are requested and in that case
-                * prevent using the "all LEDs" channel.
-                */
-               for (i = 0; i < pca->gpio.ngpio; i++)
-                       if (gpiochip_is_requested(&pca->gpio, i)) {
-                               is_gpio = true;
-                               break;
-                       }
-       } else if (pwm_get_chip_data(pwm)) {
-               is_gpio = true;
-       }
+static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
+{
+       struct pca9685 *pca = gpiochip_get_data(gpio);
 
-       mutex_unlock(&pca->lock);
-       return is_gpio;
+       if (pca9685_pwm_test_and_set_inuse(pca, offset))
+               return -EBUSY;
+       pm_runtime_get_sync(pca->chip.dev);
+       return 0;
 }
 
 static int pca9685_pwm_gpio_get(struct gpio_chip *gpio, unsigned int offset)
@@ -162,13 +163,14 @@ static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset)
 
        pca9685_pwm_gpio_set(gpio, offset, 0);
        pm_runtime_put(pca->chip.dev);
+       pca9685_pwm_clear_inuse(pca, offset);
 }
 
 static int pca9685_pwm_gpio_get_direction(struct gpio_chip *chip,
                                          unsigned int offset)
 {
        /* Always out */
-       return 0;
+       return GPIO_LINE_DIRECTION_OUT;
 }
 
 static int pca9685_pwm_gpio_direction_input(struct gpio_chip *gpio,
@@ -213,12 +215,17 @@ static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
        return devm_gpiochip_add_data(dev, &pca->gpio, pca);
 }
 #else
-static inline bool pca9685_pwm_is_gpio(struct pca9685 *pca,
-                                      struct pwm_device *pwm)
+static inline bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca,
+                                                 int pwm_idx)
 {
        return false;
 }
 
+static inline void
+pca9685_pwm_clear_inuse(struct pca9685 *pca, int pwm_idx)
+{
+}
+
 static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca)
 {
        return 0;
@@ -272,8 +279,6 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
                }
        }
 
-       pca->duty_ns = duty_ns;
-
        if (duty_ns < 1) {
                if (pwm->hwpwm >= PCA9685_MAXCHAN)
                        reg = PCA9685_ALL_LED_OFF_H;
@@ -402,7 +407,7 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        struct pca9685 *pca = to_pca(chip);
 
-       if (pca9685_pwm_is_gpio(pca, pwm))
+       if (pca9685_pwm_test_and_set_inuse(pca, pwm->hwpwm))
                return -EBUSY;
        pm_runtime_get_sync(chip->dev);
 
@@ -411,8 +416,11 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 
 static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
+       struct pca9685 *pca = to_pca(chip);
+
        pca9685_pwm_disable(chip, pwm);
        pm_runtime_put(chip->dev);
+       pca9685_pwm_clear_inuse(pca, pwm->hwpwm);
 }
 
 static const struct pwm_ops pca9685_pwm_ops = {
@@ -449,7 +457,6 @@ static int pca9685_pwm_probe(struct i2c_client *client,
                        ret);
                return ret;
        }
-       pca->duty_ns = 0;
        pca->period_ns = PCA9685_DEFAULT_PERIOD;
 
        i2c_set_clientdata(client, pca);
@@ -512,8 +519,7 @@ static int pca9685_pwm_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int pca9685_pwm_runtime_suspend(struct device *dev)
+static int __maybe_unused pca9685_pwm_runtime_suspend(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct pca9685 *pca = i2c_get_clientdata(client);
@@ -522,7 +528,7 @@ static int pca9685_pwm_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int pca9685_pwm_runtime_resume(struct device *dev)
+static int __maybe_unused pca9685_pwm_runtime_resume(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct pca9685 *pca = i2c_get_clientdata(client);
@@ -530,7 +536,6 @@ static int pca9685_pwm_runtime_resume(struct device *dev)
        pca9685_set_sleep_mode(pca, false);
        return 0;
 }
-#endif
 
 static const struct i2c_device_id pca9685_id[] = {
        { "pca9685", 0 },
index 2685577..7ab9eb6 100644 (file)
@@ -229,24 +229,28 @@ static int rcar_pwm_probe(struct platform_device *pdev)
        rcar_pwm->chip.base = -1;
        rcar_pwm->chip.npwm = 1;
 
+       pm_runtime_enable(&pdev->dev);
+
        ret = pwmchip_add(&rcar_pwm->chip);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to register PWM chip: %d\n", ret);
+               pm_runtime_disable(&pdev->dev);
                return ret;
        }
 
-       pm_runtime_enable(&pdev->dev);
-
        return 0;
 }
 
 static int rcar_pwm_remove(struct platform_device *pdev)
 {
        struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = pwmchip_remove(&rcar_pwm->chip);
 
        pm_runtime_disable(&pdev->dev);
 
-       return pwmchip_remove(&rcar_pwm->chip);
+       return ret;
 }
 
 static const struct of_device_id rcar_pwm_of_table[] = {
index 4a855a2..81ad5a5 100644 (file)
@@ -415,16 +415,15 @@ static int tpu_probe(struct platform_device *pdev)
        tpu->chip.base = -1;
        tpu->chip.npwm = TPU_CHANNEL_MAX;
 
+       pm_runtime_enable(&pdev->dev);
+
        ret = pwmchip_add(&tpu->chip);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to register PWM chip\n");
+               pm_runtime_disable(&pdev->dev);
                return ret;
        }
 
-       dev_info(&pdev->dev, "TPU PWM %d registered\n", tpu->pdev->id);
-
-       pm_runtime_enable(&pdev->dev);
-
        return 0;
 }
 
@@ -434,12 +433,10 @@ static int tpu_remove(struct platform_device *pdev)
        int ret;
 
        ret = pwmchip_remove(&tpu->chip);
-       if (ret)
-               return ret;
 
        pm_runtime_disable(&pdev->dev);
 
-       return 0;
+       return ret;
 }
 
 #ifdef CONFIG_OF
index 3e3efa6..5c677c5 100644 (file)
@@ -90,7 +90,6 @@ struct sun4i_pwm_chip {
        spinlock_t ctrl_lock;
        const struct sun4i_pwm_data *data;
        unsigned long next_period[2];
-       bool needs_delay[2];
 };
 
 static inline struct sun4i_pwm_chip *to_sun4i_pwm_chip(struct pwm_chip *chip)
@@ -287,7 +286,6 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm));
        sun4i_pwm->next_period[pwm->hwpwm] = jiffies +
                usecs_to_jiffies(cstate.period / 1000 + 1);
-       sun4i_pwm->needs_delay[pwm->hwpwm] = true;
 
        if (state->polarity != PWM_POLARITY_NORMAL)
                ctrl &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
@@ -298,7 +296,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 
        if (state->enabled) {
                ctrl |= BIT_CH(PWM_EN, pwm->hwpwm);
-       } else if (!sun4i_pwm->needs_delay[pwm->hwpwm]) {
+       } else {
                ctrl &= ~BIT_CH(PWM_EN, pwm->hwpwm);
                ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
        }
@@ -310,15 +308,9 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        if (state->enabled)
                return 0;
 
-       if (!sun4i_pwm->needs_delay[pwm->hwpwm]) {
-               clk_disable_unprepare(sun4i_pwm->clk);
-               return 0;
-       }
-
        /* We need a full period to elapse before disabling the channel. */
        now = jiffies;
-       if (sun4i_pwm->needs_delay[pwm->hwpwm] &&
-           time_before(now, sun4i_pwm->next_period[pwm->hwpwm])) {
+       if (time_before(now, sun4i_pwm->next_period[pwm->hwpwm])) {
                delay_us = jiffies_to_usecs(sun4i_pwm->next_period[pwm->hwpwm] -
                                           now);
                if ((delay_us / 500) > MAX_UDELAY_MS)
@@ -326,7 +318,6 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
                else
                        usleep_range(delay_us, delay_us * 2);
        }
-       sun4i_pwm->needs_delay[pwm->hwpwm] = false;
 
        spin_lock(&sun4i_pwm->ctrl_lock);
        ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
index aa12fb3..d26ed8f 100644 (file)
@@ -282,9 +282,15 @@ static const struct tegra_pwm_soc tegra186_pwm_soc = {
        .max_frequency = 102000000UL,
 };
 
+static const struct tegra_pwm_soc tegra194_pwm_soc = {
+       .num_channels = 1,
+       .max_frequency = 408000000UL,
+};
+
 static const struct of_device_id tegra_pwm_of_match[] = {
        { .compatible = "nvidia,tegra20-pwm", .data = &tegra20_pwm_soc },
        { .compatible = "nvidia,tegra186-pwm", .data = &tegra186_pwm_soc },
+       { .compatible = "nvidia,tegra194-pwm", .data = &tegra194_pwm_soc },
        { }
 };
 MODULE_DEVICE_TABLE(of, tegra_pwm_of_match);
index f942a33..ec873f0 100644 (file)
@@ -590,6 +590,16 @@ config RTC_DRV_RC5T583
          This driver can also be built as a module. If so, the module
          will be called rtc-rc5t583.
 
+config RTC_DRV_RC5T619
+       tristate "RICOH RC5T619 RTC driver"
+       depends on MFD_RN5T618
+       help
+         If you say yes here you get support for the RTC on the
+         RICOH RC5T619 chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-rc5t619.
+
 config RTC_DRV_S35390A
        tristate "Seiko Instruments S-35390A"
        select BITREVERSE
index 3b66ee9..0721752 100644 (file)
@@ -133,6 +133,7 @@ obj-$(CONFIG_RTC_DRV_PXA)   += rtc-pxa.o
 obj-$(CONFIG_RTC_DRV_R7301)    += rtc-r7301.o
 obj-$(CONFIG_RTC_DRV_R9701)    += rtc-r9701.o
 obj-$(CONFIG_RTC_DRV_RC5T583)  += rtc-rc5t583.o
+obj-$(CONFIG_RTC_DRV_RC5T619)  += rtc-rc5t619.o
 obj-$(CONFIG_RTC_DRV_RK808)    += rtc-rk808.o
 obj-$(CONFIG_RTC_DRV_RP5C01)   += rtc-rp5c01.o
 obj-$(CONFIG_RTC_DRV_RS5C313)  += rtc-rs5c313.o
diff --git a/drivers/rtc/rtc-rc5t619.c b/drivers/rtc/rtc-rc5t619.c
new file mode 100644 (file)
index 0000000..24e386e
--- /dev/null
@@ -0,0 +1,444 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * drivers/rtc/rtc-rc5t619.c
+ *
+ * Real time clock driver for RICOH RC5T619 power management chip.
+ *
+ * Copyright (C) 2019 Andreas Kemnade
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mfd/rn5t618.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <linux/irqdomain.h>
+
+struct rc5t619_rtc {
+       int                     irq;
+       struct rtc_device       *rtc;
+       struct rn5t618 *rn5t618;
+};
+
+#define CTRL1_ALARM_ENABLED 0x40
+#define CTRL1_24HR 0x20
+#define CTRL1_PERIODIC_MASK 0xf
+
+#define CTRL2_PON 0x10
+#define CTRL2_ALARM_STATUS 0x80
+#define CTRL2_CTFG 0x4
+#define CTRL2_CTC 0x1
+
+#define MONTH_CENTFLAG 0x80
+#define HOUR_PMFLAG 0x20
+#define MDAY_DAL_EXT 0x80
+
+static uint8_t rtc5t619_12hour_bcd2bin(uint8_t hour)
+{
+       if (hour & HOUR_PMFLAG) {
+               hour = bcd2bin(hour & ~HOUR_PMFLAG);
+               return hour == 12 ? 12 : 12 + hour;
+       }
+
+       hour = bcd2bin(hour);
+       return hour == 12 ? 0 : hour;
+}
+
+static uint8_t rtc5t619_12hour_bin2bcd(uint8_t hour)
+{
+       if (!hour)
+               return 0x12;
+
+       if (hour < 12)
+               return bin2bcd(hour);
+
+       if (hour == 12)
+               return 0x12 | HOUR_PMFLAG;
+
+       return bin2bcd(hour - 12) | HOUR_PMFLAG;
+}
+
+static int rc5t619_rtc_periodic_disable(struct device *dev)
+{
+       struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
+       int err;
+
+       /* disable function */
+       err = regmap_update_bits(rtc->rn5t618->regmap,
+                                RN5T618_RTC_CTRL1, CTRL1_PERIODIC_MASK, 0);
+       if (err < 0)
+               return err;
+
+       /* clear alarm flag and CTFG */
+       err = regmap_update_bits(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2,
+                                CTRL2_ALARM_STATUS | CTRL2_CTFG | CTRL2_CTC,
+                                0);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+/* things to be done once after power on */
+static int rc5t619_rtc_pon_setup(struct device *dev)
+{
+       struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
+       int err;
+       unsigned int reg_data;
+
+       err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, &reg_data);
+       if (err < 0)
+               return err;
+
+       /* clear VDET PON */
+       reg_data &= ~(CTRL2_PON | CTRL2_CTC | 0x4a);    /* 0101-1011 */
+       reg_data |= 0x20;       /* 0010-0000 */
+       err = regmap_write(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, reg_data);
+       if (err < 0)
+               return err;
+
+       /* clearing RTC Adjust register */
+       err = regmap_write(rtc->rn5t618->regmap, RN5T618_RTC_ADJUST, 0);
+       if (err)
+               return err;
+
+       return regmap_update_bits(rtc->rn5t618->regmap,
+                                       RN5T618_RTC_CTRL1,
+                                       CTRL1_24HR, CTRL1_24HR);
+}
+
+static int rc5t619_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
+       u8 buff[7];
+       int err;
+       int cent_flag;
+       unsigned int ctrl1;
+       unsigned int ctrl2;
+
+       err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, &ctrl2);
+       if (err < 0)
+               return err;
+
+       if (ctrl2 & CTRL2_PON)
+               return -EINVAL;
+
+       err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL1, &ctrl1);
+       if (err < 0)
+               return err;
+
+       err = regmap_bulk_read(rtc->rn5t618->regmap, RN5T618_RTC_SECONDS,
+                              buff, sizeof(buff));
+       if (err < 0)
+               return err;
+
+       if (buff[5] & MONTH_CENTFLAG)
+               cent_flag = 1;
+       else
+               cent_flag = 0;
+
+       tm->tm_sec  = bcd2bin(buff[0]);
+       tm->tm_min  = bcd2bin(buff[1]);
+
+       if (ctrl1 & CTRL1_24HR)
+               tm->tm_hour = bcd2bin(buff[2]);
+       else
+               tm->tm_hour = rtc5t619_12hour_bcd2bin(buff[2]);
+
+       tm->tm_wday = bcd2bin(buff[3]);
+       tm->tm_mday = bcd2bin(buff[4]);
+       tm->tm_mon  = bcd2bin(buff[5] & 0x1f) - 1; /* back to system 0-11 */
+       tm->tm_year = bcd2bin(buff[6]) + 100 * cent_flag;
+
+       return 0;
+}
+
+static int rc5t619_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
+       u8 buff[7];
+       int err;
+       int cent_flag;
+       unsigned int ctrl1;
+       unsigned int ctrl2;
+
+       err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, &ctrl2);
+       if (err < 0)
+               return err;
+
+       if (ctrl2 & CTRL2_PON)
+               rc5t619_rtc_pon_setup(dev);
+
+       err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL1, &ctrl1);
+       if (err < 0)
+               return err;
+
+       if (tm->tm_year >= 100)
+               cent_flag = 1;
+       else
+               cent_flag = 0;
+
+       buff[0] = bin2bcd(tm->tm_sec);
+       buff[1] = bin2bcd(tm->tm_min);
+
+       if (ctrl1 & CTRL1_24HR)
+               buff[2] = bin2bcd(tm->tm_hour);
+       else
+               buff[2] = rtc5t619_12hour_bin2bcd(tm->tm_hour);
+
+       buff[3] = bin2bcd(tm->tm_wday);
+       buff[4] = bin2bcd(tm->tm_mday);
+       buff[5] = bin2bcd(tm->tm_mon + 1);      /* system set 0-11 */
+       buff[6] = bin2bcd(tm->tm_year - cent_flag * 100);
+
+       if (cent_flag)
+               buff[5] |= MONTH_CENTFLAG;
+
+       err = regmap_bulk_write(rtc->rn5t618->regmap, RN5T618_RTC_SECONDS,
+                               buff, sizeof(buff));
+       if (err < 0) {
+               dev_err(dev, "failed to program new time: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+/* 0-disable, 1-enable */
+static int rc5t619_rtc_alarm_enable(struct device *dev, unsigned int enabled)
+{
+       struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
+
+       return regmap_update_bits(rtc->rn5t618->regmap,
+                       RN5T618_RTC_CTRL1,
+                       CTRL1_ALARM_ENABLED,
+                       enabled ? CTRL1_ALARM_ENABLED : 0);
+}
+
+static int rc5t619_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
+       u8 buff[6];
+       unsigned int buff_cent;
+       int err;
+       int cent_flag;
+       unsigned int ctrl1;
+
+       err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL1, &ctrl1);
+       if (err)
+               return err;
+
+       err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_MONTH, &buff_cent);
+       if (err < 0) {
+               dev_err(dev, "failed to read time: %d\n", err);
+               return err;
+       }
+
+       if (buff_cent & MONTH_CENTFLAG)
+               cent_flag = 1;
+       else
+               cent_flag = 0;
+
+       err = regmap_bulk_read(rtc->rn5t618->regmap, RN5T618_RTC_ALARM_Y_SEC,
+                              buff, sizeof(buff));
+       if (err)
+               return err;
+
+       buff[3] = buff[3] & 0x3f;
+
+       alrm->time.tm_sec  = bcd2bin(buff[0]);
+       alrm->time.tm_min  = bcd2bin(buff[1]);
+
+       if (ctrl1 & CTRL1_24HR)
+               alrm->time.tm_hour = bcd2bin(buff[2]);
+       else
+               alrm->time.tm_hour = rtc5t619_12hour_bcd2bin(buff[2]);
+
+       alrm->time.tm_mday = bcd2bin(buff[3]);
+       alrm->time.tm_mon  = bcd2bin(buff[4]) - 1;
+       alrm->time.tm_year = bcd2bin(buff[5]) + 100 * cent_flag;
+       alrm->enabled = !!(ctrl1 & CTRL1_ALARM_ENABLED);
+       dev_dbg(dev, "read alarm: %ptR\n", &alrm->time);
+
+       return 0;
+}
+
+static int rc5t619_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
+       u8 buff[6];
+       int err;
+       int cent_flag;
+       unsigned int ctrl1;
+
+       err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL1, &ctrl1);
+       if (err)
+               return err;
+
+       err = rc5t619_rtc_alarm_enable(dev, 0);
+       if (err < 0)
+               return err;
+
+       if (rtc->irq == -1)
+               return -EINVAL;
+
+       if (alrm->enabled == 0)
+               return 0;
+
+       if (alrm->time.tm_year >= 100)
+               cent_flag = 1;
+       else
+               cent_flag = 0;
+
+       alrm->time.tm_mon += 1;
+       buff[0] = bin2bcd(alrm->time.tm_sec);
+       buff[1] = bin2bcd(alrm->time.tm_min);
+
+       if (ctrl1 & CTRL1_24HR)
+               buff[2] = bin2bcd(alrm->time.tm_hour);
+       else
+               buff[2] = rtc5t619_12hour_bin2bcd(alrm->time.tm_hour);
+
+       buff[3] = bin2bcd(alrm->time.tm_mday);
+       buff[4] = bin2bcd(alrm->time.tm_mon);
+       buff[5] = bin2bcd(alrm->time.tm_year - 100 * cent_flag);
+       buff[3] |= MDAY_DAL_EXT;
+
+       err = regmap_bulk_write(rtc->rn5t618->regmap, RN5T618_RTC_ALARM_Y_SEC,
+                               buff, sizeof(buff));
+       if (err < 0)
+               return err;
+
+       return rc5t619_rtc_alarm_enable(dev, alrm->enabled);
+}
+
+static const struct rtc_class_ops rc5t619_rtc_ops = {
+       .read_time      = rc5t619_rtc_read_time,
+       .set_time       = rc5t619_rtc_set_time,
+       .set_alarm      = rc5t619_rtc_set_alarm,
+       .read_alarm     = rc5t619_rtc_read_alarm,
+       .alarm_irq_enable = rc5t619_rtc_alarm_enable,
+};
+
+static int rc5t619_rtc_alarm_flag_clr(struct device *dev)
+{
+       struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
+
+       /* clear alarm-D status bits.*/
+       return regmap_update_bits(rtc->rn5t618->regmap,
+                               RN5T618_RTC_CTRL2,
+                               CTRL2_ALARM_STATUS | CTRL2_CTC, 0);
+}
+
+static irqreturn_t rc5t619_rtc_irq(int irq, void *data)
+{
+       struct device *dev = data;
+       struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
+
+       rc5t619_rtc_alarm_flag_clr(dev);
+
+       rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
+       return IRQ_HANDLED;
+}
+
+static int rc5t619_rtc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent);
+       struct rc5t619_rtc *rtc;
+       unsigned int ctrl2;
+       int err;
+
+       rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
+       if (IS_ERR(rtc)) {
+               err = PTR_ERR(rtc);
+               return -ENOMEM;
+       }
+
+       rtc->rn5t618 = rn5t618;
+
+       dev_set_drvdata(dev, rtc);
+       rtc->irq = -1;
+
+       if (rn5t618->irq_data)
+               rtc->irq = regmap_irq_get_virq(rn5t618->irq_data,
+                                              RN5T618_IRQ_RTC);
+
+       if (rtc->irq  < 0)
+               rtc->irq = -1;
+
+       err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, &ctrl2);
+       if (err < 0)
+               return err;
+
+       /* disable rtc periodic function */
+       err = rc5t619_rtc_periodic_disable(&pdev->dev);
+       if (err)
+               return err;
+
+       if (ctrl2 & CTRL2_PON) {
+               err = rc5t619_rtc_alarm_flag_clr(&pdev->dev);
+               if (err)
+                       return err;
+       }
+
+       rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
+       if (IS_ERR(rtc->rtc)) {
+               err = PTR_ERR(rtc->rtc);
+               dev_err(dev, "RTC device register: err %d\n", err);
+               return err;
+       }
+
+       rtc->rtc->ops = &rc5t619_rtc_ops;
+       rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_1900;
+       rtc->rtc->range_max = RTC_TIMESTAMP_END_2099;
+
+       /* set interrupt and enable it */
+       if (rtc->irq != -1) {
+               err = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
+                                               rc5t619_rtc_irq,
+                                               IRQF_ONESHOT,
+                                               "rtc-rc5t619",
+                                               &pdev->dev);
+               if (err < 0) {
+                       dev_err(&pdev->dev, "request IRQ:%d fail\n", rtc->irq);
+                       rtc->irq = -1;
+
+                       err = rc5t619_rtc_alarm_enable(&pdev->dev, 0);
+                       if (err)
+                               return err;
+
+               } else {
+                       /* enable wake */
+                       device_init_wakeup(&pdev->dev, 1);
+                       enable_irq_wake(rtc->irq);
+               }
+       } else {
+               /* system don't want to using alarm interrupt, so close it */
+               err = rc5t619_rtc_alarm_enable(&pdev->dev, 0);
+               if (err)
+                       return err;
+
+               dev_warn(&pdev->dev, "rc5t619 interrupt is disabled\n");
+       }
+
+       return rtc_register_device(rtc->rtc);
+}
+
+static struct platform_driver rc5t619_rtc_driver = {
+       .driver = {
+               .name   = "rc5t619-rtc",
+       },
+       .probe  = rc5t619_rtc_probe,
+};
+
+module_platform_driver(rc5t619_rtc_driver);
+MODULE_ALIAS("platform:rc5t619-rtc");
+MODULE_DESCRIPTION("RICOH RC5T619 RTC driver");
+MODULE_LICENSE("GPL");
index 80d2229..384edff 100644 (file)
@@ -57,11 +57,26 @@ static size_t dcssblk_dax_copy_to_iter(struct dax_device *dax_dev,
        return copy_to_iter(addr, bytes, i);
 }
 
+static int dcssblk_dax_zero_page_range(struct dax_device *dax_dev,
+                                      pgoff_t pgoff, size_t nr_pages)
+{
+       long rc;
+       void *kaddr;
+
+       rc = dax_direct_access(dax_dev, pgoff, nr_pages, &kaddr, NULL);
+       if (rc < 0)
+               return rc;
+       memset(kaddr, 0, nr_pages << PAGE_SHIFT);
+       dax_flush(dax_dev, kaddr, nr_pages << PAGE_SHIFT);
+       return 0;
+}
+
 static const struct dax_operations dcssblk_dax_ops = {
        .direct_access = dcssblk_dax_direct_access,
        .dax_supported = generic_fsdax_supported,
        .copy_from_iter = dcssblk_dax_copy_from_iter,
        .copy_to_iter = dcssblk_dax_copy_to_iter,
+       .zero_page_range = dcssblk_dax_zero_page_range,
 };
 
 struct dcssblk_dev_info {
@@ -680,8 +695,9 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
 
        dev_info->dax_dev = alloc_dax(dev_info, dev_info->gd->disk_name,
                        &dcssblk_dax_ops, DAXDEV_F_SYNC);
-       if (!dev_info->dax_dev) {
-               rc = -ENOMEM;
+       if (IS_ERR(dev_info->dax_dev)) {
+               rc = PTR_ERR(dev_info->dax_dev);
+               dev_info->dax_dev = NULL;
                goto put_dev;
        }
 
index 50007cb..b29fe8d 100644 (file)
@@ -849,8 +849,10 @@ static void io_subchannel_register(struct ccw_device *cdev)
         * Now we know this subchannel will stay, we can throw
         * our delayed uevent.
         */
-       dev_set_uevent_suppress(&sch->dev, 0);
-       kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+       if (dev_get_uevent_suppress(&sch->dev)) {
+               dev_set_uevent_suppress(&sch->dev, 0);
+               kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+       }
        /* make it known to the system */
        ret = ccw_device_add(cdev);
        if (ret) {
@@ -1058,8 +1060,11 @@ static int io_subchannel_probe(struct subchannel *sch)
                 * Throw the delayed uevent for the subchannel, register
                 * the ccw_device and exit.
                 */
-               dev_set_uevent_suppress(&sch->dev, 0);
-               kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+               if (dev_get_uevent_suppress(&sch->dev)) {
+                       /* should always be the case for the console */
+                       dev_set_uevent_suppress(&sch->dev, 0);
+                       kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+               }
                cdev = sch_get_cdev(sch);
                rc = ccw_device_add(cdev);
                if (rc) {
index b0beafc..b8453b5 100644 (file)
@@ -374,7 +374,6 @@ int tiqdio_allocate_memory(void);
 void tiqdio_free_memory(void);
 int tiqdio_register_thinints(void);
 void tiqdio_unregister_thinints(void);
-void clear_nonshared_ind(struct qdio_irq *);
 int test_nonshared_ind(struct qdio_irq *);
 
 /* prototypes for setup */
index 5a3d9ee..286b044 100644 (file)
@@ -58,25 +58,11 @@ static void qdio_clear_dbf_list(void)
        mutex_unlock(&qdio_dbf_list_mutex);
 }
 
-int qdio_allocate_dbf(struct qdio_initialize *init_data,
-                      struct qdio_irq *irq_ptr)
+int qdio_allocate_dbf(struct qdio_irq *irq_ptr)
 {
        char text[QDIO_DBF_NAME_LEN];
        struct qdio_dbf_entry *new_entry;
 
-       DBF_EVENT("qfmt:%1d", init_data->q_format);
-       DBF_HEX(init_data->adapter_name, 8);
-       DBF_EVENT("qpff%4x", init_data->qib_param_field_format);
-       DBF_HEX(&init_data->qib_param_field, sizeof(void *));
-       DBF_HEX(&init_data->input_slib_elements, sizeof(void *));
-       DBF_HEX(&init_data->output_slib_elements, sizeof(void *));
-       DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs,
-                 init_data->no_output_qs);
-       DBF_HEX(&init_data->input_handler, sizeof(void *));
-       DBF_HEX(&init_data->output_handler, sizeof(void *));
-       DBF_HEX(&init_data->int_parm, sizeof(long));
-       DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
-       DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
        DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
 
        /* allocate trace view for the interface */
index 122450b..0dfba08 100644 (file)
@@ -64,8 +64,7 @@ static inline void DBF_DEV_HEX(struct qdio_irq *dev, void *addr,
        debug_event(dev->debug_area, level, addr, len);
 }
 
-int qdio_allocate_dbf(struct qdio_initialize *init_data,
-                      struct qdio_irq *irq_ptr);
+int qdio_allocate_dbf(struct qdio_irq *irq_ptr);
 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr);
 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr);
 int qdio_debug_init(void);
index c890848..bcc3ab1 100644 (file)
@@ -1220,27 +1220,21 @@ EXPORT_SYMBOL_GPL(qdio_free);
 
 /**
  * qdio_allocate - allocate qdio queues and associated data
- * @init_data: initialization data
+ * @cdev: associated ccw device
+ * @no_input_qs: allocate this number of Input Queues
+ * @no_output_qs: allocate this number of Output Queues
  */
-int qdio_allocate(struct qdio_initialize *init_data)
+int qdio_allocate(struct ccw_device *cdev, unsigned int no_input_qs,
+                 unsigned int no_output_qs)
 {
-       struct ccw_device *cdev = init_data->cdev;
        struct subchannel_id schid;
        struct qdio_irq *irq_ptr;
 
        ccw_device_get_schid(cdev, &schid);
        DBF_EVENT("qallocate:%4x", schid.sch_no);
 
-       if ((init_data->no_input_qs && !init_data->input_handler) ||
-           (init_data->no_output_qs && !init_data->output_handler))
-               return -EINVAL;
-
-       if ((init_data->no_input_qs > QDIO_MAX_QUEUES_PER_IRQ) ||
-           (init_data->no_output_qs > QDIO_MAX_QUEUES_PER_IRQ))
-               return -EINVAL;
-
-       if ((!init_data->input_sbal_addr_array) ||
-           (!init_data->output_sbal_addr_array))
+       if (no_input_qs > QDIO_MAX_QUEUES_PER_IRQ ||
+           no_output_qs > QDIO_MAX_QUEUES_PER_IRQ)
                return -EINVAL;
 
        /* irq_ptr must be in GFP_DMA since it contains ccw1.cda */
@@ -1250,9 +1244,12 @@ int qdio_allocate(struct qdio_initialize *init_data)
 
        irq_ptr->cdev = cdev;
        mutex_init(&irq_ptr->setup_mutex);
-       if (qdio_allocate_dbf(init_data, irq_ptr))
+       if (qdio_allocate_dbf(irq_ptr))
                goto out_rel;
 
+       DBF_DEV_EVENT(DBF_ERR, irq_ptr, "alloc niq:%1u noq:%1u", no_input_qs,
+                     no_output_qs);
+
        /*
         * Allocate a page for the chsc calls in qdio_establish.
         * Must be pre-allocated since a zfcp recovery will call
@@ -1268,8 +1265,7 @@ int qdio_allocate(struct qdio_initialize *init_data)
        if (!irq_ptr->qdr)
                goto out_rel;
 
-       if (qdio_allocate_qs(irq_ptr, init_data->no_input_qs,
-                            init_data->no_output_qs))
+       if (qdio_allocate_qs(irq_ptr, no_input_qs, no_output_qs))
                goto out_rel;
 
        INIT_LIST_HEAD(&irq_ptr->entry);
@@ -1305,13 +1301,33 @@ static void qdio_detect_hsicq(struct qdio_irq *irq_ptr)
        DBF_EVENT("use_cq:%d", use_cq);
 }
 
+static void qdio_trace_init_data(struct qdio_irq *irq,
+                                struct qdio_initialize *data)
+{
+       DBF_DEV_EVENT(DBF_ERR, irq, "qfmt:%1u", data->q_format);
+       DBF_DEV_HEX(irq, data->adapter_name, 8, DBF_ERR);
+       DBF_DEV_EVENT(DBF_ERR, irq, "qpff%4x", data->qib_param_field_format);
+       DBF_DEV_HEX(irq, &data->qib_param_field, sizeof(void *), DBF_ERR);
+       DBF_DEV_HEX(irq, &data->input_slib_elements, sizeof(void *), DBF_ERR);
+       DBF_DEV_HEX(irq, &data->output_slib_elements, sizeof(void *), DBF_ERR);
+       DBF_DEV_EVENT(DBF_ERR, irq, "niq:%1u noq:%1u", data->no_input_qs,
+                     data->no_output_qs);
+       DBF_DEV_HEX(irq, &data->input_handler, sizeof(void *), DBF_ERR);
+       DBF_DEV_HEX(irq, &data->output_handler, sizeof(void *), DBF_ERR);
+       DBF_DEV_HEX(irq, &data->int_parm, sizeof(long), DBF_ERR);
+       DBF_DEV_HEX(irq, &data->input_sbal_addr_array, sizeof(void *), DBF_ERR);
+       DBF_DEV_HEX(irq, &data->output_sbal_addr_array, sizeof(void *),
+                   DBF_ERR);
+}
+
 /**
  * qdio_establish - establish queues on a qdio subchannel
+ * @cdev: associated ccw device
  * @init_data: initialization data
  */
-int qdio_establish(struct qdio_initialize *init_data)
+int qdio_establish(struct ccw_device *cdev,
+                  struct qdio_initialize *init_data)
 {
-       struct ccw_device *cdev = init_data->cdev;
        struct qdio_irq *irq_ptr = cdev->private->qdio_data;
        struct subchannel_id schid;
        int rc;
@@ -1322,7 +1338,16 @@ int qdio_establish(struct qdio_initialize *init_data)
        if (!irq_ptr)
                return -ENODEV;
 
+       if ((init_data->no_input_qs && !init_data->input_handler) ||
+           (init_data->no_output_qs && !init_data->output_handler))
+               return -EINVAL;
+
+       if (!init_data->input_sbal_addr_array ||
+           !init_data->output_sbal_addr_array)
+               return -EINVAL;
+
        mutex_lock(&irq_ptr->setup_mutex);
+       qdio_trace_init_data(irq_ptr, init_data);
        qdio_setup_irq(irq_ptr, init_data);
 
        rc = qdio_establish_thinint(irq_ptr);
@@ -1618,8 +1643,6 @@ int qdio_start_irq(struct ccw_device *cdev)
        if (!irq_ptr)
                return -ENODEV;
 
-       clear_nonshared_ind(irq_ptr);
-
        for_each_input_queue(irq_ptr, q, i)
                qdio_stop_polling(q);
 
index bbbefc9..3083edd 100644 (file)
@@ -213,8 +213,6 @@ static void setup_queues(struct qdio_irq *irq_ptr,
                         struct qdio_initialize *qdio_init)
 {
        struct qdio_q *q;
-       struct qdio_buffer **input_sbal_array = qdio_init->input_sbal_addr_array;
-       struct qdio_buffer **output_sbal_array = qdio_init->output_sbal_addr_array;
        struct qdio_outbuf_state *output_sbal_state_array =
                                  qdio_init->output_sbal_state_array;
        int i;
@@ -225,8 +223,8 @@ static void setup_queues(struct qdio_irq *irq_ptr,
 
                q->is_input_q = 1;
 
-               setup_storage_lists(q, irq_ptr, input_sbal_array, i);
-               input_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
+               setup_storage_lists(q, irq_ptr,
+                                   qdio_init->input_sbal_addr_array[i], i);
 
                if (is_thinint_irq(irq_ptr)) {
                        tasklet_init(&q->tasklet, tiqdio_inbound_processing,
@@ -245,8 +243,8 @@ static void setup_queues(struct qdio_irq *irq_ptr,
                output_sbal_state_array += QDIO_MAX_BUFFERS_PER_Q;
 
                q->is_input_q = 0;
-               setup_storage_lists(q, irq_ptr, output_sbal_array, i);
-               output_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
+               setup_storage_lists(q, irq_ptr,
+                                   qdio_init->output_sbal_addr_array[i], i);
 
                tasklet_init(&q->tasklet, qdio_outbound_processing,
                             (unsigned long) q);
index ea09df7..ae50373 100644 (file)
@@ -82,36 +82,16 @@ void tiqdio_remove_device(struct qdio_irq *irq_ptr)
        INIT_LIST_HEAD(&irq_ptr->entry);
 }
 
-static inline int has_multiple_inq_on_dsci(struct qdio_irq *irq_ptr)
-{
-       return irq_ptr->nr_input_qs > 1;
-}
-
 static inline int references_shared_dsci(struct qdio_irq *irq_ptr)
 {
        return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
 }
 
-static inline int shared_ind(struct qdio_irq *irq_ptr)
-{
-       return references_shared_dsci(irq_ptr) ||
-               has_multiple_inq_on_dsci(irq_ptr);
-}
-
-void clear_nonshared_ind(struct qdio_irq *irq_ptr)
-{
-       if (!is_thinint_irq(irq_ptr))
-               return;
-       if (shared_ind(irq_ptr))
-               return;
-       xchg(irq_ptr->dsci, 0);
-}
-
 int test_nonshared_ind(struct qdio_irq *irq_ptr)
 {
        if (!is_thinint_irq(irq_ptr))
                return 0;
-       if (shared_ind(irq_ptr))
+       if (references_shared_dsci(irq_ptr))
                return 0;
        if (*irq_ptr->dsci)
                return 1;
@@ -131,8 +111,7 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)
        struct qdio_q *q;
        int i;
 
-       if (!references_shared_dsci(irq) &&
-           has_multiple_inq_on_dsci(irq))
+       if (!references_shared_dsci(irq))
                xchg(irq->dsci, 0);
 
        if (irq->irq_poll) {
@@ -145,9 +124,6 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)
        }
 
        for_each_input_queue(irq, q, i) {
-               if (!shared_ind(irq))
-                       xchg(irq->dsci, 0);
-
                /*
                 * Call inbound processing but not directly
                 * since that could starve other thinint queues.
index e401a3d..339a6bc 100644 (file)
@@ -167,6 +167,11 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
        if (ret)
                goto out_disable;
 
+       if (dev_get_uevent_suppress(&sch->dev)) {
+               dev_set_uevent_suppress(&sch->dev, 0);
+               kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+       }
+
        VFIO_CCW_MSG_EVENT(4, "bound to subchannel %x.%x.%04x\n",
                           sch->schid.cssid, sch->schid.ssid,
                           sch->schid.sch_no);
index acda230..e0b2631 100644 (file)
@@ -181,11 +181,12 @@ struct qeth_vnicc_info {
 /*****************************************************************************/
 /* QDIO queue and buffer handling                                            */
 /*****************************************************************************/
-#define QETH_MAX_QUEUES 4
+#define QETH_MAX_OUT_QUEUES    4
 #define QETH_IQD_MIN_TXQ       2       /* One for ucast, one for mcast. */
 #define QETH_IQD_MCAST_TXQ     0
 #define QETH_IQD_MIN_UCAST_TXQ 1
 
+#define QETH_MAX_IN_QUEUES     2
 #define QETH_RX_COPYBREAK      (PAGE_SIZE >> 1)
 #define QETH_IN_BUF_SIZE_DEFAULT 65536
 #define QETH_IN_BUF_COUNT_DEFAULT 64
@@ -539,7 +540,7 @@ struct qeth_qdio_info {
 
        /* output */
        int no_out_queues;
-       struct qeth_qdio_out_q *out_qs[QETH_MAX_QUEUES];
+       struct qeth_qdio_out_q *out_qs[QETH_MAX_OUT_QUEUES];
        struct qdio_outbuf_state *out_bufstates;
 
        /* priority queueing */
index 24fd17b..f768946 100644 (file)
@@ -4812,28 +4812,13 @@ out:
        return;
 }
 
-static void qeth_qdio_establish_cq(struct qeth_card *card,
-                                  struct qdio_buffer **in_sbal_ptrs)
-{
-       int i;
-
-       if (card->options.cq == QETH_CQ_ENABLED) {
-               int offset = QDIO_MAX_BUFFERS_PER_Q *
-                            (card->qdio.no_in_queues - 1);
-
-               for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++)
-                       in_sbal_ptrs[offset + i] =
-                               card->qdio.c_q->bufs[i].buffer;
-       }
-}
-
 static int qeth_qdio_establish(struct qeth_card *card)
 {
+       struct qdio_buffer **out_sbal_ptrs[QETH_MAX_OUT_QUEUES];
+       struct qdio_buffer **in_sbal_ptrs[QETH_MAX_IN_QUEUES];
        struct qdio_initialize init_data;
        char *qib_param_field;
-       struct qdio_buffer **in_sbal_ptrs;
-       struct qdio_buffer **out_sbal_ptrs;
-       int i, j, k;
+       unsigned int i;
        int rc = 0;
 
        QETH_CARD_TEXT(card, 2, "qdioest");
@@ -4847,35 +4832,14 @@ static int qeth_qdio_establish(struct qeth_card *card)
        qeth_create_qib_param_field(card, qib_param_field);
        qeth_create_qib_param_field_blkt(card, qib_param_field);
 
-       in_sbal_ptrs = kcalloc(card->qdio.no_in_queues * QDIO_MAX_BUFFERS_PER_Q,
-                              sizeof(void *),
-                              GFP_KERNEL);
-       if (!in_sbal_ptrs) {
-               rc = -ENOMEM;
-               goto out_free_qib_param;
-       }
-
-       for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++)
-               in_sbal_ptrs[i] = card->qdio.in_q->bufs[i].buffer;
-
-       qeth_qdio_establish_cq(card, in_sbal_ptrs);
-
-       out_sbal_ptrs =
-               kcalloc(card->qdio.no_out_queues * QDIO_MAX_BUFFERS_PER_Q,
-                       sizeof(void *),
-                       GFP_KERNEL);
-       if (!out_sbal_ptrs) {
-               rc = -ENOMEM;
-               goto out_free_in_sbals;
-       }
+       in_sbal_ptrs[0] = card->qdio.in_q->qdio_bufs;
+       if (card->options.cq == QETH_CQ_ENABLED)
+               in_sbal_ptrs[1] = card->qdio.c_q->qdio_bufs;
 
-       for (i = 0, k = 0; i < card->qdio.no_out_queues; ++i)
-               for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++, k++)
-                       out_sbal_ptrs[k] =
-                               card->qdio.out_qs[i]->bufs[j]->buffer;
+       for (i = 0; i < card->qdio.no_out_queues; i++)
+               out_sbal_ptrs[i] = card->qdio.out_qs[i]->qdio_bufs;
 
        memset(&init_data, 0, sizeof(struct qdio_initialize));
-       init_data.cdev                   = CARD_DDEV(card);
        init_data.q_format               = IS_IQD(card) ? QDIO_IQDIO_QFMT :
                                                          QDIO_QETH_QFMT;
        init_data.qib_param_field_format = 0;
@@ -4893,12 +4857,13 @@ static int qeth_qdio_establish(struct qeth_card *card)
 
        if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED,
                QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) {
-               rc = qdio_allocate(&init_data);
+               rc = qdio_allocate(CARD_DDEV(card), init_data.no_input_qs,
+                                  init_data.no_output_qs);
                if (rc) {
                        atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
                        goto out;
                }
-               rc = qdio_establish(&init_data);
+               rc = qdio_establish(CARD_DDEV(card), &init_data);
                if (rc) {
                        atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
                        qdio_free(CARD_DDEV(card));
@@ -4916,10 +4881,6 @@ static int qeth_qdio_establish(struct qeth_card *card)
                break;
        }
 out:
-       kfree(out_sbal_ptrs);
-out_free_in_sbals:
-       kfree(in_sbal_ptrs);
-out_free_qib_param:
        kfree(qib_param_field);
 out_free_nothing:
        return rc;
@@ -5985,7 +5946,7 @@ static struct net_device *qeth_alloc_netdev(struct qeth_card *card)
        switch (card->info.type) {
        case QETH_CARD_TYPE_IQD:
                dev = alloc_netdev_mqs(sizeof(*priv), "hsi%d", NET_NAME_UNKNOWN,
-                                      ether_setup, QETH_MAX_QUEUES, 1);
+                                      ether_setup, QETH_MAX_OUT_QUEUES, 1);
                break;
        case QETH_CARD_TYPE_OSM:
                dev = alloc_etherdev(sizeof(*priv));
@@ -5995,7 +5956,7 @@ static struct net_device *qeth_alloc_netdev(struct qeth_card *card)
                                   ether_setup);
                break;
        default:
-               dev = alloc_etherdev_mqs(sizeof(*priv), QETH_MAX_QUEUES, 1);
+               dev = alloc_etherdev_mqs(sizeof(*priv), QETH_MAX_OUT_QUEUES, 1);
        }
 
        if (!dev)
index 18a6751..3d0bc00 100644 (file)
@@ -178,12 +178,12 @@ static enum zfcp_erp_act_type zfcp_erp_required_act(enum zfcp_erp_act_type want,
                        return 0;
                if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
                        need = ZFCP_ERP_ACTION_REOPEN_PORT;
-               /* fall through */
+               fallthrough;
        case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
                p_status = atomic_read(&port->status);
                if (!(p_status & ZFCP_STATUS_COMMON_OPEN))
                        need = ZFCP_ERP_ACTION_REOPEN_PORT;
-               /* fall through */
+               fallthrough;
        case ZFCP_ERP_ACTION_REOPEN_PORT:
                p_status = atomic_read(&port->status);
                if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
@@ -196,7 +196,7 @@ static enum zfcp_erp_act_type zfcp_erp_required_act(enum zfcp_erp_act_type want,
                        return need;
                if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
                        need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
-               /* fall through */
+               fallthrough;
        case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
                a_status = atomic_read(&adapter->status);
                if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
@@ -1086,7 +1086,7 @@ static enum zfcp_erp_act_result zfcp_erp_lun_strategy(
                if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
                        return zfcp_erp_lun_strategy_close(erp_action);
                /* already closed */
-               /* fall through */
+               fallthrough;
        case ZFCP_ERP_STEP_LUN_CLOSING:
                if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
                        return ZFCP_ERP_FAILED;
@@ -1415,7 +1415,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act,
                if (act->step != ZFCP_ERP_STEP_UNINITIALIZED)
                        if (result == ZFCP_ERP_SUCCEEDED)
                                zfcp_erp_try_rport_unblock(port);
-               /* fall through */
+               fallthrough;
        case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
                put_device(&port->dev);
                break;
index 7c603e5..111fe3f 100644 (file)
@@ -564,7 +564,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
        case FSF_TOPO_AL:
                fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
                fc_host_fabric_name(shost) = 0;
-               /* fall through */
+               fallthrough;
        default:
                fc_host_fabric_name(shost) = 0;
                dev_err(&adapter->ccw_device->dev,
@@ -1032,7 +1032,7 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
                switch (fsq->word[0]) {
                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
                        zfcp_fc_test_link(zfcp_sdev->port);
-                       /* fall through */
+                       fallthrough;
                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
                        req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                        break;
@@ -1127,7 +1127,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
                break;
        case FSF_PORT_HANDLE_NOT_VALID:
                zfcp_erp_adapter_reopen(adapter, 0, "fsscth1");
-               /* fall through */
+               fallthrough;
        case FSF_GENERIC_COMMAND_REJECTED:
        case FSF_PAYLOAD_SIZE_MISMATCH:
        case FSF_REQUEST_SIZE_TOO_LARGE:
@@ -1313,7 +1313,7 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)
                break;
        case FSF_SBAL_MISMATCH:
                /* should never occur, avoided in zfcp_fsf_send_els */
-               /* fall through */
+               fallthrough;
        default:
                req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                break;
@@ -1736,7 +1736,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
                switch (header->fsf_status_qual.word[0]) {
                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
                        /* no zfcp_fc_test_link() with failed open port */
-                       /* fall through */
+                       fallthrough;
                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
                case FSF_SQ_NO_RETRY_POSSIBLE:
                        req->status |= ZFCP_STATUS_FSFREQ_ERROR;
@@ -1909,14 +1909,14 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
        case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
                dev_warn(&req->adapter->ccw_device->dev,
                         "Opening WKA port 0x%x failed\n", wka_port->d_id);
-               /* fall through */
+               fallthrough;
        case FSF_ADAPTER_STATUS_AVAILABLE:
                req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE;
                break;
        case FSF_GOOD:
                wka_port->handle = header->port_handle;
-               /* fall through */
+               fallthrough;
        case FSF_PORT_ALREADY_OPEN:
                wka_port->status = ZFCP_FC_WKA_PORT_ONLINE;
        }
@@ -2059,7 +2059,6 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
        case FSF_ADAPTER_STATUS_AVAILABLE:
                switch (header->fsf_status_qual.word[0]) {
                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
-                       /* fall through */
                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
                        req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                        break;
@@ -2144,7 +2143,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req)
 
        case FSF_PORT_HANDLE_NOT_VALID:
                zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1");
-               /* fall through */
+               fallthrough;
        case FSF_LUN_ALREADY_OPEN:
                break;
        case FSF_PORT_BOXED:
@@ -2175,7 +2174,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req)
                         (unsigned long long)zfcp_scsi_dev_lun(sdev),
                         (unsigned long long)zfcp_sdev->port->wwpn);
                zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED);
-               /* fall through */
+               fallthrough;
        case FSF_INVALID_COMMAND_OPTION:
                req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                break;
@@ -2183,7 +2182,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req)
                switch (header->fsf_status_qual.word[0]) {
                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
                        zfcp_fc_test_link(zfcp_sdev->port);
-                       /* fall through */
+                       fallthrough;
                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
                        req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                        break;
@@ -2277,7 +2276,7 @@ static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req)
                switch (req->qtcb->header.fsf_status_qual.word[0]) {
                case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
                        zfcp_fc_test_link(zfcp_sdev->port);
-                       /* fall through */
+                       fallthrough;
                case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
                        req->status |= ZFCP_STATUS_FSFREQ_ERROR;
                        break;
index f0d6296..26702b5 100644 (file)
@@ -277,29 +277,6 @@ int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
        return 0;
 }
 
-
-static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
-                                     struct zfcp_qdio *qdio)
-{
-       memset(id, 0, sizeof(*id));
-       id->cdev = qdio->adapter->ccw_device;
-       id->q_format = QDIO_ZFCP_QFMT;
-       memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8);
-       ASCEBC(id->adapter_name, 8);
-       id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV;
-       if (enable_multibuffer)
-               id->qdr_ac |= QDR_AC_MULTI_BUFFER_ENABLE;
-       id->no_input_qs = 1;
-       id->no_output_qs = 1;
-       id->input_handler = zfcp_qdio_int_resp;
-       id->output_handler = zfcp_qdio_int_req;
-       id->int_parm = (unsigned long) qdio;
-       id->input_sbal_addr_array = qdio->res_q;
-       id->output_sbal_addr_array = qdio->req_q;
-       id->scan_threshold =
-               QDIO_MAX_BUFFERS_PER_Q - ZFCP_QDIO_MAX_SBALS_PER_REQ * 2;
-}
-
 /**
  * zfcp_qdio_allocate - allocate queue memory and initialize QDIO data
  * @qdio: pointer to struct zfcp_qdio
@@ -308,7 +285,6 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
  */
 static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
 {
-       struct qdio_initialize init_data;
        int ret;
 
        ret = qdio_alloc_buffers(qdio->req_q, QDIO_MAX_BUFFERS_PER_Q);
@@ -319,10 +295,9 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
        if (ret)
                goto free_req_q;
 
-       zfcp_qdio_setup_init_data(&init_data, qdio);
        init_waitqueue_head(&qdio->req_q_wq);
 
-       ret = qdio_allocate(&init_data);
+       ret = qdio_allocate(qdio->adapter->ccw_device, 1, 1);
        if (ret)
                goto free_res_q;
 
@@ -374,8 +349,10 @@ void zfcp_qdio_close(struct zfcp_qdio *qdio)
  */
 int zfcp_qdio_open(struct zfcp_qdio *qdio)
 {
+       struct qdio_buffer **input_sbals[1] = {qdio->res_q};
+       struct qdio_buffer **output_sbals[1] = {qdio->req_q};
        struct qdio_buffer_element *sbale;
-       struct qdio_initialize init_data;
+       struct qdio_initialize init_data = {0};
        struct zfcp_adapter *adapter = qdio->adapter;
        struct ccw_device *cdev = adapter->ccw_device;
        struct qdio_ssqd_desc ssqd;
@@ -387,12 +364,26 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio)
        atomic_andnot(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
                          &qdio->adapter->status);
 
-       zfcp_qdio_setup_init_data(&init_data, qdio);
+       init_data.q_format = QDIO_ZFCP_QFMT;
+       memcpy(init_data.adapter_name, dev_name(&cdev->dev), 8);
+       ASCEBC(init_data.adapter_name, 8);
+       init_data.qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV;
+       if (enable_multibuffer)
+               init_data.qdr_ac |= QDR_AC_MULTI_BUFFER_ENABLE;
+       init_data.no_input_qs = 1;
+       init_data.no_output_qs = 1;
+       init_data.input_handler = zfcp_qdio_int_resp;
+       init_data.output_handler = zfcp_qdio_int_req;
+       init_data.int_parm = (unsigned long) qdio;
+       init_data.input_sbal_addr_array = input_sbals;
+       init_data.output_sbal_addr_array = output_sbals;
+       init_data.scan_threshold =
+               QDIO_MAX_BUFFERS_PER_Q - ZFCP_QDIO_MAX_SBALS_PER_REQ * 2;
 
-       if (qdio_establish(&init_data))
+       if (qdio_establish(cdev, &init_data))
                goto failed_establish;
 
-       if (qdio_get_ssqd_desc(init_data.cdev, &ssqd))
+       if (qdio_get_ssqd_desc(cdev, &ssqd))
                goto failed_qdio;
 
        if (ssqd.qdioac2 & CHSC_AC2_DATA_DIV_ENABLED)
index 4725e4c..ddd73f6 100644 (file)
@@ -1626,7 +1626,7 @@ out:
 int aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type)
 {
        unsigned long flagv = 0;
-       int retval;
+       int retval, unblock_retval;
        struct Scsi_Host *host = aac->scsi_host_ptr;
        int bled;
 
@@ -1656,8 +1656,9 @@ int aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type)
        retval = _aac_reset_adapter(aac, bled, reset_type);
        spin_unlock_irqrestore(host->host_lock, flagv);
 
-       retval = scsi_host_unblock(host, SDEV_RUNNING);
-
+       unblock_retval = scsi_host_unblock(host, SDEV_RUNNING);
+       if (!retval)
+               retval = unblock_retval;
        if ((forced < 2) && (retval == -ENODEV)) {
                /* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */
                struct fib * fibctx = aac_fib_alloc(aac);
index 4190a02..84fc499 100644 (file)
@@ -1834,21 +1834,6 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
                                printerror = 0;
                        } else if (ahc_sent_msg(ahc, AHCMSG_1B,
                                                MSG_BUS_DEV_RESET, TRUE)) {
-#ifdef __FreeBSD__
-                               /*
-                                * Don't mark the user's request for this BDR
-                                * as completing with CAM_BDR_SENT.  CAM3
-                                * specifies CAM_REQ_CMP.
-                                */
-                               if (scb != NULL
-                                && scb->io_ctx->ccb_h.func_code== XPT_RESET_DEV
-                                && ahc_match_scb(ahc, scb, target, channel,
-                                                 CAM_LUN_WILDCARD,
-                                                 SCB_LIST_NULL,
-                                                 ROLE_INITIATOR)) {
-                                       ahc_set_transaction_status(scb, CAM_REQ_CMP);
-                               }
-#endif
                                ahc_compile_devinfo(&devinfo,
                                                    initiator_role_id,
                                                    target,
@@ -4399,22 +4384,16 @@ ahc_alloc(void *platform_arg, char *name)
        struct  ahc_softc *ahc;
        int     i;
 
-#ifndef        __FreeBSD__
        ahc = kmalloc(sizeof(*ahc), GFP_ATOMIC);
        if (!ahc) {
                printk("aic7xxx: cannot malloc softc!\n");
                kfree(name);
                return NULL;
        }
-#else
-       ahc = device_get_softc((device_t)platform_arg);
-#endif
        memset(ahc, 0, sizeof(*ahc));
        ahc->seep_config = kmalloc(sizeof(*ahc->seep_config), GFP_ATOMIC);
        if (ahc->seep_config == NULL) {
-#ifndef        __FreeBSD__
                kfree(ahc);
-#endif
                kfree(name);
                return (NULL);
        }
@@ -4540,9 +4519,7 @@ ahc_free(struct ahc_softc *ahc)
                kfree(ahc->name);
        if (ahc->seep_config != NULL)
                kfree(ahc->seep_config);
-#ifndef __FreeBSD__
        kfree(ahc);
-#endif
        return;
 }
 
index 3b84db8..b6e8ed7 100644 (file)
@@ -66,7 +66,7 @@
 #include "bnx2fc_constants.h"
 
 #define BNX2FC_NAME            "bnx2fc"
-#define BNX2FC_VERSION         "2.12.10"
+#define BNX2FC_VERSION         "2.12.13"
 
 #define PFX                    "bnx2fc: "
 
@@ -482,7 +482,10 @@ struct io_bdt {
 struct bnx2fc_work {
        struct list_head list;
        struct bnx2fc_rport *tgt;
+       struct fcoe_task_ctx_entry *task;
+       unsigned char rq_data[BNX2FC_RQ_BUF_SZ];
        u16 wqe;
+       u8 num_rq;
 };
 struct bnx2fc_unsol_els {
        struct fc_lport *lport;
@@ -550,7 +553,7 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport,
                                enum fc_rport_event event);
 void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
                                   struct fcoe_task_ctx_entry *task,
-                                  u8 num_rq);
+                                  u8 num_rq, unsigned char *rq_data);
 void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req,
                               struct fcoe_task_ctx_entry *task,
                               u8 num_rq);
@@ -559,7 +562,7 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req,
                               u8 num_rq);
 void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
                             struct fcoe_task_ctx_entry *task,
-                            u8 num_rq);
+                            u8 num_rq, unsigned char *rq_data);
 void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req,
                              struct fcoe_task_ctx_entry *task,
                              u8 num_rq);
@@ -577,7 +580,9 @@ struct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did,
                                      void *arg, u32 timeout);
 void bnx2fc_arm_cq(struct bnx2fc_rport *tgt);
 int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt);
-void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe);
+void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe,
+                            unsigned char *rq_data, u8 num_rq,
+                            struct fcoe_task_ctx_entry *task);
 struct bnx2fc_rport *bnx2fc_tgt_lookup(struct fcoe_port *port,
                                             u32 port_id);
 void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt,
index b4bfab5..1cbb431 100644 (file)
@@ -660,7 +660,10 @@ static int bnx2fc_percpu_io_thread(void *arg)
 
                        list_for_each_entry_safe(work, tmp, &work_list, list) {
                                list_del_init(&work->list);
-                               bnx2fc_process_cq_compl(work->tgt, work->wqe);
+                               bnx2fc_process_cq_compl(work->tgt, work->wqe,
+                                                       work->rq_data,
+                                                       work->num_rq,
+                                                       work->task);
                                kfree(work);
                        }
 
@@ -2655,7 +2658,8 @@ static int bnx2fc_cpu_offline(unsigned int cpu)
        /* Free all work in the list */
        list_for_each_entry_safe(work, tmp, &p->work_list, list) {
                list_del_init(&work->list);
-               bnx2fc_process_cq_compl(work->tgt, work->wqe);
+               bnx2fc_process_cq_compl(work->tgt, work->wqe, work->rq_data,
+                                       work->num_rq, work->task);
                kfree(work);
        }
 
index 6f8335d..1f7c58b 100644 (file)
@@ -863,36 +863,22 @@ ret_warn_rqe:
        }
 }
 
-void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
+void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe,
+                            unsigned char *rq_data, u8 num_rq,
+                            struct fcoe_task_ctx_entry *task)
 {
-       struct fcoe_task_ctx_entry *task;
-       struct fcoe_task_ctx_entry *task_page;
        struct fcoe_port *port = tgt->port;
        struct bnx2fc_interface *interface = port->priv;
        struct bnx2fc_hba *hba = interface->hba;
        struct bnx2fc_cmd *io_req;
-       int task_idx, index;
+
        u16 xid;
        u8  cmd_type;
        u8 rx_state = 0;
-       u8 num_rq;
 
        spin_lock_bh(&tgt->tgt_lock);
-       xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID;
-       if (xid >= hba->max_tasks) {
-               printk(KERN_ERR PFX "ERROR:xid out of range\n");
-               spin_unlock_bh(&tgt->tgt_lock);
-               return;
-       }
-       task_idx = xid / BNX2FC_TASKS_PER_PAGE;
-       index = xid % BNX2FC_TASKS_PER_PAGE;
-       task_page = (struct fcoe_task_ctx_entry *)hba->task_ctx[task_idx];
-       task = &(task_page[index]);
-
-       num_rq = ((task->rxwr_txrd.var_ctx.rx_flags &
-                  FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE) >>
-                  FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE_SHIFT);
 
+       xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID;
        io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid];
 
        if (io_req == NULL) {
@@ -912,7 +898,8 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
        switch (cmd_type) {
        case BNX2FC_SCSI_CMD:
                if (rx_state == FCOE_TASK_RX_STATE_COMPLETED) {
-                       bnx2fc_process_scsi_cmd_compl(io_req, task, num_rq);
+                       bnx2fc_process_scsi_cmd_compl(io_req, task, num_rq,
+                                                     rq_data);
                        spin_unlock_bh(&tgt->tgt_lock);
                        return;
                }
@@ -929,7 +916,7 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
 
        case BNX2FC_TASK_MGMT_CMD:
                BNX2FC_IO_DBG(io_req, "Processing TM complete\n");
-               bnx2fc_process_tm_compl(io_req, task, num_rq);
+               bnx2fc_process_tm_compl(io_req, task, num_rq, rq_data);
                break;
 
        case BNX2FC_ABTS:
@@ -987,7 +974,9 @@ void bnx2fc_arm_cq(struct bnx2fc_rport *tgt)
 
 }
 
-static struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe)
+static struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe,
+                                            unsigned char *rq_data, u8 num_rq,
+                                            struct fcoe_task_ctx_entry *task)
 {
        struct bnx2fc_work *work;
        work = kzalloc(sizeof(struct bnx2fc_work), GFP_ATOMIC);
@@ -997,29 +986,87 @@ static struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe)
        INIT_LIST_HEAD(&work->list);
        work->tgt = tgt;
        work->wqe = wqe;
+       work->num_rq = num_rq;
+       work->task = task;
+       if (rq_data)
+               memcpy(work->rq_data, rq_data, BNX2FC_RQ_BUF_SZ);
+
        return work;
 }
 
 /* Pending work request completion */
-static void bnx2fc_pending_work(struct bnx2fc_rport *tgt, unsigned int wqe)
+static bool bnx2fc_pending_work(struct bnx2fc_rport *tgt, unsigned int wqe)
 {
        unsigned int cpu = wqe % num_possible_cpus();
        struct bnx2fc_percpu_s *fps;
        struct bnx2fc_work *work;
+       struct fcoe_task_ctx_entry *task;
+       struct fcoe_task_ctx_entry *task_page;
+       struct fcoe_port *port = tgt->port;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
+       unsigned char *rq_data = NULL;
+       unsigned char rq_data_buff[BNX2FC_RQ_BUF_SZ];
+       int task_idx, index;
+       unsigned char *dummy;
+       u16 xid;
+       u8 num_rq;
+       int i;
+
+       xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID;
+       if (xid >= hba->max_tasks) {
+               pr_err(PFX "ERROR:xid out of range\n");
+               return false;
+       }
+
+       task_idx = xid / BNX2FC_TASKS_PER_PAGE;
+       index = xid % BNX2FC_TASKS_PER_PAGE;
+       task_page = (struct fcoe_task_ctx_entry *)hba->task_ctx[task_idx];
+       task = &task_page[index];
+
+       num_rq = ((task->rxwr_txrd.var_ctx.rx_flags &
+                  FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE) >>
+                 FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE_SHIFT);
+
+       memset(rq_data_buff, 0, BNX2FC_RQ_BUF_SZ);
+
+       if (!num_rq)
+               goto num_rq_zero;
+
+       rq_data = bnx2fc_get_next_rqe(tgt, 1);
+
+       if (num_rq > 1) {
+               /* We do not need extra sense data */
+               for (i = 1; i < num_rq; i++)
+                       dummy = bnx2fc_get_next_rqe(tgt, 1);
+       }
+
+       if (rq_data)
+               memcpy(rq_data_buff, rq_data, BNX2FC_RQ_BUF_SZ);
+
+       /* return RQ entries */
+       for (i = 0; i < num_rq; i++)
+               bnx2fc_return_rqe(tgt, 1);
+
+num_rq_zero:
 
        fps = &per_cpu(bnx2fc_percpu, cpu);
        spin_lock_bh(&fps->fp_work_lock);
        if (fps->iothread) {
-               work = bnx2fc_alloc_work(tgt, wqe);
+               work = bnx2fc_alloc_work(tgt, wqe, rq_data_buff,
+                                        num_rq, task);
                if (work) {
                        list_add_tail(&work->list, &fps->work_list);
                        wake_up_process(fps->iothread);
                        spin_unlock_bh(&fps->fp_work_lock);
-                       return;
+                       return true;
                }
        }
        spin_unlock_bh(&fps->fp_work_lock);
-       bnx2fc_process_cq_compl(tgt, wqe);
+       bnx2fc_process_cq_compl(tgt, wqe,
+                               rq_data_buff, num_rq, task);
+
+       return true;
 }
 
 int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt)
@@ -1056,8 +1103,8 @@ int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt)
                        /* Unsolicited event notification */
                        bnx2fc_process_unsol_compl(tgt, wqe);
                } else {
-                       bnx2fc_pending_work(tgt, wqe);
-                       num_free_sqes++;
+                       if (bnx2fc_pending_work(tgt, wqe))
+                               num_free_sqes++;
                }
                cqe++;
                tgt->cq_cons_idx++;
index 4c8122a..2b070f0 100644 (file)
@@ -24,7 +24,7 @@ static void bnx2fc_unmap_sg_list(struct bnx2fc_cmd *io_req);
 static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req);
 static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
                                 struct fcoe_fcp_rsp_payload *fcp_rsp,
-                                u8 num_rq);
+                                u8 num_rq, unsigned char *rq_data);
 
 void bnx2fc_cmd_timer_set(struct bnx2fc_cmd *io_req,
                          unsigned int timer_msec)
@@ -1518,7 +1518,8 @@ static void bnx2fc_tgt_reset_cmpl(struct bnx2fc_cmd *io_req)
 }
 
 void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
-                            struct fcoe_task_ctx_entry *task, u8 num_rq)
+                            struct fcoe_task_ctx_entry *task, u8 num_rq,
+                                 unsigned char *rq_data)
 {
        struct bnx2fc_mp_req *tm_req;
        struct fc_frame_header *fc_hdr;
@@ -1557,7 +1558,7 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
        if (fc_hdr->fh_r_ctl == FC_RCTL_DD_CMD_STATUS) {
                bnx2fc_parse_fcp_rsp(io_req,
                                     (struct fcoe_fcp_rsp_payload *)
-                                    rsp_buf, num_rq);
+                                    rsp_buf, num_rq, rq_data);
                if (io_req->fcp_rsp_code == 0) {
                        /* TM successful */
                        if (tm_req->tm_flags & FCP_TMF_LUN_RESET)
@@ -1755,15 +1756,11 @@ void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req,
 
 static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
                                 struct fcoe_fcp_rsp_payload *fcp_rsp,
-                                u8 num_rq)
+                                u8 num_rq, unsigned char *rq_data)
 {
        struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
-       struct bnx2fc_rport *tgt = io_req->tgt;
        u8 rsp_flags = fcp_rsp->fcp_flags.flags;
        u32 rq_buff_len = 0;
-       int i;
-       unsigned char *rq_data;
-       unsigned char *dummy;
        int fcp_sns_len = 0;
        int fcp_rsp_len = 0;
 
@@ -1809,14 +1806,6 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
                        rq_buff_len =  num_rq * BNX2FC_RQ_BUF_SZ;
                }
 
-               rq_data = bnx2fc_get_next_rqe(tgt, 1);
-
-               if (num_rq > 1) {
-                       /* We do not need extra sense data */
-                       for (i = 1; i < num_rq; i++)
-                               dummy = bnx2fc_get_next_rqe(tgt, 1);
-               }
-
                /* fetch fcp_rsp_code */
                if ((fcp_rsp_len == 4) || (fcp_rsp_len == 8)) {
                        /* Only for task management function */
@@ -1837,9 +1826,6 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
                if (fcp_sns_len)
                        memcpy(sc_cmd->sense_buffer, rq_data, fcp_sns_len);
 
-               /* return RQ entries */
-               for (i = 0; i < num_rq; i++)
-                       bnx2fc_return_rqe(tgt, 1);
        }
 }
 
@@ -1918,7 +1904,7 @@ exit_qcmd:
 
 void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
                                   struct fcoe_task_ctx_entry *task,
-                                  u8 num_rq)
+                                  u8 num_rq, unsigned char *rq_data)
 {
        struct fcoe_fcp_rsp_payload *fcp_rsp;
        struct bnx2fc_rport *tgt = io_req->tgt;
@@ -1931,6 +1917,12 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
                /* we will not receive ABTS response for this IO */
                BNX2FC_IO_DBG(io_req, "Timer context finished processing "
                           "this scsi cmd\n");
+               if (test_and_clear_bit(BNX2FC_FLAG_IO_CLEANUP,
+                                      &io_req->req_flags)) {
+                       BNX2FC_IO_DBG(io_req,
+                                     "Actual completion after cleanup request cleaning up\n");
+                       bnx2fc_process_cleanup_compl(io_req, task, num_rq);
+               }
                return;
        }
 
@@ -1950,7 +1942,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
                   &(task->rxwr_only.union_ctx.comp_info.fcp_rsp.payload);
 
        /* parse fcp_rsp and obtain sense data from RQ if available */
-       bnx2fc_parse_fcp_rsp(io_req, fcp_rsp, num_rq);
+       bnx2fc_parse_fcp_rsp(io_req, fcp_rsp, num_rq, rq_data);
 
        if (!sc_cmd->SCp.ptr) {
                printk(KERN_ERR PFX "SCp.ptr is NULL\n");
index d4c2a2e..84d73f5 100644 (file)
@@ -404,7 +404,7 @@ static const char * const hostbyte_table[]={
 "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
 "DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE",
 "DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST", "DID_TARGET_FAILURE",
-"DID_NEXUS_FAILURE" };
+"DID_NEXUS_FAILURE", "DID_ALLOC_FAILURE", "DID_MEDIUM_ERROR" };
 
 static const char * const driverbyte_table[]={
 "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT",  "DRIVER_MEDIA", "DRIVER_ERROR",
index da6e97d..773c45a 100644 (file)
@@ -632,6 +632,8 @@ static void fc_rport_error(struct fc_rport_priv *rdata, int err)
                fc_rport_enter_ready(rdata);
                break;
        case RPORT_ST_PRLI:
+               fc_rport_enter_plogi(rdata);
+               break;
        case RPORT_ST_ADISC:
                fc_rport_enter_logo(rdata);
                break;
@@ -1208,9 +1210,15 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
                rjt = fc_frame_payload_get(fp, sizeof(*rjt));
                if (!rjt)
                        FC_RPORT_DBG(rdata, "PRLI bad response\n");
-               else
+               else {
                        FC_RPORT_DBG(rdata, "PRLI ELS rejected, reason %x expl %x\n",
                                     rjt->er_reason, rjt->er_explan);
+                       if (rjt->er_reason == ELS_RJT_UNAB &&
+                           rjt->er_explan == ELS_EXPL_PLOGI_REQD) {
+                               fc_rport_enter_plogi(rdata);
+                               goto out;
+                       }
+               }
                fc_rport_error_retry(rdata, FC_EX_ELS_RJT);
        }
 
index 357fdec..8e2a356 100644 (file)
@@ -207,8 +207,7 @@ typedef struct lpfc_vpd {
        } rev;
        struct {
 #ifdef __BIG_ENDIAN_BITFIELD
-               uint32_t rsvd3  :19;  /* Reserved                             */
-               uint32_t cdss   : 1;  /* Configure Data Security SLI          */
+               uint32_t rsvd3  :20;  /* Reserved                             */
                uint32_t rsvd2  : 3;  /* Reserved                             */
                uint32_t cbg    : 1;  /* Configure BlockGuard                 */
                uint32_t cmv    : 1;  /* Configure Max VPIs                   */
@@ -230,8 +229,7 @@ typedef struct lpfc_vpd {
                uint32_t cmv    : 1;  /* Configure Max VPIs                   */
                uint32_t cbg    : 1;  /* Configure BlockGuard                 */
                uint32_t rsvd2  : 3;  /* Reserved                             */
-               uint32_t cdss   : 1;  /* Configure Data Security SLI          */
-               uint32_t rsvd3  :19;  /* Reserved                             */
+               uint32_t rsvd3  :20;  /* Reserved                             */
 #endif
        } sli3Feat;
 } lpfc_vpd_t;
@@ -480,8 +478,8 @@ struct lpfc_vport {
        struct dentry *debug_nodelist;
        struct dentry *debug_nvmestat;
        struct dentry *debug_scsistat;
-       struct dentry *debug_nvmektime;
-       struct dentry *debug_cpucheck;
+       struct dentry *debug_ioktime;
+       struct dentry *debug_hdwqstat;
        struct dentry *vport_debugfs_root;
        struct lpfc_debugfs_trc *disc_trc;
        atomic_t disc_trc_cnt;
@@ -887,7 +885,6 @@ struct lpfc_hba {
 #define LPFC_INITIALIZE_LINK              0    /* do normal init_link mbox */
 #define LPFC_DELAY_INIT_LINK              1    /* layered driver hold off */
 #define LPFC_DELAY_INIT_LINK_INDEFINITELY 2    /* wait, manual intervention */
-       uint32_t cfg_enable_dss;
        uint32_t cfg_fdmi_on;
 #define LPFC_FDMI_NO_SUPPORT   0       /* FDMI not supported */
 #define LPFC_FDMI_SUPPORT      1       /* FDMI supported? */
@@ -1156,8 +1153,6 @@ struct lpfc_hba {
        uint32_t iocb_cnt;
        uint32_t iocb_max;
        atomic_t sdev_cnt;
-       uint8_t fips_spec_rev;
-       uint8_t fips_level;
        spinlock_t devicelock;  /* lock for luns list */
        mempool_t *device_data_mem_pool;
        struct list_head luns;
@@ -1175,12 +1170,11 @@ struct lpfc_hba {
        uint16_t sfp_warning;
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       uint16_t cpucheck_on;
+       uint16_t hdwqstat_on;
 #define LPFC_CHECK_OFF         0
 #define LPFC_CHECK_NVME_IO     1
-#define LPFC_CHECK_NVMET_RCV   2
-#define LPFC_CHECK_NVMET_IO    4
-#define LPFC_CHECK_SCSI_IO     8
+#define LPFC_CHECK_NVMET_IO    2
+#define LPFC_CHECK_SCSI_IO     4
        uint16_t ktime_on;
        uint64_t ktime_data_samples;
        uint64_t ktime_status_samples;
@@ -1225,6 +1219,11 @@ struct lpfc_hba {
 #define LPFC_POLL_SLOWPATH     1       /* called from slowpath */
 
        char os_host_name[MAXHOSTNAMELEN];
+
+       /* SCSI host template information - for physical port */
+       struct scsi_host_template port_template;
+       /* SCSI host template information - for all vports */
+       struct scsi_host_template vport_template;
 };
 
 static inline struct Scsi_Host *
index be3b0cc..1354c14 100644 (file)
@@ -2231,66 +2231,6 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr,
 }
 
 /**
- * lpfc_fips_level_show - Return the current FIPS level for the HBA
- * @dev: class unused variable.
- * @attr: device attribute, not used.
- * @buf: on return contains the module description text.
- *
- * Returns: size of formatted string.
- **/
-static ssize_t
-lpfc_fips_level_show(struct device *dev,  struct device_attribute *attr,
-                    char *buf)
-{
-       struct Scsi_Host  *shost = class_to_shost(dev);
-       struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-       struct lpfc_hba   *phba = vport->phba;
-
-       return scnprintf(buf, PAGE_SIZE, "%d\n", phba->fips_level);
-}
-
-/**
- * lpfc_fips_rev_show - Return the FIPS Spec revision for the HBA
- * @dev: class unused variable.
- * @attr: device attribute, not used.
- * @buf: on return contains the module description text.
- *
- * Returns: size of formatted string.
- **/
-static ssize_t
-lpfc_fips_rev_show(struct device *dev,  struct device_attribute *attr,
-                  char *buf)
-{
-       struct Scsi_Host  *shost = class_to_shost(dev);
-       struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-       struct lpfc_hba   *phba = vport->phba;
-
-       return scnprintf(buf, PAGE_SIZE, "%d\n", phba->fips_spec_rev);
-}
-
-/**
- * lpfc_dss_show - Return the current state of dss and the configured state
- * @dev: class converted to a Scsi_host structure.
- * @attr: device attribute, not used.
- * @buf: on return contains the formatted text.
- *
- * Returns: size of formatted string.
- **/
-static ssize_t
-lpfc_dss_show(struct device *dev, struct device_attribute *attr,
-             char *buf)
-{
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-       struct lpfc_hba   *phba = vport->phba;
-
-       return scnprintf(buf, PAGE_SIZE, "%s - %sOperational\n",
-                       (phba->cfg_enable_dss) ? "Enabled" : "Disabled",
-                       (phba->sli3_options & LPFC_SLI3_DSS_ENABLED) ?
-                               "" : "Not ");
-}
-
-/**
  * lpfc_sriov_hw_max_virtfn_show - Return maximum number of virtual functions
  * @dev: class converted to a Scsi_host structure.
  * @attr: device attribute, not used.
@@ -2705,9 +2645,6 @@ static DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL);
 static DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL);
 static DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL);
 static DEVICE_ATTR_RO(lpfc_temp_sensor);
-static DEVICE_ATTR_RO(lpfc_fips_level);
-static DEVICE_ATTR_RO(lpfc_fips_rev);
-static DEVICE_ATTR_RO(lpfc_dss);
 static DEVICE_ATTR_RO(lpfc_sriov_hw_max_virtfn);
 static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL);
 static DEVICE_ATTR(lpfc_xlane_supported, S_IRUGO, lpfc_oas_supported_show,
@@ -3868,9 +3805,9 @@ LPFC_VPORT_ATTR_R(enable_da_id, 1, 0, 1,
 
 /*
 # lun_queue_depth:  This parameter is used to limit the number of outstanding
-# commands per FCP LUN. Value range is [1,512]. Default value is 30.
+# commands per FCP LUN.
 */
-LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 512,
+LPFC_VPORT_ATTR_R(lun_queue_depth, 64, 1, 512,
                  "Max number of FCP commands we can queue to a specific LUN");
 
 /*
@@ -6251,9 +6188,6 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_pt,
        &dev_attr_txq_hw,
        &dev_attr_txcmplq_hw,
-       &dev_attr_lpfc_fips_level,
-       &dev_attr_lpfc_fips_rev,
-       &dev_attr_lpfc_dss,
        &dev_attr_lpfc_sriov_hw_max_virtfn,
        &dev_attr_protocol,
        &dev_attr_lpfc_xlane_supported,
@@ -6289,8 +6223,6 @@ struct device_attribute *lpfc_vport_attrs[] = {
        &dev_attr_lpfc_max_scsicmpl_time,
        &dev_attr_lpfc_stat_data_ctrl,
        &dev_attr_lpfc_static_vport,
-       &dev_attr_lpfc_fips_level,
-       &dev_attr_lpfc_fips_rev,
        NULL,
 };
 
@@ -7399,7 +7331,6 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
        lpfc_delay_discovery_init(phba, lpfc_delay_discovery);
        lpfc_sli_mode_init(phba, lpfc_sli_mode);
-       phba->cfg_enable_dss = 1;
        lpfc_enable_mds_diags_init(phba, lpfc_enable_mds_diags);
        lpfc_ras_fwlog_buffsize_init(phba, lpfc_ras_fwlog_buffsize);
        lpfc_ras_fwlog_level_init(phba, lpfc_ras_fwlog_level);
index a450477..76dc8d9 100644 (file)
@@ -404,9 +404,7 @@ void lpfc_free_sysfs_attr(struct lpfc_vport *);
 extern struct device_attribute *lpfc_hba_attrs[];
 extern struct device_attribute *lpfc_vport_attrs[];
 extern struct scsi_host_template lpfc_template;
-extern struct scsi_host_template lpfc_template_no_hr;
 extern struct scsi_host_template lpfc_template_nvme;
-extern struct scsi_host_template lpfc_vport_template;
 extern struct fc_function_template lpfc_transport_functions;
 extern struct fc_function_template lpfc_vport_transport_functions;
 
@@ -590,6 +588,7 @@ struct lpfc_io_buf *lpfc_get_io_buf(struct lpfc_hba *phba,
                                int);
 void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *ncmd,
                         struct lpfc_sli4_hdw_queue *qp);
+void lpfc_io_ktime(struct lpfc_hba *phba, struct lpfc_io_buf *ncmd);
 void lpfc_nvme_cmd_template(void);
 void lpfc_nvmet_cmd_template(void);
 void lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn);
index 819335b..8a6e02a 100644 (file)
@@ -1300,8 +1300,88 @@ buffer_done:
        return len;
 }
 
+void
+lpfc_io_ktime(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
+{
+       uint64_t seg1, seg2, seg3, seg4;
+       uint64_t segsum;
+
+       if (!lpfc_cmd->ts_last_cmd ||
+           !lpfc_cmd->ts_cmd_start ||
+           !lpfc_cmd->ts_cmd_wqput ||
+           !lpfc_cmd->ts_isr_cmpl ||
+           !lpfc_cmd->ts_data_io)
+               return;
+
+       if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_cmd_start)
+               return;
+       if (lpfc_cmd->ts_cmd_start < lpfc_cmd->ts_last_cmd)
+               return;
+       if (lpfc_cmd->ts_cmd_wqput < lpfc_cmd->ts_cmd_start)
+               return;
+       if (lpfc_cmd->ts_isr_cmpl < lpfc_cmd->ts_cmd_wqput)
+               return;
+       if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_isr_cmpl)
+               return;
+       /*
+        * Segment 1 - Time from Last FCP command cmpl is handed
+        * off to NVME Layer to start of next command.
+        * Segment 2 - Time from Driver receives a IO cmd start
+        * from NVME Layer to WQ put is done on IO cmd.
+        * Segment 3 - Time from Driver WQ put is done on IO cmd
+        * to MSI-X ISR for IO cmpl.
+        * Segment 4 - Time from MSI-X ISR for IO cmpl to when
+        * cmpl is handled off to the NVME Layer.
+        */
+       seg1 = lpfc_cmd->ts_cmd_start - lpfc_cmd->ts_last_cmd;
+       if (seg1 > 5000000)  /* 5 ms - for sequential IOs only */
+               seg1 = 0;
+
+       /* Calculate times relative to start of IO */
+       seg2 = (lpfc_cmd->ts_cmd_wqput - lpfc_cmd->ts_cmd_start);
+       segsum = seg2;
+       seg3 = lpfc_cmd->ts_isr_cmpl - lpfc_cmd->ts_cmd_start;
+       if (segsum > seg3)
+               return;
+       seg3 -= segsum;
+       segsum += seg3;
+
+       seg4 = lpfc_cmd->ts_data_io - lpfc_cmd->ts_cmd_start;
+       if (segsum > seg4)
+               return;
+       seg4 -= segsum;
+
+       phba->ktime_data_samples++;
+       phba->ktime_seg1_total += seg1;
+       if (seg1 < phba->ktime_seg1_min)
+               phba->ktime_seg1_min = seg1;
+       else if (seg1 > phba->ktime_seg1_max)
+               phba->ktime_seg1_max = seg1;
+       phba->ktime_seg2_total += seg2;
+       if (seg2 < phba->ktime_seg2_min)
+               phba->ktime_seg2_min = seg2;
+       else if (seg2 > phba->ktime_seg2_max)
+               phba->ktime_seg2_max = seg2;
+       phba->ktime_seg3_total += seg3;
+       if (seg3 < phba->ktime_seg3_min)
+               phba->ktime_seg3_min = seg3;
+       else if (seg3 > phba->ktime_seg3_max)
+               phba->ktime_seg3_max = seg3;
+       phba->ktime_seg4_total += seg4;
+       if (seg4 < phba->ktime_seg4_min)
+               phba->ktime_seg4_min = seg4;
+       else if (seg4 > phba->ktime_seg4_max)
+               phba->ktime_seg4_max = seg4;
+
+       lpfc_cmd->ts_last_cmd = 0;
+       lpfc_cmd->ts_cmd_start = 0;
+       lpfc_cmd->ts_cmd_wqput  = 0;
+       lpfc_cmd->ts_isr_cmpl = 0;
+       lpfc_cmd->ts_data_io = 0;
+}
+
 /**
- * lpfc_debugfs_nvmektime_data - Dump target node list to a buffer
+ * lpfc_debugfs_ioktime_data - Dump target node list to a buffer
  * @vport: The vport to gather target node info from.
  * @buf: The buffer to dump log into.
  * @size: The maximum amount of data to process.
@@ -1314,13 +1394,13 @@ buffer_done:
  * not exceed @size.
  **/
 static int
-lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size)
+lpfc_debugfs_ioktime_data(struct lpfc_vport *vport, char *buf, int size)
 {
        struct lpfc_hba   *phba = vport->phba;
        int len = 0;
 
        if (phba->nvmet_support == 0) {
-               /* NVME Initiator */
+               /* Initiator */
                len += scnprintf(buf + len, PAGE_SIZE - len,
                                "ktime %s: Total Samples: %lld\n",
                                (phba->ktime_on ?  "Enabled" : "Disabled"),
@@ -1330,8 +1410,8 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size)
 
                len += scnprintf(
                        buf + len, PAGE_SIZE - len,
-                       "Segment 1: Last NVME Cmd cmpl "
-                       "done -to- Start of next NVME cnd (in driver)\n");
+                       "Segment 1: Last Cmd cmpl "
+                       "done -to- Start of next Cmd (in driver)\n");
                len += scnprintf(
                        buf + len, PAGE_SIZE - len,
                        "avg:%08lld min:%08lld max %08lld\n",
@@ -1341,7 +1421,7 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size)
                        phba->ktime_seg1_max);
                len += scnprintf(
                        buf + len, PAGE_SIZE - len,
-                       "Segment 2: Driver start of NVME cmd "
+                       "Segment 2: Driver start of Cmd "
                        "-to- Firmware WQ doorbell\n");
                len += scnprintf(
                        buf + len, PAGE_SIZE - len,
@@ -1364,7 +1444,7 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size)
                len += scnprintf(
                        buf + len, PAGE_SIZE - len,
                        "Segment 4: MSI-X ISR cmpl -to- "
-                       "NVME cmpl done\n");
+                       "Cmd cmpl done\n");
                len += scnprintf(
                        buf + len, PAGE_SIZE - len,
                        "avg:%08lld min:%08lld max %08lld\n",
@@ -1603,42 +1683,50 @@ out:
 }
 
 /**
- * lpfc_debugfs_cpucheck_data - Dump target node list to a buffer
+ * lpfc_debugfs_hdwqstat_data - Dump I/O stats to a buffer
  * @vport: The vport to gather target node info from.
  * @buf: The buffer to dump log into.
  * @size: The maximum amount of data to process.
  *
  * Description:
- * This routine dumps the NVME statistics associated with @vport
+ * This routine dumps the NVME + SCSI statistics associated with @vport
  *
  * Return Value:
  * This routine returns the amount of bytes that were dumped into @buf and will
  * not exceed @size.
  **/
 static int
-lpfc_debugfs_cpucheck_data(struct lpfc_vport *vport, char *buf, int size)
+lpfc_debugfs_hdwqstat_data(struct lpfc_vport *vport, char *buf, int size)
 {
        struct lpfc_hba   *phba = vport->phba;
        struct lpfc_sli4_hdw_queue *qp;
-       int i, j, max_cnt;
-       int len = 0;
+       struct lpfc_hdwq_stat *c_stat;
+       int i, j, len;
        uint32_t tot_xmt;
        uint32_t tot_rcv;
        uint32_t tot_cmpl;
+       char tmp[LPFC_MAX_SCSI_INFO_TMP_LEN] = {0};
 
-       len += scnprintf(buf + len, PAGE_SIZE - len,
-                       "CPUcheck %s ",
-                       (phba->cpucheck_on & LPFC_CHECK_NVME_IO ?
-                               "Enabled" : "Disabled"));
-       if (phba->nvmet_support) {
-               len += scnprintf(buf + len, PAGE_SIZE - len,
-                               "%s\n",
-                               (phba->cpucheck_on & LPFC_CHECK_NVMET_RCV ?
-                                       "Rcv Enabled\n" : "Rcv Disabled\n"));
-       } else {
-               len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
-       }
-       max_cnt = size - LPFC_DEBUG_OUT_LINE_SZ;
+       scnprintf(tmp, sizeof(tmp), "HDWQ Stats:\n\n");
+       if (strlcat(buf, tmp, size) >= size)
+               goto buffer_done;
+
+       scnprintf(tmp, sizeof(tmp), "(NVME Accounting: %s) ",
+                 (phba->hdwqstat_on &
+                 (LPFC_CHECK_NVME_IO | LPFC_CHECK_NVMET_IO) ?
+                 "Enabled" : "Disabled"));
+       if (strlcat(buf, tmp, size) >= size)
+               goto buffer_done;
+
+       scnprintf(tmp, sizeof(tmp), "(SCSI Accounting: %s) ",
+                 (phba->hdwqstat_on & LPFC_CHECK_SCSI_IO ?
+                 "Enabled" : "Disabled"));
+       if (strlcat(buf, tmp, size) >= size)
+               goto buffer_done;
+
+       scnprintf(tmp, sizeof(tmp), "\n\n");
+       if (strlcat(buf, tmp, size) >= size)
+               goto buffer_done;
 
        for (i = 0; i < phba->cfg_hdw_queue; i++) {
                qp = &phba->sli4_hba.hdwq[i];
@@ -1646,46 +1734,76 @@ lpfc_debugfs_cpucheck_data(struct lpfc_vport *vport, char *buf, int size)
                tot_rcv = 0;
                tot_xmt = 0;
                tot_cmpl = 0;
-               for (j = 0; j < LPFC_CHECK_CPU_CNT; j++) {
-                       tot_xmt += qp->cpucheck_xmt_io[j];
-                       tot_cmpl += qp->cpucheck_cmpl_io[j];
-                       if (phba->nvmet_support)
-                               tot_rcv += qp->cpucheck_rcv_io[j];
-               }
 
-               /* Only display Hardware Qs with something */
-               if (!tot_xmt && !tot_cmpl && !tot_rcv)
-                       continue;
+               for_each_present_cpu(j) {
+                       c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, j);
+
+                       /* Only display for this HDWQ */
+                       if (i != c_stat->hdwq_no)
+                               continue;
 
-               len += scnprintf(buf + len, PAGE_SIZE - len,
-                               "HDWQ %03d: ", i);
-               for (j = 0; j < LPFC_CHECK_CPU_CNT; j++) {
                        /* Only display non-zero counters */
-                       if (!qp->cpucheck_xmt_io[j] &&
-                           !qp->cpucheck_cmpl_io[j] &&
-                           !qp->cpucheck_rcv_io[j])
+                       if (!c_stat->xmt_io && !c_stat->cmpl_io &&
+                           !c_stat->rcv_io)
                                continue;
+
+                       if (!tot_xmt && !tot_cmpl && !tot_rcv) {
+                               /* Print HDWQ string only the first time */
+                               scnprintf(tmp, sizeof(tmp), "[HDWQ %d]:\t", i);
+                               if (strlcat(buf, tmp, size) >= size)
+                                       goto buffer_done;
+                       }
+
+                       tot_xmt += c_stat->xmt_io;
+                       tot_cmpl += c_stat->cmpl_io;
+                       if (phba->nvmet_support)
+                               tot_rcv += c_stat->rcv_io;
+
+                       scnprintf(tmp, sizeof(tmp), "| [CPU %d]: ", j);
+                       if (strlcat(buf, tmp, size) >= size)
+                               goto buffer_done;
+
                        if (phba->nvmet_support) {
-                               len += scnprintf(buf + len, PAGE_SIZE - len,
-                                               "CPU %03d: %x/%x/%x ", j,
-                                               qp->cpucheck_rcv_io[j],
-                                               qp->cpucheck_xmt_io[j],
-                                               qp->cpucheck_cmpl_io[j]);
+                               scnprintf(tmp, sizeof(tmp),
+                                         "XMT 0x%x CMPL 0x%x RCV 0x%x |",
+                                         c_stat->xmt_io, c_stat->cmpl_io,
+                                         c_stat->rcv_io);
+                               if (strlcat(buf, tmp, size) >= size)
+                                       goto buffer_done;
                        } else {
-                               len += scnprintf(buf + len, PAGE_SIZE - len,
-                                               "CPU %03d: %x/%x ", j,
-                                               qp->cpucheck_xmt_io[j],
-                                               qp->cpucheck_cmpl_io[j]);
+                               scnprintf(tmp, sizeof(tmp),
+                                         "XMT 0x%x CMPL 0x%x |",
+                                         c_stat->xmt_io, c_stat->cmpl_io);
+                               if (strlcat(buf, tmp, size) >= size)
+                                       goto buffer_done;
                        }
                }
-               len += scnprintf(buf + len, PAGE_SIZE - len,
-                               "Total: %x\n", tot_xmt);
-               if (len >= max_cnt) {
-                       len += scnprintf(buf + len, PAGE_SIZE - len,
-                                       "Truncated ...\n");
-                       return len;
+
+               /* Check if nothing to display */
+               if (!tot_xmt && !tot_cmpl && !tot_rcv)
+                       continue;
+
+               scnprintf(tmp, sizeof(tmp), "\t->\t[HDWQ Total: ");
+               if (strlcat(buf, tmp, size) >= size)
+                       goto buffer_done;
+
+               if (phba->nvmet_support) {
+                       scnprintf(tmp, sizeof(tmp),
+                                 "XMT 0x%x CMPL 0x%x RCV 0x%x]\n\n",
+                                 tot_xmt, tot_cmpl, tot_rcv);
+                       if (strlcat(buf, tmp, size) >= size)
+                               goto buffer_done;
+               } else {
+                       scnprintf(tmp, sizeof(tmp),
+                                 "XMT 0x%x CMPL 0x%x]\n\n",
+                                 tot_xmt, tot_cmpl);
+                       if (strlcat(buf, tmp, size) >= size)
+                               goto buffer_done;
                }
        }
+
+buffer_done:
+       len = strnlen(buf, size);
        return len;
 }
 
@@ -2689,7 +2807,7 @@ lpfc_debugfs_scsistat_write(struct file *file, const char __user *buf,
 }
 
 static int
-lpfc_debugfs_nvmektime_open(struct inode *inode, struct file *file)
+lpfc_debugfs_ioktime_open(struct inode *inode, struct file *file)
 {
        struct lpfc_vport *vport = inode->i_private;
        struct lpfc_debug *debug;
@@ -2700,14 +2818,14 @@ lpfc_debugfs_nvmektime_open(struct inode *inode, struct file *file)
                goto out;
 
         /* Round to page boundary */
-       debug->buffer = kmalloc(LPFC_NVMEKTIME_SIZE, GFP_KERNEL);
+       debug->buffer = kmalloc(LPFC_IOKTIME_SIZE, GFP_KERNEL);
        if (!debug->buffer) {
                kfree(debug);
                goto out;
        }
 
-       debug->len = lpfc_debugfs_nvmektime_data(vport, debug->buffer,
-               LPFC_NVMEKTIME_SIZE);
+       debug->len = lpfc_debugfs_ioktime_data(vport, debug->buffer,
+               LPFC_IOKTIME_SIZE);
 
        debug->i_private = inode->i_private;
        file->private_data = debug;
@@ -2718,8 +2836,8 @@ out:
 }
 
 static ssize_t
-lpfc_debugfs_nvmektime_write(struct file *file, const char __user *buf,
-                            size_t nbytes, loff_t *ppos)
+lpfc_debugfs_ioktime_write(struct file *file, const char __user *buf,
+                          size_t nbytes, loff_t *ppos)
 {
        struct lpfc_debug *debug = file->private_data;
        struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
@@ -2921,7 +3039,7 @@ lpfc_debugfs_nvmeio_trc_write(struct file *file, const char __user *buf,
 }
 
 static int
-lpfc_debugfs_cpucheck_open(struct inode *inode, struct file *file)
+lpfc_debugfs_hdwqstat_open(struct inode *inode, struct file *file)
 {
        struct lpfc_vport *vport = inode->i_private;
        struct lpfc_debug *debug;
@@ -2932,14 +3050,14 @@ lpfc_debugfs_cpucheck_open(struct inode *inode, struct file *file)
                goto out;
 
         /* Round to page boundary */
-       debug->buffer = kmalloc(LPFC_CPUCHECK_SIZE, GFP_KERNEL);
+       debug->buffer = kcalloc(1, LPFC_SCSISTAT_SIZE, GFP_KERNEL);
        if (!debug->buffer) {
                kfree(debug);
                goto out;
        }
 
-       debug->len = lpfc_debugfs_cpucheck_data(vport, debug->buffer,
-               LPFC_CPUCHECK_SIZE);
+       debug->len = lpfc_debugfs_hdwqstat_data(vport, debug->buffer,
+                                               LPFC_SCSISTAT_SIZE);
 
        debug->i_private = inode->i_private;
        file->private_data = debug;
@@ -2950,16 +3068,16 @@ out:
 }
 
 static ssize_t
-lpfc_debugfs_cpucheck_write(struct file *file, const char __user *buf,
+lpfc_debugfs_hdwqstat_write(struct file *file, const char __user *buf,
                            size_t nbytes, loff_t *ppos)
 {
        struct lpfc_debug *debug = file->private_data;
        struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
        struct lpfc_hba   *phba = vport->phba;
-       struct lpfc_sli4_hdw_queue *qp;
+       struct lpfc_hdwq_stat *c_stat;
        char mybuf[64];
        char *pbuf;
-       int i, j;
+       int i;
 
        if (nbytes > 64)
                nbytes = 64;
@@ -2972,41 +3090,39 @@ lpfc_debugfs_cpucheck_write(struct file *file, const char __user *buf,
 
        if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) {
                if (phba->nvmet_support)
-                       phba->cpucheck_on |= LPFC_CHECK_NVMET_IO;
+                       phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO;
                else
-                       phba->cpucheck_on |= (LPFC_CHECK_NVME_IO |
+                       phba->hdwqstat_on |= (LPFC_CHECK_NVME_IO |
                                LPFC_CHECK_SCSI_IO);
                return strlen(pbuf);
        } else if ((strncmp(pbuf, "nvme_on", sizeof("nvme_on") - 1) == 0)) {
                if (phba->nvmet_support)
-                       phba->cpucheck_on |= LPFC_CHECK_NVMET_IO;
+                       phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO;
                else
-                       phba->cpucheck_on |= LPFC_CHECK_NVME_IO;
+                       phba->hdwqstat_on |= LPFC_CHECK_NVME_IO;
                return strlen(pbuf);
        } else if ((strncmp(pbuf, "scsi_on", sizeof("scsi_on") - 1) == 0)) {
-               phba->cpucheck_on |= LPFC_CHECK_SCSI_IO;
+               if (!phba->nvmet_support)
+                       phba->hdwqstat_on |= LPFC_CHECK_SCSI_IO;
                return strlen(pbuf);
-       } else if ((strncmp(pbuf, "rcv",
-                  sizeof("rcv") - 1) == 0)) {
-               if (phba->nvmet_support)
-                       phba->cpucheck_on |= LPFC_CHECK_NVMET_RCV;
-               else
-                       return -EINVAL;
+       } else if ((strncmp(pbuf, "nvme_off", sizeof("nvme_off") - 1) == 0)) {
+               phba->hdwqstat_on &= ~(LPFC_CHECK_NVME_IO |
+                                      LPFC_CHECK_NVMET_IO);
+               return strlen(pbuf);
+       } else if ((strncmp(pbuf, "scsi_off", sizeof("scsi_off") - 1) == 0)) {
+               phba->hdwqstat_on &= ~LPFC_CHECK_SCSI_IO;
                return strlen(pbuf);
        } else if ((strncmp(pbuf, "off",
                   sizeof("off") - 1) == 0)) {
-               phba->cpucheck_on = LPFC_CHECK_OFF;
+               phba->hdwqstat_on = LPFC_CHECK_OFF;
                return strlen(pbuf);
        } else if ((strncmp(pbuf, "zero",
                   sizeof("zero") - 1) == 0)) {
-               for (i = 0; i < phba->cfg_hdw_queue; i++) {
-                       qp = &phba->sli4_hba.hdwq[i];
-
-                       for (j = 0; j < LPFC_CHECK_CPU_CNT; j++) {
-                               qp->cpucheck_rcv_io[j] = 0;
-                               qp->cpucheck_xmt_io[j] = 0;
-                               qp->cpucheck_cmpl_io[j] = 0;
-                       }
+               for_each_present_cpu(i) {
+                       c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, i);
+                       c_stat->xmt_io = 0;
+                       c_stat->cmpl_io = 0;
+                       c_stat->rcv_io = 0;
                }
                return strlen(pbuf);
        }
@@ -5431,13 +5547,13 @@ static const struct file_operations lpfc_debugfs_op_scsistat = {
        .release =      lpfc_debugfs_release,
 };
 
-#undef lpfc_debugfs_op_nvmektime
-static const struct file_operations lpfc_debugfs_op_nvmektime = {
+#undef lpfc_debugfs_op_ioktime
+static const struct file_operations lpfc_debugfs_op_ioktime = {
        .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_nvmektime_open,
+       .open =         lpfc_debugfs_ioktime_open,
        .llseek =       lpfc_debugfs_lseek,
        .read =         lpfc_debugfs_read,
-       .write =        lpfc_debugfs_nvmektime_write,
+       .write =        lpfc_debugfs_ioktime_write,
        .release =      lpfc_debugfs_release,
 };
 
@@ -5451,13 +5567,13 @@ static const struct file_operations lpfc_debugfs_op_nvmeio_trc = {
        .release =      lpfc_debugfs_release,
 };
 
-#undef lpfc_debugfs_op_cpucheck
-static const struct file_operations lpfc_debugfs_op_cpucheck = {
+#undef lpfc_debugfs_op_hdwqstat
+static const struct file_operations lpfc_debugfs_op_hdwqstat = {
        .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_cpucheck_open,
+       .open =         lpfc_debugfs_hdwqstat_open,
        .llseek =       lpfc_debugfs_lseek,
        .read =         lpfc_debugfs_read,
-       .write =        lpfc_debugfs_cpucheck_write,
+       .write =        lpfc_debugfs_hdwqstat_write,
        .release =      lpfc_debugfs_release,
 };
 
@@ -6075,17 +6191,22 @@ nvmeio_off:
                goto debug_failed;
        }
 
-       snprintf(name, sizeof(name), "nvmektime");
-       vport->debug_nvmektime =
+       snprintf(name, sizeof(name), "ioktime");
+       vport->debug_ioktime =
                debugfs_create_file(name, 0644,
                                    vport->vport_debugfs_root,
-                                   vport, &lpfc_debugfs_op_nvmektime);
+                                   vport, &lpfc_debugfs_op_ioktime);
+       if (!vport->debug_ioktime) {
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                                "0815 Cannot create debugfs ioktime\n");
+               goto debug_failed;
+       }
 
-       snprintf(name, sizeof(name), "cpucheck");
-       vport->debug_cpucheck =
+       snprintf(name, sizeof(name), "hdwqstat");
+       vport->debug_hdwqstat =
                debugfs_create_file(name, 0644,
                                    vport->vport_debugfs_root,
-                                   vport, &lpfc_debugfs_op_cpucheck);
+                                   vport, &lpfc_debugfs_op_hdwqstat);
 
        /*
         * The following section is for additional directories/files for the
@@ -6216,11 +6337,11 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
        debugfs_remove(vport->debug_scsistat); /* scsistat */
        vport->debug_scsistat = NULL;
 
-       debugfs_remove(vport->debug_nvmektime); /* nvmektime */
-       vport->debug_nvmektime = NULL;
+       debugfs_remove(vport->debug_ioktime); /* ioktime */
+       vport->debug_ioktime = NULL;
 
-       debugfs_remove(vport->debug_cpucheck); /* cpucheck */
-       vport->debug_cpucheck = NULL;
+       debugfs_remove(vport->debug_hdwqstat); /* hdwqstat */
+       vport->debug_hdwqstat = NULL;
 
        if (vport->vport_debugfs_root) {
                debugfs_remove(vport->vport_debugfs_root); /* vportX */
index 20f2537..7ab6d3b 100644 (file)
@@ -46,8 +46,7 @@
 
 /* nvmestat output buffer size */
 #define LPFC_NVMESTAT_SIZE 8192
-#define LPFC_NVMEKTIME_SIZE 8192
-#define LPFC_CPUCHECK_SIZE 8192
+#define LPFC_IOKTIME_SIZE 8192
 #define LPFC_NVMEIO_TRC_SIZE 8192
 
 /* scsistat output buffer size */
index ae51c0d..c20034b 100644 (file)
@@ -3262,8 +3262,7 @@ typedef struct {
 #endif
 
 #ifdef __BIG_ENDIAN_BITFIELD
-       uint32_t rsvd1     : 19;  /* Reserved                             */
-       uint32_t cdss      :  1;  /* Configure Data Security SLI          */
+       uint32_t rsvd1     : 20;  /* Reserved                             */
        uint32_t casabt    :  1;  /* Configure async abts status notice   */
        uint32_t rsvd2     :  2;  /* Reserved                             */
        uint32_t cbg       :  1;  /* Configure BlockGuard                 */
@@ -3287,12 +3286,10 @@ typedef struct {
        uint32_t cbg       :  1;  /* Configure BlockGuard                 */
        uint32_t rsvd2     :  2;  /* Reserved                             */
        uint32_t casabt    :  1;  /* Configure async abts status notice   */
-       uint32_t cdss      :  1;  /* Configure Data Security SLI          */
-       uint32_t rsvd1     : 19;  /* Reserved                             */
+       uint32_t rsvd1     : 20;  /* Reserved                             */
 #endif
 #ifdef __BIG_ENDIAN_BITFIELD
-       uint32_t rsvd3     : 19;  /* Reserved                             */
-       uint32_t gdss      :  1;  /* Configure Data Security SLI          */
+       uint32_t rsvd3     : 20;  /* Reserved                             */
        uint32_t gasabt    :  1;  /* Grant async abts status notice       */
        uint32_t rsvd4     :  2;  /* Reserved                             */
        uint32_t gbg       :  1;  /* Grant BlockGuard                     */
@@ -3316,8 +3313,7 @@ typedef struct {
        uint32_t gbg       :  1;  /* Grant BlockGuard                     */
        uint32_t rsvd4     :  2;  /* Reserved                             */
        uint32_t gasabt    :  1;  /* Grant async abts status notice       */
-       uint32_t gdss      :  1;  /* Configure Data Security SLI          */
-       uint32_t rsvd3     : 19;  /* Reserved                             */
+       uint32_t rsvd3     : 20;  /* Reserved                             */
 #endif
 
 #ifdef __BIG_ENDIAN_BITFIELD
@@ -3339,15 +3335,11 @@ typedef struct {
        uint32_t rsvd6;           /* Reserved                             */
 
 #ifdef __BIG_ENDIAN_BITFIELD
-       uint32_t fips_rev   : 3;   /* FIPS Spec Revision                   */
-       uint32_t fips_level : 4;   /* FIPS Level                           */
-       uint32_t sec_err    : 9;   /* security crypto error                */
+       uint32_t rsvd7      : 16;
        uint32_t max_vpi    : 16;  /* Max number of virt N-Ports           */
 #else  /*  __LITTLE_ENDIAN */
        uint32_t max_vpi    : 16;  /* Max number of virt N-Ports           */
-       uint32_t sec_err    : 9;   /* security crypto error                */
-       uint32_t fips_level : 4;   /* FIPS Level                           */
-       uint32_t fips_rev   : 3;   /* FIPS Spec Revision                   */
+       uint32_t rsvd7      : 16;
 #endif
 
 } CONFIG_PORT_VAR;
index 9d03e9b..4104bdc 100644 (file)
@@ -4231,6 +4231,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
 {
        struct lpfc_vport *vport;
        struct Scsi_Host  *shost = NULL;
+       struct scsi_host_template *template;
        int error = 0;
        int i;
        uint64_t wwn;
@@ -4259,22 +4260,50 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
                }
        }
 
-       if (phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) {
-               if (dev != &phba->pcidev->dev) {
-                       shost = scsi_host_alloc(&lpfc_vport_template,
-                                               sizeof(struct lpfc_vport));
+       /* Seed template for SCSI host registration */
+       if (dev == &phba->pcidev->dev) {
+               template = &phba->port_template;
+
+               if (phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) {
+                       /* Seed physical port template */
+                       memcpy(template, &lpfc_template, sizeof(*template));
+
+                       if (use_no_reset_hba) {
+                               /* template is for a no reset SCSI Host */
+                               template->max_sectors = 0xffff;
+                               template->eh_host_reset_handler = NULL;
+                       }
+
+                       /* Template for all vports this physical port creates */
+                       memcpy(&phba->vport_template, &lpfc_template,
+                              sizeof(*template));
+                       phba->vport_template.max_sectors = 0xffff;
+                       phba->vport_template.shost_attrs = lpfc_vport_attrs;
+                       phba->vport_template.eh_bus_reset_handler = NULL;
+                       phba->vport_template.eh_host_reset_handler = NULL;
+                       phba->vport_template.vendor_id = 0;
+
+                       /* Initialize the host templates with updated value */
+                       if (phba->sli_rev == LPFC_SLI_REV4) {
+                               template->sg_tablesize = phba->cfg_scsi_seg_cnt;
+                               phba->vport_template.sg_tablesize =
+                                       phba->cfg_scsi_seg_cnt;
+                       } else {
+                               template->sg_tablesize = phba->cfg_sg_seg_cnt;
+                               phba->vport_template.sg_tablesize =
+                                       phba->cfg_sg_seg_cnt;
+                       }
+
                } else {
-                       if (!use_no_reset_hba)
-                               shost = scsi_host_alloc(&lpfc_template,
-                                               sizeof(struct lpfc_vport));
-                       else
-                               shost = scsi_host_alloc(&lpfc_template_no_hr,
-                                               sizeof(struct lpfc_vport));
+                       /* NVMET is for physical port only */
+                       memcpy(template, &lpfc_template_nvme,
+                              sizeof(*template));
                }
-       } else if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
-               shost = scsi_host_alloc(&lpfc_template_nvme,
-                                       sizeof(struct lpfc_vport));
+       } else {
+               template = &phba->vport_template;
        }
+
+       shost = scsi_host_alloc(template, sizeof(struct lpfc_vport));
        if (!shost)
                goto out;
 
@@ -4329,6 +4358,12 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
                vport->port_type = LPFC_PHYSICAL_PORT;
        }
 
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP,
+                       "9081 CreatePort TMPLATE type %x TBLsize %d "
+                       "SEGcnt %d/%d\n",
+                       vport->port_type, shost->sg_tablesize,
+                       phba->cfg_scsi_seg_cnt, phba->cfg_sg_seg_cnt);
+
        /* Initialize all internally managed lists. */
        INIT_LIST_HEAD(&vport->fc_nodes);
        INIT_LIST_HEAD(&vport->rcv_buffer_list);
@@ -6301,11 +6336,6 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
         * used to create the sg_dma_buf_pool must be dynamically calculated.
         */
 
-       /* Initialize the host templates the configured values. */
-       lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt;
-       lpfc_template_no_hr.sg_tablesize = phba->cfg_sg_seg_cnt;
-       lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt;
-
        if (phba->sli_rev == LPFC_SLI_REV4)
                entry_sz = sizeof(struct sli4_sge);
        else
@@ -6346,7 +6376,7 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
        }
 
        lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP,
-                       "9088 sg_tablesize:%d dmabuf_size:%d total_bde:%d\n",
+                       "9088 INIT sg_tablesize:%d dmabuf_size:%d total_bde:%d\n",
                        phba->cfg_sg_seg_cnt, phba->cfg_sg_dma_buf_size,
                        phba->cfg_total_seg_cnt);
 
@@ -6816,11 +6846,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                        phba->cfg_nvme_seg_cnt = phba->cfg_sg_seg_cnt;
        }
 
-       /* Initialize the host templates with the updated values. */
-       lpfc_vport_template.sg_tablesize = phba->cfg_scsi_seg_cnt;
-       lpfc_template.sg_tablesize = phba->cfg_scsi_seg_cnt;
-       lpfc_template_no_hr.sg_tablesize = phba->cfg_scsi_seg_cnt;
-
        lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP,
                        "9087 sg_seg_cnt:%d dmabuf_size:%d "
                        "total:%d scsi:%d nvme:%d\n",
@@ -6926,6 +6951,17 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                rc = -ENOMEM;
                goto out_free_hba_cpu_map;
        }
+
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       phba->sli4_hba.c_stat = alloc_percpu(struct lpfc_hdwq_stat);
+       if (!phba->sli4_hba.c_stat) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3332 Failed allocating per cpu hdwq stats\n");
+               rc = -ENOMEM;
+               goto out_free_hba_eq_info;
+       }
+#endif
+
        /*
         * Enable sr-iov virtual functions if supported and configured
         * through the module parameter.
@@ -6945,6 +6981,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
 
        return 0;
 
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+out_free_hba_eq_info:
+       free_percpu(phba->sli4_hba.eq_info);
+#endif
 out_free_hba_cpu_map:
        kfree(phba->sli4_hba.cpu_map);
 out_free_hba_eq_hdl:
@@ -6983,6 +7023,9 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
        struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry;
 
        free_percpu(phba->sli4_hba.eq_info);
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       free_percpu(phba->sli4_hba.c_stat);
+#endif
 
        /* Free memory allocated for msi-x interrupt vector to CPU mapping */
        kfree(phba->sli4_hba.cpu_map);
@@ -10823,6 +10866,9 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
 #ifdef CONFIG_X86
        struct cpuinfo_x86 *cpuinfo;
 #endif
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       struct lpfc_hdwq_stat *c_stat;
+#endif
 
        max_phys_id = 0;
        min_phys_id = LPFC_VECTOR_MAP_EMPTY;
@@ -11074,10 +11120,17 @@ found_any:
        idx = 0;
        for_each_possible_cpu(cpu) {
                cpup = &phba->sli4_hba.cpu_map[cpu];
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+               c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, cpu);
+               c_stat->hdwq_no = cpup->hdwq;
+#endif
                if (cpup->hdwq != LPFC_VECTOR_MAP_EMPTY)
                        continue;
 
                cpup->hdwq = idx++ % phba->cfg_hdw_queue;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+               c_stat->hdwq_no = cpup->hdwq;
+#endif
                lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
                                "3340 Set Affinity: not present "
                                "CPU %d hdwq %d\n",
@@ -11173,11 +11226,9 @@ static void lpfc_cpuhp_add(struct lpfc_hba *phba)
 
        rcu_read_lock();
 
-       if (!list_empty(&phba->poll_list)) {
-               timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0);
+       if (!list_empty(&phba->poll_list))
                mod_timer(&phba->cpuhp_poll_timer,
                          jiffies + msecs_to_jiffies(LPFC_POLL_HB));
-       }
 
        rcu_read_unlock();
 
@@ -13145,6 +13196,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
        lpfc_sli4_ras_setup(phba);
 
        INIT_LIST_HEAD(&phba->poll_list);
+       timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0);
        cpuhp_state_add_instance_nocalls(lpfc_cpuhp_state, &phba->cpuhp);
 
        return 0;
index d1773c0..e35b52b 100644 (file)
@@ -1299,8 +1299,6 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        if (phba->sli_rev == LPFC_SLI_REV3 && phba->vpd.sli3Feat.cerbm) {
                if (phba->cfg_enable_bg)
                        mb->un.varCfgPort.cbg = 1; /* configure BlockGuard */
-               if (phba->cfg_enable_dss)
-                       mb->un.varCfgPort.cdss = 1; /* Configure Security */
                mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
                mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */
                mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count();
index f6c8963..a45936e 100644 (file)
@@ -382,13 +382,15 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport)
        if (ndlp->upcall_flags & NLP_WAIT_FOR_UNREG) {
                ndlp->nrport = NULL;
                ndlp->upcall_flags &= ~NLP_WAIT_FOR_UNREG;
-       }
-       spin_unlock_irq(&vport->phba->hbalock);
+               spin_unlock_irq(&vport->phba->hbalock);
 
-       /* Remove original register reference. The host transport
-        * won't reference this rport/remoteport any further.
-        */
-       lpfc_nlp_put(ndlp);
+               /* Remove original register reference. The host transport
+                * won't reference this rport/remoteport any further.
+                */
+               lpfc_nlp_put(ndlp);
+       } else {
+               spin_unlock_irq(&vport->phba->hbalock);
+       }
 
  rport_err:
        return;
@@ -897,88 +899,6 @@ lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport,
        sgl->sge_len = cpu_to_le32(nCmd->rsplen);
 }
 
-#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-static void
-lpfc_nvme_ktime(struct lpfc_hba *phba,
-               struct lpfc_io_buf *lpfc_ncmd)
-{
-       uint64_t seg1, seg2, seg3, seg4;
-       uint64_t segsum;
-
-       if (!lpfc_ncmd->ts_last_cmd ||
-           !lpfc_ncmd->ts_cmd_start ||
-           !lpfc_ncmd->ts_cmd_wqput ||
-           !lpfc_ncmd->ts_isr_cmpl ||
-           !lpfc_ncmd->ts_data_nvme)
-               return;
-
-       if (lpfc_ncmd->ts_data_nvme < lpfc_ncmd->ts_cmd_start)
-               return;
-       if (lpfc_ncmd->ts_cmd_start < lpfc_ncmd->ts_last_cmd)
-               return;
-       if (lpfc_ncmd->ts_cmd_wqput < lpfc_ncmd->ts_cmd_start)
-               return;
-       if (lpfc_ncmd->ts_isr_cmpl < lpfc_ncmd->ts_cmd_wqput)
-               return;
-       if (lpfc_ncmd->ts_data_nvme < lpfc_ncmd->ts_isr_cmpl)
-               return;
-       /*
-        * Segment 1 - Time from Last FCP command cmpl is handed
-        * off to NVME Layer to start of next command.
-        * Segment 2 - Time from Driver receives a IO cmd start
-        * from NVME Layer to WQ put is done on IO cmd.
-        * Segment 3 - Time from Driver WQ put is done on IO cmd
-        * to MSI-X ISR for IO cmpl.
-        * Segment 4 - Time from MSI-X ISR for IO cmpl to when
-        * cmpl is handled off to the NVME Layer.
-        */
-       seg1 = lpfc_ncmd->ts_cmd_start - lpfc_ncmd->ts_last_cmd;
-       if (seg1 > 5000000)  /* 5 ms - for sequential IOs only */
-               seg1 = 0;
-
-       /* Calculate times relative to start of IO */
-       seg2 = (lpfc_ncmd->ts_cmd_wqput - lpfc_ncmd->ts_cmd_start);
-       segsum = seg2;
-       seg3 = lpfc_ncmd->ts_isr_cmpl - lpfc_ncmd->ts_cmd_start;
-       if (segsum > seg3)
-               return;
-       seg3 -= segsum;
-       segsum += seg3;
-
-       seg4 = lpfc_ncmd->ts_data_nvme - lpfc_ncmd->ts_cmd_start;
-       if (segsum > seg4)
-               return;
-       seg4 -= segsum;
-
-       phba->ktime_data_samples++;
-       phba->ktime_seg1_total += seg1;
-       if (seg1 < phba->ktime_seg1_min)
-               phba->ktime_seg1_min = seg1;
-       else if (seg1 > phba->ktime_seg1_max)
-               phba->ktime_seg1_max = seg1;
-       phba->ktime_seg2_total += seg2;
-       if (seg2 < phba->ktime_seg2_min)
-               phba->ktime_seg2_min = seg2;
-       else if (seg2 > phba->ktime_seg2_max)
-               phba->ktime_seg2_max = seg2;
-       phba->ktime_seg3_total += seg3;
-       if (seg3 < phba->ktime_seg3_min)
-               phba->ktime_seg3_min = seg3;
-       else if (seg3 > phba->ktime_seg3_max)
-               phba->ktime_seg3_max = seg3;
-       phba->ktime_seg4_total += seg4;
-       if (seg4 < phba->ktime_seg4_min)
-               phba->ktime_seg4_min = seg4;
-       else if (seg4 > phba->ktime_seg4_max)
-               phba->ktime_seg4_max = seg4;
-
-       lpfc_ncmd->ts_last_cmd = 0;
-       lpfc_ncmd->ts_cmd_start = 0;
-       lpfc_ncmd->ts_cmd_wqput  = 0;
-       lpfc_ncmd->ts_isr_cmpl = 0;
-       lpfc_ncmd->ts_data_nvme = 0;
-}
-#endif
 
 /**
  * lpfc_nvme_io_cmd_wqe_cmpl - Complete an NVME-over-FCP IO
@@ -1010,6 +930,9 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
        uint32_t code, status, idx;
        uint16_t cid, sqhd, data;
        uint32_t *ptr;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       int cpu;
+#endif
 
        /* Sanity check on return of outstanding command */
        if (!lpfc_ncmd) {
@@ -1178,23 +1101,19 @@ out_err:
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
        if (lpfc_ncmd->ts_cmd_start) {
                lpfc_ncmd->ts_isr_cmpl = pwqeIn->isr_timestamp;
-               lpfc_ncmd->ts_data_nvme = ktime_get_ns();
-               phba->ktime_last_cmd = lpfc_ncmd->ts_data_nvme;
-               lpfc_nvme_ktime(phba, lpfc_ncmd);
+               lpfc_ncmd->ts_data_io = ktime_get_ns();
+               phba->ktime_last_cmd = lpfc_ncmd->ts_data_io;
+               lpfc_io_ktime(phba, lpfc_ncmd);
        }
-       if (unlikely(phba->cpucheck_on & LPFC_CHECK_NVME_IO)) {
-               uint32_t cpu;
-               idx = lpfc_ncmd->cur_iocbq.hba_wqidx;
+       if (unlikely(phba->hdwqstat_on & LPFC_CHECK_NVME_IO)) {
                cpu = raw_smp_processor_id();
-               if (cpu < LPFC_CHECK_CPU_CNT) {
-                       if (lpfc_ncmd->cpu != cpu)
-                               lpfc_printf_vlog(vport,
-                                                KERN_INFO, LOG_NVME_IOERR,
-                                                "6701 CPU Check cmpl: "
-                                                "cpu %d expect %d\n",
-                                                cpu, lpfc_ncmd->cpu);
-                       phba->sli4_hba.hdwq[idx].cpucheck_cmpl_io[cpu]++;
-               }
+               this_cpu_inc(phba->sli4_hba.c_stat->cmpl_io);
+               if (lpfc_ncmd->cpu != cpu)
+                       lpfc_printf_vlog(vport,
+                                        KERN_INFO, LOG_NVME_IOERR,
+                                        "6701 CPU Check cmpl: "
+                                        "cpu %d expect %d\n",
+                                        cpu, lpfc_ncmd->cpu);
        }
 #endif
 
@@ -1743,19 +1662,17 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport,
        if (lpfc_ncmd->ts_cmd_start)
                lpfc_ncmd->ts_cmd_wqput = ktime_get_ns();
 
-       if (phba->cpucheck_on & LPFC_CHECK_NVME_IO) {
+       if (phba->hdwqstat_on & LPFC_CHECK_NVME_IO) {
                cpu = raw_smp_processor_id();
-               if (cpu < LPFC_CHECK_CPU_CNT) {
-                       lpfc_ncmd->cpu = cpu;
-                       if (idx != cpu)
-                               lpfc_printf_vlog(vport,
-                                                KERN_INFO, LOG_NVME_IOERR,
-                                               "6702 CPU Check cmd: "
-                                               "cpu %d wq %d\n",
-                                               lpfc_ncmd->cpu,
-                                               lpfc_queue_info->index);
-                       phba->sli4_hba.hdwq[idx].cpucheck_xmt_io[cpu]++;
-               }
+               this_cpu_inc(phba->sli4_hba.c_stat->xmt_io);
+               lpfc_ncmd->cpu = cpu;
+               if (idx != cpu)
+                       lpfc_printf_vlog(vport,
+                                        KERN_INFO, LOG_NVME_IOERR,
+                                       "6702 CPU Check cmd: "
+                                       "cpu %d wq %d\n",
+                                       lpfc_ncmd->cpu,
+                                       lpfc_queue_info->index);
        }
 #endif
        return 0;
@@ -1985,8 +1902,6 @@ out_unlock:
 
 /* Declare and initialization an instance of the FC NVME template. */
 static struct nvme_fc_port_template lpfc_nvme_template = {
-       .module = THIS_MODULE,
-
        /* initiator-based functions */
        .localport_delete  = lpfc_nvme_localport_delete,
        .remoteport_delete = lpfc_nvme_remoteport_delete,
index 9dc9afe..565419b 100644 (file)
@@ -707,7 +707,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
        struct lpfc_nvmet_rcv_ctx *ctxp;
        uint32_t status, result, op, start_clean, logerr;
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       uint32_t id;
+       int id;
 #endif
 
        ctxp = cmdwqe->context2;
@@ -814,16 +814,14 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
                rsp->done(rsp);
        }
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       if (phba->cpucheck_on & LPFC_CHECK_NVMET_IO) {
+       if (phba->hdwqstat_on & LPFC_CHECK_NVMET_IO) {
                id = raw_smp_processor_id();
-               if (id < LPFC_CHECK_CPU_CNT) {
-                       if (ctxp->cpu != id)
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
-                                               "6704 CPU Check cmdcmpl: "
-                                               "cpu %d expect %d\n",
-                                               id, ctxp->cpu);
-                       phba->sli4_hba.hdwq[rsp->hwqid].cpucheck_cmpl_io[id]++;
-               }
+               this_cpu_inc(phba->sli4_hba.c_stat->cmpl_io);
+               if (ctxp->cpu != id)
+                       lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
+                                       "6704 CPU Check cmdcmpl: "
+                                       "cpu %d expect %d\n",
+                                       id, ctxp->cpu);
        }
 #endif
 }
@@ -931,6 +929,9 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
        struct lpfc_sli_ring *pring;
        unsigned long iflags;
        int rc;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       int id;
+#endif
 
        if (phba->pport->load_flag & FC_UNLOADING) {
                rc = -ENODEV;
@@ -954,16 +955,14 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
        if (!ctxp->hdwq)
                ctxp->hdwq = &phba->sli4_hba.hdwq[rsp->hwqid];
 
-       if (phba->cpucheck_on & LPFC_CHECK_NVMET_IO) {
-               int id = raw_smp_processor_id();
-               if (id < LPFC_CHECK_CPU_CNT) {
-                       if (rsp->hwqid != id)
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
-                                               "6705 CPU Check OP: "
-                                               "cpu %d expect %d\n",
-                                               id, rsp->hwqid);
-                       phba->sli4_hba.hdwq[rsp->hwqid].cpucheck_xmt_io[id]++;
-               }
+       if (phba->hdwqstat_on & LPFC_CHECK_NVMET_IO) {
+               id = raw_smp_processor_id();
+               this_cpu_inc(phba->sli4_hba.c_stat->xmt_io);
+               if (rsp->hwqid != id)
+                       lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
+                                       "6705 CPU Check OP: "
+                                       "cpu %d expect %d\n",
+                                       id, rsp->hwqid);
                ctxp->cpu = id; /* Setup cpu for cmpl check */
        }
 #endif
@@ -2270,15 +2269,13 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
        size = nvmebuf->bytes_recv;
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       if (phba->cpucheck_on & LPFC_CHECK_NVMET_RCV) {
-               if (current_cpu < LPFC_CHECK_CPU_CNT) {
-                       if (idx != current_cpu)
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
-                                               "6703 CPU Check rcv: "
-                                               "cpu %d expect %d\n",
-                                               current_cpu, idx);
-                       phba->sli4_hba.hdwq[idx].cpucheck_rcv_io[current_cpu]++;
-               }
+       if (phba->hdwqstat_on & LPFC_CHECK_NVMET_IO) {
+               this_cpu_inc(phba->sli4_hba.c_stat->rcv_io);
+               if (idx != current_cpu)
+                       lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
+                                       "6703 CPU Check rcv: "
+                                       "cpu %d expect %d\n",
+                                       current_cpu, idx);
        }
 #endif
 
@@ -2598,7 +2595,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
        union lpfc_wqe128 *wqe;
        struct ulp_bde64 *bde;
        dma_addr_t physaddr;
-       int i, cnt;
+       int i, cnt, nsegs;
        int do_pbde;
        int xc = 1;
 
@@ -2629,6 +2626,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
                                phba->cfg_nvme_seg_cnt);
                return NULL;
        }
+       nsegs = rsp->sg_cnt;
 
        tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
        nvmewqe = ctxp->wqeq;
@@ -2868,7 +2866,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
                wqe->fcp_trsp.rsvd_12_15[0] = 0;
 
                /* Use rspbuf, NOT sg list */
-               rsp->sg_cnt = 0;
+               nsegs = 0;
                sgl->word2 = 0;
                atomic_inc(&tgtp->xmt_fcp_rsp);
                break;
@@ -2885,7 +2883,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
        nvmewqe->drvrTimeout = (phba->fc_ratov * 3) + LPFC_DRVR_TIMEOUT;
        nvmewqe->context1 = ndlp;
 
-       for_each_sg(rsp->sg, sgel, rsp->sg_cnt, i) {
+       for_each_sg(rsp->sg, sgel, nsegs, i) {
                physaddr = sg_dma_address(sgel);
                cnt = sg_dma_len(sgel);
                sgl->addr_hi = putPaddrHigh(physaddr);
index 0fc9a24..ad62fb3 100644 (file)
@@ -3805,9 +3805,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
        struct Scsi_Host *shost;
        int idx;
        uint32_t logit = LOG_FCP;
-#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       int cpu;
-#endif
 
        /* Guard against abort handler being called at same time */
        spin_lock(&lpfc_cmd->buf_lock);
@@ -3826,11 +3823,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
                phba->sli4_hba.hdwq[idx].scsi_cstat.io_cmpls++;
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       if (unlikely(phba->cpucheck_on & LPFC_CHECK_SCSI_IO)) {
-               cpu = raw_smp_processor_id();
-               if (cpu < LPFC_CHECK_CPU_CNT && phba->sli4_hba.hdwq)
-                       phba->sli4_hba.hdwq[idx].cpucheck_cmpl_io[cpu]++;
-       }
+       if (unlikely(phba->hdwqstat_on & LPFC_CHECK_SCSI_IO))
+               this_cpu_inc(phba->sli4_hba.c_stat->cmpl_io);
 #endif
        shost = cmd->device->host;
 
@@ -4031,6 +4025,14 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
        lpfc_cmd->pCmd = NULL;
        spin_unlock(&lpfc_cmd->buf_lock);
 
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       if (lpfc_cmd->ts_cmd_start) {
+               lpfc_cmd->ts_isr_cmpl = pIocbIn->isr_timestamp;
+               lpfc_cmd->ts_data_io = ktime_get_ns();
+               phba->ktime_last_cmd = lpfc_cmd->ts_data_io;
+               lpfc_io_ktime(phba, lpfc_cmd);
+       }
+#endif
        /* The sdev is not guaranteed to be valid post scsi_done upcall. */
        cmd->scsi_done(cmd);
 
@@ -4504,7 +4506,10 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
        struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
        int err, idx;
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       int cpu;
+       uint64_t start = 0L;
+
+       if (phba->ktime_on)
+               start = ktime_get_ns();
 #endif
 
        rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
@@ -4626,17 +4631,20 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
        lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp);
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-       if (unlikely(phba->cpucheck_on & LPFC_CHECK_SCSI_IO)) {
-               cpu = raw_smp_processor_id();
-               if (cpu < LPFC_CHECK_CPU_CNT) {
-                       struct lpfc_sli4_hdw_queue *hdwq =
-                                       &phba->sli4_hba.hdwq[lpfc_cmd->hdwq_no];
-                       hdwq->cpucheck_xmt_io[cpu]++;
-               }
-       }
+       if (unlikely(phba->hdwqstat_on & LPFC_CHECK_SCSI_IO))
+               this_cpu_inc(phba->sli4_hba.c_stat->xmt_io);
 #endif
        err = lpfc_sli_issue_iocb(phba, LPFC_FCP_RING,
                                  &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       if (start) {
+               lpfc_cmd->ts_cmd_start = start;
+               lpfc_cmd->ts_last_cmd = phba->ktime_last_cmd;
+               lpfc_cmd->ts_cmd_wqput = ktime_get_ns();
+       } else {
+               lpfc_cmd->ts_cmd_start = 0;
+       }
+#endif
        if (err) {
                lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
                                 "3376 FCP could not issue IOCB err %x"
@@ -6023,31 +6031,6 @@ struct scsi_host_template lpfc_template_nvme = {
        .track_queue_depth      = 0,
 };
 
-struct scsi_host_template lpfc_template_no_hr = {
-       .module                 = THIS_MODULE,
-       .name                   = LPFC_DRIVER_NAME,
-       .proc_name              = LPFC_DRIVER_NAME,
-       .info                   = lpfc_info,
-       .queuecommand           = lpfc_queuecommand,
-       .eh_timed_out           = fc_eh_timed_out,
-       .eh_abort_handler       = lpfc_abort_handler,
-       .eh_device_reset_handler = lpfc_device_reset_handler,
-       .eh_target_reset_handler = lpfc_target_reset_handler,
-       .eh_bus_reset_handler   = lpfc_bus_reset_handler,
-       .slave_alloc            = lpfc_slave_alloc,
-       .slave_configure        = lpfc_slave_configure,
-       .slave_destroy          = lpfc_slave_destroy,
-       .scan_finished          = lpfc_scan_finished,
-       .this_id                = -1,
-       .sg_tablesize           = LPFC_DEFAULT_SG_SEG_CNT,
-       .cmd_per_lun            = LPFC_CMD_PER_LUN,
-       .shost_attrs            = lpfc_hba_attrs,
-       .max_sectors            = 0xFFFFFFFF,
-       .vendor_id              = LPFC_NL_VENDOR_ID,
-       .change_queue_depth     = scsi_change_queue_depth,
-       .track_queue_depth      = 1,
-};
-
 struct scsi_host_template lpfc_template = {
        .module                 = THIS_MODULE,
        .name                   = LPFC_DRIVER_NAME,
@@ -6073,26 +6056,3 @@ struct scsi_host_template lpfc_template = {
        .change_queue_depth     = scsi_change_queue_depth,
        .track_queue_depth      = 1,
 };
-
-struct scsi_host_template lpfc_vport_template = {
-       .module                 = THIS_MODULE,
-       .name                   = LPFC_DRIVER_NAME,
-       .proc_name              = LPFC_DRIVER_NAME,
-       .info                   = lpfc_info,
-       .queuecommand           = lpfc_queuecommand,
-       .eh_timed_out           = fc_eh_timed_out,
-       .eh_abort_handler       = lpfc_abort_handler,
-       .eh_device_reset_handler = lpfc_device_reset_handler,
-       .eh_target_reset_handler = lpfc_target_reset_handler,
-       .slave_alloc            = lpfc_slave_alloc,
-       .slave_configure        = lpfc_slave_configure,
-       .slave_destroy          = lpfc_slave_destroy,
-       .scan_finished          = lpfc_scan_finished,
-       .this_id                = -1,
-       .sg_tablesize           = LPFC_DEFAULT_SG_SEG_CNT,
-       .cmd_per_lun            = LPFC_CMD_PER_LUN,
-       .shost_attrs            = lpfc_vport_attrs,
-       .max_sectors            = 0xFFFF,
-       .change_queue_depth     = scsi_change_queue_depth,
-       .track_queue_depth      = 1,
-};
index 0b26b5c..b6fb665 100644 (file)
@@ -230,25 +230,16 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe)
  * This routine will update the HBA index of a queue to reflect consumption of
  * Work Queue Entries by the HBA. When the HBA indicates that it has consumed
  * an entry the host calls this function to update the queue's internal
- * pointers. This routine returns the number of entries that were consumed by
- * the HBA.
+ * pointers.
  **/
-static uint32_t
+static void
 lpfc_sli4_wq_release(struct lpfc_queue *q, uint32_t index)
 {
-       uint32_t released = 0;
-
        /* sanity check on queue memory */
        if (unlikely(!q))
-               return 0;
+               return;
 
-       if (q->hba_index == index)
-               return 0;
-       do {
-               q->hba_index = ((q->hba_index + 1) % q->entry_count);
-               released++;
-       } while (q->hba_index != index);
-       return released;
+       q->hba_index = index;
 }
 
 /**
@@ -2511,6 +2502,8 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
            !pmb->u.mb.mbxStatus) {
                rpi = pmb->u.mb.un.varWords[0];
                vpi = pmb->u.mb.un.varRegLogin.vpi;
+               if (phba->sli_rev == LPFC_SLI_REV4)
+                       vpi -= phba->sli4_hba.max_cfg_param.vpi_base;
                lpfc_unreg_login(phba, vpi, rpi, pmb);
                pmb->vport = vport;
                pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
@@ -4044,6 +4037,11 @@ lpfc_sli_flush_io_rings(struct lpfc_hba *phba)
        struct lpfc_iocbq *piocb, *next_iocb;
 
        spin_lock_irq(&phba->hbalock);
+       if (phba->hba_flag & HBA_IOQ_FLUSH ||
+           !phba->sli4_hba.hdwq) {
+               spin_unlock_irq(&phba->hbalock);
+               return;
+       }
        /* Indicate the I/O queues are flushed */
        phba->hba_flag |= HBA_IOQ_FLUSH;
        spin_unlock_irq(&phba->hbalock);
@@ -5034,23 +5032,6 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
 
                } else
                        phba->max_vpi = 0;
-               phba->fips_level = 0;
-               phba->fips_spec_rev = 0;
-               if (pmb->u.mb.un.varCfgPort.gdss) {
-                       phba->sli3_options |= LPFC_SLI3_DSS_ENABLED;
-                       phba->fips_level = pmb->u.mb.un.varCfgPort.fips_level;
-                       phba->fips_spec_rev = pmb->u.mb.un.varCfgPort.fips_rev;
-                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                                       "2850 Security Crypto Active. FIPS x%d "
-                                       "(Spec Rev: x%d)",
-                                       phba->fips_level, phba->fips_spec_rev);
-               }
-               if (pmb->u.mb.un.varCfgPort.sec_err) {
-                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                                       "2856 Config Port Security Crypto "
-                                       "Error: x%x ",
-                                       pmb->u.mb.un.varCfgPort.sec_err);
-               }
                if (pmb->u.mb.un.varCfgPort.gerbm)
                        phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED;
                if (pmb->u.mb.un.varCfgPort.gcrp)
@@ -14442,12 +14423,10 @@ static inline void lpfc_sli4_add_to_poll_list(struct lpfc_queue *eq)
 {
        struct lpfc_hba *phba = eq->phba;
 
-       if (list_empty(&phba->poll_list)) {
-               timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0);
-               /* kickstart slowpath processing for this eq */
+       /* kickstart slowpath processing if needed */
+       if (list_empty(&phba->poll_list))
                mod_timer(&phba->cpuhp_poll_timer,
                          jiffies + msecs_to_jiffies(LPFC_POLL_HB));
-       }
 
        list_add_rcu(&eq->_poll_list, &phba->poll_list);
        synchronize_rcu();
index 7bcf922..93d976e 100644 (file)
@@ -446,6 +446,6 @@ struct lpfc_io_buf {
        uint64_t ts_last_cmd;
        uint64_t ts_cmd_wqput;
        uint64_t ts_isr_cmpl;
-       uint64_t ts_data_nvme;
+       uint64_t ts_data_io;
 #endif
 };
index d963ca8..8da7429 100644 (file)
@@ -697,13 +697,6 @@ struct lpfc_sli4_hdw_queue {
        struct lpfc_lock_stat lock_conflict;
 #endif
 
-#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
-#define LPFC_CHECK_CPU_CNT    128
-       uint32_t cpucheck_rcv_io[LPFC_CHECK_CPU_CNT];
-       uint32_t cpucheck_xmt_io[LPFC_CHECK_CPU_CNT];
-       uint32_t cpucheck_cmpl_io[LPFC_CHECK_CPU_CNT];
-#endif
-
        /* Per HDWQ pool resources */
        struct list_head sgl_list;
        struct list_head cmd_rsp_buf_list;
@@ -740,6 +733,15 @@ struct lpfc_sli4_hdw_queue {
 #define lpfc_qp_spin_lock(lock, qp, lstat) spin_lock(lock)
 #endif
 
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+struct lpfc_hdwq_stat {
+       u32 hdwq_no;
+       u32 rcv_io;
+       u32 xmt_io;
+       u32 cmpl_io;
+};
+#endif
+
 struct lpfc_sli4_hba {
        void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for
                                           * config space registers
@@ -921,6 +923,9 @@ struct lpfc_sli4_hba {
        struct cpumask numa_mask;
        uint16_t curr_disp_cpu;
        struct lpfc_eq_intr_info __percpu *eq_info;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       struct lpfc_hdwq_stat __percpu *c_stat;
+#endif
        uint32_t conf_trunk;
 #define lpfc_conf_trunk_port0_WORD     conf_trunk
 #define lpfc_conf_trunk_port0_SHIFT    0
index c4ab006..ca40c47 100644 (file)
@@ -20,7 +20,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "12.6.0.4"
+#define LPFC_DRIVER_VERSION "12.8.0.0"
 #define LPFC_DRIVER_NAME               "lpfc"
 
 /* Used for SLI 2/3 */
index 778d5e6..04a40af 100644 (file)
@@ -9908,8 +9908,8 @@ static void scsih_remove(struct pci_dev *pdev)
 
        ioc->remove_host = 1;
 
-       mpt3sas_wait_for_commands_to_complete(ioc);
-       _scsih_flush_running_cmds(ioc);
+       if (!pci_device_is_present(pdev))
+               _scsih_flush_running_cmds(ioc);
 
        _scsih_fw_event_cleanup_queue(ioc);
 
@@ -9992,8 +9992,8 @@ scsih_shutdown(struct pci_dev *pdev)
 
        ioc->remove_host = 1;
 
-       mpt3sas_wait_for_commands_to_complete(ioc);
-       _scsih_flush_running_cmds(ioc);
+       if (!pci_device_is_present(pdev))
+               _scsih_flush_running_cmds(ioc);
 
        _scsih_fw_event_cleanup_queue(ioc);
 
index 84e2a98..4886d24 100644 (file)
@@ -610,7 +610,6 @@ static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
 }
 
 static struct nvme_fc_port_template qla_nvme_fc_transport = {
-       .module = THIS_MODULE,
        .localport_delete = qla_nvme_localport_delete,
        .remoteport_delete = qla_nvme_remoteport_delete,
        .create_queue   = qla_nvme_alloc_queue,
index 0ec1b31..b2a803c 100644 (file)
@@ -2022,7 +2022,7 @@ static void __iscsi_unbind_session(struct work_struct *work)
        if (session->target_id == ISCSI_MAX_TARGET) {
                spin_unlock_irqrestore(&session->lock, flags);
                mutex_unlock(&ihost->mutex);
-               return;
+               goto unbind_session_exit;
        }
 
        target_id = session->target_id;
@@ -2034,6 +2034,8 @@ static void __iscsi_unbind_session(struct work_struct *work)
                ida_simple_remove(&iscsi_sess_ida, target_id);
 
        scsi_remove_target(&session->dev);
+
+unbind_session_exit:
        iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
        ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n");
 }
index 1c270e6..d2fe3fa 100644 (file)
@@ -550,10 +550,12 @@ out:
 static void sr_block_release(struct gendisk *disk, fmode_t mode)
 {
        struct scsi_cd *cd = scsi_cd(disk);
+
        mutex_lock(&cd->lock);
        cdrom_release(&cd->cdi, mode);
-       scsi_cd_put(cd);
        mutex_unlock(&cd->lock);
+
+       scsi_cd_put(cd);
 }
 
 static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
index 40a66b3..673c165 100644 (file)
@@ -499,8 +499,15 @@ static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 
        if (ufshcd_is_link_hibern8(hba)) {
                err = ufs_mtk_link_set_lpm(hba);
-               if (err)
+               if (err) {
+                       /*
+                        * Set link as off state enforcedly to trigger
+                        * ufshcd_host_reset_and_restore() in ufshcd_suspend()
+                        * for completed host reset.
+                        */
+                       ufshcd_set_link_off(hba);
                        return -EAGAIN;
+               }
        }
 
        if (!ufshcd_is_link_active(hba))
@@ -519,8 +526,10 @@ static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 
        if (ufshcd_is_link_hibern8(hba)) {
                err = ufs_mtk_link_set_hpm(hba);
-               if (err)
+               if (err) {
+                       err = ufshcd_link_recovery(hba);
                        return err;
+               }
        }
 
        return 0;
index e04e8b8..698e8d2 100644 (file)
@@ -172,19 +172,6 @@ enum {
 #define ufshcd_clear_eh_in_progress(h) \
        ((h)->eh_flags &= ~UFSHCD_EH_IN_PROGRESS)
 
-#define ufshcd_set_ufs_dev_active(h) \
-       ((h)->curr_dev_pwr_mode = UFS_ACTIVE_PWR_MODE)
-#define ufshcd_set_ufs_dev_sleep(h) \
-       ((h)->curr_dev_pwr_mode = UFS_SLEEP_PWR_MODE)
-#define ufshcd_set_ufs_dev_poweroff(h) \
-       ((h)->curr_dev_pwr_mode = UFS_POWERDOWN_PWR_MODE)
-#define ufshcd_is_ufs_dev_active(h) \
-       ((h)->curr_dev_pwr_mode == UFS_ACTIVE_PWR_MODE)
-#define ufshcd_is_ufs_dev_sleep(h) \
-       ((h)->curr_dev_pwr_mode == UFS_SLEEP_PWR_MODE)
-#define ufshcd_is_ufs_dev_poweroff(h) \
-       ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE)
-
 struct ufs_pm_lvl_states ufs_pm_lvl_states[] = {
        {UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE},
        {UFS_ACTIVE_PWR_MODE, UIC_LINK_HIBERN8_STATE},
@@ -868,28 +855,29 @@ static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba)
                return false;
 }
 
-static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
+/**
+ * ufshcd_set_clk_freq - set UFS controller clock frequencies
+ * @hba: per adapter instance
+ * @scale_up: If True, set max possible frequency othewise set low frequency
+ *
+ * Returns 0 if successful
+ * Returns < 0 for any other errors
+ */
+static int ufshcd_set_clk_freq(struct ufs_hba *hba, bool scale_up)
 {
        int ret = 0;
        struct ufs_clk_info *clki;
        struct list_head *head = &hba->clk_list_head;
-       ktime_t start = ktime_get();
-       bool clk_state_changed = false;
 
        if (list_empty(head))
                goto out;
 
-       ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE);
-       if (ret)
-               return ret;
-
        list_for_each_entry(clki, head, list) {
                if (!IS_ERR_OR_NULL(clki->clk)) {
                        if (scale_up && clki->max_freq) {
                                if (clki->curr_freq == clki->max_freq)
                                        continue;
 
-                               clk_state_changed = true;
                                ret = clk_set_rate(clki->clk, clki->max_freq);
                                if (ret) {
                                        dev_err(hba->dev, "%s: %s clk set rate(%dHz) failed, %d\n",
@@ -908,7 +896,6 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
                                if (clki->curr_freq == clki->min_freq)
                                        continue;
 
-                               clk_state_changed = true;
                                ret = clk_set_rate(clki->clk, clki->min_freq);
                                if (ret) {
                                        dev_err(hba->dev, "%s: %s clk set rate(%dHz) failed, %d\n",
@@ -927,11 +914,37 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
                                clki->name, clk_get_rate(clki->clk));
        }
 
+out:
+       return ret;
+}
+
+/**
+ * ufshcd_scale_clks - scale up or scale down UFS controller clocks
+ * @hba: per adapter instance
+ * @scale_up: True if scaling up and false if scaling down
+ *
+ * Returns 0 if successful
+ * Returns < 0 for any other errors
+ */
+static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
+{
+       int ret = 0;
+       ktime_t start = ktime_get();
+
+       ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE);
+       if (ret)
+               goto out;
+
+       ret = ufshcd_set_clk_freq(hba, scale_up);
+       if (ret)
+               goto out;
+
        ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE);
+       if (ret)
+               ufshcd_set_clk_freq(hba, !scale_up);
 
 out:
-       if (clk_state_changed)
-               trace_ufshcd_profile_clk_scaling(dev_name(hba->dev),
+       trace_ufshcd_profile_clk_scaling(dev_name(hba->dev),
                        (scale_up ? "up" : "down"),
                        ktime_to_us(ktime_sub(ktime_get(), start)), ret);
        return ret;
@@ -1065,8 +1078,7 @@ static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up)
        }
 
        /* check if the power mode needs to be changed or not? */
-       ret = ufshcd_change_power_mode(hba, &new_pwr_info);
-
+       ret = ufshcd_config_pwr_mode(hba, &new_pwr_info);
        if (ret)
                dev_err(hba->dev, "%s: failed err %d, old gear: (tx %d rx %d), new gear: (tx %d rx %d)",
                        __func__, ret,
@@ -1119,35 +1131,32 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
 
        ret = ufshcd_clock_scaling_prepare(hba);
        if (ret)
-               return ret;
+               goto out;
 
        /* scale down the gear before scaling down clocks */
        if (!scale_up) {
                ret = ufshcd_scale_gear(hba, false);
                if (ret)
-                       goto out;
+                       goto out_unprepare;
        }
 
        ret = ufshcd_scale_clks(hba, scale_up);
        if (ret) {
                if (!scale_up)
                        ufshcd_scale_gear(hba, true);
-               goto out;
+               goto out_unprepare;
        }
 
        /* scale up the gear after scaling up clocks */
        if (scale_up) {
                ret = ufshcd_scale_gear(hba, true);
-               if (ret) {
+               if (ret)
                        ufshcd_scale_clks(hba, false);
-                       goto out;
-               }
        }
 
-       ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE);
-
-out:
+out_unprepare:
        ufshcd_clock_scaling_unprepare(hba);
+out:
        ufshcd_release(hba);
        return ret;
 }
@@ -3785,7 +3794,7 @@ out:
        return ret;
 }
 
-static int ufshcd_link_recovery(struct ufs_hba *hba)
+int ufshcd_link_recovery(struct ufs_hba *hba)
 {
        int ret;
        unsigned long flags;
@@ -3812,6 +3821,7 @@ static int ufshcd_link_recovery(struct ufs_hba *hba)
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(ufshcd_link_recovery);
 
 static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba)
 {
@@ -4112,8 +4122,6 @@ int ufshcd_config_pwr_mode(struct ufs_hba *hba,
                memcpy(&final_params, desired_pwr_mode, sizeof(final_params));
 
        ret = ufshcd_change_power_mode(hba, &final_params);
-       if (!ret)
-               ufshcd_print_pwr_info(hba);
 
        return ret;
 }
@@ -6299,7 +6307,7 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
        spin_unlock_irqrestore(hba->host->host_lock, flags);
 
        /* scale up clocks to max frequency before full reinitialization */
-       ufshcd_scale_clks(hba, true);
+       ufshcd_set_clk_freq(hba, true);
 
        err = ufshcd_hba_enable(hba);
        if (err)
@@ -7127,6 +7135,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool async)
                                        __func__, ret);
                        goto out;
                }
+               ufshcd_print_pwr_info(hba);
        }
 
        /*
index dd1ee27..6ffc08a 100644 (file)
@@ -130,6 +130,19 @@ enum uic_link_state {
 #define ufshcd_set_link_hibern8(hba) ((hba)->uic_link_state = \
                                    UIC_LINK_HIBERN8_STATE)
 
+#define ufshcd_set_ufs_dev_active(h) \
+       ((h)->curr_dev_pwr_mode = UFS_ACTIVE_PWR_MODE)
+#define ufshcd_set_ufs_dev_sleep(h) \
+       ((h)->curr_dev_pwr_mode = UFS_SLEEP_PWR_MODE)
+#define ufshcd_set_ufs_dev_poweroff(h) \
+       ((h)->curr_dev_pwr_mode = UFS_POWERDOWN_PWR_MODE)
+#define ufshcd_is_ufs_dev_active(h) \
+       ((h)->curr_dev_pwr_mode == UFS_ACTIVE_PWR_MODE)
+#define ufshcd_is_ufs_dev_sleep(h) \
+       ((h)->curr_dev_pwr_mode == UFS_SLEEP_PWR_MODE)
+#define ufshcd_is_ufs_dev_poweroff(h) \
+       ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE)
+
 /*
  * UFS Power management levels.
  * Each level is in increasing order of power savings.
@@ -788,6 +801,7 @@ int ufshcd_alloc_host(struct device *, struct ufs_hba **);
 void ufshcd_dealloc_host(struct ufs_hba *);
 int ufshcd_hba_enable(struct ufs_hba *hba);
 int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
+int ufshcd_link_recovery(struct ufs_hba *hba);
 int ufshcd_make_hba_operational(struct ufs_hba *hba);
 void ufshcd_remove(struct ufs_hba *);
 int ufshcd_uic_hibern8_exit(struct ufs_hba *hba);
@@ -1083,6 +1097,7 @@ static inline void ufshcd_vops_device_reset(struct ufs_hba *hba)
 {
        if (hba->vops && hba->vops->device_reset) {
                hba->vops->device_reset(hba);
+               ufshcd_set_ufs_dev_active(hba);
                ufshcd_update_reg_hist(&hba->ufs_stats.dev_reset, 0);
        }
 }
index 1778f8c..425ab6f 100644 (file)
@@ -22,5 +22,6 @@ source "drivers/soc/ux500/Kconfig"
 source "drivers/soc/versatile/Kconfig"
 source "drivers/soc/xilinx/Kconfig"
 source "drivers/soc/zte/Kconfig"
+source "drivers/soc/kendryte/Kconfig"
 
 endmenu
index a39f17c..36452be 100644 (file)
@@ -28,3 +28,4 @@ obj-$(CONFIG_ARCH_U8500)      += ux500/
 obj-$(CONFIG_PLAT_VERSATILE)   += versatile/
 obj-y                          += xilinx/
 obj-$(CONFIG_ARCH_ZX)          += zte/
+obj-$(CONFIG_SOC_KENDRYTE)     += kendryte/
diff --git a/drivers/soc/kendryte/Kconfig b/drivers/soc/kendryte/Kconfig
new file mode 100644 (file)
index 0000000..49785b1
--- /dev/null
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+
+if SOC_KENDRYTE
+
+config K210_SYSCTL
+       bool "Kendryte K210 system controller"
+       default y
+       depends on RISCV
+       help
+         Enables controlling the K210 various clocks and to enable
+         general purpose use of the extra 2MB of SRAM normally
+         reserved for the AI engine.
+
+endif
diff --git a/drivers/soc/kendryte/Makefile b/drivers/soc/kendryte/Makefile
new file mode 100644 (file)
index 0000000..002d9ce
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_K210_SYSCTL)      += k210-sysctl.o
diff --git a/drivers/soc/kendryte/k210-sysctl.c b/drivers/soc/kendryte/k210-sysctl.c
new file mode 100644 (file)
index 0000000..4608fbc
--- /dev/null
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Christoph Hellwig.
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ */
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/bitfield.h>
+#include <asm/soc.h>
+
+#define K210_SYSCTL_CLK0_FREQ          26000000UL
+
+/* Registers base address */
+#define K210_SYSCTL_SYSCTL_BASE_ADDR   0x50440000ULL
+
+/* Registers */
+#define K210_SYSCTL_PLL0               0x08
+#define K210_SYSCTL_PLL1               0x0c
+/* clkr: 4bits, clkf1: 6bits, clkod: 4bits, bwadj: 4bits */
+#define   PLL_RESET            (1 << 20)
+#define   PLL_PWR              (1 << 21)
+#define   PLL_INTFB            (1 << 22)
+#define   PLL_BYPASS           (1 << 23)
+#define   PLL_TEST             (1 << 24)
+#define   PLL_OUT_EN           (1 << 25)
+#define   PLL_TEST_EN          (1 << 26)
+#define K210_SYSCTL_PLL_LOCK           0x18
+#define   PLL0_LOCK1           (1 << 0)
+#define   PLL0_LOCK2           (1 << 1)
+#define   PLL0_SLIP_CLEAR      (1 << 2)
+#define   PLL0_TEST_CLK_OUT    (1 << 3)
+#define   PLL1_LOCK1           (1 << 8)
+#define   PLL1_LOCK2           (1 << 9)
+#define   PLL1_SLIP_CLEAR      (1 << 10)
+#define   PLL1_TEST_CLK_OUT    (1 << 11)
+#define   PLL2_LOCK1           (1 << 16)
+#define   PLL2_LOCK2           (1 << 16)
+#define   PLL2_SLIP_CLEAR      (1 << 18)
+#define   PLL2_TEST_CLK_OUT    (1 << 19)
+#define K210_SYSCTL_CLKSEL0    0x20
+#define   CLKSEL_ACLK          (1 << 0)
+#define K210_SYSCTL_CLKEN_CENT         0x28
+#define   CLKEN_CPU            (1 << 0)
+#define   CLKEN_SRAM0          (1 << 1)
+#define   CLKEN_SRAM1          (1 << 2)
+#define   CLKEN_APB0           (1 << 3)
+#define   CLKEN_APB1           (1 << 4)
+#define   CLKEN_APB2           (1 << 5)
+#define K210_SYSCTL_CLKEN_PERI         0x2c
+#define   CLKEN_ROM            (1 << 0)
+#define   CLKEN_DMA            (1 << 1)
+#define   CLKEN_AI             (1 << 2)
+#define   CLKEN_DVP            (1 << 3)
+#define   CLKEN_FFT            (1 << 4)
+#define   CLKEN_GPIO           (1 << 5)
+#define   CLKEN_SPI0           (1 << 6)
+#define   CLKEN_SPI1           (1 << 7)
+#define   CLKEN_SPI2           (1 << 8)
+#define   CLKEN_SPI3           (1 << 9)
+#define   CLKEN_I2S0           (1 << 10)
+#define   CLKEN_I2S1           (1 << 11)
+#define   CLKEN_I2S2           (1 << 12)
+#define   CLKEN_I2C0           (1 << 13)
+#define   CLKEN_I2C1           (1 << 14)
+#define   CLKEN_I2C2           (1 << 15)
+#define   CLKEN_UART1          (1 << 16)
+#define   CLKEN_UART2          (1 << 17)
+#define   CLKEN_UART3          (1 << 18)
+#define   CLKEN_AES            (1 << 19)
+#define   CLKEN_FPIO           (1 << 20)
+#define   CLKEN_TIMER0         (1 << 21)
+#define   CLKEN_TIMER1         (1 << 22)
+#define   CLKEN_TIMER2         (1 << 23)
+#define   CLKEN_WDT0           (1 << 24)
+#define   CLKEN_WDT1           (1 << 25)
+#define   CLKEN_SHA            (1 << 26)
+#define   CLKEN_OTP            (1 << 27)
+#define   CLKEN_RTC            (1 << 29)
+
+struct k210_sysctl {
+       void __iomem            *regs;
+       struct clk_hw           hw;
+};
+
+static void k210_set_bits(u32 val, void __iomem *reg)
+{
+       writel(readl(reg) | val, reg);
+}
+
+static void k210_clear_bits(u32 val, void __iomem *reg)
+{
+       writel(readl(reg) & ~val, reg);
+}
+
+static void k210_pll1_enable(void __iomem *regs)
+{
+       u32 val;
+
+       val = readl(regs + K210_SYSCTL_PLL1);
+       val &= ~GENMASK(19, 0);                         /* clkr1 = 0 */
+       val |= FIELD_PREP(GENMASK(9, 4), 0x3B);         /* clkf1 = 59 */
+       val |= FIELD_PREP(GENMASK(13, 10), 0x3);        /* clkod1 = 3 */
+       val |= FIELD_PREP(GENMASK(19, 14), 0x3B);       /* bwadj1 = 59 */
+       writel(val, regs + K210_SYSCTL_PLL1);
+
+       k210_clear_bits(PLL_BYPASS, regs + K210_SYSCTL_PLL1);
+       k210_set_bits(PLL_PWR, regs + K210_SYSCTL_PLL1);
+
+       /*
+        * Reset the pll. The magic NOPs come from the Kendryte reference SDK.
+        */
+       k210_clear_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
+       k210_set_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
+       nop();
+       nop();
+       k210_clear_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
+
+       for (;;) {
+               val = readl(regs + K210_SYSCTL_PLL_LOCK);
+               if (val & PLL1_LOCK2)
+                       break;
+               writel(val | PLL1_SLIP_CLEAR, regs + K210_SYSCTL_PLL_LOCK);
+       }
+
+       k210_set_bits(PLL_OUT_EN, regs + K210_SYSCTL_PLL1);
+}
+
+static unsigned long k210_sysctl_clk_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct k210_sysctl *s = container_of(hw, struct k210_sysctl, hw);
+       u32 clksel0, pll0;
+       u64 pll0_freq, clkr0, clkf0, clkod0;
+
+       /*
+        * If the clock selector is not set, use the base frequency.
+        * Otherwise, use PLL0 frequency with a frequency divisor.
+        */
+       clksel0 = readl(s->regs + K210_SYSCTL_CLKSEL0);
+       if (!(clksel0 & CLKSEL_ACLK))
+               return K210_SYSCTL_CLK0_FREQ;
+
+       /*
+        * Get PLL0 frequency:
+        * freq = base frequency * clkf0 / (clkr0 * clkod0)
+        */
+       pll0 = readl(s->regs + K210_SYSCTL_PLL0);
+       clkr0 = 1 + FIELD_GET(GENMASK(3, 0), pll0);
+       clkf0 = 1 + FIELD_GET(GENMASK(9, 4), pll0);
+       clkod0 = 1 + FIELD_GET(GENMASK(13, 10), pll0);
+       pll0_freq = clkf0 * K210_SYSCTL_CLK0_FREQ / (clkr0 * clkod0);
+
+       /* Get the frequency divisor from the clock selector */
+       return pll0_freq / (2ULL << FIELD_GET(0x00000006, clksel0));
+}
+
+static const struct clk_ops k210_sysctl_clk_ops = {
+       .recalc_rate    = k210_sysctl_clk_recalc_rate,
+};
+
+static const struct clk_init_data k210_clk_init_data = {
+       .name           = "k210-sysctl-pll1",
+       .ops            = &k210_sysctl_clk_ops,
+};
+
+static int k210_sysctl_probe(struct platform_device *pdev)
+{
+       struct k210_sysctl *s;
+       int error;
+
+       pr_info("Kendryte K210 SoC sysctl\n");
+
+       s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
+       if (!s)
+               return -ENOMEM;
+
+       s->regs = devm_ioremap_resource(&pdev->dev,
+                       platform_get_resource(pdev, IORESOURCE_MEM, 0));
+       if (IS_ERR(s->regs))
+               return PTR_ERR(s->regs);
+
+       s->hw.init = &k210_clk_init_data;
+       error = devm_clk_hw_register(&pdev->dev, &s->hw);
+       if (error) {
+               dev_err(&pdev->dev, "failed to register clk");
+               return error;
+       }
+
+       error = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,
+                                           &s->hw);
+       if (error) {
+               dev_err(&pdev->dev, "adding clk provider failed\n");
+               return error;
+       }
+
+       return 0;
+}
+
+static const struct of_device_id k210_sysctl_of_match[] = {
+       { .compatible = "kendryte,k210-sysctl", },
+       {}
+};
+
+static struct platform_driver k210_sysctl_driver = {
+       .driver = {
+               .name           = "k210-sysctl",
+               .of_match_table = k210_sysctl_of_match,
+       },
+       .probe                  = k210_sysctl_probe,
+};
+
+static int __init k210_sysctl_init(void)
+{
+       return platform_driver_register(&k210_sysctl_driver);
+}
+core_initcall(k210_sysctl_init);
+
+/*
+ * This needs to be called very early during initialization, given that
+ * PLL1 needs to be enabled to be able to use all SRAM.
+ */
+static void __init k210_soc_early_init(const void *fdt)
+{
+       void __iomem *regs;
+
+       regs = ioremap(K210_SYSCTL_SYSCTL_BASE_ADDR, 0x1000);
+       if (!regs)
+               panic("K210 sysctl ioremap");
+
+       /* Enable PLL1 to make the KPU SRAM useable */
+       k210_pll1_enable(regs);
+
+       k210_set_bits(PLL_OUT_EN, regs + K210_SYSCTL_PLL0);
+
+       k210_set_bits(CLKEN_CPU | CLKEN_SRAM0 | CLKEN_SRAM1,
+                     regs + K210_SYSCTL_CLKEN_CENT);
+       k210_set_bits(CLKEN_ROM | CLKEN_TIMER0 | CLKEN_RTC,
+                     regs + K210_SYSCTL_CLKEN_PERI);
+
+       k210_set_bits(CLKSEL_ACLK, regs + K210_SYSCTL_CLKSEL0);
+
+       iounmap(regs);
+}
+SOC_EARLY_INIT_DECLARE(generic_k210, "kendryte,k210", k210_soc_early_init);
index cd181a6..8e0575f 100644 (file)
@@ -689,7 +689,7 @@ static bool gasket_mmap_has_permissions(struct gasket_dev *gasket_dev,
 
        /* Make sure that no wrong flags are set. */
        requested_permissions =
-               (vma->vm_flags & (VM_WRITE | VM_READ | VM_EXEC));
+               (vma->vm_flags & VM_ACCESS_FLAGS);
        if (requested_permissions & ~(bar_permissions)) {
                dev_dbg(gasket_dev->dev,
                        "Attempting to map a region with requested permissions 0x%x, but region has permissions 0x%x.\n",
index 425c107..bd3ed6c 100644 (file)
@@ -134,7 +134,7 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op
         * Assigned designator
         */
        desig_len = desc[7];
-       if (desig_len != 16) {
+       if (desig_len != XCOPY_NAA_IEEE_REGEX_LEN) {
                pr_err("XCOPY 0xe4: invalid desig_len: %d\n", (int)desig_len);
                return -EINVAL;
        }
@@ -315,11 +315,6 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op
                xop->nolb, (unsigned long long)xop->src_lba,
                (unsigned long long)xop->dst_lba);
 
-       if (dc != 0) {
-               xop->dbl = get_unaligned_be24(&desc[29]);
-
-               pr_debug("XCOPY seg desc 0x02: DC=1 w/ dbl: %u\n", xop->dbl);
-       }
        return 0;
 }
 
@@ -415,7 +410,8 @@ static void xcopy_pt_release_cmd(struct se_cmd *se_cmd)
        struct xcopy_pt_cmd *xpt_cmd = container_of(se_cmd,
                                struct xcopy_pt_cmd, se_cmd);
 
-       kfree(xpt_cmd);
+       /* xpt_cmd is on the stack, nothing to free here */
+       pr_debug("xpt_cmd done: %p\n", xpt_cmd);
 }
 
 static int xcopy_pt_check_stop_free(struct se_cmd *se_cmd)
@@ -504,7 +500,6 @@ void target_xcopy_release_pt(void)
  * @cdb:        SCSI CDB to be copied into @xpt_cmd.
  * @remote_port: If false, use the LUN through which the XCOPY command has
  *              been received. If true, use @se_dev->xcopy_lun.
- * @alloc_mem:  Whether or not to allocate an SGL list.
  *
  * Set up a SCSI command (READ or WRITE) that will be used to execute an
  * XCOPY command.
@@ -514,12 +509,9 @@ static int target_xcopy_setup_pt_cmd(
        struct xcopy_op *xop,
        struct se_device *se_dev,
        unsigned char *cdb,
-       bool remote_port,
-       bool alloc_mem)
+       bool remote_port)
 {
        struct se_cmd *cmd = &xpt_cmd->se_cmd;
-       sense_reason_t sense_rc;
-       int ret = 0, rc;
 
        /*
         * Setup LUN+port to honor reservations based upon xop->op_origin for
@@ -535,46 +527,17 @@ static int target_xcopy_setup_pt_cmd(
        cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
 
        cmd->tag = 0;
-       sense_rc = target_setup_cmd_from_cdb(cmd, cdb);
-       if (sense_rc) {
-               ret = -EINVAL;
-               goto out;
-       }
+       if (target_setup_cmd_from_cdb(cmd, cdb))
+               return -EINVAL;
 
-       if (alloc_mem) {
-               rc = target_alloc_sgl(&cmd->t_data_sg, &cmd->t_data_nents,
-                                     cmd->data_length, false, false);
-               if (rc < 0) {
-                       ret = rc;
-                       goto out;
-               }
-               /*
-                * Set this bit so that transport_free_pages() allows the
-                * caller to release SGLs + physical memory allocated by
-                * transport_generic_get_mem()..
-                */
-               cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
-       } else {
-               /*
-                * Here the previously allocated SGLs for the internal READ
-                * are mapped zero-copy to the internal WRITE.
-                */
-               sense_rc = transport_generic_map_mem_to_cmd(cmd,
-                                       xop->xop_data_sg, xop->xop_data_nents,
-                                       NULL, 0);
-               if (sense_rc) {
-                       ret = -EINVAL;
-                       goto out;
-               }
+       if (transport_generic_map_mem_to_cmd(cmd, xop->xop_data_sg,
+                                       xop->xop_data_nents, NULL, 0))
+               return -EINVAL;
 
-               pr_debug("Setup PASSTHROUGH_NOALLOC t_data_sg: %p t_data_nents:"
-                        " %u\n", cmd->t_data_sg, cmd->t_data_nents);
-       }
+       pr_debug("Setup PASSTHROUGH_NOALLOC t_data_sg: %p t_data_nents:"
+                " %u\n", cmd->t_data_sg, cmd->t_data_nents);
 
        return 0;
-
-out:
-       return ret;
 }
 
 static int target_xcopy_issue_pt_cmd(struct xcopy_pt_cmd *xpt_cmd)
@@ -604,20 +567,15 @@ static int target_xcopy_read_source(
        sector_t src_lba,
        u32 src_sectors)
 {
-       struct xcopy_pt_cmd *xpt_cmd;
-       struct se_cmd *se_cmd;
+       struct xcopy_pt_cmd xpt_cmd;
+       struct se_cmd *se_cmd = &xpt_cmd.se_cmd;
        u32 length = (src_sectors * src_dev->dev_attrib.block_size);
        int rc;
        unsigned char cdb[16];
        bool remote_port = (xop->op_origin == XCOL_DEST_RECV_OP);
 
-       xpt_cmd = kzalloc(sizeof(struct xcopy_pt_cmd), GFP_KERNEL);
-       if (!xpt_cmd) {
-               pr_err("Unable to allocate xcopy_pt_cmd\n");
-               return -ENOMEM;
-       }
-       init_completion(&xpt_cmd->xpt_passthrough_sem);
-       se_cmd = &xpt_cmd->se_cmd;
+       memset(&xpt_cmd, 0, sizeof(xpt_cmd));
+       init_completion(&xpt_cmd.xpt_passthrough_sem);
 
        memset(&cdb[0], 0, 16);
        cdb[0] = READ_16;
@@ -627,36 +585,24 @@ static int target_xcopy_read_source(
                (unsigned long long)src_lba, src_sectors, length);
 
        transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess, length,
-                             DMA_FROM_DEVICE, 0, &xpt_cmd->sense_buffer[0]);
-       xop->src_pt_cmd = xpt_cmd;
+                             DMA_FROM_DEVICE, 0, &xpt_cmd.sense_buffer[0]);
 
-       rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, src_dev, &cdb[0],
-                               remote_port, true);
+       rc = target_xcopy_setup_pt_cmd(&xpt_cmd, xop, src_dev, &cdb[0],
+                               remote_port);
        if (rc < 0) {
-               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
-               transport_generic_free_cmd(se_cmd, 0);
-               return rc;
+               ec_cmd->scsi_status = se_cmd->scsi_status;
+               goto out;
        }
 
-       xop->xop_data_sg = se_cmd->t_data_sg;
-       xop->xop_data_nents = se_cmd->t_data_nents;
        pr_debug("XCOPY-READ: Saved xop->xop_data_sg: %p, num: %u for READ"
                " memory\n", xop->xop_data_sg, xop->xop_data_nents);
 
-       rc = target_xcopy_issue_pt_cmd(xpt_cmd);
-       if (rc < 0) {
-               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
-               transport_generic_free_cmd(se_cmd, 0);
-               return rc;
-       }
-       /*
-        * Clear off the allocated t_data_sg, that has been saved for
-        * zero-copy WRITE submission reuse in struct xcopy_op..
-        */
-       se_cmd->t_data_sg = NULL;
-       se_cmd->t_data_nents = 0;
-
-       return 0;
+       rc = target_xcopy_issue_pt_cmd(&xpt_cmd);
+       if (rc < 0)
+               ec_cmd->scsi_status = se_cmd->scsi_status;
+out:
+       transport_generic_free_cmd(se_cmd, 0);
+       return rc;
 }
 
 static int target_xcopy_write_destination(
@@ -666,20 +612,15 @@ static int target_xcopy_write_destination(
        sector_t dst_lba,
        u32 dst_sectors)
 {
-       struct xcopy_pt_cmd *xpt_cmd;
-       struct se_cmd *se_cmd;
+       struct xcopy_pt_cmd xpt_cmd;
+       struct se_cmd *se_cmd = &xpt_cmd.se_cmd;
        u32 length = (dst_sectors * dst_dev->dev_attrib.block_size);
        int rc;
        unsigned char cdb[16];
        bool remote_port = (xop->op_origin == XCOL_SOURCE_RECV_OP);
 
-       xpt_cmd = kzalloc(sizeof(struct xcopy_pt_cmd), GFP_KERNEL);
-       if (!xpt_cmd) {
-               pr_err("Unable to allocate xcopy_pt_cmd\n");
-               return -ENOMEM;
-       }
-       init_completion(&xpt_cmd->xpt_passthrough_sem);
-       se_cmd = &xpt_cmd->se_cmd;
+       memset(&xpt_cmd, 0, sizeof(xpt_cmd));
+       init_completion(&xpt_cmd.xpt_passthrough_sem);
 
        memset(&cdb[0], 0, 16);
        cdb[0] = WRITE_16;
@@ -689,36 +630,21 @@ static int target_xcopy_write_destination(
                (unsigned long long)dst_lba, dst_sectors, length);
 
        transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess, length,
-                             DMA_TO_DEVICE, 0, &xpt_cmd->sense_buffer[0]);
-       xop->dst_pt_cmd = xpt_cmd;
+                             DMA_TO_DEVICE, 0, &xpt_cmd.sense_buffer[0]);
 
-       rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, dst_dev, &cdb[0],
-                               remote_port, false);
+       rc = target_xcopy_setup_pt_cmd(&xpt_cmd, xop, dst_dev, &cdb[0],
+                               remote_port);
        if (rc < 0) {
-               struct se_cmd *src_cmd = &xop->src_pt_cmd->se_cmd;
-               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
-               /*
-                * If the failure happened before the t_mem_list hand-off in
-                * target_xcopy_setup_pt_cmd(), Reset memory + clear flag so that
-                * core releases this memory on error during X-COPY WRITE I/O.
-                */
-               src_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
-               src_cmd->t_data_sg = xop->xop_data_sg;
-               src_cmd->t_data_nents = xop->xop_data_nents;
-
-               transport_generic_free_cmd(se_cmd, 0);
-               return rc;
-       }
-
-       rc = target_xcopy_issue_pt_cmd(xpt_cmd);
-       if (rc < 0) {
-               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
-               se_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
-               transport_generic_free_cmd(se_cmd, 0);
-               return rc;
+               ec_cmd->scsi_status = se_cmd->scsi_status;
+               goto out;
        }
 
-       return 0;
+       rc = target_xcopy_issue_pt_cmd(&xpt_cmd);
+       if (rc < 0)
+               ec_cmd->scsi_status = se_cmd->scsi_status;
+out:
+       transport_generic_free_cmd(se_cmd, 0);
+       return rc;
 }
 
 static void target_xcopy_do_work(struct work_struct *work)
@@ -729,7 +655,7 @@ static void target_xcopy_do_work(struct work_struct *work)
        sector_t src_lba, dst_lba, end_lba;
        unsigned int max_sectors;
        int rc = 0;
-       unsigned short nolb, cur_nolb, max_nolb, copied_nolb = 0;
+       unsigned short nolb, max_nolb, copied_nolb = 0;
 
        if (target_parse_xcopy_cmd(xop) != TCM_NO_SENSE)
                goto err_free;
@@ -759,7 +685,23 @@ static void target_xcopy_do_work(struct work_struct *work)
                        (unsigned long long)src_lba, (unsigned long long)dst_lba);
 
        while (src_lba < end_lba) {
-               cur_nolb = min(nolb, max_nolb);
+               unsigned short cur_nolb = min(nolb, max_nolb);
+               u32 cur_bytes = cur_nolb * src_dev->dev_attrib.block_size;
+
+               if (cur_bytes != xop->xop_data_bytes) {
+                       /*
+                        * (Re)allocate a buffer large enough to hold the XCOPY
+                        * I/O size, which can be reused each read / write loop.
+                        */
+                       target_free_sgl(xop->xop_data_sg, xop->xop_data_nents);
+                       rc = target_alloc_sgl(&xop->xop_data_sg,
+                                             &xop->xop_data_nents,
+                                             cur_bytes,
+                                             false, false);
+                       if (rc < 0)
+                               goto out;
+                       xop->xop_data_bytes = cur_bytes;
+               }
 
                pr_debug("target_xcopy_do_work: Calling read src_dev: %p src_lba: %llu,"
                        " cur_nolb: %hu\n", src_dev, (unsigned long long)src_lba, cur_nolb);
@@ -777,10 +719,8 @@ static void target_xcopy_do_work(struct work_struct *work)
 
                rc = target_xcopy_write_destination(ec_cmd, xop, dst_dev,
                                                dst_lba, cur_nolb);
-               if (rc < 0) {
-                       transport_generic_free_cmd(&xop->src_pt_cmd->se_cmd, 0);
+               if (rc < 0)
                        goto out;
-               }
 
                dst_lba += cur_nolb;
                pr_debug("target_xcopy_do_work: Incremented WRITE dst_lba to %llu\n",
@@ -788,14 +728,10 @@ static void target_xcopy_do_work(struct work_struct *work)
 
                copied_nolb += cur_nolb;
                nolb -= cur_nolb;
-
-               transport_generic_free_cmd(&xop->src_pt_cmd->se_cmd, 0);
-               xop->dst_pt_cmd->se_cmd.se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
-
-               transport_generic_free_cmd(&xop->dst_pt_cmd->se_cmd, 0);
        }
 
        xcopy_pt_undepend_remotedev(xop);
+       target_free_sgl(xop->xop_data_sg, xop->xop_data_nents);
        kfree(xop);
 
        pr_debug("target_xcopy_do_work: Final src_lba: %llu, dst_lba: %llu\n",
@@ -809,6 +745,7 @@ static void target_xcopy_do_work(struct work_struct *work)
 
 out:
        xcopy_pt_undepend_remotedev(xop);
+       target_free_sgl(xop->xop_data_sg, xop->xop_data_nents);
 
 err_free:
        kfree(xop);
index 26ba4c3..c56a1bd 100644 (file)
@@ -5,7 +5,7 @@
 #define XCOPY_TARGET_DESC_LEN          32
 #define XCOPY_SEGMENT_DESC_LEN         28
 #define XCOPY_NAA_IEEE_REGEX_LEN       16
-#define XCOPY_MAX_SECTORS              1024
+#define XCOPY_MAX_SECTORS              4096
 
 /*
  * SPC4r37 6.4.6.1
@@ -18,8 +18,6 @@ enum xcopy_origin_list {
        XCOL_DEST_RECV_OP = 0x02,
 };
 
-struct xcopy_pt_cmd;
-
 struct xcopy_op {
        int op_origin;
 
@@ -35,11 +33,8 @@ struct xcopy_op {
        unsigned short stdi;
        unsigned short dtdi;
        unsigned short nolb;
-       unsigned int dbl;
-
-       struct xcopy_pt_cmd *src_pt_cmd;
-       struct xcopy_pt_cmd *dst_pt_cmd;
 
+       u32 xop_data_bytes;
        u32 xop_data_nents;
        struct scatterlist *xop_data_sg;
        struct work_struct xop_work;
index 5a05db5..91af271 100644 (file)
@@ -1,17 +1,18 @@
 # SPDX-License-Identifier: GPL-2.0-only
 #
-# Generic thermal sysfs drivers configuration
+# Generic thermal drivers configuration
 #
 
 menuconfig THERMAL
-       bool "Generic Thermal sysfs driver"
+       bool "Thermal drivers"
        help
-         Generic Thermal Sysfs driver offers a generic mechanism for
+         Thermal drivers offer a generic mechanism for
          thermal management. Usually it's made up of one or more thermal
-         zone and cooling device.
+         zones and cooling devices.
          Each thermal zone contains its own temperature, trip points,
-         cooling devices.
-         All platforms with ACPI thermal support can use this driver.
+         and cooling devices.
+         All platforms with ACPI or Open Firmware thermal support can use
+         this driver.
          If you want this support, you should say Y here.
 
 if THERMAL
@@ -251,6 +252,27 @@ config IMX_THERMAL
          cpufreq is used as the cooling device to throttle CPUs when the
          passive trip is crossed.
 
+config IMX_SC_THERMAL
+       tristate "Temperature sensor driver for NXP i.MX SoCs with System Controller"
+       depends on IMX_SCU
+       depends on OF
+       help
+         Support for Temperature Monitor (TEMPMON) found on NXP i.MX SoCs with
+         system controller inside, Linux kernel has to communicate with system
+         controller via MU (message unit) IPC to get temperature from thermal
+         sensor. It supports one critical trip point and one
+         passive trip point for each thermal sensor.
+
+config IMX8MM_THERMAL
+       tristate "Temperature sensor driver for Freescale i.MX8MM SoC"
+       depends on ARCH_MXC || COMPILE_TEST
+       depends on OF
+       help
+         Support for Thermal Monitoring Unit (TMU) found on Freescale i.MX8MM SoC.
+         It supports one critical trip point and one passive trip point. The
+         cpufreq is used as the cooling device to throttle CPUs when the passive
+         trip is crossed.
+
 config MAX77620_THERMAL
        tristate "Temperature sensor driver for Maxim MAX77620 PMIC"
        depends on MFD_MAX77620
@@ -265,6 +287,7 @@ config QORIQ_THERMAL
        tristate "QorIQ Thermal Monitoring Unit"
        depends on THERMAL_OF
        depends on HAS_IOMEM
+       select REGMAP_MMIO
        help
          Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms.
          It supports one critical trip point and one passive trip point. The
@@ -460,4 +483,11 @@ config UNIPHIER_THERMAL
          Enable this to plug in UniPhier on-chip PVT thermal driver into the
          thermal framework. The driver supports CPU thermal zone temperature
          reporting and a couple of trip points.
+
+config SPRD_THERMAL
+       tristate "Temperature sensor on Spreadtrum SoCs"
+       depends on ARCH_SPRD || COMPILE_TEST
+       help
+         Support for the Spreadtrum thermal sensor driver in the Linux thermal
+         framework.
 endif
index 9fb88e2..8c8ed7b 100644 (file)
@@ -43,6 +43,8 @@ obj-$(CONFIG_DB8500_THERMAL)  += db8500_thermal.o
 obj-$(CONFIG_ARMADA_THERMAL)   += armada_thermal.o
 obj-$(CONFIG_TANGO_THERMAL)    += tango_thermal.o
 obj-$(CONFIG_IMX_THERMAL)      += imx_thermal.o
+obj-$(CONFIG_IMX_SC_THERMAL)   += imx_sc_thermal.o
+obj-$(CONFIG_IMX8MM_THERMAL)   += imx8mm_thermal.o
 obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o
 obj-$(CONFIG_QORIQ_THERMAL)    += qoriq_thermal.o
 obj-$(CONFIG_DA9062_THERMAL)   += da9062-thermal.o
@@ -57,3 +59,4 @@ obj-$(CONFIG_GENERIC_ADC_THERMAL)     += thermal-generic-adc.o
 obj-$(CONFIG_ZX2967_THERMAL)   += zx2967_thermal.o
 obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o
 obj-$(CONFIG_AMLOGIC_THERMAL)     += amlogic_thermal.o
+obj-$(CONFIG_SPRD_THERMAL)     += sprd_thermal.o
index 4ae8c85..e297e13 100644 (file)
@@ -273,7 +273,7 @@ static int cpufreq_state2power(struct thermal_cooling_device *cdev,
        struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
 
        /* Request state should be less than max_level */
-       if (WARN_ON(state > cpufreq_cdev->max_level))
+       if (state > cpufreq_cdev->max_level)
                return -EINVAL;
 
        num_cpus = cpumask_weight(cpufreq_cdev->policy->cpus);
@@ -437,7 +437,7 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
        int ret;
 
        /* Request state should be less than max_level */
-       if (WARN_ON(state > cpufreq_cdev->max_level))
+       if (state > cpufreq_cdev->max_level)
                return -EINVAL;
 
        /* Check if the old cooling action is same as new cooling action */
@@ -456,6 +456,7 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
                capacity = frequency * max_capacity;
                capacity /= cpufreq_cdev->policy->cpuinfo.max_freq;
                arch_set_thermal_pressure(cpus, max_capacity - capacity);
+               ret = 0;
        }
 
        return ret;
diff --git a/drivers/thermal/imx8mm_thermal.c b/drivers/thermal/imx8mm_thermal.c
new file mode 100644 (file)
index 0000000..0d60f8d
--- /dev/null
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2020 NXP.
+ *
+ * Author: Anson Huang <Anson.Huang@nxp.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+
+#include "thermal_core.h"
+
+#define TER                    0x0     /* TMU enable */
+#define TPS                    0x4
+#define TRITSR                 0x20    /* TMU immediate temp */
+
+#define TER_EN                 BIT(31)
+#define TRITSR_TEMP0_VAL_MASK  0xff
+#define TRITSR_TEMP1_VAL_MASK  0xff0000
+
+#define PROBE_SEL_ALL          GENMASK(31, 30)
+
+#define probe_status_offset(x) (30 + x)
+#define SIGN_BIT               BIT(7)
+#define TEMP_VAL_MASK          GENMASK(6, 0)
+
+#define VER1_TEMP_LOW_LIMIT    10000
+#define VER2_TEMP_LOW_LIMIT    -40000
+#define VER2_TEMP_HIGH_LIMIT   125000
+
+#define TMU_VER1               0x1
+#define TMU_VER2               0x2
+
+struct thermal_soc_data {
+       u32 num_sensors;
+       u32 version;
+       int (*get_temp)(void *, int *);
+};
+
+struct tmu_sensor {
+       struct imx8mm_tmu *priv;
+       u32 hw_id;
+       struct thermal_zone_device *tzd;
+};
+
+struct imx8mm_tmu {
+       void __iomem *base;
+       struct clk *clk;
+       const struct thermal_soc_data *socdata;
+       struct tmu_sensor sensors[0];
+};
+
+static int imx8mm_tmu_get_temp(void *data, int *temp)
+{
+       struct tmu_sensor *sensor = data;
+       struct imx8mm_tmu *tmu = sensor->priv;
+       u32 val;
+
+       val = readl_relaxed(tmu->base + TRITSR) & TRITSR_TEMP0_VAL_MASK;
+       *temp = val * 1000;
+       if (*temp < VER1_TEMP_LOW_LIMIT)
+               return -EAGAIN;
+
+       return 0;
+}
+
+static int imx8mp_tmu_get_temp(void *data, int *temp)
+{
+       struct tmu_sensor *sensor = data;
+       struct imx8mm_tmu *tmu = sensor->priv;
+       unsigned long val;
+       bool ready;
+
+       val = readl_relaxed(tmu->base + TRITSR);
+       ready = test_bit(probe_status_offset(sensor->hw_id), &val);
+       if (!ready)
+               return -EAGAIN;
+
+       val = sensor->hw_id ? FIELD_GET(TRITSR_TEMP1_VAL_MASK, val) :
+             FIELD_GET(TRITSR_TEMP0_VAL_MASK, val);
+       if (val & SIGN_BIT) /* negative */
+               val = (~(val & TEMP_VAL_MASK) + 1);
+
+       *temp = val * 1000;
+       if (*temp < VER2_TEMP_LOW_LIMIT || *temp > VER2_TEMP_HIGH_LIMIT)
+               return -EAGAIN;
+
+       return 0;
+}
+
+static int tmu_get_temp(void *data, int *temp)
+{
+       struct tmu_sensor *sensor = data;
+       struct imx8mm_tmu *tmu = sensor->priv;
+
+       return tmu->socdata->get_temp(data, temp);
+}
+
+static struct thermal_zone_of_device_ops tmu_tz_ops = {
+       .get_temp = tmu_get_temp,
+};
+
+static void imx8mm_tmu_enable(struct imx8mm_tmu *tmu, bool enable)
+{
+       u32 val;
+
+       val = readl_relaxed(tmu->base + TER);
+       val = enable ? (val | TER_EN) : (val & ~TER_EN);
+       writel_relaxed(val, tmu->base + TER);
+}
+
+static void imx8mm_tmu_probe_sel_all(struct imx8mm_tmu *tmu)
+{
+       u32 val;
+
+       val = readl_relaxed(tmu->base + TPS);
+       val |= PROBE_SEL_ALL;
+       writel_relaxed(val, tmu->base + TPS);
+}
+
+static int imx8mm_tmu_probe(struct platform_device *pdev)
+{
+       const struct thermal_soc_data *data;
+       struct imx8mm_tmu *tmu;
+       int ret;
+       int i;
+
+       data = of_device_get_match_data(&pdev->dev);
+
+       tmu = devm_kzalloc(&pdev->dev, struct_size(tmu, sensors,
+                          data->num_sensors), GFP_KERNEL);
+       if (!tmu)
+               return -ENOMEM;
+
+       tmu->socdata = data;
+
+       tmu->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(tmu->base))
+               return PTR_ERR(tmu->base);
+
+       tmu->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(tmu->clk)) {
+               ret = PTR_ERR(tmu->clk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev,
+                               "failed to get tmu clock: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(tmu->clk);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to enable tmu clock: %d\n", ret);
+               return ret;
+       }
+
+       /* disable the monitor during initialization */
+       imx8mm_tmu_enable(tmu, false);
+
+       for (i = 0; i < data->num_sensors; i++) {
+               tmu->sensors[i].priv = tmu;
+               tmu->sensors[i].tzd =
+                       devm_thermal_zone_of_sensor_register(&pdev->dev, i,
+                                                            &tmu->sensors[i],
+                                                            &tmu_tz_ops);
+               if (IS_ERR(tmu->sensors[i].tzd)) {
+                       dev_err(&pdev->dev,
+                               "failed to register thermal zone sensor[%d]: %d\n",
+                               i, ret);
+                       return PTR_ERR(tmu->sensors[i].tzd);
+               }
+               tmu->sensors[i].hw_id = i;
+       }
+
+       platform_set_drvdata(pdev, tmu);
+
+       /* enable all the probes for V2 TMU */
+       if (tmu->socdata->version == TMU_VER2)
+               imx8mm_tmu_probe_sel_all(tmu);
+
+       /* enable the monitor */
+       imx8mm_tmu_enable(tmu, true);
+
+       return 0;
+}
+
+static int imx8mm_tmu_remove(struct platform_device *pdev)
+{
+       struct imx8mm_tmu *tmu = platform_get_drvdata(pdev);
+
+       /* disable TMU */
+       imx8mm_tmu_enable(tmu, false);
+
+       clk_disable_unprepare(tmu->clk);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct thermal_soc_data imx8mm_tmu_data = {
+       .num_sensors = 1,
+       .version = TMU_VER1,
+       .get_temp = imx8mm_tmu_get_temp,
+};
+
+static struct thermal_soc_data imx8mp_tmu_data = {
+       .num_sensors = 2,
+       .version = TMU_VER2,
+       .get_temp = imx8mp_tmu_get_temp,
+};
+
+static const struct of_device_id imx8mm_tmu_table[] = {
+       { .compatible = "fsl,imx8mm-tmu", .data = &imx8mm_tmu_data, },
+       { .compatible = "fsl,imx8mp-tmu", .data = &imx8mp_tmu_data, },
+       { },
+};
+
+static struct platform_driver imx8mm_tmu = {
+       .driver = {
+               .name   = "i.mx8mm_thermal",
+               .of_match_table = imx8mm_tmu_table,
+       },
+       .probe = imx8mm_tmu_probe,
+       .remove = imx8mm_tmu_remove,
+};
+module_platform_driver(imx8mm_tmu);
+
+MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
+MODULE_DESCRIPTION("i.MX8MM Thermal Monitor Unit driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/imx_sc_thermal.c b/drivers/thermal/imx_sc_thermal.c
new file mode 100644 (file)
index 0000000..a8723b1
--- /dev/null
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018-2020 NXP.
+ */
+
+#include <linux/err.h>
+#include <linux/firmware/imx/sci.h>
+#include <linux/firmware/imx/types.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+
+#include "thermal_core.h"
+
+#define IMX_SC_MISC_FUNC_GET_TEMP      13
+
+static struct imx_sc_ipc *thermal_ipc_handle;
+
+struct imx_sc_sensor {
+       struct thermal_zone_device *tzd;
+       u32 resource_id;
+};
+
+struct req_get_temp {
+       u16 resource_id;
+       u8 type;
+} __packed __aligned(4);
+
+struct resp_get_temp {
+       s16 celsius;
+       s8 tenths;
+} __packed __aligned(4);
+
+struct imx_sc_msg_misc_get_temp {
+       struct imx_sc_rpc_msg hdr;
+       union {
+               struct req_get_temp req;
+               struct resp_get_temp resp;
+       } data;
+} __packed __aligned(4);
+
+static int imx_sc_thermal_get_temp(void *data, int *temp)
+{
+       struct imx_sc_msg_misc_get_temp msg;
+       struct imx_sc_rpc_msg *hdr = &msg.hdr;
+       struct imx_sc_sensor *sensor = data;
+       int ret;
+
+       msg.data.req.resource_id = sensor->resource_id;
+       msg.data.req.type = IMX_SC_C_TEMP;
+
+       hdr->ver = IMX_SC_RPC_VERSION;
+       hdr->svc = IMX_SC_RPC_SVC_MISC;
+       hdr->func = IMX_SC_MISC_FUNC_GET_TEMP;
+       hdr->size = 2;
+
+       ret = imx_scu_call_rpc(thermal_ipc_handle, &msg, true);
+       if (ret) {
+               dev_err(&sensor->tzd->device, "read temp sensor %d failed, ret %d\n",
+                       sensor->resource_id, ret);
+               return ret;
+       }
+
+       *temp = msg.data.resp.celsius * 1000 + msg.data.resp.tenths * 100;
+
+       return 0;
+}
+
+static const struct thermal_zone_of_device_ops imx_sc_thermal_ops = {
+       .get_temp = imx_sc_thermal_get_temp,
+};
+
+static int imx_sc_thermal_probe(struct platform_device *pdev)
+{
+       struct device_node *np, *child, *sensor_np;
+       struct imx_sc_sensor *sensor;
+       int ret;
+
+       ret = imx_scu_get_handle(&thermal_ipc_handle);
+       if (ret)
+               return ret;
+
+       np = of_find_node_by_name(NULL, "thermal-zones");
+       if (!np)
+               return -ENODEV;
+
+       sensor_np = of_node_get(pdev->dev.of_node);
+
+       for_each_available_child_of_node(np, child) {
+               sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL);
+               if (!sensor) {
+                       of_node_put(sensor_np);
+                       return -ENOMEM;
+               }
+
+               ret = thermal_zone_of_get_sensor_id(child,
+                                                   sensor_np,
+                                                   &sensor->resource_id);
+               if (ret < 0) {
+                       dev_err(&pdev->dev,
+                               "failed to get valid sensor resource id: %d\n",
+                               ret);
+                       break;
+               }
+
+               sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev,
+                                                                  sensor->resource_id,
+                                                                  sensor,
+                                                                  &imx_sc_thermal_ops);
+               if (IS_ERR(sensor->tzd)) {
+                       dev_err(&pdev->dev, "failed to register thermal zone\n");
+                       ret = PTR_ERR(sensor->tzd);
+                       break;
+               }
+       }
+
+       of_node_put(sensor_np);
+
+       return ret;
+}
+
+static int imx_sc_thermal_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static const struct of_device_id imx_sc_thermal_table[] = {
+       { .compatible = "fsl,imx-sc-thermal", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, imx_sc_thermal_table);
+
+static struct platform_driver imx_sc_thermal_driver = {
+               .probe = imx_sc_thermal_probe,
+               .remove = imx_sc_thermal_remove,
+               .driver = {
+                       .name = "imx-sc-thermal",
+                       .of_match_table = imx_sc_thermal_table,
+               },
+};
+module_platform_driver(imx_sc_thermal_driver);
+
+MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
+MODULE_DESCRIPTION("Thermal driver for NXP i.MX SoCs with system controller");
+MODULE_LICENSE("GPL v2");
index bb6754a..e761c9b 100644 (file)
@@ -3,24 +3,17 @@
 // Copyright 2013 Freescale Semiconductor, Inc.
 
 #include <linux/clk.h>
-#include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/cpu_cooling.h>
 #include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
-#include <linux/kernel.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/platform_device.h>
 #include <linux/regmap.h>
-#include <linux/slab.h>
 #include <linux/thermal.h>
-#include <linux/types.h>
 #include <linux/nvmem-consumer.h>
 
 #define REG_SET                0x4
@@ -872,14 +865,12 @@ static int imx_thermal_remove(struct platform_device *pdev)
                clk_disable_unprepare(data->thermal_clk);
 
        thermal_zone_device_unregister(data->tz);
-       cpufreq_cooling_unregister(data->cdev);
-       cpufreq_cpu_put(data->policy);
+       imx_thermal_unregister_legacy_cooling(data);
 
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int imx_thermal_suspend(struct device *dev)
+static int __maybe_unused imx_thermal_suspend(struct device *dev)
 {
        struct imx_thermal_data *data = dev_get_drvdata(dev);
        struct regmap *map = data->tempmon;
@@ -900,7 +891,7 @@ static int imx_thermal_suspend(struct device *dev)
        return 0;
 }
 
-static int imx_thermal_resume(struct device *dev)
+static int __maybe_unused imx_thermal_resume(struct device *dev)
 {
        struct imx_thermal_data *data = dev_get_drvdata(dev);
        struct regmap *map = data->tempmon;
@@ -918,7 +909,6 @@ static int imx_thermal_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
 static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops,
                         imx_thermal_suspend, imx_thermal_resume);
index 6cad15e..ceef89c 100644 (file)
@@ -65,7 +65,7 @@ static ssize_t available_uuids_show(struct device *dev,
        for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; i++) {
                if (priv->uuid_bitmap & (1 << i))
                        if (PAGE_SIZE - length > 0)
-                               length += snprintf(&buf[length],
+                               length += scnprintf(&buf[length],
                                                   PAGE_SIZE - length,
                                                   "%s\n",
                                                   int3400_thermal_uuids[i]);
index b1fd345..297db1d 100644 (file)
@@ -45,6 +45,9 @@
 /* JasperLake thermal reporting device */
 #define PCI_DEVICE_ID_PROC_JSL_THERMAL 0x4503
 
+/* TigerLake thermal reporting device */
+#define PCI_DEVICE_ID_PROC_TGL_THERMAL 0x9A03
+
 #define DRV_NAME "proc_thermal"
 
 struct power_config {
@@ -728,6 +731,8 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_ICL_THERMAL),
                .driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_JSL_THERMAL)},
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_TGL_THERMAL),
+               .driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
        { 0, },
 };
 
index ef0baa9..874a47d 100644 (file)
@@ -449,6 +449,50 @@ thermal_zone_of_add_sensor(struct device_node *zone,
 }
 
 /**
+ * thermal_zone_of_get_sensor_id - get sensor ID from a DT thermal zone
+ * @tz_np: a valid thermal zone device node.
+ * @sensor_np: a sensor node of a valid sensor device.
+ * @id: the sensor ID returned if success.
+ *
+ * This function will get sensor ID from a given thermal zone node and
+ * the sensor node must match the temperature provider @sensor_np.
+ *
+ * Return: 0 on success, proper error code otherwise.
+ */
+
+int thermal_zone_of_get_sensor_id(struct device_node *tz_np,
+                                 struct device_node *sensor_np,
+                                 u32 *id)
+{
+       struct of_phandle_args sensor_specs;
+       int ret;
+
+       ret = of_parse_phandle_with_args(tz_np,
+                                        "thermal-sensors",
+                                        "#thermal-sensor-cells",
+                                        0,
+                                        &sensor_specs);
+       if (ret)
+               return ret;
+
+       if (sensor_specs.np != sensor_np) {
+               of_node_put(sensor_specs.np);
+               return -ENODEV;
+       }
+
+       if (sensor_specs.args_count > 1)
+               pr_warn("%pOFn: too many cells in sensor specifier %d\n",
+                    sensor_specs.np, sensor_specs.args_count);
+
+       *id = sensor_specs.args_count ? sensor_specs.args[0] : 0;
+
+       of_node_put(sensor_specs.np);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(thermal_zone_of_get_sensor_id);
+
+/**
  * thermal_zone_of_sensor_register - registers a sensor to a DT thermal zone
  * @dev: a valid struct device pointer of a sensor device. Must contain
  *       a valid .of_node, for the sensor node.
@@ -499,36 +543,22 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
        sensor_np = of_node_get(dev->of_node);
 
        for_each_available_child_of_node(np, child) {
-               struct of_phandle_args sensor_specs;
                int ret, id;
 
                /* For now, thermal framework supports only 1 sensor per zone */
-               ret = of_parse_phandle_with_args(child, "thermal-sensors",
-                                                "#thermal-sensor-cells",
-                                                0, &sensor_specs);
+               ret = thermal_zone_of_get_sensor_id(child, sensor_np, &id);
                if (ret)
                        continue;
 
-               if (sensor_specs.args_count >= 1) {
-                       id = sensor_specs.args[0];
-                       WARN(sensor_specs.args_count > 1,
-                            "%pOFn: too many cells in sensor specifier %d\n",
-                            sensor_specs.np, sensor_specs.args_count);
-               } else {
-                       id = 0;
-               }
-
-               if (sensor_specs.np == sensor_np && id == sensor_id) {
+               if (id == sensor_id) {
                        tzd = thermal_zone_of_add_sensor(child, sensor_np,
                                                         data, ops);
                        if (!IS_ERR(tzd))
                                tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
 
-                       of_node_put(sensor_specs.np);
                        of_node_put(child);
                        goto exit;
                }
-               of_node_put(sensor_specs.np);
        }
 exit:
        of_node_put(sensor_np);
index fb77acb..2a28a5a 100644 (file)
@@ -245,7 +245,7 @@ static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
        return adc_code * slope + offset;
 }
 
-static int get_temp_8960(struct tsens_sensor *s, int *temp)
+static int get_temp_8960(const struct tsens_sensor *s, int *temp)
 {
        int ret;
        u32 code, trdy;
@@ -279,7 +279,7 @@ static const struct tsens_ops ops_8960 = {
        .resume         = resume_8960,
 };
 
-const struct tsens_plat_data data_8960 = {
+struct tsens_plat_data data_8960 = {
        .num_sensors    = 11,
        .ops            = &ops_8960,
 };
index c8d57ee..1725453 100644 (file)
  * @low_thresh:     lower threshold temperature value
  * @low_irq_mask:   mask register for lower threshold irqs
  * @low_irq_clear:  clear register for lower threshold irqs
+ * @crit_viol:      critical threshold violated
+ * @crit_thresh:    critical threshold temperature value
+ * @crit_irq_mask:  mask register for critical threshold irqs
+ * @crit_irq_clear: clear register for critical threshold irqs
  *
  * Structure containing data about temperature threshold settings and
  * irq status if they were violated.
@@ -36,6 +40,10 @@ struct tsens_irq_data {
        int low_thresh;
        u32 low_irq_mask;
        u32 low_irq_clear;
+       u32 crit_viol;
+       u32 crit_thresh;
+       u32 crit_irq_mask;
+       u32 crit_irq_clear;
 };
 
 char *qfprom_read(struct device *dev, const char *cname)
@@ -128,7 +136,7 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
  * Return: Temperature in milliCelsius on success, a negative errno will
  * be returned in error cases
  */
-static int tsens_hw_to_mC(struct tsens_sensor *s, int field)
+static int tsens_hw_to_mC(const struct tsens_sensor *s, int field)
 {
        struct tsens_priv *priv = s->priv;
        u32 resolution;
@@ -160,7 +168,7 @@ static int tsens_hw_to_mC(struct tsens_sensor *s, int field)
  *
  * Return: ADC code or temperature in deciCelsius.
  */
-static int tsens_mC_to_hw(struct tsens_sensor *s, int temp)
+static int tsens_mC_to_hw(const struct tsens_sensor *s, int temp)
 {
        struct tsens_priv *priv = s->priv;
 
@@ -189,6 +197,9 @@ static void tsens_set_interrupt_v1(struct tsens_priv *priv, u32 hw_id,
        case LOWER:
                index = LOW_INT_CLEAR_0 + hw_id;
                break;
+       case CRITICAL:
+               /* No critical interrupts before v2 */
+               return;
        }
        regmap_field_write(priv->rf[index], enable ? 0 : 1);
 }
@@ -214,6 +225,10 @@ static void tsens_set_interrupt_v2(struct tsens_priv *priv, u32 hw_id,
                index_mask  = LOW_INT_MASK_0 + hw_id;
                index_clear = LOW_INT_CLEAR_0 + hw_id;
                break;
+       case CRITICAL:
+               index_mask  = CRIT_INT_MASK_0 + hw_id;
+               index_clear = CRIT_INT_CLEAR_0 + hw_id;
+               break;
        }
 
        if (enable) {
@@ -268,14 +283,23 @@ static int tsens_threshold_violated(struct tsens_priv *priv, u32 hw_id,
        ret = regmap_field_read(priv->rf[LOWER_STATUS_0 + hw_id], &d->low_viol);
        if (ret)
                return ret;
-       if (d->up_viol || d->low_viol)
+
+       if (priv->feat->crit_int) {
+               ret = regmap_field_read(priv->rf[CRITICAL_STATUS_0 + hw_id],
+                                       &d->crit_viol);
+               if (ret)
+                       return ret;
+       }
+
+       if (d->up_viol || d->low_viol || d->crit_viol)
                return 1;
 
        return 0;
 }
 
 static int tsens_read_irq_state(struct tsens_priv *priv, u32 hw_id,
-                               struct tsens_sensor *s, struct tsens_irq_data *d)
+                               const struct tsens_sensor *s,
+                               struct tsens_irq_data *d)
 {
        int ret;
 
@@ -292,22 +316,37 @@ static int tsens_read_irq_state(struct tsens_priv *priv, u32 hw_id,
                ret = regmap_field_read(priv->rf[LOW_INT_MASK_0 + hw_id], &d->low_irq_mask);
                if (ret)
                        return ret;
+               ret = regmap_field_read(priv->rf[CRIT_INT_CLEAR_0 + hw_id],
+                                       &d->crit_irq_clear);
+               if (ret)
+                       return ret;
+               ret = regmap_field_read(priv->rf[CRIT_INT_MASK_0 + hw_id],
+                                       &d->crit_irq_mask);
+               if (ret)
+                       return ret;
+
+               d->crit_thresh = tsens_hw_to_mC(s, CRIT_THRESH_0 + hw_id);
        } else {
                /* No mask register on older TSENS */
                d->up_irq_mask = 0;
                d->low_irq_mask = 0;
+               d->crit_irq_clear = 0;
+               d->crit_irq_mask = 0;
+               d->crit_thresh = 0;
        }
 
        d->up_thresh  = tsens_hw_to_mC(s, UP_THRESH_0 + hw_id);
        d->low_thresh = tsens_hw_to_mC(s, LOW_THRESH_0 + hw_id);
 
-       dev_dbg(priv->dev, "[%u] %s%s: status(%u|%u) | clr(%u|%u) | mask(%u|%u)\n",
-               hw_id, __func__, (d->up_viol || d->low_viol) ? "(V)" : "",
-               d->low_viol, d->up_viol, d->low_irq_clear, d->up_irq_clear,
-               d->low_irq_mask, d->up_irq_mask);
-       dev_dbg(priv->dev, "[%u] %s%s: thresh: (%d:%d)\n", hw_id, __func__,
-               (d->up_viol || d->low_viol) ? "(violation)" : "",
-               d->low_thresh, d->up_thresh);
+       dev_dbg(priv->dev, "[%u] %s%s: status(%u|%u|%u) | clr(%u|%u|%u) | mask(%u|%u|%u)\n",
+               hw_id, __func__,
+               (d->up_viol || d->low_viol || d->crit_viol) ? "(V)" : "",
+               d->low_viol, d->up_viol, d->crit_viol,
+               d->low_irq_clear, d->up_irq_clear, d->crit_irq_clear,
+               d->low_irq_mask, d->up_irq_mask, d->crit_irq_mask);
+       dev_dbg(priv->dev, "[%u] %s%s: thresh: (%d:%d:%d)\n", hw_id, __func__,
+               (d->up_viol || d->low_viol || d->crit_viol) ? "(V)" : "",
+               d->low_thresh, d->up_thresh, d->crit_thresh);
 
        return 0;
 }
@@ -322,6 +361,76 @@ static inline u32 masked_irq(u32 hw_id, u32 mask, enum tsens_ver ver)
 }
 
 /**
+ * tsens_critical_irq_thread() - Threaded handler for critical interrupts
+ * @irq: irq number
+ * @data: tsens controller private data
+ *
+ * Check FSM watchdog bark status and clear if needed.
+ * Check all sensors to find ones that violated their critical threshold limits.
+ * Clear and then re-enable the interrupt.
+ *
+ * The level-triggered interrupt might deassert if the temperature returned to
+ * within the threshold limits by the time the handler got scheduled. We
+ * consider the irq to have been handled in that case.
+ *
+ * Return: IRQ_HANDLED
+ */
+irqreturn_t tsens_critical_irq_thread(int irq, void *data)
+{
+       struct tsens_priv *priv = data;
+       struct tsens_irq_data d;
+       int temp, ret, i;
+       u32 wdog_status, wdog_count;
+
+       if (priv->feat->has_watchdog) {
+               ret = regmap_field_read(priv->rf[WDOG_BARK_STATUS],
+                                       &wdog_status);
+               if (ret)
+                       return ret;
+
+               if (wdog_status) {
+                       /* Clear WDOG interrupt */
+                       regmap_field_write(priv->rf[WDOG_BARK_CLEAR], 1);
+                       regmap_field_write(priv->rf[WDOG_BARK_CLEAR], 0);
+                       ret = regmap_field_read(priv->rf[WDOG_BARK_COUNT],
+                                               &wdog_count);
+                       if (ret)
+                               return ret;
+                       if (wdog_count)
+                               dev_dbg(priv->dev, "%s: watchdog count: %d\n",
+                                       __func__, wdog_count);
+
+                       /* Fall through to handle critical interrupts if any */
+               }
+       }
+
+       for (i = 0; i < priv->num_sensors; i++) {
+               const struct tsens_sensor *s = &priv->sensor[i];
+               u32 hw_id = s->hw_id;
+
+               if (IS_ERR(s->tzd))
+                       continue;
+               if (!tsens_threshold_violated(priv, hw_id, &d))
+                       continue;
+               ret = get_temp_tsens_valid(s, &temp);
+               if (ret) {
+                       dev_err(priv->dev, "[%u] %s: error reading sensor\n",
+                               hw_id, __func__);
+                       continue;
+               }
+
+               tsens_read_irq_state(priv, hw_id, s, &d);
+               if (d.crit_viol &&
+                   !masked_irq(hw_id, d.crit_irq_mask, tsens_version(priv))) {
+                       /* Mask critical interrupts, unused on Linux */
+                       tsens_set_interrupt(priv, hw_id, CRITICAL, false);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+/**
  * tsens_irq_thread - Threaded interrupt handler for uplow interrupts
  * @irq: irq number
  * @data: tsens controller private data
@@ -346,10 +455,10 @@ irqreturn_t tsens_irq_thread(int irq, void *data)
 
        for (i = 0; i < priv->num_sensors; i++) {
                bool trigger = false;
-               struct tsens_sensor *s = &priv->sensor[i];
+               const struct tsens_sensor *s = &priv->sensor[i];
                u32 hw_id = s->hw_id;
 
-               if (IS_ERR(priv->sensor[i].tzd))
+               if (IS_ERR(s->tzd))
                        continue;
                if (!tsens_threshold_violated(priv, hw_id, &d))
                        continue;
@@ -368,7 +477,7 @@ irqreturn_t tsens_irq_thread(int irq, void *data)
                        tsens_set_interrupt(priv, hw_id, UPPER, disable);
                        if (d.up_thresh > temp) {
                                dev_dbg(priv->dev, "[%u] %s: re-arm upper\n",
-                                       priv->sensor[i].hw_id, __func__);
+                                       hw_id, __func__);
                                tsens_set_interrupt(priv, hw_id, UPPER, enable);
                        } else {
                                trigger = true;
@@ -379,7 +488,7 @@ irqreturn_t tsens_irq_thread(int irq, void *data)
                        tsens_set_interrupt(priv, hw_id, LOWER, disable);
                        if (d.low_thresh < temp) {
                                dev_dbg(priv->dev, "[%u] %s: re-arm low\n",
-                                       priv->sensor[i].hw_id, __func__);
+                                       hw_id, __func__);
                                tsens_set_interrupt(priv, hw_id, LOWER, enable);
                        } else {
                                trigger = true;
@@ -392,7 +501,7 @@ irqreturn_t tsens_irq_thread(int irq, void *data)
                if (trigger) {
                        dev_dbg(priv->dev, "[%u] %s: TZ update trigger (%d mC)\n",
                                hw_id, __func__, temp);
-                       thermal_zone_device_update(priv->sensor[i].tzd,
+                       thermal_zone_device_update(s->tzd,
                                                   THERMAL_EVENT_UNSPECIFIED);
                } else {
                        dev_dbg(priv->dev, "[%u] %s: no violation:  %d\n",
@@ -435,7 +544,7 @@ int tsens_set_trips(void *_sensor, int low, int high)
        spin_unlock_irqrestore(&priv->ul_lock, flags);
 
        dev_dbg(dev, "[%u] %s: (%d:%d)->(%d:%d)\n",
-               s->hw_id, __func__, d.low_thresh, d.up_thresh, cl_low, cl_high);
+               hw_id, __func__, d.low_thresh, d.up_thresh, cl_low, cl_high);
 
        return 0;
 }
@@ -457,7 +566,7 @@ void tsens_disable_irq(struct tsens_priv *priv)
        regmap_field_write(priv->rf[INT_EN], 0);
 }
 
-int get_temp_tsens_valid(struct tsens_sensor *s, int *temp)
+int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
 {
        struct tsens_priv *priv = s->priv;
        int hw_id = s->hw_id;
@@ -486,7 +595,7 @@ int get_temp_tsens_valid(struct tsens_sensor *s, int *temp)
        return 0;
 }
 
-int get_temp_common(struct tsens_sensor *s, int *temp)
+int get_temp_common(const struct tsens_sensor *s, int *temp)
 {
        struct tsens_priv *priv = s->priv;
        int hw_id = s->hw_id;
@@ -590,6 +699,7 @@ int __init init_common(struct tsens_priv *priv)
 {
        void __iomem *tm_base, *srot_base;
        struct device *dev = priv->dev;
+       u32 ver_minor;
        struct resource *res;
        u32 enabled;
        int ret, i, j;
@@ -602,7 +712,7 @@ int __init init_common(struct tsens_priv *priv)
                /* DT with separate SROT and TM address space */
                priv->tm_offset = 0;
                res = platform_get_resource(op, IORESOURCE_MEM, 1);
-               srot_base = devm_ioremap_resource(&op->dev, res);
+               srot_base = devm_ioremap_resource(dev, res);
                if (IS_ERR(srot_base)) {
                        ret = PTR_ERR(srot_base);
                        goto err_put_device;
@@ -620,7 +730,7 @@ int __init init_common(struct tsens_priv *priv)
        }
 
        res = platform_get_resource(op, IORESOURCE_MEM, 0);
-       tm_base = devm_ioremap_resource(&op->dev, res);
+       tm_base = devm_ioremap_resource(dev, res);
        if (IS_ERR(tm_base)) {
                ret = PTR_ERR(tm_base);
                goto err_put_device;
@@ -639,6 +749,9 @@ int __init init_common(struct tsens_priv *priv)
                        if (IS_ERR(priv->rf[i]))
                                return PTR_ERR(priv->rf[i]);
                }
+               ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor);
+               if (ret)
+                       goto err_put_device;
        }
 
        priv->rf[TSENS_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
@@ -683,12 +796,47 @@ int __init init_common(struct tsens_priv *priv)
                }
        }
 
+       if (priv->feat->crit_int) {
+               /* Loop might need changes if enum regfield_ids is reordered */
+               for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) {
+                       for (i = 0; i < priv->feat->max_sensors; i++) {
+                               int idx = j + i;
+
+                               priv->rf[idx] =
+                                       devm_regmap_field_alloc(dev,
+                                                               priv->tm_map,
+                                                               priv->fields[idx]);
+                               if (IS_ERR(priv->rf[idx])) {
+                                       ret = PTR_ERR(priv->rf[idx]);
+                                       goto err_put_device;
+                               }
+                       }
+               }
+       }
+
+       if (tsens_version(priv) > VER_1_X &&  ver_minor > 2) {
+               /* Watchdog is present only on v2.3+ */
+               priv->feat->has_watchdog = 1;
+               for (i = WDOG_BARK_STATUS; i <= CC_MON_MASK; i++) {
+                       priv->rf[i] = devm_regmap_field_alloc(dev, priv->tm_map,
+                                                             priv->fields[i]);
+                       if (IS_ERR(priv->rf[i])) {
+                               ret = PTR_ERR(priv->rf[i]);
+                               goto err_put_device;
+                       }
+               }
+               /*
+                * Watchdog is already enabled, unmask the bark.
+                * Disable cycle completion monitoring
+                */
+               regmap_field_write(priv->rf[WDOG_BARK_MASK], 0);
+               regmap_field_write(priv->rf[CC_MON_MASK], 1);
+       }
+
        spin_lock_init(&priv->ul_lock);
        tsens_enable_irq(priv);
        tsens_debug_init(op);
 
-       return 0;
-
 err_put_device:
        put_device(&op->dev);
        return ret;
index 4b8dd6d..959a937 100644 (file)
@@ -327,7 +327,7 @@ static int calibrate_8974(struct tsens_priv *priv)
 
 /* v0.1: 8916, 8974 */
 
-static const struct tsens_features tsens_v0_1_feat = {
+static struct tsens_features tsens_v0_1_feat = {
        .ver_major      = VER_0_1,
        .crit_int       = 0,
        .adc            = 1,
@@ -377,7 +377,7 @@ static const struct tsens_ops ops_8916 = {
        .get_temp       = get_temp_common,
 };
 
-const struct tsens_plat_data data_8916 = {
+struct tsens_plat_data data_8916 = {
        .num_sensors    = 5,
        .ops            = &ops_8916,
        .hw_ids         = (unsigned int []){0, 1, 2, 4, 5 },
@@ -392,7 +392,7 @@ static const struct tsens_ops ops_8974 = {
        .get_temp       = get_temp_common,
 };
 
-const struct tsens_plat_data data_8974 = {
+struct tsens_plat_data data_8974 = {
        .num_sensors    = 11,
        .ops            = &ops_8974,
        .feat           = &tsens_v0_1_feat,
index bd2ddb6..b682a4d 100644 (file)
@@ -299,7 +299,7 @@ static int calibrate_8976(struct tsens_priv *priv)
 
 /* v1.x: msm8956,8976,qcs404,405 */
 
-static const struct tsens_features tsens_v1_feat = {
+static struct tsens_features tsens_v1_feat = {
        .ver_major      = VER_1_X,
        .crit_int       = 0,
        .adc            = 1,
@@ -368,7 +368,7 @@ static const struct tsens_ops ops_generic_v1 = {
        .get_temp       = get_temp_tsens_valid,
 };
 
-const struct tsens_plat_data data_tsens_v1 = {
+struct tsens_plat_data data_tsens_v1 = {
        .ops            = &ops_generic_v1,
        .feat           = &tsens_v1_feat,
        .fields = tsens_v1_regfields,
@@ -381,7 +381,7 @@ static const struct tsens_ops ops_8976 = {
 };
 
 /* Valid for both MSM8956 and MSM8976. Sensor ID 3 is unused. */
-const struct tsens_plat_data data_8976 = {
+struct tsens_plat_data data_8976 = {
        .num_sensors    = 11,
        .ops            = &ops_8976,
        .hw_ids         = (unsigned int[]){0, 1, 2, 4, 5, 6, 7, 8, 9, 10},
index a4d15e1..b293ed3 100644 (file)
 #define TM_Sn_CRITICAL_THRESHOLD_OFF   0x0060
 #define TM_Sn_STATUS_OFF               0x00a0
 #define TM_TRDY_OFF                    0x00e4
+#define TM_WDOG_LOG_OFF                0x013c
 
 /* v2.x: 8996, 8998, sdm845 */
 
-static const struct tsens_features tsens_v2_feat = {
+static struct tsens_features tsens_v2_feat = {
        .ver_major      = VER_2_X,
        .crit_int       = 1,
        .adc            = 0,
@@ -51,8 +52,9 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
        [INT_EN]  = REG_FIELD(TM_INT_EN_OFF, 0, 2),
 
        /* TEMPERATURE THRESHOLDS */
-       REG_FIELD_FOR_EACH_SENSOR16(LOW_THRESH, TM_Sn_UPPER_LOWER_THRESHOLD_OFF,  0,  11),
-       REG_FIELD_FOR_EACH_SENSOR16(UP_THRESH,  TM_Sn_UPPER_LOWER_THRESHOLD_OFF, 12,  23),
+       REG_FIELD_FOR_EACH_SENSOR16(LOW_THRESH,  TM_Sn_UPPER_LOWER_THRESHOLD_OFF,  0,  11),
+       REG_FIELD_FOR_EACH_SENSOR16(UP_THRESH,   TM_Sn_UPPER_LOWER_THRESHOLD_OFF, 12,  23),
+       REG_FIELD_FOR_EACH_SENSOR16(CRIT_THRESH, TM_Sn_CRITICAL_THRESHOLD_OFF,     0,  11),
 
        /* INTERRUPTS [CLEAR/STATUS/MASK] */
        REG_FIELD_SPLIT_BITS_0_15(LOW_INT_STATUS,  TM_UPPER_LOWER_INT_STATUS_OFF),
@@ -61,6 +63,18 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
        REG_FIELD_SPLIT_BITS_16_31(UP_INT_STATUS,  TM_UPPER_LOWER_INT_STATUS_OFF),
        REG_FIELD_SPLIT_BITS_16_31(UP_INT_CLEAR,   TM_UPPER_LOWER_INT_CLEAR_OFF),
        REG_FIELD_SPLIT_BITS_16_31(UP_INT_MASK,    TM_UPPER_LOWER_INT_MASK_OFF),
+       REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_STATUS, TM_CRITICAL_INT_STATUS_OFF),
+       REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_CLEAR,  TM_CRITICAL_INT_CLEAR_OFF),
+       REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_MASK,   TM_CRITICAL_INT_MASK_OFF),
+
+       /* WATCHDOG on v2.3 or later */
+       [WDOG_BARK_STATUS] = REG_FIELD(TM_CRITICAL_INT_STATUS_OFF, 31, 31),
+       [WDOG_BARK_CLEAR]  = REG_FIELD(TM_CRITICAL_INT_CLEAR_OFF,  31, 31),
+       [WDOG_BARK_MASK]   = REG_FIELD(TM_CRITICAL_INT_MASK_OFF,   31, 31),
+       [CC_MON_STATUS]    = REG_FIELD(TM_CRITICAL_INT_STATUS_OFF, 30, 30),
+       [CC_MON_CLEAR]     = REG_FIELD(TM_CRITICAL_INT_CLEAR_OFF,  30, 30),
+       [CC_MON_MASK]      = REG_FIELD(TM_CRITICAL_INT_MASK_OFF,   30, 30),
+       [WDOG_BARK_COUNT]  = REG_FIELD(TM_WDOG_LOG_OFF,             0,  7),
 
        /* Sn_STATUS */
        REG_FIELD_FOR_EACH_SENSOR16(LAST_TEMP,       TM_Sn_STATUS_OFF,  0,  11),
@@ -81,14 +95,14 @@ static const struct tsens_ops ops_generic_v2 = {
        .get_temp       = get_temp_tsens_valid,
 };
 
-const struct tsens_plat_data data_tsens_v2 = {
+struct tsens_plat_data data_tsens_v2 = {
        .ops            = &ops_generic_v2,
        .feat           = &tsens_v2_feat,
        .fields = tsens_v2_regfields,
 };
 
 /* Kept around for backward compatibility with old msm8996.dtsi */
-const struct tsens_plat_data data_8996 = {
+struct tsens_plat_data data_8996 = {
        .num_sensors    = 13,
        .ops            = &ops_generic_v2,
        .feat           = &tsens_v2_feat,
index 0e7cf52..2f77d23 100644 (file)
@@ -85,11 +85,42 @@ static const struct thermal_zone_of_device_ops tsens_of_ops = {
        .set_trips = tsens_set_trips,
 };
 
+static int tsens_register_irq(struct tsens_priv *priv, char *irqname,
+                             irq_handler_t thread_fn)
+{
+       struct platform_device *pdev;
+       int ret, irq;
+
+       pdev = of_find_device_by_node(priv->dev->of_node);
+       if (!pdev)
+               return -ENODEV;
+
+       irq = platform_get_irq_byname(pdev, irqname);
+       if (irq < 0) {
+               ret = irq;
+               /* For old DTs with no IRQ defined */
+               if (irq == -ENXIO)
+                       ret = 0;
+       } else {
+               ret = devm_request_threaded_irq(&pdev->dev, irq,
+                                               NULL, thread_fn,
+                                               IRQF_ONESHOT,
+                                               dev_name(&pdev->dev), priv);
+               if (ret)
+                       dev_err(&pdev->dev, "%s: failed to get irq\n",
+                               __func__);
+               else
+                       enable_irq_wake(irq);
+       }
+
+       put_device(&pdev->dev);
+       return ret;
+}
+
 static int tsens_register(struct tsens_priv *priv)
 {
-       int i, ret, irq;
+       int i, ret;
        struct thermal_zone_device *tzd;
-       struct platform_device *pdev;
 
        for (i = 0;  i < priv->num_sensors; i++) {
                priv->sensor[i].priv = priv;
@@ -103,32 +134,14 @@ static int tsens_register(struct tsens_priv *priv)
                        priv->ops->enable(priv, i);
        }
 
-       pdev = of_find_device_by_node(priv->dev->of_node);
-       if (!pdev)
-               return -ENODEV;
-
-       irq = platform_get_irq_byname(pdev, "uplow");
-       if (irq < 0) {
-               ret = irq;
-               /* For old DTs with no IRQ defined */
-               if (irq == -ENXIO)
-                       ret = 0;
-               goto err_put_device;
-       }
-
-       ret = devm_request_threaded_irq(&pdev->dev, irq,
-                                       NULL, tsens_irq_thread,
-                                       IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
-                                       dev_name(&pdev->dev), priv);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to get irq\n", __func__);
-               goto err_put_device;
-       }
+       ret = tsens_register_irq(priv, "uplow", tsens_irq_thread);
+       if (ret < 0)
+               return ret;
 
-       enable_irq_wake(irq);
+       if (priv->feat->crit_int)
+               ret = tsens_register_irq(priv, "critical",
+                                        tsens_critical_irq_thread);
 
-err_put_device:
-       put_device(&pdev->dev);
        return ret;
 }
 
index e24a865..502acf0 100644 (file)
@@ -23,6 +23,7 @@
 
 struct tsens_priv;
 
+/* IP version numbers in ascending order */
 enum tsens_ver {
        VER_0_1 = 0,
        VER_1_X,
@@ -32,6 +33,7 @@ enum tsens_ver {
 enum tsens_irq_type {
        LOWER,
        UPPER,
+       CRITICAL,
 };
 
 /**
@@ -67,7 +69,7 @@ struct tsens_ops {
        /* mandatory callbacks */
        int (*init)(struct tsens_priv *priv);
        int (*calibrate)(struct tsens_priv *priv);
-       int (*get_temp)(struct tsens_sensor *s, int *temp);
+       int (*get_temp)(const struct tsens_sensor *s, int *temp);
        /* optional callbacks */
        int (*enable)(struct tsens_priv *priv, int i);
        void (*disable)(struct tsens_priv *priv);
@@ -374,6 +376,82 @@ enum regfield_ids {
        CRITICAL_STATUS_13,
        CRITICAL_STATUS_14,
        CRITICAL_STATUS_15,
+       CRIT_INT_STATUS_0,      /* CRITICAL interrupt status */
+       CRIT_INT_STATUS_1,
+       CRIT_INT_STATUS_2,
+       CRIT_INT_STATUS_3,
+       CRIT_INT_STATUS_4,
+       CRIT_INT_STATUS_5,
+       CRIT_INT_STATUS_6,
+       CRIT_INT_STATUS_7,
+       CRIT_INT_STATUS_8,
+       CRIT_INT_STATUS_9,
+       CRIT_INT_STATUS_10,
+       CRIT_INT_STATUS_11,
+       CRIT_INT_STATUS_12,
+       CRIT_INT_STATUS_13,
+       CRIT_INT_STATUS_14,
+       CRIT_INT_STATUS_15,
+       CRIT_INT_CLEAR_0,       /* CRITICAL interrupt clear */
+       CRIT_INT_CLEAR_1,
+       CRIT_INT_CLEAR_2,
+       CRIT_INT_CLEAR_3,
+       CRIT_INT_CLEAR_4,
+       CRIT_INT_CLEAR_5,
+       CRIT_INT_CLEAR_6,
+       CRIT_INT_CLEAR_7,
+       CRIT_INT_CLEAR_8,
+       CRIT_INT_CLEAR_9,
+       CRIT_INT_CLEAR_10,
+       CRIT_INT_CLEAR_11,
+       CRIT_INT_CLEAR_12,
+       CRIT_INT_CLEAR_13,
+       CRIT_INT_CLEAR_14,
+       CRIT_INT_CLEAR_15,
+       CRIT_INT_MASK_0,        /* CRITICAL interrupt mask */
+       CRIT_INT_MASK_1,
+       CRIT_INT_MASK_2,
+       CRIT_INT_MASK_3,
+       CRIT_INT_MASK_4,
+       CRIT_INT_MASK_5,
+       CRIT_INT_MASK_6,
+       CRIT_INT_MASK_7,
+       CRIT_INT_MASK_8,
+       CRIT_INT_MASK_9,
+       CRIT_INT_MASK_10,
+       CRIT_INT_MASK_11,
+       CRIT_INT_MASK_12,
+       CRIT_INT_MASK_13,
+       CRIT_INT_MASK_14,
+       CRIT_INT_MASK_15,
+       CRIT_THRESH_0,          /* CRITICAL threshold values */
+       CRIT_THRESH_1,
+       CRIT_THRESH_2,
+       CRIT_THRESH_3,
+       CRIT_THRESH_4,
+       CRIT_THRESH_5,
+       CRIT_THRESH_6,
+       CRIT_THRESH_7,
+       CRIT_THRESH_8,
+       CRIT_THRESH_9,
+       CRIT_THRESH_10,
+       CRIT_THRESH_11,
+       CRIT_THRESH_12,
+       CRIT_THRESH_13,
+       CRIT_THRESH_14,
+       CRIT_THRESH_15,
+
+       /* WATCHDOG */
+       WDOG_BARK_STATUS,
+       WDOG_BARK_CLEAR,
+       WDOG_BARK_MASK,
+       WDOG_BARK_COUNT,
+
+       /* CYCLE COMPLETION MONITOR */
+       CC_MON_STATUS,
+       CC_MON_CLEAR,
+       CC_MON_MASK,
+
        MIN_STATUS_0,           /* MIN threshold violated */
        MIN_STATUS_1,
        MIN_STATUS_2,
@@ -418,6 +496,7 @@ enum regfield_ids {
  * @adc:      do the sensors only output adc code (instead of temperature)?
  * @srot_split: does the IP neatly splits the register space into SROT and TM,
  *              with SROT only being available to secure boot firmware?
+ * @has_watchdog: does this IP support watchdog functionality?
  * @max_sensors: maximum sensors supported by this version of the IP
  */
 struct tsens_features {
@@ -425,6 +504,7 @@ struct tsens_features {
        unsigned int crit_int:1;
        unsigned int adc:1;
        unsigned int srot_split:1;
+       unsigned int has_watchdog:1;
        unsigned int max_sensors;
 };
 
@@ -440,12 +520,14 @@ struct tsens_plat_data {
        const u32               num_sensors;
        const struct tsens_ops  *ops;
        unsigned int            *hw_ids;
-       const struct tsens_features     *feat;
+       struct tsens_features   *feat;
        const struct reg_field          *fields;
 };
 
 /**
  * struct tsens_context - Registers to be saved/restored across a context loss
+ * @threshold: Threshold register value
+ * @control: Control register value
  */
 struct tsens_context {
        int     threshold;
@@ -460,6 +542,8 @@ struct tsens_context {
  * @srot_map: pointer to SROT register address space
  * @tm_offset: deal with old device trees that don't address TM and SROT
  *             address space separately
+ * @ul_lock: lock while processing upper/lower threshold interrupts
+ * @crit_lock: lock while processing critical threshold interrupts
  * @rf: array of regmap_fields used to store value of the field
  * @ctx: registers to be saved and restored during suspend/resume
  * @feat: features of the IP
@@ -481,36 +565,37 @@ struct tsens_priv {
 
        struct regmap_field             *rf[MAX_REGFIELDS];
        struct tsens_context            ctx;
-       const struct tsens_features     *feat;
+       struct tsens_features           *feat;
        const struct reg_field          *fields;
        const struct tsens_ops          *ops;
 
        struct dentry                   *debug_root;
        struct dentry                   *debug;
 
-       struct tsens_sensor             sensor[0];
+       struct tsens_sensor             sensor[];
 };
 
 char *qfprom_read(struct device *dev, const char *cname);
 void compute_intercept_slope(struct tsens_priv *priv, u32 *pt1, u32 *pt2, u32 mode);
 int init_common(struct tsens_priv *priv);
-int get_temp_tsens_valid(struct tsens_sensor *s, int *temp);
-int get_temp_common(struct tsens_sensor *s, int *temp);
+int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp);
+int get_temp_common(const struct tsens_sensor *s, int *temp);
 int tsens_enable_irq(struct tsens_priv *priv);
 void tsens_disable_irq(struct tsens_priv *priv);
 int tsens_set_trips(void *_sensor, int low, int high);
 irqreturn_t tsens_irq_thread(int irq, void *data);
+irqreturn_t tsens_critical_irq_thread(int irq, void *data);
 
 /* TSENS target */
-extern const struct tsens_plat_data data_8960;
+extern struct tsens_plat_data data_8960;
 
 /* TSENS v0.1 targets */
-extern const struct tsens_plat_data data_8916, data_8974;
+extern struct tsens_plat_data data_8916, data_8974;
 
 /* TSENS v1 targets */
-extern const struct tsens_plat_data data_tsens_v1, data_8976;
+extern struct tsens_plat_data data_tsens_v1, data_8976;
 
 /* TSENS v2 targets */
-extern const struct tsens_plat_data data_8996, data_tsens_v2;
+extern struct tsens_plat_data data_8996, data_tsens_v2;
 
 #endif /* __QCOM_TSENS_H__ */
index 874bc46..028a6bb 100644 (file)
@@ -3,12 +3,11 @@
 // Copyright 2016 Freescale Semiconductor, Inc.
 
 #include <linux/clk.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_address.h>
+#include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/sizes.h>
 #include <linux/thermal.h>
@@ -228,6 +227,14 @@ static const struct regmap_access_table qoriq_rd_table = {
        .n_yes_ranges   = ARRAY_SIZE(qoriq_yes_ranges),
 };
 
+static void qoriq_tmu_action(void *p)
+{
+       struct qoriq_tmu_data *data = p;
+
+       regmap_write(data->regmap, REGS_TMR, TMR_DISABLE);
+       clk_disable_unprepare(data->clk);
+}
+
 static int qoriq_tmu_probe(struct platform_device *pdev)
 {
        int ret;
@@ -278,6 +285,10 @@ static int qoriq_tmu_probe(struct platform_device *pdev)
                return ret;
        }
 
+       ret = devm_add_action_or_reset(dev, qoriq_tmu_action, data);
+       if (ret)
+               return ret;
+
        /* version register offset at: 0xbf8 on both v1 and v2 */
        ret = regmap_read(data->regmap, REGS_IPBRR(0), &ver);
        if (ret) {
@@ -290,35 +301,17 @@ static int qoriq_tmu_probe(struct platform_device *pdev)
 
        ret = qoriq_tmu_calibration(dev, data); /* TMU calibration */
        if (ret < 0)
-               goto err;
+               return ret;
 
        ret = qoriq_tmu_register_tmu_zone(dev, data);
        if (ret < 0) {
                dev_err(dev, "Failed to register sensors\n");
-               ret = -ENODEV;
-               goto err;
+               return ret;
        }
 
        platform_set_drvdata(pdev, data);
 
        return 0;
-
-err:
-       clk_disable_unprepare(data->clk);
-
-       return ret;
-}
-
-static int qoriq_tmu_remove(struct platform_device *pdev)
-{
-       struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
-
-       /* Disable monitoring */
-       regmap_write(data->regmap, REGS_TMR, TMR_DISABLE);
-
-       clk_disable_unprepare(data->clk);
-
-       return 0;
 }
 
 static int __maybe_unused qoriq_tmu_suspend(struct device *dev)
@@ -365,7 +358,6 @@ static struct platform_driver qoriq_tmu = {
                .of_match_table = qoriq_tmu_match,
        },
        .probe  = qoriq_tmu_probe,
-       .remove = qoriq_tmu_remove,
 };
 module_platform_driver(qoriq_tmu);
 
index 72877bd..58fe7c1 100644 (file)
@@ -81,8 +81,6 @@ struct rcar_gen3_thermal_tsc {
        void __iomem *base;
        struct thermal_zone_device *zone;
        struct equation_coefs coef;
-       int low;
-       int high;
        int tj_t;
        int id; /* thermal channel id */
 };
@@ -204,12 +202,14 @@ static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,
        return INT_FIXPT(val);
 }
 
-static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high)
+static int rcar_gen3_thermal_update_range(struct rcar_gen3_thermal_tsc *tsc)
 {
-       struct rcar_gen3_thermal_tsc *tsc = devdata;
+       int temperature, low, high;
+
+       rcar_gen3_thermal_get_temp(tsc, &temperature);
 
-       low = clamp_val(low, -40000, 120000);
-       high = clamp_val(high, -40000, 120000);
+       low = temperature - MCELSIUS(1);
+       high = temperature + MCELSIUS(1);
 
        rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1,
                                rcar_gen3_thermal_mcelsius_to_temp(tsc, low));
@@ -217,15 +217,11 @@ static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high)
        rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2,
                                rcar_gen3_thermal_mcelsius_to_temp(tsc, high));
 
-       tsc->low = low;
-       tsc->high = high;
-
        return 0;
 }
 
 static const struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
        .get_temp       = rcar_gen3_thermal_get_temp,
-       .set_trips      = rcar_gen3_thermal_set_trips,
 };
 
 static void rcar_thermal_irq_set(struct rcar_gen3_thermal_priv *priv, bool on)
@@ -246,9 +242,11 @@ static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
        for (i = 0; i < priv->num_tscs; i++) {
                status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR);
                rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0);
-               if (status)
+               if (status) {
+                       rcar_gen3_thermal_update_range(priv->tscs[i]);
                        thermal_zone_device_update(priv->tscs[i]->zone,
                                                   THERMAL_EVENT_UNSPECIFIED);
+               }
        }
 
        return IRQ_HANDLED;
@@ -325,6 +323,10 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
                .data = &rcar_gen3_ths_tj_1_m3_w,
        },
        {
+               .compatible = "renesas,r8a77961-thermal",
+               .data = &rcar_gen3_ths_tj_1_m3_w,
+       },
+       {
                .compatible = "renesas,r8a77965-thermal",
                .data = &rcar_gen3_ths_tj_1,
        },
@@ -446,14 +448,15 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
                        goto error_unregister;
 
                ret = devm_add_action_or_reset(dev, rcar_gen3_hwmon_action, zone);
-               if (ret) {
+               if (ret)
                        goto error_unregister;
-               }
 
                ret = of_thermal_get_ntrips(tsc->zone);
                if (ret < 0)
                        goto error_unregister;
 
+               rcar_gen3_thermal_update_range(tsc);
+
                dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret);
        }
 
@@ -492,7 +495,7 @@ static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev)
                struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
 
                priv->thermal_init(tsc);
-               rcar_gen3_thermal_set_trips(tsc, tsc->low, tsc->high);
+               rcar_gen3_thermal_update_range(tsc);
        }
 
        rcar_thermal_irq_set(priv, true);
index 8f1aafa..e0c1f24 100644 (file)
@@ -95,7 +95,6 @@ struct rcar_thermal_priv {
        struct mutex lock;
        struct list_head list;
        int id;
-       u32 ctemp;
 };
 
 #define rcar_thermal_for_each_priv(pos, common)        \
@@ -201,7 +200,6 @@ static int rcar_thermal_update_temp(struct rcar_thermal_priv *priv)
        struct device *dev = rcar_priv_to_dev(priv);
        int i;
        u32 ctemp, old, new;
-       int ret = -EINVAL;
 
        mutex_lock(&priv->lock);
 
@@ -247,37 +245,29 @@ static int rcar_thermal_update_temp(struct rcar_thermal_priv *priv)
                                                   ((ctemp - 1) << 0)));
        }
 
-       dev_dbg(dev, "thermal%d  %d -> %d\n", priv->id, priv->ctemp, ctemp);
-
-       priv->ctemp = ctemp;
-       ret = 0;
 err_out_unlock:
        mutex_unlock(&priv->lock);
-       return ret;
+
+       return ctemp ? ctemp : -EINVAL;
 }
 
 static int rcar_thermal_get_current_temp(struct rcar_thermal_priv *priv,
                                         int *temp)
 {
-       int tmp;
-       int ret;
-
-       ret = rcar_thermal_update_temp(priv);
-       if (ret < 0)
-               return ret;
+       int ctemp;
 
-       mutex_lock(&priv->lock);
-       if (priv->chip->ctemp_bands == 1)
-               tmp = MCELSIUS((priv->ctemp * 5) - 65);
-       else if (priv->ctemp < 24)
-               tmp = MCELSIUS(((priv->ctemp * 55) - 720) / 10);
-       else
-               tmp = MCELSIUS((priv->ctemp * 5) - 60);
-       mutex_unlock(&priv->lock);
+       ctemp = rcar_thermal_update_temp(priv);
+       if (ctemp < 0)
+               return ctemp;
 
        /* Guaranteed operating range is -45C to 125C. */
 
-       *temp = tmp;
+       if (priv->chip->ctemp_bands == 1)
+               *temp = MCELSIUS((ctemp * 5) - 65);
+       else if (ctemp < 24)
+               *temp = MCELSIUS(((ctemp * 55) - 720) / 10);
+       else
+               *temp = MCELSIUS((ctemp * 5) - 60);
 
        return 0;
 }
@@ -387,28 +377,17 @@ static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable)
 static void rcar_thermal_work(struct work_struct *work)
 {
        struct rcar_thermal_priv *priv;
-       int cctemp, nctemp;
        int ret;
 
        priv = container_of(work, struct rcar_thermal_priv, work.work);
 
-       ret = rcar_thermal_get_current_temp(priv, &cctemp);
-       if (ret < 0)
-               return;
-
        ret = rcar_thermal_update_temp(priv);
        if (ret < 0)
                return;
 
        rcar_thermal_irq_enable(priv);
 
-       ret = rcar_thermal_get_current_temp(priv, &nctemp);
-       if (ret < 0)
-               return;
-
-       if (nctemp != cctemp)
-               thermal_zone_device_update(priv->zone,
-                                          THERMAL_EVENT_UNSPECIFIED);
+       thermal_zone_device_update(priv->zone, THERMAL_EVENT_UNSPECIFIED);
 }
 
 static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status)
@@ -521,8 +500,10 @@ static int rcar_thermal_probe(struct platform_device *pdev)
                        res = platform_get_resource(pdev, IORESOURCE_MEM,
                                                    mres++);
                        common->base = devm_ioremap_resource(dev, res);
-                       if (IS_ERR(common->base))
-                               return PTR_ERR(common->base);
+                       if (IS_ERR(common->base)) {
+                               ret = PTR_ERR(common->base);
+                               goto error_unregister;
+                       }
 
                        idle = 0; /* polling delay is not needed */
                }
index fd4a178..e9a90bc 100644 (file)
@@ -1094,7 +1094,9 @@ static int exynos_tmu_probe(struct platform_device *pdev)
                                                    &exynos_sensor_ops);
        if (IS_ERR(data->tzd)) {
                ret = PTR_ERR(data->tzd);
-               dev_err(&pdev->dev, "Failed to register sensor: %d\n", ret);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "Failed to register sensor: %d\n",
+                               ret);
                goto err_sclk;
        }
 
diff --git a/drivers/thermal/sprd_thermal.c b/drivers/thermal/sprd_thermal.c
new file mode 100644 (file)
index 0000000..a340374
--- /dev/null
@@ -0,0 +1,552 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2020 Spreadtrum Communications Inc.
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+
+#define SPRD_THM_CTL                   0x0
+#define SPRD_THM_INT_EN                        0x4
+#define SPRD_THM_INT_STS               0x8
+#define SPRD_THM_INT_RAW_STS           0xc
+#define SPRD_THM_DET_PERIOD            0x10
+#define SPRD_THM_INT_CLR               0x14
+#define SPRD_THM_INT_CLR_ST            0x18
+#define SPRD_THM_MON_PERIOD            0x4c
+#define SPRD_THM_MON_CTL               0x50
+#define SPRD_THM_INTERNAL_STS1         0x54
+#define SPRD_THM_RAW_READ_MSK          0x3ff
+
+#define SPRD_THM_OFFSET(id)            ((id) * 0x4)
+#define SPRD_THM_TEMP(id)              (SPRD_THM_OFFSET(id) + 0x5c)
+#define SPRD_THM_THRES(id)             (SPRD_THM_OFFSET(id) + 0x2c)
+
+#define SPRD_THM_SEN(id)               BIT((id) + 2)
+#define SPRD_THM_SEN_OVERHEAT_EN(id)   BIT((id) + 8)
+#define SPRD_THM_SEN_OVERHEAT_ALARM_EN(id)     BIT((id) + 0)
+
+/* bits definitions for register THM_CTL */
+#define SPRD_THM_SET_RDY_ST            BIT(13)
+#define SPRD_THM_SET_RDY               BIT(12)
+#define SPRD_THM_MON_EN                        BIT(1)
+#define SPRD_THM_EN                    BIT(0)
+
+/* bits definitions for register THM_INT_CTL */
+#define SPRD_THM_BIT_INT_EN            BIT(26)
+#define SPRD_THM_OVERHEAT_EN           BIT(25)
+#define SPRD_THM_OTP_TRIP_SHIFT                10
+
+/* bits definitions for register SPRD_THM_INTERNAL_STS1 */
+#define SPRD_THM_TEMPER_RDY            BIT(0)
+
+#define SPRD_THM_DET_PERIOD_DATA       0x800
+#define SPRD_THM_DET_PERIOD_MASK       GENMASK(19, 0)
+#define SPRD_THM_MON_MODE              0x7
+#define SPRD_THM_MON_MODE_MASK         GENMASK(3, 0)
+#define SPRD_THM_MON_PERIOD_DATA       0x10
+#define SPRD_THM_MON_PERIOD_MASK       GENMASK(15, 0)
+#define SPRD_THM_THRES_MASK            GENMASK(19, 0)
+#define SPRD_THM_INT_CLR_MASK          GENMASK(24, 0)
+
+/* thermal sensor calibration parameters */
+#define SPRD_THM_TEMP_LOW              -40000
+#define SPRD_THM_TEMP_HIGH             120000
+#define SPRD_THM_OTP_TEMP              120000
+#define SPRD_THM_HOT_TEMP              75000
+#define SPRD_THM_RAW_DATA_LOW          0
+#define SPRD_THM_RAW_DATA_HIGH         1000
+#define SPRD_THM_SEN_NUM               8
+#define SPRD_THM_DT_OFFSET             24
+#define SPRD_THM_RATION_OFFSET         17
+#define SPRD_THM_RATION_SIGN           16
+
+#define SPRD_THM_RDYST_POLLING_TIME    10
+#define SPRD_THM_RDYST_TIMEOUT         700
+#define SPRD_THM_TEMP_READY_POLL_TIME  10000
+#define SPRD_THM_TEMP_READY_TIMEOUT    600000
+#define SPRD_THM_MAX_SENSOR            8
+
+struct sprd_thermal_sensor {
+       struct thermal_zone_device *tzd;
+       struct sprd_thermal_data *data;
+       struct device *dev;
+       int cal_slope;
+       int cal_offset;
+       int id;
+};
+
+struct sprd_thermal_data {
+       const struct sprd_thm_variant_data *var_data;
+       struct sprd_thermal_sensor *sensor[SPRD_THM_MAX_SENSOR];
+       struct clk *clk;
+       void __iomem *base;
+       u32 ratio_off;
+       int ratio_sign;
+       int nr_sensors;
+};
+
+/*
+ * The conversion between ADC and temperature is based on linear relationship,
+ * and use idea_k to specify the slope and ideal_b to specify the offset.
+ *
+ * Since different Spreadtrum SoCs have different ideal_k and ideal_b,
+ * we should save ideal_k and ideal_b in the device data structure.
+ */
+struct sprd_thm_variant_data {
+       u32 ideal_k;
+       u32 ideal_b;
+};
+
+static const struct sprd_thm_variant_data ums512_data = {
+       .ideal_k = 262,
+       .ideal_b = 66400,
+};
+
+static inline void sprd_thm_update_bits(void __iomem *reg, u32 mask, u32 val)
+{
+       u32 tmp, orig;
+
+       orig = readl(reg);
+       tmp = orig & ~mask;
+       tmp |= val & mask;
+       writel(tmp, reg);
+}
+
+static int sprd_thm_cal_read(struct device_node *np, const char *cell_id,
+                            u32 *val)
+{
+       struct nvmem_cell *cell;
+       void *buf;
+       size_t len;
+
+       cell = of_nvmem_cell_get(np, cell_id);
+       if (IS_ERR(cell))
+               return PTR_ERR(cell);
+
+       buf = nvmem_cell_read(cell, &len);
+       nvmem_cell_put(cell);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       if (len > sizeof(u32)) {
+               kfree(buf);
+               return -EINVAL;
+       }
+
+       memcpy(val, buf, len);
+
+       kfree(buf);
+       return 0;
+}
+
+static int sprd_thm_sensor_calibration(struct device_node *np,
+                                      struct sprd_thermal_data *thm,
+                                      struct sprd_thermal_sensor *sen)
+{
+       int ret;
+       /*
+        * According to thermal datasheet, the default calibration offset is 64,
+        * and the default ratio is 1000.
+        */
+       int dt_offset = 64, ratio = 1000;
+
+       ret = sprd_thm_cal_read(np, "sen_delta_cal", &dt_offset);
+       if (ret)
+               return ret;
+
+       ratio += thm->ratio_sign * thm->ratio_off;
+
+       /*
+        * According to the ideal slope K and ideal offset B, combined with
+        * calibration value of thermal from efuse, then calibrate the real
+        * slope k and offset b:
+        * k_cal = (k * ratio) / 1000.
+        * b_cal = b + (dt_offset - 64) * 500.
+        */
+       sen->cal_slope = (thm->var_data->ideal_k * ratio) / 1000;
+       sen->cal_offset = thm->var_data->ideal_b + (dt_offset - 128) * 250;
+
+       return 0;
+}
+
+static int sprd_thm_rawdata_to_temp(struct sprd_thermal_sensor *sen,
+                                   u32 rawdata)
+{
+       clamp(rawdata, (u32)SPRD_THM_RAW_DATA_LOW, (u32)SPRD_THM_RAW_DATA_HIGH);
+
+       /*
+        * According to the thermal datasheet, the formula of converting
+        * adc value to the temperature value should be:
+        * T_final = k_cal * x - b_cal.
+        */
+       return sen->cal_slope * rawdata - sen->cal_offset;
+}
+
+static int sprd_thm_temp_to_rawdata(int temp, struct sprd_thermal_sensor *sen)
+{
+       u32 val;
+
+       clamp(temp, (int)SPRD_THM_TEMP_LOW, (int)SPRD_THM_TEMP_HIGH);
+
+       /*
+        * According to the thermal datasheet, the formula of converting
+        * adc value to the temperature value should be:
+        * T_final = k_cal * x - b_cal.
+        */
+       val = (temp + sen->cal_offset) / sen->cal_slope;
+
+       return clamp(val, val, (u32)(SPRD_THM_RAW_DATA_HIGH - 1));
+}
+
+static int sprd_thm_read_temp(void *devdata, int *temp)
+{
+       struct sprd_thermal_sensor *sen = devdata;
+       u32 data;
+
+       data = readl(sen->data->base + SPRD_THM_TEMP(sen->id)) &
+               SPRD_THM_RAW_READ_MSK;
+
+       *temp = sprd_thm_rawdata_to_temp(sen, data);
+
+       return 0;
+}
+
+static const struct thermal_zone_of_device_ops sprd_thm_ops = {
+       .get_temp = sprd_thm_read_temp,
+};
+
+static int sprd_thm_poll_ready_status(struct sprd_thermal_data *thm)
+{
+       u32 val;
+       int ret;
+
+       /*
+        * Wait for thermal ready status before configuring thermal parameters.
+        */
+       ret = readl_poll_timeout(thm->base + SPRD_THM_CTL, val,
+                                !(val & SPRD_THM_SET_RDY_ST),
+                                SPRD_THM_RDYST_POLLING_TIME,
+                                SPRD_THM_RDYST_TIMEOUT);
+       if (ret)
+               return ret;
+
+       sprd_thm_update_bits(thm->base + SPRD_THM_CTL, SPRD_THM_MON_EN,
+                            SPRD_THM_MON_EN);
+       sprd_thm_update_bits(thm->base + SPRD_THM_CTL, SPRD_THM_SET_RDY,
+                            SPRD_THM_SET_RDY);
+       return 0;
+}
+
+static int sprd_thm_wait_temp_ready(struct sprd_thermal_data *thm)
+{
+       u32 val;
+
+       /* Wait for first temperature data ready before reading temperature */
+       return readl_poll_timeout(thm->base + SPRD_THM_INTERNAL_STS1, val,
+                                 !(val & SPRD_THM_TEMPER_RDY),
+                                 SPRD_THM_TEMP_READY_POLL_TIME,
+                                 SPRD_THM_TEMP_READY_TIMEOUT);
+}
+
+static int sprd_thm_set_ready(struct sprd_thermal_data *thm)
+{
+       int ret;
+
+       ret = sprd_thm_poll_ready_status(thm);
+       if (ret)
+               return ret;
+
+       /*
+        * Clear interrupt status, enable thermal interrupt and enable thermal.
+        *
+        * The SPRD thermal controller integrates a hardware interrupt signal,
+        * which means if the temperature is overheat, it will generate an
+        * interrupt and notify the event to PMIC automatically to shutdown the
+        * system. So here we should enable the interrupt bits, though we have
+        * not registered an irq handler.
+        */
+       writel(SPRD_THM_INT_CLR_MASK, thm->base + SPRD_THM_INT_CLR);
+       sprd_thm_update_bits(thm->base + SPRD_THM_INT_EN,
+                            SPRD_THM_BIT_INT_EN, SPRD_THM_BIT_INT_EN);
+       sprd_thm_update_bits(thm->base + SPRD_THM_CTL,
+                            SPRD_THM_EN, SPRD_THM_EN);
+       return 0;
+}
+
+static void sprd_thm_sensor_init(struct sprd_thermal_data *thm,
+                                struct sprd_thermal_sensor *sen)
+{
+       u32 otp_rawdata, hot_rawdata;
+
+       otp_rawdata = sprd_thm_temp_to_rawdata(SPRD_THM_OTP_TEMP, sen);
+       hot_rawdata = sprd_thm_temp_to_rawdata(SPRD_THM_HOT_TEMP, sen);
+
+       /* Enable the sensor' overheat temperature protection interrupt */
+       sprd_thm_update_bits(thm->base + SPRD_THM_INT_EN,
+                            SPRD_THM_SEN_OVERHEAT_ALARM_EN(sen->id),
+                            SPRD_THM_SEN_OVERHEAT_ALARM_EN(sen->id));
+
+       /* Set the sensor' overheat and hot threshold temperature */
+       sprd_thm_update_bits(thm->base + SPRD_THM_THRES(sen->id),
+                            SPRD_THM_THRES_MASK,
+                            (otp_rawdata << SPRD_THM_OTP_TRIP_SHIFT) |
+                            hot_rawdata);
+
+       /* Enable the corresponding sensor */
+       sprd_thm_update_bits(thm->base + SPRD_THM_CTL, SPRD_THM_SEN(sen->id),
+                            SPRD_THM_SEN(sen->id));
+}
+
+static void sprd_thm_para_config(struct sprd_thermal_data *thm)
+{
+       /* Set the period of two valid temperature detection action */
+       sprd_thm_update_bits(thm->base + SPRD_THM_DET_PERIOD,
+                            SPRD_THM_DET_PERIOD_MASK, SPRD_THM_DET_PERIOD);
+
+       /* Set the sensors' monitor mode */
+       sprd_thm_update_bits(thm->base + SPRD_THM_MON_CTL,
+                            SPRD_THM_MON_MODE_MASK, SPRD_THM_MON_MODE);
+
+       /* Set the sensors' monitor period */
+       sprd_thm_update_bits(thm->base + SPRD_THM_MON_PERIOD,
+                            SPRD_THM_MON_PERIOD_MASK, SPRD_THM_MON_PERIOD);
+}
+
+static void sprd_thm_toggle_sensor(struct sprd_thermal_sensor *sen, bool on)
+{
+       struct thermal_zone_device *tzd = sen->tzd;
+
+       tzd->ops->set_mode(tzd,
+               on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
+}
+
+static int sprd_thm_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *sen_child;
+       struct sprd_thermal_data *thm;
+       struct sprd_thermal_sensor *sen;
+       const struct sprd_thm_variant_data *pdata;
+       int ret, i;
+       u32 val;
+
+       pdata = of_device_get_match_data(&pdev->dev);
+       if (!pdata) {
+               dev_err(&pdev->dev, "No matching driver data found\n");
+               return -EINVAL;
+       }
+
+       thm = devm_kzalloc(&pdev->dev, sizeof(*thm), GFP_KERNEL);
+       if (!thm)
+               return -ENOMEM;
+
+       thm->var_data = pdata;
+       thm->base = devm_platform_ioremap_resource(pdev, 0);
+       if (!thm->base)
+               return -ENOMEM;
+
+       thm->nr_sensors = of_get_child_count(np);
+       if (thm->nr_sensors == 0 || thm->nr_sensors > SPRD_THM_MAX_SENSOR) {
+               dev_err(&pdev->dev, "incorrect sensor count\n");
+               return -EINVAL;
+       }
+
+       thm->clk = devm_clk_get(&pdev->dev, "enable");
+       if (IS_ERR(thm->clk)) {
+               dev_err(&pdev->dev, "failed to get enable clock\n");
+               return PTR_ERR(thm->clk);
+       }
+
+       ret = clk_prepare_enable(thm->clk);
+       if (ret)
+               return ret;
+
+       sprd_thm_para_config(thm);
+
+       ret = sprd_thm_cal_read(np, "thm_sign_cal", &val);
+       if (ret)
+               goto disable_clk;
+
+       if (val > 0)
+               thm->ratio_sign = -1;
+       else
+               thm->ratio_sign = 1;
+
+       ret = sprd_thm_cal_read(np, "thm_ratio_cal", &thm->ratio_off);
+       if (ret)
+               goto disable_clk;
+
+       for_each_child_of_node(np, sen_child) {
+               sen = devm_kzalloc(&pdev->dev, sizeof(*sen), GFP_KERNEL);
+               if (!sen) {
+                       ret = -ENOMEM;
+                       goto disable_clk;
+               }
+
+               sen->data = thm;
+               sen->dev = &pdev->dev;
+
+               ret = of_property_read_u32(sen_child, "reg", &sen->id);
+               if (ret) {
+                       dev_err(&pdev->dev, "get sensor reg failed");
+                       goto disable_clk;
+               }
+
+               ret = sprd_thm_sensor_calibration(sen_child, thm, sen);
+               if (ret) {
+                       dev_err(&pdev->dev, "efuse cal analysis failed");
+                       goto disable_clk;
+               }
+
+               sprd_thm_sensor_init(thm, sen);
+
+               sen->tzd = devm_thermal_zone_of_sensor_register(sen->dev,
+                                                               sen->id,
+                                                               sen,
+                                                               &sprd_thm_ops);
+               if (IS_ERR(sen->tzd)) {
+                       dev_err(&pdev->dev, "register thermal zone failed %d\n",
+                               sen->id);
+                       ret = PTR_ERR(sen->tzd);
+                       goto disable_clk;
+               }
+
+               thm->sensor[sen->id] = sen;
+       }
+
+       ret = sprd_thm_set_ready(thm);
+       if (ret)
+               goto disable_clk;
+
+       ret = sprd_thm_wait_temp_ready(thm);
+       if (ret)
+               goto disable_clk;
+
+       for (i = 0; i < thm->nr_sensors; i++)
+               sprd_thm_toggle_sensor(thm->sensor[i], true);
+
+       platform_set_drvdata(pdev, thm);
+       return 0;
+
+disable_clk:
+       clk_disable_unprepare(thm->clk);
+       return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static void sprd_thm_hw_suspend(struct sprd_thermal_data *thm)
+{
+       int i;
+
+       for (i = 0; i < thm->nr_sensors; i++) {
+               sprd_thm_update_bits(thm->base + SPRD_THM_CTL,
+                                    SPRD_THM_SEN(thm->sensor[i]->id), 0);
+       }
+
+       sprd_thm_update_bits(thm->base + SPRD_THM_CTL,
+                            SPRD_THM_EN, 0x0);
+}
+
+static int sprd_thm_suspend(struct device *dev)
+{
+       struct sprd_thermal_data *thm = dev_get_drvdata(dev);
+       int i;
+
+       for (i = 0; i < thm->nr_sensors; i++)
+               sprd_thm_toggle_sensor(thm->sensor[i], false);
+
+       sprd_thm_hw_suspend(thm);
+       clk_disable_unprepare(thm->clk);
+
+       return 0;
+}
+
+static int sprd_thm_hw_resume(struct sprd_thermal_data *thm)
+{
+       int ret, i;
+
+       for (i = 0; i < thm->nr_sensors; i++) {
+               sprd_thm_update_bits(thm->base + SPRD_THM_CTL,
+                                    SPRD_THM_SEN(thm->sensor[i]->id),
+                                    SPRD_THM_SEN(thm->sensor[i]->id));
+       }
+
+       ret = sprd_thm_poll_ready_status(thm);
+       if (ret)
+               return ret;
+
+       writel(SPRD_THM_INT_CLR_MASK, thm->base + SPRD_THM_INT_CLR);
+       sprd_thm_update_bits(thm->base + SPRD_THM_CTL,
+                            SPRD_THM_EN, SPRD_THM_EN);
+       return sprd_thm_wait_temp_ready(thm);
+}
+
+static int sprd_thm_resume(struct device *dev)
+{
+       struct sprd_thermal_data *thm = dev_get_drvdata(dev);
+       int ret, i;
+
+       ret = clk_prepare_enable(thm->clk);
+       if (ret)
+               return ret;
+
+       ret = sprd_thm_hw_resume(thm);
+       if (ret)
+               goto disable_clk;
+
+       for (i = 0; i < thm->nr_sensors; i++)
+               sprd_thm_toggle_sensor(thm->sensor[i], true);
+
+       return 0;
+
+disable_clk:
+       clk_disable_unprepare(thm->clk);
+       return ret;
+}
+#endif
+
+static int sprd_thm_remove(struct platform_device *pdev)
+{
+       struct sprd_thermal_data *thm = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < thm->nr_sensors; i++) {
+               sprd_thm_toggle_sensor(thm->sensor[i], false);
+               devm_thermal_zone_of_sensor_unregister(&pdev->dev,
+                                                      thm->sensor[i]->tzd);
+       }
+
+       clk_disable_unprepare(thm->clk);
+       return 0;
+}
+
+static const struct of_device_id sprd_thermal_of_match[] = {
+       { .compatible = "sprd,ums512-thermal", .data = &ums512_data },
+       { },
+};
+
+static const struct dev_pm_ops sprd_thermal_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(sprd_thm_suspend, sprd_thm_resume)
+};
+
+static struct platform_driver sprd_thermal_driver = {
+       .probe = sprd_thm_probe,
+       .remove = sprd_thm_remove,
+       .driver = {
+               .name = "sprd-thermal",
+               .pm = &sprd_thermal_pm_ops,
+               .of_match_table = sprd_thermal_of_match,
+       },
+};
+
+module_platform_driver(sprd_thermal_driver);
+
+MODULE_AUTHOR("Freeman Liu <freeman.liu@unisoc.com>");
+MODULE_DESCRIPTION("Spreadtrum thermal driver");
+MODULE_LICENSE("GPL v2");
index ad9e3bf..9314e3d 100644 (file)
@@ -478,7 +478,8 @@ static int stm_thermal_resume(struct device *dev)
 }
 #endif /* CONFIG_PM_SLEEP */
 
-SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops, stm_thermal_suspend, stm_thermal_resume);
+static SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops,
+                        stm_thermal_suspend, stm_thermal_resume);
 
 static const struct thermal_zone_of_device_ops stm_tz_ops = {
        .get_temp       = stm_thermal_get_temp,
index 2fa78f7..263b042 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/clk.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
 #include <linux/types.h>
@@ -24,7 +24,6 @@
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 #include <linux/of_irq.h>
-#include <linux/of_gpio.h>
 #include <linux/io.h>
 
 #include "ti-bandgap.h"
@@ -743,27 +742,13 @@ exit:
 static int ti_bandgap_tshut_init(struct ti_bandgap *bgp,
                                 struct platform_device *pdev)
 {
-       int gpio_nr = bgp->tshut_gpio;
        int status;
 
-       /* Request for gpio_86 line */
-       status = gpio_request(gpio_nr, "tshut");
-       if (status < 0) {
-               dev_err(bgp->dev, "Could not request for TSHUT GPIO:%i\n", 86);
-               return status;
-       }
-       status = gpio_direction_input(gpio_nr);
-       if (status) {
-               dev_err(bgp->dev, "Cannot set input TSHUT GPIO %d\n", gpio_nr);
-               return status;
-       }
-
-       status = request_irq(gpio_to_irq(gpio_nr), ti_bandgap_tshut_irq_handler,
+       status = request_irq(gpiod_to_irq(bgp->tshut_gpiod),
+                            ti_bandgap_tshut_irq_handler,
                             IRQF_TRIGGER_RISING, "tshut", NULL);
-       if (status) {
-               gpio_free(gpio_nr);
+       if (status)
                dev_err(bgp->dev, "request irq failed for TSHUT");
-       }
 
        return 0;
 }
@@ -860,11 +845,10 @@ static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev)
        } while (res);
 
        if (TI_BANDGAP_HAS(bgp, TSHUT)) {
-               bgp->tshut_gpio = of_get_gpio(node, 0);
-               if (!gpio_is_valid(bgp->tshut_gpio)) {
-                       dev_err(&pdev->dev, "invalid gpio for tshut (%d)\n",
-                               bgp->tshut_gpio);
-                       return ERR_PTR(-EINVAL);
+               bgp->tshut_gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_IN);
+               if (IS_ERR(bgp->tshut_gpiod)) {
+                       dev_err(&pdev->dev, "invalid gpio for tshut\n");
+                       return ERR_CAST(bgp->tshut_gpiod);
                }
        }
 
@@ -1046,10 +1030,8 @@ put_clks:
 put_fclock:
        clk_put(bgp->fclock);
 free_irqs:
-       if (TI_BANDGAP_HAS(bgp, TSHUT)) {
-               free_irq(gpio_to_irq(bgp->tshut_gpio), NULL);
-               gpio_free(bgp->tshut_gpio);
-       }
+       if (TI_BANDGAP_HAS(bgp, TSHUT))
+               free_irq(gpiod_to_irq(bgp->tshut_gpiod), NULL);
 
        return ret;
 }
@@ -1079,10 +1061,8 @@ int ti_bandgap_remove(struct platform_device *pdev)
        if (TI_BANDGAP_HAS(bgp, TALERT))
                free_irq(bgp->irq, bgp);
 
-       if (TI_BANDGAP_HAS(bgp, TSHUT)) {
-               free_irq(gpio_to_irq(bgp->tshut_gpio), NULL);
-               gpio_free(bgp->tshut_gpio);
-       }
+       if (TI_BANDGAP_HAS(bgp, TSHUT))
+               free_irq(gpiod_to_irq(bgp->tshut_gpiod), NULL);
 
        return 0;
 }
index bb9b0f7..fce4657 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/types.h>
 #include <linux/err.h>
 
+struct gpio_desc;
+
 /**
  * DOC: bandgap driver data structure
  * ==================================
@@ -199,7 +201,7 @@ struct ti_bandgap {
        struct clk                      *div_clk;
        spinlock_t                      lock; /* shields this struct */
        int                             irq;
-       int                             tshut_gpio;
+       struct gpio_desc                *tshut_gpiod;
        u32                             clk_rate;
 };
 
diff --git a/drivers/vdpa/Kconfig b/drivers/vdpa/Kconfig
new file mode 100644 (file)
index 0000000..7db1460
--- /dev/null
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config VDPA
+       tristate
+       help
+         Enable this module to support vDPA device that uses a
+         datapath which complies with virtio specifications with
+         vendor specific control path.
+
+menuconfig VDPA_MENU
+       bool "VDPA drivers"
+       default n
+
+if VDPA_MENU
+
+config VDPA_SIM
+       tristate "vDPA device simulator"
+       depends on RUNTIME_TESTING_MENU
+       select VDPA
+       select VHOST_RING
+       default n
+       help
+         vDPA networking device simulator which loop TX traffic back
+         to RX. This device is used for testing, prototyping and
+         development of vDPA.
+
+config IFCVF
+       tristate "Intel IFC VF VDPA driver"
+       depends on PCI_MSI
+       select VDPA
+       default n
+       help
+         This kernel module can drive Intel IFC VF NIC to offload
+         virtio dataplane traffic to hardware.
+         To compile this driver as a module, choose M here: the module will
+         be called ifcvf.
+
+endif # VDPA_MENU
diff --git a/drivers/vdpa/Makefile b/drivers/vdpa/Makefile
new file mode 100644 (file)
index 0000000..8bbb686
--- /dev/null
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_VDPA) += vdpa.o
+obj-$(CONFIG_VDPA_SIM) += vdpa_sim/
+obj-$(CONFIG_IFCVF)    += ifcvf/
diff --git a/drivers/vdpa/ifcvf/Makefile b/drivers/vdpa/ifcvf/Makefile
new file mode 100644 (file)
index 0000000..d709915
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_IFCVF) += ifcvf.o
+ifcvf-$(CONFIG_IFCVF) += ifcvf_main.o ifcvf_base.o
diff --git a/drivers/vdpa/ifcvf/ifcvf_base.c b/drivers/vdpa/ifcvf/ifcvf_base.c
new file mode 100644 (file)
index 0000000..b61b06e
--- /dev/null
@@ -0,0 +1,389 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel IFC VF NIC driver for virtio dataplane offloading
+ *
+ * Copyright (C) 2020 Intel Corporation.
+ *
+ * Author: Zhu Lingshan <lingshan.zhu@intel.com>
+ *
+ */
+
+#include "ifcvf_base.h"
+
+static inline u8 ifc_ioread8(u8 __iomem *addr)
+{
+       return ioread8(addr);
+}
+static inline u16 ifc_ioread16 (__le16 __iomem *addr)
+{
+       return ioread16(addr);
+}
+
+static inline u32 ifc_ioread32(__le32 __iomem *addr)
+{
+       return ioread32(addr);
+}
+
+static inline void ifc_iowrite8(u8 value, u8 __iomem *addr)
+{
+       iowrite8(value, addr);
+}
+
+static inline void ifc_iowrite16(u16 value, __le16 __iomem *addr)
+{
+       iowrite16(value, addr);
+}
+
+static inline void ifc_iowrite32(u32 value, __le32 __iomem *addr)
+{
+       iowrite32(value, addr);
+}
+
+static void ifc_iowrite64_twopart(u64 val,
+                                 __le32 __iomem *lo, __le32 __iomem *hi)
+{
+       ifc_iowrite32((u32)val, lo);
+       ifc_iowrite32(val >> 32, hi);
+}
+
+struct ifcvf_adapter *vf_to_adapter(struct ifcvf_hw *hw)
+{
+       return container_of(hw, struct ifcvf_adapter, vf);
+}
+
+static void __iomem *get_cap_addr(struct ifcvf_hw *hw,
+                                 struct virtio_pci_cap *cap)
+{
+       struct ifcvf_adapter *ifcvf;
+       struct pci_dev *pdev;
+       u32 length, offset;
+       u8 bar;
+
+       length = le32_to_cpu(cap->length);
+       offset = le32_to_cpu(cap->offset);
+       bar = cap->bar;
+
+       ifcvf= vf_to_adapter(hw);
+       pdev = ifcvf->pdev;
+
+       if (bar >= IFCVF_PCI_MAX_RESOURCE) {
+               IFCVF_DBG(pdev,
+                         "Invalid bar number %u to get capabilities\n", bar);
+               return NULL;
+       }
+
+       if (offset + length > pci_resource_len(pdev, bar)) {
+               IFCVF_DBG(pdev,
+                         "offset(%u) + len(%u) overflows bar%u's capability\n",
+                         offset, length, bar);
+               return NULL;
+       }
+
+       return hw->base[bar] + offset;
+}
+
+static int ifcvf_read_config_range(struct pci_dev *dev,
+                                  uint32_t *val, int size, int where)
+{
+       int ret, i;
+
+       for (i = 0; i < size; i += 4) {
+               ret = pci_read_config_dword(dev, where + i, val + i / 4);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int ifcvf_init_hw(struct ifcvf_hw *hw, struct pci_dev *pdev)
+{
+       struct virtio_pci_cap cap;
+       u16 notify_off;
+       int ret;
+       u8 pos;
+       u32 i;
+
+       ret = pci_read_config_byte(pdev, PCI_CAPABILITY_LIST, &pos);
+       if (ret < 0) {
+               IFCVF_ERR(pdev, "Failed to read PCI capability list\n");
+               return -EIO;
+       }
+
+       while (pos) {
+               ret = ifcvf_read_config_range(pdev, (u32 *)&cap,
+                                             sizeof(cap), pos);
+               if (ret < 0) {
+                       IFCVF_ERR(pdev,
+                                 "Failed to get PCI capability at %x\n", pos);
+                       break;
+               }
+
+               if (cap.cap_vndr != PCI_CAP_ID_VNDR)
+                       goto next;
+
+               switch (cap.cfg_type) {
+               case VIRTIO_PCI_CAP_COMMON_CFG:
+                       hw->common_cfg = get_cap_addr(hw, &cap);
+                       IFCVF_DBG(pdev, "hw->common_cfg = %p\n",
+                                 hw->common_cfg);
+                       break;
+               case VIRTIO_PCI_CAP_NOTIFY_CFG:
+                       pci_read_config_dword(pdev, pos + sizeof(cap),
+                                             &hw->notify_off_multiplier);
+                       hw->notify_bar = cap.bar;
+                       hw->notify_base = get_cap_addr(hw, &cap);
+                       IFCVF_DBG(pdev, "hw->notify_base = %p\n",
+                                 hw->notify_base);
+                       break;
+               case VIRTIO_PCI_CAP_ISR_CFG:
+                       hw->isr = get_cap_addr(hw, &cap);
+                       IFCVF_DBG(pdev, "hw->isr = %p\n", hw->isr);
+                       break;
+               case VIRTIO_PCI_CAP_DEVICE_CFG:
+                       hw->net_cfg = get_cap_addr(hw, &cap);
+                       IFCVF_DBG(pdev, "hw->net_cfg = %p\n", hw->net_cfg);
+                       break;
+               }
+
+next:
+               pos = cap.cap_next;
+       }
+
+       if (hw->common_cfg == NULL || hw->notify_base == NULL ||
+           hw->isr == NULL || hw->net_cfg == NULL) {
+               IFCVF_ERR(pdev, "Incomplete PCI capabilities\n");
+               return -EIO;
+       }
+
+       for (i = 0; i < IFCVF_MAX_QUEUE_PAIRS * 2; i++) {
+               ifc_iowrite16(i, &hw->common_cfg->queue_select);
+               notify_off = ifc_ioread16(&hw->common_cfg->queue_notify_off);
+               hw->vring[i].notify_addr = hw->notify_base +
+                       notify_off * hw->notify_off_multiplier;
+       }
+
+       hw->lm_cfg = hw->base[IFCVF_LM_BAR];
+
+       IFCVF_DBG(pdev,
+                 "PCI capability mapping: common cfg: %p, notify base: %p\n, isr cfg: %p, device cfg: %p, multiplier: %u\n",
+                 hw->common_cfg, hw->notify_base, hw->isr,
+                 hw->net_cfg, hw->notify_off_multiplier);
+
+       return 0;
+}
+
+u8 ifcvf_get_status(struct ifcvf_hw *hw)
+{
+       return ifc_ioread8(&hw->common_cfg->device_status);
+}
+
+void ifcvf_set_status(struct ifcvf_hw *hw, u8 status)
+{
+       ifc_iowrite8(status, &hw->common_cfg->device_status);
+}
+
+void ifcvf_reset(struct ifcvf_hw *hw)
+{
+       ifcvf_set_status(hw, 0);
+       /* flush set_status, make sure VF is stopped, reset */
+       ifcvf_get_status(hw);
+}
+
+static void ifcvf_add_status(struct ifcvf_hw *hw, u8 status)
+{
+       if (status != 0)
+               status |= ifcvf_get_status(hw);
+
+       ifcvf_set_status(hw, status);
+       ifcvf_get_status(hw);
+}
+
+u64 ifcvf_get_features(struct ifcvf_hw *hw)
+{
+       struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg;
+       u32 features_lo, features_hi;
+
+       ifc_iowrite32(0, &cfg->device_feature_select);
+       features_lo = ifc_ioread32(&cfg->device_feature);
+
+       ifc_iowrite32(1, &cfg->device_feature_select);
+       features_hi = ifc_ioread32(&cfg->device_feature);
+
+       return ((u64)features_hi << 32) | features_lo;
+}
+
+void ifcvf_read_net_config(struct ifcvf_hw *hw, u64 offset,
+                          void *dst, int length)
+{
+       u8 old_gen, new_gen, *p;
+       int i;
+
+       WARN_ON(offset + length > sizeof(struct virtio_net_config));
+       do {
+               old_gen = ifc_ioread8(&hw->common_cfg->config_generation);
+               p = dst;
+               for (i = 0; i < length; i++)
+                       *p++ = ifc_ioread8(hw->net_cfg + offset + i);
+
+               new_gen = ifc_ioread8(&hw->common_cfg->config_generation);
+       } while (old_gen != new_gen);
+}
+
+void ifcvf_write_net_config(struct ifcvf_hw *hw, u64 offset,
+                           const void *src, int length)
+{
+       const u8 *p;
+       int i;
+
+       p = src;
+       WARN_ON(offset + length > sizeof(struct virtio_net_config));
+       for (i = 0; i < length; i++)
+               ifc_iowrite8(*p++, hw->net_cfg + offset + i);
+}
+
+static void ifcvf_set_features(struct ifcvf_hw *hw, u64 features)
+{
+       struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg;
+
+       ifc_iowrite32(0, &cfg->guest_feature_select);
+       ifc_iowrite32((u32)features, &cfg->guest_feature);
+
+       ifc_iowrite32(1, &cfg->guest_feature_select);
+       ifc_iowrite32(features >> 32, &cfg->guest_feature);
+}
+
+static int ifcvf_config_features(struct ifcvf_hw *hw)
+{
+       struct ifcvf_adapter *ifcvf;
+
+       ifcvf = vf_to_adapter(hw);
+       ifcvf_set_features(hw, hw->req_features);
+       ifcvf_add_status(hw, VIRTIO_CONFIG_S_FEATURES_OK);
+
+       if (!(ifcvf_get_status(hw) & VIRTIO_CONFIG_S_FEATURES_OK)) {
+               IFCVF_ERR(ifcvf->pdev, "Failed to set FEATURES_OK status\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+u64 ifcvf_get_vq_state(struct ifcvf_hw *hw, u16 qid)
+{
+       struct ifcvf_lm_cfg __iomem *ifcvf_lm;
+       void __iomem *avail_idx_addr;
+       u16 last_avail_idx;
+       u32 q_pair_id;
+
+       ifcvf_lm = (struct ifcvf_lm_cfg __iomem *)hw->lm_cfg;
+       q_pair_id = qid / (IFCVF_MAX_QUEUE_PAIRS * 2);
+       avail_idx_addr = &ifcvf_lm->vring_lm_cfg[q_pair_id].idx_addr[qid % 2];
+       last_avail_idx = ifc_ioread16(avail_idx_addr);
+
+       return last_avail_idx;
+}
+
+int ifcvf_set_vq_state(struct ifcvf_hw *hw, u16 qid, u64 num)
+{
+       struct ifcvf_lm_cfg __iomem *ifcvf_lm;
+       void __iomem *avail_idx_addr;
+       u32 q_pair_id;
+
+       ifcvf_lm = (struct ifcvf_lm_cfg __iomem *)hw->lm_cfg;
+       q_pair_id = qid / (IFCVF_MAX_QUEUE_PAIRS * 2);
+       avail_idx_addr = &ifcvf_lm->vring_lm_cfg[q_pair_id].idx_addr[qid % 2];
+       hw->vring[qid].last_avail_idx = num;
+       ifc_iowrite16(num, avail_idx_addr);
+
+       return 0;
+}
+
+static int ifcvf_hw_enable(struct ifcvf_hw *hw)
+{
+       struct ifcvf_lm_cfg __iomem *ifcvf_lm;
+       struct virtio_pci_common_cfg __iomem *cfg;
+       struct ifcvf_adapter *ifcvf;
+       u32 i;
+
+       ifcvf_lm = (struct ifcvf_lm_cfg __iomem *)hw->lm_cfg;
+       ifcvf = vf_to_adapter(hw);
+       cfg = hw->common_cfg;
+       ifc_iowrite16(IFCVF_MSI_CONFIG_OFF, &cfg->msix_config);
+
+       if (ifc_ioread16(&cfg->msix_config) == VIRTIO_MSI_NO_VECTOR) {
+               IFCVF_ERR(ifcvf->pdev, "No msix vector for device config\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < hw->nr_vring; i++) {
+               if (!hw->vring[i].ready)
+                       break;
+
+               ifc_iowrite16(i, &cfg->queue_select);
+               ifc_iowrite64_twopart(hw->vring[i].desc, &cfg->queue_desc_lo,
+                                    &cfg->queue_desc_hi);
+               ifc_iowrite64_twopart(hw->vring[i].avail, &cfg->queue_avail_lo,
+                                     &cfg->queue_avail_hi);
+               ifc_iowrite64_twopart(hw->vring[i].used, &cfg->queue_used_lo,
+                                    &cfg->queue_used_hi);
+               ifc_iowrite16(hw->vring[i].size, &cfg->queue_size);
+               ifc_iowrite16(i + IFCVF_MSI_QUEUE_OFF, &cfg->queue_msix_vector);
+
+               if (ifc_ioread16(&cfg->queue_msix_vector) ==
+                   VIRTIO_MSI_NO_VECTOR) {
+                       IFCVF_ERR(ifcvf->pdev,
+                                 "No msix vector for queue %u\n", i);
+                       return -EINVAL;
+               }
+
+               ifcvf_set_vq_state(hw, i, hw->vring[i].last_avail_idx);
+               ifc_iowrite16(1, &cfg->queue_enable);
+       }
+
+       return 0;
+}
+
+static void ifcvf_hw_disable(struct ifcvf_hw *hw)
+{
+       struct virtio_pci_common_cfg __iomem *cfg;
+       u32 i;
+
+       cfg = hw->common_cfg;
+       ifc_iowrite16(VIRTIO_MSI_NO_VECTOR, &cfg->msix_config);
+
+       for (i = 0; i < hw->nr_vring; i++) {
+               ifc_iowrite16(i, &cfg->queue_select);
+               ifc_iowrite16(VIRTIO_MSI_NO_VECTOR, &cfg->queue_msix_vector);
+       }
+
+       ifc_ioread16(&cfg->queue_msix_vector);
+}
+
+int ifcvf_start_hw(struct ifcvf_hw *hw)
+{
+       ifcvf_reset(hw);
+       ifcvf_add_status(hw, VIRTIO_CONFIG_S_ACKNOWLEDGE);
+       ifcvf_add_status(hw, VIRTIO_CONFIG_S_DRIVER);
+
+       if (ifcvf_config_features(hw) < 0)
+               return -EINVAL;
+
+       if (ifcvf_hw_enable(hw) < 0)
+               return -EINVAL;
+
+       ifcvf_add_status(hw, VIRTIO_CONFIG_S_DRIVER_OK);
+
+       return 0;
+}
+
+void ifcvf_stop_hw(struct ifcvf_hw *hw)
+{
+       ifcvf_hw_disable(hw);
+       ifcvf_reset(hw);
+}
+
+void ifcvf_notify_queue(struct ifcvf_hw *hw, u16 qid)
+{
+       ifc_iowrite16(qid, hw->vring[qid].notify_addr);
+}
diff --git a/drivers/vdpa/ifcvf/ifcvf_base.h b/drivers/vdpa/ifcvf/ifcvf_base.h
new file mode 100644 (file)
index 0000000..e803070
--- /dev/null
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Intel IFC VF NIC driver for virtio dataplane offloading
+ *
+ * Copyright (C) 2020 Intel Corporation.
+ *
+ * Author: Zhu Lingshan <lingshan.zhu@intel.com>
+ *
+ */
+
+#ifndef _IFCVF_H_
+#define _IFCVF_H_
+
+#include <linux/pci.h>
+#include <linux/pci_regs.h>
+#include <linux/vdpa.h>
+#include <uapi/linux/virtio_net.h>
+#include <uapi/linux/virtio_config.h>
+#include <uapi/linux/virtio_pci.h>
+
+#define IFCVF_VENDOR_ID                0x1AF4
+#define IFCVF_DEVICE_ID                0x1041
+#define IFCVF_SUBSYS_VENDOR_ID 0x8086
+#define IFCVF_SUBSYS_DEVICE_ID 0x001A
+
+#define IFCVF_SUPPORTED_FEATURES \
+               ((1ULL << VIRTIO_NET_F_MAC)                     | \
+                (1ULL << VIRTIO_F_ANY_LAYOUT)                  | \
+                (1ULL << VIRTIO_F_VERSION_1)                   | \
+                (1ULL << VIRTIO_F_ORDER_PLATFORM)              | \
+                (1ULL << VIRTIO_F_IOMMU_PLATFORM)              | \
+                (1ULL << VIRTIO_NET_F_MRG_RXBUF))
+
+/* Only one queue pair for now. */
+#define IFCVF_MAX_QUEUE_PAIRS  1
+
+#define IFCVF_QUEUE_ALIGNMENT  PAGE_SIZE
+#define IFCVF_QUEUE_MAX                32768
+#define IFCVF_MSI_CONFIG_OFF   0
+#define IFCVF_MSI_QUEUE_OFF    1
+#define IFCVF_PCI_MAX_RESOURCE 6
+
+#define IFCVF_LM_CFG_SIZE              0x40
+#define IFCVF_LM_RING_STATE_OFFSET     0x20
+#define IFCVF_LM_BAR                   4
+
+#define IFCVF_ERR(pdev, fmt, ...)      dev_err(&pdev->dev, fmt, ##__VA_ARGS__)
+#define IFCVF_DBG(pdev, fmt, ...)      dev_dbg(&pdev->dev, fmt, ##__VA_ARGS__)
+#define IFCVF_INFO(pdev, fmt, ...)     dev_info(&pdev->dev, fmt, ##__VA_ARGS__)
+
+#define ifcvf_private_to_vf(adapter) \
+       (&((struct ifcvf_adapter *)adapter)->vf)
+
+#define IFCVF_MAX_INTR (IFCVF_MAX_QUEUE_PAIRS * 2 + 1)
+
+struct vring_info {
+       u64 desc;
+       u64 avail;
+       u64 used;
+       u16 size;
+       u16 last_avail_idx;
+       bool ready;
+       void __iomem *notify_addr;
+       u32 irq;
+       struct vdpa_callback cb;
+       char msix_name[256];
+};
+
+struct ifcvf_hw {
+       u8 __iomem *isr;
+       /* Live migration */
+       u8 __iomem *lm_cfg;
+       u16 nr_vring;
+       /* Notification bar number */
+       u8 notify_bar;
+       /* Notificaiton bar address */
+       void __iomem *notify_base;
+       u32 notify_off_multiplier;
+       u64 req_features;
+       struct virtio_pci_common_cfg __iomem *common_cfg;
+       void __iomem *net_cfg;
+       struct vring_info vring[IFCVF_MAX_QUEUE_PAIRS * 2];
+       void __iomem * const *base;
+};
+
+struct ifcvf_adapter {
+       struct vdpa_device vdpa;
+       struct pci_dev *pdev;
+       struct ifcvf_hw vf;
+};
+
+struct ifcvf_vring_lm_cfg {
+       u32 idx_addr[2];
+       u8 reserved[IFCVF_LM_CFG_SIZE - 8];
+};
+
+struct ifcvf_lm_cfg {
+       u8 reserved[IFCVF_LM_RING_STATE_OFFSET];
+       struct ifcvf_vring_lm_cfg vring_lm_cfg[IFCVF_MAX_QUEUE_PAIRS];
+};
+
+int ifcvf_init_hw(struct ifcvf_hw *hw, struct pci_dev *dev);
+int ifcvf_start_hw(struct ifcvf_hw *hw);
+void ifcvf_stop_hw(struct ifcvf_hw *hw);
+void ifcvf_notify_queue(struct ifcvf_hw *hw, u16 qid);
+void ifcvf_read_net_config(struct ifcvf_hw *hw, u64 offset,
+                          void *dst, int length);
+void ifcvf_write_net_config(struct ifcvf_hw *hw, u64 offset,
+                           const void *src, int length);
+u8 ifcvf_get_status(struct ifcvf_hw *hw);
+void ifcvf_set_status(struct ifcvf_hw *hw, u8 status);
+void io_write64_twopart(u64 val, u32 *lo, u32 *hi);
+void ifcvf_reset(struct ifcvf_hw *hw);
+u64 ifcvf_get_features(struct ifcvf_hw *hw);
+u64 ifcvf_get_vq_state(struct ifcvf_hw *hw, u16 qid);
+int ifcvf_set_vq_state(struct ifcvf_hw *hw, u16 qid, u64 num);
+struct ifcvf_adapter *vf_to_adapter(struct ifcvf_hw *hw);
+#endif /* _IFCVF_H_ */
diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c
new file mode 100644 (file)
index 0000000..8d54dc5
--- /dev/null
@@ -0,0 +1,435 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel IFC VF NIC driver for virtio dataplane offloading
+ *
+ * Copyright (C) 2020 Intel Corporation.
+ *
+ * Author: Zhu Lingshan <lingshan.zhu@intel.com>
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sysfs.h>
+#include "ifcvf_base.h"
+
+#define VERSION_STRING  "0.1"
+#define DRIVER_AUTHOR   "Intel Corporation"
+#define IFCVF_DRIVER_NAME       "ifcvf"
+
+static irqreturn_t ifcvf_intr_handler(int irq, void *arg)
+{
+       struct vring_info *vring = arg;
+
+       if (vring->cb.callback)
+               return vring->cb.callback(vring->cb.private);
+
+       return IRQ_HANDLED;
+}
+
+static int ifcvf_start_datapath(void *private)
+{
+       struct ifcvf_hw *vf = ifcvf_private_to_vf(private);
+       struct ifcvf_adapter *ifcvf;
+       u8 status;
+       int ret;
+
+       ifcvf = vf_to_adapter(vf);
+       vf->nr_vring = IFCVF_MAX_QUEUE_PAIRS * 2;
+       ret = ifcvf_start_hw(vf);
+       if (ret < 0) {
+               status = ifcvf_get_status(vf);
+               status |= VIRTIO_CONFIG_S_FAILED;
+               ifcvf_set_status(vf, status);
+       }
+
+       return ret;
+}
+
+static int ifcvf_stop_datapath(void *private)
+{
+       struct ifcvf_hw *vf = ifcvf_private_to_vf(private);
+       int i;
+
+       for (i = 0; i < IFCVF_MAX_QUEUE_PAIRS * 2; i++)
+               vf->vring[i].cb.callback = NULL;
+
+       ifcvf_stop_hw(vf);
+
+       return 0;
+}
+
+static void ifcvf_reset_vring(struct ifcvf_adapter *adapter)
+{
+       struct ifcvf_hw *vf = ifcvf_private_to_vf(adapter);
+       int i;
+
+       for (i = 0; i < IFCVF_MAX_QUEUE_PAIRS * 2; i++) {
+               vf->vring[i].last_avail_idx = 0;
+               vf->vring[i].desc = 0;
+               vf->vring[i].avail = 0;
+               vf->vring[i].used = 0;
+               vf->vring[i].ready = 0;
+               vf->vring[i].cb.callback = NULL;
+               vf->vring[i].cb.private = NULL;
+       }
+
+       ifcvf_reset(vf);
+}
+
+static struct ifcvf_adapter *vdpa_to_adapter(struct vdpa_device *vdpa_dev)
+{
+       return container_of(vdpa_dev, struct ifcvf_adapter, vdpa);
+}
+
+static struct ifcvf_hw *vdpa_to_vf(struct vdpa_device *vdpa_dev)
+{
+       struct ifcvf_adapter *adapter = vdpa_to_adapter(vdpa_dev);
+
+       return &adapter->vf;
+}
+
+static u64 ifcvf_vdpa_get_features(struct vdpa_device *vdpa_dev)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+       u64 features;
+
+       features = ifcvf_get_features(vf) & IFCVF_SUPPORTED_FEATURES;
+
+       return features;
+}
+
+static int ifcvf_vdpa_set_features(struct vdpa_device *vdpa_dev, u64 features)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+
+       vf->req_features = features;
+
+       return 0;
+}
+
+static u8 ifcvf_vdpa_get_status(struct vdpa_device *vdpa_dev)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+
+       return ifcvf_get_status(vf);
+}
+
+static void ifcvf_vdpa_set_status(struct vdpa_device *vdpa_dev, u8 status)
+{
+       struct ifcvf_adapter *adapter;
+       struct ifcvf_hw *vf;
+
+       vf  = vdpa_to_vf(vdpa_dev);
+       adapter = dev_get_drvdata(vdpa_dev->dev.parent);
+
+       if (status == 0) {
+               ifcvf_stop_datapath(adapter);
+               ifcvf_reset_vring(adapter);
+               return;
+       }
+
+       if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
+               if (ifcvf_start_datapath(adapter) < 0)
+                       IFCVF_ERR(adapter->pdev,
+                                 "Failed to set ifcvf vdpa  status %u\n",
+                                 status);
+       }
+
+       ifcvf_set_status(vf, status);
+}
+
+static u16 ifcvf_vdpa_get_vq_num_max(struct vdpa_device *vdpa_dev)
+{
+       return IFCVF_QUEUE_MAX;
+}
+
+static u64 ifcvf_vdpa_get_vq_state(struct vdpa_device *vdpa_dev, u16 qid)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+
+       return ifcvf_get_vq_state(vf, qid);
+}
+
+static int ifcvf_vdpa_set_vq_state(struct vdpa_device *vdpa_dev, u16 qid,
+                                  u64 num)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+
+       return ifcvf_set_vq_state(vf, qid, num);
+}
+
+static void ifcvf_vdpa_set_vq_cb(struct vdpa_device *vdpa_dev, u16 qid,
+                                struct vdpa_callback *cb)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+
+       vf->vring[qid].cb = *cb;
+}
+
+static void ifcvf_vdpa_set_vq_ready(struct vdpa_device *vdpa_dev,
+                                   u16 qid, bool ready)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+
+       vf->vring[qid].ready = ready;
+}
+
+static bool ifcvf_vdpa_get_vq_ready(struct vdpa_device *vdpa_dev, u16 qid)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+
+       return vf->vring[qid].ready;
+}
+
+static void ifcvf_vdpa_set_vq_num(struct vdpa_device *vdpa_dev, u16 qid,
+                                 u32 num)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+
+       vf->vring[qid].size = num;
+}
+
+static int ifcvf_vdpa_set_vq_address(struct vdpa_device *vdpa_dev, u16 qid,
+                                    u64 desc_area, u64 driver_area,
+                                    u64 device_area)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+
+       vf->vring[qid].desc = desc_area;
+       vf->vring[qid].avail = driver_area;
+       vf->vring[qid].used = device_area;
+
+       return 0;
+}
+
+static void ifcvf_vdpa_kick_vq(struct vdpa_device *vdpa_dev, u16 qid)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+
+       ifcvf_notify_queue(vf, qid);
+}
+
+static u32 ifcvf_vdpa_get_generation(struct vdpa_device *vdpa_dev)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+
+       return ioread8(&vf->common_cfg->config_generation);
+}
+
+static u32 ifcvf_vdpa_get_device_id(struct vdpa_device *vdpa_dev)
+{
+       return VIRTIO_ID_NET;
+}
+
+static u32 ifcvf_vdpa_get_vendor_id(struct vdpa_device *vdpa_dev)
+{
+       return IFCVF_SUBSYS_VENDOR_ID;
+}
+
+static u16 ifcvf_vdpa_get_vq_align(struct vdpa_device *vdpa_dev)
+{
+       return IFCVF_QUEUE_ALIGNMENT;
+}
+
+static void ifcvf_vdpa_get_config(struct vdpa_device *vdpa_dev,
+                                 unsigned int offset,
+                                 void *buf, unsigned int len)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+
+       WARN_ON(offset + len > sizeof(struct virtio_net_config));
+       ifcvf_read_net_config(vf, offset, buf, len);
+}
+
+static void ifcvf_vdpa_set_config(struct vdpa_device *vdpa_dev,
+                                 unsigned int offset, const void *buf,
+                                 unsigned int len)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+
+       WARN_ON(offset + len > sizeof(struct virtio_net_config));
+       ifcvf_write_net_config(vf, offset, buf, len);
+}
+
+static void ifcvf_vdpa_set_config_cb(struct vdpa_device *vdpa_dev,
+                                    struct vdpa_callback *cb)
+{
+       /* We don't support config interrupt */
+}
+
+/*
+ * IFCVF currently does't have on-chip IOMMU, so not
+ * implemented set_map()/dma_map()/dma_unmap()
+ */
+static const struct vdpa_config_ops ifc_vdpa_ops = {
+       .get_features   = ifcvf_vdpa_get_features,
+       .set_features   = ifcvf_vdpa_set_features,
+       .get_status     = ifcvf_vdpa_get_status,
+       .set_status     = ifcvf_vdpa_set_status,
+       .get_vq_num_max = ifcvf_vdpa_get_vq_num_max,
+       .get_vq_state   = ifcvf_vdpa_get_vq_state,
+       .set_vq_state   = ifcvf_vdpa_set_vq_state,
+       .set_vq_cb      = ifcvf_vdpa_set_vq_cb,
+       .set_vq_ready   = ifcvf_vdpa_set_vq_ready,
+       .get_vq_ready   = ifcvf_vdpa_get_vq_ready,
+       .set_vq_num     = ifcvf_vdpa_set_vq_num,
+       .set_vq_address = ifcvf_vdpa_set_vq_address,
+       .kick_vq        = ifcvf_vdpa_kick_vq,
+       .get_generation = ifcvf_vdpa_get_generation,
+       .get_device_id  = ifcvf_vdpa_get_device_id,
+       .get_vendor_id  = ifcvf_vdpa_get_vendor_id,
+       .get_vq_align   = ifcvf_vdpa_get_vq_align,
+       .get_config     = ifcvf_vdpa_get_config,
+       .set_config     = ifcvf_vdpa_set_config,
+       .set_config_cb  = ifcvf_vdpa_set_config_cb,
+};
+
+static int ifcvf_request_irq(struct ifcvf_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       struct ifcvf_hw *vf = &adapter->vf;
+       int vector, i, ret, irq;
+
+
+       for (i = 0; i < IFCVF_MAX_QUEUE_PAIRS * 2; i++) {
+               snprintf(vf->vring[i].msix_name, 256, "ifcvf[%s]-%d\n",
+                        pci_name(pdev), i);
+               vector = i + IFCVF_MSI_QUEUE_OFF;
+               irq = pci_irq_vector(pdev, vector);
+               ret = devm_request_irq(&pdev->dev, irq,
+                                      ifcvf_intr_handler, 0,
+                                      vf->vring[i].msix_name,
+                                      &vf->vring[i]);
+               if (ret) {
+                       IFCVF_ERR(pdev,
+                                 "Failed to request irq for vq %d\n", i);
+                       return ret;
+               }
+               vf->vring[i].irq = irq;
+       }
+
+       return 0;
+}
+
+static void ifcvf_free_irq_vectors(void *data)
+{
+       pci_free_irq_vectors(data);
+}
+
+static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct device *dev = &pdev->dev;
+       struct ifcvf_adapter *adapter;
+       struct ifcvf_hw *vf;
+       int ret;
+
+       ret = pcim_enable_device(pdev);
+       if (ret) {
+               IFCVF_ERR(pdev, "Failed to enable device\n");
+               return ret;
+       }
+
+       ret = pcim_iomap_regions(pdev, BIT(0) | BIT(2) | BIT(4),
+                                IFCVF_DRIVER_NAME);
+       if (ret) {
+               IFCVF_ERR(pdev, "Failed to request MMIO region\n");
+               return ret;
+       }
+
+       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+       if (ret) {
+               IFCVF_ERR(pdev, "No usable DMA confiugration\n");
+               return ret;
+       }
+
+       ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+       if (ret) {
+               IFCVF_ERR(pdev,
+                         "No usable coherent DMA confiugration\n");
+               return ret;
+       }
+
+       ret = pci_alloc_irq_vectors(pdev, IFCVF_MAX_INTR,
+                                   IFCVF_MAX_INTR, PCI_IRQ_MSIX);
+       if (ret < 0) {
+               IFCVF_ERR(pdev, "Failed to alloc irq vectors\n");
+               return ret;
+       }
+
+       ret = devm_add_action_or_reset(dev, ifcvf_free_irq_vectors, pdev);
+       if (ret) {
+               IFCVF_ERR(pdev,
+                         "Failed for adding devres for freeing irq vectors\n");
+               return ret;
+       }
+
+       adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa,
+                                   dev, &ifc_vdpa_ops);
+       if (adapter == NULL) {
+               IFCVF_ERR(pdev, "Failed to allocate vDPA structure");
+               return -ENOMEM;
+       }
+
+       pci_set_master(pdev);
+       pci_set_drvdata(pdev, adapter);
+
+       vf = &adapter->vf;
+       vf->base = pcim_iomap_table(pdev);
+
+       adapter->pdev = pdev;
+       adapter->vdpa.dma_dev = &pdev->dev;
+
+       ret = ifcvf_request_irq(adapter);
+       if (ret) {
+               IFCVF_ERR(pdev, "Failed to request MSI-X irq\n");
+               goto err;
+       }
+
+       ret = ifcvf_init_hw(vf, pdev);
+       if (ret) {
+               IFCVF_ERR(pdev, "Failed to init IFCVF hw\n");
+               goto err;
+       }
+
+       ret = vdpa_register_device(&adapter->vdpa);
+       if (ret) {
+               IFCVF_ERR(pdev, "Failed to register ifcvf to vdpa bus");
+               goto err;
+       }
+
+       return 0;
+
+err:
+       put_device(&adapter->vdpa.dev);
+       return ret;
+}
+
+static void ifcvf_remove(struct pci_dev *pdev)
+{
+       struct ifcvf_adapter *adapter = pci_get_drvdata(pdev);
+
+       vdpa_unregister_device(&adapter->vdpa);
+}
+
+static struct pci_device_id ifcvf_pci_ids[] = {
+       { PCI_DEVICE_SUB(IFCVF_VENDOR_ID,
+               IFCVF_DEVICE_ID,
+               IFCVF_SUBSYS_VENDOR_ID,
+               IFCVF_SUBSYS_DEVICE_ID) },
+       { 0 },
+};
+MODULE_DEVICE_TABLE(pci, ifcvf_pci_ids);
+
+static struct pci_driver ifcvf_driver = {
+       .name     = IFCVF_DRIVER_NAME,
+       .id_table = ifcvf_pci_ids,
+       .probe    = ifcvf_probe,
+       .remove   = ifcvf_remove,
+};
+
+module_pci_driver(ifcvf_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(VERSION_STRING);
diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c
new file mode 100644 (file)
index 0000000..e9ed6a2
--- /dev/null
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vDPA bus.
+ *
+ * Copyright (c) 2020, Red Hat. All rights reserved.
+ *     Author: Jason Wang <jasowang@redhat.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/idr.h>
+#include <linux/slab.h>
+#include <linux/vdpa.h>
+
+static DEFINE_IDA(vdpa_index_ida);
+
+static int vdpa_dev_probe(struct device *d)
+{
+       struct vdpa_device *vdev = dev_to_vdpa(d);
+       struct vdpa_driver *drv = drv_to_vdpa(vdev->dev.driver);
+       int ret = 0;
+
+       if (drv && drv->probe)
+               ret = drv->probe(vdev);
+
+       return ret;
+}
+
+static int vdpa_dev_remove(struct device *d)
+{
+       struct vdpa_device *vdev = dev_to_vdpa(d);
+       struct vdpa_driver *drv = drv_to_vdpa(vdev->dev.driver);
+
+       if (drv && drv->remove)
+               drv->remove(vdev);
+
+       return 0;
+}
+
+static struct bus_type vdpa_bus = {
+       .name  = "vdpa",
+       .probe = vdpa_dev_probe,
+       .remove = vdpa_dev_remove,
+};
+
+static void vdpa_release_dev(struct device *d)
+{
+       struct vdpa_device *vdev = dev_to_vdpa(d);
+       const struct vdpa_config_ops *ops = vdev->config;
+
+       if (ops->free)
+               ops->free(vdev);
+
+       ida_simple_remove(&vdpa_index_ida, vdev->index);
+       kfree(vdev);
+}
+
+/**
+ * __vdpa_alloc_device - allocate and initilaize a vDPA device
+ * This allows driver to some prepartion after device is
+ * initialized but before registered.
+ * @parent: the parent device
+ * @config: the bus operations that is supported by this device
+ * @size: size of the parent structure that contains private data
+ *
+ * Drvier should use vdap_alloc_device() wrapper macro instead of
+ * using this directly.
+ *
+ * Returns an error when parent/config/dma_dev is not set or fail to get
+ * ida.
+ */
+struct vdpa_device *__vdpa_alloc_device(struct device *parent,
+                                       const struct vdpa_config_ops *config,
+                                       size_t size)
+{
+       struct vdpa_device *vdev;
+       int err = -EINVAL;
+
+       if (!config)
+               goto err;
+
+       if (!!config->dma_map != !!config->dma_unmap)
+               goto err;
+
+       err = -ENOMEM;
+       vdev = kzalloc(size, GFP_KERNEL);
+       if (!vdev)
+               goto err;
+
+       err = ida_simple_get(&vdpa_index_ida, 0, 0, GFP_KERNEL);
+       if (err < 0)
+               goto err_ida;
+
+       vdev->dev.bus = &vdpa_bus;
+       vdev->dev.parent = parent;
+       vdev->dev.release = vdpa_release_dev;
+       vdev->index = err;
+       vdev->config = config;
+
+       err = dev_set_name(&vdev->dev, "vdpa%u", vdev->index);
+       if (err)
+               goto err_name;
+
+       device_initialize(&vdev->dev);
+
+       return vdev;
+
+err_name:
+       ida_simple_remove(&vdpa_index_ida, vdev->index);
+err_ida:
+       kfree(vdev);
+err:
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(__vdpa_alloc_device);
+
+/**
+ * vdpa_register_device - register a vDPA device
+ * Callers must have a succeed call of vdpa_init_device() before.
+ * @vdev: the vdpa device to be registered to vDPA bus
+ *
+ * Returns an error when fail to add to vDPA bus
+ */
+int vdpa_register_device(struct vdpa_device *vdev)
+{
+       return device_add(&vdev->dev);
+}
+EXPORT_SYMBOL_GPL(vdpa_register_device);
+
+/**
+ * vdpa_unregister_device - unregister a vDPA device
+ * @vdev: the vdpa device to be unregisted from vDPA bus
+ */
+void vdpa_unregister_device(struct vdpa_device *vdev)
+{
+       device_unregister(&vdev->dev);
+}
+EXPORT_SYMBOL_GPL(vdpa_unregister_device);
+
+/**
+ * __vdpa_register_driver - register a vDPA device driver
+ * @drv: the vdpa device driver to be registered
+ * @owner: module owner of the driver
+ *
+ * Returns an err when fail to do the registration
+ */
+int __vdpa_register_driver(struct vdpa_driver *drv, struct module *owner)
+{
+       drv->driver.bus = &vdpa_bus;
+       drv->driver.owner = owner;
+
+       return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(__vdpa_register_driver);
+
+/**
+ * vdpa_unregister_driver - unregister a vDPA device driver
+ * @drv: the vdpa device driver to be unregistered
+ */
+void vdpa_unregister_driver(struct vdpa_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(vdpa_unregister_driver);
+
+static int vdpa_init(void)
+{
+       return bus_register(&vdpa_bus);
+}
+
+static void __exit vdpa_exit(void)
+{
+       bus_unregister(&vdpa_bus);
+       ida_destroy(&vdpa_index_ida);
+}
+core_initcall(vdpa_init);
+module_exit(vdpa_exit);
+
+MODULE_AUTHOR("Jason Wang <jasowang@redhat.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/vdpa/vdpa_sim/Makefile b/drivers/vdpa/vdpa_sim/Makefile
new file mode 100644 (file)
index 0000000..b40278f
--- /dev/null
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_VDPA_SIM) += vdpa_sim.o
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c
new file mode 100644 (file)
index 0000000..6e8a0cf
--- /dev/null
@@ -0,0 +1,629 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * VDPA networking device simulator.
+ *
+ * Copyright (c) 2020, Red Hat Inc. All rights reserved.
+ *     Author: Jason Wang <jasowang@redhat.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uuid.h>
+#include <linux/iommu.h>
+#include <linux/dma-mapping.h>
+#include <linux/sysfs.h>
+#include <linux/file.h>
+#include <linux/etherdevice.h>
+#include <linux/vringh.h>
+#include <linux/vdpa.h>
+#include <linux/vhost_iotlb.h>
+#include <uapi/linux/virtio_config.h>
+#include <uapi/linux/virtio_net.h>
+
+#define DRV_VERSION  "0.1"
+#define DRV_AUTHOR   "Jason Wang <jasowang@redhat.com>"
+#define DRV_DESC     "vDPA Device Simulator"
+#define DRV_LICENSE  "GPL v2"
+
+struct vdpasim_virtqueue {
+       struct vringh vring;
+       struct vringh_kiov iov;
+       unsigned short head;
+       bool ready;
+       u64 desc_addr;
+       u64 device_addr;
+       u64 driver_addr;
+       u32 num;
+       void *private;
+       irqreturn_t (*cb)(void *data);
+};
+
+#define VDPASIM_QUEUE_ALIGN PAGE_SIZE
+#define VDPASIM_QUEUE_MAX 256
+#define VDPASIM_DEVICE_ID 0x1
+#define VDPASIM_VENDOR_ID 0
+#define VDPASIM_VQ_NUM 0x2
+#define VDPASIM_NAME "vdpasim-netdev"
+
+static u64 vdpasim_features = (1ULL << VIRTIO_F_ANY_LAYOUT) |
+                             (1ULL << VIRTIO_F_VERSION_1)  |
+                             (1ULL << VIRTIO_F_IOMMU_PLATFORM);
+
+/* State of each vdpasim device */
+struct vdpasim {
+       struct vdpa_device vdpa;
+       struct vdpasim_virtqueue vqs[2];
+       struct work_struct work;
+       /* spinlock to synchronize virtqueue state */
+       spinlock_t lock;
+       struct virtio_net_config config;
+       struct vhost_iotlb *iommu;
+       void *buffer;
+       u32 status;
+       u32 generation;
+       u64 features;
+};
+
+static struct vdpasim *vdpasim_dev;
+
+static struct vdpasim *vdpa_to_sim(struct vdpa_device *vdpa)
+{
+       return container_of(vdpa, struct vdpasim, vdpa);
+}
+
+static struct vdpasim *dev_to_sim(struct device *dev)
+{
+       struct vdpa_device *vdpa = dev_to_vdpa(dev);
+
+       return vdpa_to_sim(vdpa);
+}
+
+static void vdpasim_queue_ready(struct vdpasim *vdpasim, unsigned int idx)
+{
+       struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx];
+       int ret;
+
+       ret = vringh_init_iotlb(&vq->vring, vdpasim_features,
+                               VDPASIM_QUEUE_MAX, false,
+                               (struct vring_desc *)(uintptr_t)vq->desc_addr,
+                               (struct vring_avail *)
+                               (uintptr_t)vq->driver_addr,
+                               (struct vring_used *)
+                               (uintptr_t)vq->device_addr);
+}
+
+static void vdpasim_vq_reset(struct vdpasim_virtqueue *vq)
+{
+       vq->ready = 0;
+       vq->desc_addr = 0;
+       vq->driver_addr = 0;
+       vq->device_addr = 0;
+       vq->cb = NULL;
+       vq->private = NULL;
+       vringh_init_iotlb(&vq->vring, vdpasim_features, VDPASIM_QUEUE_MAX,
+                         false, NULL, NULL, NULL);
+}
+
+static void vdpasim_reset(struct vdpasim *vdpasim)
+{
+       int i;
+
+       for (i = 0; i < VDPASIM_VQ_NUM; i++)
+               vdpasim_vq_reset(&vdpasim->vqs[i]);
+
+       vhost_iotlb_reset(vdpasim->iommu);
+
+       vdpasim->features = 0;
+       vdpasim->status = 0;
+       ++vdpasim->generation;
+}
+
+static void vdpasim_work(struct work_struct *work)
+{
+       struct vdpasim *vdpasim = container_of(work, struct
+                                                vdpasim, work);
+       struct vdpasim_virtqueue *txq = &vdpasim->vqs[1];
+       struct vdpasim_virtqueue *rxq = &vdpasim->vqs[0];
+       size_t read, write, total_write;
+       int err;
+       int pkts = 0;
+
+       spin_lock(&vdpasim->lock);
+
+       if (!(vdpasim->status & VIRTIO_CONFIG_S_DRIVER_OK))
+               goto out;
+
+       if (!txq->ready || !rxq->ready)
+               goto out;
+
+       while (true) {
+               total_write = 0;
+               err = vringh_getdesc_iotlb(&txq->vring, &txq->iov, NULL,
+                                          &txq->head, GFP_ATOMIC);
+               if (err <= 0)
+                       break;
+
+               err = vringh_getdesc_iotlb(&rxq->vring, NULL, &rxq->iov,
+                                          &rxq->head, GFP_ATOMIC);
+               if (err <= 0) {
+                       vringh_complete_iotlb(&txq->vring, txq->head, 0);
+                       break;
+               }
+
+               while (true) {
+                       read = vringh_iov_pull_iotlb(&txq->vring, &txq->iov,
+                                                    vdpasim->buffer,
+                                                    PAGE_SIZE);
+                       if (read <= 0)
+                               break;
+
+                       write = vringh_iov_push_iotlb(&rxq->vring, &rxq->iov,
+                                                     vdpasim->buffer, read);
+                       if (write <= 0)
+                               break;
+
+                       total_write += write;
+               }
+
+               /* Make sure data is wrote before advancing index */
+               smp_wmb();
+
+               vringh_complete_iotlb(&txq->vring, txq->head, 0);
+               vringh_complete_iotlb(&rxq->vring, rxq->head, total_write);
+
+               /* Make sure used is visible before rasing the interrupt. */
+               smp_wmb();
+
+               local_bh_disable();
+               if (txq->cb)
+                       txq->cb(txq->private);
+               if (rxq->cb)
+                       rxq->cb(rxq->private);
+               local_bh_enable();
+
+               if (++pkts > 4) {
+                       schedule_work(&vdpasim->work);
+                       goto out;
+               }
+       }
+
+out:
+       spin_unlock(&vdpasim->lock);
+}
+
+static int dir_to_perm(enum dma_data_direction dir)
+{
+       int perm = -EFAULT;
+
+       switch (dir) {
+       case DMA_FROM_DEVICE:
+               perm = VHOST_MAP_WO;
+               break;
+       case DMA_TO_DEVICE:
+               perm = VHOST_MAP_RO;
+               break;
+       case DMA_BIDIRECTIONAL:
+               perm = VHOST_MAP_RW;
+               break;
+       default:
+               break;
+       }
+
+       return perm;
+}
+
+static dma_addr_t vdpasim_map_page(struct device *dev, struct page *page,
+                                  unsigned long offset, size_t size,
+                                  enum dma_data_direction dir,
+                                  unsigned long attrs)
+{
+       struct vdpasim *vdpasim = dev_to_sim(dev);
+       struct vhost_iotlb *iommu = vdpasim->iommu;
+       u64 pa = (page_to_pfn(page) << PAGE_SHIFT) + offset;
+       int ret, perm = dir_to_perm(dir);
+
+       if (perm < 0)
+               return DMA_MAPPING_ERROR;
+
+       /* For simplicity, use identical mapping to avoid e.g iova
+        * allocator.
+        */
+       ret = vhost_iotlb_add_range(iommu, pa, pa + size - 1,
+                                   pa, dir_to_perm(dir));
+       if (ret)
+               return DMA_MAPPING_ERROR;
+
+       return (dma_addr_t)(pa);
+}
+
+static void vdpasim_unmap_page(struct device *dev, dma_addr_t dma_addr,
+                              size_t size, enum dma_data_direction dir,
+                              unsigned long attrs)
+{
+       struct vdpasim *vdpasim = dev_to_sim(dev);
+       struct vhost_iotlb *iommu = vdpasim->iommu;
+
+       vhost_iotlb_del_range(iommu, (u64)dma_addr,
+                             (u64)dma_addr + size - 1);
+}
+
+static void *vdpasim_alloc_coherent(struct device *dev, size_t size,
+                                   dma_addr_t *dma_addr, gfp_t flag,
+                                   unsigned long attrs)
+{
+       struct vdpasim *vdpasim = dev_to_sim(dev);
+       struct vhost_iotlb *iommu = vdpasim->iommu;
+       void *addr = kmalloc(size, flag);
+       int ret;
+
+       if (!addr)
+               *dma_addr = DMA_MAPPING_ERROR;
+       else {
+               u64 pa = virt_to_phys(addr);
+
+               ret = vhost_iotlb_add_range(iommu, (u64)pa,
+                                           (u64)pa + size - 1,
+                                           pa, VHOST_MAP_RW);
+               if (ret) {
+                       *dma_addr = DMA_MAPPING_ERROR;
+                       kfree(addr);
+                       addr = NULL;
+               } else
+                       *dma_addr = (dma_addr_t)pa;
+       }
+
+       return addr;
+}
+
+static void vdpasim_free_coherent(struct device *dev, size_t size,
+                                 void *vaddr, dma_addr_t dma_addr,
+                                 unsigned long attrs)
+{
+       struct vdpasim *vdpasim = dev_to_sim(dev);
+       struct vhost_iotlb *iommu = vdpasim->iommu;
+
+       vhost_iotlb_del_range(iommu, (u64)dma_addr,
+                             (u64)dma_addr + size - 1);
+       kfree(phys_to_virt((uintptr_t)dma_addr));
+}
+
+static const struct dma_map_ops vdpasim_dma_ops = {
+       .map_page = vdpasim_map_page,
+       .unmap_page = vdpasim_unmap_page,
+       .alloc = vdpasim_alloc_coherent,
+       .free = vdpasim_free_coherent,
+};
+
+static const struct vdpa_config_ops vdpasim_net_config_ops;
+
+static struct vdpasim *vdpasim_create(void)
+{
+       struct virtio_net_config *config;
+       struct vdpasim *vdpasim;
+       struct device *dev;
+       int ret = -ENOMEM;
+
+       vdpasim = vdpa_alloc_device(struct vdpasim, vdpa, NULL,
+                                   &vdpasim_net_config_ops);
+       if (!vdpasim)
+               goto err_alloc;
+
+       INIT_WORK(&vdpasim->work, vdpasim_work);
+       spin_lock_init(&vdpasim->lock);
+
+       dev = &vdpasim->vdpa.dev;
+       dev->coherent_dma_mask = DMA_BIT_MASK(64);
+       set_dma_ops(dev, &vdpasim_dma_ops);
+
+       vdpasim->iommu = vhost_iotlb_alloc(2048, 0);
+       if (!vdpasim->iommu)
+               goto err_iommu;
+
+       vdpasim->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!vdpasim->buffer)
+               goto err_iommu;
+
+       config = &vdpasim->config;
+       config->mtu = 1500;
+       config->status = VIRTIO_NET_S_LINK_UP;
+       eth_random_addr(config->mac);
+
+       vringh_set_iotlb(&vdpasim->vqs[0].vring, vdpasim->iommu);
+       vringh_set_iotlb(&vdpasim->vqs[1].vring, vdpasim->iommu);
+
+       vdpasim->vdpa.dma_dev = dev;
+       ret = vdpa_register_device(&vdpasim->vdpa);
+       if (ret)
+               goto err_iommu;
+
+       return vdpasim;
+
+err_iommu:
+       put_device(dev);
+err_alloc:
+       return ERR_PTR(ret);
+}
+
+static int vdpasim_set_vq_address(struct vdpa_device *vdpa, u16 idx,
+                                 u64 desc_area, u64 driver_area,
+                                 u64 device_area)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+       struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx];
+
+       vq->desc_addr = desc_area;
+       vq->driver_addr = driver_area;
+       vq->device_addr = device_area;
+
+       return 0;
+}
+
+static void vdpasim_set_vq_num(struct vdpa_device *vdpa, u16 idx, u32 num)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+       struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx];
+
+       vq->num = num;
+}
+
+static void vdpasim_kick_vq(struct vdpa_device *vdpa, u16 idx)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+       struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx];
+
+       if (vq->ready)
+               schedule_work(&vdpasim->work);
+}
+
+static void vdpasim_set_vq_cb(struct vdpa_device *vdpa, u16 idx,
+                             struct vdpa_callback *cb)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+       struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx];
+
+       vq->cb = cb->callback;
+       vq->private = cb->private;
+}
+
+static void vdpasim_set_vq_ready(struct vdpa_device *vdpa, u16 idx, bool ready)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+       struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx];
+
+       spin_lock(&vdpasim->lock);
+       vq->ready = ready;
+       if (vq->ready)
+               vdpasim_queue_ready(vdpasim, idx);
+       spin_unlock(&vdpasim->lock);
+}
+
+static bool vdpasim_get_vq_ready(struct vdpa_device *vdpa, u16 idx)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+       struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx];
+
+       return vq->ready;
+}
+
+static int vdpasim_set_vq_state(struct vdpa_device *vdpa, u16 idx, u64 state)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+       struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx];
+       struct vringh *vrh = &vq->vring;
+
+       spin_lock(&vdpasim->lock);
+       vrh->last_avail_idx = state;
+       spin_unlock(&vdpasim->lock);
+
+       return 0;
+}
+
+static u64 vdpasim_get_vq_state(struct vdpa_device *vdpa, u16 idx)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+       struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx];
+       struct vringh *vrh = &vq->vring;
+
+       return vrh->last_avail_idx;
+}
+
+static u16 vdpasim_get_vq_align(struct vdpa_device *vdpa)
+{
+       return VDPASIM_QUEUE_ALIGN;
+}
+
+static u64 vdpasim_get_features(struct vdpa_device *vdpa)
+{
+       return vdpasim_features;
+}
+
+static int vdpasim_set_features(struct vdpa_device *vdpa, u64 features)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+
+       /* DMA mapping must be done by driver */
+       if (!(features & (1ULL << VIRTIO_F_IOMMU_PLATFORM)))
+               return -EINVAL;
+
+       vdpasim->features = features & vdpasim_features;
+
+       return 0;
+}
+
+static void vdpasim_set_config_cb(struct vdpa_device *vdpa,
+                                 struct vdpa_callback *cb)
+{
+       /* We don't support config interrupt */
+}
+
+static u16 vdpasim_get_vq_num_max(struct vdpa_device *vdpa)
+{
+       return VDPASIM_QUEUE_MAX;
+}
+
+static u32 vdpasim_get_device_id(struct vdpa_device *vdpa)
+{
+       return VDPASIM_DEVICE_ID;
+}
+
+static u32 vdpasim_get_vendor_id(struct vdpa_device *vdpa)
+{
+       return VDPASIM_VENDOR_ID;
+}
+
+static u8 vdpasim_get_status(struct vdpa_device *vdpa)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+       u8 status;
+
+       spin_lock(&vdpasim->lock);
+       status = vdpasim->status;
+       spin_unlock(&vdpasim->lock);
+
+       return vdpasim->status;
+}
+
+static void vdpasim_set_status(struct vdpa_device *vdpa, u8 status)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+
+       spin_lock(&vdpasim->lock);
+       vdpasim->status = status;
+       if (status == 0)
+               vdpasim_reset(vdpasim);
+       spin_unlock(&vdpasim->lock);
+}
+
+static void vdpasim_get_config(struct vdpa_device *vdpa, unsigned int offset,
+                            void *buf, unsigned int len)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+
+       if (offset + len < sizeof(struct virtio_net_config))
+               memcpy(buf, &vdpasim->config + offset, len);
+}
+
+static void vdpasim_set_config(struct vdpa_device *vdpa, unsigned int offset,
+                            const void *buf, unsigned int len)
+{
+       /* No writable config supportted by vdpasim */
+}
+
+static u32 vdpasim_get_generation(struct vdpa_device *vdpa)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+
+       return vdpasim->generation;
+}
+
+static int vdpasim_set_map(struct vdpa_device *vdpa,
+                          struct vhost_iotlb *iotlb)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+       struct vhost_iotlb_map *map;
+       u64 start = 0ULL, last = 0ULL - 1;
+       int ret;
+
+       vhost_iotlb_reset(vdpasim->iommu);
+
+       for (map = vhost_iotlb_itree_first(iotlb, start, last); map;
+            map = vhost_iotlb_itree_next(map, start, last)) {
+               ret = vhost_iotlb_add_range(vdpasim->iommu, map->start,
+                                           map->last, map->addr, map->perm);
+               if (ret)
+                       goto err;
+       }
+       return 0;
+
+err:
+       vhost_iotlb_reset(vdpasim->iommu);
+       return ret;
+}
+
+static int vdpasim_dma_map(struct vdpa_device *vdpa, u64 iova, u64 size,
+                          u64 pa, u32 perm)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+
+       return vhost_iotlb_add_range(vdpasim->iommu, iova,
+                                    iova + size - 1, pa, perm);
+}
+
+static int vdpasim_dma_unmap(struct vdpa_device *vdpa, u64 iova, u64 size)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+
+       vhost_iotlb_del_range(vdpasim->iommu, iova, iova + size - 1);
+
+       return 0;
+}
+
+static void vdpasim_free(struct vdpa_device *vdpa)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+
+       cancel_work_sync(&vdpasim->work);
+       kfree(vdpasim->buffer);
+       if (vdpasim->iommu)
+               vhost_iotlb_free(vdpasim->iommu);
+}
+
+static const struct vdpa_config_ops vdpasim_net_config_ops = {
+       .set_vq_address         = vdpasim_set_vq_address,
+       .set_vq_num             = vdpasim_set_vq_num,
+       .kick_vq                = vdpasim_kick_vq,
+       .set_vq_cb              = vdpasim_set_vq_cb,
+       .set_vq_ready           = vdpasim_set_vq_ready,
+       .get_vq_ready           = vdpasim_get_vq_ready,
+       .set_vq_state           = vdpasim_set_vq_state,
+       .get_vq_state           = vdpasim_get_vq_state,
+       .get_vq_align           = vdpasim_get_vq_align,
+       .get_features           = vdpasim_get_features,
+       .set_features           = vdpasim_set_features,
+       .set_config_cb          = vdpasim_set_config_cb,
+       .get_vq_num_max         = vdpasim_get_vq_num_max,
+       .get_device_id          = vdpasim_get_device_id,
+       .get_vendor_id          = vdpasim_get_vendor_id,
+       .get_status             = vdpasim_get_status,
+       .set_status             = vdpasim_set_status,
+       .get_config             = vdpasim_get_config,
+       .set_config             = vdpasim_set_config,
+       .get_generation         = vdpasim_get_generation,
+       .set_map                = vdpasim_set_map,
+       .dma_map                = vdpasim_dma_map,
+       .dma_unmap              = vdpasim_dma_unmap,
+       .free                   = vdpasim_free,
+};
+
+static int __init vdpasim_dev_init(void)
+{
+       vdpasim_dev = vdpasim_create();
+
+       if (!IS_ERR(vdpasim_dev))
+               return 0;
+
+       return PTR_ERR(vdpasim_dev);
+}
+
+static void __exit vdpasim_dev_exit(void)
+{
+       struct vdpa_device *vdpa = &vdpasim_dev->vdpa;
+
+       vdpa_unregister_device(vdpa);
+}
+
+module_init(vdpasim_dev_init)
+module_exit(vdpasim_dev_exit)
+
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE(DRV_LICENSE);
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION(DRV_DESC);
index 3d03ccb..362b832 100644 (file)
@@ -1,4 +1,29 @@
 # SPDX-License-Identifier: GPL-2.0-only
+config VHOST_IOTLB
+       tristate
+       help
+         Generic IOTLB implementation for vhost and vringh.
+
+config VHOST_RING
+       tristate
+       select VHOST_IOTLB
+       help
+         This option is selected by any driver which needs to access
+         the host side of a virtio ring.
+
+config VHOST
+       tristate
+       select VHOST_IOTLB
+       help
+         This option is selected by any driver which needs to access
+         the core of vhost.
+
+menuconfig VHOST_MENU
+       bool "VHOST drivers"
+       default y
+
+if VHOST_MENU
+
 config VHOST_NET
        tristate "Host kernel accelerator for virtio net"
        depends on NET && EVENTFD && (TUN || !TUN) && (TAP || !TAP)
@@ -23,8 +48,8 @@ config VHOST_SCSI
 config VHOST_VSOCK
        tristate "vhost virtio-vsock driver"
        depends on VSOCKETS && EVENTFD
-       select VIRTIO_VSOCKETS_COMMON
        select VHOST
+       select VIRTIO_VSOCKETS_COMMON
        default n
        ---help---
        This kernel module can be loaded in the host kernel to provide AF_VSOCK
@@ -34,11 +59,17 @@ config VHOST_VSOCK
        To compile this driver as a module, choose M here: the module will be called
        vhost_vsock.
 
-config VHOST
-       tristate
-       ---help---
-         This option is selected by any driver which needs to access
-         the core of vhost.
+config VHOST_VDPA
+       tristate "Vhost driver for vDPA-based backend"
+       depends on EVENTFD
+       select VHOST
+       select VDPA
+       help
+         This kernel module can be loaded in host kernel to accelerate
+         guest virtio devices with the vDPA-based backends.
+
+         To compile this driver as a module, choose M here: the module
+         will be called vhost_vdpa.
 
 config VHOST_CROSS_ENDIAN_LEGACY
        bool "Cross-endian support for vhost"
@@ -54,3 +85,5 @@ config VHOST_CROSS_ENDIAN_LEGACY
          adds some overhead, it is disabled by default.
 
          If unsure, say "N".
+
+endif
diff --git a/drivers/vhost/Kconfig.vringh b/drivers/vhost/Kconfig.vringh
deleted file mode 100644 (file)
index c1fe36a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config VHOST_RING
-       tristate
-       ---help---
-         This option is selected by any driver which needs to access
-         the host side of a virtio ring.
index 6c6df24..f3e1897 100644 (file)
@@ -10,4 +10,10 @@ vhost_vsock-y := vsock.o
 
 obj-$(CONFIG_VHOST_RING) += vringh.o
 
+obj-$(CONFIG_VHOST_VDPA) += vhost_vdpa.o
+vhost_vdpa-y := vdpa.o
+
 obj-$(CONFIG_VHOST)    += vhost.o
+
+obj-$(CONFIG_VHOST_IOTLB) += vhost_iotlb.o
+vhost_iotlb-y := iotlb.o
diff --git a/drivers/vhost/iotlb.c b/drivers/vhost/iotlb.c
new file mode 100644 (file)
index 0000000..1f0ca6e
--- /dev/null
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2020 Red Hat, Inc.
+ * Author: Jason Wang <jasowang@redhat.com>
+ *
+ * IOTLB implementation for vhost.
+ */
+#include <linux/slab.h>
+#include <linux/vhost_iotlb.h>
+#include <linux/module.h>
+
+#define MOD_VERSION  "0.1"
+#define MOD_DESC     "VHOST IOTLB"
+#define MOD_AUTHOR   "Jason Wang <jasowang@redhat.com>"
+#define MOD_LICENSE  "GPL v2"
+
+#define START(map) ((map)->start)
+#define LAST(map) ((map)->last)
+
+INTERVAL_TREE_DEFINE(struct vhost_iotlb_map,
+                    rb, __u64, __subtree_last,
+                    START, LAST, static inline, vhost_iotlb_itree);
+
+/**
+ * vhost_iotlb_map_free - remove a map node and free it
+ * @iotlb: the IOTLB
+ * @map: the map that want to be remove and freed
+ */
+void vhost_iotlb_map_free(struct vhost_iotlb *iotlb,
+                         struct vhost_iotlb_map *map)
+{
+       vhost_iotlb_itree_remove(map, &iotlb->root);
+       list_del(&map->link);
+       kfree(map);
+       iotlb->nmaps--;
+}
+EXPORT_SYMBOL_GPL(vhost_iotlb_map_free);
+
+/**
+ * vhost_iotlb_add_range - add a new range to vhost IOTLB
+ * @iotlb: the IOTLB
+ * @start: start of the IOVA range
+ * @last: last of IOVA range
+ * @addr: the address that is mapped to @start
+ * @perm: access permission of this range
+ *
+ * Returns an error last is smaller than start or memory allocation
+ * fails
+ */
+int vhost_iotlb_add_range(struct vhost_iotlb *iotlb,
+                         u64 start, u64 last,
+                         u64 addr, unsigned int perm)
+{
+       struct vhost_iotlb_map *map;
+
+       if (last < start)
+               return -EFAULT;
+
+       if (iotlb->limit &&
+           iotlb->nmaps == iotlb->limit &&
+           iotlb->flags & VHOST_IOTLB_FLAG_RETIRE) {
+               map = list_first_entry(&iotlb->list, typeof(*map), link);
+               vhost_iotlb_map_free(iotlb, map);
+       }
+
+       map = kmalloc(sizeof(*map), GFP_ATOMIC);
+       if (!map)
+               return -ENOMEM;
+
+       map->start = start;
+       map->size = last - start + 1;
+       map->last = last;
+       map->addr = addr;
+       map->perm = perm;
+
+       iotlb->nmaps++;
+       vhost_iotlb_itree_insert(map, &iotlb->root);
+
+       INIT_LIST_HEAD(&map->link);
+       list_add_tail(&map->link, &iotlb->list);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vhost_iotlb_add_range);
+
+/**
+ * vring_iotlb_del_range - delete overlapped ranges from vhost IOTLB
+ * @iotlb: the IOTLB
+ * @start: start of the IOVA range
+ * @last: last of IOVA range
+ */
+void vhost_iotlb_del_range(struct vhost_iotlb *iotlb, u64 start, u64 last)
+{
+       struct vhost_iotlb_map *map;
+
+       while ((map = vhost_iotlb_itree_iter_first(&iotlb->root,
+                                                  start, last)))
+               vhost_iotlb_map_free(iotlb, map);
+}
+EXPORT_SYMBOL_GPL(vhost_iotlb_del_range);
+
+/**
+ * vhost_iotlb_alloc - add a new vhost IOTLB
+ * @limit: maximum number of IOTLB entries
+ * @flags: VHOST_IOTLB_FLAG_XXX
+ *
+ * Returns an error is memory allocation fails
+ */
+struct vhost_iotlb *vhost_iotlb_alloc(unsigned int limit, unsigned int flags)
+{
+       struct vhost_iotlb *iotlb = kzalloc(sizeof(*iotlb), GFP_KERNEL);
+
+       if (!iotlb)
+               return NULL;
+
+       iotlb->root = RB_ROOT_CACHED;
+       iotlb->limit = limit;
+       iotlb->nmaps = 0;
+       iotlb->flags = flags;
+       INIT_LIST_HEAD(&iotlb->list);
+
+       return iotlb;
+}
+EXPORT_SYMBOL_GPL(vhost_iotlb_alloc);
+
+/**
+ * vhost_iotlb_reset - reset vhost IOTLB (free all IOTLB entries)
+ * @iotlb: the IOTLB to be reset
+ */
+void vhost_iotlb_reset(struct vhost_iotlb *iotlb)
+{
+       vhost_iotlb_del_range(iotlb, 0ULL, 0ULL - 1);
+}
+EXPORT_SYMBOL_GPL(vhost_iotlb_reset);
+
+/**
+ * vhost_iotlb_free - reset and free vhost IOTLB
+ * @iotlb: the IOTLB to be freed
+ */
+void vhost_iotlb_free(struct vhost_iotlb *iotlb)
+{
+       if (iotlb) {
+               vhost_iotlb_reset(iotlb);
+               kfree(iotlb);
+       }
+}
+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
+ */
+struct vhost_iotlb_map *
+vhost_iotlb_itree_first(struct vhost_iotlb *iotlb, u64 start, u64 last)
+{
+       return vhost_iotlb_itree_iter_first(&iotlb->root, start, last);
+}
+EXPORT_SYMBOL_GPL(vhost_iotlb_itree_first);
+
+/**
+ * vhost_iotlb_itree_first - return the next overlapped range
+ * @iotlb: the IOTLB
+ * @start: start of IOVA range
+ * @end: end of IOVA range
+ */
+struct vhost_iotlb_map *
+vhost_iotlb_itree_next(struct vhost_iotlb_map *map, u64 start, u64 last)
+{
+       return vhost_iotlb_itree_iter_next(map, start, last);
+}
+EXPORT_SYMBOL_GPL(vhost_iotlb_itree_next);
+
+MODULE_VERSION(MOD_VERSION);
+MODULE_DESCRIPTION(MOD_DESC);
+MODULE_AUTHOR(MOD_AUTHOR);
+MODULE_LICENSE(MOD_LICENSE);
index 18e205e..87469d6 100644 (file)
@@ -1324,7 +1324,8 @@ static int vhost_net_open(struct inode *inode, struct file *f)
        }
        vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX,
                       UIO_MAXIOV + VHOST_NET_BATCH,
-                      VHOST_NET_PKT_WEIGHT, VHOST_NET_WEIGHT);
+                      VHOST_NET_PKT_WEIGHT, VHOST_NET_WEIGHT,
+                      NULL);
 
        vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, EPOLLOUT, dev);
        vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, EPOLLIN, dev);
@@ -1586,7 +1587,7 @@ static long vhost_net_reset_owner(struct vhost_net *n)
        struct socket *tx_sock = NULL;
        struct socket *rx_sock = NULL;
        long err;
-       struct vhost_umem *umem;
+       struct vhost_iotlb *umem;
 
        mutex_lock(&n->dev.mutex);
        err = vhost_dev_check_owner(&n->dev);
index 0b949a1..7653667 100644 (file)
@@ -1628,7 +1628,7 @@ static int vhost_scsi_open(struct inode *inode, struct file *f)
                vs->vqs[i].vq.handle_kick = vhost_scsi_handle_kick;
        }
        vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ, UIO_MAXIOV,
-                      VHOST_SCSI_WEIGHT, 0);
+                      VHOST_SCSI_WEIGHT, 0, NULL);
 
        vhost_scsi_init_inflight(vs, NULL);
 
diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
new file mode 100644 (file)
index 0000000..421f02a
--- /dev/null
@@ -0,0 +1,883 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018-2020 Intel Corporation.
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * Author: Tiwei Bie <tiwei.bie@intel.com>
+ *         Jason Wang <jasowang@redhat.com>
+ *
+ * Thanks Michael S. Tsirkin for the valuable comments and
+ * suggestions.  And thanks to Cunming Liang and Zhihong Wang for all
+ * their supports.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/iommu.h>
+#include <linux/uuid.h>
+#include <linux/vdpa.h>
+#include <linux/nospec.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+
+#include "vhost.h"
+
+enum {
+       VHOST_VDPA_FEATURES =
+               (1ULL << VIRTIO_F_NOTIFY_ON_EMPTY) |
+               (1ULL << VIRTIO_F_ANY_LAYOUT) |
+               (1ULL << VIRTIO_F_VERSION_1) |
+               (1ULL << VIRTIO_F_IOMMU_PLATFORM) |
+               (1ULL << VIRTIO_F_RING_PACKED) |
+               (1ULL << VIRTIO_F_ORDER_PLATFORM) |
+               (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
+               (1ULL << VIRTIO_RING_F_EVENT_IDX),
+
+       VHOST_VDPA_NET_FEATURES = VHOST_VDPA_FEATURES |
+               (1ULL << VIRTIO_NET_F_CSUM) |
+               (1ULL << VIRTIO_NET_F_GUEST_CSUM) |
+               (1ULL << VIRTIO_NET_F_MTU) |
+               (1ULL << VIRTIO_NET_F_MAC) |
+               (1ULL << VIRTIO_NET_F_GUEST_TSO4) |
+               (1ULL << VIRTIO_NET_F_GUEST_TSO6) |
+               (1ULL << VIRTIO_NET_F_GUEST_ECN) |
+               (1ULL << VIRTIO_NET_F_GUEST_UFO) |
+               (1ULL << VIRTIO_NET_F_HOST_TSO4) |
+               (1ULL << VIRTIO_NET_F_HOST_TSO6) |
+               (1ULL << VIRTIO_NET_F_HOST_ECN) |
+               (1ULL << VIRTIO_NET_F_HOST_UFO) |
+               (1ULL << VIRTIO_NET_F_MRG_RXBUF) |
+               (1ULL << VIRTIO_NET_F_STATUS) |
+               (1ULL << VIRTIO_NET_F_SPEED_DUPLEX),
+};
+
+/* Currently, only network backend w/o multiqueue is supported. */
+#define VHOST_VDPA_VQ_MAX      2
+
+#define VHOST_VDPA_DEV_MAX (1U << MINORBITS)
+
+struct vhost_vdpa {
+       struct vhost_dev vdev;
+       struct iommu_domain *domain;
+       struct vhost_virtqueue *vqs;
+       struct completion completion;
+       struct vdpa_device *vdpa;
+       struct device dev;
+       struct cdev cdev;
+       atomic_t opened;
+       int nvqs;
+       int virtio_id;
+       int minor;
+};
+
+static DEFINE_IDA(vhost_vdpa_ida);
+
+static dev_t vhost_vdpa_major;
+
+static const u64 vhost_vdpa_features[] = {
+       [VIRTIO_ID_NET] = VHOST_VDPA_NET_FEATURES,
+};
+
+static void handle_vq_kick(struct vhost_work *work)
+{
+       struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
+                                                 poll.work);
+       struct vhost_vdpa *v = container_of(vq->dev, struct vhost_vdpa, vdev);
+       const struct vdpa_config_ops *ops = v->vdpa->config;
+
+       ops->kick_vq(v->vdpa, vq - v->vqs);
+}
+
+static irqreturn_t vhost_vdpa_virtqueue_cb(void *private)
+{
+       struct vhost_virtqueue *vq = private;
+       struct eventfd_ctx *call_ctx = vq->call_ctx;
+
+       if (call_ctx)
+               eventfd_signal(call_ctx, 1);
+
+       return IRQ_HANDLED;
+}
+
+static void vhost_vdpa_reset(struct vhost_vdpa *v)
+{
+       struct vdpa_device *vdpa = v->vdpa;
+       const struct vdpa_config_ops *ops = vdpa->config;
+
+       ops->set_status(vdpa, 0);
+}
+
+static long vhost_vdpa_get_device_id(struct vhost_vdpa *v, u8 __user *argp)
+{
+       struct vdpa_device *vdpa = v->vdpa;
+       const struct vdpa_config_ops *ops = vdpa->config;
+       u32 device_id;
+
+       device_id = ops->get_device_id(vdpa);
+
+       if (copy_to_user(argp, &device_id, sizeof(device_id)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static long vhost_vdpa_get_status(struct vhost_vdpa *v, u8 __user *statusp)
+{
+       struct vdpa_device *vdpa = v->vdpa;
+       const struct vdpa_config_ops *ops = vdpa->config;
+       u8 status;
+
+       status = ops->get_status(vdpa);
+
+       if (copy_to_user(statusp, &status, sizeof(status)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static long vhost_vdpa_set_status(struct vhost_vdpa *v, u8 __user *statusp)
+{
+       struct vdpa_device *vdpa = v->vdpa;
+       const struct vdpa_config_ops *ops = vdpa->config;
+       u8 status;
+
+       if (copy_from_user(&status, statusp, sizeof(status)))
+               return -EFAULT;
+
+       /*
+        * Userspace shouldn't remove status bits unless reset the
+        * status to 0.
+        */
+       if (status != 0 && (ops->get_status(vdpa) & ~status) != 0)
+               return -EINVAL;
+
+       ops->set_status(vdpa, status);
+
+       return 0;
+}
+
+static int vhost_vdpa_config_validate(struct vhost_vdpa *v,
+                                     struct vhost_vdpa_config *c)
+{
+       long size = 0;
+
+       switch (v->virtio_id) {
+       case VIRTIO_ID_NET:
+               size = sizeof(struct virtio_net_config);
+               break;
+       }
+
+       if (c->len == 0)
+               return -EINVAL;
+
+       if (c->len > size - c->off)
+               return -E2BIG;
+
+       return 0;
+}
+
+static long vhost_vdpa_get_config(struct vhost_vdpa *v,
+                                 struct vhost_vdpa_config __user *c)
+{
+       struct vdpa_device *vdpa = v->vdpa;
+       const struct vdpa_config_ops *ops = vdpa->config;
+       struct vhost_vdpa_config config;
+       unsigned long size = offsetof(struct vhost_vdpa_config, buf);
+       u8 *buf;
+
+       if (copy_from_user(&config, c, size))
+               return -EFAULT;
+       if (vhost_vdpa_config_validate(v, &config))
+               return -EINVAL;
+       buf = kvzalloc(config.len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ops->get_config(vdpa, config.off, buf, config.len);
+
+       if (copy_to_user(c->buf, buf, config.len)) {
+               kvfree(buf);
+               return -EFAULT;
+       }
+
+       kvfree(buf);
+       return 0;
+}
+
+static long vhost_vdpa_set_config(struct vhost_vdpa *v,
+                                 struct vhost_vdpa_config __user *c)
+{
+       struct vdpa_device *vdpa = v->vdpa;
+       const struct vdpa_config_ops *ops = vdpa->config;
+       struct vhost_vdpa_config config;
+       unsigned long size = offsetof(struct vhost_vdpa_config, buf);
+       u8 *buf;
+
+       if (copy_from_user(&config, c, size))
+               return -EFAULT;
+       if (vhost_vdpa_config_validate(v, &config))
+               return -EINVAL;
+       buf = kvzalloc(config.len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       if (copy_from_user(buf, c->buf, config.len)) {
+               kvfree(buf);
+               return -EFAULT;
+       }
+
+       ops->set_config(vdpa, config.off, buf, config.len);
+
+       kvfree(buf);
+       return 0;
+}
+
+static long vhost_vdpa_get_features(struct vhost_vdpa *v, u64 __user *featurep)
+{
+       struct vdpa_device *vdpa = v->vdpa;
+       const struct vdpa_config_ops *ops = vdpa->config;
+       u64 features;
+
+       features = ops->get_features(vdpa);
+       features &= vhost_vdpa_features[v->virtio_id];
+
+       if (copy_to_user(featurep, &features, sizeof(features)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static long vhost_vdpa_set_features(struct vhost_vdpa *v, u64 __user *featurep)
+{
+       struct vdpa_device *vdpa = v->vdpa;
+       const struct vdpa_config_ops *ops = vdpa->config;
+       u64 features;
+
+       /*
+        * It's not allowed to change the features after they have
+        * been negotiated.
+        */
+       if (ops->get_status(vdpa) & VIRTIO_CONFIG_S_FEATURES_OK)
+               return -EBUSY;
+
+       if (copy_from_user(&features, featurep, sizeof(features)))
+               return -EFAULT;
+
+       if (features & ~vhost_vdpa_features[v->virtio_id])
+               return -EINVAL;
+
+       if (ops->set_features(vdpa, features))
+               return -EINVAL;
+
+       return 0;
+}
+
+static long vhost_vdpa_get_vring_num(struct vhost_vdpa *v, u16 __user *argp)
+{
+       struct vdpa_device *vdpa = v->vdpa;
+       const struct vdpa_config_ops *ops = vdpa->config;
+       u16 num;
+
+       num = ops->get_vq_num_max(vdpa);
+
+       if (copy_to_user(argp, &num, sizeof(num)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
+                                  void __user *argp)
+{
+       struct vdpa_device *vdpa = v->vdpa;
+       const struct vdpa_config_ops *ops = vdpa->config;
+       struct vdpa_callback cb;
+       struct vhost_virtqueue *vq;
+       struct vhost_vring_state s;
+       u8 status;
+       u32 idx;
+       long r;
+
+       r = get_user(idx, (u32 __user *)argp);
+       if (r < 0)
+               return r;
+
+       if (idx >= v->nvqs)
+               return -ENOBUFS;
+
+       idx = array_index_nospec(idx, v->nvqs);
+       vq = &v->vqs[idx];
+
+       status = ops->get_status(vdpa);
+
+       if (cmd == VHOST_VDPA_SET_VRING_ENABLE) {
+               if (copy_from_user(&s, argp, sizeof(s)))
+                       return -EFAULT;
+               ops->set_vq_ready(vdpa, idx, s.num);
+               return 0;
+       }
+
+       if (cmd == VHOST_GET_VRING_BASE)
+               vq->last_avail_idx = ops->get_vq_state(v->vdpa, idx);
+
+       r = vhost_vring_ioctl(&v->vdev, cmd, argp);
+       if (r)
+               return r;
+
+       switch (cmd) {
+       case VHOST_SET_VRING_ADDR:
+               if (ops->set_vq_address(vdpa, idx,
+                                       (u64)(uintptr_t)vq->desc,
+                                       (u64)(uintptr_t)vq->avail,
+                                       (u64)(uintptr_t)vq->used))
+                       r = -EINVAL;
+               break;
+
+       case VHOST_SET_VRING_BASE:
+               if (ops->set_vq_state(vdpa, idx, vq->last_avail_idx))
+                       r = -EINVAL;
+               break;
+
+       case VHOST_SET_VRING_CALL:
+               if (vq->call_ctx) {
+                       cb.callback = vhost_vdpa_virtqueue_cb;
+                       cb.private = vq;
+               } else {
+                       cb.callback = NULL;
+                       cb.private = NULL;
+               }
+               ops->set_vq_cb(vdpa, idx, &cb);
+               break;
+
+       case VHOST_SET_VRING_NUM:
+               ops->set_vq_num(vdpa, idx, vq->num);
+               break;
+       }
+
+       return r;
+}
+
+static long vhost_vdpa_unlocked_ioctl(struct file *filep,
+                                     unsigned int cmd, unsigned long arg)
+{
+       struct vhost_vdpa *v = filep->private_data;
+       struct vhost_dev *d = &v->vdev;
+       void __user *argp = (void __user *)arg;
+       long r;
+
+       mutex_lock(&d->mutex);
+
+       switch (cmd) {
+       case VHOST_VDPA_GET_DEVICE_ID:
+               r = vhost_vdpa_get_device_id(v, argp);
+               break;
+       case VHOST_VDPA_GET_STATUS:
+               r = vhost_vdpa_get_status(v, argp);
+               break;
+       case VHOST_VDPA_SET_STATUS:
+               r = vhost_vdpa_set_status(v, argp);
+               break;
+       case VHOST_VDPA_GET_CONFIG:
+               r = vhost_vdpa_get_config(v, argp);
+               break;
+       case VHOST_VDPA_SET_CONFIG:
+               r = vhost_vdpa_set_config(v, argp);
+               break;
+       case VHOST_GET_FEATURES:
+               r = vhost_vdpa_get_features(v, argp);
+               break;
+       case VHOST_SET_FEATURES:
+               r = vhost_vdpa_set_features(v, argp);
+               break;
+       case VHOST_VDPA_GET_VRING_NUM:
+               r = vhost_vdpa_get_vring_num(v, argp);
+               break;
+       case VHOST_SET_LOG_BASE:
+       case VHOST_SET_LOG_FD:
+               r = -ENOIOCTLCMD;
+               break;
+       default:
+               r = vhost_dev_ioctl(&v->vdev, cmd, argp);
+               if (r == -ENOIOCTLCMD)
+                       r = vhost_vdpa_vring_ioctl(v, cmd, argp);
+               break;
+       }
+
+       mutex_unlock(&d->mutex);
+       return r;
+}
+
+static void vhost_vdpa_iotlb_unmap(struct vhost_vdpa *v, u64 start, u64 last)
+{
+       struct vhost_dev *dev = &v->vdev;
+       struct vhost_iotlb *iotlb = dev->iotlb;
+       struct vhost_iotlb_map *map;
+       struct page *page;
+       unsigned long pfn, pinned;
+
+       while ((map = vhost_iotlb_itree_first(iotlb, start, last)) != NULL) {
+               pinned = map->size >> PAGE_SHIFT;
+               for (pfn = map->addr >> PAGE_SHIFT;
+                    pinned > 0; pfn++, pinned--) {
+                       page = pfn_to_page(pfn);
+                       if (map->perm & VHOST_ACCESS_WO)
+                               set_page_dirty_lock(page);
+                       unpin_user_page(page);
+               }
+               atomic64_sub(map->size >> PAGE_SHIFT, &dev->mm->pinned_vm);
+               vhost_iotlb_map_free(iotlb, map);
+       }
+}
+
+static void vhost_vdpa_iotlb_free(struct vhost_vdpa *v)
+{
+       struct vhost_dev *dev = &v->vdev;
+
+       vhost_vdpa_iotlb_unmap(v, 0ULL, 0ULL - 1);
+       kfree(dev->iotlb);
+       dev->iotlb = NULL;
+}
+
+static int perm_to_iommu_flags(u32 perm)
+{
+       int flags = 0;
+
+       switch (perm) {
+       case VHOST_ACCESS_WO:
+               flags |= IOMMU_WRITE;
+               break;
+       case VHOST_ACCESS_RO:
+               flags |= IOMMU_READ;
+               break;
+       case VHOST_ACCESS_RW:
+               flags |= (IOMMU_WRITE | IOMMU_READ);
+               break;
+       default:
+               WARN(1, "invalidate vhost IOTLB permission\n");
+               break;
+       }
+
+       return flags | IOMMU_CACHE;
+}
+
+static int vhost_vdpa_map(struct vhost_vdpa *v,
+                         u64 iova, u64 size, u64 pa, u32 perm)
+{
+       struct vhost_dev *dev = &v->vdev;
+       struct vdpa_device *vdpa = v->vdpa;
+       const struct vdpa_config_ops *ops = vdpa->config;
+       int r = 0;
+
+       r = vhost_iotlb_add_range(dev->iotlb, iova, iova + size - 1,
+                                 pa, perm);
+       if (r)
+               return r;
+
+       if (ops->dma_map)
+               r = ops->dma_map(vdpa, iova, size, pa, perm);
+       else if (ops->set_map)
+               r = ops->set_map(vdpa, dev->iotlb);
+       else
+               r = iommu_map(v->domain, iova, pa, size,
+                             perm_to_iommu_flags(perm));
+
+       return r;
+}
+
+static void vhost_vdpa_unmap(struct vhost_vdpa *v, u64 iova, u64 size)
+{
+       struct vhost_dev *dev = &v->vdev;
+       struct vdpa_device *vdpa = v->vdpa;
+       const struct vdpa_config_ops *ops = vdpa->config;
+
+       vhost_vdpa_iotlb_unmap(v, iova, iova + size - 1);
+
+       if (ops->dma_map)
+               ops->dma_unmap(vdpa, iova, size);
+       else if (ops->set_map)
+               ops->set_map(vdpa, dev->iotlb);
+       else
+               iommu_unmap(v->domain, iova, size);
+}
+
+static int vhost_vdpa_process_iotlb_update(struct vhost_vdpa *v,
+                                          struct vhost_iotlb_msg *msg)
+{
+       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 *);
+       unsigned int gup_flags = FOLL_LONGTERM;
+       unsigned long npages, cur_base, map_pfn, last_pfn = 0;
+       unsigned long locked, lock_limit, pinned, i;
+       u64 iova = msg->iova;
+       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;
+
+       npages = PAGE_ALIGN(msg->size + (iova & ~PAGE_MASK)) >> PAGE_SHIFT;
+       if (!npages)
+               return -EINVAL;
+
+       down_read(&dev->mm->mmap_sem);
+
+       locked = atomic64_add_return(npages, &dev->mm->pinned_vm);
+       lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+
+       if (locked > lock_limit) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       cur_base = msg->uaddr & PAGE_MASK;
+       iova &= PAGE_MASK;
+
+       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;
+                       }
+
+                       last_pfn = this_pfn;
+               }
+
+               cur_base += ret << PAGE_SHIFT;
+               npages -= ret;
+       }
+
+       /* Pin the rest chunk */
+       ret = vhost_vdpa_map(v, iova, (last_pfn - map_pfn + 1) << PAGE_SHIFT,
+                            map_pfn << PAGE_SHIFT, msg->perm);
+out:
+       if (ret) {
+               vhost_vdpa_unmap(v, msg->iova, msg->size);
+               atomic64_sub(npages, &dev->mm->pinned_vm);
+       }
+       up_read(&dev->mm->mmap_sem);
+       free_page((unsigned long)page_list);
+       return ret;
+}
+
+static int vhost_vdpa_process_iotlb_msg(struct vhost_dev *dev,
+                                       struct vhost_iotlb_msg *msg)
+{
+       struct vhost_vdpa *v = container_of(dev, struct vhost_vdpa, vdev);
+       int r = 0;
+
+       r = vhost_dev_check_owner(dev);
+       if (r)
+               return r;
+
+       switch (msg->type) {
+       case VHOST_IOTLB_UPDATE:
+               r = vhost_vdpa_process_iotlb_update(v, msg);
+               break;
+       case VHOST_IOTLB_INVALIDATE:
+               vhost_vdpa_unmap(v, msg->iova, msg->size);
+               break;
+       default:
+               r = -EINVAL;
+               break;
+       }
+
+       return r;
+}
+
+static ssize_t vhost_vdpa_chr_write_iter(struct kiocb *iocb,
+                                        struct iov_iter *from)
+{
+       struct file *file = iocb->ki_filp;
+       struct vhost_vdpa *v = file->private_data;
+       struct vhost_dev *dev = &v->vdev;
+
+       return vhost_chr_write_iter(dev, from);
+}
+
+static int vhost_vdpa_alloc_domain(struct vhost_vdpa *v)
+{
+       struct vdpa_device *vdpa = v->vdpa;
+       const struct vdpa_config_ops *ops = vdpa->config;
+       struct device *dma_dev = vdpa_get_dma_dev(vdpa);
+       struct bus_type *bus;
+       int ret;
+
+       /* Device want to do DMA by itself */
+       if (ops->set_map || ops->dma_map)
+               return 0;
+
+       bus = dma_dev->bus;
+       if (!bus)
+               return -EFAULT;
+
+       if (!iommu_capable(bus, IOMMU_CAP_CACHE_COHERENCY))
+               return -ENOTSUPP;
+
+       v->domain = iommu_domain_alloc(bus);
+       if (!v->domain)
+               return -EIO;
+
+       ret = iommu_attach_device(v->domain, dma_dev);
+       if (ret)
+               goto err_attach;
+
+       return 0;
+
+err_attach:
+       iommu_domain_free(v->domain);
+       return ret;
+}
+
+static void vhost_vdpa_free_domain(struct vhost_vdpa *v)
+{
+       struct vdpa_device *vdpa = v->vdpa;
+       struct device *dma_dev = vdpa_get_dma_dev(vdpa);
+
+       if (v->domain) {
+               iommu_detach_device(v->domain, dma_dev);
+               iommu_domain_free(v->domain);
+       }
+
+       v->domain = NULL;
+}
+
+static int vhost_vdpa_open(struct inode *inode, struct file *filep)
+{
+       struct vhost_vdpa *v;
+       struct vhost_dev *dev;
+       struct vhost_virtqueue **vqs;
+       int nvqs, i, r, opened;
+
+       v = container_of(inode->i_cdev, struct vhost_vdpa, cdev);
+       if (!v)
+               return -ENODEV;
+
+       opened = atomic_cmpxchg(&v->opened, 0, 1);
+       if (opened)
+               return -EBUSY;
+
+       nvqs = v->nvqs;
+       vhost_vdpa_reset(v);
+
+       vqs = kmalloc_array(nvqs, sizeof(*vqs), GFP_KERNEL);
+       if (!vqs) {
+               r = -ENOMEM;
+               goto err;
+       }
+
+       dev = &v->vdev;
+       for (i = 0; i < nvqs; i++) {
+               vqs[i] = &v->vqs[i];
+               vqs[i]->handle_kick = handle_vq_kick;
+       }
+       vhost_dev_init(dev, vqs, nvqs, 0, 0, 0,
+                      vhost_vdpa_process_iotlb_msg);
+
+       dev->iotlb = vhost_iotlb_alloc(0, 0);
+       if (!dev->iotlb) {
+               r = -ENOMEM;
+               goto err_init_iotlb;
+       }
+
+       r = vhost_vdpa_alloc_domain(v);
+       if (r)
+               goto err_init_iotlb;
+
+       filep->private_data = v;
+
+       return 0;
+
+err_init_iotlb:
+       vhost_dev_cleanup(&v->vdev);
+err:
+       atomic_dec(&v->opened);
+       return r;
+}
+
+static int vhost_vdpa_release(struct inode *inode, struct file *filep)
+{
+       struct vhost_vdpa *v = filep->private_data;
+       struct vhost_dev *d = &v->vdev;
+
+       mutex_lock(&d->mutex);
+       filep->private_data = NULL;
+       vhost_vdpa_reset(v);
+       vhost_dev_stop(&v->vdev);
+       vhost_vdpa_iotlb_free(v);
+       vhost_vdpa_free_domain(v);
+       vhost_dev_cleanup(&v->vdev);
+       kfree(v->vdev.vqs);
+       mutex_unlock(&d->mutex);
+
+       atomic_dec(&v->opened);
+       complete(&v->completion);
+
+       return 0;
+}
+
+static const struct file_operations vhost_vdpa_fops = {
+       .owner          = THIS_MODULE,
+       .open           = vhost_vdpa_open,
+       .release        = vhost_vdpa_release,
+       .write_iter     = vhost_vdpa_chr_write_iter,
+       .unlocked_ioctl = vhost_vdpa_unlocked_ioctl,
+       .compat_ioctl   = compat_ptr_ioctl,
+};
+
+static void vhost_vdpa_release_dev(struct device *device)
+{
+       struct vhost_vdpa *v =
+              container_of(device, struct vhost_vdpa, dev);
+
+       ida_simple_remove(&vhost_vdpa_ida, v->minor);
+       kfree(v->vqs);
+       kfree(v);
+}
+
+static int vhost_vdpa_probe(struct vdpa_device *vdpa)
+{
+       const struct vdpa_config_ops *ops = vdpa->config;
+       struct vhost_vdpa *v;
+       int minor, nvqs = VHOST_VDPA_VQ_MAX;
+       int r;
+
+       /* Currently, we only accept the network devices. */
+       if (ops->get_device_id(vdpa) != VIRTIO_ID_NET)
+               return -ENOTSUPP;
+
+       v = kzalloc(sizeof(*v), GFP_KERNEL | __GFP_RETRY_MAYFAIL);
+       if (!v)
+               return -ENOMEM;
+
+       minor = ida_simple_get(&vhost_vdpa_ida, 0,
+                              VHOST_VDPA_DEV_MAX, GFP_KERNEL);
+       if (minor < 0) {
+               kfree(v);
+               return minor;
+       }
+
+       atomic_set(&v->opened, 0);
+       v->minor = minor;
+       v->vdpa = vdpa;
+       v->nvqs = nvqs;
+       v->virtio_id = ops->get_device_id(vdpa);
+
+       device_initialize(&v->dev);
+       v->dev.release = vhost_vdpa_release_dev;
+       v->dev.parent = &vdpa->dev;
+       v->dev.devt = MKDEV(MAJOR(vhost_vdpa_major), minor);
+       v->vqs = kmalloc_array(nvqs, sizeof(struct vhost_virtqueue),
+                              GFP_KERNEL);
+       if (!v->vqs) {
+               r = -ENOMEM;
+               goto err;
+       }
+
+       r = dev_set_name(&v->dev, "vhost-vdpa-%u", minor);
+       if (r)
+               goto err;
+
+       cdev_init(&v->cdev, &vhost_vdpa_fops);
+       v->cdev.owner = THIS_MODULE;
+
+       r = cdev_device_add(&v->cdev, &v->dev);
+       if (r)
+               goto err;
+
+       init_completion(&v->completion);
+       vdpa_set_drvdata(vdpa, v);
+
+       return 0;
+
+err:
+       put_device(&v->dev);
+       return r;
+}
+
+static void vhost_vdpa_remove(struct vdpa_device *vdpa)
+{
+       struct vhost_vdpa *v = vdpa_get_drvdata(vdpa);
+       int opened;
+
+       cdev_device_del(&v->cdev, &v->dev);
+
+       do {
+               opened = atomic_cmpxchg(&v->opened, 0, 1);
+               if (!opened)
+                       break;
+               wait_for_completion(&v->completion);
+       } while (1);
+
+       put_device(&v->dev);
+}
+
+static struct vdpa_driver vhost_vdpa_driver = {
+       .driver = {
+               .name   = "vhost_vdpa",
+       },
+       .probe  = vhost_vdpa_probe,
+       .remove = vhost_vdpa_remove,
+};
+
+static int __init vhost_vdpa_init(void)
+{
+       int r;
+
+       r = alloc_chrdev_region(&vhost_vdpa_major, 0, VHOST_VDPA_DEV_MAX,
+                               "vhost-vdpa");
+       if (r)
+               goto err_alloc_chrdev;
+
+       r = vdpa_register_driver(&vhost_vdpa_driver);
+       if (r)
+               goto err_vdpa_register_driver;
+
+       return 0;
+
+err_vdpa_register_driver:
+       unregister_chrdev_region(vhost_vdpa_major, VHOST_VDPA_DEV_MAX);
+err_alloc_chrdev:
+       return r;
+}
+module_init(vhost_vdpa_init);
+
+static void __exit vhost_vdpa_exit(void)
+{
+       vdpa_unregister_driver(&vhost_vdpa_driver);
+       unregister_chrdev_region(vhost_vdpa_major, VHOST_VDPA_DEV_MAX);
+}
+module_exit(vhost_vdpa_exit);
+
+MODULE_VERSION("0.0.1");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("vDPA-based vhost backend for virtio");
index f44340b..d450e16 100644 (file)
@@ -50,10 +50,6 @@ enum {
 #define vhost_used_event(vq) ((__virtio16 __user *)&vq->avail->ring[vq->num])
 #define vhost_avail_event(vq) ((__virtio16 __user *)&vq->used->ring[vq->num])
 
-INTERVAL_TREE_DEFINE(struct vhost_umem_node,
-                    rb, __u64, __subtree_last,
-                    START, LAST, static inline, vhost_umem_interval_tree);
-
 #ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY
 static void vhost_disable_cross_endian(struct vhost_virtqueue *vq)
 {
@@ -457,7 +453,9 @@ static size_t vhost_get_desc_size(struct vhost_virtqueue *vq,
 
 void vhost_dev_init(struct vhost_dev *dev,
                    struct vhost_virtqueue **vqs, int nvqs,
-                   int iov_limit, int weight, int byte_weight)
+                   int iov_limit, int weight, int byte_weight,
+                   int (*msg_handler)(struct vhost_dev *dev,
+                                      struct vhost_iotlb_msg *msg))
 {
        struct vhost_virtqueue *vq;
        int i;
@@ -473,6 +471,7 @@ void vhost_dev_init(struct vhost_dev *dev,
        dev->iov_limit = iov_limit;
        dev->weight = weight;
        dev->byte_weight = byte_weight;
+       dev->msg_handler = msg_handler;
        init_llist_head(&dev->work_list);
        init_waitqueue_head(&dev->wait);
        INIT_LIST_HEAD(&dev->read_list);
@@ -581,21 +580,25 @@ err_mm:
 }
 EXPORT_SYMBOL_GPL(vhost_dev_set_owner);
 
-struct vhost_umem *vhost_dev_reset_owner_prepare(void)
+static struct vhost_iotlb *iotlb_alloc(void)
+{
+       return vhost_iotlb_alloc(max_iotlb_entries,
+                                VHOST_IOTLB_FLAG_RETIRE);
+}
+
+struct vhost_iotlb *vhost_dev_reset_owner_prepare(void)
 {
-       return kvzalloc(sizeof(struct vhost_umem), GFP_KERNEL);
+       return iotlb_alloc();
 }
 EXPORT_SYMBOL_GPL(vhost_dev_reset_owner_prepare);
 
 /* Caller should have device mutex */
-void vhost_dev_reset_owner(struct vhost_dev *dev, struct vhost_umem *umem)
+void vhost_dev_reset_owner(struct vhost_dev *dev, struct vhost_iotlb *umem)
 {
        int i;
 
        vhost_dev_cleanup(dev);
 
-       /* Restore memory to default empty mapping. */
-       INIT_LIST_HEAD(&umem->umem_list);
        dev->umem = umem;
        /* We don't need VQ locks below since vhost_dev_cleanup makes sure
         * VQs aren't running.
@@ -618,28 +621,6 @@ void vhost_dev_stop(struct vhost_dev *dev)
 }
 EXPORT_SYMBOL_GPL(vhost_dev_stop);
 
-static void vhost_umem_free(struct vhost_umem *umem,
-                           struct vhost_umem_node *node)
-{
-       vhost_umem_interval_tree_remove(node, &umem->umem_tree);
-       list_del(&node->link);
-       kfree(node);
-       umem->numem--;
-}
-
-static void vhost_umem_clean(struct vhost_umem *umem)
-{
-       struct vhost_umem_node *node, *tmp;
-
-       if (!umem)
-               return;
-
-       list_for_each_entry_safe(node, tmp, &umem->umem_list, link)
-               vhost_umem_free(umem, node);
-
-       kvfree(umem);
-}
-
 static void vhost_clear_msg(struct vhost_dev *dev)
 {
        struct vhost_msg_node *node, *n;
@@ -677,9 +658,9 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
                eventfd_ctx_put(dev->log_ctx);
        dev->log_ctx = NULL;
        /* No one will access memory at this point */
-       vhost_umem_clean(dev->umem);
+       vhost_iotlb_free(dev->umem);
        dev->umem = NULL;
-       vhost_umem_clean(dev->iotlb);
+       vhost_iotlb_free(dev->iotlb);
        dev->iotlb = NULL;
        vhost_clear_msg(dev);
        wake_up_interruptible_poll(&dev->wait, EPOLLIN | EPOLLRDNORM);
@@ -715,27 +696,26 @@ static bool vhost_overflow(u64 uaddr, u64 size)
 }
 
 /* Caller should have vq mutex and device mutex. */
-static bool vq_memory_access_ok(void __user *log_base, struct vhost_umem *umem,
+static bool vq_memory_access_ok(void __user *log_base, struct vhost_iotlb *umem,
                                int log_all)
 {
-       struct vhost_umem_node *node;
+       struct vhost_iotlb_map *map;
 
        if (!umem)
                return false;
 
-       list_for_each_entry(node, &umem->umem_list, link) {
-               unsigned long a = node->userspace_addr;
+       list_for_each_entry(map, &umem->list, link) {
+               unsigned long a = map->addr;
 
-               if (vhost_overflow(node->userspace_addr, node->size))
+               if (vhost_overflow(map->addr, map->size))
                        return false;
 
 
-               if (!access_ok((void __user *)a,
-                                   node->size))
+               if (!access_ok((void __user *)a, map->size))
                        return false;
                else if (log_all && !log_access_ok(log_base,
-                                                  node->start,
-                                                  node->size))
+                                                  map->start,
+                                                  map->size))
                        return false;
        }
        return true;
@@ -745,17 +725,17 @@ static inline void __user *vhost_vq_meta_fetch(struct vhost_virtqueue *vq,
                                               u64 addr, unsigned int size,
                                               int type)
 {
-       const struct vhost_umem_node *node = vq->meta_iotlb[type];
+       const struct vhost_iotlb_map *map = vq->meta_iotlb[type];
 
-       if (!node)
+       if (!map)
                return NULL;
 
-       return (void *)(uintptr_t)(node->userspace_addr + addr - node->start);
+       return (void *)(uintptr_t)(map->addr + addr - map->start);
 }
 
 /* Can we switch to this memory table? */
 /* Caller should have device mutex but not vq mutex */
-static bool memory_access_ok(struct vhost_dev *d, struct vhost_umem *umem,
+static bool memory_access_ok(struct vhost_dev *d, struct vhost_iotlb *umem,
                             int log_all)
 {
        int i;
@@ -1020,47 +1000,6 @@ static inline int vhost_get_desc(struct vhost_virtqueue *vq,
        return vhost_copy_from_user(vq, desc, vq->desc + idx, sizeof(*desc));
 }
 
-static int vhost_new_umem_range(struct vhost_umem *umem,
-                               u64 start, u64 size, u64 end,
-                               u64 userspace_addr, int perm)
-{
-       struct vhost_umem_node *tmp, *node;
-
-       if (!size)
-               return -EFAULT;
-
-       node = kmalloc(sizeof(*node), GFP_ATOMIC);
-       if (!node)
-               return -ENOMEM;
-
-       if (umem->numem == max_iotlb_entries) {
-               tmp = list_first_entry(&umem->umem_list, typeof(*tmp), link);
-               vhost_umem_free(umem, tmp);
-       }
-
-       node->start = start;
-       node->size = size;
-       node->last = end;
-       node->userspace_addr = userspace_addr;
-       node->perm = perm;
-       INIT_LIST_HEAD(&node->link);
-       list_add_tail(&node->link, &umem->umem_list);
-       vhost_umem_interval_tree_insert(node, &umem->umem_tree);
-       umem->numem++;
-
-       return 0;
-}
-
-static void vhost_del_umem_range(struct vhost_umem *umem,
-                                u64 start, u64 end)
-{
-       struct vhost_umem_node *node;
-
-       while ((node = vhost_umem_interval_tree_iter_first(&umem->umem_tree,
-                                                          start, end)))
-               vhost_umem_free(umem, node);
-}
-
 static void vhost_iotlb_notify_vq(struct vhost_dev *d,
                                  struct vhost_iotlb_msg *msg)
 {
@@ -1117,9 +1056,9 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev,
                        break;
                }
                vhost_vq_meta_reset(dev);
-               if (vhost_new_umem_range(dev->iotlb, msg->iova, msg->size,
-                                        msg->iova + msg->size - 1,
-                                        msg->uaddr, msg->perm)) {
+               if (vhost_iotlb_add_range(dev->iotlb, msg->iova,
+                                         msg->iova + msg->size - 1,
+                                         msg->uaddr, msg->perm)) {
                        ret = -ENOMEM;
                        break;
                }
@@ -1131,8 +1070,8 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev,
                        break;
                }
                vhost_vq_meta_reset(dev);
-               vhost_del_umem_range(dev->iotlb, msg->iova,
-                                    msg->iova + msg->size - 1);
+               vhost_iotlb_del_range(dev->iotlb, msg->iova,
+                                     msg->iova + msg->size - 1);
                break;
        default:
                ret = -EINVAL;
@@ -1178,7 +1117,12 @@ ssize_t vhost_chr_write_iter(struct vhost_dev *dev,
                ret = -EINVAL;
                goto done;
        }
-       if (vhost_process_iotlb_msg(dev, &msg)) {
+
+       if (dev->msg_handler)
+               ret = dev->msg_handler(dev, &msg);
+       else
+               ret = vhost_process_iotlb_msg(dev, &msg);
+       if (ret) {
                ret = -EFAULT;
                goto done;
        }
@@ -1311,44 +1255,42 @@ static bool vq_access_ok(struct vhost_virtqueue *vq, unsigned int num,
 }
 
 static void vhost_vq_meta_update(struct vhost_virtqueue *vq,
-                                const struct vhost_umem_node *node,
+                                const struct vhost_iotlb_map *map,
                                 int type)
 {
        int access = (type == VHOST_ADDR_USED) ?
                     VHOST_ACCESS_WO : VHOST_ACCESS_RO;
 
-       if (likely(node->perm & access))
-               vq->meta_iotlb[type] = node;
+       if (likely(map->perm & access))
+               vq->meta_iotlb[type] = map;
 }
 
 static bool iotlb_access_ok(struct vhost_virtqueue *vq,
                            int access, u64 addr, u64 len, int type)
 {
-       const struct vhost_umem_node *node;
-       struct vhost_umem *umem = vq->iotlb;
+       const struct vhost_iotlb_map *map;
+       struct vhost_iotlb *umem = vq->iotlb;
        u64 s = 0, size, orig_addr = addr, last = addr + len - 1;
 
        if (vhost_vq_meta_fetch(vq, addr, len, type))
                return true;
 
        while (len > s) {
-               node = vhost_umem_interval_tree_iter_first(&umem->umem_tree,
-                                                          addr,
-                                                          last);
-               if (node == NULL || node->start > addr) {
+               map = vhost_iotlb_itree_first(umem, addr, last);
+               if (map == NULL || map->start > addr) {
                        vhost_iotlb_miss(vq, addr, access);
                        return false;
-               } else if (!(node->perm & access)) {
+               } else if (!(map->perm & access)) {
                        /* Report the possible access violation by
                         * request another translation from userspace.
                         */
                        return false;
                }
 
-               size = node->size - addr + node->start;
+               size = map->size - addr + map->start;
 
                if (orig_addr == addr && size >= len)
-                       vhost_vq_meta_update(vq, node, type);
+                       vhost_vq_meta_update(vq, map, type);
 
                s += size;
                addr += size;
@@ -1364,12 +1306,12 @@ int vq_meta_prefetch(struct vhost_virtqueue *vq)
        if (!vq->iotlb)
                return 1;
 
-       return iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->desc,
+       return iotlb_access_ok(vq, VHOST_MAP_RO, (u64)(uintptr_t)vq->desc,
                               vhost_get_desc_size(vq, num), VHOST_ADDR_DESC) &&
-              iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->avail,
+              iotlb_access_ok(vq, VHOST_MAP_RO, (u64)(uintptr_t)vq->avail,
                               vhost_get_avail_size(vq, num),
                               VHOST_ADDR_AVAIL) &&
-              iotlb_access_ok(vq, VHOST_ACCESS_WO, (u64)(uintptr_t)vq->used,
+              iotlb_access_ok(vq, VHOST_MAP_WO, (u64)(uintptr_t)vq->used,
                               vhost_get_used_size(vq, num), VHOST_ADDR_USED);
 }
 EXPORT_SYMBOL_GPL(vq_meta_prefetch);
@@ -1408,25 +1350,11 @@ bool vhost_vq_access_ok(struct vhost_virtqueue *vq)
 }
 EXPORT_SYMBOL_GPL(vhost_vq_access_ok);
 
-static struct vhost_umem *vhost_umem_alloc(void)
-{
-       struct vhost_umem *umem = kvzalloc(sizeof(*umem), GFP_KERNEL);
-
-       if (!umem)
-               return NULL;
-
-       umem->umem_tree = RB_ROOT_CACHED;
-       umem->numem = 0;
-       INIT_LIST_HEAD(&umem->umem_list);
-
-       return umem;
-}
-
 static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
 {
        struct vhost_memory mem, *newmem;
        struct vhost_memory_region *region;
-       struct vhost_umem *newumem, *oldumem;
+       struct vhost_iotlb *newumem, *oldumem;
        unsigned long size = offsetof(struct vhost_memory, regions);
        int i;
 
@@ -1448,7 +1376,7 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
                return -EFAULT;
        }
 
-       newumem = vhost_umem_alloc();
+       newumem = iotlb_alloc();
        if (!newumem) {
                kvfree(newmem);
                return -ENOMEM;
@@ -1457,13 +1385,12 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
        for (region = newmem->regions;
             region < newmem->regions + mem.nregions;
             region++) {
-               if (vhost_new_umem_range(newumem,
-                                        region->guest_phys_addr,
-                                        region->memory_size,
-                                        region->guest_phys_addr +
-                                        region->memory_size - 1,
-                                        region->userspace_addr,
-                                        VHOST_ACCESS_RW))
+               if (vhost_iotlb_add_range(newumem,
+                                         region->guest_phys_addr,
+                                         region->guest_phys_addr +
+                                         region->memory_size - 1,
+                                         region->userspace_addr,
+                                         VHOST_MAP_RW))
                        goto err;
        }
 
@@ -1481,11 +1408,11 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
        }
 
        kvfree(newmem);
-       vhost_umem_clean(oldumem);
+       vhost_iotlb_free(oldumem);
        return 0;
 
 err:
-       vhost_umem_clean(newumem);
+       vhost_iotlb_free(newumem);
        kvfree(newmem);
        return -EFAULT;
 }
@@ -1726,10 +1653,10 @@ EXPORT_SYMBOL_GPL(vhost_vring_ioctl);
 
 int vhost_init_device_iotlb(struct vhost_dev *d, bool enabled)
 {
-       struct vhost_umem *niotlb, *oiotlb;
+       struct vhost_iotlb *niotlb, *oiotlb;
        int i;
 
-       niotlb = vhost_umem_alloc();
+       niotlb = iotlb_alloc();
        if (!niotlb)
                return -ENOMEM;
 
@@ -1745,7 +1672,7 @@ int vhost_init_device_iotlb(struct vhost_dev *d, bool enabled)
                mutex_unlock(&vq->mutex);
        }
 
-       vhost_umem_clean(oiotlb);
+       vhost_iotlb_free(oiotlb);
 
        return 0;
 }
@@ -1875,8 +1802,8 @@ static int log_write(void __user *log_base,
 
 static int log_write_hva(struct vhost_virtqueue *vq, u64 hva, u64 len)
 {
-       struct vhost_umem *umem = vq->umem;
-       struct vhost_umem_node *u;
+       struct vhost_iotlb *umem = vq->umem;
+       struct vhost_iotlb_map *u;
        u64 start, end, l, min;
        int r;
        bool hit = false;
@@ -1886,16 +1813,15 @@ static int log_write_hva(struct vhost_virtqueue *vq, u64 hva, u64 len)
                /* More than one GPAs can be mapped into a single HVA. So
                 * iterate all possible umems here to be safe.
                 */
-               list_for_each_entry(u, &umem->umem_list, link) {
-                       if (u->userspace_addr > hva - 1 + len ||
-                           u->userspace_addr - 1 + u->size < hva)
+               list_for_each_entry(u, &umem->list, link) {
+                       if (u->addr > hva - 1 + len ||
+                           u->addr - 1 + u->size < hva)
                                continue;
-                       start = max(u->userspace_addr, hva);
-                       end = min(u->userspace_addr - 1 + u->size,
-                                 hva - 1 + len);
+                       start = max(u->addr, hva);
+                       end = min(u->addr - 1 + u->size, hva - 1 + len);
                        l = end - start + 1;
                        r = log_write(vq->log_base,
-                                     u->start + start - u->userspace_addr,
+                                     u->start + start - u->addr,
                                      l);
                        if (r < 0)
                                return r;
@@ -2046,9 +1972,9 @@ EXPORT_SYMBOL_GPL(vhost_vq_init_access);
 static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len,
                          struct iovec iov[], int iov_size, int access)
 {
-       const struct vhost_umem_node *node;
+       const struct vhost_iotlb_map *map;
        struct vhost_dev *dev = vq->dev;
-       struct vhost_umem *umem = dev->iotlb ? dev->iotlb : dev->umem;
+       struct vhost_iotlb *umem = dev->iotlb ? dev->iotlb : dev->umem;
        struct iovec *_iov;
        u64 s = 0;
        int ret = 0;
@@ -2060,25 +1986,24 @@ static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len,
                        break;
                }
 
-               node = vhost_umem_interval_tree_iter_first(&umem->umem_tree,
-                                                       addr, addr + len - 1);
-               if (node == NULL || node->start > addr) {
+               map = vhost_iotlb_itree_first(umem, addr, addr + len - 1);
+               if (map == NULL || map->start > addr) {
                        if (umem != dev->iotlb) {
                                ret = -EFAULT;
                                break;
                        }
                        ret = -EAGAIN;
                        break;
-               } else if (!(node->perm & access)) {
+               } else if (!(map->perm & access)) {
                        ret = -EPERM;
                        break;
                }
 
                _iov = iov + ret;
-               size = node->size - addr + node->start;
+               size = map->size - addr + map->start;
                _iov->iov_len = min((u64)len - s, size);
                _iov->iov_base = (void __user *)(unsigned long)
-                       (node->userspace_addr + addr - node->start);
+                                (map->addr + addr - map->start);
                s += size;
                addr += size;
                ++ret;
index a123fd7..1813821 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/virtio_config.h>
 #include <linux/virtio_ring.h>
 #include <linux/atomic.h>
+#include <linux/vhost_iotlb.h>
 
 struct vhost_work;
 typedef void (*vhost_work_fn_t)(struct vhost_work *work);
@@ -52,27 +53,6 @@ struct vhost_log {
        u64 len;
 };
 
-#define START(node) ((node)->start)
-#define LAST(node) ((node)->last)
-
-struct vhost_umem_node {
-       struct rb_node rb;
-       struct list_head link;
-       __u64 start;
-       __u64 last;
-       __u64 size;
-       __u64 userspace_addr;
-       __u32 perm;
-       __u32 flags_padding;
-       __u64 __subtree_last;
-};
-
-struct vhost_umem {
-       struct rb_root_cached umem_tree;
-       struct list_head umem_list;
-       int numem;
-};
-
 enum vhost_uaddr_type {
        VHOST_ADDR_DESC = 0,
        VHOST_ADDR_AVAIL = 1,
@@ -90,7 +70,7 @@ struct vhost_virtqueue {
        struct vring_desc __user *desc;
        struct vring_avail __user *avail;
        struct vring_used __user *used;
-       const struct vhost_umem_node *meta_iotlb[VHOST_NUM_ADDRS];
+       const struct vhost_iotlb_map *meta_iotlb[VHOST_NUM_ADDRS];
        struct file *kick;
        struct eventfd_ctx *call_ctx;
        struct eventfd_ctx *error_ctx;
@@ -128,8 +108,8 @@ struct vhost_virtqueue {
        struct iovec *indirect;
        struct vring_used_elem *heads;
        /* Protected by virtqueue mutex. */
-       struct vhost_umem *umem;
-       struct vhost_umem *iotlb;
+       struct vhost_iotlb *umem;
+       struct vhost_iotlb *iotlb;
        void *private_data;
        u64 acked_features;
        u64 acked_backend_features;
@@ -164,8 +144,8 @@ struct vhost_dev {
        struct eventfd_ctx *log_ctx;
        struct llist_head work_list;
        struct task_struct *worker;
-       struct vhost_umem *umem;
-       struct vhost_umem *iotlb;
+       struct vhost_iotlb *umem;
+       struct vhost_iotlb *iotlb;
        spinlock_t iotlb_lock;
        struct list_head read_list;
        struct list_head pending_list;
@@ -174,16 +154,20 @@ struct vhost_dev {
        int weight;
        int byte_weight;
        u64 kcov_handle;
+       int (*msg_handler)(struct vhost_dev *dev,
+                          struct vhost_iotlb_msg *msg);
 };
 
 bool vhost_exceeds_weight(struct vhost_virtqueue *vq, int pkts, int total_len);
 void vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs,
-                   int nvqs, int iov_limit, int weight, int byte_weight);
+                   int nvqs, int iov_limit, int weight, int byte_weight,
+                   int (*msg_handler)(struct vhost_dev *dev,
+                                      struct vhost_iotlb_msg *msg));
 long vhost_dev_set_owner(struct vhost_dev *dev);
 bool vhost_dev_has_owner(struct vhost_dev *dev);
 long vhost_dev_check_owner(struct vhost_dev *);
-struct vhost_umem *vhost_dev_reset_owner_prepare(void);
-void vhost_dev_reset_owner(struct vhost_dev *, struct vhost_umem *);
+struct vhost_iotlb *vhost_dev_reset_owner_prepare(void);
+void vhost_dev_reset_owner(struct vhost_dev *dev, struct vhost_iotlb *iotlb);
 void vhost_dev_cleanup(struct vhost_dev *);
 void vhost_dev_stop(struct vhost_dev *);
 long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, void __user *argp);
@@ -229,6 +213,9 @@ ssize_t vhost_chr_write_iter(struct vhost_dev *dev,
                             struct iov_iter *from);
 int vhost_init_device_iotlb(struct vhost_dev *d, bool enabled);
 
+void vhost_iotlb_map_free(struct vhost_iotlb *iotlb,
+                         struct vhost_iotlb_map *map);
+
 #define vq_err(vq, fmt, ...) do {                                  \
                pr_debug(pr_fmt(fmt), ##__VA_ARGS__);       \
                if ((vq)->error_ctx)                               \
index a0a2d74..ee0491f 100644 (file)
@@ -13,6 +13,9 @@
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/bvec.h>
+#include <linux/highmem.h>
+#include <linux/vhost_iotlb.h>
 #include <uapi/linux/virtio_config.h>
 
 static __printf(1,2) __cold void vringh_bad(const char *fmt, ...)
@@ -71,9 +74,11 @@ static inline int __vringh_get_head(const struct vringh *vrh,
 }
 
 /* Copy some bytes to/from the iovec.  Returns num copied. */
-static inline ssize_t vringh_iov_xfer(struct vringh_kiov *iov,
+static inline ssize_t vringh_iov_xfer(struct vringh *vrh,
+                                     struct vringh_kiov *iov,
                                      void *ptr, size_t len,
-                                     int (*xfer)(void *addr, void *ptr,
+                                     int (*xfer)(const struct vringh *vrh,
+                                                 void *addr, void *ptr,
                                                  size_t len))
 {
        int err, done = 0;
@@ -82,7 +87,7 @@ static inline ssize_t vringh_iov_xfer(struct vringh_kiov *iov,
                size_t partlen;
 
                partlen = min(iov->iov[iov->i].iov_len, len);
-               err = xfer(iov->iov[iov->i].iov_base, ptr, partlen);
+               err = xfer(vrh, iov->iov[iov->i].iov_base, ptr, partlen);
                if (err)
                        return err;
                done += partlen;
@@ -96,6 +101,7 @@ static inline ssize_t vringh_iov_xfer(struct vringh_kiov *iov,
                        /* Fix up old iov element then increment. */
                        iov->iov[iov->i].iov_len = iov->consumed;
                        iov->iov[iov->i].iov_base -= iov->consumed;
+
                        
                        iov->consumed = 0;
                        iov->i++;
@@ -227,7 +233,8 @@ static int slow_copy(struct vringh *vrh, void *dst, const void *src,
                                      u64 addr,
                                      struct vringh_range *r),
                     struct vringh_range *range,
-                    int (*copy)(void *dst, const void *src, size_t len))
+                    int (*copy)(const struct vringh *vrh,
+                                void *dst, const void *src, size_t len))
 {
        size_t part, len = sizeof(struct vring_desc);
 
@@ -241,7 +248,7 @@ static int slow_copy(struct vringh *vrh, void *dst, const void *src,
                if (!rcheck(vrh, addr, &part, range, getrange))
                        return -EINVAL;
 
-               err = copy(dst, src, part);
+               err = copy(vrh, dst, src, part);
                if (err)
                        return err;
 
@@ -262,7 +269,8 @@ __vringh_iov(struct vringh *vrh, u16 i,
                                             struct vringh_range *)),
             bool (*getrange)(struct vringh *, u64, struct vringh_range *),
             gfp_t gfp,
-            int (*copy)(void *dst, const void *src, size_t len))
+            int (*copy)(const struct vringh *vrh,
+                        void *dst, const void *src, size_t len))
 {
        int err, count = 0, up_next, desc_max;
        struct vring_desc desc, *descs;
@@ -291,7 +299,7 @@ __vringh_iov(struct vringh *vrh, u16 i,
                        err = slow_copy(vrh, &desc, &descs[i], rcheck, getrange,
                                        &slowrange, copy);
                else
-                       err = copy(&desc, &descs[i], sizeof(desc));
+                       err = copy(vrh, &desc, &descs[i], sizeof(desc));
                if (unlikely(err))
                        goto fail;
 
@@ -404,7 +412,8 @@ static inline int __vringh_complete(struct vringh *vrh,
                                    unsigned int num_used,
                                    int (*putu16)(const struct vringh *vrh,
                                                  __virtio16 *p, u16 val),
-                                   int (*putused)(struct vring_used_elem *dst,
+                                   int (*putused)(const struct vringh *vrh,
+                                                  struct vring_used_elem *dst,
                                                   const struct vring_used_elem
                                                   *src, unsigned num))
 {
@@ -420,12 +429,12 @@ static inline int __vringh_complete(struct vringh *vrh,
        /* Compiler knows num_used == 1 sometimes, hence extra check */
        if (num_used > 1 && unlikely(off + num_used >= vrh->vring.num)) {
                u16 part = vrh->vring.num - off;
-               err = putused(&used_ring->ring[off], used, part);
+               err = putused(vrh, &used_ring->ring[off], used, part);
                if (!err)
-                       err = putused(&used_ring->ring[0], used + part,
+                       err = putused(vrh, &used_ring->ring[0], used + part,
                                      num_used - part);
        } else
-               err = putused(&used_ring->ring[off], used, num_used);
+               err = putused(vrh, &used_ring->ring[off], used, num_used);
 
        if (err) {
                vringh_bad("Failed to write %u used entries %u at %p",
@@ -564,13 +573,15 @@ static inline int putu16_user(const struct vringh *vrh, __virtio16 *p, u16 val)
        return put_user(v, (__force __virtio16 __user *)p);
 }
 
-static inline int copydesc_user(void *dst, const void *src, size_t len)
+static inline int copydesc_user(const struct vringh *vrh,
+                               void *dst, const void *src, size_t len)
 {
        return copy_from_user(dst, (__force void __user *)src, len) ?
                -EFAULT : 0;
 }
 
-static inline int putused_user(struct vring_used_elem *dst,
+static inline int putused_user(const struct vringh *vrh,
+                              struct vring_used_elem *dst,
                               const struct vring_used_elem *src,
                               unsigned int num)
 {
@@ -578,13 +589,15 @@ static inline int putused_user(struct vring_used_elem *dst,
                            sizeof(*dst) * num) ? -EFAULT : 0;
 }
 
-static inline int xfer_from_user(void *src, void *dst, size_t len)
+static inline int xfer_from_user(const struct vringh *vrh, void *src,
+                                void *dst, size_t len)
 {
        return copy_from_user(dst, (__force void __user *)src, len) ?
                -EFAULT : 0;
 }
 
-static inline int xfer_to_user(void *dst, void *src, size_t len)
+static inline int xfer_to_user(const struct vringh *vrh,
+                              void *dst, void *src, size_t len)
 {
        return copy_to_user((__force void __user *)dst, src, len) ?
                -EFAULT : 0;
@@ -706,7 +719,7 @@ EXPORT_SYMBOL(vringh_getdesc_user);
  */
 ssize_t vringh_iov_pull_user(struct vringh_iov *riov, void *dst, size_t len)
 {
-       return vringh_iov_xfer((struct vringh_kiov *)riov,
+       return vringh_iov_xfer(NULL, (struct vringh_kiov *)riov,
                               dst, len, xfer_from_user);
 }
 EXPORT_SYMBOL(vringh_iov_pull_user);
@@ -722,7 +735,7 @@ EXPORT_SYMBOL(vringh_iov_pull_user);
 ssize_t vringh_iov_push_user(struct vringh_iov *wiov,
                             const void *src, size_t len)
 {
-       return vringh_iov_xfer((struct vringh_kiov *)wiov,
+       return vringh_iov_xfer(NULL, (struct vringh_kiov *)wiov,
                               (void *)src, len, xfer_to_user);
 }
 EXPORT_SYMBOL(vringh_iov_push_user);
@@ -832,13 +845,15 @@ static inline int putu16_kern(const struct vringh *vrh, __virtio16 *p, u16 val)
        return 0;
 }
 
-static inline int copydesc_kern(void *dst, const void *src, size_t len)
+static inline int copydesc_kern(const struct vringh *vrh,
+                               void *dst, const void *src, size_t len)
 {
        memcpy(dst, src, len);
        return 0;
 }
 
-static inline int putused_kern(struct vring_used_elem *dst,
+static inline int putused_kern(const struct vringh *vrh,
+                              struct vring_used_elem *dst,
                               const struct vring_used_elem *src,
                               unsigned int num)
 {
@@ -846,13 +861,15 @@ static inline int putused_kern(struct vring_used_elem *dst,
        return 0;
 }
 
-static inline int xfer_kern(void *src, void *dst, size_t len)
+static inline int xfer_kern(const struct vringh *vrh, void *src,
+                           void *dst, size_t len)
 {
        memcpy(dst, src, len);
        return 0;
 }
 
-static inline int kern_xfer(void *dst, void *src, size_t len)
+static inline int kern_xfer(const struct vringh *vrh, void *dst,
+                           void *src, size_t len)
 {
        memcpy(dst, src, len);
        return 0;
@@ -949,7 +966,7 @@ EXPORT_SYMBOL(vringh_getdesc_kern);
  */
 ssize_t vringh_iov_pull_kern(struct vringh_kiov *riov, void *dst, size_t len)
 {
-       return vringh_iov_xfer(riov, dst, len, xfer_kern);
+       return vringh_iov_xfer(NULL, riov, dst, len, xfer_kern);
 }
 EXPORT_SYMBOL(vringh_iov_pull_kern);
 
@@ -964,7 +981,7 @@ EXPORT_SYMBOL(vringh_iov_pull_kern);
 ssize_t vringh_iov_push_kern(struct vringh_kiov *wiov,
                             const void *src, size_t len)
 {
-       return vringh_iov_xfer(wiov, (void *)src, len, kern_xfer);
+       return vringh_iov_xfer(NULL, wiov, (void *)src, len, kern_xfer);
 }
 EXPORT_SYMBOL(vringh_iov_push_kern);
 
@@ -1042,4 +1059,362 @@ int vringh_need_notify_kern(struct vringh *vrh)
 }
 EXPORT_SYMBOL(vringh_need_notify_kern);
 
+static int iotlb_translate(const struct vringh *vrh,
+                          u64 addr, u64 len, struct bio_vec iov[],
+                          int iov_size, u32 perm)
+{
+       struct vhost_iotlb_map *map;
+       struct vhost_iotlb *iotlb = vrh->iotlb;
+       int ret = 0;
+       u64 s = 0;
+
+       while (len > s) {
+               u64 size, pa, pfn;
+
+               if (unlikely(ret >= iov_size)) {
+                       ret = -ENOBUFS;
+                       break;
+               }
+
+               map = vhost_iotlb_itree_first(iotlb, addr,
+                                             addr + len - 1);
+               if (!map || map->start > addr) {
+                       ret = -EINVAL;
+                       break;
+               } else if (!(map->perm & perm)) {
+                       ret = -EPERM;
+                       break;
+               }
+
+               size = map->size - addr + map->start;
+               pa = map->addr + addr - map->start;
+               pfn = pa >> PAGE_SHIFT;
+               iov[ret].bv_page = pfn_to_page(pfn);
+               iov[ret].bv_len = min(len - s, size);
+               iov[ret].bv_offset = pa & (PAGE_SIZE - 1);
+               s += size;
+               addr += size;
+               ++ret;
+       }
+
+       return ret;
+}
+
+static inline int copy_from_iotlb(const struct vringh *vrh, void *dst,
+                                 void *src, size_t len)
+{
+       struct iov_iter iter;
+       struct bio_vec iov[16];
+       int ret;
+
+       ret = iotlb_translate(vrh, (u64)(uintptr_t)src,
+                             len, iov, 16, VHOST_MAP_RO);
+       if (ret < 0)
+               return ret;
+
+       iov_iter_bvec(&iter, READ, iov, ret, len);
+
+       ret = copy_from_iter(dst, len, &iter);
+
+       return ret;
+}
+
+static inline int copy_to_iotlb(const struct vringh *vrh, void *dst,
+                               void *src, size_t len)
+{
+       struct iov_iter iter;
+       struct bio_vec iov[16];
+       int ret;
+
+       ret = iotlb_translate(vrh, (u64)(uintptr_t)dst,
+                             len, iov, 16, VHOST_MAP_WO);
+       if (ret < 0)
+               return ret;
+
+       iov_iter_bvec(&iter, WRITE, iov, ret, len);
+
+       return copy_to_iter(src, len, &iter);
+}
+
+static inline int getu16_iotlb(const struct vringh *vrh,
+                              u16 *val, const __virtio16 *p)
+{
+       struct bio_vec iov;
+       void *kaddr, *from;
+       int ret;
+
+       /* Atomic read is needed for getu16 */
+       ret = iotlb_translate(vrh, (u64)(uintptr_t)p, sizeof(*p),
+                             &iov, 1, VHOST_MAP_RO);
+       if (ret < 0)
+               return ret;
+
+       kaddr = kmap_atomic(iov.bv_page);
+       from = kaddr + iov.bv_offset;
+       *val = vringh16_to_cpu(vrh, READ_ONCE(*(__virtio16 *)from));
+       kunmap_atomic(kaddr);
+
+       return 0;
+}
+
+static inline int putu16_iotlb(const struct vringh *vrh,
+                              __virtio16 *p, u16 val)
+{
+       struct bio_vec iov;
+       void *kaddr, *to;
+       int ret;
+
+       /* Atomic write is needed for putu16 */
+       ret = iotlb_translate(vrh, (u64)(uintptr_t)p, sizeof(*p),
+                             &iov, 1, VHOST_MAP_WO);
+       if (ret < 0)
+               return ret;
+
+       kaddr = kmap_atomic(iov.bv_page);
+       to = kaddr + iov.bv_offset;
+       WRITE_ONCE(*(__virtio16 *)to, cpu_to_vringh16(vrh, val));
+       kunmap_atomic(kaddr);
+
+       return 0;
+}
+
+static inline int copydesc_iotlb(const struct vringh *vrh,
+                                void *dst, const void *src, size_t len)
+{
+       int ret;
+
+       ret = copy_from_iotlb(vrh, dst, (void *)src, len);
+       if (ret != len)
+               return -EFAULT;
+
+       return 0;
+}
+
+static inline int xfer_from_iotlb(const struct vringh *vrh, void *src,
+                                 void *dst, size_t len)
+{
+       int ret;
+
+       ret = copy_from_iotlb(vrh, dst, src, len);
+       if (ret != len)
+               return -EFAULT;
+
+       return 0;
+}
+
+static inline int xfer_to_iotlb(const struct vringh *vrh,
+                              void *dst, void *src, size_t len)
+{
+       int ret;
+
+       ret = copy_to_iotlb(vrh, dst, src, len);
+       if (ret != len)
+               return -EFAULT;
+
+       return 0;
+}
+
+static inline int putused_iotlb(const struct vringh *vrh,
+                               struct vring_used_elem *dst,
+                               const struct vring_used_elem *src,
+                               unsigned int num)
+{
+       int size = num * sizeof(*dst);
+       int ret;
+
+       ret = copy_to_iotlb(vrh, dst, (void *)src, num * sizeof(*dst));
+       if (ret != size)
+               return -EFAULT;
+
+       return 0;
+}
+
+/**
+ * vringh_init_iotlb - initialize a vringh for a ring with IOTLB.
+ * @vrh: the vringh to initialize.
+ * @features: the feature bits for this ring.
+ * @num: the number of elements.
+ * @weak_barriers: true if we only need memory barriers, not I/O.
+ * @desc: the userpace descriptor pointer.
+ * @avail: the userpace avail pointer.
+ * @used: the userpace used pointer.
+ *
+ * Returns an error if num is invalid.
+ */
+int vringh_init_iotlb(struct vringh *vrh, u64 features,
+                     unsigned int num, bool weak_barriers,
+                     struct vring_desc *desc,
+                     struct vring_avail *avail,
+                     struct vring_used *used)
+{
+       return vringh_init_kern(vrh, features, num, weak_barriers,
+                               desc, avail, used);
+}
+EXPORT_SYMBOL(vringh_init_iotlb);
+
+/**
+ * vringh_set_iotlb - initialize a vringh for a ring with IOTLB.
+ * @vrh: the vring
+ * @iotlb: iotlb associated with this vring
+ */
+void vringh_set_iotlb(struct vringh *vrh, struct vhost_iotlb *iotlb)
+{
+       vrh->iotlb = iotlb;
+}
+EXPORT_SYMBOL(vringh_set_iotlb);
+
+/**
+ * vringh_getdesc_iotlb - get next available descriptor from ring with
+ * IOTLB.
+ * @vrh: the kernelspace vring.
+ * @riov: where to put the readable descriptors (or NULL)
+ * @wiov: where to put the writable descriptors (or NULL)
+ * @head: head index we received, for passing to vringh_complete_iotlb().
+ * @gfp: flags for allocating larger riov/wiov.
+ *
+ * Returns 0 if there was no descriptor, 1 if there was, or -errno.
+ *
+ * Note that on error return, you can tell the difference between an
+ * invalid ring and a single invalid descriptor: in the former case,
+ * *head will be vrh->vring.num.  You may be able to ignore an invalid
+ * descriptor, but there's not much you can do with an invalid ring.
+ *
+ * Note that you may need to clean up riov and wiov, even on error!
+ */
+int vringh_getdesc_iotlb(struct vringh *vrh,
+                        struct vringh_kiov *riov,
+                        struct vringh_kiov *wiov,
+                        u16 *head,
+                        gfp_t gfp)
+{
+       int err;
+
+       err = __vringh_get_head(vrh, getu16_iotlb, &vrh->last_avail_idx);
+       if (err < 0)
+               return err;
+
+       /* Empty... */
+       if (err == vrh->vring.num)
+               return 0;
+
+       *head = err;
+       err = __vringh_iov(vrh, *head, riov, wiov, no_range_check, NULL,
+                          gfp, copydesc_iotlb);
+       if (err)
+               return err;
+
+       return 1;
+}
+EXPORT_SYMBOL(vringh_getdesc_iotlb);
+
+/**
+ * vringh_iov_pull_iotlb - copy bytes from vring_iov.
+ * @vrh: the vring.
+ * @riov: the riov as passed to vringh_getdesc_iotlb() (updated as we consume)
+ * @dst: the place to copy.
+ * @len: the maximum length to copy.
+ *
+ * Returns the bytes copied <= len or a negative errno.
+ */
+ssize_t vringh_iov_pull_iotlb(struct vringh *vrh,
+                             struct vringh_kiov *riov,
+                             void *dst, size_t len)
+{
+       return vringh_iov_xfer(vrh, riov, dst, len, xfer_from_iotlb);
+}
+EXPORT_SYMBOL(vringh_iov_pull_iotlb);
+
+/**
+ * vringh_iov_push_iotlb - copy bytes into vring_iov.
+ * @vrh: the vring.
+ * @wiov: the wiov as passed to vringh_getdesc_iotlb() (updated as we consume)
+ * @dst: the place to copy.
+ * @len: the maximum length to copy.
+ *
+ * Returns the bytes copied <= len or a negative errno.
+ */
+ssize_t vringh_iov_push_iotlb(struct vringh *vrh,
+                             struct vringh_kiov *wiov,
+                             const void *src, size_t len)
+{
+       return vringh_iov_xfer(vrh, wiov, (void *)src, len, xfer_to_iotlb);
+}
+EXPORT_SYMBOL(vringh_iov_push_iotlb);
+
+/**
+ * vringh_abandon_iotlb - we've decided not to handle the descriptor(s).
+ * @vrh: the vring.
+ * @num: the number of descriptors to put back (ie. num
+ *      vringh_get_iotlb() to undo).
+ *
+ * The next vringh_get_iotlb() will return the old descriptor(s) again.
+ */
+void vringh_abandon_iotlb(struct vringh *vrh, unsigned int num)
+{
+       /* We only update vring_avail_event(vr) when we want to be notified,
+        * so we haven't changed that yet.
+        */
+       vrh->last_avail_idx -= num;
+}
+EXPORT_SYMBOL(vringh_abandon_iotlb);
+
+/**
+ * vringh_complete_iotlb - we've finished with descriptor, publish it.
+ * @vrh: the vring.
+ * @head: the head as filled in by vringh_getdesc_iotlb.
+ * @len: the length of data we have written.
+ *
+ * You should check vringh_need_notify_iotlb() after one or more calls
+ * to this function.
+ */
+int vringh_complete_iotlb(struct vringh *vrh, u16 head, u32 len)
+{
+       struct vring_used_elem used;
+
+       used.id = cpu_to_vringh32(vrh, head);
+       used.len = cpu_to_vringh32(vrh, len);
+
+       return __vringh_complete(vrh, &used, 1, putu16_iotlb, putused_iotlb);
+}
+EXPORT_SYMBOL(vringh_complete_iotlb);
+
+/**
+ * vringh_notify_enable_iotlb - we want to know if something changes.
+ * @vrh: the vring.
+ *
+ * This always enables notifications, but returns false if there are
+ * now more buffers available in the vring.
+ */
+bool vringh_notify_enable_iotlb(struct vringh *vrh)
+{
+       return __vringh_notify_enable(vrh, getu16_iotlb, putu16_iotlb);
+}
+EXPORT_SYMBOL(vringh_notify_enable_iotlb);
+
+/**
+ * vringh_notify_disable_iotlb - don't tell us if something changes.
+ * @vrh: the vring.
+ *
+ * This is our normal running state: we disable and then only enable when
+ * we're going to sleep.
+ */
+void vringh_notify_disable_iotlb(struct vringh *vrh)
+{
+       __vringh_notify_disable(vrh, putu16_iotlb);
+}
+EXPORT_SYMBOL(vringh_notify_disable_iotlb);
+
+/**
+ * vringh_need_notify_iotlb - must we tell the other side about used buffers?
+ * @vrh: the vring we've called vringh_complete_iotlb() on.
+ *
+ * Returns -errno or 0 if we don't need to tell the other side, 1 if we do.
+ */
+int vringh_need_notify_iotlb(struct vringh *vrh)
+{
+       return __vringh_need_notify(vrh, getu16_iotlb);
+}
+EXPORT_SYMBOL(vringh_need_notify_iotlb);
+
+
 MODULE_LICENSE("GPL");
index c2d7d57..9766948 100644 (file)
@@ -621,7 +621,7 @@ static int vhost_vsock_dev_open(struct inode *inode, struct file *file)
 
        vhost_dev_init(&vsock->dev, vqs, ARRAY_SIZE(vsock->vqs),
                       UIO_MAXIOV, VHOST_VSOCK_PKT_WEIGHT,
-                      VHOST_VSOCK_WEIGHT);
+                      VHOST_VSOCK_WEIGHT, NULL);
 
        file->private_data = vsock;
        spin_lock_init(&vsock->send_pkt_list_lock);
index 68f7592..25ef0cb 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/fb.h>
 #include <linux/lcd.h>
 #include <linux/spi/spi.h>
@@ -90,9 +90,8 @@ struct corgi_lcd {
        int     mode;
        char    buf[2];
 
-       int     gpio_backlight_on;
-       int     gpio_backlight_cont;
-       int     gpio_backlight_cont_inverted;
+       struct gpio_desc *backlight_on;
+       struct gpio_desc *backlight_cont;
 
        void (*kick_battery)(void);
 };
@@ -403,13 +402,13 @@ static int corgi_bl_set_intensity(struct corgi_lcd *lcd, int intensity)
        corgi_ssp_lcdtg_send(lcd, DUTYCTRL_ADRS, intensity);
 
        /* Bit 5 via GPIO_BACKLIGHT_CONT */
-       cont = !!(intensity & 0x20) ^ lcd->gpio_backlight_cont_inverted;
+       cont = !!(intensity & 0x20);
 
-       if (gpio_is_valid(lcd->gpio_backlight_cont))
-               gpio_set_value_cansleep(lcd->gpio_backlight_cont, cont);
+       if (lcd->backlight_cont)
+               gpiod_set_value_cansleep(lcd->backlight_cont, cont);
 
-       if (gpio_is_valid(lcd->gpio_backlight_on))
-               gpio_set_value_cansleep(lcd->gpio_backlight_on, intensity);
+       if (lcd->backlight_on)
+               gpiod_set_value_cansleep(lcd->backlight_on, intensity);
 
        if (lcd->kick_battery)
                lcd->kick_battery();
@@ -482,48 +481,17 @@ static int setup_gpio_backlight(struct corgi_lcd *lcd,
                                struct corgi_lcd_platform_data *pdata)
 {
        struct spi_device *spi = lcd->spi_dev;
-       int err;
-
-       lcd->gpio_backlight_on = -1;
-       lcd->gpio_backlight_cont = -1;
-
-       if (gpio_is_valid(pdata->gpio_backlight_on)) {
-               err = devm_gpio_request(&spi->dev, pdata->gpio_backlight_on,
-                                       "BL_ON");
-               if (err) {
-                       dev_err(&spi->dev,
-                               "failed to request GPIO%d for backlight_on\n",
-                               pdata->gpio_backlight_on);
-                       return err;
-               }
-
-               lcd->gpio_backlight_on = pdata->gpio_backlight_on;
-               gpio_direction_output(lcd->gpio_backlight_on, 0);
-       }
 
-       if (gpio_is_valid(pdata->gpio_backlight_cont)) {
-               err = devm_gpio_request(&spi->dev, pdata->gpio_backlight_cont,
-                                       "BL_CONT");
-               if (err) {
-                       dev_err(&spi->dev,
-                               "failed to request GPIO%d for backlight_cont\n",
-                               pdata->gpio_backlight_cont);
-                       return err;
-               }
-
-               lcd->gpio_backlight_cont = pdata->gpio_backlight_cont;
-
-               /* spitz and akita use both GPIOs for backlight, and
-                * have inverted polarity of GPIO_BACKLIGHT_CONT
-                */
-               if (gpio_is_valid(lcd->gpio_backlight_on)) {
-                       lcd->gpio_backlight_cont_inverted = 1;
-                       gpio_direction_output(lcd->gpio_backlight_cont, 1);
-               } else {
-                       lcd->gpio_backlight_cont_inverted = 0;
-                       gpio_direction_output(lcd->gpio_backlight_cont, 0);
-               }
-       }
+       lcd->backlight_on = devm_gpiod_get_optional(&spi->dev,
+                                                   "BL_ON", GPIOD_OUT_LOW);
+       if (IS_ERR(lcd->backlight_on))
+               return PTR_ERR(lcd->backlight_on);
+
+       lcd->backlight_cont = devm_gpiod_get_optional(&spi->dev, "BL_CONT",
+                                                     GPIOD_OUT_LOW);
+       if (IS_ERR(lcd->backlight_cont))
+               return PTR_ERR(lcd->backlight_cont);
+
        return 0;
 }
 
index efb4efc..82b8d75 100644 (file)
@@ -7,7 +7,6 @@
 
 #include <linux/delay.h>
 #include <linux/gpio/consumer.h>
-#include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -258,8 +257,6 @@ static int pwm_backlight_parse_dt(struct device *dev,
                             &data->post_pwm_on_delay);
        of_property_read_u32(node, "pwm-off-delay-ms", &data->pwm_off_delay);
 
-       data->enable_gpio = -EINVAL;
-
        /*
         * Determine the number of brightness levels, if this property is not
         * set a default table of brightness levels will be used.
@@ -503,22 +500,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
        }
 
        /*
-        * Compatibility fallback for drivers still using the integer GPIO
-        * platform data. Must go away soon.
-        */
-       if (!pb->enable_gpio && gpio_is_valid(data->enable_gpio)) {
-               ret = devm_gpio_request_one(&pdev->dev, data->enable_gpio,
-                                           GPIOF_OUT_INIT_HIGH, "enable");
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "failed to request GPIO#%d: %d\n",
-                               data->enable_gpio, ret);
-                       goto err_alloc;
-               }
-
-               pb->enable_gpio = gpio_to_desc(data->enable_gpio);
-       }
-
-       /*
         * If the GPIO is not known to be already configured as output, that
         * is, if gpiod_get_direction returns either 1 or -EINVAL, change the
         * direction to output and set the GPIO as active.
index 2833578..9d28a8e 100644 (file)
@@ -1282,6 +1282,9 @@ finished:
        if (!con_is_bound(&fb_con))
                fbcon_exit();
 
+       if (vc->vc_num == logo_shown)
+               logo_shown = FBCON_LOGO_CANSHOW;
+
        return;
 }
 
index 4b2dd82..2bbf94b 100644 (file)
@@ -43,6 +43,19 @@ config VIRTIO_PCI_LEGACY
 
          If unsure, say Y.
 
+config VIRTIO_VDPA
+       tristate "vDPA driver for virtio devices"
+       select VDPA
+       select VIRTIO
+       help
+         This driver provides support for virtio based paravirtual
+         device driver over vDPA bus. For this to be useful, you need
+         an appropriate vDPA device implementation that operates on a
+         physical device to allow the datapath of virtio to be
+         offloaded to hardware.
+
+         If unsure, say M.
+
 config VIRTIO_PMEM
        tristate "Support for virtio pmem driver"
        depends on VIRTIO
index 3a2b5c5..29a1386 100644 (file)
@@ -6,3 +6,4 @@ virtio_pci-y := virtio_pci_modern.o virtio_pci_common.o
 virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) += virtio_pci_legacy.o
 obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
 obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o
+obj-$(CONFIG_VIRTIO_VDPA) += virtio_vdpa.o
diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
new file mode 100644 (file)
index 0000000..c30eb55
--- /dev/null
@@ -0,0 +1,396 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * VIRTIO based driver for vDPA device
+ *
+ * Copyright (c) 2020, Red Hat. All rights reserved.
+ *     Author: Jason Wang <jasowang@redhat.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/uuid.h>
+#include <linux/virtio.h>
+#include <linux/vdpa.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+
+#define MOD_VERSION  "0.1"
+#define MOD_AUTHOR   "Jason Wang <jasowang@redhat.com>"
+#define MOD_DESC     "vDPA bus driver for virtio devices"
+#define MOD_LICENSE  "GPL v2"
+
+struct virtio_vdpa_device {
+       struct virtio_device vdev;
+       struct vdpa_device *vdpa;
+       u64 features;
+
+       /* The lock to protect virtqueue list */
+       spinlock_t lock;
+       /* List of virtio_vdpa_vq_info */
+       struct list_head virtqueues;
+};
+
+struct virtio_vdpa_vq_info {
+       /* the actual virtqueue */
+       struct virtqueue *vq;
+
+       /* the list node for the virtqueues list */
+       struct list_head node;
+};
+
+static inline struct virtio_vdpa_device *
+to_virtio_vdpa_device(struct virtio_device *dev)
+{
+       return container_of(dev, struct virtio_vdpa_device, vdev);
+}
+
+static struct vdpa_device *vd_get_vdpa(struct virtio_device *vdev)
+{
+       return to_virtio_vdpa_device(vdev)->vdpa;
+}
+
+static void virtio_vdpa_get(struct virtio_device *vdev, unsigned offset,
+                           void *buf, unsigned len)
+{
+       struct vdpa_device *vdpa = vd_get_vdpa(vdev);
+       const struct vdpa_config_ops *ops = vdpa->config;
+
+       ops->get_config(vdpa, offset, buf, len);
+}
+
+static void virtio_vdpa_set(struct virtio_device *vdev, unsigned offset,
+                           const void *buf, unsigned len)
+{
+       struct vdpa_device *vdpa = vd_get_vdpa(vdev);
+       const struct vdpa_config_ops *ops = vdpa->config;
+
+       ops->set_config(vdpa, offset, buf, len);
+}
+
+static u32 virtio_vdpa_generation(struct virtio_device *vdev)
+{
+       struct vdpa_device *vdpa = vd_get_vdpa(vdev);
+       const struct vdpa_config_ops *ops = vdpa->config;
+
+       if (ops->get_generation)
+               return ops->get_generation(vdpa);
+
+       return 0;
+}
+
+static u8 virtio_vdpa_get_status(struct virtio_device *vdev)
+{
+       struct vdpa_device *vdpa = vd_get_vdpa(vdev);
+       const struct vdpa_config_ops *ops = vdpa->config;
+
+       return ops->get_status(vdpa);
+}
+
+static void virtio_vdpa_set_status(struct virtio_device *vdev, u8 status)
+{
+       struct vdpa_device *vdpa = vd_get_vdpa(vdev);
+       const struct vdpa_config_ops *ops = vdpa->config;
+
+       return ops->set_status(vdpa, status);
+}
+
+static void virtio_vdpa_reset(struct virtio_device *vdev)
+{
+       struct vdpa_device *vdpa = vd_get_vdpa(vdev);
+       const struct vdpa_config_ops *ops = vdpa->config;
+
+       return ops->set_status(vdpa, 0);
+}
+
+static bool virtio_vdpa_notify(struct virtqueue *vq)
+{
+       struct vdpa_device *vdpa = vd_get_vdpa(vq->vdev);
+       const struct vdpa_config_ops *ops = vdpa->config;
+
+       ops->kick_vq(vdpa, vq->index);
+
+       return true;
+}
+
+static irqreturn_t virtio_vdpa_config_cb(void *private)
+{
+       struct virtio_vdpa_device *vd_dev = private;
+
+       virtio_config_changed(&vd_dev->vdev);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t virtio_vdpa_virtqueue_cb(void *private)
+{
+       struct virtio_vdpa_vq_info *info = private;
+
+       return vring_interrupt(0, info->vq);
+}
+
+static struct virtqueue *
+virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
+                    void (*callback)(struct virtqueue *vq),
+                    const char *name, bool ctx)
+{
+       struct virtio_vdpa_device *vd_dev = to_virtio_vdpa_device(vdev);
+       struct vdpa_device *vdpa = vd_get_vdpa(vdev);
+       const struct vdpa_config_ops *ops = vdpa->config;
+       struct virtio_vdpa_vq_info *info;
+       struct vdpa_callback cb;
+       struct virtqueue *vq;
+       u64 desc_addr, driver_addr, device_addr;
+       unsigned long flags;
+       u32 align, num;
+       int err;
+
+       if (!name)
+               return NULL;
+
+       /* Queue shouldn't already be set up. */
+       if (ops->get_vq_ready(vdpa, index))
+               return ERR_PTR(-ENOENT);
+
+       /* Allocate and fill out our active queue description */
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return ERR_PTR(-ENOMEM);
+
+       num = ops->get_vq_num_max(vdpa);
+       if (num == 0) {
+               err = -ENOENT;
+               goto error_new_virtqueue;
+       }
+
+       /* Create the vring */
+       align = ops->get_vq_align(vdpa);
+       vq = vring_create_virtqueue(index, num, align, vdev,
+                                   true, true, ctx,
+                                   virtio_vdpa_notify, callback, name);
+       if (!vq) {
+               err = -ENOMEM;
+               goto error_new_virtqueue;
+       }
+
+       /* Setup virtqueue callback */
+       cb.callback = virtio_vdpa_virtqueue_cb;
+       cb.private = info;
+       ops->set_vq_cb(vdpa, index, &cb);
+       ops->set_vq_num(vdpa, index, virtqueue_get_vring_size(vq));
+
+       desc_addr = virtqueue_get_desc_addr(vq);
+       driver_addr = virtqueue_get_avail_addr(vq);
+       device_addr = virtqueue_get_used_addr(vq);
+
+       if (ops->set_vq_address(vdpa, index,
+                               desc_addr, driver_addr,
+                               device_addr)) {
+               err = -EINVAL;
+               goto err_vq;
+       }
+
+       ops->set_vq_ready(vdpa, index, 1);
+
+       vq->priv = info;
+       info->vq = vq;
+
+       spin_lock_irqsave(&vd_dev->lock, flags);
+       list_add(&info->node, &vd_dev->virtqueues);
+       spin_unlock_irqrestore(&vd_dev->lock, flags);
+
+       return vq;
+
+err_vq:
+       vring_del_virtqueue(vq);
+error_new_virtqueue:
+       ops->set_vq_ready(vdpa, index, 0);
+       /* VDPA driver should make sure vq is stopeed here */
+       WARN_ON(ops->get_vq_ready(vdpa, index));
+       kfree(info);
+       return ERR_PTR(err);
+}
+
+static void virtio_vdpa_del_vq(struct virtqueue *vq)
+{
+       struct virtio_vdpa_device *vd_dev = to_virtio_vdpa_device(vq->vdev);
+       struct vdpa_device *vdpa = vd_dev->vdpa;
+       const struct vdpa_config_ops *ops = vdpa->config;
+       struct virtio_vdpa_vq_info *info = vq->priv;
+       unsigned int index = vq->index;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vd_dev->lock, flags);
+       list_del(&info->node);
+       spin_unlock_irqrestore(&vd_dev->lock, flags);
+
+       /* Select and deactivate the queue */
+       ops->set_vq_ready(vdpa, index, 0);
+       WARN_ON(ops->get_vq_ready(vdpa, index));
+
+       vring_del_virtqueue(vq);
+
+       kfree(info);
+}
+
+static void virtio_vdpa_del_vqs(struct virtio_device *vdev)
+{
+       struct virtqueue *vq, *n;
+
+       list_for_each_entry_safe(vq, n, &vdev->vqs, list)
+               virtio_vdpa_del_vq(vq);
+}
+
+static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+                               struct virtqueue *vqs[],
+                               vq_callback_t *callbacks[],
+                               const char * const names[],
+                               const bool *ctx,
+                               struct irq_affinity *desc)
+{
+       struct virtio_vdpa_device *vd_dev = to_virtio_vdpa_device(vdev);
+       struct vdpa_device *vdpa = vd_get_vdpa(vdev);
+       const struct vdpa_config_ops *ops = vdpa->config;
+       struct vdpa_callback cb;
+       int i, err, queue_idx = 0;
+
+       for (i = 0; i < nvqs; ++i) {
+               if (!names[i]) {
+                       vqs[i] = NULL;
+                       continue;
+               }
+
+               vqs[i] = virtio_vdpa_setup_vq(vdev, queue_idx++,
+                                             callbacks[i], names[i], ctx ?
+                                             ctx[i] : false);
+               if (IS_ERR(vqs[i])) {
+                       err = PTR_ERR(vqs[i]);
+                       goto err_setup_vq;
+               }
+       }
+
+       cb.callback = virtio_vdpa_config_cb;
+       cb.private = vd_dev;
+       ops->set_config_cb(vdpa, &cb);
+
+       return 0;
+
+err_setup_vq:
+       virtio_vdpa_del_vqs(vdev);
+       return err;
+}
+
+static u64 virtio_vdpa_get_features(struct virtio_device *vdev)
+{
+       struct vdpa_device *vdpa = vd_get_vdpa(vdev);
+       const struct vdpa_config_ops *ops = vdpa->config;
+
+       return ops->get_features(vdpa);
+}
+
+static int virtio_vdpa_finalize_features(struct virtio_device *vdev)
+{
+       struct vdpa_device *vdpa = vd_get_vdpa(vdev);
+       const struct vdpa_config_ops *ops = vdpa->config;
+
+       /* Give virtio_ring a chance to accept features. */
+       vring_transport_features(vdev);
+
+       return ops->set_features(vdpa, vdev->features);
+}
+
+static const char *virtio_vdpa_bus_name(struct virtio_device *vdev)
+{
+       struct virtio_vdpa_device *vd_dev = to_virtio_vdpa_device(vdev);
+       struct vdpa_device *vdpa = vd_dev->vdpa;
+
+       return dev_name(&vdpa->dev);
+}
+
+static const struct virtio_config_ops virtio_vdpa_config_ops = {
+       .get            = virtio_vdpa_get,
+       .set            = virtio_vdpa_set,
+       .generation     = virtio_vdpa_generation,
+       .get_status     = virtio_vdpa_get_status,
+       .set_status     = virtio_vdpa_set_status,
+       .reset          = virtio_vdpa_reset,
+       .find_vqs       = virtio_vdpa_find_vqs,
+       .del_vqs        = virtio_vdpa_del_vqs,
+       .get_features   = virtio_vdpa_get_features,
+       .finalize_features = virtio_vdpa_finalize_features,
+       .bus_name       = virtio_vdpa_bus_name,
+};
+
+static void virtio_vdpa_release_dev(struct device *_d)
+{
+       struct virtio_device *vdev =
+              container_of(_d, struct virtio_device, dev);
+       struct virtio_vdpa_device *vd_dev =
+              container_of(vdev, struct virtio_vdpa_device, vdev);
+
+       kfree(vd_dev);
+}
+
+static int virtio_vdpa_probe(struct vdpa_device *vdpa)
+{
+       const struct vdpa_config_ops *ops = vdpa->config;
+       struct virtio_vdpa_device *vd_dev, *reg_dev = NULL;
+       int ret = -EINVAL;
+
+       vd_dev = kzalloc(sizeof(*vd_dev), GFP_KERNEL);
+       if (!vd_dev)
+               return -ENOMEM;
+
+       vd_dev->vdev.dev.parent = vdpa_get_dma_dev(vdpa);
+       vd_dev->vdev.dev.release = virtio_vdpa_release_dev;
+       vd_dev->vdev.config = &virtio_vdpa_config_ops;
+       vd_dev->vdpa = vdpa;
+       INIT_LIST_HEAD(&vd_dev->virtqueues);
+       spin_lock_init(&vd_dev->lock);
+
+       vd_dev->vdev.id.device = ops->get_device_id(vdpa);
+       if (vd_dev->vdev.id.device == 0)
+               goto err;
+
+       vd_dev->vdev.id.vendor = ops->get_vendor_id(vdpa);
+       ret = register_virtio_device(&vd_dev->vdev);
+       reg_dev = vd_dev;
+       if (ret)
+               goto err;
+
+       vdpa_set_drvdata(vdpa, vd_dev);
+
+       return 0;
+
+err:
+       if (reg_dev)
+               put_device(&vd_dev->vdev.dev);
+       else
+               kfree(vd_dev);
+       return ret;
+}
+
+static void virtio_vdpa_remove(struct vdpa_device *vdpa)
+{
+       struct virtio_vdpa_device *vd_dev = vdpa_get_drvdata(vdpa);
+
+       unregister_virtio_device(&vd_dev->vdev);
+}
+
+static struct vdpa_driver virtio_vdpa_driver = {
+       .driver = {
+               .name   = "virtio_vdpa",
+       },
+       .probe  = virtio_vdpa_probe,
+       .remove = virtio_vdpa_remove,
+};
+
+module_vdpa_driver(virtio_vdpa_driver);
+
+MODULE_VERSION(MOD_VERSION);
+MODULE_LICENSE(MOD_LICENSE);
+MODULE_AUTHOR(MOD_AUTHOR);
+MODULE_DESCRIPTION(MOD_DESC);
index 9ea2b43..0663c60 100644 (file)
@@ -584,6 +584,14 @@ config DAVINCI_WATCHDOG
          NOTE: once enabled, this timer cannot be disabled.
          Say N if you are unsure.
 
+config K3_RTI_WATCHDOG
+       tristate "Texas Instruments K3 RTI watchdog"
+       depends on ARCH_K3 || COMPILE_TEST
+       select WATCHDOG_CORE
+       help
+         Say Y here if you want to include support for the K3 watchdog
+         timer (RTI module) available in the K3 generation of processors.
+
 config ORION_WATCHDOG
        tristate "Orion watchdog"
        depends on ARCH_ORION5X || ARCH_DOVE || MACH_DOVE || ARCH_MVEBU || (COMPILE_TEST && !ARCH_EBSA110)
index 2ee352b..6de2e4c 100644 (file)
@@ -57,6 +57,7 @@ obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
 obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
 obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
+obj-$(CONFIG_K3_RTI_WATCHDOG) += rti_wdt.o
 obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o
 obj-$(CONFIG_SUNXI_WATCHDOG) += sunxi_wdt.o
 obj-$(CONFIG_RN5T618_WATCHDOG) += rn5t618_wdt.o
index f8d58bf..1fe472f 100644 (file)
@@ -244,6 +244,11 @@ static const struct regmap_config imx2_wdt_regmap_config = {
        .max_register = 0x8,
 };
 
+static void imx2_wdt_action(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
 static int __init imx2_wdt_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -292,6 +297,10 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       ret = devm_add_action_or_reset(dev, imx2_wdt_action, wdev->clk);
+       if (ret)
+               return ret;
+
        regmap_read(wdev->regmap, IMX2_WDT_WRSR, &val);
        wdog->bootstatus = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0;
 
@@ -315,32 +324,7 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
         */
        regmap_write(wdev->regmap, IMX2_WDT_WMCR, 0);
 
-       ret = watchdog_register_device(wdog);
-       if (ret)
-               goto disable_clk;
-
-       dev_info(dev, "timeout %d sec (nowayout=%d)\n",
-                wdog->timeout, nowayout);
-
-       return 0;
-
-disable_clk:
-       clk_disable_unprepare(wdev->clk);
-       return ret;
-}
-
-static int __exit imx2_wdt_remove(struct platform_device *pdev)
-{
-       struct watchdog_device *wdog = platform_get_drvdata(pdev);
-       struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
-
-       watchdog_unregister_device(wdog);
-
-       if (imx2_wdt_is_running(wdev)) {
-               imx2_wdt_ping(wdog);
-               dev_crit(&pdev->dev, "Device removed: Expect reboot!\n");
-       }
-       return 0;
+       return devm_watchdog_register_device(dev, wdog);
 }
 
 static void imx2_wdt_shutdown(struct platform_device *pdev)
@@ -417,7 +401,6 @@ static const struct of_device_id imx2_wdt_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, imx2_wdt_dt_ids);
 
 static struct platform_driver imx2_wdt_driver = {
-       .remove         = __exit_p(imx2_wdt_remove),
        .shutdown       = imx2_wdt_shutdown,
        .driver         = {
                .name   = DRIVER_NAME,
index 11b9e7c..7993c8c 100644 (file)
@@ -4,7 +4,6 @@
  */
 
 #include <linux/clk.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
index 8ed89f0..60a3246 100644 (file)
@@ -6,13 +6,11 @@
 #include <linux/arm-smccc.h>
 #include <linux/firmware/imx/sci.h>
 #include <linux/io.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
-#include <linux/reboot.h>
 #include <linux/watchdog.h>
 
 #define DEFAULT_TIMEOUT 60
index 9c773c3..765577f 100644 (file)
@@ -103,30 +103,29 @@ static int npcm_wdt_stop(struct watchdog_device *wdd)
        return 0;
 }
 
-
 static int npcm_wdt_set_timeout(struct watchdog_device *wdd,
                                unsigned int timeout)
 {
        if (timeout < 2)
                wdd->timeout = 1;
        else if (timeout < 3)
-             wdd->timeout = 2;
+               wdd->timeout = 2;
        else if (timeout < 6)
-             wdd->timeout = 5;
+               wdd->timeout = 5;
        else if (timeout < 11)
-             wdd->timeout = 10;
+               wdd->timeout = 10;
        else if (timeout < 22)
-             wdd->timeout = 21;
+               wdd->timeout = 21;
        else if (timeout < 44)
-             wdd->timeout = 43;
+               wdd->timeout = 43;
        else if (timeout < 87)
-             wdd->timeout = 86;
+               wdd->timeout = 86;
        else if (timeout < 173)
-             wdd->timeout = 172;
+               wdd->timeout = 172;
        else if (timeout < 688)
-             wdd->timeout = 687;
+               wdd->timeout = 687;
        else
-             wdd->timeout = 2750;
+               wdd->timeout = 2750;
 
        if (watchdog_active(wdd))
                npcm_wdt_start(wdd);
index 8e6dfe7..4ddb4ea 100644 (file)
@@ -52,7 +52,7 @@
 #define WDT_A370_RATIO         (1 << WDT_A370_RATIO_SHIFT)
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
-static int heartbeat = -1;             /* module parameter (seconds) */
+static int heartbeat;          /* module parameter (seconds) */
 
 struct orion_watchdog;
 
index 1213179..0937b8d 100644 (file)
@@ -192,6 +192,7 @@ static int pm8916_wdt_probe(struct platform_device *pdev)
        wdt->wdev.timeout = PM8916_WDT_DEFAULT_TIMEOUT;
        wdt->wdev.pretimeout = 0;
        watchdog_set_drvdata(&wdt->wdev, wdt);
+       platform_set_drvdata(pdev, wdt);
 
        watchdog_init_timeout(&wdt->wdev, 0, dev);
        pm8916_wdt_configure_timers(&wdt->wdev);
@@ -199,6 +200,29 @@ static int pm8916_wdt_probe(struct platform_device *pdev)
        return devm_watchdog_register_device(dev, &wdt->wdev);
 }
 
+static int __maybe_unused pm8916_wdt_suspend(struct device *dev)
+{
+       struct pm8916_wdt *wdt = dev_get_drvdata(dev);
+
+       if (watchdog_active(&wdt->wdev))
+               return pm8916_wdt_stop(&wdt->wdev);
+
+       return 0;
+}
+
+static int __maybe_unused pm8916_wdt_resume(struct device *dev)
+{
+       struct pm8916_wdt *wdt = dev_get_drvdata(dev);
+
+       if (watchdog_active(&wdt->wdev))
+               return pm8916_wdt_start(&wdt->wdev);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pm8916_wdt_pm_ops, pm8916_wdt_suspend,
+                        pm8916_wdt_resume);
+
 static const struct of_device_id pm8916_wdt_id_table[] = {
        { .compatible = "qcom,pm8916-wdt" },
        { }
@@ -210,6 +234,7 @@ static struct platform_driver pm8916_wdt_driver = {
        .driver = {
                .name = "pm8916-wdt",
                .of_match_table = of_match_ptr(pm8916_wdt_id_table),
+               .pm = &pm8916_wdt_pm_ops,
        },
 };
 module_platform_driver(pm8916_wdt_driver);
index eb47fe5..ab7465d 100644 (file)
@@ -40,6 +40,11 @@ static const u32 reg_offset_data_kpss[] = {
        [WDT_BITE_TIME] = 0x14,
 };
 
+struct qcom_wdt_match_data {
+       const u32 *offset;
+       bool pretimeout;
+};
+
 struct qcom_wdt {
        struct watchdog_device  wdd;
        unsigned long           rate;
@@ -179,19 +184,29 @@ static void qcom_clk_disable_unprepare(void *data)
        clk_disable_unprepare(data);
 }
 
+static const struct qcom_wdt_match_data match_data_apcs_tmr = {
+       .offset = reg_offset_data_apcs_tmr,
+       .pretimeout = false,
+};
+
+static const struct qcom_wdt_match_data match_data_kpss = {
+       .offset = reg_offset_data_kpss,
+       .pretimeout = true,
+};
+
 static int qcom_wdt_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct qcom_wdt *wdt;
        struct resource *res;
        struct device_node *np = dev->of_node;
-       const u32 *regs;
+       const struct qcom_wdt_match_data *data;
        u32 percpu_offset;
        int irq, ret;
        struct clk *clk;
 
-       regs = of_device_get_match_data(dev);
-       if (!regs) {
+       data = of_device_get_match_data(dev);
+       if (!data) {
                dev_err(dev, "Unsupported QCOM WDT module\n");
                return -ENODEV;
        }
@@ -247,9 +262,8 @@ static int qcom_wdt_probe(struct platform_device *pdev)
 
        /* check if there is pretimeout support */
        irq = platform_get_irq_optional(pdev, 0);
-       if (irq > 0) {
-               ret = devm_request_irq(dev, irq, qcom_wdt_isr,
-                                      IRQF_TRIGGER_RISING,
+       if (data->pretimeout && irq > 0) {
+               ret = devm_request_irq(dev, irq, qcom_wdt_isr, 0,
                                       "wdt_bark", &wdt->wdd);
                if (ret)
                        return ret;
@@ -267,7 +281,7 @@ static int qcom_wdt_probe(struct platform_device *pdev)
        wdt->wdd.min_timeout = 1;
        wdt->wdd.max_timeout = 0x10000000U / wdt->rate;
        wdt->wdd.parent = dev;
-       wdt->layout = regs;
+       wdt->layout = data->offset;
 
        if (readl(wdt_addr(wdt, WDT_STS)) & 1)
                wdt->wdd.bootstatus = WDIOF_CARDRESET;
@@ -311,9 +325,9 @@ static int __maybe_unused qcom_wdt_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(qcom_wdt_pm_ops, qcom_wdt_suspend, qcom_wdt_resume);
 
 static const struct of_device_id qcom_wdt_of_table[] = {
-       { .compatible = "qcom,kpss-timer", .data = reg_offset_data_apcs_tmr },
-       { .compatible = "qcom,scss-timer", .data = reg_offset_data_apcs_tmr },
-       { .compatible = "qcom,kpss-wdt", .data = reg_offset_data_kpss },
+       { .compatible = "qcom,kpss-timer", .data = &match_data_apcs_tmr },
+       { .compatible = "qcom,scss-timer", .data = &match_data_apcs_tmr },
+       { .compatible = "qcom,kpss-wdt", .data = &match_data_kpss },
        { },
 };
 MODULE_DEVICE_TABLE(of, qcom_wdt_of_table);
diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c
new file mode 100644 (file)
index 0000000..d456dd7
--- /dev/null
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Watchdog driver for the K3 RTI module
+ *
+ * (c) Copyright 2019-2020 Texas Instruments Inc.
+ * All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+
+#define DEFAULT_HEARTBEAT 60
+
+/* Max heartbeat is calculated at 32kHz source clock */
+#define MAX_HEARTBEAT  1000
+
+/* Timer register set definition */
+#define RTIDWDCTRL     0x90
+#define RTIDWDPRLD     0x94
+#define RTIWDSTATUS    0x98
+#define RTIWDKEY       0x9c
+#define RTIDWDCNTR     0xa0
+#define RTIWWDRXCTRL   0xa4
+#define RTIWWDSIZECTRL 0xa8
+
+#define RTIWWDRX_NMI   0xa
+
+#define RTIWWDSIZE_50P 0x50
+
+#define WDENABLE_KEY   0xa98559da
+
+#define WDKEY_SEQ0             0xe51a
+#define WDKEY_SEQ1             0xa35c
+
+#define WDT_PRELOAD_SHIFT      13
+
+#define WDT_PRELOAD_MAX                0xfff
+
+#define DWDST                  BIT(1)
+
+static int heartbeat;
+
+/*
+ * struct to hold data for each WDT device
+ * @base - base io address of WD device
+ * @freq - source clock frequency of WDT
+ * @wdd  - hold watchdog device as is in WDT core
+ */
+struct rti_wdt_device {
+       void __iomem            *base;
+       unsigned long           freq;
+       struct watchdog_device  wdd;
+};
+
+static int rti_wdt_start(struct watchdog_device *wdd)
+{
+       u32 timer_margin;
+       struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);
+
+       /* set timeout period */
+       timer_margin = (u64)wdd->timeout * wdt->freq;
+       timer_margin >>= WDT_PRELOAD_SHIFT;
+       if (timer_margin > WDT_PRELOAD_MAX)
+               timer_margin = WDT_PRELOAD_MAX;
+       writel_relaxed(timer_margin, wdt->base + RTIDWDPRLD);
+
+       /*
+        * RTI only supports a windowed mode, where the watchdog can only
+        * be petted during the open window; not too early or not too late.
+        * The HW configuration options only allow for the open window size
+        * to be 50% or less than that; we obviouly want to configure the open
+        * window as large as possible so we select the 50% option. To avoid
+        * any glitches, we accommodate 5% safety margin also, so we setup
+        * the min_hw_hearbeat at 55% of the timeout period.
+        */
+       wdd->min_hw_heartbeat_ms = 11 * wdd->timeout * 1000 / 20;
+
+       /* Generate NMI when wdt expires */
+       writel_relaxed(RTIWWDRX_NMI, wdt->base + RTIWWDRXCTRL);
+
+       /* Open window size 50%; this is the largest window size available */
+       writel_relaxed(RTIWWDSIZE_50P, wdt->base + RTIWWDSIZECTRL);
+
+       readl_relaxed(wdt->base + RTIWWDSIZECTRL);
+
+       /* enable watchdog */
+       writel_relaxed(WDENABLE_KEY, wdt->base + RTIDWDCTRL);
+       return 0;
+}
+
+static int rti_wdt_ping(struct watchdog_device *wdd)
+{
+       struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);
+
+       /* put watchdog in service state */
+       writel_relaxed(WDKEY_SEQ0, wdt->base + RTIWDKEY);
+       /* put watchdog in active state */
+       writel_relaxed(WDKEY_SEQ1, wdt->base + RTIWDKEY);
+
+       return 0;
+}
+
+static unsigned int rti_wdt_get_timeleft(struct watchdog_device *wdd)
+{
+       u64 timer_counter;
+       u32 val;
+       struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);
+
+       /* if timeout has occurred then return 0 */
+       val = readl_relaxed(wdt->base + RTIWDSTATUS);
+       if (val & DWDST)
+               return 0;
+
+       timer_counter = readl_relaxed(wdt->base + RTIDWDCNTR);
+
+       do_div(timer_counter, wdt->freq);
+
+       return timer_counter;
+}
+
+static const struct watchdog_info rti_wdt_info = {
+       .options = WDIOF_KEEPALIVEPING,
+       .identity = "K3 RTI Watchdog",
+};
+
+static const struct watchdog_ops rti_wdt_ops = {
+       .owner          = THIS_MODULE,
+       .start          = rti_wdt_start,
+       .ping           = rti_wdt_ping,
+       .get_timeleft   = rti_wdt_get_timeleft,
+};
+
+static int rti_wdt_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct device *dev = &pdev->dev;
+       struct resource *wdt_mem;
+       struct watchdog_device *wdd;
+       struct rti_wdt_device *wdt;
+       struct clk *clk;
+
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
+       if (!wdt)
+               return -ENOMEM;
+
+       clk = clk_get(dev, NULL);
+       if (IS_ERR(clk)) {
+               if (PTR_ERR(clk) != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get clock\n");
+               return PTR_ERR(clk);
+       }
+
+       wdt->freq = clk_get_rate(clk);
+
+       clk_put(clk);
+
+       if (!wdt->freq) {
+               dev_err(dev, "Failed to get fck rate.\n");
+               return -EINVAL;
+       }
+
+       pm_runtime_enable(dev);
+       ret = pm_runtime_get_sync(dev);
+       if (ret) {
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "runtime pm failed\n");
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, wdt);
+
+       wdd = &wdt->wdd;
+       wdd->info = &rti_wdt_info;
+       wdd->ops = &rti_wdt_ops;
+       wdd->min_timeout = 1;
+       wdd->max_hw_heartbeat_ms = (WDT_PRELOAD_MAX << WDT_PRELOAD_SHIFT) /
+               wdt->freq * 1000;
+       wdd->timeout = DEFAULT_HEARTBEAT;
+       wdd->parent = dev;
+
+       watchdog_init_timeout(wdd, heartbeat, dev);
+
+       watchdog_set_drvdata(wdd, wdt);
+       watchdog_set_nowayout(wdd, 1);
+       watchdog_set_restart_priority(wdd, 128);
+
+       wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       wdt->base = devm_ioremap_resource(dev, wdt_mem);
+       if (IS_ERR(wdt->base)) {
+               ret = PTR_ERR(wdt->base);
+               goto err_iomap;
+       }
+
+       ret = watchdog_register_device(wdd);
+       if (ret) {
+               dev_err(dev, "cannot register watchdog device\n");
+               goto err_iomap;
+       }
+
+       return 0;
+
+err_iomap:
+       pm_runtime_put_sync(&pdev->dev);
+
+       return ret;
+}
+
+static int rti_wdt_remove(struct platform_device *pdev)
+{
+       struct rti_wdt_device *wdt = platform_get_drvdata(pdev);
+
+       watchdog_unregister_device(&wdt->wdd);
+       pm_runtime_put(&pdev->dev);
+
+       return 0;
+}
+
+static const struct of_device_id rti_wdt_of_match[] = {
+       { .compatible = "ti,j7-rti-wdt", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rti_wdt_of_match);
+
+static struct platform_driver rti_wdt_driver = {
+       .driver = {
+               .name = "rti-wdt",
+               .of_match_table = rti_wdt_of_match,
+       },
+       .probe = rti_wdt_probe,
+       .remove = rti_wdt_remove,
+};
+
+module_platform_driver(rti_wdt_driver);
+
+MODULE_AUTHOR("Tero Kristo <t-kristo@ti.com>");
+MODULE_DESCRIPTION("K3 RTI Watchdog Driver");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat,
+                "Watchdog heartbeat period in seconds from 1 to "
+                __MODULE_STRING(MAX_HEARTBEAT) ", default "
+                __MODULE_STRING(DEFAULT_HEARTBEAT));
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rti-wdt");
index 861daf4..4238447 100644 (file)
 
 static DEFINE_IDA(watchdog_ida);
 
+static int stop_on_reboot = -1;
+module_param(stop_on_reboot, int, 0444);
+MODULE_PARM_DESC(stop_on_reboot, "Stop watchdogs on reboot (0=keep watching, 1=stop)");
+
 /*
  * Deferred Registration infrastructure.
  *
@@ -254,6 +258,14 @@ static int __watchdog_register_device(struct watchdog_device *wdd)
                }
        }
 
+       /* Module parameter to force watchdog policy on reboot. */
+       if (stop_on_reboot != -1) {
+               if (stop_on_reboot)
+                       set_bit(WDOG_STOP_ON_REBOOT, &wdd->status);
+               else
+                       clear_bit(WDOG_STOP_ON_REBOOT, &wdd->status);
+       }
+
        if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) {
                wdd->reboot_nb.notifier_call = watchdog_reboot_notifier;
 
index 8b5c742..7e4cd34 100644 (file)
@@ -282,6 +282,7 @@ static int watchdog_start(struct watchdog_device *wdd)
        if (err == 0) {
                set_bit(WDOG_ACTIVE, &wdd->status);
                wd_data->last_keepalive = started_at;
+               wd_data->last_hw_keepalive = started_at;
                watchdog_update_worker(wdd);
        }
 
index 030ce24..d96ad8f 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/platform_device.h>
 #include <linux/watchdog.h>
 #include <linux/uaccess.h>
-#include <linux/gpio.h>
 
 #include <linux/mfd/wm831x/core.h>
 #include <linux/mfd/wm831x/pdata.h>
@@ -29,7 +28,6 @@ struct wm831x_wdt_drvdata {
        struct watchdog_device wdt;
        struct wm831x *wm831x;
        struct mutex lock;
-       int update_gpio;
        int update_state;
 };
 
@@ -103,14 +101,6 @@ static int wm831x_wdt_ping(struct watchdog_device *wdt_dev)
 
        mutex_lock(&driver_data->lock);
 
-       if (driver_data->update_gpio) {
-               gpio_set_value_cansleep(driver_data->update_gpio,
-                                       driver_data->update_state);
-               driver_data->update_state = !driver_data->update_state;
-               ret = 0;
-               goto out;
-       }
-
        reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG);
 
        if (!(reg & WM831X_WDOG_RST_SRC)) {
@@ -239,23 +229,6 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
                reg |= pdata->secondary << WM831X_WDOG_SECACT_SHIFT;
                reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT;
 
-               if (pdata->update_gpio) {
-                       ret = devm_gpio_request_one(dev, pdata->update_gpio,
-                                                   GPIOF_OUT_INIT_LOW,
-                                                   "Watchdog update");
-                       if (ret < 0) {
-                               dev_err(wm831x->dev,
-                                       "Failed to request update GPIO: %d\n",
-                                       ret);
-                               return ret;
-                       }
-
-                       driver_data->update_gpio = pdata->update_gpio;
-
-                       /* Make sure the watchdog takes hardware updates */
-                       reg |= WM831X_WDOG_RST_SRC;
-               }
-
                ret = wm831x_reg_unlock(wm831x);
                if (ret == 0) {
                        ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg);
index 4a363a8..cab86a0 100644 (file)
@@ -422,7 +422,7 @@ static int ziirave_firm_upload(struct watchdog_device *wdd,
 
 static const struct watchdog_info ziirave_wdt_info = {
        .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
-       .identity = "Zodiac RAVE Watchdog",
+       .identity = "RAVE Switch Watchdog",
 };
 
 static const struct watchdog_ops ziirave_wdt_ops = {
index 8edef51..64df919 100644 (file)
@@ -53,37 +53,37 @@ static void evtchn_2l_bind_to_cpu(struct irq_info *info, unsigned cpu)
        set_bit(info->evtchn, BM(per_cpu(cpu_evtchn_mask, cpu)));
 }
 
-static void evtchn_2l_clear_pending(unsigned port)
+static void evtchn_2l_clear_pending(evtchn_port_t port)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
        sync_clear_bit(port, BM(&s->evtchn_pending[0]));
 }
 
-static void evtchn_2l_set_pending(unsigned port)
+static void evtchn_2l_set_pending(evtchn_port_t port)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
        sync_set_bit(port, BM(&s->evtchn_pending[0]));
 }
 
-static bool evtchn_2l_is_pending(unsigned port)
+static bool evtchn_2l_is_pending(evtchn_port_t port)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
        return sync_test_bit(port, BM(&s->evtchn_pending[0]));
 }
 
-static bool evtchn_2l_test_and_set_mask(unsigned port)
+static bool evtchn_2l_test_and_set_mask(evtchn_port_t port)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
        return sync_test_and_set_bit(port, BM(&s->evtchn_mask[0]));
 }
 
-static void evtchn_2l_mask(unsigned port)
+static void evtchn_2l_mask(evtchn_port_t port)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
        sync_set_bit(port, BM(&s->evtchn_mask[0]));
 }
 
-static void evtchn_2l_unmask(unsigned port)
+static void evtchn_2l_unmask(evtchn_port_t port)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
        unsigned int cpu = get_cpu();
@@ -173,7 +173,7 @@ static void evtchn_2l_handle_events(unsigned cpu)
        /* Timer interrupt has highest priority. */
        irq = irq_from_virq(cpu, VIRQ_TIMER);
        if (irq != -1) {
-               unsigned int evtchn = evtchn_from_irq(irq);
+               evtchn_port_t evtchn = evtchn_from_irq(irq);
                word_idx = evtchn / BITS_PER_LONG;
                bit_idx = evtchn % BITS_PER_LONG;
                if (active_evtchns(cpu, s, word_idx) & (1ULL << bit_idx))
@@ -228,7 +228,7 @@ static void evtchn_2l_handle_events(unsigned cpu)
 
                do {
                        xen_ulong_t bits;
-                       int port;
+                       evtchn_port_t port;
 
                        bits = MASK_LSBS(pending_bits, bit_idx);
 
index 499eff7..3a791c8 100644 (file)
@@ -116,7 +116,7 @@ static void clear_evtchn_to_irq_all(void)
        }
 }
 
-static int set_evtchn_to_irq(unsigned evtchn, unsigned irq)
+static int set_evtchn_to_irq(evtchn_port_t evtchn, unsigned int irq)
 {
        unsigned row;
        unsigned col;
@@ -143,7 +143,7 @@ static int set_evtchn_to_irq(unsigned evtchn, unsigned irq)
        return 0;
 }
 
-int get_evtchn_to_irq(unsigned evtchn)
+int get_evtchn_to_irq(evtchn_port_t evtchn)
 {
        if (evtchn >= xen_evtchn_max_channels())
                return -1;
@@ -162,7 +162,7 @@ struct irq_info *info_for_irq(unsigned irq)
 static int xen_irq_info_common_setup(struct irq_info *info,
                                     unsigned irq,
                                     enum xen_irq_type type,
-                                    unsigned evtchn,
+                                    evtchn_port_t evtchn,
                                     unsigned short cpu)
 {
        int ret;
@@ -184,7 +184,7 @@ static int xen_irq_info_common_setup(struct irq_info *info,
 }
 
 static int xen_irq_info_evtchn_setup(unsigned irq,
-                                    unsigned evtchn)
+                                    evtchn_port_t evtchn)
 {
        struct irq_info *info = info_for_irq(irq);
 
@@ -193,7 +193,7 @@ static int xen_irq_info_evtchn_setup(unsigned irq,
 
 static int xen_irq_info_ipi_setup(unsigned cpu,
                                  unsigned irq,
-                                 unsigned evtchn,
+                                 evtchn_port_t evtchn,
                                  enum ipi_vector ipi)
 {
        struct irq_info *info = info_for_irq(irq);
@@ -207,7 +207,7 @@ static int xen_irq_info_ipi_setup(unsigned cpu,
 
 static int xen_irq_info_virq_setup(unsigned cpu,
                                   unsigned irq,
-                                  unsigned evtchn,
+                                  evtchn_port_t evtchn,
                                   unsigned virq)
 {
        struct irq_info *info = info_for_irq(irq);
@@ -220,7 +220,7 @@ static int xen_irq_info_virq_setup(unsigned cpu,
 }
 
 static int xen_irq_info_pirq_setup(unsigned irq,
-                                  unsigned evtchn,
+                                  evtchn_port_t evtchn,
                                   unsigned pirq,
                                   unsigned gsi,
                                   uint16_t domid,
@@ -245,7 +245,7 @@ static void xen_irq_info_cleanup(struct irq_info *info)
 /*
  * Accessors for packed IRQ information.
  */
-unsigned int evtchn_from_irq(unsigned irq)
+evtchn_port_t evtchn_from_irq(unsigned irq)
 {
        if (WARN(irq >= nr_irqs, "Invalid irq %d!\n", irq))
                return 0;
@@ -253,7 +253,7 @@ unsigned int evtchn_from_irq(unsigned irq)
        return info_for_irq(irq)->evtchn;
 }
 
-unsigned irq_from_evtchn(unsigned int evtchn)
+unsigned int irq_from_evtchn(evtchn_port_t evtchn)
 {
        return get_evtchn_to_irq(evtchn);
 }
@@ -304,7 +304,7 @@ unsigned cpu_from_irq(unsigned irq)
        return info_for_irq(irq)->cpu;
 }
 
-unsigned int cpu_from_evtchn(unsigned int evtchn)
+unsigned int cpu_from_evtchn(evtchn_port_t evtchn)
 {
        int irq = get_evtchn_to_irq(evtchn);
        unsigned ret = 0;
@@ -330,9 +330,9 @@ static bool pirq_needs_eoi_flag(unsigned irq)
        return info->u.pirq.flags & PIRQ_NEEDS_EOI;
 }
 
-static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
+static void bind_evtchn_to_cpu(evtchn_port_t evtchn, unsigned int cpu)
 {
-       int irq = get_evtchn_to_irq(chn);
+       int irq = get_evtchn_to_irq(evtchn);
        struct irq_info *info = info_for_irq(irq);
 
        BUG_ON(irq == -1);
@@ -354,7 +354,7 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
  */
 void notify_remote_via_irq(int irq)
 {
-       int evtchn = evtchn_from_irq(irq);
+       evtchn_port_t evtchn = evtchn_from_irq(irq);
 
        if (VALID_EVTCHN(evtchn))
                notify_remote_via_evtchn(evtchn);
@@ -445,7 +445,7 @@ static void xen_free_irq(unsigned irq)
        irq_free_desc(irq);
 }
 
-static void xen_evtchn_close(unsigned int port)
+static void xen_evtchn_close(evtchn_port_t port)
 {
        struct evtchn_close close;
 
@@ -472,7 +472,7 @@ static void pirq_query_unmask(int irq)
 
 static void eoi_pirq(struct irq_data *data)
 {
-       int evtchn = evtchn_from_irq(data->irq);
+       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
        struct physdev_eoi eoi = { .irq = pirq_from_irq(data->irq) };
        int rc = 0;
 
@@ -508,7 +508,7 @@ static unsigned int __startup_pirq(unsigned int irq)
 {
        struct evtchn_bind_pirq bind_pirq;
        struct irq_info *info = info_for_irq(irq);
-       int evtchn = evtchn_from_irq(irq);
+       evtchn_port_t evtchn = evtchn_from_irq(irq);
        int rc;
 
        BUG_ON(info->type != IRQT_PIRQ);
@@ -561,7 +561,7 @@ static void shutdown_pirq(struct irq_data *data)
 {
        unsigned int irq = data->irq;
        struct irq_info *info = info_for_irq(irq);
-       unsigned evtchn = evtchn_from_irq(irq);
+       evtchn_port_t evtchn = evtchn_from_irq(irq);
 
        BUG_ON(info->type != IRQT_PIRQ);
 
@@ -601,7 +601,7 @@ EXPORT_SYMBOL_GPL(xen_irq_from_gsi);
 
 static void __unbind_from_irq(unsigned int irq)
 {
-       int evtchn = evtchn_from_irq(irq);
+       evtchn_port_t evtchn = evtchn_from_irq(irq);
        struct irq_info *info = irq_get_handler_data(irq);
 
        if (info->refcnt > 0) {
@@ -827,7 +827,7 @@ int xen_pirq_from_irq(unsigned irq)
 }
 EXPORT_SYMBOL_GPL(xen_pirq_from_irq);
 
-int bind_evtchn_to_irq(unsigned int evtchn)
+int bind_evtchn_to_irq(evtchn_port_t evtchn)
 {
        int irq;
        int ret;
@@ -870,8 +870,8 @@ EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
 static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
 {
        struct evtchn_bind_ipi bind_ipi;
-       int evtchn, irq;
-       int ret;
+       evtchn_port_t evtchn;
+       int ret, irq;
 
        mutex_lock(&irq_mapping_update_lock);
 
@@ -909,7 +909,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
 }
 
 int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
-                                  unsigned int remote_port)
+                                  evtchn_port_t remote_port)
 {
        struct evtchn_bind_interdomain bind_interdomain;
        int err;
@@ -924,10 +924,11 @@ int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
 }
 EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irq);
 
-static int find_virq(unsigned int virq, unsigned int cpu)
+static int find_virq(unsigned int virq, unsigned int cpu, evtchn_port_t *evtchn)
 {
        struct evtchn_status status;
-       int port, rc = -ENOENT;
+       evtchn_port_t port;
+       int rc = -ENOENT;
 
        memset(&status, 0, sizeof(status));
        for (port = 0; port < xen_evtchn_max_channels(); port++) {
@@ -939,7 +940,7 @@ static int find_virq(unsigned int virq, unsigned int cpu)
                if (status.status != EVTCHNSTAT_virq)
                        continue;
                if (status.u.virq == virq && status.vcpu == xen_vcpu_nr(cpu)) {
-                       rc = port;
+                       *evtchn = port;
                        break;
                }
        }
@@ -962,7 +963,8 @@ EXPORT_SYMBOL_GPL(xen_evtchn_nr_channels);
 int bind_virq_to_irq(unsigned int virq, unsigned int cpu, bool percpu)
 {
        struct evtchn_bind_virq bind_virq;
-       int evtchn, irq, ret;
+       evtchn_port_t evtchn = 0;
+       int irq, ret;
 
        mutex_lock(&irq_mapping_update_lock);
 
@@ -988,9 +990,8 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu, bool percpu)
                        evtchn = bind_virq.port;
                else {
                        if (ret == -EEXIST)
-                               ret = find_virq(virq, cpu);
+                               ret = find_virq(virq, cpu, &evtchn);
                        BUG_ON(ret < 0);
-                       evtchn = ret;
                }
 
                ret = xen_irq_info_virq_setup(cpu, irq, evtchn, virq);
@@ -1019,7 +1020,7 @@ static void unbind_from_irq(unsigned int irq)
        mutex_unlock(&irq_mapping_update_lock);
 }
 
-int bind_evtchn_to_irqhandler(unsigned int evtchn,
+int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
                              irq_handler_t handler,
                              unsigned long irqflags,
                              const char *devname, void *dev_id)
@@ -1040,7 +1041,7 @@ int bind_evtchn_to_irqhandler(unsigned int evtchn,
 EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
 
 int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
-                                         unsigned int remote_port,
+                                         evtchn_port_t remote_port,
                                          irq_handler_t handler,
                                          unsigned long irqflags,
                                          const char *devname,
@@ -1132,7 +1133,7 @@ int xen_set_irq_priority(unsigned irq, unsigned priority)
 }
 EXPORT_SYMBOL_GPL(xen_set_irq_priority);
 
-int evtchn_make_refcounted(unsigned int evtchn)
+int evtchn_make_refcounted(evtchn_port_t evtchn)
 {
        int irq = get_evtchn_to_irq(evtchn);
        struct irq_info *info;
@@ -1153,7 +1154,7 @@ int evtchn_make_refcounted(unsigned int evtchn)
 }
 EXPORT_SYMBOL_GPL(evtchn_make_refcounted);
 
-int evtchn_get(unsigned int evtchn)
+int evtchn_get(evtchn_port_t evtchn)
 {
        int irq;
        struct irq_info *info;
@@ -1186,7 +1187,7 @@ int evtchn_get(unsigned int evtchn)
 }
 EXPORT_SYMBOL_GPL(evtchn_get);
 
-void evtchn_put(unsigned int evtchn)
+void evtchn_put(evtchn_port_t evtchn)
 {
        int irq = get_evtchn_to_irq(evtchn);
        if (WARN_ON(irq == -1))
@@ -1252,7 +1253,7 @@ void xen_hvm_evtchn_do_upcall(void)
 EXPORT_SYMBOL_GPL(xen_hvm_evtchn_do_upcall);
 
 /* Rebind a new event channel to an existing irq. */
-void rebind_evtchn_irq(int evtchn, int irq)
+void rebind_evtchn_irq(evtchn_port_t evtchn, int irq)
 {
        struct irq_info *info = info_for_irq(irq);
 
@@ -1284,7 +1285,7 @@ void rebind_evtchn_irq(int evtchn, int irq)
 }
 
 /* Rebind an evtchn so that it gets delivered to a specific cpu */
-static int xen_rebind_evtchn_to_cpu(int evtchn, unsigned int tcpu)
+static int xen_rebind_evtchn_to_cpu(evtchn_port_t evtchn, unsigned int tcpu)
 {
        struct evtchn_bind_vcpu bind_vcpu;
        int masked;
@@ -1342,7 +1343,7 @@ EXPORT_SYMBOL_GPL(xen_set_affinity_evtchn);
 
 static void enable_dynirq(struct irq_data *data)
 {
-       int evtchn = evtchn_from_irq(data->irq);
+       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
 
        if (VALID_EVTCHN(evtchn))
                unmask_evtchn(evtchn);
@@ -1350,7 +1351,7 @@ static void enable_dynirq(struct irq_data *data)
 
 static void disable_dynirq(struct irq_data *data)
 {
-       int evtchn = evtchn_from_irq(data->irq);
+       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
 
        if (VALID_EVTCHN(evtchn))
                mask_evtchn(evtchn);
@@ -1358,7 +1359,7 @@ static void disable_dynirq(struct irq_data *data)
 
 static void ack_dynirq(struct irq_data *data)
 {
-       int evtchn = evtchn_from_irq(data->irq);
+       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
 
        if (!VALID_EVTCHN(evtchn))
                return;
@@ -1385,7 +1386,7 @@ static void mask_ack_dynirq(struct irq_data *data)
 
 static int retrigger_dynirq(struct irq_data *data)
 {
-       unsigned int evtchn = evtchn_from_irq(data->irq);
+       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
        int masked;
 
        if (!VALID_EVTCHN(evtchn))
@@ -1440,7 +1441,8 @@ static void restore_pirqs(void)
 static void restore_cpu_virqs(unsigned int cpu)
 {
        struct evtchn_bind_virq bind_virq;
-       int virq, irq, evtchn;
+       evtchn_port_t evtchn;
+       int virq, irq;
 
        for (virq = 0; virq < NR_VIRQS; virq++) {
                if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1)
@@ -1465,7 +1467,8 @@ static void restore_cpu_virqs(unsigned int cpu)
 static void restore_cpu_ipis(unsigned int cpu)
 {
        struct evtchn_bind_ipi bind_ipi;
-       int ipi, irq, evtchn;
+       evtchn_port_t evtchn;
+       int ipi, irq;
 
        for (ipi = 0; ipi < XEN_NR_IPIS; ipi++) {
                if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1)
@@ -1489,7 +1492,7 @@ static void restore_cpu_ipis(unsigned int cpu)
 /* Clear an irq's pending state, in preparation for polling on it */
 void xen_clear_irq_pending(int irq)
 {
-       int evtchn = evtchn_from_irq(irq);
+       evtchn_port_t evtchn = evtchn_from_irq(irq);
 
        if (VALID_EVTCHN(evtchn))
                clear_evtchn(evtchn);
@@ -1497,7 +1500,7 @@ void xen_clear_irq_pending(int irq)
 EXPORT_SYMBOL(xen_clear_irq_pending);
 void xen_set_irq_pending(int irq)
 {
-       int evtchn = evtchn_from_irq(irq);
+       evtchn_port_t evtchn = evtchn_from_irq(irq);
 
        if (VALID_EVTCHN(evtchn))
                set_evtchn(evtchn);
@@ -1505,7 +1508,7 @@ void xen_set_irq_pending(int irq)
 
 bool xen_test_irq_pending(int irq)
 {
-       int evtchn = evtchn_from_irq(irq);
+       evtchn_port_t evtchn = evtchn_from_irq(irq);
        bool ret = false;
 
        if (VALID_EVTCHN(evtchn))
@@ -1667,7 +1670,7 @@ module_param(fifo_events, bool, 0);
 void __init xen_init_IRQ(void)
 {
        int ret = -EINVAL;
-       unsigned int evtchn;
+       evtchn_port_t evtchn;
 
        if (fifo_events)
                ret = xen_evtchn_fifo_init();
index 76b318e..c60ee04 100644 (file)
@@ -82,7 +82,7 @@ static unsigned event_array_pages __read_mostly;
 
 #endif
 
-static inline event_word_t *event_word_from_port(unsigned port)
+static inline event_word_t *event_word_from_port(evtchn_port_t port)
 {
        unsigned i = port / EVENT_WORDS_PER_PAGE;
 
@@ -140,7 +140,7 @@ static void init_array_page(event_word_t *array_page)
 
 static int evtchn_fifo_setup(struct irq_info *info)
 {
-       unsigned port = info->evtchn;
+       evtchn_port_t port = info->evtchn;
        unsigned new_array_pages;
        int ret;
 
@@ -191,37 +191,37 @@ static void evtchn_fifo_bind_to_cpu(struct irq_info *info, unsigned cpu)
        /* no-op */
 }
 
-static void evtchn_fifo_clear_pending(unsigned port)
+static void evtchn_fifo_clear_pending(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
        sync_clear_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word));
 }
 
-static void evtchn_fifo_set_pending(unsigned port)
+static void evtchn_fifo_set_pending(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
        sync_set_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word));
 }
 
-static bool evtchn_fifo_is_pending(unsigned port)
+static bool evtchn_fifo_is_pending(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
        return sync_test_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word));
 }
 
-static bool evtchn_fifo_test_and_set_mask(unsigned port)
+static bool evtchn_fifo_test_and_set_mask(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
        return sync_test_and_set_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word));
 }
 
-static void evtchn_fifo_mask(unsigned port)
+static void evtchn_fifo_mask(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
        sync_set_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word));
 }
 
-static bool evtchn_fifo_is_masked(unsigned port)
+static bool evtchn_fifo_is_masked(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
        return sync_test_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word));
@@ -242,7 +242,7 @@ static void clear_masked(volatile event_word_t *word)
        } while (w != old);
 }
 
-static void evtchn_fifo_unmask(unsigned port)
+static void evtchn_fifo_unmask(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
 
@@ -270,7 +270,7 @@ static uint32_t clear_linked(volatile event_word_t *word)
        return w & EVTCHN_FIFO_LINK_MASK;
 }
 
-static void handle_irq_for_port(unsigned port)
+static void handle_irq_for_port(evtchn_port_t port)
 {
        int irq;
 
@@ -286,7 +286,7 @@ static void consume_one_event(unsigned cpu,
 {
        struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu);
        uint32_t head;
-       unsigned port;
+       evtchn_port_t port;
        event_word_t *word;
 
        head = q->head[priority];
index 82938cf..10684fe 100644 (file)
@@ -33,7 +33,7 @@ struct irq_info {
        int refcnt;
        enum xen_irq_type type; /* type */
        unsigned irq;
-       unsigned int evtchn;    /* event channel */
+       evtchn_port_t evtchn;   /* event channel */
        unsigned short cpu;     /* cpu bound */
 
        union {
@@ -60,12 +60,12 @@ struct evtchn_ops {
        int (*setup)(struct irq_info *info);
        void (*bind_to_cpu)(struct irq_info *info, unsigned cpu);
 
-       void (*clear_pending)(unsigned port);
-       void (*set_pending)(unsigned port);
-       bool (*is_pending)(unsigned port);
-       bool (*test_and_set_mask)(unsigned port);
-       void (*mask)(unsigned port);
-       void (*unmask)(unsigned port);
+       void (*clear_pending)(evtchn_port_t port);
+       void (*set_pending)(evtchn_port_t port);
+       bool (*is_pending)(evtchn_port_t port);
+       bool (*test_and_set_mask)(evtchn_port_t port);
+       void (*mask)(evtchn_port_t port);
+       void (*unmask)(evtchn_port_t port);
 
        void (*handle_events)(unsigned cpu);
        void (*resume)(void);
@@ -74,11 +74,11 @@ struct evtchn_ops {
 extern const struct evtchn_ops *evtchn_ops;
 
 extern int **evtchn_to_irq;
-int get_evtchn_to_irq(unsigned int evtchn);
+int get_evtchn_to_irq(evtchn_port_t evtchn);
 
 struct irq_info *info_for_irq(unsigned irq);
 unsigned cpu_from_irq(unsigned irq);
-unsigned cpu_from_evtchn(unsigned int evtchn);
+unsigned int cpu_from_evtchn(evtchn_port_t evtchn);
 
 static inline unsigned xen_evtchn_max_channels(void)
 {
@@ -102,32 +102,32 @@ static inline void xen_evtchn_port_bind_to_cpu(struct irq_info *info,
        evtchn_ops->bind_to_cpu(info, cpu);
 }
 
-static inline void clear_evtchn(unsigned port)
+static inline void clear_evtchn(evtchn_port_t port)
 {
        evtchn_ops->clear_pending(port);
 }
 
-static inline void set_evtchn(unsigned port)
+static inline void set_evtchn(evtchn_port_t port)
 {
        evtchn_ops->set_pending(port);
 }
 
-static inline bool test_evtchn(unsigned port)
+static inline bool test_evtchn(evtchn_port_t port)
 {
        return evtchn_ops->is_pending(port);
 }
 
-static inline bool test_and_set_mask(unsigned port)
+static inline bool test_and_set_mask(evtchn_port_t port)
 {
        return evtchn_ops->test_and_set_mask(port);
 }
 
-static inline void mask_evtchn(unsigned port)
+static inline void mask_evtchn(evtchn_port_t port)
 {
        return evtchn_ops->mask(port);
 }
 
-static inline void unmask_evtchn(unsigned port)
+static inline void unmask_evtchn(evtchn_port_t port)
 {
        return evtchn_ops->unmask(port);
 }
index 052b55a..6e0b1dd 100644 (file)
@@ -83,7 +83,7 @@ struct per_user_data {
 struct user_evtchn {
        struct rb_node node;
        struct per_user_data *user;
-       unsigned port;
+       evtchn_port_t port;
        bool enabled;
 };
 
@@ -138,7 +138,8 @@ static void del_evtchn(struct per_user_data *u, struct user_evtchn *evtchn)
        kfree(evtchn);
 }
 
-static struct user_evtchn *find_evtchn(struct per_user_data *u, unsigned port)
+static struct user_evtchn *find_evtchn(struct per_user_data *u,
+                                      evtchn_port_t port)
 {
        struct rb_node *node = u->evtchns.rb_node;
 
@@ -163,7 +164,7 @@ static irqreturn_t evtchn_interrupt(int irq, void *data)
        struct per_user_data *u = evtchn->user;
 
        WARN(!evtchn->enabled,
-            "Interrupt for port %d, but apparently not enabled; per-user %p\n",
+            "Interrupt for port %u, but apparently not enabled; per-user %p\n",
             evtchn->port, u);
 
        disable_irq_nosync(irq);
@@ -286,7 +287,7 @@ static ssize_t evtchn_write(struct file *file, const char __user *buf,
        mutex_lock(&u->bind_mutex);
 
        for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) {
-               unsigned port = kbuf[i];
+               evtchn_port_t port = kbuf[i];
                struct user_evtchn *evtchn;
 
                evtchn = find_evtchn(u, port);
@@ -361,7 +362,7 @@ static int evtchn_resize_ring(struct per_user_data *u)
        return 0;
 }
 
-static int evtchn_bind_to_user(struct per_user_data *u, int port)
+static int evtchn_bind_to_user(struct per_user_data *u, evtchn_port_t port)
 {
        struct user_evtchn *evtchn;
        struct evtchn_close close;
@@ -423,7 +424,7 @@ static void evtchn_unbind_from_user(struct per_user_data *u,
 
 static DEFINE_PER_CPU(int, bind_last_selected_cpu);
 
-static void evtchn_bind_interdom_next_vcpu(int evtchn)
+static void evtchn_bind_interdom_next_vcpu(evtchn_port_t evtchn)
 {
        unsigned int selected_cpu, irq;
        struct irq_desc *desc;
index 9a3960e..20d7d05 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/mman.h>
 #include <linux/mmu_notifier.h>
 #include <linux/types.h>
+#include <xen/interface/event_channel.h>
 
 struct gntdev_dmabuf_priv;
 
@@ -38,7 +39,7 @@ struct gntdev_unmap_notify {
        int flags;
        /* Address relative to the start of the gntdev_grant_map. */
        int addr;
-       int event;
+       evtchn_port_t event;
 };
 
 struct gntdev_grant_map {
index 0258415..50651e5 100644 (file)
@@ -652,7 +652,7 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
        struct gntdev_grant_map *map;
        int rc;
        int out_flags;
-       unsigned int out_event;
+       evtchn_port_t out_event;
 
        if (copy_from_user(&op, u, sizeof(op)))
                return -EFAULT;
index c57c71b..cf4ce3e 100644 (file)
@@ -300,7 +300,7 @@ static struct sock_mapping *pvcalls_new_active_socket(
                struct pvcalls_fedata *fedata,
                uint64_t id,
                grant_ref_t ref,
-               uint32_t evtchn,
+               evtchn_port_t evtchn,
                struct socket *sock)
 {
        int ret;
@@ -905,7 +905,8 @@ static irqreturn_t pvcalls_back_conn_event(int irq, void *sock_map)
 
 static int backend_connect(struct xenbus_device *dev)
 {
-       int err, evtchn;
+       int err;
+       evtchn_port_t evtchn;
        grant_ref_t ring_ref;
        struct pvcalls_fedata *fedata = NULL;
 
index 57592a6..b43b559 100644 (file)
@@ -368,12 +368,12 @@ out:
        return -ENOMEM;
 }
 
-static int create_active(struct sock_mapping *map, int *evtchn)
+static int create_active(struct sock_mapping *map, evtchn_port_t *evtchn)
 {
        void *bytes;
        int ret = -ENOMEM, irq = -1, i;
 
-       *evtchn = -1;
+       *evtchn = 0;
        init_waitqueue_head(&map->active.inflight_conn_req);
 
        bytes = map->active.data.in;
@@ -404,7 +404,7 @@ static int create_active(struct sock_mapping *map, int *evtchn)
        return 0;
 
 out_error:
-       if (*evtchn >= 0)
+       if (*evtchn > 0)
                xenbus_free_evtchn(pvcalls_front_dev, *evtchn);
        return ret;
 }
@@ -415,7 +415,8 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
        struct pvcalls_bedata *bedata;
        struct sock_mapping *map = NULL;
        struct xen_pvcalls_request *req;
-       int notify, req_id, ret, evtchn;
+       int notify, req_id, ret;
+       evtchn_port_t evtchn;
 
        if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM)
                return -EOPNOTSUPP;
@@ -765,7 +766,8 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
        struct sock_mapping *map;
        struct sock_mapping *map2 = NULL;
        struct xen_pvcalls_request *req;
-       int notify, req_id, ret, evtchn, nonblock;
+       int notify, req_id, ret, nonblock;
+       evtchn_port_t evtchn;
 
        map = pvcalls_enter_sock(sock);
        if (IS_ERR(map))
@@ -1125,7 +1127,8 @@ static int pvcalls_front_remove(struct xenbus_device *dev)
 static int pvcalls_front_probe(struct xenbus_device *dev,
                          const struct xenbus_device_id *id)
 {
-       int ret = -ENOMEM, evtchn, i;
+       int ret = -ENOMEM, i;
+       evtchn_port_t evtchn;
        unsigned int max_page_order, function_calls, len;
        char *versions;
        grant_ref_t gref_head = 0;
index 833b2d2..f211558 100644 (file)
@@ -105,13 +105,13 @@ static void free_pdev(struct xen_pcibk_device *pdev)
 }
 
 static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref,
-                            int remote_evtchn)
+                            evtchn_port_t remote_evtchn)
 {
        int err = 0;
        void *vaddr;
 
        dev_dbg(&pdev->xdev->dev,
-               "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
+               "Attaching to frontend resources - gnt_ref=%d evtchn=%u\n",
                gnt_ref, remote_evtchn);
 
        err = xenbus_map_ring_valloc(pdev->xdev, &gnt_ref, 1, &vaddr);
@@ -142,7 +142,8 @@ out:
 static int xen_pcibk_attach(struct xen_pcibk_device *pdev)
 {
        int err = 0;
-       int gnt_ref, remote_evtchn;
+       int gnt_ref;
+       evtchn_port_t remote_evtchn;
        char *magic = NULL;
 
 
index ba0942e..75c0a2e 100644 (file)
@@ -854,7 +854,8 @@ unmap_page:
 static int scsiback_map(struct vscsibk_info *info)
 {
        struct xenbus_device *dev = info->dev;
-       unsigned int ring_ref, evtchn;
+       unsigned int ring_ref;
+       evtchn_port_t evtchn;
        int err;
 
        err = xenbus_gather(XBT_NIL, dev->otherend,
index 31eb822..3858432 100644 (file)
@@ -391,7 +391,7 @@ EXPORT_SYMBOL_GPL(xenbus_grant_ring);
  * error, the device will switch to XenbusStateClosing, and the error will be
  * saved in the store.
  */
-int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
+int xenbus_alloc_evtchn(struct xenbus_device *dev, evtchn_port_t *port)
 {
        struct evtchn_alloc_unbound alloc_unbound;
        int err;
@@ -414,7 +414,7 @@ EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn);
 /**
  * Free an existing event channel. Returns 0 on success or -errno on error.
  */
-int xenbus_free_evtchn(struct xenbus_device *dev, int port)
+int xenbus_free_evtchn(struct xenbus_device *dev, evtchn_port_t port)
 {
        struct evtchn_close close;
        int err;
@@ -423,7 +423,7 @@ int xenbus_free_evtchn(struct xenbus_device *dev, int port)
 
        err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
        if (err)
-               xenbus_dev_error(dev, err, "freeing event channel %d", port);
+               xenbus_dev_error(dev, err, "freeing event channel %u", port);
 
        return err;
 }
index 5c794f4..d1e1caa 100644 (file)
@@ -1032,7 +1032,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
        struct dentry *parent;
        struct inode *inode;
        struct key *key;
-       afs_dataversion_t dir_version;
+       afs_dataversion_t dir_version, invalid_before;
        long de_version;
        int ret;
 
@@ -1084,8 +1084,8 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
        if (de_version == (long)dir_version)
                goto out_valid_noupdate;
 
-       dir_version = dir->invalid_before;
-       if (de_version - (long)dir_version >= 0)
+       invalid_before = dir->invalid_before;
+       if (de_version - (long)invalid_before >= 0)
                goto out_valid;
 
        _debug("dir modified");
@@ -1275,6 +1275,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        struct afs_fs_cursor fc;
        struct afs_vnode *dvnode = AFS_FS_I(dir);
        struct key *key;
+       afs_dataversion_t data_version;
        int ret;
 
        mode |= S_IFDIR;
@@ -1295,7 +1296,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 
        ret = -ERESTARTSYS;
        if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
-               afs_dataversion_t data_version = dvnode->status.data_version + 1;
+               data_version = dvnode->status.data_version + 1;
 
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(dvnode);
@@ -1316,10 +1317,14 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
                goto error_key;
        }
 
-       if (ret == 0 &&
-           test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
-               afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid,
-                                afs_edit_dir_for_create);
+       if (ret == 0) {
+               down_write(&dvnode->validate_lock);
+               if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
+                   dvnode->status.data_version == data_version)
+                       afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid,
+                                        afs_edit_dir_for_create);
+               up_write(&dvnode->validate_lock);
+       }
 
        key_put(key);
        kfree(scb);
@@ -1360,6 +1365,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
        struct afs_fs_cursor fc;
        struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL;
        struct key *key;
+       afs_dataversion_t data_version;
        int ret;
 
        _enter("{%llx:%llu},{%pd}",
@@ -1391,7 +1397,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
 
        ret = -ERESTARTSYS;
        if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
-               afs_dataversion_t data_version = dvnode->status.data_version + 1;
+               data_version = dvnode->status.data_version + 1;
 
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(dvnode);
@@ -1404,9 +1410,12 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
                ret = afs_end_vnode_operation(&fc);
                if (ret == 0) {
                        afs_dir_remove_subdir(dentry);
-                       if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
+                       down_write(&dvnode->validate_lock);
+                       if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
+                           dvnode->status.data_version == data_version)
                                afs_edit_dir_remove(dvnode, &dentry->d_name,
                                                    afs_edit_dir_for_rmdir);
+                       up_write(&dvnode->validate_lock);
                }
        }
 
@@ -1544,10 +1553,15 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
                ret = afs_end_vnode_operation(&fc);
                if (ret == 0 && !(scb[1].have_status || scb[1].have_error))
                        ret = afs_dir_remove_link(dvnode, dentry, key);
-               if (ret == 0 &&
-                   test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
-                       afs_edit_dir_remove(dvnode, &dentry->d_name,
-                                           afs_edit_dir_for_unlink);
+
+               if (ret == 0) {
+                       down_write(&dvnode->validate_lock);
+                       if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
+                           dvnode->status.data_version == data_version)
+                               afs_edit_dir_remove(dvnode, &dentry->d_name,
+                                                   afs_edit_dir_for_unlink);
+                       up_write(&dvnode->validate_lock);
+               }
        }
 
        if (need_rehash && ret < 0 && ret != -ENOENT)
@@ -1573,6 +1587,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        struct afs_status_cb *scb;
        struct afs_vnode *dvnode = AFS_FS_I(dir);
        struct key *key;
+       afs_dataversion_t data_version;
        int ret;
 
        mode |= S_IFREG;
@@ -1597,7 +1612,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 
        ret = -ERESTARTSYS;
        if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
-               afs_dataversion_t data_version = dvnode->status.data_version + 1;
+               data_version = dvnode->status.data_version + 1;
 
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(dvnode);
@@ -1618,9 +1633,12 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
                goto error_key;
        }
 
-       if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
+       down_write(&dvnode->validate_lock);
+       if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
+           dvnode->status.data_version == data_version)
                afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid,
                                 afs_edit_dir_for_create);
+       up_write(&dvnode->validate_lock);
 
        kfree(scb);
        key_put(key);
@@ -1648,6 +1666,7 @@ static int afs_link(struct dentry *from, struct inode *dir,
        struct afs_vnode *dvnode = AFS_FS_I(dir);
        struct afs_vnode *vnode = AFS_FS_I(d_inode(from));
        struct key *key;
+       afs_dataversion_t data_version;
        int ret;
 
        _enter("{%llx:%llu},{%llx:%llu},{%pd}",
@@ -1672,7 +1691,7 @@ static int afs_link(struct dentry *from, struct inode *dir,
 
        ret = -ERESTARTSYS;
        if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
-               afs_dataversion_t data_version = dvnode->status.data_version + 1;
+               data_version = dvnode->status.data_version + 1;
 
                if (mutex_lock_interruptible_nested(&vnode->io_lock, 1) < 0) {
                        afs_end_vnode_operation(&fc);
@@ -1702,9 +1721,12 @@ static int afs_link(struct dentry *from, struct inode *dir,
                goto error_key;
        }
 
-       if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
+       down_write(&dvnode->validate_lock);
+       if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
+           dvnode->status.data_version == data_version)
                afs_edit_dir_add(dvnode, &dentry->d_name, &vnode->fid,
                                 afs_edit_dir_for_link);
+       up_write(&dvnode->validate_lock);
 
        key_put(key);
        kfree(scb);
@@ -1732,6 +1754,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
        struct afs_status_cb *scb;
        struct afs_vnode *dvnode = AFS_FS_I(dir);
        struct key *key;
+       afs_dataversion_t data_version;
        int ret;
 
        _enter("{%llx:%llu},{%pd},%s",
@@ -1759,7 +1782,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
 
        ret = -ERESTARTSYS;
        if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
-               afs_dataversion_t data_version = dvnode->status.data_version + 1;
+               data_version = dvnode->status.data_version + 1;
 
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(dvnode);
@@ -1780,9 +1803,12 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
                goto error_key;
        }
 
-       if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
+       down_write(&dvnode->validate_lock);
+       if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
+           dvnode->status.data_version == data_version)
                afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid,
                                 afs_edit_dir_for_symlink);
+       up_write(&dvnode->validate_lock);
 
        key_put(key);
        kfree(scb);
@@ -1812,6 +1838,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct dentry *tmp = NULL, *rehash = NULL;
        struct inode *new_inode;
        struct key *key;
+       afs_dataversion_t orig_data_version;
+       afs_dataversion_t new_data_version;
        bool new_negative = d_is_negative(new_dentry);
        int ret;
 
@@ -1890,10 +1918,6 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        ret = -ERESTARTSYS;
        if (afs_begin_vnode_operation(&fc, orig_dvnode, key, true)) {
-               afs_dataversion_t orig_data_version;
-               afs_dataversion_t new_data_version;
-               struct afs_status_cb *new_scb = &scb[1];
-
                orig_data_version = orig_dvnode->status.data_version + 1;
 
                if (orig_dvnode != new_dvnode) {
@@ -1904,7 +1928,6 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        new_data_version = new_dvnode->status.data_version + 1;
                } else {
                        new_data_version = orig_data_version;
-                       new_scb = &scb[0];
                }
 
                while (afs_select_fileserver(&fc)) {
@@ -1912,7 +1935,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        fc.cb_break_2 = afs_calc_vnode_cb_break(new_dvnode);
                        afs_fs_rename(&fc, old_dentry->d_name.name,
                                      new_dvnode, new_dentry->d_name.name,
-                                     &scb[0], new_scb);
+                                     &scb[0], &scb[1]);
                }
 
                afs_vnode_commit_status(&fc, orig_dvnode, fc.cb_break,
@@ -1930,18 +1953,25 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (ret == 0) {
                if (rehash)
                        d_rehash(rehash);
-               if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags))
-                   afs_edit_dir_remove(orig_dvnode, &old_dentry->d_name,
-                                       afs_edit_dir_for_rename_0);
+               down_write(&orig_dvnode->validate_lock);
+               if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags) &&
+                   orig_dvnode->status.data_version == orig_data_version)
+                       afs_edit_dir_remove(orig_dvnode, &old_dentry->d_name,
+                                           afs_edit_dir_for_rename_0);
+               if (orig_dvnode != new_dvnode) {
+                       up_write(&orig_dvnode->validate_lock);
 
-               if (!new_negative &&
-                   test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags))
-                       afs_edit_dir_remove(new_dvnode, &new_dentry->d_name,
-                                           afs_edit_dir_for_rename_1);
+                       down_write(&new_dvnode->validate_lock);
+               }
+               if (test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags) &&
+                   orig_dvnode->status.data_version == new_data_version) {
+                       if (!new_negative)
+                               afs_edit_dir_remove(new_dvnode, &new_dentry->d_name,
+                                                   afs_edit_dir_for_rename_1);
 
-               if (test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags))
                        afs_edit_dir_add(new_dvnode, &new_dentry->d_name,
                                         &vnode->fid, afs_edit_dir_for_rename_2);
+               }
 
                new_inode = d_inode(new_dentry);
                if (new_inode) {
@@ -1957,14 +1987,10 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
                 * Note that if we ever implement RENAME_EXCHANGE, we'll have
                 * to update both dentries with opposing dir versions.
                 */
-               if (new_dvnode != orig_dvnode) {
-                       afs_update_dentry_version(&fc, old_dentry, &scb[1]);
-                       afs_update_dentry_version(&fc, new_dentry, &scb[1]);
-               } else {
-                       afs_update_dentry_version(&fc, old_dentry, &scb[0]);
-                       afs_update_dentry_version(&fc, new_dentry, &scb[0]);
-               }
+               afs_update_dentry_version(&fc, old_dentry, &scb[1]);
+               afs_update_dentry_version(&fc, new_dentry, &scb[1]);
                d_move(old_dentry, new_dentry);
+               up_write(&new_dvnode->validate_lock);
                goto error_tmp;
        }
 
index 361088a..d94e2b7 100644 (file)
@@ -21,6 +21,7 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode
 {
        struct afs_fs_cursor fc;
        struct afs_status_cb *scb;
+       afs_dataversion_t dir_data_version;
        int ret = -ERESTARTSYS;
 
        _enter("%pd,%pd", old, new);
@@ -31,7 +32,7 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode
 
        trace_afs_silly_rename(vnode, false);
        if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
-               afs_dataversion_t dir_data_version = dvnode->status.data_version + 1;
+               dir_data_version = dvnode->status.data_version + 1;
 
                while (afs_select_fileserver(&fc)) {
                        fc.cb_break = afs_calc_vnode_cb_break(dvnode);
@@ -54,12 +55,15 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode
                        dvnode->silly_key = key_get(key);
                }
 
-               if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
+               down_write(&dvnode->validate_lock);
+               if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
+                   dvnode->status.data_version == dir_data_version) {
                        afs_edit_dir_remove(dvnode, &old->d_name,
                                            afs_edit_dir_for_silly_0);
-               if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
                        afs_edit_dir_add(dvnode, &new->d_name,
                                         &vnode->fid, afs_edit_dir_for_silly_1);
+               }
+               up_write(&dvnode->validate_lock);
        }
 
        kfree(scb);
@@ -181,10 +185,14 @@ static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode
                                clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
                        }
                }
-               if (ret == 0 &&
-                   test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
-                       afs_edit_dir_remove(dvnode, &dentry->d_name,
-                                           afs_edit_dir_for_unlink);
+               if (ret == 0) {
+                       down_write(&dvnode->validate_lock);
+                       if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
+                           dvnode->status.data_version == dir_data_version)
+                               afs_edit_dir_remove(dvnode, &dentry->d_name,
+                                                   afs_edit_dir_for_unlink);
+                       up_write(&dvnode->validate_lock);
+               }
        }
 
        kfree(scb);
index 1f9c5d8..68fc466 100644 (file)
@@ -65,6 +65,7 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
        bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus);
        u64 data_version, size;
        u32 type, abort_code;
+       int ret;
 
        abort_code = ntohl(xdr->abort_code);
 
@@ -78,7 +79,7 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
                         */
                        status->abort_code = abort_code;
                        scb->have_error = true;
-                       return 0;
+                       goto good;
                }
 
                pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
@@ -87,7 +88,8 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
 
        if (abort_code != 0 && inline_error) {
                status->abort_code = abort_code;
-               return 0;
+               scb->have_error = true;
+               goto good;
        }
 
        type = ntohl(xdr->type);
@@ -123,13 +125,16 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
        data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
        status->data_version = data_version;
        scb->have_status = true;
-
+good:
+       ret = 0;
+advance:
        *_bp = (const void *)*_bp + sizeof(*xdr);
-       return 0;
+       return ret;
 
 bad:
        xdr_dump_bad(*_bp);
-       return afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status);
+       ret = afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status);
+       goto advance;
 }
 
 static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
@@ -981,16 +986,16 @@ static int afs_deliver_fs_rename(struct afs_call *call)
        if (ret < 0)
                return ret;
 
-       /* unmarshall the reply once we've received all of it */
+       /* If the two dirs are the same, we have two copies of the same status
+        * report, so we just decode it twice.
+        */
        bp = call->buffer;
        ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
        if (ret < 0)
                return ret;
-       if (call->out_dir_scb != call->out_scb) {
-               ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
-               if (ret < 0)
-                       return ret;
-       }
+       ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
+       if (ret < 0)
+               return ret;
        xdr_decode_AFSVolSync(&bp, call->out_volsync);
 
        _leave(" = 0 [done]");
index a26126a..b5b45c5 100644 (file)
@@ -165,15 +165,15 @@ static void xdr_dump_bad(const __be32 *bp)
        int i;
 
        pr_notice("YFS XDR: Bad status record\n");
-       for (i = 0; i < 5 * 4 * 4; i += 16) {
+       for (i = 0; i < 6 * 4 * 4; i += 16) {
                memcpy(x, bp, 16);
                bp += 4;
                pr_notice("%03x: %08x %08x %08x %08x\n",
                          i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3]));
        }
 
-       memcpy(x, bp, 4);
-       pr_notice("0x50: %08x\n", ntohl(x[0]));
+       memcpy(x, bp, 8);
+       pr_notice("0x60: %08x %08x\n", ntohl(x[0]), ntohl(x[1]));
 }
 
 /*
@@ -186,13 +186,14 @@ static int xdr_decode_YFSFetchStatus(const __be32 **_bp,
        const struct yfs_xdr_YFSFetchStatus *xdr = (const void *)*_bp;
        struct afs_file_status *status = &scb->status;
        u32 type;
+       int ret;
 
        status->abort_code = ntohl(xdr->abort_code);
        if (status->abort_code != 0) {
                if (status->abort_code == VNOVNODE)
                        status->nlink = 0;
                scb->have_error = true;
-               return 0;
+               goto good;
        }
 
        type = ntohl(xdr->type);
@@ -220,13 +221,16 @@ static int xdr_decode_YFSFetchStatus(const __be32 **_bp,
        status->size            = xdr_to_u64(xdr->size);
        status->data_version    = xdr_to_u64(xdr->data_version);
        scb->have_status        = true;
-
+good:
+       ret = 0;
+advance:
        *_bp += xdr_size(xdr);
-       return 0;
+       return ret;
 
 bad:
        xdr_dump_bad(*_bp);
-       return afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status);
+       ret = afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status);
+       goto advance;
 }
 
 /*
@@ -1153,11 +1157,9 @@ static int yfs_deliver_fs_rename(struct afs_call *call)
        ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_dir_scb);
        if (ret < 0)
                return ret;
-       if (call->out_dir_scb != call->out_scb) {
-               ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb);
-               if (ret < 0)
-                       return ret;
-       }
+       ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb);
+       if (ret < 0)
+               return ret;
 
        xdr_decode_YFSVolSync(&bp, call->out_volsync);
        _leave(" = 0 [done]");
index 786849f..47f66c6 100644 (file)
@@ -3370,6 +3370,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
                            space_info->bytes_reserved > 0 ||
                            space_info->bytes_may_use > 0))
                        btrfs_dump_space_info(info, space_info, 0, 0);
+               WARN_ON(space_info->reclaim_size > 0);
                list_del(&space_info->list);
                btrfs_sysfs_remove_space_info(space_info);
        }
index 8a144f9..719e68a 100644 (file)
@@ -2098,6 +2098,21 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        atomic_inc(&root->log_batch);
 
        /*
+        * If the inode needs a full sync, make sure we use a full range to
+        * avoid log tree corruption, due to hole detection racing with ordered
+        * extent completion for adjacent ranges and races between logging and
+        * completion of ordered extents for adjancent ranges - both races
+        * could lead to file extent items in the log with overlapping ranges.
+        * Do this while holding the inode lock, to avoid races with other
+        * tasks.
+        */
+       if (test_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+                    &BTRFS_I(inode)->runtime_flags)) {
+               start = 0;
+               end = LLONG_MAX;
+       }
+
+       /*
         * Before we acquired the inode's lock, someone may have dirtied more
         * pages in the target range. We need to make sure that writeback for
         * any such pages does not start while we are logging the inode, because
index d197314..040009d 100644 (file)
@@ -264,6 +264,7 @@ copy_inline_extent:
                            size);
        inode_add_bytes(dst, datal);
        set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(dst)->runtime_flags);
+       ret = btrfs_inode_set_file_extent_range(BTRFS_I(dst), 0, aligned_end);
 out:
        if (!ret && !trans) {
                /*
index f655956..7e362a6 100644 (file)
@@ -611,8 +611,8 @@ static int should_ignore_root(struct btrfs_root *root)
        if (!reloc_root)
                return 0;
 
-       if (btrfs_root_last_snapshot(&reloc_root->root_item) ==
-           root->fs_info->running_transaction->transid - 1)
+       if (btrfs_header_generation(reloc_root->commit_root) ==
+           root->fs_info->running_transaction->transid)
                return 0;
        /*
         * if there is reloc tree and it was created in previous
index 8b0fe05..ff17a44 100644 (file)
@@ -361,6 +361,16 @@ int btrfs_can_overcommit(struct btrfs_fs_info *fs_info,
        return 0;
 }
 
+static void remove_ticket(struct btrfs_space_info *space_info,
+                         struct reserve_ticket *ticket)
+{
+       if (!list_empty(&ticket->list)) {
+               list_del_init(&ticket->list);
+               ASSERT(space_info->reclaim_size >= ticket->bytes);
+               space_info->reclaim_size -= ticket->bytes;
+       }
+}
+
 /*
  * This is for space we already have accounted in space_info->bytes_may_use, so
  * basically when we're returning space from block_rsv's.
@@ -388,9 +398,7 @@ again:
                        btrfs_space_info_update_bytes_may_use(fs_info,
                                                              space_info,
                                                              ticket->bytes);
-                       list_del_init(&ticket->list);
-                       ASSERT(space_info->reclaim_size >= ticket->bytes);
-                       space_info->reclaim_size -= ticket->bytes;
+                       remove_ticket(space_info, ticket);
                        ticket->bytes = 0;
                        space_info->tickets_id++;
                        wake_up(&ticket->wait);
@@ -899,7 +907,7 @@ static bool maybe_fail_all_tickets(struct btrfs_fs_info *fs_info,
                        btrfs_info(fs_info, "failing ticket with %llu bytes",
                                   ticket->bytes);
 
-               list_del_init(&ticket->list);
+               remove_ticket(space_info, ticket);
                ticket->error = -ENOSPC;
                wake_up(&ticket->wait);
 
@@ -1063,7 +1071,7 @@ static void wait_reserve_ticket(struct btrfs_fs_info *fs_info,
                         * despite getting an error, resulting in a space leak
                         * (bytes_may_use counter of our space_info).
                         */
-                       list_del_init(&ticket->list);
+                       remove_ticket(space_info, ticket);
                        ticket->error = -EINTR;
                        break;
                }
@@ -1121,7 +1129,7 @@ static int handle_reserve_ticket(struct btrfs_fs_info *fs_info,
                 * either the async reclaim job deletes the ticket from the list
                 * or we delete it ourselves at wait_reserve_ticket().
                 */
-               list_del_init(&ticket->list);
+               remove_ticket(space_info, ticket);
                if (!ret)
                        ret = -ENOSPC;
        }
index 58c1114..ec36a7c 100644 (file)
@@ -96,8 +96,8 @@ enum {
 static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root, struct btrfs_inode *inode,
                           int inode_only,
-                          u64 start,
-                          u64 end,
+                          const loff_t start,
+                          const loff_t end,
                           struct btrfs_log_ctx *ctx);
 static int link_to_fixup_dir(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
@@ -4533,15 +4533,13 @@ static int btrfs_log_all_xattrs(struct btrfs_trans_handle *trans,
 static int btrfs_log_holes(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
                           struct btrfs_inode *inode,
-                          struct btrfs_path *path,
-                          const u64 start,
-                          const u64 end)
+                          struct btrfs_path *path)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_key key;
        const u64 ino = btrfs_ino(inode);
        const u64 i_size = i_size_read(&inode->vfs_inode);
-       u64 prev_extent_end = start;
+       u64 prev_extent_end = 0;
        int ret;
 
        if (!btrfs_fs_incompat(fs_info, NO_HOLES) || i_size == 0)
@@ -4549,21 +4547,14 @@ static int btrfs_log_holes(struct btrfs_trans_handle *trans,
 
        key.objectid = ino;
        key.type = BTRFS_EXTENT_DATA_KEY;
-       key.offset = start;
+       key.offset = 0;
 
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
        if (ret < 0)
                return ret;
 
-       if (ret > 0 && path->slots[0] > 0) {
-               btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0] - 1);
-               if (key.objectid == ino && key.type == BTRFS_EXTENT_DATA_KEY)
-                       path->slots[0]--;
-       }
-
        while (true) {
                struct extent_buffer *leaf = path->nodes[0];
-               u64 extent_end;
 
                if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
                        ret = btrfs_next_leaf(root, path);
@@ -4580,18 +4571,9 @@ static int btrfs_log_holes(struct btrfs_trans_handle *trans,
                if (key.objectid != ino || key.type != BTRFS_EXTENT_DATA_KEY)
                        break;
 
-               extent_end = btrfs_file_extent_end(path);
-               if (extent_end <= start)
-                       goto next_slot;
-
                /* We have a hole, log it. */
                if (prev_extent_end < key.offset) {
-                       u64 hole_len;
-
-                       if (key.offset >= end)
-                               hole_len = end - prev_extent_end;
-                       else
-                               hole_len = key.offset - prev_extent_end;
+                       const u64 hole_len = key.offset - prev_extent_end;
 
                        /*
                         * Release the path to avoid deadlocks with other code
@@ -4621,20 +4603,16 @@ static int btrfs_log_holes(struct btrfs_trans_handle *trans,
                        leaf = path->nodes[0];
                }
 
-               prev_extent_end = min(extent_end, end);
-               if (extent_end >= end)
-                       break;
-next_slot:
+               prev_extent_end = btrfs_file_extent_end(path);
                path->slots[0]++;
                cond_resched();
        }
 
-       if (prev_extent_end < end && prev_extent_end < i_size) {
+       if (prev_extent_end < i_size) {
                u64 hole_len;
 
                btrfs_release_path(path);
-               hole_len = min(ALIGN(i_size, fs_info->sectorsize), end);
-               hole_len -= prev_extent_end;
+               hole_len = ALIGN(i_size - prev_extent_end, fs_info->sectorsize);
                ret = btrfs_insert_file_extent(trans, root->log_root,
                                               ino, prev_extent_end, 0, 0,
                                               hole_len, 0, hole_len,
@@ -4971,8 +4949,6 @@ static int copy_inode_items_to_log(struct btrfs_trans_handle *trans,
                                   const u64 logged_isize,
                                   const bool recursive_logging,
                                   const int inode_only,
-                                  const u64 start,
-                                  const u64 end,
                                   struct btrfs_log_ctx *ctx,
                                   bool *need_log_inode_item)
 {
@@ -4981,21 +4957,6 @@ static int copy_inode_items_to_log(struct btrfs_trans_handle *trans,
        int ins_nr = 0;
        int ret;
 
-       /*
-        * We must make sure we don't copy extent items that are entirely out of
-        * the range [start, end - 1]. This is not just an optimization to avoid
-        * copying but also needed to avoid a corruption where we end up with
-        * file extent items in the log tree that have overlapping ranges - this
-        * can happen if we race with ordered extent completion for ranges that
-        * are outside our target range. For example we copy an extent item and
-        * when we move to the next leaf, that extent was trimmed and a new one
-        * covering a subrange of it, but with a higher key, was inserted - we
-        * would then copy this other extent too, resulting in a log tree with
-        * 2 extent items that represent overlapping ranges.
-        *
-        * We can copy the entire extents at the range bondaries however, even
-        * if they cover an area outside the target range. That's ok.
-        */
        while (1) {
                ret = btrfs_search_forward(root, min_key, path, trans->transid);
                if (ret < 0)
@@ -5063,29 +5024,6 @@ again:
                        goto next_slot;
                }
 
-               if (min_key->type == BTRFS_EXTENT_DATA_KEY) {
-                       const u64 extent_end = btrfs_file_extent_end(path);
-
-                       if (extent_end <= start) {
-                               if (ins_nr > 0) {
-                                       ret = copy_items(trans, inode, dst_path,
-                                                        path, ins_start_slot,
-                                                        ins_nr, inode_only,
-                                                        logged_isize);
-                                       if (ret < 0)
-                                               return ret;
-                                       ins_nr = 0;
-                               }
-                               goto next_slot;
-                       }
-                       if (extent_end >= end) {
-                               ins_nr++;
-                               if (ins_nr == 1)
-                                       ins_start_slot = path->slots[0];
-                               break;
-                       }
-               }
-
                if (ins_nr && ins_start_slot + ins_nr == path->slots[0]) {
                        ins_nr++;
                        goto next_slot;
@@ -5151,8 +5089,8 @@ next_key:
 static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root, struct btrfs_inode *inode,
                           int inode_only,
-                          u64 start,
-                          u64 end,
+                          const loff_t start,
+                          const loff_t end,
                           struct btrfs_log_ctx *ctx)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
@@ -5180,9 +5118,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                return -ENOMEM;
        }
 
-       start = ALIGN_DOWN(start, fs_info->sectorsize);
-       end = ALIGN(end, fs_info->sectorsize);
-
        min_key.objectid = ino;
        min_key.type = BTRFS_INODE_ITEM_KEY;
        min_key.offset = 0;
@@ -5298,8 +5233,8 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
 
        err = copy_inode_items_to_log(trans, inode, &min_key, &max_key,
                                      path, dst_path, logged_isize,
-                                     recursive_logging, inode_only,
-                                     start, end, ctx, &need_log_inode_item);
+                                     recursive_logging, inode_only, ctx,
+                                     &need_log_inode_item);
        if (err)
                goto out_unlock;
 
@@ -5312,7 +5247,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
        if (max_key.type >= BTRFS_EXTENT_DATA_KEY && !fast_search) {
                btrfs_release_path(path);
                btrfs_release_path(dst_path);
-               err = btrfs_log_holes(trans, root, inode, path, start, end);
+               err = btrfs_log_holes(trans, root, inode, path);
                if (err)
                        goto out_unlock;
        }
index 7ab6166..6f4678d 100644 (file)
@@ -159,8 +159,6 @@ static void ceph_invalidatepage(struct page *page, unsigned int offset,
        if (!PagePrivate(page))
                return;
 
-       ClearPageChecked(page);
-
        dout("%p invalidatepage %p idx %lu full dirty page\n",
             inode, page, page->index);
 
@@ -183,6 +181,47 @@ static int ceph_releasepage(struct page *page, gfp_t g)
 }
 
 /*
+ * Read some contiguous pages.  If we cross a stripe boundary, shorten
+ * *plen.  Return number of bytes read, or error.
+ */
+static int ceph_sync_readpages(struct ceph_fs_client *fsc,
+                              struct ceph_vino vino,
+                              struct ceph_file_layout *layout,
+                              u64 off, u64 *plen,
+                              u32 truncate_seq, u64 truncate_size,
+                              struct page **pages, int num_pages,
+                              int page_align)
+{
+       struct ceph_osd_client *osdc = &fsc->client->osdc;
+       struct ceph_osd_request *req;
+       int rc = 0;
+
+       dout("readpages on ino %llx.%llx on %llu~%llu\n", vino.ino,
+            vino.snap, off, *plen);
+       req = ceph_osdc_new_request(osdc, layout, vino, off, plen, 0, 1,
+                                   CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ,
+                                   NULL, truncate_seq, truncate_size,
+                                   false);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       /* it may be a short read due to an object boundary */
+       osd_req_op_extent_osd_data_pages(req, 0,
+                               pages, *plen, page_align, false, false);
+
+       dout("readpages  final extent is %llu~%llu (%llu bytes align %d)\n",
+            off, *plen, *plen, page_align);
+
+       rc = ceph_osdc_start_request(osdc, req, false);
+       if (!rc)
+               rc = ceph_osdc_wait_request(osdc, req);
+
+       ceph_osdc_put_request(req);
+       dout("readpages result %d\n", rc);
+       return rc;
+}
+
+/*
  * read a single page, without unlocking it.
  */
 static int ceph_do_readpage(struct file *filp, struct page *page)
@@ -218,7 +257,7 @@ static int ceph_do_readpage(struct file *filp, struct page *page)
 
        dout("readpage inode %p file %p page %p index %lu\n",
             inode, filp, page, page->index);
-       err = ceph_osdc_readpages(&fsc->client->osdc, ceph_vino(inode),
+       err = ceph_sync_readpages(fsc, ceph_vino(inode),
                                  &ci->i_layout, off, &len,
                                  ci->i_truncate_seq, ci->i_truncate_size,
                                  &page, 1, 0);
@@ -571,6 +610,47 @@ static u64 get_writepages_data_length(struct inode *inode,
 }
 
 /*
+ * do a synchronous write on N pages
+ */
+static int ceph_sync_writepages(struct ceph_fs_client *fsc,
+                               struct ceph_vino vino,
+                               struct ceph_file_layout *layout,
+                               struct ceph_snap_context *snapc,
+                               u64 off, u64 len,
+                               u32 truncate_seq, u64 truncate_size,
+                               struct timespec64 *mtime,
+                               struct page **pages, int num_pages)
+{
+       struct ceph_osd_client *osdc = &fsc->client->osdc;
+       struct ceph_osd_request *req;
+       int rc = 0;
+       int page_align = off & ~PAGE_MASK;
+
+       req = ceph_osdc_new_request(osdc, layout, vino, off, &len, 0, 1,
+                                   CEPH_OSD_OP_WRITE, CEPH_OSD_FLAG_WRITE,
+                                   snapc, truncate_seq, truncate_size,
+                                   true);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       /* it may be a short write due to an object boundary */
+       osd_req_op_extent_osd_data_pages(req, 0, pages, len, page_align,
+                               false, false);
+       dout("writepages %llu~%llu (%llu bytes)\n", off, len, len);
+
+       req->r_mtime = *mtime;
+       rc = ceph_osdc_start_request(osdc, req, true);
+       if (!rc)
+               rc = ceph_osdc_wait_request(osdc, req);
+
+       ceph_osdc_put_request(req);
+       if (rc == 0)
+               rc = len;
+       dout("writepages result %d\n", rc);
+       return rc;
+}
+
+/*
  * Write a single page, but leave the page locked.
  *
  * If we get a write error, mark the mapping for error, but still adjust the
@@ -628,7 +708,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
                set_bdi_congested(inode_to_bdi(inode), BLK_RW_ASYNC);
 
        set_page_writeback(page);
-       err = ceph_osdc_writepages(&fsc->client->osdc, ceph_vino(inode),
+       err = ceph_sync_writepages(fsc, ceph_vino(inode),
                                   &ci->i_layout, snapc, page_off, len,
                                   ceph_wbc.truncate_seq,
                                   ceph_wbc.truncate_size,
@@ -1575,7 +1655,7 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf)
        do {
                lock_page(page);
 
-               if ((off > size) || (page->mapping != inode->i_mapping)) {
+               if (page_mkwrite_check_truncate(page, inode) < 0) {
                        unlock_page(page);
                        ret = VM_FAULT_NOPAGE;
                        break;
index 270b769..2f5cb6b 100644 (file)
@@ -32,7 +32,7 @@ struct ceph_fscache_entry {
        size_t uniq_len;
        /* The following members must be last */
        struct ceph_fsid fsid;
-       char uniquifier[0];
+       char uniquifier[];
 };
 
 static const struct fscache_cookie_def ceph_fscache_fsid_object_def = {
index 28ae0c1..185db76 100644 (file)
@@ -490,13 +490,10 @@ static void __cap_set_timeouts(struct ceph_mds_client *mdsc,
                               struct ceph_inode_info *ci)
 {
        struct ceph_mount_options *opt = mdsc->fsc->mount_options;
-
-       ci->i_hold_caps_min = round_jiffies(jiffies +
-                                           opt->caps_wanted_delay_min * HZ);
        ci->i_hold_caps_max = round_jiffies(jiffies +
                                            opt->caps_wanted_delay_max * HZ);
-       dout("__cap_set_timeouts %p min %lu max %lu\n", &ci->vfs_inode,
-            ci->i_hold_caps_min - jiffies, ci->i_hold_caps_max - jiffies);
+       dout("__cap_set_timeouts %p %lu\n", &ci->vfs_inode,
+            ci->i_hold_caps_max - jiffies);
 }
 
 /*
@@ -508,10 +505,9 @@ static void __cap_set_timeouts(struct ceph_mds_client *mdsc,
  *    -> we take mdsc->cap_delay_lock
  */
 static void __cap_delay_requeue(struct ceph_mds_client *mdsc,
-                               struct ceph_inode_info *ci,
-                               bool set_timeout)
+                               struct ceph_inode_info *ci)
 {
-       dout("__cap_delay_requeue %p flags %d at %lu\n", &ci->vfs_inode,
+       dout("__cap_delay_requeue %p flags 0x%lx at %lu\n", &ci->vfs_inode,
             ci->i_ceph_flags, ci->i_hold_caps_max);
        if (!mdsc->stopping) {
                spin_lock(&mdsc->cap_delay_lock);
@@ -520,8 +516,7 @@ static void __cap_delay_requeue(struct ceph_mds_client *mdsc,
                                goto no_change;
                        list_del_init(&ci->i_cap_delay_list);
                }
-               if (set_timeout)
-                       __cap_set_timeouts(mdsc, ci);
+               __cap_set_timeouts(mdsc, ci);
                list_add_tail(&ci->i_cap_delay_list, &mdsc->cap_delay_list);
 no_change:
                spin_unlock(&mdsc->cap_delay_lock);
@@ -561,19 +556,20 @@ static void __cap_delay_cancel(struct ceph_mds_client *mdsc,
        spin_unlock(&mdsc->cap_delay_lock);
 }
 
-/*
- * Common issue checks for add_cap, handle_cap_grant.
- */
+/* Common issue checks for add_cap, handle_cap_grant. */
 static void __check_cap_issue(struct ceph_inode_info *ci, struct ceph_cap *cap,
                              unsigned issued)
 {
        unsigned had = __ceph_caps_issued(ci, NULL);
 
+       lockdep_assert_held(&ci->i_ceph_lock);
+
        /*
         * Each time we receive FILE_CACHE anew, we increment
         * i_rdcache_gen.
         */
-       if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) &&
+       if (S_ISREG(ci->vfs_inode.i_mode) &&
+           (issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) &&
            (had & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0) {
                ci->i_rdcache_gen++;
        }
@@ -592,6 +588,13 @@ static void __check_cap_issue(struct ceph_inode_info *ci, struct ceph_cap *cap,
                        __ceph_dir_clear_complete(ci);
                }
        }
+
+       /* Wipe saved layout if we're losing DIR_CREATE caps */
+       if (S_ISDIR(ci->vfs_inode.i_mode) && (had & CEPH_CAP_DIR_CREATE) &&
+               !(issued & CEPH_CAP_DIR_CREATE)) {
+            ceph_put_string(rcu_dereference_raw(ci->i_cached_layout.pool_ns));
+            memset(&ci->i_cached_layout, 0, sizeof(ci->i_cached_layout));
+       }
 }
 
 /*
@@ -605,7 +608,7 @@ static void __check_cap_issue(struct ceph_inode_info *ci, struct ceph_cap *cap,
  */
 void ceph_add_cap(struct inode *inode,
                  struct ceph_mds_session *session, u64 cap_id,
-                 int fmode, unsigned issued, unsigned wanted,
+                 unsigned issued, unsigned wanted,
                  unsigned seq, unsigned mseq, u64 realmino, int flags,
                  struct ceph_cap **new_cap)
 {
@@ -621,13 +624,6 @@ void ceph_add_cap(struct inode *inode,
        dout("add_cap %p mds%d cap %llx %s seq %d\n", inode,
             session->s_mds, cap_id, ceph_cap_string(issued), seq);
 
-       /*
-        * If we are opening the file, include file mode wanted bits
-        * in wanted.
-        */
-       if (fmode >= 0)
-               wanted |= ceph_caps_for_mode(fmode);
-
        spin_lock(&session->s_gen_ttl_lock);
        gen = session->s_cap_gen;
        spin_unlock(&session->s_gen_ttl_lock);
@@ -725,7 +721,7 @@ void ceph_add_cap(struct inode *inode,
                dout(" issued %s, mds wanted %s, actual %s, queueing\n",
                     ceph_cap_string(issued), ceph_cap_string(wanted),
                     ceph_cap_string(actual_wanted));
-               __cap_delay_requeue(mdsc, ci, true);
+               __cap_delay_requeue(mdsc, ci);
        }
 
        if (flags & CEPH_CAP_FLAG_AUTH) {
@@ -752,9 +748,6 @@ void ceph_add_cap(struct inode *inode,
        cap->issue_seq = seq;
        cap->mseq = mseq;
        cap->cap_gen = gen;
-
-       if (fmode >= 0)
-               __ceph_get_fmode(ci, fmode);
 }
 
 /*
@@ -958,29 +951,97 @@ int __ceph_caps_used(struct ceph_inode_info *ci)
        if (ci->i_rd_ref)
                used |= CEPH_CAP_FILE_RD;
        if (ci->i_rdcache_ref ||
-           (!S_ISDIR(ci->vfs_inode.i_mode) && /* ignore readdir cache */
+           (S_ISREG(ci->vfs_inode.i_mode) &&
             ci->vfs_inode.i_data.nrpages))
                used |= CEPH_CAP_FILE_CACHE;
        if (ci->i_wr_ref)
                used |= CEPH_CAP_FILE_WR;
        if (ci->i_wb_ref || ci->i_wrbuffer_ref)
                used |= CEPH_CAP_FILE_BUFFER;
+       if (ci->i_fx_ref)
+               used |= CEPH_CAP_FILE_EXCL;
        return used;
 }
 
+#define FMODE_WAIT_BIAS 1000
+
 /*
  * wanted, by virtue of open file modes
  */
 int __ceph_caps_file_wanted(struct ceph_inode_info *ci)
 {
-       int i, bits = 0;
-       for (i = 0; i < CEPH_FILE_MODE_BITS; i++) {
-               if (ci->i_nr_by_mode[i])
-                       bits |= 1 << i;
+       const int PIN_SHIFT = ffs(CEPH_FILE_MODE_PIN);
+       const int RD_SHIFT = ffs(CEPH_FILE_MODE_RD);
+       const int WR_SHIFT = ffs(CEPH_FILE_MODE_WR);
+       const int LAZY_SHIFT = ffs(CEPH_FILE_MODE_LAZY);
+       struct ceph_mount_options *opt =
+               ceph_inode_to_client(&ci->vfs_inode)->mount_options;
+       unsigned long used_cutoff = jiffies - opt->caps_wanted_delay_max * HZ;
+       unsigned long idle_cutoff = jiffies - opt->caps_wanted_delay_min * HZ;
+
+       if (S_ISDIR(ci->vfs_inode.i_mode)) {
+               int want = 0;
+
+               /* use used_cutoff here, to keep dir's wanted caps longer */
+               if (ci->i_nr_by_mode[RD_SHIFT] > 0 ||
+                   time_after(ci->i_last_rd, used_cutoff))
+                       want |= CEPH_CAP_ANY_SHARED;
+
+               if (ci->i_nr_by_mode[WR_SHIFT] > 0 ||
+                   time_after(ci->i_last_wr, used_cutoff)) {
+                       want |= CEPH_CAP_ANY_SHARED | CEPH_CAP_FILE_EXCL;
+                       if (opt->flags & CEPH_MOUNT_OPT_ASYNC_DIROPS)
+                               want |= CEPH_CAP_ANY_DIR_OPS;
+               }
+
+               if (want || ci->i_nr_by_mode[PIN_SHIFT] > 0)
+                       want |= CEPH_CAP_PIN;
+
+               return want;
+       } else {
+               int bits = 0;
+
+               if (ci->i_nr_by_mode[RD_SHIFT] > 0) {
+                       if (ci->i_nr_by_mode[RD_SHIFT] >= FMODE_WAIT_BIAS ||
+                           time_after(ci->i_last_rd, used_cutoff))
+                               bits |= 1 << RD_SHIFT;
+               } else if (time_after(ci->i_last_rd, idle_cutoff)) {
+                       bits |= 1 << RD_SHIFT;
+               }
+
+               if (ci->i_nr_by_mode[WR_SHIFT] > 0) {
+                       if (ci->i_nr_by_mode[WR_SHIFT] >= FMODE_WAIT_BIAS ||
+                           time_after(ci->i_last_wr, used_cutoff))
+                               bits |= 1 << WR_SHIFT;
+               } else if (time_after(ci->i_last_wr, idle_cutoff)) {
+                       bits |= 1 << WR_SHIFT;
+               }
+
+               /* check lazyio only when read/write is wanted */
+               if ((bits & (CEPH_FILE_MODE_RDWR << 1)) &&
+                   ci->i_nr_by_mode[LAZY_SHIFT] > 0)
+                       bits |= 1 << LAZY_SHIFT;
+
+               return bits ? ceph_caps_for_mode(bits >> 1) : 0;
        }
-       if (bits == 0)
-               return 0;
-       return ceph_caps_for_mode(bits >> 1);
+}
+
+/*
+ * wanted, by virtue of open file modes AND cap refs (buffered/cached data)
+ */
+int __ceph_caps_wanted(struct ceph_inode_info *ci)
+{
+       int w = __ceph_caps_file_wanted(ci) | __ceph_caps_used(ci);
+       if (S_ISDIR(ci->vfs_inode.i_mode)) {
+               /* we want EXCL if holding caps of dir ops */
+               if (w & CEPH_CAP_ANY_DIR_OPS)
+                       w |= CEPH_CAP_FILE_EXCL;
+       } else {
+               /* we want EXCL if dirty data */
+               if (w & CEPH_CAP_FILE_BUFFER)
+                       w |= CEPH_CAP_FILE_EXCL;
+       }
+       return w;
 }
 
 /*
@@ -1004,14 +1065,6 @@ int __ceph_caps_mds_wanted(struct ceph_inode_info *ci, bool check)
        return mds_wanted;
 }
 
-/*
- * called under i_ceph_lock
- */
-static int __ceph_is_single_caps(struct ceph_inode_info *ci)
-{
-       return rb_first(&ci->i_caps) == rb_last(&ci->i_caps);
-}
-
 int ceph_is_any_caps(struct inode *inode)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
@@ -1274,9 +1327,15 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
        struct cap_msg_args arg;
        int held, revoking;
        int wake = 0;
-       int delayed = 0;
        int ret;
 
+       /* Don't send anything if it's still being created. Return delayed */
+       if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE) {
+               spin_unlock(&ci->i_ceph_lock);
+               dout("%s async create in flight for %p\n", __func__, inode);
+               return 1;
+       }
+
        held = cap->issued | cap->implemented;
        revoking = cap->implemented & ~cap->issued;
        retain &= ~revoking;
@@ -1287,28 +1346,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
             ceph_cap_string(revoking));
        BUG_ON((retain & CEPH_CAP_PIN) == 0);
 
-       arg.session = cap->session;
-
-       /* don't release wanted unless we've waited a bit. */
-       if ((ci->i_ceph_flags & CEPH_I_NODELAY) == 0 &&
-           time_before(jiffies, ci->i_hold_caps_min)) {
-               dout(" delaying issued %s -> %s, wanted %s -> %s on send\n",
-                    ceph_cap_string(cap->issued),
-                    ceph_cap_string(cap->issued & retain),
-                    ceph_cap_string(cap->mds_wanted),
-                    ceph_cap_string(want));
-               want |= cap->mds_wanted;
-               retain |= cap->issued;
-               delayed = 1;
-       }
-       ci->i_ceph_flags &= ~(CEPH_I_NODELAY | CEPH_I_FLUSH);
-       if (want & ~cap->mds_wanted) {
-               /* user space may open/close single file frequently.
-                * This avoids droping mds_wanted immediately after
-                * requesting new mds_wanted.
-                */
-               __cap_set_timeouts(mdsc, ci);
-       }
+       ci->i_ceph_flags &= ~CEPH_I_FLUSH;
 
        cap->issued &= retain;  /* drop bits we don't want */
        if (cap->implemented & ~cap->issued) {
@@ -1323,6 +1361,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
        cap->implemented &= cap->issued | used;
        cap->mds_wanted = want;
 
+       arg.session = cap->session;
        arg.ino = ceph_vino(inode).ino;
        arg.cid = cap->cap_id;
        arg.follows = flushing ? ci->i_head_snapc->seq : 0;
@@ -1332,7 +1371,8 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
        arg.size = inode->i_size;
        ci->i_reported_size = arg.size;
        arg.max_size = ci->i_wanted_max_size;
-       ci->i_requested_max_size = arg.max_size;
+       if (cap == ci->i_auth_cap)
+               ci->i_requested_max_size = arg.max_size;
 
        if (flushing & CEPH_CAP_XATTR_EXCL) {
                old_blob = __ceph_build_xattrs_blob(ci);
@@ -1383,14 +1423,19 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
 
        ret = send_cap_msg(&arg);
        if (ret < 0) {
-               dout("error sending cap msg, must requeue %p\n", inode);
-               delayed = 1;
+               pr_err("error sending cap msg, ino (%llx.%llx) "
+                      "flushing %s tid %llu, requeue\n",
+                      ceph_vinop(inode), ceph_cap_string(flushing),
+                      flush_tid);
+               spin_lock(&ci->i_ceph_lock);
+               __cap_delay_requeue(mdsc, ci);
+               spin_unlock(&ci->i_ceph_lock);
        }
 
        if (wake)
                wake_up_all(&ci->i_cap_wq);
 
-       return delayed;
+       return ret;
 }
 
 static inline int __send_flush_snap(struct inode *inode,
@@ -1617,6 +1662,8 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask,
        int was = ci->i_dirty_caps;
        int dirty = 0;
 
+       lockdep_assert_held(&ci->i_ceph_lock);
+
        if (!ci->i_auth_cap) {
                pr_warn("__mark_dirty_caps %p %llx mask %s, "
                        "but no auth cap (session was closed?)\n",
@@ -1654,7 +1701,7 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask,
        if (((was | ci->i_flushing_caps) & CEPH_CAP_FILE_BUFFER) &&
            (mask & CEPH_CAP_FILE_BUFFER))
                dirty |= I_DIRTY_DATASYNC;
-       __cap_delay_requeue(mdsc, ci, true);
+       __cap_delay_requeue(mdsc, ci);
        return dirty;
 }
 
@@ -1726,6 +1773,7 @@ static u64 __mark_caps_flushing(struct inode *inode,
        struct ceph_cap_flush *cf = NULL;
        int flushing;
 
+       lockdep_assert_held(&ci->i_ceph_lock);
        BUG_ON(ci->i_dirty_caps == 0);
        BUG_ON(list_empty(&ci->i_dirty_item));
        BUG_ON(!ci->i_prealloc_cap_flush);
@@ -1805,8 +1853,6 @@ bool __ceph_should_report_size(struct ceph_inode_info *ci)
  * versus held caps.  Release, flush, ack revoked caps to mds as
  * appropriate.
  *
- *  CHECK_CAPS_NODELAY - caller is delayed work and we should not delay
- *    cap release further.
  *  CHECK_CAPS_AUTHONLY - we should only check the auth cap
  *  CHECK_CAPS_FLUSH - we should flush any dirty caps immediately, without
  *    further delay.
@@ -1825,24 +1871,13 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags,
        int mds = -1;   /* keep track of how far we've gone through i_caps list
                           to avoid an infinite loop on retry */
        struct rb_node *p;
-       int delayed = 0, sent = 0;
-       bool no_delay = flags & CHECK_CAPS_NODELAY;
        bool queue_invalidate = false;
        bool tried_invalidate = false;
 
-       /* if we are unmounting, flush any unused caps immediately. */
-       if (mdsc->stopping)
-               no_delay = true;
-
        spin_lock(&ci->i_ceph_lock);
-
        if (ci->i_ceph_flags & CEPH_I_FLUSH)
                flags |= CHECK_CAPS_FLUSH;
 
-       if (!(flags & CHECK_CAPS_AUTHONLY) ||
-           (ci->i_auth_cap && __ceph_is_single_caps(ci)))
-               __cap_delay_cancel(mdsc, ci);
-
        goto retry_locked;
 retry:
        spin_lock(&ci->i_ceph_lock);
@@ -1866,10 +1901,11 @@ retry_locked:
                         * revoking the shared cap on every create/unlink
                         * operation.
                         */
-                       if (IS_RDONLY(inode))
+                       if (IS_RDONLY(inode)) {
                                want = CEPH_CAP_ANY_SHARED;
-                       else
-                               want = CEPH_CAP_ANY_SHARED | CEPH_CAP_FILE_EXCL;
+                       } else {
+                               want |= CEPH_CAP_ANY_SHARED | CEPH_CAP_FILE_EXCL;
+                       }
                        retain |= want;
                } else {
 
@@ -1885,14 +1921,13 @@ retry_locked:
        }
 
        dout("check_caps %p file_want %s used %s dirty %s flushing %s"
-            " issued %s revoking %s retain %s %s%s%s\n", inode,
+            " issued %s revoking %s retain %s %s%s\n", inode,
             ceph_cap_string(file_wanted),
             ceph_cap_string(used), ceph_cap_string(ci->i_dirty_caps),
             ceph_cap_string(ci->i_flushing_caps),
             ceph_cap_string(issued), ceph_cap_string(revoking),
             ceph_cap_string(retain),
             (flags & CHECK_CAPS_AUTHONLY) ? " AUTHONLY" : "",
-            (flags & CHECK_CAPS_NODELAY) ? " NODELAY" : "",
             (flags & CHECK_CAPS_FLUSH) ? " FLUSH" : "");
 
        /*
@@ -1900,8 +1935,8 @@ retry_locked:
         * have cached pages, but don't want them, then try to invalidate.
         * If we fail, it's because pages are locked.... try again later.
         */
-       if ((!no_delay || mdsc->stopping) &&
-           !S_ISDIR(inode->i_mode) &&          /* ignore readdir cache */
+       if ((!(flags & CHECK_CAPS_NOINVAL) || mdsc->stopping) &&
+           S_ISREG(inode->i_mode) &&
            !(ci->i_wb_ref || ci->i_wrbuffer_ref) &&   /* no dirty pages... */
            inode->i_data.nrpages &&            /* have cached pages */
            (revoking & (CEPH_CAP_FILE_CACHE|
@@ -1973,28 +2008,17 @@ retry_locked:
                }
 
                /* want more caps from mds? */
-               if (want & ~(cap->mds_wanted | cap->issued))
-                       goto ack;
+               if (want & ~cap->mds_wanted) {
+                       if (want & ~(cap->mds_wanted | cap->issued))
+                               goto ack;
+                       if (!__cap_is_valid(cap))
+                               goto ack;
+               }
 
                /* things we might delay */
                if ((cap->issued & ~retain) == 0)
                        continue;     /* nope, all good */
 
-               if (no_delay)
-                       goto ack;
-
-               /* delay? */
-               if ((ci->i_ceph_flags & CEPH_I_NODELAY) == 0 &&
-                   time_before(jiffies, ci->i_hold_caps_max)) {
-                       dout(" delaying issued %s -> %s, wanted %s -> %s\n",
-                            ceph_cap_string(cap->issued),
-                            ceph_cap_string(cap->issued & retain),
-                            ceph_cap_string(cap->mds_wanted),
-                            ceph_cap_string(want));
-                       delayed++;
-                       continue;
-               }
-
 ack:
                if (session && session != cap->session) {
                        dout("oops, wrong session %p mutex\n", session);
@@ -2055,18 +2079,20 @@ ack:
                }
 
                mds = cap->mds;  /* remember mds, so we don't repeat */
-               sent++;
 
                /* __send_cap drops i_ceph_lock */
-               delayed += __send_cap(mdsc, cap, CEPH_CAP_OP_UPDATE, 0,
-                               cap_used, want, retain, flushing,
-                               flush_tid, oldest_flush_tid);
+               __send_cap(mdsc, cap, CEPH_CAP_OP_UPDATE, 0, cap_used, want,
+                          retain, flushing, flush_tid, oldest_flush_tid);
                goto retry; /* retake i_ceph_lock and restart our cap scan. */
        }
 
-       /* Reschedule delayed caps release if we delayed anything */
-       if (delayed)
-               __cap_delay_requeue(mdsc, ci, false);
+       /* periodically re-calculate caps wanted by open files */
+       if (__ceph_is_any_real_caps(ci) &&
+           list_empty(&ci->i_cap_delay_list) &&
+           (file_wanted & ~CEPH_CAP_PIN) &&
+           !(used & (CEPH_CAP_FILE_RD | CEPH_CAP_ANY_FILE_WR))) {
+               __cap_delay_requeue(mdsc, ci);
+       }
 
        spin_unlock(&ci->i_ceph_lock);
 
@@ -2095,7 +2121,6 @@ retry:
 retry_locked:
        if (ci->i_dirty_caps && ci->i_auth_cap) {
                struct ceph_cap *cap = ci->i_auth_cap;
-               int delayed;
 
                if (session != cap->session) {
                        spin_unlock(&ci->i_ceph_lock);
@@ -2124,18 +2149,10 @@ retry_locked:
                                                 &oldest_flush_tid);
 
                /* __send_cap drops i_ceph_lock */
-               delayed = __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH,
-                                    CEPH_CLIENT_CAPS_SYNC,
-                                    __ceph_caps_used(ci),
-                                    __ceph_caps_wanted(ci),
-                                    (cap->issued | cap->implemented),
-                                    flushing, flush_tid, oldest_flush_tid);
-
-               if (delayed) {
-                       spin_lock(&ci->i_ceph_lock);
-                       __cap_delay_requeue(mdsc, ci, true);
-                       spin_unlock(&ci->i_ceph_lock);
-               }
+               __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH, CEPH_CLIENT_CAPS_SYNC,
+                          __ceph_caps_used(ci), __ceph_caps_wanted(ci),
+                          (cap->issued | cap->implemented),
+                          flushing, flush_tid, oldest_flush_tid);
        } else {
                if (!list_empty(&ci->i_cap_flush_list)) {
                        struct ceph_cap_flush *cf =
@@ -2233,6 +2250,10 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
        if (datasync)
                goto out;
 
+       ret = ceph_wait_on_async_create(inode);
+       if (ret)
+               goto out;
+
        dirty = try_flush_caps(inode, &flush_tid);
        dout("fsync dirty caps are %s\n", ceph_cap_string(dirty));
 
@@ -2335,22 +2356,13 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc,
                if (cf->caps) {
                        dout("kick_flushing_caps %p cap %p tid %llu %s\n",
                             inode, cap, cf->tid, ceph_cap_string(cf->caps));
-                       ci->i_ceph_flags |= CEPH_I_NODELAY;
-
-                       ret = __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH,
+                       __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH,
                                         (cf->tid < last_snap_flush ?
                                          CEPH_CLIENT_CAPS_PENDING_CAPSNAP : 0),
                                          __ceph_caps_used(ci),
                                          __ceph_caps_wanted(ci),
                                          (cap->issued | cap->implemented),
                                          cf->caps, cf->tid, oldest_flush_tid);
-                       if (ret) {
-                               pr_err("kick_flushing_caps: error sending "
-                                       "cap flush, ino (%llx.%llx) "
-                                       "tid %llu flushing %s\n",
-                                       ceph_vinop(inode), cf->tid,
-                                       ceph_cap_string(cf->caps));
-                       }
                } else {
                        struct ceph_cap_snap *capsnap =
                                        container_of(cf, struct ceph_cap_snap,
@@ -2457,16 +2469,15 @@ void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
        }
 }
 
-static void kick_flushing_inode_caps(struct ceph_mds_client *mdsc,
-                                    struct ceph_mds_session *session,
-                                    struct inode *inode)
-       __releases(ci->i_ceph_lock)
+void ceph_kick_flushing_inode_caps(struct ceph_mds_session *session,
+                                  struct ceph_inode_info *ci)
 {
-       struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_cap *cap;
+       struct ceph_mds_client *mdsc = session->s_mdsc;
+       struct ceph_cap *cap = ci->i_auth_cap;
+
+       lockdep_assert_held(&ci->i_ceph_lock);
 
-       cap = ci->i_auth_cap;
-       dout("kick_flushing_inode_caps %p flushing %s\n", inode,
+       dout("%s %p flushing %s\n", __func__, &ci->vfs_inode,
             ceph_cap_string(ci->i_flushing_caps));
 
        if (!list_empty(&ci->i_cap_flush_list)) {
@@ -2478,9 +2489,6 @@ static void kick_flushing_inode_caps(struct ceph_mds_client *mdsc,
                spin_unlock(&mdsc->cap_dirty_lock);
 
                __kick_flushing_caps(mdsc, session, ci, oldest_flush_tid);
-               spin_unlock(&ci->i_ceph_lock);
-       } else {
-               spin_unlock(&ci->i_ceph_lock);
        }
 }
 
@@ -2488,18 +2496,20 @@ static void kick_flushing_inode_caps(struct ceph_mds_client *mdsc,
 /*
  * Take references to capabilities we hold, so that we don't release
  * them to the MDS prematurely.
- *
- * Protected by i_ceph_lock.
  */
-static void __take_cap_refs(struct ceph_inode_info *ci, int got,
+void ceph_take_cap_refs(struct ceph_inode_info *ci, int got,
                            bool snap_rwsem_locked)
 {
+       lockdep_assert_held(&ci->i_ceph_lock);
+
        if (got & CEPH_CAP_PIN)
                ci->i_pin_ref++;
        if (got & CEPH_CAP_FILE_RD)
                ci->i_rd_ref++;
        if (got & CEPH_CAP_FILE_CACHE)
                ci->i_rdcache_ref++;
+       if (got & CEPH_CAP_FILE_EXCL)
+               ci->i_fx_ref++;
        if (got & CEPH_CAP_FILE_WR) {
                if (ci->i_wr_ref == 0 && !ci->i_head_snapc) {
                        BUG_ON(!snap_rwsem_locked);
@@ -2512,7 +2522,7 @@ static void __take_cap_refs(struct ceph_inode_info *ci, int got,
                if (ci->i_wb_ref == 0)
                        ihold(&ci->vfs_inode);
                ci->i_wb_ref++;
-               dout("__take_cap_refs %p wb %d -> %d (?)\n",
+               dout("%s %p wb %d -> %d (?)\n", __func__,
                     &ci->vfs_inode, ci->i_wb_ref-1, ci->i_wb_ref);
        }
 }
@@ -2524,14 +2534,16 @@ static void __take_cap_refs(struct ceph_inode_info *ci, int got,
  * Note that caller is responsible for ensuring max_size increases are
  * requested from the MDS.
  *
- * Returns 0 if caps were not able to be acquired (yet), a 1 if they were,
- * or a negative error code.
- *
- * FIXME: how does a 0 return differ from -EAGAIN?
+ * Returns 0 if caps were not able to be acquired (yet), 1 if succeed,
+ * or a negative error code. There are 3 speical error codes:
+ *  -EAGAIN: need to sleep but non-blocking is specified
+ *  -EFBIG:  ask caller to call check_max_size() and try again.
+ *  -ESTALE: ask caller to call ceph_renew_caps() and try again.
  */
 enum {
-       NON_BLOCKING    = 1,
-       CHECK_FILELOCK  = 2,
+       /* first 8 bits are reserved for CEPH_FILE_MODE_FOO */
+       NON_BLOCKING    = (1 << 8),
+       CHECK_FILELOCK  = (1 << 9),
 };
 
 static int try_get_cap_refs(struct inode *inode, int need, int want,
@@ -2541,7 +2553,6 @@ static int try_get_cap_refs(struct inode *inode, int need, int want,
        struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
        int ret = 0;
        int have, implemented;
-       int file_wanted;
        bool snap_rwsem_locked = false;
 
        dout("get_cap_refs %p need %s want %s\n", inode,
@@ -2557,15 +2568,6 @@ again:
                goto out_unlock;
        }
 
-       /* make sure file is actually open */
-       file_wanted = __ceph_caps_file_wanted(ci);
-       if ((file_wanted & need) != need) {
-               dout("try_get_cap_refs need %s file_wanted %s, EBADF\n",
-                    ceph_cap_string(need), ceph_cap_string(file_wanted));
-               ret = -EBADF;
-               goto out_unlock;
-       }
-
        /* finish pending truncate */
        while (ci->i_truncate_pending) {
                spin_unlock(&ci->i_ceph_lock);
@@ -2584,7 +2586,7 @@ again:
                        dout("get_cap_refs %p endoff %llu > maxsize %llu\n",
                             inode, endoff, ci->i_max_size);
                        if (endoff > ci->i_requested_max_size)
-                               ret = -EAGAIN;
+                               ret = ci->i_auth_cap ? -EFBIG : -ESTALE;
                        goto out_unlock;
                }
                /*
@@ -2630,51 +2632,55 @@ again:
                                }
                                snap_rwsem_locked = true;
                        }
-                       *got = need | (have & want);
-                       if ((need & CEPH_CAP_FILE_RD) &&
+                       if ((have & want) == want)
+                               *got = need | want;
+                       else
+                               *got = need;
+                       if (S_ISREG(inode->i_mode) &&
+                           (need & CEPH_CAP_FILE_RD) &&
                            !(*got & CEPH_CAP_FILE_CACHE))
                                ceph_disable_fscache_readpage(ci);
-                       __take_cap_refs(ci, *got, true);
+                       ceph_take_cap_refs(ci, *got, true);
                        ret = 1;
                }
        } else {
                int session_readonly = false;
-               if ((need & CEPH_CAP_FILE_WR) && ci->i_auth_cap) {
+               int mds_wanted;
+               if (ci->i_auth_cap &&
+                   (need & (CEPH_CAP_FILE_WR | CEPH_CAP_FILE_EXCL))) {
                        struct ceph_mds_session *s = ci->i_auth_cap->session;
                        spin_lock(&s->s_cap_lock);
                        session_readonly = s->s_readonly;
                        spin_unlock(&s->s_cap_lock);
                }
                if (session_readonly) {
-                       dout("get_cap_refs %p needed %s but mds%d readonly\n",
+                       dout("get_cap_refs %p need %s but mds%d readonly\n",
                             inode, ceph_cap_string(need), ci->i_auth_cap->mds);
                        ret = -EROFS;
                        goto out_unlock;
                }
 
-               if (ci->i_ceph_flags & CEPH_I_CAP_DROPPED) {
-                       int mds_wanted;
-                       if (READ_ONCE(mdsc->fsc->mount_state) ==
-                           CEPH_MOUNT_SHUTDOWN) {
-                               dout("get_cap_refs %p forced umount\n", inode);
-                               ret = -EIO;
-                               goto out_unlock;
-                       }
-                       mds_wanted = __ceph_caps_mds_wanted(ci, false);
-                       if (need & ~(mds_wanted & need)) {
-                               dout("get_cap_refs %p caps were dropped"
-                                    " (session killed?)\n", inode);
-                               ret = -ESTALE;
-                               goto out_unlock;
-                       }
-                       if (!(file_wanted & ~mds_wanted))
-                               ci->i_ceph_flags &= ~CEPH_I_CAP_DROPPED;
+               if (READ_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) {
+                       dout("get_cap_refs %p forced umount\n", inode);
+                       ret = -EIO;
+                       goto out_unlock;
+               }
+               mds_wanted = __ceph_caps_mds_wanted(ci, false);
+               if (need & ~mds_wanted) {
+                       dout("get_cap_refs %p need %s > mds_wanted %s\n",
+                            inode, ceph_cap_string(need),
+                            ceph_cap_string(mds_wanted));
+                       ret = -ESTALE;
+                       goto out_unlock;
                }
 
-               dout("get_cap_refs %p have %s needed %s\n", inode,
+               dout("get_cap_refs %p have %s need %s\n", inode,
                     ceph_cap_string(have), ceph_cap_string(need));
        }
 out_unlock:
+
+       __ceph_touch_fmode(ci, mdsc, flags);
+
        spin_unlock(&ci->i_ceph_lock);
        if (snap_rwsem_locked)
                up_read(&mdsc->snap_rwsem);
@@ -2712,20 +2718,40 @@ static void check_max_size(struct inode *inode, loff_t endoff)
                ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
 }
 
+static inline int get_used_fmode(int caps)
+{
+       int fmode = 0;
+       if (caps & CEPH_CAP_FILE_RD)
+               fmode |= CEPH_FILE_MODE_RD;
+       if (caps & CEPH_CAP_FILE_WR)
+               fmode |= CEPH_FILE_MODE_WR;
+       return fmode;
+}
+
 int ceph_try_get_caps(struct inode *inode, int need, int want,
                      bool nonblock, int *got)
 {
-       int ret;
+       int ret, flags;
 
        BUG_ON(need & ~CEPH_CAP_FILE_RD);
-       BUG_ON(want & ~(CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO|CEPH_CAP_FILE_SHARED));
-       ret = ceph_pool_perm_check(inode, need);
-       if (ret < 0)
-               return ret;
+       BUG_ON(want & ~(CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO |
+                       CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL |
+                       CEPH_CAP_ANY_DIR_OPS));
+       if (need) {
+               ret = ceph_pool_perm_check(inode, need);
+               if (ret < 0)
+                       return ret;
+       }
+
+       flags = get_used_fmode(need | want);
+       if (nonblock)
+               flags |= NON_BLOCKING;
 
-       ret = try_get_cap_refs(inode, need, want, 0,
-                              (nonblock ? NON_BLOCKING : 0), got);
-       return ret == -EAGAIN ? 0 : ret;
+       ret = try_get_cap_refs(inode, need, want, 0, flags, got);
+       /* three special error codes */
+       if (ret == -EAGAIN || ret == -EFBIG || ret == -EAGAIN)
+               ret = 0;
+       return ret;
 }
 
 /*
@@ -2750,16 +2776,16 @@ int ceph_get_caps(struct file *filp, int need, int want,
            fi->filp_gen != READ_ONCE(fsc->filp_gen))
                return -EBADF;
 
-       while (true) {
-               if (endoff > 0)
-                       check_max_size(inode, endoff);
+       flags = get_used_fmode(need | want);
 
-               flags = atomic_read(&fi->num_locks) ? CHECK_FILELOCK : 0;
+       while (true) {
+               flags &= CEPH_FILE_MODE_MASK;
+               if (atomic_read(&fi->num_locks))
+                       flags |= CHECK_FILELOCK;
                _got = 0;
                ret = try_get_cap_refs(inode, need, want, endoff,
                                       flags, &_got);
-               if (ret == -EAGAIN)
-                       continue;
+               WARN_ON_ONCE(ret == -EAGAIN);
                if (!ret) {
                        struct ceph_mds_client *mdsc = fsc->mdsc;
                        struct cap_wait cw;
@@ -2774,6 +2800,8 @@ int ceph_get_caps(struct file *filp, int need, int want,
                        list_add(&cw.list, &mdsc->cap_wait_list);
                        spin_unlock(&mdsc->caps_list_lock);
 
+                       /* make sure used fmode not timeout */
+                       ceph_get_fmode(ci, flags, FMODE_WAIT_BIAS);
                        add_wait_queue(&ci->i_cap_wq, &wait);
 
                        flags |= NON_BLOCKING;
@@ -2787,6 +2815,7 @@ int ceph_get_caps(struct file *filp, int need, int want,
                        }
 
                        remove_wait_queue(&ci->i_cap_wq, &wait);
+                       ceph_put_fmode(ci, flags, FMODE_WAIT_BIAS);
 
                        spin_lock(&mdsc->caps_list_lock);
                        list_del(&cw.list);
@@ -2804,16 +2833,26 @@ int ceph_get_caps(struct file *filp, int need, int want,
                }
 
                if (ret < 0) {
+                       if (ret == -EFBIG || ret == -ESTALE) {
+                               int ret2 = ceph_wait_on_async_create(inode);
+                               if (ret2 < 0)
+                                       return ret2;
+                       }
+                       if (ret == -EFBIG) {
+                               check_max_size(inode, endoff);
+                               continue;
+                       }
                        if (ret == -ESTALE) {
                                /* session was killed, try renew caps */
-                               ret = ceph_renew_caps(inode);
+                               ret = ceph_renew_caps(inode, flags);
                                if (ret == 0)
                                        continue;
                        }
                        return ret;
                }
 
-               if (ci->i_inline_version != CEPH_INLINE_NONE &&
+               if (S_ISREG(ci->vfs_inode.i_mode) &&
+                   ci->i_inline_version != CEPH_INLINE_NONE &&
                    (_got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) &&
                    i_size_read(inode) > 0) {
                        struct page *page =
@@ -2846,7 +2885,8 @@ int ceph_get_caps(struct file *filp, int need, int want,
                break;
        }
 
-       if ((_got & CEPH_CAP_FILE_RD) && (_got & CEPH_CAP_FILE_CACHE))
+       if (S_ISREG(ci->vfs_inode.i_mode) &&
+           (_got & CEPH_CAP_FILE_RD) && (_got & CEPH_CAP_FILE_CACHE))
                ceph_fscache_revalidate_cookie(ci);
 
        *got = _got;
@@ -2860,7 +2900,7 @@ int ceph_get_caps(struct file *filp, int need, int want,
 void ceph_get_cap_refs(struct ceph_inode_info *ci, int caps)
 {
        spin_lock(&ci->i_ceph_lock);
-       __take_cap_refs(ci, caps, false);
+       ceph_take_cap_refs(ci, caps, false);
        spin_unlock(&ci->i_ceph_lock);
 }
 
@@ -2911,6 +2951,9 @@ void ceph_put_cap_refs(struct ceph_inode_info *ci, int had)
        if (had & CEPH_CAP_FILE_CACHE)
                if (--ci->i_rdcache_ref == 0)
                        last++;
+       if (had & CEPH_CAP_FILE_EXCL)
+               if (--ci->i_fx_ref == 0)
+                       last++;
        if (had & CEPH_CAP_FILE_BUFFER) {
                if (--ci->i_wb_ref == 0) {
                        last++;
@@ -2950,7 +2993,7 @@ void ceph_put_cap_refs(struct ceph_inode_info *ci, int had)
        dout("put_cap_refs %p had %s%s%s\n", inode, ceph_cap_string(had),
             last ? " last" : "", put ? " put" : "");
 
-       if (last && !flushsnaps)
+       if (last)
                ceph_check_caps(ci, 0, NULL);
        else if (flushsnaps)
                ceph_flush_snaps(ci, NULL);
@@ -3032,7 +3075,7 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
        spin_unlock(&ci->i_ceph_lock);
 
        if (last) {
-               ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
+               ceph_check_caps(ci, 0, NULL);
        } else if (flush_snaps) {
                ceph_flush_snaps(ci, NULL);
        }
@@ -3133,7 +3176,7 @@ static void handle_cap_grant(struct inode *inode,
         * try to invalidate (once).  (If there are dirty buffers, we
         * will invalidate _after_ writeback.)
         */
-       if (!S_ISDIR(inode->i_mode) && /* don't invalidate readdir cache */
+       if (S_ISREG(inode->i_mode) && /* don't invalidate readdir cache */
            ((cap->issued & ~newcaps) & CEPH_CAP_FILE_CACHE) &&
            (newcaps & CEPH_CAP_FILE_LAZYIO) == 0 &&
            !(ci->i_wrbuffer_ref || ci->i_wb_ref)) {
@@ -3297,11 +3340,12 @@ static void handle_cap_grant(struct inode *inode,
                     ceph_cap_string(cap->issued),
                     ceph_cap_string(newcaps),
                     ceph_cap_string(revoking));
-               if (revoking & used & CEPH_CAP_FILE_BUFFER)
+               if (S_ISREG(inode->i_mode) &&
+                   (revoking & used & CEPH_CAP_FILE_BUFFER))
                        writeback = true;  /* initiate writeback; will delay ack */
-               else if (revoking == CEPH_CAP_FILE_CACHE &&
-                        (newcaps & CEPH_CAP_FILE_LAZYIO) == 0 &&
-                        queue_invalidate)
+               else if (queue_invalidate &&
+                        revoking == CEPH_CAP_FILE_CACHE &&
+                        (newcaps & CEPH_CAP_FILE_LAZYIO) == 0)
                        ; /* do nothing yet, invalidation will be queued */
                else if (cap == ci->i_auth_cap)
                        check_caps = 1; /* check auth cap only */
@@ -3339,7 +3383,8 @@ static void handle_cap_grant(struct inode *inode,
        if (le32_to_cpu(grant->op) == CEPH_CAP_OP_IMPORT) {
                if (newcaps & ~extra_info->issued)
                        wake = true;
-               kick_flushing_inode_caps(session->s_mdsc, session, inode);
+               ceph_kick_flushing_inode_caps(session, ci);
+               spin_unlock(&ci->i_ceph_lock);
                up_read(&session->s_mdsc->snap_rwsem);
        } else {
                spin_unlock(&ci->i_ceph_lock);
@@ -3367,10 +3412,10 @@ static void handle_cap_grant(struct inode *inode,
                wake_up_all(&ci->i_cap_wq);
 
        if (check_caps == 1)
-               ceph_check_caps(ci, CHECK_CAPS_NODELAY|CHECK_CAPS_AUTHONLY,
+               ceph_check_caps(ci, CHECK_CAPS_AUTHONLY | CHECK_CAPS_NOINVAL,
                                session);
        else if (check_caps == 2)
-               ceph_check_caps(ci, CHECK_CAPS_NODELAY, session);
+               ceph_check_caps(ci, CHECK_CAPS_NOINVAL, session);
        else
                mutex_unlock(&session->s_mutex);
 }
@@ -3619,8 +3664,6 @@ retry:
                goto out_unlock;
 
        if (target < 0) {
-               if (cap->mds_wanted | cap->issued)
-                       ci->i_ceph_flags |= CEPH_I_CAP_DROPPED;
                __ceph_remove_cap(cap, false);
                goto out_unlock;
        }
@@ -3668,7 +3711,7 @@ retry:
                /* add placeholder for the export tagert */
                int flag = (cap == ci->i_auth_cap) ? CEPH_CAP_FLAG_AUTH : 0;
                tcap = new_cap;
-               ceph_add_cap(inode, tsession, t_cap_id, -1, issued, 0,
+               ceph_add_cap(inode, tsession, t_cap_id, issued, 0,
                             t_seq - 1, t_mseq, (u64)-1, flag, &new_cap);
 
                if (!list_empty(&ci->i_cap_flush_list) &&
@@ -3773,7 +3816,7 @@ retry:
        __ceph_caps_issued(ci, &issued);
        issued |= __ceph_caps_dirty(ci);
 
-       ceph_add_cap(inode, session, cap_id, -1, caps, wanted, seq, mseq,
+       ceph_add_cap(inode, session, cap_id, caps, wanted, seq, mseq,
                     realmino, CEPH_CAP_FLAG_AUTH, &new_cap);
 
        ocap = peer >= 0 ? __get_cap_for_mds(ci, peer) : NULL;
@@ -4047,7 +4090,6 @@ void ceph_check_delayed_caps(struct ceph_mds_client *mdsc)
 {
        struct inode *inode;
        struct ceph_inode_info *ci;
-       int flags = CHECK_CAPS_NODELAY;
 
        dout("check_delayed_caps\n");
        while (1) {
@@ -4067,7 +4109,7 @@ void ceph_check_delayed_caps(struct ceph_mds_client *mdsc)
 
                if (inode) {
                        dout("check_delayed_caps on %p\n", inode);
-                       ceph_check_caps(ci, flags, NULL);
+                       ceph_check_caps(ci, 0, NULL);
                        /* avoid calling iput_final() in tick thread */
                        ceph_async_iput(inode);
                }
@@ -4092,7 +4134,7 @@ void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc)
                ihold(inode);
                dout("flush_dirty_caps %p\n", inode);
                spin_unlock(&mdsc->cap_dirty_lock);
-               ceph_check_caps(ci, CHECK_CAPS_NODELAY|CHECK_CAPS_FLUSH, NULL);
+               ceph_check_caps(ci, CHECK_CAPS_FLUSH, NULL);
                iput(inode);
                spin_lock(&mdsc->cap_dirty_lock);
        }
@@ -4100,14 +4142,31 @@ void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc)
        dout("flush_dirty_caps done\n");
 }
 
-void __ceph_get_fmode(struct ceph_inode_info *ci, int fmode)
+void __ceph_touch_fmode(struct ceph_inode_info *ci,
+                       struct ceph_mds_client *mdsc, int fmode)
+{
+       unsigned long now = jiffies;
+       if (fmode & CEPH_FILE_MODE_RD)
+               ci->i_last_rd = now;
+       if (fmode & CEPH_FILE_MODE_WR)
+               ci->i_last_wr = now;
+       /* queue periodic check */
+       if (fmode &&
+           __ceph_is_any_real_caps(ci) &&
+           list_empty(&ci->i_cap_delay_list))
+               __cap_delay_requeue(mdsc, ci);
+}
+
+void ceph_get_fmode(struct ceph_inode_info *ci, int fmode, int count)
 {
        int i;
        int bits = (fmode << 1) | 1;
+       spin_lock(&ci->i_ceph_lock);
        for (i = 0; i < CEPH_FILE_MODE_BITS; i++) {
                if (bits & (1 << i))
-                       ci->i_nr_by_mode[i]++;
+                       ci->i_nr_by_mode[i] += count;
        }
+       spin_unlock(&ci->i_ceph_lock);
 }
 
 /*
@@ -4115,26 +4174,18 @@ void __ceph_get_fmode(struct ceph_inode_info *ci, int fmode)
  * we may need to release capabilities to the MDS (or schedule
  * their delayed release).
  */
-void ceph_put_fmode(struct ceph_inode_info *ci, int fmode)
+void ceph_put_fmode(struct ceph_inode_info *ci, int fmode, int count)
 {
-       int i, last = 0;
+       int i;
        int bits = (fmode << 1) | 1;
        spin_lock(&ci->i_ceph_lock);
        for (i = 0; i < CEPH_FILE_MODE_BITS; i++) {
                if (bits & (1 << i)) {
-                       BUG_ON(ci->i_nr_by_mode[i] == 0);
-                       if (--ci->i_nr_by_mode[i] == 0)
-                               last++;
+                       BUG_ON(ci->i_nr_by_mode[i] < count);
+                       ci->i_nr_by_mode[i] -= count;
                }
        }
-       dout("put_fmode %p fmode %d {%d,%d,%d,%d}\n",
-            &ci->vfs_inode, fmode,
-            ci->i_nr_by_mode[0], ci->i_nr_by_mode[1],
-            ci->i_nr_by_mode[2], ci->i_nr_by_mode[3]);
        spin_unlock(&ci->i_ceph_lock);
-
-       if (last && ci->i_vino.snap == CEPH_NOSNAP)
-               ceph_check_caps(ci, 0, NULL);
 }
 
 /*
@@ -4152,7 +4203,6 @@ int ceph_drop_caps_for_unlink(struct inode *inode)
        if (inode->i_nlink == 1) {
                drop |= ~(__ceph_caps_wanted(ci) | CEPH_CAP_PIN);
 
-               ci->i_ceph_flags |= CEPH_I_NODELAY;
                if (__ceph_caps_dirty(ci)) {
                        struct ceph_mds_client *mdsc =
                                ceph_inode_to_client(inode)->mdsc;
@@ -4208,8 +4258,6 @@ int ceph_encode_inode_release(void **p, struct inode *inode,
                if (force || (cap->issued & drop)) {
                        if (cap->issued & drop) {
                                int wanted = __ceph_caps_wanted(ci);
-                               if ((ci->i_ceph_flags & CEPH_I_NODELAY) == 0)
-                                       wanted |= cap->mds_wanted;
                                dout("encode_inode_release %p cap %p "
                                     "%s -> %s, wanted %s -> %s\n", inode, cap,
                                     ceph_cap_string(cap->issued),
index fb7cabd..481ac97 100644 (file)
@@ -218,10 +218,10 @@ static int mds_sessions_show(struct seq_file *s, void *ptr)
        return 0;
 }
 
-CEPH_DEFINE_SHOW_FUNC(mdsmap_show)
-CEPH_DEFINE_SHOW_FUNC(mdsc_show)
-CEPH_DEFINE_SHOW_FUNC(caps_show)
-CEPH_DEFINE_SHOW_FUNC(mds_sessions_show)
+DEFINE_SHOW_ATTRIBUTE(mdsmap);
+DEFINE_SHOW_ATTRIBUTE(mdsc);
+DEFINE_SHOW_ATTRIBUTE(caps);
+DEFINE_SHOW_ATTRIBUTE(mds_sessions);
 
 
 /*
@@ -281,25 +281,25 @@ void ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
                                        0400,
                                        fsc->client->debugfs_dir,
                                        fsc,
-                                       &mdsmap_show_fops);
+                                       &mdsmap_fops);
 
        fsc->debugfs_mds_sessions = debugfs_create_file("mds_sessions",
                                        0400,
                                        fsc->client->debugfs_dir,
                                        fsc,
-                                       &mds_sessions_show_fops);
+                                       &mds_sessions_fops);
 
        fsc->debugfs_mdsc = debugfs_create_file("mdsc",
                                                0400,
                                                fsc->client->debugfs_dir,
                                                fsc,
-                                               &mdsc_show_fops);
+                                               &mdsc_fops);
 
        fsc->debugfs_caps = debugfs_create_file("caps",
                                                   0400,
                                                   fsc->client->debugfs_dir,
                                                   fsc,
-                                                  &caps_show_fops);
+                                                  &caps_fops);
 }
 
 
index d0cd0ab..4c4202c 100644 (file)
@@ -335,8 +335,11 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
                ctx->pos = 2;
        }
 
-       /* can we use the dcache? */
        spin_lock(&ci->i_ceph_lock);
+       /* request Fx cap. if have Fx, we don't need to release Fs cap
+        * for later create/unlink. */
+       __ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_WR);
+       /* can we use the dcache? */
        if (ceph_test_mount_opt(fsc, DCACHE) &&
            !ceph_test_mount_opt(fsc, NOASYNCREADDIR) &&
            ceph_snap(inode) != CEPH_SNAPDIR &&
@@ -752,7 +755,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
                struct ceph_dentry_info *di = ceph_dentry(dentry);
 
                spin_lock(&ci->i_ceph_lock);
-               dout(" dir %p flags are %d\n", dir, ci->i_ceph_flags);
+               dout(" dir %p flags are 0x%lx\n", dir, ci->i_ceph_flags);
                if (strncmp(dentry->d_name.name,
                            fsc->mount_options->snapdir_name,
                            dentry->d_name.len) &&
@@ -760,6 +763,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
                    ceph_test_mount_opt(fsc, DCACHE) &&
                    __ceph_dir_is_complete(ci) &&
                    (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) {
+                       __ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_RD);
                        spin_unlock(&ci->i_ceph_lock);
                        dout(" dir %p complete, -ENOENT\n", dir);
                        d_add(dentry, NULL);
@@ -1036,6 +1040,78 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir,
        return err;
 }
 
+static void ceph_async_unlink_cb(struct ceph_mds_client *mdsc,
+                                struct ceph_mds_request *req)
+{
+       int result = req->r_err ? req->r_err :
+                       le32_to_cpu(req->r_reply_info.head->result);
+
+       if (result == -EJUKEBOX)
+               goto out;
+
+       /* If op failed, mark everyone involved for errors */
+       if (result) {
+               int pathlen = 0;
+               u64 base = 0;
+               char *path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
+                                                 &base, 0);
+
+               /* mark error on parent + clear complete */
+               mapping_set_error(req->r_parent->i_mapping, result);
+               ceph_dir_clear_complete(req->r_parent);
+
+               /* drop the dentry -- we don't know its status */
+               if (!d_unhashed(req->r_dentry))
+                       d_drop(req->r_dentry);
+
+               /* mark inode itself for an error (since metadata is bogus) */
+               mapping_set_error(req->r_old_inode->i_mapping, result);
+
+               pr_warn("ceph: async unlink failure path=(%llx)%s result=%d!\n",
+                       base, IS_ERR(path) ? "<<bad>>" : path, result);
+               ceph_mdsc_free_path(path, pathlen);
+       }
+out:
+       iput(req->r_old_inode);
+       ceph_mdsc_release_dir_caps(req);
+}
+
+static int get_caps_for_async_unlink(struct inode *dir, struct dentry *dentry)
+{
+       struct ceph_inode_info *ci = ceph_inode(dir);
+       struct ceph_dentry_info *di;
+       int got = 0, want = CEPH_CAP_FILE_EXCL | CEPH_CAP_DIR_UNLINK;
+
+       spin_lock(&ci->i_ceph_lock);
+       if ((__ceph_caps_issued(ci, NULL) & want) == want) {
+               ceph_take_cap_refs(ci, want, false);
+               got = want;
+       }
+       spin_unlock(&ci->i_ceph_lock);
+
+       /* If we didn't get anything, return 0 */
+       if (!got)
+               return 0;
+
+        spin_lock(&dentry->d_lock);
+        di = ceph_dentry(dentry);
+       /*
+        * - We are holding Fx, which implies Fs caps.
+        * - Only support async unlink for primary linkage
+        */
+       if (atomic_read(&ci->i_shared_gen) != di->lease_shared_gen ||
+           !(di->flags & CEPH_DENTRY_PRIMARY_LINK))
+               want = 0;
+        spin_unlock(&dentry->d_lock);
+
+       /* Do we still want what we've got? */
+       if (want == got)
+               return got;
+
+       ceph_put_cap_refs(ci, got);
+       return 0;
+}
+
 /*
  * rmdir and unlink are differ only by the metadata op code
  */
@@ -1045,6 +1121,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
        struct ceph_mds_client *mdsc = fsc->mdsc;
        struct inode *inode = d_inode(dentry);
        struct ceph_mds_request *req;
+       bool try_async = ceph_test_mount_opt(fsc, ASYNC_DIROPS);
        int err = -EROFS;
        int op;
 
@@ -1059,6 +1136,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
                        CEPH_MDS_OP_RMDIR : CEPH_MDS_OP_UNLINK;
        } else
                goto out;
+retry:
        req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
        if (IS_ERR(req)) {
                err = PTR_ERR(req);
@@ -1067,13 +1145,39 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
        req->r_dentry = dget(dentry);
        req->r_num_caps = 2;
        req->r_parent = dir;
-       set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
        req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
        req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
        req->r_inode_drop = ceph_drop_caps_for_unlink(inode);
-       err = ceph_mdsc_do_request(mdsc, dir, req);
-       if (!err && !req->r_reply_info.head->is_dentry)
-               d_delete(dentry);
+
+       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,
+                    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);
+               req->r_callback = ceph_async_unlink_cb;
+               req->r_old_inode = d_inode(dentry);
+               ihold(req->r_old_inode);
+               err = ceph_mdsc_submit_request(mdsc, dir, req);
+               if (!err) {
+                       /*
+                        * We have enough caps, so we assume that the unlink
+                        * will succeed. Fix up the target inode and dcache.
+                        */
+                       drop_nlink(inode);
+                       d_delete(dentry);
+               } else if (err == -EJUKEBOX) {
+                       try_async = false;
+                       ceph_mdsc_put_request(req);
+                       goto retry;
+               }
+       } else {
+               set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
+               err = ceph_mdsc_do_request(mdsc, dir, req);
+               if (!err && !req->r_reply_info.head->is_dentry)
+                       d_delete(dentry);
+       }
+
        ceph_mdsc_put_request(req);
 out:
        return err;
@@ -1411,6 +1515,7 @@ void ceph_invalidate_dentry_lease(struct dentry *dentry)
        spin_lock(&dentry->d_lock);
        di->time = jiffies;
        di->lease_shared_gen = 0;
+       di->flags &= ~CEPH_DENTRY_PRIMARY_LINK;
        __dentry_lease_unlist(di);
        spin_unlock(&dentry->d_lock);
 }
@@ -1520,7 +1625,8 @@ static int __dir_lease_try_check(const struct dentry *dentry)
 /*
  * Check if directory-wide content lease/cap is valid.
  */
-static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
+static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry,
+                             struct ceph_mds_client *mdsc)
 {
        struct ceph_inode_info *ci = ceph_inode(dir);
        int valid;
@@ -1528,7 +1634,10 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
 
        spin_lock(&ci->i_ceph_lock);
        valid = __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1);
-       shared_gen = atomic_read(&ci->i_shared_gen);
+       if (valid) {
+               __ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_RD);
+               shared_gen = atomic_read(&ci->i_shared_gen);
+       }
        spin_unlock(&ci->i_ceph_lock);
        if (valid) {
                struct ceph_dentry_info *di;
@@ -1554,6 +1663,7 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
        int valid = 0;
        struct dentry *parent;
        struct inode *dir, *inode;
+       struct ceph_mds_client *mdsc;
 
        if (flags & LOOKUP_RCU) {
                parent = READ_ONCE(dentry->d_parent);
@@ -1570,6 +1680,8 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
        dout("d_revalidate %p '%pd' inode %p offset 0x%llx\n", dentry,
             dentry, inode, ceph_dentry(dentry)->offset);
 
+       mdsc = ceph_sb_to_client(dir->i_sb)->mdsc;
+
        /* always trust cached snapped dentries, snapdir dentry */
        if (ceph_snap(dir) != CEPH_NOSNAP) {
                dout("d_revalidate %p '%pd' inode %p is SNAPPED\n", dentry,
@@ -1581,7 +1693,7 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
                valid = dentry_lease_is_valid(dentry, flags);
                if (valid == -ECHILD)
                        return valid;
-               if (valid || dir_lease_is_valid(dir, dentry)) {
+               if (valid || dir_lease_is_valid(dir, dentry, mdsc)) {
                        if (inode)
                                valid = ceph_is_any_caps(inode);
                        else
@@ -1590,8 +1702,6 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
        }
 
        if (!valid) {
-               struct ceph_mds_client *mdsc =
-                       ceph_sb_to_client(dir->i_sb)->mdsc;
                struct ceph_mds_request *req;
                int op, err;
                u32 mask;
index b6bfa94..79dc068 100644 (file)
@@ -315,6 +315,11 @@ static struct dentry *__get_parent(struct super_block *sb,
 
        req->r_num_caps = 1;
        err = ceph_mdsc_do_request(mdsc, NULL, req);
+       if (err) {
+               ceph_mdsc_put_request(req);
+               return ERR_PTR(err);
+       }
+
        inode = req->r_target_inode;
        if (inode)
                ihold(inode);
index 5a478cd..afdfca9 100644 (file)
@@ -212,10 +212,8 @@ static int ceph_init_file_info(struct inode *inode, struct file *file,
        if (isdir) {
                struct ceph_dir_file_info *dfi =
                        kmem_cache_zalloc(ceph_dir_file_cachep, GFP_KERNEL);
-               if (!dfi) {
-                       ceph_put_fmode(ci, fmode); /* clean up */
+               if (!dfi)
                        return -ENOMEM;
-               }
 
                file->private_data = dfi;
                fi = &dfi->file_info;
@@ -223,15 +221,15 @@ static int ceph_init_file_info(struct inode *inode, struct file *file,
                dfi->readdir_cache_idx = -1;
        } else {
                fi = kmem_cache_zalloc(ceph_file_cachep, GFP_KERNEL);
-               if (!fi) {
-                       ceph_put_fmode(ci, fmode); /* clean up */
+               if (!fi)
                        return -ENOMEM;
-               }
 
                file->private_data = fi;
        }
 
+       ceph_get_fmode(ci, fmode, 1);
        fi->fmode = fmode;
+
        spin_lock_init(&fi->rw_contexts_lock);
        INIT_LIST_HEAD(&fi->rw_contexts);
        fi->meta_err = errseq_sample(&ci->i_meta_err);
@@ -263,7 +261,6 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
        case S_IFLNK:
                dout("init_file %p %p 0%o (symlink)\n", inode, file,
                     inode->i_mode);
-               ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
                break;
 
        default:
@@ -273,7 +270,6 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
                 * we need to drop the open ref now, since we don't
                 * have .release set to ceph_release.
                 */
-               ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
                BUG_ON(inode->i_fop->release == ceph_release);
 
                /* call the proper open fop */
@@ -285,14 +281,15 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
 /*
  * try renew caps after session gets killed.
  */
-int ceph_renew_caps(struct inode *inode)
+int ceph_renew_caps(struct inode *inode, int fmode)
 {
-       struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
+       struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_mds_request *req;
        int err, flags, wanted;
 
        spin_lock(&ci->i_ceph_lock);
+       __ceph_touch_fmode(ci, mdsc, fmode);
        wanted = __ceph_caps_file_wanted(ci);
        if (__ceph_is_any_real_caps(ci) &&
            (!(wanted & CEPH_CAP_ANY_WR) || ci->i_auth_cap)) {
@@ -326,7 +323,6 @@ int ceph_renew_caps(struct inode *inode)
        req->r_inode = inode;
        ihold(inode);
        req->r_num_caps = 1;
-       req->r_fmode = -1;
 
        err = ceph_mdsc_do_request(mdsc, NULL, req);
        ceph_mdsc_put_request(req);
@@ -372,9 +368,6 @@ int ceph_open(struct inode *inode, struct file *file)
 
        /* trivially open snapdir */
        if (ceph_snap(inode) == CEPH_SNAPDIR) {
-               spin_lock(&ci->i_ceph_lock);
-               __ceph_get_fmode(ci, fmode);
-               spin_unlock(&ci->i_ceph_lock);
                return ceph_init_file(inode, file, fmode);
        }
 
@@ -392,7 +385,7 @@ int ceph_open(struct inode *inode, struct file *file)
                dout("open %p fmode %d want %s issued %s using existing\n",
                     inode, fmode, ceph_cap_string(wanted),
                     ceph_cap_string(issued));
-               __ceph_get_fmode(ci, fmode);
+               __ceph_touch_fmode(ci, mdsc, fmode);
                spin_unlock(&ci->i_ceph_lock);
 
                /* adjust wanted? */
@@ -404,7 +397,7 @@ int ceph_open(struct inode *inode, struct file *file)
                return ceph_init_file(inode, file, fmode);
        } else if (ceph_snap(inode) != CEPH_NOSNAP &&
                   (ci->i_snap_caps & wanted) == wanted) {
-               __ceph_get_fmode(ci, fmode);
+               __ceph_touch_fmode(ci, mdsc, fmode);
                spin_unlock(&ci->i_ceph_lock);
                return ceph_init_file(inode, file, fmode);
        }
@@ -430,6 +423,236 @@ out:
        return err;
 }
 
+/* Clone the layout from a synchronous create, if the dir now has Dc caps */
+static void
+cache_file_layout(struct inode *dst, struct inode *src)
+{
+       struct ceph_inode_info *cdst = ceph_inode(dst);
+       struct ceph_inode_info *csrc = ceph_inode(src);
+
+       spin_lock(&cdst->i_ceph_lock);
+       if ((__ceph_caps_issued(cdst, NULL) & CEPH_CAP_DIR_CREATE) &&
+           !ceph_file_layout_is_valid(&cdst->i_cached_layout)) {
+               memcpy(&cdst->i_cached_layout, &csrc->i_layout,
+                       sizeof(cdst->i_cached_layout));
+               rcu_assign_pointer(cdst->i_cached_layout.pool_ns,
+                                  ceph_try_get_string(csrc->i_layout.pool_ns));
+       }
+       spin_unlock(&cdst->i_ceph_lock);
+}
+
+/*
+ * Try to set up an async create. We need caps, a file layout, and inode number,
+ * and either a lease on the dentry or complete dir info. If any of those
+ * criteria are not satisfied, then return false and the caller can go
+ * synchronous.
+ */
+static int try_prep_async_create(struct inode *dir, struct dentry *dentry,
+                                struct ceph_file_layout *lo, u64 *pino)
+{
+       struct ceph_inode_info *ci = ceph_inode(dir);
+       struct ceph_dentry_info *di = ceph_dentry(dentry);
+       int got = 0, want = CEPH_CAP_FILE_EXCL | CEPH_CAP_DIR_CREATE;
+       u64 ino;
+
+       spin_lock(&ci->i_ceph_lock);
+       /* No auth cap means no chance for Dc caps */
+       if (!ci->i_auth_cap)
+               goto no_async;
+
+       /* Any delegated inos? */
+       if (xa_empty(&ci->i_auth_cap->session->s_delegated_inos))
+               goto no_async;
+
+       if (!ceph_file_layout_is_valid(&ci->i_cached_layout))
+               goto no_async;
+
+       if ((__ceph_caps_issued(ci, NULL) & want) != want)
+               goto no_async;
+
+       if (d_in_lookup(dentry)) {
+               if (!__ceph_dir_is_complete(ci))
+                       goto no_async;
+               spin_lock(&dentry->d_lock);
+               di->lease_shared_gen = atomic_read(&ci->i_shared_gen);
+               spin_unlock(&dentry->d_lock);
+       } else if (atomic_read(&ci->i_shared_gen) !=
+                  READ_ONCE(di->lease_shared_gen)) {
+               goto no_async;
+       }
+
+       ino = ceph_get_deleg_ino(ci->i_auth_cap->session);
+       if (!ino)
+               goto no_async;
+
+       *pino = ino;
+       ceph_take_cap_refs(ci, want, false);
+       memcpy(lo, &ci->i_cached_layout, sizeof(*lo));
+       rcu_assign_pointer(lo->pool_ns,
+                          ceph_try_get_string(ci->i_cached_layout.pool_ns));
+       got = want;
+no_async:
+       spin_unlock(&ci->i_ceph_lock);
+       return got;
+}
+
+static void restore_deleg_ino(struct inode *dir, u64 ino)
+{
+       struct ceph_inode_info *ci = ceph_inode(dir);
+       struct ceph_mds_session *s = NULL;
+
+       spin_lock(&ci->i_ceph_lock);
+       if (ci->i_auth_cap)
+               s = ceph_get_mds_session(ci->i_auth_cap->session);
+       spin_unlock(&ci->i_ceph_lock);
+       if (s) {
+               int err = ceph_restore_deleg_ino(s, ino);
+               if (err)
+                       pr_warn("ceph: unable to restore delegated ino 0x%llx to session: %d\n",
+                               ino, err);
+               ceph_put_mds_session(s);
+       }
+}
+
+static void ceph_async_create_cb(struct ceph_mds_client *mdsc,
+                                 struct ceph_mds_request *req)
+{
+       int result = req->r_err ? req->r_err :
+                       le32_to_cpu(req->r_reply_info.head->result);
+
+       if (result == -EJUKEBOX)
+               goto out;
+
+       mapping_set_error(req->r_parent->i_mapping, result);
+
+       if (result) {
+               struct dentry *dentry = req->r_dentry;
+               int pathlen = 0;
+               u64 base = 0;
+               char *path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
+                                                 &base, 0);
+
+               ceph_dir_clear_complete(req->r_parent);
+               if (!d_unhashed(dentry))
+                       d_drop(dentry);
+
+               /* FIXME: start returning I/O errors on all accesses? */
+               pr_warn("ceph: async create failure path=(%llx)%s result=%d!\n",
+                       base, IS_ERR(path) ? "<<bad>>" : path, result);
+               ceph_mdsc_free_path(path, pathlen);
+       }
+
+       if (req->r_target_inode) {
+               struct ceph_inode_info *ci = ceph_inode(req->r_target_inode);
+               u64 ino = ceph_vino(req->r_target_inode).ino;
+
+               if (req->r_deleg_ino != ino)
+                       pr_warn("%s: inode number mismatch! err=%d deleg_ino=0x%llx target=0x%llx\n",
+                               __func__, req->r_err, req->r_deleg_ino, ino);
+               mapping_set_error(req->r_target_inode->i_mapping, result);
+
+               spin_lock(&ci->i_ceph_lock);
+               if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE) {
+                       ci->i_ceph_flags &= ~CEPH_I_ASYNC_CREATE;
+                       wake_up_bit(&ci->i_ceph_flags, CEPH_ASYNC_CREATE_BIT);
+               }
+               ceph_kick_flushing_inode_caps(req->r_session, ci);
+               spin_unlock(&ci->i_ceph_lock);
+       } else {
+               pr_warn("%s: no req->r_target_inode for 0x%llx\n", __func__,
+                       req->r_deleg_ino);
+       }
+out:
+       ceph_mdsc_release_dir_caps(req);
+}
+
+static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,
+                                   struct file *file, umode_t mode,
+                                   struct ceph_mds_request *req,
+                                   struct ceph_acl_sec_ctx *as_ctx,
+                                   struct ceph_file_layout *lo)
+{
+       int ret;
+       char xattr_buf[4];
+       struct ceph_mds_reply_inode in = { };
+       struct ceph_mds_reply_info_in iinfo = { .in = &in };
+       struct ceph_inode_info *ci = ceph_inode(dir);
+       struct inode *inode;
+       struct timespec64 now;
+       struct ceph_vino vino = { .ino = req->r_deleg_ino,
+                                 .snap = CEPH_NOSNAP };
+
+       ktime_get_real_ts64(&now);
+
+       inode = ceph_get_inode(dentry->d_sb, vino);
+       if (IS_ERR(inode))
+               return PTR_ERR(inode);
+
+       iinfo.inline_version = CEPH_INLINE_NONE;
+       iinfo.change_attr = 1;
+       ceph_encode_timespec64(&iinfo.btime, &now);
+
+       iinfo.xattr_len = ARRAY_SIZE(xattr_buf);
+       iinfo.xattr_data = xattr_buf;
+       memset(iinfo.xattr_data, 0, iinfo.xattr_len);
+
+       in.ino = cpu_to_le64(vino.ino);
+       in.snapid = cpu_to_le64(CEPH_NOSNAP);
+       in.version = cpu_to_le64(1);    // ???
+       in.cap.caps = in.cap.wanted = cpu_to_le32(CEPH_CAP_ALL_FILE);
+       in.cap.cap_id = cpu_to_le64(1);
+       in.cap.realm = cpu_to_le64(ci->i_snap_realm->ino);
+       in.cap.flags = CEPH_CAP_FLAG_AUTH;
+       in.ctime = in.mtime = in.atime = iinfo.btime;
+       in.mode = cpu_to_le32((u32)mode);
+       in.truncate_seq = cpu_to_le32(1);
+       in.truncate_size = cpu_to_le64(-1ULL);
+       in.xattr_version = cpu_to_le64(1);
+       in.uid = cpu_to_le32(from_kuid(&init_user_ns, current_fsuid()));
+       in.gid = cpu_to_le32(from_kgid(&init_user_ns, dir->i_mode & S_ISGID ?
+                               dir->i_gid : current_fsgid()));
+       in.nlink = cpu_to_le32(1);
+       in.max_size = cpu_to_le64(lo->stripe_unit);
+
+       ceph_file_layout_to_legacy(lo, &in.layout);
+
+       ret = ceph_fill_inode(inode, NULL, &iinfo, NULL, req->r_session,
+                             req->r_fmode, NULL);
+       if (ret) {
+               dout("%s failed to fill inode: %d\n", __func__, ret);
+               ceph_dir_clear_complete(dir);
+               if (!d_unhashed(dentry))
+                       d_drop(dentry);
+               if (inode->i_state & I_NEW)
+                       discard_new_inode(inode);
+       } 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);
+               ceph_dir_clear_ordered(dir);
+               ceph_init_inode_acls(inode, as_ctx);
+               if (inode->i_state & I_NEW) {
+                       /*
+                        * If it's not I_NEW, then someone created this before
+                        * we got here. Assume the server is aware of it at
+                        * that point and don't worry about setting
+                        * CEPH_I_ASYNC_CREATE.
+                        */
+                       ceph_inode(inode)->i_ceph_flags = CEPH_I_ASYNC_CREATE;
+                       unlock_new_inode(inode);
+               }
+               if (d_in_lookup(dentry) || d_really_is_negative(dentry)) {
+                       if (!d_unhashed(dentry))
+                               d_drop(dentry);
+                       dn = d_splice_alias(inode, dentry);
+                       WARN_ON_ONCE(dn && dn != dentry);
+               }
+               file->f_mode |= FMODE_CREATED;
+               ret = finish_open(file, dentry, ceph_open);
+       }
+       return ret;
+}
 
 /*
  * Do a lookup + open with a single request.  If we get a non-existent
@@ -443,6 +666,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
        struct ceph_mds_request *req;
        struct dentry *dn;
        struct ceph_acl_sec_ctx as_ctx = {};
+       bool try_async = ceph_test_mount_opt(fsc, ASYNC_DIROPS);
        int mask;
        int err;
 
@@ -466,7 +690,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
                /* If it's not being looked up, it's negative */
                return -ENOENT;
        }
-
+retry:
        /* do the open */
        req = prepare_open_request(dir->i_sb, flags, mode);
        if (IS_ERR(req)) {
@@ -475,21 +699,43 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
        }
        req->r_dentry = dget(dentry);
        req->r_num_caps = 2;
+       mask = CEPH_STAT_CAP_INODE | CEPH_CAP_AUTH_SHARED;
+       if (ceph_security_xattr_wanted(dir))
+               mask |= CEPH_CAP_XATTR_SHARED;
+       req->r_args.open.mask = cpu_to_le32(mask);
+       req->r_parent = dir;
+
        if (flags & O_CREAT) {
+               struct ceph_file_layout lo;
+
                req->r_dentry_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_AUTH_EXCL;
                req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
                if (as_ctx.pagelist) {
                        req->r_pagelist = as_ctx.pagelist;
                        as_ctx.pagelist = NULL;
                }
+               if (try_async &&
+                   (req->r_dir_caps =
+                     try_prep_async_create(dir, dentry, &lo,
+                                           &req->r_deleg_ino))) {
+                       set_bit(CEPH_MDS_R_ASYNC, &req->r_req_flags);
+                       req->r_args.open.flags |= cpu_to_le32(CEPH_O_EXCL);
+                       req->r_callback = ceph_async_create_cb;
+                       err = ceph_mdsc_submit_request(mdsc, dir, req);
+                       if (!err) {
+                               err = ceph_finish_async_create(dir, dentry,
+                                                       file, mode, req,
+                                                       &as_ctx, &lo);
+                       } else if (err == -EJUKEBOX) {
+                               restore_deleg_ino(dir, req->r_deleg_ino);
+                               ceph_mdsc_put_request(req);
+                               try_async = false;
+                               goto retry;
+                       }
+                       goto out_req;
+               }
        }
 
-       mask = CEPH_STAT_CAP_INODE | CEPH_CAP_AUTH_SHARED;
-       if (ceph_security_xattr_wanted(dir))
-               mask |= CEPH_CAP_XATTR_SHARED;
-       req->r_args.open.mask = cpu_to_le32(mask);
-
-       req->r_parent = dir;
        set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
        err = ceph_mdsc_do_request(mdsc,
                                   (flags & (O_CREAT|O_TRUNC)) ? dir : NULL,
@@ -518,14 +764,15 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
        } else {
                dout("atomic_open finish_open on dn %p\n", dn);
                if (req->r_op == CEPH_MDS_OP_CREATE && req->r_reply_info.has_create_ino) {
-                       ceph_init_inode_acls(d_inode(dentry), &as_ctx);
+                       struct inode *newino = d_inode(dentry);
+
+                       cache_file_layout(dir, newino);
+                       ceph_init_inode_acls(newino, &as_ctx);
                        file->f_mode |= FMODE_CREATED;
                }
                err = finish_open(file, dentry, ceph_open);
        }
 out_req:
-       if (!req->r_err && req->r_target_inode)
-               ceph_put_fmode(ceph_inode(req->r_target_inode), req->r_fmode);
        ceph_mdsc_put_request(req);
 out_ctx:
        ceph_release_acl_sec_ctx(&as_ctx);
@@ -542,7 +789,7 @@ int ceph_release(struct inode *inode, struct file *file)
                dout("release inode %p dir file %p\n", inode, file);
                WARN_ON(!list_empty(&dfi->file_info.rw_contexts));
 
-               ceph_put_fmode(ci, dfi->file_info.fmode);
+               ceph_put_fmode(ci, dfi->file_info.fmode, 1);
 
                if (dfi->last_readdir)
                        ceph_mdsc_put_request(dfi->last_readdir);
@@ -554,7 +801,8 @@ int ceph_release(struct inode *inode, struct file *file)
                dout("release inode %p regular file %p\n", inode, file);
                WARN_ON(!list_empty(&fi->rw_contexts));
 
-               ceph_put_fmode(ci, fi->fmode);
+               ceph_put_fmode(ci, fi->fmode, 1);
+
                kmem_cache_free(ceph_file_cachep, fi);
        }
 
@@ -1567,7 +1815,7 @@ retry_snap:
                if (dirty)
                        __mark_inode_dirty(inode, dirty);
                if (ceph_quota_is_max_bytes_approaching(inode, iocb->ki_pos))
-                       ceph_check_caps(ci, CHECK_CAPS_NODELAY, NULL);
+                       ceph_check_caps(ci, 0, NULL);
        }
 
        dout("aio_write %p %llx.%llx %llu~%u  dropping cap refs on %s\n",
@@ -1944,6 +2192,71 @@ static int is_file_size_ok(struct inode *src_inode, struct inode *dst_inode,
        return 0;
 }
 
+static ssize_t ceph_do_objects_copy(struct ceph_inode_info *src_ci, u64 *src_off,
+                                   struct ceph_inode_info *dst_ci, u64 *dst_off,
+                                   struct ceph_fs_client *fsc,
+                                   size_t len, unsigned int flags)
+{
+       struct ceph_object_locator src_oloc, dst_oloc;
+       struct ceph_object_id src_oid, dst_oid;
+       size_t bytes = 0;
+       u64 src_objnum, src_objoff, dst_objnum, dst_objoff;
+       u32 src_objlen, dst_objlen;
+       u32 object_size = src_ci->i_layout.object_size;
+       int ret;
+
+       src_oloc.pool = src_ci->i_layout.pool_id;
+       src_oloc.pool_ns = ceph_try_get_string(src_ci->i_layout.pool_ns);
+       dst_oloc.pool = dst_ci->i_layout.pool_id;
+       dst_oloc.pool_ns = ceph_try_get_string(dst_ci->i_layout.pool_ns);
+
+       while (len >= object_size) {
+               ceph_calc_file_object_mapping(&src_ci->i_layout, *src_off,
+                                             object_size, &src_objnum,
+                                             &src_objoff, &src_objlen);
+               ceph_calc_file_object_mapping(&dst_ci->i_layout, *dst_off,
+                                             object_size, &dst_objnum,
+                                             &dst_objoff, &dst_objlen);
+               ceph_oid_init(&src_oid);
+               ceph_oid_printf(&src_oid, "%llx.%08llx",
+                               src_ci->i_vino.ino, src_objnum);
+               ceph_oid_init(&dst_oid);
+               ceph_oid_printf(&dst_oid, "%llx.%08llx",
+                               dst_ci->i_vino.ino, dst_objnum);
+               /* Do an object remote copy */
+               ret = ceph_osdc_copy_from(&fsc->client->osdc,
+                                         src_ci->i_vino.snap, 0,
+                                         &src_oid, &src_oloc,
+                                         CEPH_OSD_OP_FLAG_FADVISE_SEQUENTIAL |
+                                         CEPH_OSD_OP_FLAG_FADVISE_NOCACHE,
+                                         &dst_oid, &dst_oloc,
+                                         CEPH_OSD_OP_FLAG_FADVISE_SEQUENTIAL |
+                                         CEPH_OSD_OP_FLAG_FADVISE_DONTNEED,
+                                         dst_ci->i_truncate_seq,
+                                         dst_ci->i_truncate_size,
+                                         CEPH_OSD_COPY_FROM_FLAG_TRUNCATE_SEQ);
+               if (ret) {
+                       if (ret == -EOPNOTSUPP) {
+                               fsc->have_copy_from2 = false;
+                               pr_notice("OSDs don't support copy-from2; disabling copy offload\n");
+                       }
+                       dout("ceph_osdc_copy_from returned %d\n", ret);
+                       if (!bytes)
+                               bytes = ret;
+                       goto out;
+               }
+               len -= object_size;
+               bytes += object_size;
+               *src_off += object_size;
+               *dst_off += object_size;
+       }
+
+out:
+       ceph_oloc_destroy(&src_oloc);
+       ceph_oloc_destroy(&dst_oloc);
+       return bytes;
+}
+
 static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
                                      struct file *dst_file, loff_t dst_off,
                                      size_t len, unsigned int flags)
@@ -1954,14 +2267,11 @@ static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
        struct ceph_inode_info *dst_ci = ceph_inode(dst_inode);
        struct ceph_cap_flush *prealloc_cf;
        struct ceph_fs_client *src_fsc = ceph_inode_to_client(src_inode);
-       struct ceph_object_locator src_oloc, dst_oloc;
-       struct ceph_object_id src_oid, dst_oid;
-       loff_t endoff = 0, size;
-       ssize_t ret = -EIO;
+       loff_t size;
+       ssize_t ret = -EIO, bytes;
        u64 src_objnum, dst_objnum, src_objoff, dst_objoff;
-       u32 src_objlen, dst_objlen, object_size;
+       u32 src_objlen, dst_objlen;
        int src_got = 0, dst_got = 0, err, dirty;
-       bool do_final_copy = false;
 
        if (src_inode->i_sb != dst_inode->i_sb) {
                struct ceph_fs_client *dst_fsc = ceph_inode_to_client(dst_inode);
@@ -2039,22 +2349,14 @@ static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
        if (ret < 0)
                goto out_caps;
 
-       size = i_size_read(dst_inode);
-       endoff = dst_off + len;
-
        /* Drop dst file cached pages */
        ret = invalidate_inode_pages2_range(dst_inode->i_mapping,
                                            dst_off >> PAGE_SHIFT,
-                                           endoff >> PAGE_SHIFT);
+                                           (dst_off + len) >> PAGE_SHIFT);
        if (ret < 0) {
                dout("Failed to invalidate inode pages (%zd)\n", ret);
                ret = 0; /* XXX */
        }
-       src_oloc.pool = src_ci->i_layout.pool_id;
-       src_oloc.pool_ns = ceph_try_get_string(src_ci->i_layout.pool_ns);
-       dst_oloc.pool = dst_ci->i_layout.pool_id;
-       dst_oloc.pool_ns = ceph_try_get_string(dst_ci->i_layout.pool_ns);
-
        ceph_calc_file_object_mapping(&src_ci->i_layout, src_off,
                                      src_ci->i_layout.object_size,
                                      &src_objnum, &src_objoff, &src_objlen);
@@ -2073,6 +2375,8 @@ static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
         * starting at the src_off
         */
        if (src_objoff) {
+               dout("Initial partial copy of %u bytes\n", src_objlen);
+
                /*
                 * we need to temporarily drop all caps as we'll be calling
                 * {read,write}_iter, which will get caps again.
@@ -2080,8 +2384,9 @@ static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
                put_rd_wr_caps(src_ci, src_got, dst_ci, dst_got);
                ret = do_splice_direct(src_file, &src_off, dst_file,
                                       &dst_off, src_objlen, flags);
-               if (ret < 0) {
-                       dout("do_splice_direct returned %d\n", err);
+               /* Abort on short copies or on error */
+               if (ret < src_objlen) {
+                       dout("Failed partial copy (%zd)\n", ret);
                        goto out;
                }
                len -= ret;
@@ -2094,65 +2399,27 @@ static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
                if (err < 0)
                        goto out_caps;
        }
-       object_size = src_ci->i_layout.object_size;
-       while (len >= object_size) {
-               ceph_calc_file_object_mapping(&src_ci->i_layout, src_off,
-                                             object_size, &src_objnum,
-                                             &src_objoff, &src_objlen);
-               ceph_calc_file_object_mapping(&dst_ci->i_layout, dst_off,
-                                             object_size, &dst_objnum,
-                                             &dst_objoff, &dst_objlen);
-               ceph_oid_init(&src_oid);
-               ceph_oid_printf(&src_oid, "%llx.%08llx",
-                               src_ci->i_vino.ino, src_objnum);
-               ceph_oid_init(&dst_oid);
-               ceph_oid_printf(&dst_oid, "%llx.%08llx",
-                               dst_ci->i_vino.ino, dst_objnum);
-               /* Do an object remote copy */
-               err = ceph_osdc_copy_from(
-                       &src_fsc->client->osdc,
-                       src_ci->i_vino.snap, 0,
-                       &src_oid, &src_oloc,
-                       CEPH_OSD_OP_FLAG_FADVISE_SEQUENTIAL |
-                       CEPH_OSD_OP_FLAG_FADVISE_NOCACHE,
-                       &dst_oid, &dst_oloc,
-                       CEPH_OSD_OP_FLAG_FADVISE_SEQUENTIAL |
-                       CEPH_OSD_OP_FLAG_FADVISE_DONTNEED,
-                       dst_ci->i_truncate_seq, dst_ci->i_truncate_size,
-                       CEPH_OSD_COPY_FROM_FLAG_TRUNCATE_SEQ);
-               if (err) {
-                       if (err == -EOPNOTSUPP) {
-                               src_fsc->have_copy_from2 = false;
-                               pr_notice("OSDs don't support copy-from2; disabling copy offload\n");
-                       }
-                       dout("ceph_osdc_copy_from returned %d\n", err);
-                       if (!ret)
-                               ret = err;
-                       goto out_caps;
-               }
-               len -= object_size;
-               src_off += object_size;
-               dst_off += object_size;
-               ret += object_size;
-       }
 
-       if (len)
-               /* We still need one final local copy */
-               do_final_copy = true;
+       size = i_size_read(dst_inode);
+       bytes = ceph_do_objects_copy(src_ci, &src_off, dst_ci, &dst_off,
+                                    src_fsc, len, flags);
+       if (bytes <= 0) {
+               if (!ret)
+                       ret = bytes;
+               goto out_caps;
+       }
+       dout("Copied %zu bytes out of %zu\n", bytes, len);
+       len -= bytes;
+       ret += bytes;
 
        file_update_time(dst_file);
        inode_inc_iversion_raw(dst_inode);
 
-       if (endoff > size) {
-               int caps_flags = 0;
-
+       if (dst_off > size) {
                /* Let the MDS know about dst file size change */
-               if (ceph_quota_is_max_bytes_approaching(dst_inode, endoff))
-                       caps_flags |= CHECK_CAPS_NODELAY;
-               if (ceph_inode_set_size(dst_inode, endoff))
-                       caps_flags |= CHECK_CAPS_AUTHONLY;
-               if (caps_flags)
-                       ceph_check_caps(dst_ci, caps_flags, NULL);
+               if (ceph_inode_set_size(dst_inode, dst_off) ||
+                   ceph_quota_is_max_bytes_approaching(dst_inode, dst_off))
+                       ceph_check_caps(dst_ci, CHECK_CAPS_AUTHONLY, NULL);
        }
        /* Mark Fw dirty */
        spin_lock(&dst_ci->i_ceph_lock);
@@ -2165,15 +2432,18 @@ static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
 out_caps:
        put_rd_wr_caps(src_ci, src_got, dst_ci, dst_got);
 
-       if (do_final_copy) {
-               err = do_splice_direct(src_file, &src_off, dst_file,
-                                      &dst_off, len, flags);
-               if (err < 0) {
-                       dout("do_splice_direct returned %d\n", err);
-                       goto out;
-               }
-               len -= err;
-               ret += err;
+       /*
+        * Do the final manual copy if we still have some bytes left, unless
+        * there were errors in remote object copies (len >= object_size).
+        */
+       if (len && (len < src_ci->i_layout.object_size)) {
+               dout("Final partial copy of %zu bytes\n", len);
+               bytes = do_splice_direct(src_file, &src_off, dst_file,
+                                        &dst_off, len, flags);
+               if (bytes > 0)
+                       ret += bytes;
+               else
+                       dout("Failed partial copy (%zd)\n", bytes);
        }
 
 out:
index d01710a..7fef94f 100644 (file)
@@ -82,10 +82,14 @@ struct inode *ceph_get_snapdir(struct inode *parent)
        inode->i_mode = parent->i_mode;
        inode->i_uid = parent->i_uid;
        inode->i_gid = parent->i_gid;
+       inode->i_mtime = parent->i_mtime;
+       inode->i_ctime = parent->i_ctime;
+       inode->i_atime = parent->i_atime;
        inode->i_op = &ceph_snapdir_iops;
        inode->i_fop = &ceph_snapdir_fops;
        ci->i_snap_caps = CEPH_CAP_PIN; /* so we can open */
        ci->i_rbytes = 0;
+       ci->i_btime = ceph_inode(parent)->i_btime;
 
        if (inode->i_state & I_NEW)
                unlock_new_inode(inode);
@@ -447,6 +451,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
        ci->i_max_files = 0;
 
        memset(&ci->i_dir_layout, 0, sizeof(ci->i_dir_layout));
+       memset(&ci->i_cached_layout, 0, sizeof(ci->i_cached_layout));
        RCU_INIT_POINTER(ci->i_layout.pool_ns, NULL);
 
        ci->i_fragtree = RB_ROOT;
@@ -471,13 +476,13 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
        ci->i_prealloc_cap_flush = NULL;
        INIT_LIST_HEAD(&ci->i_cap_flush_list);
        init_waitqueue_head(&ci->i_cap_wq);
-       ci->i_hold_caps_min = 0;
        ci->i_hold_caps_max = 0;
        INIT_LIST_HEAD(&ci->i_cap_delay_list);
        INIT_LIST_HEAD(&ci->i_cap_snaps);
        ci->i_head_snapc = NULL;
        ci->i_snap_caps = 0;
 
+       ci->i_last_rd = ci->i_last_wr = jiffies - 3600 * HZ;
        for (i = 0; i < CEPH_FILE_MODE_BITS; i++)
                ci->i_nr_by_mode[i] = 0;
 
@@ -496,6 +501,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
        ci->i_rdcache_ref = 0;
        ci->i_wr_ref = 0;
        ci->i_wb_ref = 0;
+       ci->i_fx_ref = 0;
        ci->i_wrbuffer_ref = 0;
        ci->i_wrbuffer_ref_head = 0;
        atomic_set(&ci->i_filelock_ref, 0);
@@ -586,6 +592,7 @@ void ceph_evict_inode(struct inode *inode)
                ceph_buffer_put(ci->i_xattrs.prealloc_blob);
 
        ceph_put_string(rcu_dereference_raw(ci->i_layout.pool_ns));
+       ceph_put_string(rcu_dereference_raw(ci->i_cached_layout.pool_ns));
 }
 
 static inline blkcnt_t calc_inode_blocks(u64 size)
@@ -636,7 +643,7 @@ int ceph_fill_file_size(struct inode *inode, int issued,
                        if ((issued & (CEPH_CAP_FILE_CACHE|
                                       CEPH_CAP_FILE_BUFFER)) ||
                            mapping_mapped(inode->i_mapping) ||
-                           __ceph_caps_file_wanted(ci)) {
+                           __ceph_is_file_opened(ci)) {
                                ci->i_truncate_pending++;
                                queue_trunc = 1;
                        }
@@ -727,11 +734,11 @@ void ceph_fill_file_time(struct inode *inode, int issued,
  * Populate an inode based on info from mds.  May be called on new or
  * existing inodes.
  */
-static int fill_inode(struct inode *inode, struct page *locked_page,
-                     struct ceph_mds_reply_info_in *iinfo,
-                     struct ceph_mds_reply_dirfrag *dirinfo,
-                     struct ceph_mds_session *session, int cap_fmode,
-                     struct ceph_cap_reservation *caps_reservation)
+int ceph_fill_inode(struct inode *inode, struct page *locked_page,
+                   struct ceph_mds_reply_info_in *iinfo,
+                   struct ceph_mds_reply_dirfrag *dirinfo,
+                   struct ceph_mds_session *session, int cap_fmode,
+                   struct ceph_cap_reservation *caps_reservation)
 {
        struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
        struct ceph_mds_reply_inode *info = iinfo->in;
@@ -748,7 +755,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
        bool new_version = false;
        bool fill_inline = false;
 
-       dout("fill_inode %p ino %llx.%llx v %llu had %llu\n",
+       dout("%s %p ino %llx.%llx v %llu had %llu\n", __func__,
             inode, ceph_vinop(inode), le64_to_cpu(info->version),
             ci->i_version);
 
@@ -769,7 +776,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
        if (iinfo->xattr_len > 4) {
                xattr_blob = ceph_buffer_new(iinfo->xattr_len, GFP_NOFS);
                if (!xattr_blob)
-                       pr_err("fill_inode ENOMEM xattr blob %d bytes\n",
+                       pr_err("%s ENOMEM xattr blob %d bytes\n", __func__,
                               iinfo->xattr_len);
        }
 
@@ -932,8 +939,9 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                        spin_unlock(&ci->i_ceph_lock);
 
                        if (symlen != i_size_read(inode)) {
-                               pr_err("fill_inode %llx.%llx BAD symlink "
-                                       "size %lld\n", ceph_vinop(inode),
+                               pr_err("%s %llx.%llx BAD symlink "
+                                       "size %lld\n", __func__,
+                                       ceph_vinop(inode),
                                        i_size_read(inode));
                                i_size_write(inode, symlen);
                                inode->i_blocks = calc_inode_blocks(symlen);
@@ -957,7 +965,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                inode->i_fop = &ceph_dir_fops;
                break;
        default:
-               pr_err("fill_inode %llx.%llx BAD mode 0%o\n",
+               pr_err("%s %llx.%llx BAD mode 0%o\n", __func__,
                       ceph_vinop(inode), inode->i_mode);
        }
 
@@ -966,7 +974,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                if (ceph_snap(inode) == CEPH_NOSNAP) {
                        ceph_add_cap(inode, session,
                                     le64_to_cpu(info->cap.cap_id),
-                                    cap_fmode, info_caps,
+                                    info_caps,
                                     le32_to_cpu(info->cap.wanted),
                                     le32_to_cpu(info->cap.seq),
                                     le32_to_cpu(info->cap.mseq),
@@ -991,13 +999,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                        dout(" %p got snap_caps %s\n", inode,
                             ceph_cap_string(info_caps));
                        ci->i_snap_caps |= info_caps;
-                       if (cap_fmode >= 0)
-                               __ceph_get_fmode(ci, cap_fmode);
                }
-       } else if (cap_fmode >= 0) {
-               pr_warn("mds issued no caps on %llx.%llx\n",
-                          ceph_vinop(inode));
-               __ceph_get_fmode(ci, cap_fmode);
        }
 
        if (iinfo->inline_version > 0 &&
@@ -1009,6 +1011,13 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                        fill_inline = true;
        }
 
+       if (cap_fmode >= 0) {
+               if (!info_caps)
+                       pr_warn("mds issued no caps on %llx.%llx\n",
+                               ceph_vinop(inode));
+               __ceph_touch_fmode(ci, mdsc, cap_fmode);
+       }
+
        spin_unlock(&ci->i_ceph_lock);
 
        if (fill_inline)
@@ -1050,6 +1059,7 @@ static void __update_dentry_lease(struct inode *dir, struct dentry *dentry,
                                  struct ceph_mds_session **old_lease_session)
 {
        struct ceph_dentry_info *di = ceph_dentry(dentry);
+       unsigned mask = le16_to_cpu(lease->mask);
        long unsigned duration = le32_to_cpu(lease->duration_ms);
        long unsigned ttl = from_time + (duration * HZ) / 1000;
        long unsigned half_ttl = from_time + (duration * HZ / 2) / 1000;
@@ -1061,8 +1071,13 @@ static void __update_dentry_lease(struct inode *dir, struct dentry *dentry,
        if (ceph_snap(dir) != CEPH_NOSNAP)
                return;
 
+       if (mask & CEPH_LEASE_PRIMARY_LINK)
+               di->flags |= CEPH_DENTRY_PRIMARY_LINK;
+       else
+               di->flags &= ~CEPH_DENTRY_PRIMARY_LINK;
+
        di->lease_shared_gen = atomic_read(&ceph_inode(dir)->i_shared_gen);
-       if (duration == 0) {
+       if (!(mask & CEPH_LEASE_VALID)) {
                __ceph_dentry_dir_lease_touch(di);
                return;
        }
@@ -1239,10 +1254,9 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
                struct inode *dir = req->r_parent;
 
                if (dir) {
-                       err = fill_inode(dir, NULL,
-                                        &rinfo->diri, rinfo->dirfrag,
-                                        session, -1,
-                                        &req->r_caps_reservation);
+                       err = ceph_fill_inode(dir, NULL, &rinfo->diri,
+                                             rinfo->dirfrag, session, -1,
+                                             &req->r_caps_reservation);
                        if (err < 0)
                                goto done;
                } else {
@@ -1307,13 +1321,14 @@ retry_lookup:
                        goto done;
                }
 
-               err = fill_inode(in, req->r_locked_page, &rinfo->targeti, NULL,
-                               session,
+               err = ceph_fill_inode(in, req->r_locked_page, &rinfo->targeti,
+                               NULL, session,
                                (!test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags) &&
+                                !test_bit(CEPH_MDS_R_ASYNC, &req->r_req_flags) &&
                                 rinfo->head->result == 0) ?  req->r_fmode : -1,
                                &req->r_caps_reservation);
                if (err < 0) {
-                       pr_err("fill_inode badness %p %llx.%llx\n",
+                       pr_err("ceph_fill_inode badness %p %llx.%llx\n",
                                in, ceph_vinop(in));
                        if (in->i_state & I_NEW)
                                discard_new_inode(in);
@@ -1500,10 +1515,11 @@ static int readdir_prepopulate_inodes_only(struct ceph_mds_request *req,
                        dout("new_inode badness got %d\n", err);
                        continue;
                }
-               rc = fill_inode(in, NULL, &rde->inode, NULL, session,
-                               -1, &req->r_caps_reservation);
+               rc = ceph_fill_inode(in, NULL, &rde->inode, NULL, session,
+                                    -1, &req->r_caps_reservation);
                if (rc < 0) {
-                       pr_err("fill_inode badness on %p got %d\n", in, rc);
+                       pr_err("ceph_fill_inode badness on %p got %d\n",
+                              in, rc);
                        err = rc;
                        if (in->i_state & I_NEW) {
                                ihold(in);
@@ -1707,10 +1723,10 @@ retry_lookup:
                        }
                }
 
-               ret = fill_inode(in, NULL, &rde->inode, NULL, session,
-                                -1, &req->r_caps_reservation);
+               ret = ceph_fill_inode(in, NULL, &rde->inode, NULL, session,
+                                     -1, &req->r_caps_reservation);
                if (ret < 0) {
-                       pr_err("fill_inode badness on %p\n", in);
+                       pr_err("ceph_fill_inode badness on %p\n", in);
                        if (d_really_is_negative(dn)) {
                                /* avoid calling iput_final() in mds
                                 * dispatch threads */
@@ -1972,7 +1988,7 @@ retry:
        mutex_unlock(&ci->i_truncate_mutex);
 
        if (wrbuffer_refs == 0)
-               ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
+               ceph_check_caps(ci, 0, NULL);
 
        wake_up_all(&ci->i_cap_wq);
 }
index c90f03b..6e061bf 100644 (file)
@@ -243,11 +243,13 @@ static long ceph_ioctl_lazyio(struct file *file)
        struct ceph_file_info *fi = file->private_data;
        struct inode *inode = file_inode(file);
        struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
 
        if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) {
                spin_lock(&ci->i_ceph_lock);
                fi->fmode |= CEPH_FILE_MODE_LAZY;
                ci->i_nr_by_mode[ffs(CEPH_FILE_MODE_LAZY)]++;
+               __ceph_touch_fmode(ci, mdsc, fi->fmode);
                spin_unlock(&ci->i_ceph_lock);
                dout("ioctl_layzio: file %p marked lazy\n", file);
 
index 544e9e8..d6b9166 100644 (file)
@@ -210,6 +210,21 @@ static int ceph_lock_wait_for_completion(struct ceph_mds_client *mdsc,
        return 0;
 }
 
+static int try_unlock_file(struct file *file, struct file_lock *fl)
+{
+       int err;
+       unsigned int orig_flags = fl->fl_flags;
+       fl->fl_flags |= FL_EXISTS;
+       err = locks_lock_file_wait(file, fl);
+       fl->fl_flags = orig_flags;
+       if (err == -ENOENT) {
+               if (!(orig_flags & FL_EXISTS))
+                       err = 0;
+               return err;
+       }
+       return 1;
+}
+
 /**
  * Attempt to set an fcntl lock.
  * For now, this just goes away to the server. Later it may be more awesome.
@@ -255,9 +270,15 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
        else
                lock_cmd = CEPH_LOCK_UNLOCK;
 
+       if (op == CEPH_MDS_OP_SETFILELOCK && F_UNLCK == fl->fl_type) {
+               err = try_unlock_file(file, fl);
+               if (err <= 0)
+                       return err;
+       }
+
        err = ceph_lock_message(CEPH_LOCK_FCNTL, op, inode, lock_cmd, wait, fl);
        if (!err) {
-               if (op == CEPH_MDS_OP_SETFILELOCK) {
+               if (op == CEPH_MDS_OP_SETFILELOCK && F_UNLCK != fl->fl_type) {
                        dout("mds locked, locking locally\n");
                        err = posix_lock_file(file, fl, NULL);
                        if (err) {
@@ -311,9 +332,15 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
        else
                lock_cmd = CEPH_LOCK_UNLOCK;
 
+       if (F_UNLCK == fl->fl_type) {
+               err = try_unlock_file(file, fl);
+               if (err <= 0)
+                       return err;
+       }
+
        err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK,
                                inode, lock_cmd, wait, fl);
-       if (!err) {
+       if (!err && F_UNLCK != fl->fl_type) {
                err = locks_lock_file_wait(file, fl);
                if (err) {
                        ceph_lock_message(CEPH_LOCK_FLOCK,
index bbbbddf..486f91f 100644 (file)
@@ -415,21 +415,121 @@ bad:
        return -EIO;
 }
 
+
+#if BITS_PER_LONG == 64
+
+#define DELEGATED_INO_AVAILABLE                xa_mk_value(1)
+
+static int ceph_parse_deleg_inos(void **p, void *end,
+                                struct ceph_mds_session *s)
+{
+       u32 sets;
+
+       ceph_decode_32_safe(p, end, sets, bad);
+       dout("got %u sets of delegated inodes\n", sets);
+       while (sets--) {
+               u64 start, len, ino;
+
+               ceph_decode_64_safe(p, end, start, bad);
+               ceph_decode_64_safe(p, end, len, bad);
+               while (len--) {
+                       int err = xa_insert(&s->s_delegated_inos, ino = start++,
+                                           DELEGATED_INO_AVAILABLE,
+                                           GFP_KERNEL);
+                       if (!err) {
+                               dout("added delegated inode 0x%llx\n",
+                                    start - 1);
+                       } else if (err == -EBUSY) {
+                               pr_warn("ceph: MDS delegated inode 0x%llx more than once.\n",
+                                       start - 1);
+                       } else {
+                               return err;
+                       }
+               }
+       }
+       return 0;
+bad:
+       return -EIO;
+}
+
+u64 ceph_get_deleg_ino(struct ceph_mds_session *s)
+{
+       unsigned long ino;
+       void *val;
+
+       xa_for_each(&s->s_delegated_inos, ino, val) {
+               val = xa_erase(&s->s_delegated_inos, ino);
+               if (val == DELEGATED_INO_AVAILABLE)
+                       return ino;
+       }
+       return 0;
+}
+
+int ceph_restore_deleg_ino(struct ceph_mds_session *s, u64 ino)
+{
+       return xa_insert(&s->s_delegated_inos, ino, DELEGATED_INO_AVAILABLE,
+                        GFP_KERNEL);
+}
+#else /* BITS_PER_LONG == 64 */
+/*
+ * FIXME: xarrays can't handle 64-bit indexes on a 32-bit arch. For now, just
+ * ignore delegated_inos on 32 bit arch. Maybe eventually add xarrays for top
+ * and bottom words?
+ */
+static int ceph_parse_deleg_inos(void **p, void *end,
+                                struct ceph_mds_session *s)
+{
+       u32 sets;
+
+       ceph_decode_32_safe(p, end, sets, bad);
+       if (sets)
+               ceph_decode_skip_n(p, end, sets * 2 * sizeof(__le64), bad);
+       return 0;
+bad:
+       return -EIO;
+}
+
+u64 ceph_get_deleg_ino(struct ceph_mds_session *s)
+{
+       return 0;
+}
+
+int ceph_restore_deleg_ino(struct ceph_mds_session *s, u64 ino)
+{
+       return 0;
+}
+#endif /* BITS_PER_LONG == 64 */
+
 /*
  * parse create results
  */
 static int parse_reply_info_create(void **p, void *end,
                                  struct ceph_mds_reply_info_parsed *info,
-                                 u64 features)
+                                 u64 features, struct ceph_mds_session *s)
 {
+       int ret;
+
        if (features == (u64)-1 ||
            (features & CEPH_FEATURE_REPLY_CREATE_INODE)) {
-               /* Malformed reply? */
                if (*p == end) {
+                       /* Malformed reply? */
                        info->has_create_ino = false;
-               } else {
+               } else if (test_bit(CEPHFS_FEATURE_DELEG_INO, &s->s_features)) {
+                       u8 struct_v, struct_compat;
+                       u32 len;
+
                        info->has_create_ino = true;
+                       ceph_decode_8_safe(p, end, struct_v, bad);
+                       ceph_decode_8_safe(p, end, struct_compat, bad);
+                       ceph_decode_32_safe(p, end, len, bad);
+                       ceph_decode_64_safe(p, end, info->ino, bad);
+                       ret = ceph_parse_deleg_inos(p, end, s);
+                       if (ret)
+                               return ret;
+               } else {
+                       /* legacy */
                        ceph_decode_64_safe(p, end, info->ino, bad);
+                       info->has_create_ino = true;
                }
        } else {
                if (*p != end)
@@ -448,7 +548,7 @@ bad:
  */
 static int parse_reply_info_extra(void **p, void *end,
                                  struct ceph_mds_reply_info_parsed *info,
-                                 u64 features)
+                                 u64 features, struct ceph_mds_session *s)
 {
        u32 op = le32_to_cpu(info->head->op);
 
@@ -457,7 +557,7 @@ static int parse_reply_info_extra(void **p, void *end,
        else if (op == CEPH_MDS_OP_READDIR || op == CEPH_MDS_OP_LSSNAP)
                return parse_reply_info_readdir(p, end, info, features);
        else if (op == CEPH_MDS_OP_CREATE)
-               return parse_reply_info_create(p, end, info, features);
+               return parse_reply_info_create(p, end, info, features, s);
        else
                return -EIO;
 }
@@ -465,7 +565,7 @@ static int parse_reply_info_extra(void **p, void *end,
 /*
  * parse entire mds reply
  */
-static int parse_reply_info(struct ceph_msg *msg,
+static int parse_reply_info(struct ceph_mds_session *s, struct ceph_msg *msg,
                            struct ceph_mds_reply_info_parsed *info,
                            u64 features)
 {
@@ -490,7 +590,7 @@ static int parse_reply_info(struct ceph_msg *msg,
        ceph_decode_32_safe(&p, end, len, bad);
        if (len > 0) {
                ceph_decode_need(&p, end, len, bad);
-               err = parse_reply_info_extra(&p, p+len, info, features);
+               err = parse_reply_info_extra(&p, p+len, info, features, s);
                if (err < 0)
                        goto out_bad;
        }
@@ -558,6 +658,7 @@ void ceph_put_mds_session(struct ceph_mds_session *s)
        if (refcount_dec_and_test(&s->s_ref)) {
                if (s->s_auth.authorizer)
                        ceph_auth_destroy_authorizer(s->s_auth.authorizer);
+               xa_destroy(&s->s_delegated_inos);
                kfree(s);
        }
 }
@@ -645,6 +746,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
        refcount_set(&s->s_ref, 1);
        INIT_LIST_HEAD(&s->s_waiting);
        INIT_LIST_HEAD(&s->s_unsafe);
+       xa_init(&s->s_delegated_inos);
        s->s_num_cap_releases = 0;
        s->s_cap_reconnect = 0;
        s->s_cap_iterator = NULL;
@@ -699,6 +801,7 @@ void ceph_mdsc_release_request(struct kref *kref)
        struct ceph_mds_request *req = container_of(kref,
                                                    struct ceph_mds_request,
                                                    r_kref);
+       ceph_mdsc_release_dir_caps(req);
        destroy_reply_info(&req->r_reply_info);
        if (req->r_request)
                ceph_msg_put(req->r_request);
@@ -736,7 +839,7 @@ void ceph_mdsc_release_request(struct kref *kref)
        put_request_session(req);
        ceph_unreserve_caps(req->r_mdsc, &req->r_caps_reservation);
        WARN_ON_ONCE(!list_empty(&req->r_wait));
-       kfree(req);
+       kmem_cache_free(ceph_mds_request_cachep, req);
 }
 
 DEFINE_RB_FUNCS(request, struct ceph_mds_request, r_tid, r_node)
@@ -793,8 +896,13 @@ static void __register_request(struct ceph_mds_client *mdsc,
                mdsc->oldest_tid = req->r_tid;
 
        if (dir) {
+               struct ceph_inode_info *ci = ceph_inode(dir);
+
                ihold(dir);
                req->r_unsafe_dir = dir;
+               spin_lock(&ci->i_unsafe_lock);
+               list_add_tail(&req->r_unsafe_dir_item, &ci->i_unsafe_dirops);
+               spin_unlock(&ci->i_unsafe_lock);
        }
 }
 
@@ -822,8 +930,7 @@ static void __unregister_request(struct ceph_mds_client *mdsc,
 
        erase_request(&mdsc->request_tree, req);
 
-       if (req->r_unsafe_dir  &&
-           test_bit(CEPH_MDS_R_GOT_UNSAFE, &req->r_req_flags)) {
+       if (req->r_unsafe_dir) {
                struct ceph_inode_info *ci = ceph_inode(req->r_unsafe_dir);
                spin_lock(&ci->i_unsafe_lock);
                list_del_init(&req->r_unsafe_dir_item);
@@ -1407,8 +1514,6 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
        dout("removing cap %p, ci is %p, inode is %p\n",
             cap, ci, &ci->vfs_inode);
        spin_lock(&ci->i_ceph_lock);
-       if (cap->mds_wanted | cap->issued)
-               ci->i_ceph_flags |= CEPH_I_CAP_DROPPED;
        __ceph_remove_cap(cap, false);
        if (!ci->i_auth_cap) {
                struct ceph_cap_flush *cf;
@@ -1574,9 +1679,6 @@ static int wake_up_session_cb(struct inode *inode, struct ceph_cap *cap,
                        /* mds did not re-issue stale cap */
                        spin_lock(&ci->i_ceph_lock);
                        cap->issued = cap->implemented = CEPH_CAP_PIN;
-                       /* make sure mds knows what we want */
-                       if (__ceph_caps_file_wanted(ci) & ~cap->mds_wanted)
-                               ci->i_ceph_flags |= CEPH_I_CAP_DROPPED;
                        spin_unlock(&ci->i_ceph_lock);
                }
        } else if (ev == FORCE_RO) {
@@ -1772,7 +1874,8 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg)
        }
        /* The inode has cached pages, but it's no longer used.
         * we can safely drop it */
-       if (wanted == 0 && used == CEPH_CAP_FILE_CACHE &&
+       if (S_ISREG(inode->i_mode) &&
+           wanted == 0 && used == CEPH_CAP_FILE_CACHE &&
            !(oissued & CEPH_CAP_FILE_CACHE)) {
          used = 0;
          oissued = 0;
@@ -2089,8 +2192,9 @@ int ceph_alloc_readdir_reply_buffer(struct ceph_mds_request *req,
 struct ceph_mds_request *
 ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode)
 {
-       struct ceph_mds_request *req = kzalloc(sizeof(*req), GFP_NOFS);
+       struct ceph_mds_request *req;
 
+       req = kmem_cache_zalloc(ceph_mds_request_cachep, GFP_NOFS);
        if (!req)
                return ERR_PTR(-ENOMEM);
 
@@ -2368,7 +2472,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
        head->op = cpu_to_le32(req->r_op);
        head->caller_uid = cpu_to_le32(from_kuid(&init_user_ns, req->r_uid));
        head->caller_gid = cpu_to_le32(from_kgid(&init_user_ns, req->r_gid));
-       head->ino = 0;
+       head->ino = cpu_to_le64(req->r_deleg_ino);
        head->args = req->r_args;
 
        ceph_encode_filepath(&p, end, ino1, path1);
@@ -2382,7 +2486,8 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
        if (req->r_inode_drop)
                releases += ceph_encode_inode_release(&p,
                      req->r_inode ? req->r_inode : d_inode(req->r_dentry),
-                     mds, req->r_inode_drop, req->r_inode_unless, 0);
+                     mds, req->r_inode_drop, req->r_inode_unless,
+                     req->r_op == CEPH_MDS_OP_READDIR);
        if (req->r_dentry_drop)
                releases += ceph_encode_dentry_release(&p, req->r_dentry,
                                req->r_parent, mds, req->r_dentry_drop,
@@ -2522,12 +2627,13 @@ static int __prepare_send_request(struct ceph_mds_client *mdsc,
        rhead->oldest_client_tid = cpu_to_le64(__get_oldest_tid(mdsc));
        if (test_bit(CEPH_MDS_R_GOT_UNSAFE, &req->r_req_flags))
                flags |= CEPH_MDS_FLAG_REPLAY;
+       if (test_bit(CEPH_MDS_R_ASYNC, &req->r_req_flags))
+               flags |= CEPH_MDS_FLAG_ASYNC;
        if (req->r_parent)
                flags |= CEPH_MDS_FLAG_WANT_DENTRY;
        rhead->flags = cpu_to_le32(flags);
        rhead->num_fwd = req->r_num_fwd;
        rhead->num_retry = req->r_attempts - 1;
-       rhead->ino = 0;
 
        dout(" r_parent = %p\n", req->r_parent);
        return 0;
@@ -2573,7 +2679,7 @@ static void __do_request(struct ceph_mds_client *mdsc,
        if (req->r_timeout &&
            time_after_eq(jiffies, req->r_started + req->r_timeout)) {
                dout("do_request timed out\n");
-               err = -EIO;
+               err = -ETIMEDOUT;
                goto finish;
        }
        if (READ_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) {
@@ -2605,6 +2711,10 @@ static void __do_request(struct ceph_mds_client *mdsc,
        mds = __choose_mds(mdsc, req, &random);
        if (mds < 0 ||
            ceph_mdsmap_get_state(mdsc->mdsmap, mds) < CEPH_MDS_STATE_ACTIVE) {
+               if (test_bit(CEPH_MDS_R_ASYNC, &req->r_req_flags)) {
+                       err = -EJUKEBOX;
+                       goto finish;
+               }
                dout("do_request no mds or not active, waiting for map\n");
                list_add(&req->r_wait, &mdsc->waiting_for_map);
                return;
@@ -2629,6 +2739,15 @@ static void __do_request(struct ceph_mds_client *mdsc,
                        err = -EACCES;
                        goto out_session;
                }
+               /*
+                * We cannot queue async requests since the caps and delegated
+                * inodes are bound to the session. Just return -EJUKEBOX and
+                * let the caller retry a sync request in that case.
+                */
+               if (test_bit(CEPH_MDS_R_ASYNC, &req->r_req_flags)) {
+                       err = -EJUKEBOX;
+                       goto out_session;
+               }
                if (session->s_state == CEPH_MDS_SESSION_NEW ||
                    session->s_state == CEPH_MDS_SESSION_CLOSING) {
                        __open_session(mdsc, session);
@@ -2709,19 +2828,43 @@ static void kick_requests(struct ceph_mds_client *mdsc, int mds)
 int ceph_mdsc_submit_request(struct ceph_mds_client *mdsc, struct inode *dir,
                              struct ceph_mds_request *req)
 {
-       int err;
+       int err = 0;
 
        /* take CAP_PIN refs for r_inode, r_parent, r_old_dentry */
        if (req->r_inode)
                ceph_get_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN);
        if (req->r_parent) {
-               ceph_get_cap_refs(ceph_inode(req->r_parent), CEPH_CAP_PIN);
+               struct ceph_inode_info *ci = ceph_inode(req->r_parent);
+               int fmode = (req->r_op & CEPH_MDS_OP_WRITE) ?
+                           CEPH_FILE_MODE_WR : CEPH_FILE_MODE_RD;
+               spin_lock(&ci->i_ceph_lock);
+               ceph_take_cap_refs(ci, CEPH_CAP_PIN, false);
+               __ceph_touch_fmode(ci, mdsc, fmode);
+               spin_unlock(&ci->i_ceph_lock);
                ihold(req->r_parent);
        }
        if (req->r_old_dentry_dir)
                ceph_get_cap_refs(ceph_inode(req->r_old_dentry_dir),
                                  CEPH_CAP_PIN);
 
+       if (req->r_inode) {
+               err = ceph_wait_on_async_create(req->r_inode);
+               if (err) {
+                       dout("%s: wait for async create returned: %d\n",
+                            __func__, err);
+                       return err;
+               }
+       }
+
+       if (!err && req->r_old_inode) {
+               err = ceph_wait_on_async_create(req->r_old_inode);
+               if (err) {
+                       dout("%s: wait for async create returned: %d\n",
+                            __func__, err);
+                       return err;
+               }
+       }
+
        dout("submit_request on %p for inode %p\n", req, dir);
        mutex_lock(&mdsc->mutex);
        __register_request(mdsc, req, dir);
@@ -2747,7 +2890,7 @@ static int ceph_mdsc_wait_request(struct ceph_mds_client *mdsc,
                if (timeleft > 0)
                        err = 0;
                else if (!timeleft)
-                       err = -EIO;  /* timed out */
+                       err = -ETIMEDOUT;  /* timed out */
                else
                        err = timeleft;  /* killed */
        }
@@ -2935,22 +3078,14 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
        } else {
                set_bit(CEPH_MDS_R_GOT_UNSAFE, &req->r_req_flags);
                list_add_tail(&req->r_unsafe_item, &req->r_session->s_unsafe);
-               if (req->r_unsafe_dir) {
-                       struct ceph_inode_info *ci =
-                                       ceph_inode(req->r_unsafe_dir);
-                       spin_lock(&ci->i_unsafe_lock);
-                       list_add_tail(&req->r_unsafe_dir_item,
-                                     &ci->i_unsafe_dirops);
-                       spin_unlock(&ci->i_unsafe_lock);
-               }
        }
 
        dout("handle_reply tid %lld result %d\n", tid, result);
        rinfo = &req->r_reply_info;
        if (test_bit(CEPHFS_FEATURE_REPLY_ENCODING, &session->s_features))
-               err = parse_reply_info(msg, rinfo, (u64)-1);
+               err = parse_reply_info(session, msg, rinfo, (u64)-1);
        else
-               err = parse_reply_info(msg, rinfo, session->s_con.peer_features);
+               err = parse_reply_info(session, msg, rinfo, session->s_con.peer_features);
        mutex_unlock(&mdsc->mutex);
 
        mutex_lock(&session->s_mutex);
@@ -3249,6 +3384,17 @@ bad:
        return;
 }
 
+void ceph_mdsc_release_dir_caps(struct ceph_mds_request *req)
+{
+       int dcaps;
+
+       dcaps = xchg(&req->r_dir_caps, 0);
+       if (dcaps) {
+               dout("releasing r_dir_caps=%s\n", ceph_cap_string(dcaps));
+               ceph_put_cap_refs(ceph_inode(req->r_parent), dcaps);
+       }
+}
+
 /*
  * called under session->mutex.
  */
@@ -3276,9 +3422,14 @@ static void replay_unsafe_requests(struct ceph_mds_client *mdsc,
                        continue;
                if (req->r_attempts == 0)
                        continue; /* only old requests */
-               if (req->r_session &&
-                   req->r_session->s_mds == session->s_mds)
-                       __send_request(mdsc, session, req, true);
+               if (!req->r_session)
+                       continue;
+               if (req->r_session->s_mds != session->s_mds)
+                       continue;
+
+               ceph_mdsc_release_dir_caps(req);
+
+               __send_request(mdsc, session, req, true);
        }
        mutex_unlock(&mdsc->mutex);
 }
@@ -3362,7 +3513,7 @@ fail_msg:
 /*
  * Encode information about a cap for a reconnect with the MDS.
  */
-static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
+static int reconnect_caps_cb(struct inode *inode, struct ceph_cap *cap,
                          void *arg)
 {
        union {
@@ -3385,6 +3536,15 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
        cap->mseq = 0;       /* and migrate_seq */
        cap->cap_gen = cap->session->s_cap_gen;
 
+       /* These are lost when the session goes away */
+       if (S_ISDIR(inode->i_mode)) {
+               if (cap->issued & CEPH_CAP_DIR_CREATE) {
+                       ceph_put_string(rcu_dereference_raw(ci->i_cached_layout.pool_ns));
+                       memset(&ci->i_cached_layout, 0, sizeof(ci->i_cached_layout));
+               }
+               cap->issued &= ~CEPH_CAP_ANY_DIR_OPS;
+       }
+
        if (recon_state->msg_version >= 2) {
                rec.v2.cap_id = cpu_to_le64(cap->cap_id);
                rec.v2.wanted = cpu_to_le32(__ceph_caps_wanted(ci));
@@ -3626,6 +3786,8 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
        if (!reply)
                goto fail_nomsg;
 
+       xa_destroy(&session->s_delegated_inos);
+
        mutex_lock(&session->s_mutex);
        session->s_state = CEPH_MDS_SESSION_RECONNECTING;
        session->s_seq = 0;
@@ -3681,7 +3843,7 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
                recon_state.msg_version = 2;
        }
        /* trsaverse this session's caps */
-       err = ceph_iterate_session_caps(session, encode_caps_cb, &recon_state);
+       err = ceph_iterate_session_caps(session, reconnect_caps_cb, &recon_state);
 
        spin_lock(&session->s_cap_lock);
        session->s_cap_reconnect = 0;
index 27a7446..903d9ed 100644 (file)
@@ -23,8 +23,9 @@ enum ceph_feature_type {
        CEPHFS_FEATURE_RECLAIM_CLIENT,
        CEPHFS_FEATURE_LAZY_CAP_WANTED,
        CEPHFS_FEATURE_MULTI_RECONNECT,
+       CEPHFS_FEATURE_DELEG_INO,
 
-       CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_MULTI_RECONNECT,
+       CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_DELEG_INO,
 };
 
 /*
@@ -37,6 +38,7 @@ enum ceph_feature_type {
        CEPHFS_FEATURE_REPLY_ENCODING,          \
        CEPHFS_FEATURE_LAZY_CAP_WANTED,         \
        CEPHFS_FEATURE_MULTI_RECONNECT,         \
+       CEPHFS_FEATURE_DELEG_INO,               \
                                                \
        CEPHFS_FEATURE_MAX,                     \
 }
@@ -201,6 +203,7 @@ struct ceph_mds_session {
 
        struct list_head  s_waiting;  /* waiting requests */
        struct list_head  s_unsafe;   /* unsafe requests */
+       struct xarray     s_delegated_inos;
 };
 
 /*
@@ -255,6 +258,7 @@ struct ceph_mds_request {
 #define CEPH_MDS_R_GOT_RESULT          (5) /* got a result */
 #define CEPH_MDS_R_DID_PREPOPULATE     (6) /* prepopulated readdir */
 #define CEPH_MDS_R_PARENT_LOCKED       (7) /* is r_parent->i_rwsem wlocked? */
+#define CEPH_MDS_R_ASYNC               (8) /* async request */
        unsigned long   r_req_flags;
 
        struct mutex r_fill_mutex;
@@ -263,6 +267,7 @@ struct ceph_mds_request {
        int r_fmode;        /* file mode, if expecting cap */
        kuid_t r_uid;
        kgid_t r_gid;
+       int r_request_release_offset;
        struct timespec64 r_stamp;
 
        /* for choosing which mds to send this request to */
@@ -280,12 +285,16 @@ struct ceph_mds_request {
        int r_old_inode_drop, r_old_inode_unless;
 
        struct ceph_msg  *r_request;  /* original request */
-       int r_request_release_offset;
        struct ceph_msg  *r_reply;
        struct ceph_mds_reply_info_parsed r_reply_info;
-       struct page *r_locked_page;
        int r_err;
 
+
+       struct page *r_locked_page;
+       int r_dir_caps;
+       int r_num_caps;
+       u32               r_readdir_offset;
+
        unsigned long r_timeout;  /* optional.  jiffies, 0 is "wait forever" */
        unsigned long r_started;  /* start time to measure timeout against */
        unsigned long r_request_started; /* start time for mds request only,
@@ -304,6 +313,7 @@ struct ceph_mds_request {
        int               r_num_fwd;    /* number of forward attempts */
        int               r_resend_mds; /* mds to resend to next, if any*/
        u32               r_sent_on_mseq; /* cap mseq request was sent at*/
+       u64               r_deleg_ino;
 
        struct list_head  r_wait;
        struct completion r_completion;
@@ -315,10 +325,8 @@ struct ceph_mds_request {
        long long         r_dir_release_cnt;
        long long         r_dir_ordered_cnt;
        int               r_readdir_cache_idx;
-       u32               r_readdir_offset;
 
        struct ceph_cap_reservation r_caps_reservation;
-       int r_num_caps;
 };
 
 struct ceph_pool_perm {
@@ -488,6 +496,7 @@ extern int ceph_mdsc_submit_request(struct ceph_mds_client *mdsc,
 extern int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
                                struct inode *dir,
                                struct ceph_mds_request *req);
+extern void ceph_mdsc_release_dir_caps(struct ceph_mds_request *req);
 static inline void ceph_mdsc_get_request(struct ceph_mds_request *req)
 {
        kref_get(&req->r_kref);
@@ -512,7 +521,7 @@ extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc);
 
 static inline void ceph_mdsc_free_path(char *path, int len)
 {
-       if (path)
+       if (!IS_ERR_OR_NULL(path))
                __putname(path - (PATH_MAX - 1 - len));
 }
 
@@ -537,4 +546,15 @@ extern void ceph_mdsc_open_export_target_sessions(struct ceph_mds_client *mdsc,
 extern int ceph_trim_caps(struct ceph_mds_client *mdsc,
                          struct ceph_mds_session *session,
                          int max_caps);
+
+static inline int ceph_wait_on_async_create(struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+
+       return wait_on_bit(&ci->i_ceph_flags, CEPH_ASYNC_CREATE_BIT,
+                          TASK_INTERRUPTIBLE);
+}
+
+extern u64 ceph_get_deleg_ino(struct ceph_mds_session *session);
+extern int ceph_restore_deleg_ino(struct ceph_mds_session *session, u64 ino);
 #endif
index c7f1506..c9784eb 100644 (file)
@@ -155,6 +155,7 @@ enum {
        Opt_acl,
        Opt_quotadf,
        Opt_copyfrom,
+       Opt_wsync,
 };
 
 enum ceph_recover_session_mode {
@@ -194,6 +195,7 @@ static const struct fs_parameter_spec ceph_mount_parameters[] = {
        fsparam_string  ("snapdirname",                 Opt_snapdirname),
        fsparam_string  ("source",                      Opt_source),
        fsparam_u32     ("wsize",                       Opt_wsize),
+       fsparam_flag_no ("wsync",                       Opt_wsync),
        {}
 };
 
@@ -444,6 +446,12 @@ static int ceph_parse_mount_param(struct fs_context *fc,
                        fc->sb_flags &= ~SB_POSIXACL;
                }
                break;
+       case Opt_wsync:
+               if (!result.negated)
+                       fsopt->flags &= ~CEPH_MOUNT_OPT_ASYNC_DIROPS;
+               else
+                       fsopt->flags |= CEPH_MOUNT_OPT_ASYNC_DIROPS;
+               break;
        default:
                BUG();
        }
@@ -567,6 +575,9 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
        if (fsopt->flags & CEPH_MOUNT_OPT_CLEANRECOVER)
                seq_show_option(m, "recover_session", "clean");
 
+       if (fsopt->flags & CEPH_MOUNT_OPT_ASYNC_DIROPS)
+               seq_puts(m, ",nowsync");
+
        if (fsopt->wsize != CEPH_MAX_WRITE_SIZE)
                seq_printf(m, ",wsize=%u", fsopt->wsize);
        if (fsopt->rsize != CEPH_MAX_READ_SIZE)
@@ -729,6 +740,7 @@ struct kmem_cache *ceph_cap_flush_cachep;
 struct kmem_cache *ceph_dentry_cachep;
 struct kmem_cache *ceph_file_cachep;
 struct kmem_cache *ceph_dir_file_cachep;
+struct kmem_cache *ceph_mds_request_cachep;
 
 static void ceph_inode_init_once(void *foo)
 {
@@ -769,6 +781,10 @@ static int __init init_caches(void)
        if (!ceph_dir_file_cachep)
                goto bad_dir_file;
 
+       ceph_mds_request_cachep = KMEM_CACHE(ceph_mds_request, SLAB_MEM_SPREAD);
+       if (!ceph_mds_request_cachep)
+               goto bad_mds_req;
+
        error = ceph_fscache_register();
        if (error)
                goto bad_fscache;
@@ -776,6 +792,8 @@ static int __init init_caches(void)
        return 0;
 
 bad_fscache:
+       kmem_cache_destroy(ceph_mds_request_cachep);
+bad_mds_req:
        kmem_cache_destroy(ceph_dir_file_cachep);
 bad_dir_file:
        kmem_cache_destroy(ceph_file_cachep);
@@ -804,6 +822,7 @@ static void destroy_caches(void)
        kmem_cache_destroy(ceph_dentry_cachep);
        kmem_cache_destroy(ceph_file_cachep);
        kmem_cache_destroy(ceph_dir_file_cachep);
+       kmem_cache_destroy(ceph_mds_request_cachep);
 
        ceph_fscache_unregister();
 }
@@ -1107,6 +1126,15 @@ static void ceph_free_fc(struct fs_context *fc)
 
 static int ceph_reconfigure_fc(struct fs_context *fc)
 {
+       struct ceph_parse_opts_ctx *pctx = fc->fs_private;
+       struct ceph_mount_options *fsopt = pctx->opts;
+       struct ceph_fs_client *fsc = ceph_sb_to_client(fc->root->d_sb);
+
+       if (fsopt->flags & CEPH_MOUNT_OPT_ASYNC_DIROPS)
+               ceph_set_mount_opt(fsc, ASYNC_DIROPS);
+       else
+               ceph_clear_mount_opt(fsc, ASYNC_DIROPS);
+
        sync_filesystem(fc->root->d_sb);
        return 0;
 }
index 037cdfb..60aac3a 100644 (file)
 #define CEPH_MOUNT_OPT_MOUNTWAIT       (1<<12) /* mount waits if no mds is up */
 #define CEPH_MOUNT_OPT_NOQUOTADF       (1<<13) /* no root dir quota in statfs */
 #define CEPH_MOUNT_OPT_NOCOPYFROM      (1<<14) /* don't use RADOS 'copy-from' op */
+#define CEPH_MOUNT_OPT_ASYNC_DIROPS    (1<<15) /* allow async directory ops */
 
 #define CEPH_MOUNT_OPT_DEFAULT                 \
        (CEPH_MOUNT_OPT_DCACHE |                \
         CEPH_MOUNT_OPT_NOCOPYFROM)
 
 #define ceph_set_mount_opt(fsc, opt) \
-       (fsc)->mount_options->flags |= CEPH_MOUNT_OPT_##opt;
+       (fsc)->mount_options->flags |= CEPH_MOUNT_OPT_##opt
+#define ceph_clear_mount_opt(fsc, opt) \
+       (fsc)->mount_options->flags &= ~CEPH_MOUNT_OPT_##opt
 #define ceph_test_mount_opt(fsc, opt) \
        (!!((fsc)->mount_options->flags & CEPH_MOUNT_OPT_##opt))
 
@@ -170,9 +173,9 @@ struct ceph_cap {
        struct list_head caps_item;
 };
 
-#define CHECK_CAPS_NODELAY    1  /* do not delay any further */
-#define CHECK_CAPS_AUTHONLY   2  /* only check auth cap */
-#define CHECK_CAPS_FLUSH      4  /* flush any dirty caps */
+#define CHECK_CAPS_AUTHONLY   1  /* only check auth cap */
+#define CHECK_CAPS_FLUSH      2  /* flush any dirty caps */
+#define CHECK_CAPS_NOINVAL    4  /* don't invalidate pagecache */
 
 struct ceph_cap_flush {
        u64 tid;
@@ -284,6 +287,7 @@ struct ceph_dentry_info {
 #define CEPH_DENTRY_REFERENCED         1
 #define CEPH_DENTRY_LEASE_LIST         2
 #define CEPH_DENTRY_SHRINK_LIST                4
+#define CEPH_DENTRY_PRIMARY_LINK       8
 
 struct ceph_inode_xattrs_info {
        /*
@@ -315,13 +319,14 @@ struct ceph_inode_info {
        u64 i_inline_version;
        u32 i_time_warp_seq;
 
-       unsigned i_ceph_flags;
+       unsigned long i_ceph_flags;
        atomic64_t i_release_count;
        atomic64_t i_ordered_count;
        atomic64_t i_complete_seq[2];
 
        struct ceph_dir_layout i_dir_layout;
        struct ceph_file_layout i_layout;
+       struct ceph_file_layout i_cached_layout;        // for async creates
        char *i_symlink;
 
        /* for dirs */
@@ -352,7 +357,6 @@ struct ceph_inode_info {
        struct ceph_cap_flush *i_prealloc_cap_flush;
        struct list_head i_cap_flush_list;
        wait_queue_head_t i_cap_wq;      /* threads waiting on a capability */
-       unsigned long i_hold_caps_min; /* jiffies */
        unsigned long i_hold_caps_max; /* jiffies */
        struct list_head i_cap_delay_list;  /* for delayed cap release to mds */
        struct ceph_cap_reservation i_cap_migration_resv;
@@ -361,6 +365,8 @@ struct ceph_inode_info {
                                                    dirty|flushing caps */
        unsigned i_snap_caps;           /* cap bits for snapped files */
 
+       unsigned long i_last_rd;
+       unsigned long i_last_wr;
        int i_nr_by_mode[CEPH_FILE_MODE_BITS];  /* open file counts */
 
        struct mutex i_truncate_mutex;
@@ -375,7 +381,7 @@ struct ceph_inode_info {
 
        /* held references to caps */
        int i_pin_ref;
-       int i_rd_ref, i_rdcache_ref, i_wr_ref, i_wb_ref;
+       int i_rd_ref, i_rdcache_ref, i_wr_ref, i_wb_ref, i_fx_ref;
        int i_wrbuffer_ref, i_wrbuffer_ref_head;
        atomic_t i_filelock_ref;
        atomic_t i_shared_gen;       /* increment each time we get FILE_SHARED */
@@ -511,18 +517,18 @@ static inline struct inode *ceph_find_inode(struct super_block *sb,
  * Ceph inode.
  */
 #define CEPH_I_DIR_ORDERED     (1 << 0)  /* dentries in dir are ordered */
-#define CEPH_I_NODELAY         (1 << 1)  /* do not delay cap release */
 #define CEPH_I_FLUSH           (1 << 2)  /* do not delay flush of dirty metadata */
 #define CEPH_I_POOL_PERM       (1 << 3)  /* pool rd/wr bits are valid */
 #define CEPH_I_POOL_RD         (1 << 4)  /* can read from pool */
 #define CEPH_I_POOL_WR         (1 << 5)  /* can write to pool */
 #define CEPH_I_SEC_INITED      (1 << 6)  /* security initialized */
-#define CEPH_I_CAP_DROPPED     (1 << 7)  /* caps were forcibly dropped */
-#define CEPH_I_KICK_FLUSH      (1 << 8)  /* kick flushing caps */
-#define CEPH_I_FLUSH_SNAPS     (1 << 9)  /* need flush snapss */
-#define CEPH_I_ERROR_WRITE     (1 << 10) /* have seen write errors */
-#define CEPH_I_ERROR_FILELOCK  (1 << 11) /* have seen file lock errors */
-#define CEPH_I_ODIRECT         (1 << 12) /* inode in direct I/O mode */
+#define CEPH_I_KICK_FLUSH      (1 << 7)  /* kick flushing caps */
+#define CEPH_I_FLUSH_SNAPS     (1 << 8)  /* need flush snapss */
+#define CEPH_I_ERROR_WRITE     (1 << 9) /* have seen write errors */
+#define CEPH_I_ERROR_FILELOCK  (1 << 10) /* have seen file lock errors */
+#define CEPH_I_ODIRECT         (1 << 11) /* inode in direct I/O mode */
+#define CEPH_ASYNC_CREATE_BIT  (12)      /* async create in flight for this */
+#define CEPH_I_ASYNC_CREATE    (1 << CEPH_ASYNC_CREATE_BIT)
 
 /*
  * Masks of ceph inode work.
@@ -674,18 +680,12 @@ extern int __ceph_caps_revoking_other(struct ceph_inode_info *ci,
 extern int ceph_caps_revoking(struct ceph_inode_info *ci, int mask);
 extern int __ceph_caps_used(struct ceph_inode_info *ci);
 
-extern int __ceph_caps_file_wanted(struct ceph_inode_info *ci);
-
-/*
- * wanted, by virtue of open file modes AND cap refs (buffered/cached data)
- */
-static inline int __ceph_caps_wanted(struct ceph_inode_info *ci)
+static inline bool __ceph_is_file_opened(struct ceph_inode_info *ci)
 {
-       int w = __ceph_caps_file_wanted(ci) | __ceph_caps_used(ci);
-       if (w & CEPH_CAP_FILE_BUFFER)
-               w |= CEPH_CAP_FILE_EXCL;  /* we want EXCL if dirty data */
-       return w;
+       return ci->i_nr_by_mode[0];
 }
+extern int __ceph_caps_file_wanted(struct ceph_inode_info *ci);
+extern int __ceph_caps_wanted(struct ceph_inode_info *ci);
 
 /* what the mds thinks we want */
 extern int __ceph_caps_mds_wanted(struct ceph_inode_info *ci, bool check);
@@ -899,6 +899,9 @@ static inline bool __ceph_have_pending_cap_snap(struct ceph_inode_info *ci)
 }
 
 /* inode.c */
+struct ceph_mds_reply_info_in;
+struct ceph_mds_reply_dirfrag;
+
 extern const struct inode_operations ceph_file_iops;
 
 extern struct inode *ceph_alloc_inode(struct super_block *sb);
@@ -914,6 +917,11 @@ extern void ceph_fill_file_time(struct inode *inode, int issued,
                                u64 time_warp_seq, struct timespec64 *ctime,
                                struct timespec64 *mtime,
                                struct timespec64 *atime);
+extern int ceph_fill_inode(struct inode *inode, struct page *locked_page,
+                   struct ceph_mds_reply_info_in *iinfo,
+                   struct ceph_mds_reply_dirfrag *dirinfo,
+                   struct ceph_mds_session *session, int cap_fmode,
+                   struct ceph_cap_reservation *caps_reservation);
 extern int ceph_fill_trace(struct super_block *sb,
                           struct ceph_mds_request *req);
 extern int ceph_readdir_prepopulate(struct ceph_mds_request *req,
@@ -1042,7 +1050,7 @@ extern struct ceph_cap *ceph_get_cap(struct ceph_mds_client *mdsc,
                                     struct ceph_cap_reservation *ctx);
 extern void ceph_add_cap(struct inode *inode,
                         struct ceph_mds_session *session, u64 cap_id,
-                        int fmode, unsigned issued, unsigned wanted,
+                        unsigned issued, unsigned wanted,
                         unsigned cap, unsigned seq, u64 realmino, int flags,
                         struct ceph_cap **new_cap);
 extern void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release);
@@ -1058,8 +1066,12 @@ extern void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
                                          struct ceph_mds_session *session);
 extern void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
                                    struct ceph_mds_session *session);
+void ceph_kick_flushing_inode_caps(struct ceph_mds_session *session,
+                                  struct ceph_inode_info *ci);
 extern struct ceph_cap *ceph_get_cap_for_mds(struct ceph_inode_info *ci,
                                             int mds);
+extern void ceph_take_cap_refs(struct ceph_inode_info *ci, int caps,
+                               bool snap_rwsem_locked);
 extern void ceph_get_cap_refs(struct ceph_inode_info *ci, int caps);
 extern void ceph_put_cap_refs(struct ceph_inode_info *ci, int had);
 extern void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
@@ -1084,8 +1096,10 @@ extern int ceph_try_get_caps(struct inode *inode,
                             int need, int want, bool nonblock, int *got);
 
 /* for counting open files by mode */
-extern void __ceph_get_fmode(struct ceph_inode_info *ci, int mode);
-extern void ceph_put_fmode(struct ceph_inode_info *ci, int mode);
+extern void ceph_get_fmode(struct ceph_inode_info *ci, int mode, int count);
+extern void ceph_put_fmode(struct ceph_inode_info *ci, int mode, int count);
+extern void __ceph_touch_fmode(struct ceph_inode_info *ci,
+                              struct ceph_mds_client *mdsc, int fmode);
 
 /* addr.c */
 extern const struct address_space_operations ceph_aops;
@@ -1097,7 +1111,7 @@ extern void ceph_pool_perm_destroy(struct ceph_mds_client* mdsc);
 /* file.c */
 extern const struct file_operations ceph_file_fops;
 
-extern int ceph_renew_caps(struct inode *inode);
+extern int ceph_renew_caps(struct inode *inode, int fmode);
 extern int ceph_open(struct inode *inode, struct file *file);
 extern int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
                            struct file *file, unsigned flags, umode_t mode);
index 22cf04f..604f65f 100644 (file)
@@ -202,7 +202,7 @@ config CIFS_SMB_DIRECT
        help
          Enables SMB Direct support for SMB 3.0, 3.02 and 3.1.1.
          SMB Direct allows transferring SMB packets over RDMA. If unsure,
-         say N.
+         say Y.
 
 config CIFS_FSCACHE
        bool "Provide CIFS client caching support"
index 276e4b5..916567d 100644 (file)
@@ -323,10 +323,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                        atomic_read(&server->smbd_conn->send_credits),
                        atomic_read(&server->smbd_conn->receive_credits),
                        server->smbd_conn->receive_credit_target);
-               seq_printf(m, "\nPending send_pending: %x "
-                       "send_payload_pending: %x",
-                       atomic_read(&server->smbd_conn->send_pending),
-                       atomic_read(&server->smbd_conn->send_payload_pending));
+               seq_printf(m, "\nPending send_pending: %x ",
+                       atomic_read(&server->smbd_conn->send_pending));
                seq_printf(m, "\nReceive buffers count_receive_queue: %x "
                        "count_empty_packet_queue: %x",
                        server->smbd_conn->count_receive_queue,
index 94e3ed4..c31f362 100644 (file)
@@ -1208,6 +1208,10 @@ static ssize_t cifs_copy_file_range(struct file *src_file, loff_t off,
 {
        unsigned int xid = get_xid();
        ssize_t rc;
+       struct cifsFileInfo *cfile = dst_file->private_data;
+
+       if (cfile->swapfile)
+               return -EOPNOTSUPP;
 
        rc = cifs_file_copychunk_range(xid, src_file, off, dst_file, destoff,
                                        len, flags);
index 0d95636..05dd3de 100644 (file)
@@ -426,7 +426,8 @@ struct smb_version_operations {
        /* generate new lease key */
        void (*new_lease_key)(struct cifs_fid *);
        int (*generate_signingkey)(struct cifs_ses *);
-       int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *);
+       int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *,
+                               bool allocate_crypto);
        int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon,
                             struct cifsFileInfo *src_file);
        int (*enum_snapshots)(const unsigned int xid, struct cifs_tcon *tcon,
@@ -1312,6 +1313,7 @@ struct cifsFileInfo {
        struct tcon_link *tlink;
        unsigned int f_flags;
        bool invalidHandle:1;   /* file closed via session abend */
+       bool swapfile:1;
        bool oplock_break_cancelled:1;
        unsigned int oplock_epoch; /* epoch from the lease break */
        __u32 oplock_level; /* oplock/lease level from the lease break */
index 5920820..0b1528e 100644 (file)
@@ -4808,6 +4808,60 @@ cifs_direct_io(struct kiocb *iocb, struct iov_iter *iter)
         return -EINVAL;
 }
 
+static int cifs_swap_activate(struct swap_info_struct *sis,
+                             struct file *swap_file, sector_t *span)
+{
+       struct cifsFileInfo *cfile = swap_file->private_data;
+       struct inode *inode = swap_file->f_mapping->host;
+       unsigned long blocks;
+       long long isize;
+
+       cifs_dbg(FYI, "swap activate\n");
+
+       spin_lock(&inode->i_lock);
+       blocks = inode->i_blocks;
+       isize = inode->i_size;
+       spin_unlock(&inode->i_lock);
+       if (blocks*512 < isize) {
+               pr_warn("swap activate: swapfile has holes\n");
+               return -EINVAL;
+       }
+       *span = sis->pages;
+
+       printk_once(KERN_WARNING "Swap support over SMB3 is experimental\n");
+
+       /*
+        * TODO: consider adding ACL (or documenting how) to prevent other
+        * users (on this or other systems) from reading it
+        */
+
+
+       /* TODO: add sk_set_memalloc(inet) or similar */
+
+       if (cfile)
+               cfile->swapfile = true;
+       /*
+        * TODO: Since file already open, we can't open with DENY_ALL here
+        * but we could add call to grab a byte range lock to prevent others
+        * from reading or writing the file
+        */
+
+       return 0;
+}
+
+static void cifs_swap_deactivate(struct file *file)
+{
+       struct cifsFileInfo *cfile = file->private_data;
+
+       cifs_dbg(FYI, "swap deactivate\n");
+
+       /* TODO: undo sk_set_memalloc(inet) will eventually be needed */
+
+       if (cfile)
+               cfile->swapfile = false;
+
+       /* do we need to unpin (or unlock) the file */
+}
 
 const struct address_space_operations cifs_addr_ops = {
        .readpage = cifs_readpage,
@@ -4821,6 +4875,13 @@ const struct address_space_operations cifs_addr_ops = {
        .direct_IO = cifs_direct_io,
        .invalidatepage = cifs_invalidate_page,
        .launder_page = cifs_launder_page,
+       /*
+        * TODO: investigate and if useful we could add an cifs_migratePage
+        * helper (under an CONFIG_MIGRATION) in the future, and also
+        * investigate and add an is_dirty_writeback helper if needed
+        */
+       .swap_activate = cifs_swap_activate,
+       .swap_deactivate = cifs_swap_deactivate,
 };
 
 /*
index 8d01ec2..8fbbdcd 100644 (file)
@@ -2026,6 +2026,10 @@ cifs_revalidate_mapping(struct inode *inode)
        int rc;
        unsigned long *flags = &CIFS_I(inode)->flags;
 
+       /* swapfiles are not supposed to be shared */
+       if (IS_SWAPFILE(inode))
+               return 0;
+
        rc = wait_on_bit_lock_action(flags, CIFS_INO_LOCK, cifs_wait_bit_killable,
                                     TASK_KILLABLE);
        if (rc)
index 19e4a5d..50f776a 100644 (file)
@@ -246,7 +246,7 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
         */
        fattr->cf_mode = le32_to_cpu(info->Mode) & ~S_IFMT;
 
-       cifs_dbg(VFS, "XXX dev %d, reparse %d, mode %o",
+       cifs_dbg(FYI, "posix fattr: dev %d, reparse %d, mode %o",
                 le32_to_cpu(info->DeviceId),
                 le32_to_cpu(info->ReparseTag),
                 le32_to_cpu(info->Mode));
index 0511aaf..497afb0 100644 (file)
@@ -766,6 +766,20 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
 
        cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count);
        spin_lock(&cifs_tcp_ses_lock);
+       if (tcon->tc_count <= 0) {
+               struct TCP_Server_Info *server = NULL;
+
+               WARN_ONCE(tcon->tc_count < 0, "tcon refcount is negative");
+               spin_unlock(&cifs_tcp_ses_lock);
+
+               if (tcon->ses)
+                       server = tcon->ses->server;
+
+               cifs_server_dbg(FYI, "tid=%u: tcon is closing, skipping async close retry of fid %llu %llu\n",
+                               tcon->tid, persistent_fid, volatile_fid);
+
+               return 0;
+       }
        tcon->tc_count++;
        spin_unlock(&cifs_tcp_ses_lock);
 
index 4d1ff7b..087d5f1 100644 (file)
@@ -55,9 +55,11 @@ extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server,
 extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server,
                                                __u64 ses_id, __u32  tid);
 extern int smb2_calc_signature(struct smb_rqst *rqst,
-                               struct TCP_Server_Info *server);
+                               struct TCP_Server_Info *server,
+                               bool allocate_crypto);
 extern int smb3_calc_signature(struct smb_rqst *rqst,
-                               struct TCP_Server_Info *server);
+                               struct TCP_Server_Info *server,
+                               bool allocate_crypto);
 extern void smb2_echo_request(struct work_struct *work);
 extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
 extern bool smb2_is_valid_oplock_break(char *buffer,
index 20cc79e..1a6c227 100644 (file)
 #include "smb2glob.h"
 
 static int
-smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
-{
-       return cifs_alloc_hash("hmac(sha256)",
-                              &server->secmech.hmacsha256,
-                              &server->secmech.sdeschmacsha256);
-}
-
-static int
 smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
 {
        struct cifs_secmech *p = &server->secmech;
@@ -219,7 +211,8 @@ smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32  tid)
 }
 
 int
-smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
+smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
+                       bool allocate_crypto)
 {
        int rc;
        unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
@@ -228,6 +221,8 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
        struct cifs_ses *ses;
        struct shash_desc *shash;
+       struct crypto_shash *hash;
+       struct sdesc *sdesc = NULL;
        struct smb_rqst drqst;
 
        ses = smb2_find_smb_ses(server, shdr->SessionId);
@@ -239,24 +234,32 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
        memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 
-       rc = smb2_crypto_shash_allocate(server);
-       if (rc) {
-               cifs_server_dbg(VFS, "%s: sha256 alloc failed\n", __func__);
-               return rc;
+       if (allocate_crypto) {
+               rc = cifs_alloc_hash("hmac(sha256)", &hash, &sdesc);
+               if (rc) {
+                       cifs_server_dbg(VFS,
+                                       "%s: sha256 alloc failed\n", __func__);
+                       return rc;
+               }
+               shash = &sdesc->shash;
+       } else {
+               hash = server->secmech.hmacsha256;
+               shash = &server->secmech.sdeschmacsha256->shash;
        }
 
-       rc = crypto_shash_setkey(server->secmech.hmacsha256,
-                                ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
+       rc = crypto_shash_setkey(hash, ses->auth_key.response,
+                       SMB2_NTLMV2_SESSKEY_SIZE);
        if (rc) {
-               cifs_server_dbg(VFS, "%s: Could not update with response\n", __func__);
-               return rc;
+               cifs_server_dbg(VFS,
+                               "%s: Could not update with response\n",
+                               __func__);
+               goto out;
        }
 
-       shash = &server->secmech.sdeschmacsha256->shash;
        rc = crypto_shash_init(shash);
        if (rc) {
                cifs_server_dbg(VFS, "%s: Could not init sha256", __func__);
-               return rc;
+               goto out;
        }
 
        /*
@@ -271,9 +274,10 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
                rc = crypto_shash_update(shash, iov[0].iov_base,
                                         iov[0].iov_len);
                if (rc) {
-                       cifs_server_dbg(VFS, "%s: Could not update with payload\n",
-                                __func__);
-                       return rc;
+                       cifs_server_dbg(VFS,
+                                       "%s: Could not update with payload\n",
+                                       __func__);
+                       goto out;
                }
                drqst.rq_iov++;
                drqst.rq_nvec--;
@@ -283,6 +287,9 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        if (!rc)
                memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
 
+out:
+       if (allocate_crypto)
+               cifs_free_hash(&hash, &sdesc);
        return rc;
 }
 
@@ -504,14 +511,17 @@ generate_smb311signingkey(struct cifs_ses *ses)
 }
 
 int
-smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
+smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
+                       bool allocate_crypto)
 {
        int rc;
        unsigned char smb3_signature[SMB2_CMACAES_SIZE];
        unsigned char *sigptr = smb3_signature;
        struct kvec *iov = rqst->rq_iov;
        struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
-       struct shash_desc *shash = &server->secmech.sdesccmacaes->shash;
+       struct shash_desc *shash;
+       struct crypto_shash *hash;
+       struct sdesc *sdesc = NULL;
        struct smb_rqst drqst;
        u8 key[SMB3_SIGN_KEY_SIZE];
 
@@ -519,14 +529,24 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        if (rc)
                return 0;
 
+       if (allocate_crypto) {
+               rc = cifs_alloc_hash("cmac(aes)", &hash, &sdesc);
+               if (rc)
+                       return rc;
+
+               shash = &sdesc->shash;
+       } else {
+               hash = server->secmech.cmacaes;
+               shash = &server->secmech.sdesccmacaes->shash;
+       }
+
        memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
        memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 
-       rc = crypto_shash_setkey(server->secmech.cmacaes,
-                                key, SMB2_CMACAES_SIZE);
+       rc = crypto_shash_setkey(hash, key, SMB2_CMACAES_SIZE);
        if (rc) {
                cifs_server_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
-               return rc;
+               goto out;
        }
 
        /*
@@ -537,7 +557,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        rc = crypto_shash_init(shash);
        if (rc) {
                cifs_server_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
-               return rc;
+               goto out;
        }
 
        /*
@@ -554,7 +574,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
                if (rc) {
                        cifs_server_dbg(VFS, "%s: Could not update with payload\n",
                                 __func__);
-                       return rc;
+                       goto out;
                }
                drqst.rq_iov++;
                drqst.rq_nvec--;
@@ -564,6 +584,9 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        if (!rc)
                memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
 
+out:
+       if (allocate_crypto)
+               cifs_free_hash(&hash, &sdesc);
        return rc;
 }
 
@@ -593,7 +616,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
                return 0;
        }
 
-       rc = server->ops->calc_signature(rqst, server);
+       rc = server->ops->calc_signature(rqst, server, false);
 
        return rc;
 }
@@ -631,9 +654,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 
        memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE);
 
-       mutex_lock(&server->srv_mutex);
-       rc = server->ops->calc_signature(rqst, server);
-       mutex_unlock(&server->srv_mutex);
+       rc = server->ops->calc_signature(rqst, server, true);
 
        if (rc)
                return rc;
index 8da43a5..1a5834a 100644 (file)
@@ -284,13 +284,10 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc)
                        request->sge[i].length,
                        DMA_TO_DEVICE);
 
-       if (request->has_payload) {
-               if (atomic_dec_and_test(&request->info->send_payload_pending))
-                       wake_up(&request->info->wait_send_payload_pending);
-       } else {
-               if (atomic_dec_and_test(&request->info->send_pending))
-                       wake_up(&request->info->wait_send_pending);
-       }
+       if (atomic_dec_and_test(&request->info->send_pending))
+               wake_up(&request->info->wait_send_pending);
+
+       wake_up(&request->info->wait_post_send);
 
        mempool_free(request, request->info->request_mempool);
 }
@@ -383,27 +380,6 @@ static bool process_negotiation_response(
        return true;
 }
 
-/*
- * Check and schedule to send an immediate packet
- * This is used to extend credtis to remote peer to keep the transport busy
- */
-static void check_and_send_immediate(struct smbd_connection *info)
-{
-       if (info->transport_status != SMBD_CONNECTED)
-               return;
-
-       info->send_immediate = true;
-
-       /*
-        * Promptly send a packet if our peer is running low on receive
-        * credits
-        */
-       if (atomic_read(&info->receive_credits) <
-               info->receive_credit_target - 1)
-               queue_delayed_work(
-                       info->workqueue, &info->send_immediate_work, 0);
-}
-
 static void smbd_post_send_credits(struct work_struct *work)
 {
        int ret = 0;
@@ -453,10 +429,16 @@ static void smbd_post_send_credits(struct work_struct *work)
        info->new_credits_offered += ret;
        spin_unlock(&info->lock_new_credits_offered);
 
-       atomic_add(ret, &info->receive_credits);
-
-       /* Check if we can post new receive and grant credits to peer */
-       check_and_send_immediate(info);
+       /* Promptly send an immediate packet as defined in [MS-SMBD] 3.1.1.1 */
+       info->send_immediate = true;
+       if (atomic_read(&info->receive_credits) <
+               info->receive_credit_target - 1) {
+               if (info->keep_alive_requested == KEEP_ALIVE_PENDING ||
+                   info->send_immediate) {
+                       log_keep_alive(INFO, "send an empty message\n");
+                       smbd_post_send_empty(info);
+               }
+       }
 }
 
 /* Called from softirq, when recv is done */
@@ -551,12 +533,6 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
                        info->keep_alive_requested = KEEP_ALIVE_PENDING;
                }
 
-               /*
-                * Check if we need to send something to remote peer to
-                * grant more credits or respond to KEEP_ALIVE packet
-                */
-               check_and_send_immediate(info);
-
                return;
 
        default:
@@ -749,7 +725,6 @@ static int smbd_post_send_negotiate_req(struct smbd_connection *info)
                request->sge[0].addr,
                request->sge[0].length, request->sge[0].lkey);
 
-       request->has_payload = false;
        atomic_inc(&info->send_pending);
        rc = ib_post_send(info->id->qp, &send_wr, NULL);
        if (!rc)
@@ -806,45 +781,96 @@ static int manage_keep_alive_before_sending(struct smbd_connection *info)
        return 0;
 }
 
-/*
- * Build and prepare the SMBD packet header
- * This function waits for avaialbe send credits and build a SMBD packet
- * header. The caller then optional append payload to the packet after
- * the header
- * intput values
- * size: the size of the payload
- * remaining_data_length: remaining data to send if this is part of a
- * fragmented packet
- * output values
- * request_out: the request allocated from this function
- * return values: 0 on success, otherwise actual error code returned
- */
-static int smbd_create_header(struct smbd_connection *info,
-               int size, int remaining_data_length,
-               struct smbd_request **request_out)
+/* Post the send request */
+static int smbd_post_send(struct smbd_connection *info,
+               struct smbd_request *request)
+{
+       struct ib_send_wr send_wr;
+       int rc, i;
+
+       for (i = 0; i < request->num_sge; i++) {
+               log_rdma_send(INFO,
+                       "rdma_request sge[%d] addr=%llu length=%u\n",
+                       i, request->sge[i].addr, request->sge[i].length);
+               ib_dma_sync_single_for_device(
+                       info->id->device,
+                       request->sge[i].addr,
+                       request->sge[i].length,
+                       DMA_TO_DEVICE);
+       }
+
+       request->cqe.done = send_done;
+
+       send_wr.next = NULL;
+       send_wr.wr_cqe = &request->cqe;
+       send_wr.sg_list = request->sge;
+       send_wr.num_sge = request->num_sge;
+       send_wr.opcode = IB_WR_SEND;
+       send_wr.send_flags = IB_SEND_SIGNALED;
+
+       rc = ib_post_send(info->id->qp, &send_wr, NULL);
+       if (rc) {
+               log_rdma_send(ERR, "ib_post_send failed rc=%d\n", rc);
+               smbd_disconnect_rdma_connection(info);
+               rc = -EAGAIN;
+       } else
+               /* Reset timer for idle connection after packet is sent */
+               mod_delayed_work(info->workqueue, &info->idle_timer_work,
+                       info->keep_alive_interval*HZ);
+
+       return rc;
+}
+
+static int smbd_post_send_sgl(struct smbd_connection *info,
+       struct scatterlist *sgl, int data_length, int remaining_data_length)
 {
+       int num_sgs;
+       int i, rc;
+       int header_length;
        struct smbd_request *request;
        struct smbd_data_transfer *packet;
-       int header_length;
-       int rc;
+       int new_credits;
+       struct scatterlist *sg;
 
+wait_credit:
        /* Wait for send credits. A SMBD packet needs one credit */
        rc = wait_event_interruptible(info->wait_send_queue,
                atomic_read(&info->send_credits) > 0 ||
                info->transport_status != SMBD_CONNECTED);
        if (rc)
-               return rc;
+               goto err_wait_credit;
+
+       if (info->transport_status != SMBD_CONNECTED) {
+               log_outgoing(ERR, "disconnected not sending on wait_credit\n");
+               rc = -EAGAIN;
+               goto err_wait_credit;
+       }
+       if (unlikely(atomic_dec_return(&info->send_credits) < 0)) {
+               atomic_inc(&info->send_credits);
+               goto wait_credit;
+       }
+
+wait_send_queue:
+       wait_event(info->wait_post_send,
+               atomic_read(&info->send_pending) < info->send_credit_target ||
+               info->transport_status != SMBD_CONNECTED);
 
        if (info->transport_status != SMBD_CONNECTED) {
-               log_outgoing(ERR, "disconnected not sending\n");
-               return -EAGAIN;
+               log_outgoing(ERR, "disconnected not sending on wait_send_queue\n");
+               rc = -EAGAIN;
+               goto err_wait_send_queue;
+       }
+
+       if (unlikely(atomic_inc_return(&info->send_pending) >
+                               info->send_credit_target)) {
+               atomic_dec(&info->send_pending);
+               goto wait_send_queue;
        }
-       atomic_dec(&info->send_credits);
 
        request = mempool_alloc(info->request_mempool, GFP_KERNEL);
        if (!request) {
                rc = -ENOMEM;
-               goto err;
+               goto err_alloc;
        }
 
        request->info = info;
@@ -852,8 +878,11 @@ static int smbd_create_header(struct smbd_connection *info,
        /* Fill in the packet header */
        packet = smbd_request_payload(request);
        packet->credits_requested = cpu_to_le16(info->send_credit_target);
-       packet->credits_granted =
-               cpu_to_le16(manage_credits_prior_sending(info));
+
+       new_credits = manage_credits_prior_sending(info);
+       atomic_add(new_credits, &info->receive_credits);
+       packet->credits_granted = cpu_to_le16(new_credits);
+
        info->send_immediate = false;
 
        packet->flags = 0;
@@ -861,11 +890,11 @@ static int smbd_create_header(struct smbd_connection *info,
                packet->flags |= cpu_to_le16(SMB_DIRECT_RESPONSE_REQUESTED);
 
        packet->reserved = 0;
-       if (!size)
+       if (!data_length)
                packet->data_offset = 0;
        else
                packet->data_offset = cpu_to_le32(24);
-       packet->data_length = cpu_to_le32(size);
+       packet->data_length = cpu_to_le32(data_length);
        packet->remaining_data_length = cpu_to_le32(remaining_data_length);
        packet->padding = 0;
 
@@ -880,7 +909,7 @@ static int smbd_create_header(struct smbd_connection *info,
        /* Map the packet to DMA */
        header_length = sizeof(struct smbd_data_transfer);
        /* If this is a packet without payload, don't send padding */
-       if (!size)
+       if (!data_length)
                header_length = offsetof(struct smbd_data_transfer, padding);
 
        request->num_sge = 1;
@@ -889,102 +918,15 @@ static int smbd_create_header(struct smbd_connection *info,
                                                 header_length,
                                                 DMA_TO_DEVICE);
        if (ib_dma_mapping_error(info->id->device, request->sge[0].addr)) {
-               mempool_free(request, info->request_mempool);
                rc = -EIO;
-               goto err;
+               request->sge[0].addr = 0;
+               goto err_dma;
        }
 
        request->sge[0].length = header_length;
        request->sge[0].lkey = info->pd->local_dma_lkey;
 
-       *request_out = request;
-       return 0;
-
-err:
-       atomic_inc(&info->send_credits);
-       return rc;
-}
-
-static void smbd_destroy_header(struct smbd_connection *info,
-               struct smbd_request *request)
-{
-
-       ib_dma_unmap_single(info->id->device,
-                           request->sge[0].addr,
-                           request->sge[0].length,
-                           DMA_TO_DEVICE);
-       mempool_free(request, info->request_mempool);
-       atomic_inc(&info->send_credits);
-}
-
-/* Post the send request */
-static int smbd_post_send(struct smbd_connection *info,
-               struct smbd_request *request, bool has_payload)
-{
-       struct ib_send_wr send_wr;
-       int rc, i;
-
-       for (i = 0; i < request->num_sge; i++) {
-               log_rdma_send(INFO,
-                       "rdma_request sge[%d] addr=%llu length=%u\n",
-                       i, request->sge[i].addr, request->sge[i].length);
-               ib_dma_sync_single_for_device(
-                       info->id->device,
-                       request->sge[i].addr,
-                       request->sge[i].length,
-                       DMA_TO_DEVICE);
-       }
-
-       request->cqe.done = send_done;
-
-       send_wr.next = NULL;
-       send_wr.wr_cqe = &request->cqe;
-       send_wr.sg_list = request->sge;
-       send_wr.num_sge = request->num_sge;
-       send_wr.opcode = IB_WR_SEND;
-       send_wr.send_flags = IB_SEND_SIGNALED;
-
-       if (has_payload) {
-               request->has_payload = true;
-               atomic_inc(&info->send_payload_pending);
-       } else {
-               request->has_payload = false;
-               atomic_inc(&info->send_pending);
-       }
-
-       rc = ib_post_send(info->id->qp, &send_wr, NULL);
-       if (rc) {
-               log_rdma_send(ERR, "ib_post_send failed rc=%d\n", rc);
-               if (has_payload) {
-                       if (atomic_dec_and_test(&info->send_payload_pending))
-                               wake_up(&info->wait_send_payload_pending);
-               } else {
-                       if (atomic_dec_and_test(&info->send_pending))
-                               wake_up(&info->wait_send_pending);
-               }
-               smbd_disconnect_rdma_connection(info);
-               rc = -EAGAIN;
-       } else
-               /* Reset timer for idle connection after packet is sent */
-               mod_delayed_work(info->workqueue, &info->idle_timer_work,
-                       info->keep_alive_interval*HZ);
-
-       return rc;
-}
-
-static int smbd_post_send_sgl(struct smbd_connection *info,
-       struct scatterlist *sgl, int data_length, int remaining_data_length)
-{
-       int num_sgs;
-       int i, rc;
-       struct smbd_request *request;
-       struct scatterlist *sg;
-
-       rc = smbd_create_header(
-               info, data_length, remaining_data_length, &request);
-       if (rc)
-               return rc;
-
+       /* Fill in the packet data payload */
        num_sgs = sgl ? sg_nents(sgl) : 0;
        for_each_sg(sgl, sg, num_sgs, i) {
                request->sge[i+1].addr =
@@ -994,25 +936,41 @@ static int smbd_post_send_sgl(struct smbd_connection *info,
                                info->id->device, request->sge[i+1].addr)) {
                        rc = -EIO;
                        request->sge[i+1].addr = 0;
-                       goto dma_mapping_failure;
+                       goto err_dma;
                }
                request->sge[i+1].length = sg->length;
                request->sge[i+1].lkey = info->pd->local_dma_lkey;
                request->num_sge++;
        }
 
-       rc = smbd_post_send(info, request, data_length);
+       rc = smbd_post_send(info, request);
        if (!rc)
                return 0;
 
-dma_mapping_failure:
-       for (i = 1; i < request->num_sge; i++)
+err_dma:
+       for (i = 0; i < request->num_sge; i++)
                if (request->sge[i].addr)
                        ib_dma_unmap_single(info->id->device,
                                            request->sge[i].addr,
                                            request->sge[i].length,
                                            DMA_TO_DEVICE);
-       smbd_destroy_header(info, request);
+       mempool_free(request, info->request_mempool);
+
+       /* roll back receive credits and credits to be offered */
+       spin_lock(&info->lock_new_credits_offered);
+       info->new_credits_offered += new_credits;
+       spin_unlock(&info->lock_new_credits_offered);
+       atomic_sub(new_credits, &info->receive_credits);
+
+err_alloc:
+       if (atomic_dec_and_test(&info->send_pending))
+               wake_up(&info->wait_send_pending);
+
+err_wait_send_queue:
+       /* roll back send credits and pending */
+       atomic_inc(&info->send_credits);
+
+err_wait_credit:
        return rc;
 }
 
@@ -1334,25 +1292,6 @@ static void destroy_receive_buffers(struct smbd_connection *info)
                mempool_free(response, info->response_mempool);
 }
 
-/*
- * Check and send an immediate or keep alive packet
- * The condition to send those packets are defined in [MS-SMBD] 3.1.1.1
- * Connection.KeepaliveRequested and Connection.SendImmediate
- * The idea is to extend credits to server as soon as it becomes available
- */
-static void send_immediate_work(struct work_struct *work)
-{
-       struct smbd_connection *info = container_of(
-                                       work, struct smbd_connection,
-                                       send_immediate_work.work);
-
-       if (info->keep_alive_requested == KEEP_ALIVE_PENDING ||
-           info->send_immediate) {
-               log_keep_alive(INFO, "send an empty message\n");
-               smbd_post_send_empty(info);
-       }
-}
-
 /* Implement idle connection timer [MS-SMBD] 3.1.6.2 */
 static void idle_connection_timer(struct work_struct *work)
 {
@@ -1407,14 +1346,10 @@ void smbd_destroy(struct TCP_Server_Info *server)
 
        log_rdma_event(INFO, "cancelling idle timer\n");
        cancel_delayed_work_sync(&info->idle_timer_work);
-       log_rdma_event(INFO, "cancelling send immediate work\n");
-       cancel_delayed_work_sync(&info->send_immediate_work);
 
        log_rdma_event(INFO, "wait for all send posted to IB to finish\n");
        wait_event(info->wait_send_pending,
                atomic_read(&info->send_pending) == 0);
-       wait_event(info->wait_send_payload_pending,
-               atomic_read(&info->send_payload_pending) == 0);
 
        /* It's not posssible for upper layer to get to reassembly */
        log_rdma_event(INFO, "drain the reassembly queue\n");
@@ -1744,15 +1679,13 @@ static struct smbd_connection *_smbd_get_connection(
 
        init_waitqueue_head(&info->wait_send_queue);
        INIT_DELAYED_WORK(&info->idle_timer_work, idle_connection_timer);
-       INIT_DELAYED_WORK(&info->send_immediate_work, send_immediate_work);
        queue_delayed_work(info->workqueue, &info->idle_timer_work,
                info->keep_alive_interval*HZ);
 
        init_waitqueue_head(&info->wait_send_pending);
        atomic_set(&info->send_pending, 0);
 
-       init_waitqueue_head(&info->wait_send_payload_pending);
-       atomic_set(&info->send_payload_pending, 0);
+       init_waitqueue_head(&info->wait_post_send);
 
        INIT_WORK(&info->disconnect_work, smbd_disconnect_rdma_work);
        INIT_WORK(&info->post_send_credits_work, smbd_post_send_credits);
@@ -2226,8 +2159,8 @@ done:
         * that means all the I/Os have been out and we are good to return
         */
 
-       wait_event(info->wait_send_payload_pending,
-               atomic_read(&info->send_payload_pending) == 0);
+       wait_event(info->wait_send_pending,
+               atomic_read(&info->send_pending) == 0);
 
        return rc;
 }
index 8ede915..a87fca8 100644 (file)
@@ -114,8 +114,7 @@ struct smbd_connection {
        /* Activity accoutning */
        atomic_t send_pending;
        wait_queue_head_t wait_send_pending;
-       atomic_t send_payload_pending;
-       wait_queue_head_t wait_send_payload_pending;
+       wait_queue_head_t wait_post_send;
 
        /* Receive queue */
        struct list_head receive_queue;
@@ -154,7 +153,6 @@ struct smbd_connection {
 
        struct workqueue_struct *workqueue;
        struct delayed_work idle_timer_work;
-       struct delayed_work send_immediate_work;
 
        /* Memory pool for preallocating buffers */
        /* request pool for RDMA send */
@@ -234,9 +232,6 @@ struct smbd_request {
        struct smbd_connection *info;
        struct ib_cqe cqe;
 
-       /* true if this request carries upper layer payload */
-       bool has_payload;
-
        /* the SGE entries for this packet */
        struct ib_sge sge[SMBDIRECT_MAX_SGE];
        int num_sge;
index 35da144..11b1672 100644 (file)
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -1038,50 +1038,43 @@ static vm_fault_t dax_load_hole(struct xa_state *xas,
        return ret;
 }
 
-static bool dax_range_is_aligned(struct block_device *bdev,
-                                unsigned int offset, unsigned int length)
+int dax_iomap_zero(loff_t pos, unsigned offset, unsigned size,
+                  struct iomap *iomap)
 {
-       unsigned short sector_size = bdev_logical_block_size(bdev);
+       sector_t sector = iomap_sector(iomap, pos & PAGE_MASK);
+       pgoff_t pgoff;
+       long rc, id;
+       void *kaddr;
+       bool page_aligned = false;
 
-       if (!IS_ALIGNED(offset, sector_size))
-               return false;
-       if (!IS_ALIGNED(length, sector_size))
-               return false;
 
-       return true;
-}
+       if (IS_ALIGNED(sector << SECTOR_SHIFT, PAGE_SIZE) &&
+           IS_ALIGNED(size, PAGE_SIZE))
+               page_aligned = true;
 
-int __dax_zero_page_range(struct block_device *bdev,
-               struct dax_device *dax_dev, sector_t sector,
-               unsigned int offset, unsigned int size)
-{
-       if (dax_range_is_aligned(bdev, offset, size)) {
-               sector_t start_sector = sector + (offset >> 9);
+       rc = bdev_dax_pgoff(iomap->bdev, sector, PAGE_SIZE, &pgoff);
+       if (rc)
+               return rc;
 
-               return blkdev_issue_zeroout(bdev, start_sector,
-                               size >> 9, GFP_NOFS, 0);
-       } else {
-               pgoff_t pgoff;
-               long rc, id;
-               void *kaddr;
+       id = dax_read_lock();
 
-               rc = bdev_dax_pgoff(bdev, sector, PAGE_SIZE, &pgoff);
-               if (rc)
-                       return rc;
+       if (page_aligned)
+               rc = dax_zero_page_range(iomap->dax_dev, pgoff,
+                                        size >> PAGE_SHIFT);
+       else
+               rc = dax_direct_access(iomap->dax_dev, pgoff, 1, &kaddr, NULL);
+       if (rc < 0) {
+               dax_read_unlock(id);
+               return rc;
+       }
 
-               id = dax_read_lock();
-               rc = dax_direct_access(dax_dev, pgoff, 1, &kaddr, NULL);
-               if (rc < 0) {
-                       dax_read_unlock(id);
-                       return rc;
-               }
+       if (!page_aligned) {
                memset(kaddr + offset, 0, size);
-               dax_flush(dax_dev, kaddr + offset, size);
-               dax_read_unlock(id);
+               dax_flush(iomap->dax_dev, kaddr + offset, size);
        }
+       dax_read_unlock(id);
        return 0;
 }
-EXPORT_SYMBOL_GPL(__dax_zero_page_range);
 
 static loff_t
 dax_iomap_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
index 77bf5f9..90b8d87 100644 (file)
@@ -272,7 +272,9 @@ struct file_system_type *get_fs_type(const char *name)
        fs = __get_fs_type(name, len);
        if (!fs && (request_module("fs-%.*s", len, name) == 0)) {
                fs = __get_fs_type(name, len);
-               WARN_ONCE(!fs, "request_module fs-%.*s succeeded, but still no fs?\n", len, name);
+               if (!fs)
+                       pr_warn_once("request_module fs-%.*s succeeded, but still no fs?\n",
+                                    len, name);
        }
 
        if (dot && fs && !(fs->fs_flags & FS_HAS_SUBTYPE)) {
index e6d5544..eeebe80 100644 (file)
@@ -292,6 +292,10 @@ static int __hfsplus_delete_attr(struct inode *inode, u32 cnid,
                return -ENOENT;
        }
 
+       /* Avoid btree corruption */
+       hfs_bnode_read(fd->bnode, fd->search_key,
+                       fd->keyoffset, fd->keylength);
+
        err = hfs_brec_remove(fd);
        if (err)
                return err;
index cc5cf22..4023c98 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/kthread.h>
 #include <linux/rculist_nulls.h>
 #include <linux/fs_struct.h>
+#include <linux/task_work.h>
 
 #include "io-wq.h"
 
@@ -716,6 +717,9 @@ static int io_wq_manager(void *data)
        complete(&wq->done);
 
        while (!kthread_should_stop()) {
+               if (current->task_works)
+                       task_work_run();
+
                for_each_node(node) {
                        struct io_wqe *wqe = wq->wqes[node];
                        bool fork_worker[2] = { false, false };
@@ -738,6 +742,9 @@ static int io_wq_manager(void *data)
                schedule_timeout(HZ);
        }
 
+       if (current->task_works)
+               task_work_run();
+
        return 0;
 err:
        set_bit(IO_WQ_BIT_ERROR, &wq->state);
@@ -1124,3 +1131,8 @@ void io_wq_destroy(struct io_wq *wq)
        if (refcount_dec_and_test(&wq->use_refs))
                __io_wq_destroy(wq);
 }
+
+struct task_struct *io_wq_get_task(struct io_wq *wq)
+{
+       return wq->manager;
+}
index 3ee7356..5ba12de 100644 (file)
@@ -136,6 +136,8 @@ typedef bool (work_cancel_fn)(struct io_wq_work *, void *);
 enum io_wq_cancel io_wq_cancel_cb(struct io_wq *wq, work_cancel_fn *cancel,
                                        void *data);
 
+struct task_struct *io_wq_get_task(struct io_wq *wq);
+
 #if defined(CONFIG_IO_WQ)
 extern void io_wq_worker_sleeping(struct task_struct *);
 extern void io_wq_worker_running(struct task_struct *);
index 358f97b..5190bfb 100644 (file)
@@ -186,14 +186,23 @@ struct fixed_file_table {
        struct file             **files;
 };
 
+struct fixed_file_ref_node {
+       struct percpu_ref               refs;
+       struct list_head                node;
+       struct list_head                file_list;
+       struct fixed_file_data          *file_data;
+       struct work_struct              work;
+};
+
 struct fixed_file_data {
        struct fixed_file_table         *table;
        struct io_ring_ctx              *ctx;
 
+       struct percpu_ref               *cur_refs;
        struct percpu_ref               refs;
-       struct llist_head               put_llist;
-       struct work_struct              ref_work;
        struct completion               done;
+       struct list_head                ref_list;
+       spinlock_t                      lock;
 };
 
 struct io_buffer {
@@ -317,6 +326,8 @@ struct io_ring_ctx {
                spinlock_t              inflight_lock;
                struct list_head        inflight_list;
        } ____cacheline_aligned_in_smp;
+
+       struct work_struct              exit_work;
 };
 
 /*
@@ -599,6 +610,7 @@ struct io_kiocb {
        };
 
        struct io_async_ctx             *io;
+       int                             cflags;
        bool                            needs_fixed_file;
        u8                              opcode;
 
@@ -606,10 +618,8 @@ struct io_kiocb {
        struct list_head        list;
        unsigned int            flags;
        refcount_t              refs;
-       union {
-               struct task_struct      *task;
-               unsigned long           fsize;
-       };
+       struct task_struct      *task;
+       unsigned long           fsize;
        u64                     user_data;
        u32                     result;
        u32                     sequence;
@@ -618,6 +628,8 @@ struct io_kiocb {
 
        struct list_head        inflight_entry;
 
+       struct percpu_ref       *fixed_file_refs;
+
        union {
                /*
                 * Only commands that never go async can use the below fields,
@@ -629,7 +641,6 @@ struct io_kiocb {
                        struct callback_head    task_work;
                        struct hlist_node       hash_node;
                        struct async_poll       *apoll;
-                       int                     cflags;
                };
                struct io_wq_work       work;
        };
@@ -848,7 +859,6 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
                                 struct io_uring_files_update *ip,
                                 unsigned nr_args);
 static int io_grab_files(struct io_kiocb *req);
-static void io_ring_file_ref_flush(struct fixed_file_data *data);
 static void io_cleanup_req(struct io_kiocb *req);
 static int io_file_get(struct io_submit_state *state, struct io_kiocb *req,
                       int fd, struct file **out_file, bool fixed);
@@ -1285,8 +1295,8 @@ static struct io_kiocb *io_get_fallback_req(struct io_ring_ctx *ctx)
        return NULL;
 }
 
-static struct io_kiocb *io_get_req(struct io_ring_ctx *ctx,
-                                  struct io_submit_state *state)
+static struct io_kiocb *io_alloc_req(struct io_ring_ctx *ctx,
+                                    struct io_submit_state *state)
 {
        gfp_t gfp = GFP_KERNEL | __GFP_NOWARN;
        struct io_kiocb *req;
@@ -1319,41 +1329,20 @@ static struct io_kiocb *io_get_req(struct io_ring_ctx *ctx,
                req = state->reqs[state->free_reqs];
        }
 
-got_it:
-       req->io = NULL;
-       req->file = NULL;
-       req->ctx = ctx;
-       req->flags = 0;
-       /* one is dropped after submission, the other at completion */
-       refcount_set(&req->refs, 2);
-       req->result = 0;
-       INIT_IO_WORK(&req->work, io_wq_submit_work);
        return req;
 fallback:
-       req = io_get_fallback_req(ctx);
-       if (req)
-               goto got_it;
-       percpu_ref_put(&ctx->refs);
-       return NULL;
+       return io_get_fallback_req(ctx);
 }
 
 static inline void io_put_file(struct io_kiocb *req, struct file *file,
                          bool fixed)
 {
        if (fixed)
-               percpu_ref_put(&req->ctx->file_data->refs);
+               percpu_ref_put(req->fixed_file_refs);
        else
                fput(file);
 }
 
-static void __io_req_do_free(struct io_kiocb *req)
-{
-       if (likely(!io_is_fallback_req(req)))
-               kmem_cache_free(req_cachep, req);
-       else
-               clear_bit_unlock(0, (unsigned long *) req->ctx->fallback_req);
-}
-
 static void __io_req_aux_free(struct io_kiocb *req)
 {
        if (req->flags & REQ_F_NEED_CLEANUP)
@@ -1362,6 +1351,8 @@ static void __io_req_aux_free(struct io_kiocb *req)
        kfree(req->io);
        if (req->file)
                io_put_file(req, req->file, (req->flags & REQ_F_FIXED_FILE));
+       if (req->task)
+               put_task_struct(req->task);
 
        io_req_work_drop_env(req);
 }
@@ -1382,7 +1373,10 @@ static void __io_free_req(struct io_kiocb *req)
        }
 
        percpu_ref_put(&req->ctx->refs);
-       __io_req_do_free(req);
+       if (likely(!io_is_fallback_req(req)))
+               kmem_cache_free(req_cachep, req);
+       else
+               clear_bit_unlock(0, (unsigned long *) req->ctx->fallback_req);
 }
 
 struct req_batch {
@@ -1393,21 +1387,18 @@ struct req_batch {
 
 static void io_free_req_many(struct io_ring_ctx *ctx, struct req_batch *rb)
 {
-       int fixed_refs = rb->to_free;
-
        if (!rb->to_free)
                return;
        if (rb->need_iter) {
                int i, inflight = 0;
                unsigned long flags;
 
-               fixed_refs = 0;
                for (i = 0; i < rb->to_free; i++) {
                        struct io_kiocb *req = rb->reqs[i];
 
                        if (req->flags & REQ_F_FIXED_FILE) {
                                req->file = NULL;
-                               fixed_refs++;
+                               percpu_ref_put(req->fixed_file_refs);
                        }
                        if (req->flags & REQ_F_INFLIGHT)
                                inflight++;
@@ -1433,8 +1424,6 @@ static void io_free_req_many(struct io_ring_ctx *ctx, struct req_batch *rb)
        }
 do_free:
        kmem_cache_free_bulk(req_cachep, rb->to_free, rb->reqs);
-       if (fixed_refs)
-               percpu_ref_put_many(&ctx->file_data->refs, fixed_refs);
        percpu_ref_put_many(&ctx->refs, rb->to_free);
        rb->to_free = rb->need_iter = 0;
 }
@@ -1738,11 +1727,24 @@ static void io_iopoll_complete(struct io_ring_ctx *ctx, unsigned int *nr_events,
        io_free_req_many(ctx, &rb);
 }
 
+static void io_iopoll_queue(struct list_head *again)
+{
+       struct io_kiocb *req;
+
+       do {
+               req = list_first_entry(again, struct io_kiocb, list);
+               list_del(&req->list);
+               refcount_inc(&req->refs);
+               io_queue_async_work(req);
+       } while (!list_empty(again));
+}
+
 static int io_do_iopoll(struct io_ring_ctx *ctx, unsigned int *nr_events,
                        long min)
 {
        struct io_kiocb *req, *tmp;
        LIST_HEAD(done);
+       LIST_HEAD(again);
        bool spin;
        int ret;
 
@@ -1757,9 +1759,9 @@ static int io_do_iopoll(struct io_ring_ctx *ctx, unsigned int *nr_events,
                struct kiocb *kiocb = &req->rw.kiocb;
 
                /*
-                * Move completed entries to our local list. If we find a
-                * request that requires polling, break out and complete
-                * the done list first, if we have entries there.
+                * Move completed and retryable entries to our local lists.
+                * If we find a request that requires polling, break out
+                * and complete those lists first, if we have entries there.
                 */
                if (req->flags & REQ_F_IOPOLL_COMPLETED) {
                        list_move_tail(&req->list, &done);
@@ -1768,6 +1770,13 @@ static int io_do_iopoll(struct io_ring_ctx *ctx, unsigned int *nr_events,
                if (!list_empty(&done))
                        break;
 
+               if (req->result == -EAGAIN) {
+                       list_move_tail(&req->list, &again);
+                       continue;
+               }
+               if (!list_empty(&again))
+                       break;
+
                ret = kiocb->ki_filp->f_op->iopoll(kiocb, spin);
                if (ret < 0)
                        break;
@@ -1780,6 +1789,9 @@ static int io_do_iopoll(struct io_ring_ctx *ctx, unsigned int *nr_events,
        if (!list_empty(&done))
                io_iopoll_complete(ctx, nr_events, &done);
 
+       if (!list_empty(&again))
+               io_iopoll_queue(&again);
+
        return ret;
 }
 
@@ -2465,8 +2477,9 @@ static void io_req_map_rw(struct io_kiocb *req, ssize_t io_size,
        req->io->rw.iov = iovec;
        if (!req->io->rw.iov) {
                req->io->rw.iov = req->io->rw.fast_iov;
-               memcpy(req->io->rw.iov, fast_iov,
-                       sizeof(struct iovec) * iter->nr_segs);
+               if (req->io->rw.iov != fast_iov)
+                       memcpy(req->io->rw.iov, fast_iov,
+                              sizeof(struct iovec) * iter->nr_segs);
        } else {
                req->flags |= REQ_F_NEED_CLEANUP;
        }
@@ -2920,7 +2933,7 @@ static int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 
        if (sqe->ioprio || sqe->buf_index)
                return -EINVAL;
-       if (sqe->flags & IOSQE_FIXED_FILE)
+       if (req->flags & REQ_F_FIXED_FILE)
                return -EBADF;
        if (req->flags & REQ_F_NEED_CLEANUP)
                return 0;
@@ -2929,6 +2942,8 @@ static int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        req->open.how.mode = READ_ONCE(sqe->len);
        fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
        req->open.how.flags = READ_ONCE(sqe->open_flags);
+       if (force_o_largefile())
+               req->open.how.flags |= O_LARGEFILE;
 
        req->open.filename = getname(fname);
        if (IS_ERR(req->open.filename)) {
@@ -2951,7 +2966,7 @@ static int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 
        if (sqe->ioprio || sqe->buf_index)
                return -EINVAL;
-       if (sqe->flags & IOSQE_FIXED_FILE)
+       if (req->flags & REQ_F_FIXED_FILE)
                return -EBADF;
        if (req->flags & REQ_F_NEED_CLEANUP)
                return 0;
@@ -3305,7 +3320,7 @@ static int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 
        if (sqe->ioprio || sqe->buf_index)
                return -EINVAL;
-       if (sqe->flags & IOSQE_FIXED_FILE)
+       if (req->flags & REQ_F_FIXED_FILE)
                return -EBADF;
        if (req->flags & REQ_F_NEED_CLEANUP)
                return 0;
@@ -3382,7 +3397,7 @@ static int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        if (sqe->ioprio || sqe->off || sqe->addr || sqe->len ||
            sqe->rw_flags || sqe->buf_index)
                return -EINVAL;
-       if (sqe->flags & IOSQE_FIXED_FILE)
+       if (req->flags & REQ_F_FIXED_FILE)
                return -EBADF;
 
        req->close.fd = READ_ONCE(sqe->fd);
@@ -3481,14 +3496,11 @@ static void __io_sync_file_range(struct io_kiocb *req)
 static void io_sync_file_range_finish(struct io_wq_work **workptr)
 {
        struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
-       struct io_kiocb *nxt = NULL;
 
        if (io_req_cancelled(req))
                return;
        __io_sync_file_range(req);
        io_put_req(req); /* put submission ref */
-       if (nxt)
-               io_wq_assign_next(workptr, nxt);
 }
 
 static int io_sync_file_range(struct io_kiocb *req, bool force_nonblock)
@@ -4114,6 +4126,7 @@ static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll,
                           __poll_t mask, task_work_func_t func)
 {
        struct task_struct *tsk;
+       int ret;
 
        /* for instances that support it check for an event match first: */
        if (mask && !(mask & poll->events))
@@ -4127,11 +4140,15 @@ static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll,
        req->result = mask;
        init_task_work(&req->task_work, func);
        /*
-        * If this fails, then the task is exiting. If that is the case, then
-        * the exit check will ultimately cancel these work items. Hence we
-        * don't need to check here and handle it specifically.
+        * If this fails, then the task is exiting. Punt to one of the io-wq
+        * threads to ensure the work gets run, we can't always rely on exit
+        * cancelation taking care of this.
         */
-       task_work_add(tsk, &req->task_work, true);
+       ret = task_work_add(tsk, &req->task_work, true);
+       if (unlikely(ret)) {
+               tsk = io_wq_get_task(req->ctx->io_wq);
+               task_work_add(tsk, &req->task_work, true);
+       }
        wake_up_process(tsk);
        return 1;
 }
@@ -4251,10 +4268,7 @@ static bool io_arm_poll_handler(struct io_kiocb *req)
        req->flags |= REQ_F_POLLED;
        memcpy(&apoll->work, &req->work, sizeof(req->work));
 
-       /*
-        * Don't need a reference here, as we're adding it to the task
-        * task_works list. If the task exits, the list is pruned.
-        */
+       get_task_struct(current);
        req->task = current;
        req->apoll = apoll;
        INIT_HLIST_NODE(&req->hash_node);
@@ -4407,8 +4421,20 @@ static void io_poll_complete(struct io_kiocb *req, __poll_t mask, int error)
 static void io_poll_task_handler(struct io_kiocb *req, struct io_kiocb **nxt)
 {
        struct io_ring_ctx *ctx = req->ctx;
+       struct io_poll_iocb *poll = &req->poll;
+
+       if (!req->result && !READ_ONCE(poll->canceled)) {
+               struct poll_table_struct pt = { ._key = poll->events };
+
+               req->result = vfs_poll(req->file, &pt) & poll->events;
+       }
 
        spin_lock_irq(&ctx->completion_lock);
+       if (!req->result && !READ_ONCE(poll->canceled)) {
+               add_wait_queue(poll->head, &poll->wait);
+               spin_unlock_irq(&ctx->completion_lock);
+               return;
+       }
        hash_del(&req->hash_node);
        io_poll_complete(req, req->result, 0);
        req->flags |= REQ_F_COMP_LOCKED;
@@ -4465,10 +4491,7 @@ static int io_poll_add_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
        events = READ_ONCE(sqe->poll_events);
        poll->events = demangle_poll(events) | EPOLLERR | EPOLLHUP;
 
-       /*
-        * Don't need a reference here, as we're adding it to the task
-        * task_works list. If the task exits, the list is pruned.
-        */
+       get_task_struct(current);
        req->task = current;
        return 0;
 }
@@ -5331,7 +5354,8 @@ static int io_file_get(struct io_submit_state *state, struct io_kiocb *req,
                file = io_file_from_index(ctx, fd);
                if (!file)
                        return -EBADF;
-               percpu_ref_get(&ctx->file_data->refs);
+               req->fixed_file_refs = ctx->file_data->cur_refs;
+               percpu_ref_get(req->fixed_file_refs);
        } else {
                trace_io_uring_file_get(ctx, fd);
                file = __io_file_get(state, fd);
@@ -5344,15 +5368,10 @@ static int io_file_get(struct io_submit_state *state, struct io_kiocb *req,
 }
 
 static int io_req_set_file(struct io_submit_state *state, struct io_kiocb *req,
-                          const struct io_uring_sqe *sqe)
+                          int fd, unsigned int flags)
 {
-       unsigned flags;
-       int fd;
        bool fixed;
 
-       flags = READ_ONCE(sqe->flags);
-       fd = READ_ONCE(sqe->fd);
-
        if (!io_req_needs_file(req, fd))
                return 0;
 
@@ -5594,7 +5613,7 @@ static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
 {
        struct io_ring_ctx *ctx = req->ctx;
        unsigned int sqe_flags;
-       int ret, id;
+       int ret, id, fd;
 
        sqe_flags = READ_ONCE(sqe->flags);
 
@@ -5625,7 +5644,8 @@ static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                                        IOSQE_ASYNC | IOSQE_FIXED_FILE |
                                        IOSQE_BUFFER_SELECT);
 
-       ret = io_req_set_file(state, req, sqe);
+       fd = READ_ONCE(sqe->fd);
+       ret = io_req_set_file(state, req, fd, sqe_flags);
        if (unlikely(ret)) {
 err_req:
                io_cqring_add_event(req, ret);
@@ -5741,8 +5761,7 @@ static void io_commit_sqring(struct io_ring_ctx *ctx)
  * used, it's important that those reads are done through READ_ONCE() to
  * prevent a re-load down the line.
  */
-static bool io_get_sqring(struct io_ring_ctx *ctx, struct io_kiocb *req,
-                         const struct io_uring_sqe **sqe_ptr)
+static const struct io_uring_sqe *io_get_sqe(struct io_ring_ctx *ctx)
 {
        u32 *sq_array = ctx->sq_array;
        unsigned head;
@@ -5756,25 +5775,40 @@ static bool io_get_sqring(struct io_ring_ctx *ctx, struct io_kiocb *req,
         *    though the application is the one updating it.
         */
        head = READ_ONCE(sq_array[ctx->cached_sq_head & ctx->sq_mask]);
-       if (likely(head < ctx->sq_entries)) {
-               /*
-                * All io need record the previous position, if LINK vs DARIN,
-                * it can be used to mark the position of the first IO in the
-                * link list.
-                */
-               req->sequence = ctx->cached_sq_head;
-               *sqe_ptr = &ctx->sq_sqes[head];
-               req->opcode = READ_ONCE((*sqe_ptr)->opcode);
-               req->user_data = READ_ONCE((*sqe_ptr)->user_data);
-               ctx->cached_sq_head++;
-               return true;
-       }
+       if (likely(head < ctx->sq_entries))
+               return &ctx->sq_sqes[head];
 
        /* drop invalid entries */
-       ctx->cached_sq_head++;
        ctx->cached_sq_dropped++;
        WRITE_ONCE(ctx->rings->sq_dropped, ctx->cached_sq_dropped);
-       return false;
+       return NULL;
+}
+
+static inline void io_consume_sqe(struct io_ring_ctx *ctx)
+{
+       ctx->cached_sq_head++;
+}
+
+static void io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
+                       const struct io_uring_sqe *sqe)
+{
+       /*
+        * All io need record the previous position, if LINK vs DARIN,
+        * it can be used to mark the position of the first IO in the
+        * link list.
+        */
+       req->sequence = ctx->cached_sq_head;
+       req->opcode = READ_ONCE(sqe->opcode);
+       req->user_data = READ_ONCE(sqe->user_data);
+       req->io = NULL;
+       req->file = NULL;
+       req->ctx = ctx;
+       req->flags = 0;
+       /* one is dropped after submission, the other at completion */
+       refcount_set(&req->refs, 2);
+       req->task = NULL;
+       req->result = 0;
+       INIT_IO_WORK(&req->work, io_wq_submit_work);
 }
 
 static int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr,
@@ -5812,17 +5846,20 @@ static int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr,
                struct io_kiocb *req;
                int err;
 
-               req = io_get_req(ctx, statep);
+               sqe = io_get_sqe(ctx);
+               if (unlikely(!sqe)) {
+                       io_consume_sqe(ctx);
+                       break;
+               }
+               req = io_alloc_req(ctx, statep);
                if (unlikely(!req)) {
                        if (!submitted)
                                submitted = -EAGAIN;
                        break;
                }
-               if (!io_get_sqring(ctx, req, &sqe)) {
-                       __io_req_do_free(req);
-                       break;
-               }
 
+               io_init_req(ctx, req, sqe);
+               io_consume_sqe(ctx);
                /* will complete beyond this point, count as submitted */
                submitted++;
 
@@ -5962,6 +5999,7 @@ static int io_sq_thread(void *data)
                                }
                                if (current->task_works) {
                                        task_work_run();
+                                       finish_wait(&ctx->sqo_wait, &wait);
                                        continue;
                                }
                                if (signal_pending(current))
@@ -6124,43 +6162,36 @@ static void io_file_ref_kill(struct percpu_ref *ref)
        complete(&data->done);
 }
 
-static void io_file_ref_exit_and_free(struct work_struct *work)
-{
-       struct fixed_file_data *data;
-
-       data = container_of(work, struct fixed_file_data, ref_work);
-
-       /*
-        * Ensure any percpu-ref atomic switch callback has run, it could have
-        * been in progress when the files were being unregistered. Once
-        * that's done, we can safely exit and free the ref and containing
-        * data structure.
-        */
-       rcu_barrier();
-       percpu_ref_exit(&data->refs);
-       kfree(data);
-}
-
 static int io_sqe_files_unregister(struct io_ring_ctx *ctx)
 {
        struct fixed_file_data *data = ctx->file_data;
+       struct fixed_file_ref_node *ref_node = NULL;
        unsigned nr_tables, i;
+       unsigned long flags;
 
        if (!data)
                return -ENXIO;
 
-       percpu_ref_kill_and_confirm(&data->refs, io_file_ref_kill);
-       flush_work(&data->ref_work);
+       spin_lock_irqsave(&data->lock, flags);
+       if (!list_empty(&data->ref_list))
+               ref_node = list_first_entry(&data->ref_list,
+                               struct fixed_file_ref_node, node);
+       spin_unlock_irqrestore(&data->lock, flags);
+       if (ref_node)
+               percpu_ref_kill(&ref_node->refs);
+
+       percpu_ref_kill(&data->refs);
+
+       /* wait for all refs nodes to complete */
        wait_for_completion(&data->done);
-       io_ring_file_ref_flush(data);
 
        __io_sqe_files_unregister(ctx);
        nr_tables = DIV_ROUND_UP(ctx->nr_user_files, IORING_MAX_FILES_TABLE);
        for (i = 0; i < nr_tables; i++)
                kfree(data->table[i].files);
        kfree(data->table);
-       INIT_WORK(&data->ref_work, io_file_ref_exit_and_free);
-       queue_work(system_wq, &data->ref_work);
+       percpu_ref_exit(&data->refs);
+       kfree(data);
        ctx->file_data = NULL;
        ctx->nr_user_files = 0;
        return 0;
@@ -6204,13 +6235,6 @@ static int __io_sqe_files_scm(struct io_ring_ctx *ctx, int nr, int offset)
        struct sk_buff *skb;
        int i, nr_files;
 
-       if (!capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) {
-               unsigned long inflight = ctx->user->unix_inflight + nr;
-
-               if (inflight > task_rlimit(current, RLIMIT_NOFILE))
-                       return -EMFILE;
-       }
-
        fpl = kzalloc(sizeof(*fpl), GFP_KERNEL);
        if (!fpl)
                return -ENOMEM;
@@ -6385,46 +6409,72 @@ static void io_ring_file_put(struct io_ring_ctx *ctx, struct file *file)
 }
 
 struct io_file_put {
-       struct llist_node llist;
+       struct list_head list;
        struct file *file;
 };
 
-static void io_ring_file_ref_flush(struct fixed_file_data *data)
+static void io_file_put_work(struct work_struct *work)
 {
+       struct fixed_file_ref_node *ref_node;
+       struct fixed_file_data *file_data;
+       struct io_ring_ctx *ctx;
        struct io_file_put *pfile, *tmp;
-       struct llist_node *node;
+       unsigned long flags;
 
-       while ((node = llist_del_all(&data->put_llist)) != NULL) {
-               llist_for_each_entry_safe(pfile, tmp, node, llist) {
-                       io_ring_file_put(data->ctx, pfile->file);
-                       kfree(pfile);
-               }
+       ref_node = container_of(work, struct fixed_file_ref_node, work);
+       file_data = ref_node->file_data;
+       ctx = file_data->ctx;
+
+       list_for_each_entry_safe(pfile, tmp, &ref_node->file_list, list) {
+               list_del_init(&pfile->list);
+               io_ring_file_put(ctx, pfile->file);
+               kfree(pfile);
        }
+
+       spin_lock_irqsave(&file_data->lock, flags);
+       list_del_init(&ref_node->node);
+       spin_unlock_irqrestore(&file_data->lock, flags);
+
+       percpu_ref_exit(&ref_node->refs);
+       kfree(ref_node);
+       percpu_ref_put(&file_data->refs);
 }
 
-static void io_ring_file_ref_switch(struct work_struct *work)
+static void io_file_data_ref_zero(struct percpu_ref *ref)
 {
-       struct fixed_file_data *data;
+       struct fixed_file_ref_node *ref_node;
+
+       ref_node = container_of(ref, struct fixed_file_ref_node, refs);
 
-       data = container_of(work, struct fixed_file_data, ref_work);
-       io_ring_file_ref_flush(data);
-       percpu_ref_switch_to_percpu(&data->refs);
+       queue_work(system_wq, &ref_node->work);
 }
 
-static void io_file_data_ref_zero(struct percpu_ref *ref)
+static struct fixed_file_ref_node *alloc_fixed_file_ref_node(
+                       struct io_ring_ctx *ctx)
 {
-       struct fixed_file_data *data;
+       struct fixed_file_ref_node *ref_node;
 
-       data = container_of(ref, struct fixed_file_data, refs);
+       ref_node = kzalloc(sizeof(*ref_node), GFP_KERNEL);
+       if (!ref_node)
+               return ERR_PTR(-ENOMEM);
+
+       if (percpu_ref_init(&ref_node->refs, io_file_data_ref_zero,
+                           0, GFP_KERNEL)) {
+               kfree(ref_node);
+               return ERR_PTR(-ENOMEM);
+       }
+       INIT_LIST_HEAD(&ref_node->node);
+       INIT_LIST_HEAD(&ref_node->file_list);
+       INIT_WORK(&ref_node->work, io_file_put_work);
+       ref_node->file_data = ctx->file_data;
+       return ref_node;
 
-       /*
-        * We can't safely switch from inside this context, punt to wq. If
-        * the table ref is going away, the table is being unregistered.
-        * Don't queue up the async work for that case, the caller will
-        * handle it.
-        */
-       if (!percpu_ref_is_dying(&data->refs))
-               queue_work(system_wq, &data->ref_work);
+}
+
+static void destroy_fixed_file_ref_node(struct fixed_file_ref_node *ref_node)
+{
+       percpu_ref_exit(&ref_node->refs);
+       kfree(ref_node);
 }
 
 static int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
@@ -6435,6 +6485,8 @@ static int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
        struct file *file;
        int fd, ret = 0;
        unsigned i;
+       struct fixed_file_ref_node *ref_node;
+       unsigned long flags;
 
        if (ctx->file_data)
                return -EBUSY;
@@ -6448,6 +6500,8 @@ static int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
                return -ENOMEM;
        ctx->file_data->ctx = ctx;
        init_completion(&ctx->file_data->done);
+       INIT_LIST_HEAD(&ctx->file_data->ref_list);
+       spin_lock_init(&ctx->file_data->lock);
 
        nr_tables = DIV_ROUND_UP(nr_args, IORING_MAX_FILES_TABLE);
        ctx->file_data->table = kcalloc(nr_tables,
@@ -6459,15 +6513,13 @@ static int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
                return -ENOMEM;
        }
 
-       if (percpu_ref_init(&ctx->file_data->refs, io_file_data_ref_zero,
+       if (percpu_ref_init(&ctx->file_data->refs, io_file_ref_kill,
                                PERCPU_REF_ALLOW_REINIT, GFP_KERNEL)) {
                kfree(ctx->file_data->table);
                kfree(ctx->file_data);
                ctx->file_data = NULL;
                return -ENOMEM;
        }
-       ctx->file_data->put_llist.first = NULL;
-       INIT_WORK(&ctx->file_data->ref_work, io_ring_file_ref_switch);
 
        if (io_sqe_alloc_file_tables(ctx, nr_tables, nr_args)) {
                percpu_ref_exit(&ctx->file_data->refs);
@@ -6530,9 +6582,22 @@ static int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
        }
 
        ret = io_sqe_files_scm(ctx);
-       if (ret)
+       if (ret) {
                io_sqe_files_unregister(ctx);
+               return ret;
+       }
+
+       ref_node = alloc_fixed_file_ref_node(ctx);
+       if (IS_ERR(ref_node)) {
+               io_sqe_files_unregister(ctx);
+               return PTR_ERR(ref_node);
+       }
 
+       ctx->file_data->cur_refs = &ref_node->refs;
+       spin_lock_irqsave(&ctx->file_data->lock, flags);
+       list_add(&ref_node->node, &ctx->file_data->ref_list);
+       spin_unlock_irqrestore(&ctx->file_data->lock, flags);
+       percpu_ref_get(&ctx->file_data->refs);
        return ret;
 }
 
@@ -6579,30 +6644,21 @@ static int io_sqe_file_register(struct io_ring_ctx *ctx, struct file *file,
 #endif
 }
 
-static void io_atomic_switch(struct percpu_ref *ref)
-{
-       struct fixed_file_data *data;
-
-       /*
-        * Juggle reference to ensure we hit zero, if needed, so we can
-        * switch back to percpu mode
-        */
-       data = container_of(ref, struct fixed_file_data, refs);
-       percpu_ref_put(&data->refs);
-       percpu_ref_get(&data->refs);
-}
-
 static int io_queue_file_removal(struct fixed_file_data *data,
-                                 struct file *file)
+                                struct file *file)
 {
        struct io_file_put *pfile;
+       struct percpu_ref *refs = data->cur_refs;
+       struct fixed_file_ref_node *ref_node;
 
        pfile = kzalloc(sizeof(*pfile), GFP_KERNEL);
        if (!pfile)
                return -ENOMEM;
 
+       ref_node = container_of(refs, struct fixed_file_ref_node, refs);
        pfile->file = file;
-       llist_add(&pfile->llist, &data->put_llist);
+       list_add(&pfile->list, &ref_node->file_list);
+
        return 0;
 }
 
@@ -6611,17 +6667,23 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
                                 unsigned nr_args)
 {
        struct fixed_file_data *data = ctx->file_data;
-       bool ref_switch = false;
+       struct fixed_file_ref_node *ref_node;
        struct file *file;
        __s32 __user *fds;
        int fd, i, err;
        __u32 done;
+       unsigned long flags;
+       bool needs_switch = false;
 
        if (check_add_overflow(up->offset, nr_args, &done))
                return -EOVERFLOW;
        if (done > ctx->nr_user_files)
                return -EINVAL;
 
+       ref_node = alloc_fixed_file_ref_node(ctx);
+       if (IS_ERR(ref_node))
+               return PTR_ERR(ref_node);
+
        done = 0;
        fds = u64_to_user_ptr(up->fds);
        while (nr_args) {
@@ -6642,7 +6704,7 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
                        if (err)
                                break;
                        table->files[index] = NULL;
-                       ref_switch = true;
+                       needs_switch = true;
                }
                if (fd != -1) {
                        file = fget(fd);
@@ -6673,11 +6735,19 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
                up->offset++;
        }
 
-       if (ref_switch)
-               percpu_ref_switch_to_atomic(&data->refs, io_atomic_switch);
+       if (needs_switch) {
+               percpu_ref_kill(data->cur_refs);
+               spin_lock_irqsave(&data->lock, flags);
+               list_add(&ref_node->node, &data->ref_list);
+               data->cur_refs = &ref_node->refs;
+               spin_unlock_irqrestore(&data->lock, flags);
+               percpu_ref_get(&ctx->file_data->refs);
+       } else
+               destroy_fixed_file_ref_node(ref_node);
 
        return done ? done : err;
 }
+
 static int io_sqe_files_update(struct io_ring_ctx *ctx, void __user *arg,
                               unsigned nr_args)
 {
@@ -7203,6 +7273,18 @@ static int io_remove_personalities(int id, void *p, void *data)
        return 0;
 }
 
+static void io_ring_exit_work(struct work_struct *work)
+{
+       struct io_ring_ctx *ctx;
+
+       ctx = container_of(work, struct io_ring_ctx, exit_work);
+       if (ctx->rings)
+               io_cqring_overflow_flush(ctx, true);
+
+       wait_for_completion(&ctx->completions[0]);
+       io_ring_ctx_free(ctx);
+}
+
 static void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
 {
        mutex_lock(&ctx->uring_lock);
@@ -7230,8 +7312,8 @@ static void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
        if (ctx->rings)
                io_cqring_overflow_flush(ctx, true);
        idr_for_each(&ctx->personality_idr, io_remove_personalities, ctx);
-       wait_for_completion(&ctx->completions[0]);
-       io_ring_ctx_free(ctx);
+       INIT_WORK(&ctx->exit_work, io_ring_exit_work);
+       queue_work(system_wq, &ctx->exit_work);
 }
 
 static int io_uring_release(struct inode *inode, struct file *file)
index f080f54..89e2196 100644 (file)
@@ -302,6 +302,7 @@ iomap_readpage_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
 
        if (!ctx->bio || !is_contig || bio_full(ctx->bio, plen)) {
                gfp_t gfp = mapping_gfp_constraint(page->mapping, GFP_KERNEL);
+               gfp_t orig_gfp = gfp;
                int nr_vecs = (length + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
                if (ctx->bio)
@@ -310,6 +311,13 @@ iomap_readpage_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
                if (ctx->is_readahead) /* same as readahead_gfp_mask */
                        gfp |= __GFP_NORETRY | __GFP_NOWARN;
                ctx->bio = bio_alloc(gfp, min(BIO_MAX_PAGES, nr_vecs));
+               /*
+                * If the bio_alloc fails, try it again for a single page to
+                * avoid having to deal with partial page reads.  This emulates
+                * what do_mpage_readpage does.
+                */
+               if (!ctx->bio)
+                       ctx->bio = bio_alloc(orig_gfp, 1);
                ctx->bio->bi_opf = REQ_OP_READ;
                if (ctx->is_readahead)
                        ctx->bio->bi_opf |= REQ_RAHEAD;
@@ -975,13 +983,6 @@ static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset,
        return iomap_write_end(inode, pos, bytes, bytes, page, iomap, srcmap);
 }
 
-static int iomap_dax_zero(loff_t pos, unsigned offset, unsigned bytes,
-               struct iomap *iomap)
-{
-       return __dax_zero_page_range(iomap->bdev, iomap->dax_dev,
-                       iomap_sector(iomap, pos & PAGE_MASK), offset, bytes);
-}
-
 static loff_t
 iomap_zero_range_actor(struct inode *inode, loff_t pos, loff_t count,
                void *data, struct iomap *iomap, struct iomap *srcmap)
@@ -1001,7 +1002,7 @@ iomap_zero_range_actor(struct inode *inode, loff_t pos, loff_t count,
                bytes = min_t(loff_t, PAGE_SIZE - offset, count);
 
                if (IS_DAX(inode))
-                       status = iomap_dax_zero(pos, offset, bytes, iomap);
+                       status = dax_iomap_zero(pos, offset, bytes, iomap);
                else
                        status = iomap_zero(inode, pos, offset, bytes, iomap,
                                        srcmap);
index 25f1355..e7ddbce 100644 (file)
@@ -501,6 +501,7 @@ pnfs_alloc_ds_commits_list(struct list_head *list,
                rcu_read_lock();
                pnfs_put_commit_array(array, cinfo->inode);
        }
+       rcu_read_unlock();
        return ret;
 }
 
index 65b3abb..2f834ad 100644 (file)
@@ -7402,6 +7402,10 @@ int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh,
        struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
        struct ocfs2_inline_data *idata = &di->id2.i_data;
 
+       /* No need to punch hole beyond i_size. */
+       if (start >= i_size_read(inode))
+               return 0;
+
        if (end > i_size_read(inode))
                end = i_size_read(inode);
 
index c740159..af375e0 100644 (file)
@@ -346,23 +346,8 @@ static ssize_t orangefs_file_read_iter(struct kiocb *iocb,
     struct iov_iter *iter)
 {
        int ret;
-       struct orangefs_read_options *ro;
-
        orangefs_stats.reads++;
 
-       /*
-        * Remember how they set "count" in read(2) or pread(2) or whatever -
-        * users can use count as a knob to control orangefs io size and later
-        * we can try to help them fill as many pages as possible in readpage.
-        */
-       if (!iocb->ki_filp->private_data) {
-               iocb->ki_filp->private_data = kmalloc(sizeof *ro, GFP_KERNEL);
-               if (!iocb->ki_filp->private_data)
-                       return(ENOMEM);
-               ro = iocb->ki_filp->private_data;
-               ro->blksiz = iter->count;
-       }
-
        down_read(&file_inode(iocb->ki_filp)->i_rwsem);
        ret = orangefs_revalidate_mapping(file_inode(iocb->ki_filp));
        if (ret)
@@ -650,12 +635,6 @@ static int orangefs_lock(struct file *filp, int cmd, struct file_lock *fl)
        return rc;
 }
 
-static int orangefs_file_open(struct inode * inode, struct file *file)
-{
-       file->private_data = NULL;
-       return generic_file_open(inode, file);
-}
-
 static int orangefs_flush(struct file *file, fl_owner_t id)
 {
        /*
@@ -666,19 +645,8 @@ static int orangefs_flush(struct file *file, fl_owner_t id)
         * on an explicit fsync call.  This duplicates historical OrangeFS
         * behavior.
         */
-       struct inode *inode = file->f_mapping->host;
        int r;
 
-       kfree(file->private_data);
-       file->private_data = NULL;
-
-       if (inode->i_state & I_DIRTY_TIME) {
-               spin_lock(&inode->i_lock);
-               inode->i_state &= ~I_DIRTY_TIME;
-               spin_unlock(&inode->i_lock);
-               mark_inode_dirty_sync(inode);
-       }
-
        r = filemap_write_and_wait_range(file->f_mapping, 0, LLONG_MAX);
        if (r > 0)
                return 0;
@@ -694,7 +662,7 @@ const struct file_operations orangefs_file_operations = {
        .lock           = orangefs_lock,
        .unlocked_ioctl = orangefs_ioctl,
        .mmap           = orangefs_file_mmap,
-       .open           = orangefs_file_open,
+       .open           = generic_file_open,
        .flush          = orangefs_flush,
        .release        = orangefs_file_release,
        .fsync          = orangefs_fsync,
index 961c0fd..12ae630 100644 (file)
@@ -259,46 +259,19 @@ static int orangefs_readpage(struct file *file, struct page *page)
        pgoff_t index; /* which page */
        struct page *next_page;
        char *kaddr;
-       struct orangefs_read_options *ro = file->private_data;
        loff_t read_size;
-       loff_t roundedup;
        int buffer_index = -1; /* orangefs shared memory slot */
        int slot_index;   /* index into slot */
        int remaining;
 
        /*
-        * If they set some miniscule size for "count" in read(2)
-        * (for example) then let's try to read a page, or the whole file
-        * if it is smaller than a page. Once "count" goes over a page
-        * then lets round up to the highest page size multiple that is
-        * less than or equal to "count" and do that much orangefs IO and
-        * try to fill as many pages as we can from it.
-        *
-        * "count" should be represented in ro->blksiz.
-        *
-        * inode->i_size = file size.
+        * Get up to this many bytes from Orangefs at a time and try
+        * to fill them into the page cache at once. Tests with dd made
+        * this seem like a reasonable static number, if there was
+        * interest perhaps this number could be made setable through
+        * sysfs...
         */
-       if (ro) {
-               if (ro->blksiz < PAGE_SIZE) {
-                       if (inode->i_size < PAGE_SIZE)
-                               read_size = inode->i_size;
-                       else
-                               read_size = PAGE_SIZE;
-               } else {
-                       roundedup = ((PAGE_SIZE - 1) & ro->blksiz) ?
-                               ((ro->blksiz + PAGE_SIZE) & ~(PAGE_SIZE -1)) :
-                               ro->blksiz;
-                       if (roundedup > inode->i_size)
-                               read_size = inode->i_size;
-                       else
-                               read_size = roundedup;
-
-               }
-       } else {
-               read_size = PAGE_SIZE;
-       }
-       if (!read_size)
-               read_size = PAGE_SIZE;
+       read_size = 524288;
 
        if (PageDirty(page))
                orangefs_launder_page(page);
index ed67f39..e12aeb9 100644 (file)
@@ -239,10 +239,6 @@ struct orangefs_write_range {
        kgid_t gid;
 };
 
-struct orangefs_read_options {
-       ssize_t blksiz;
-};
-
 extern struct orangefs_stats orangefs_stats;
 
 /*
index 9fc47c2..9709cf2 100644 (file)
@@ -36,6 +36,13 @@ static int ovl_ccup_get(char *buf, const struct kernel_param *param)
 module_param_call(check_copy_up, ovl_ccup_set, ovl_ccup_get, NULL, 0644);
 MODULE_PARM_DESC(check_copy_up, "Obsolete; does nothing");
 
+static bool ovl_must_copy_xattr(const char *name)
+{
+       return !strcmp(name, XATTR_POSIX_ACL_ACCESS) ||
+              !strcmp(name, XATTR_POSIX_ACL_DEFAULT) ||
+              !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN);
+}
+
 int ovl_copy_xattr(struct dentry *old, struct dentry *new)
 {
        ssize_t list_size, size, value_size = 0;
@@ -107,8 +114,13 @@ retry:
                        continue; /* Discard */
                }
                error = vfs_setxattr(new, name, value, size, 0);
-               if (error)
-                       break;
+               if (error) {
+                       if (error != -EOPNOTSUPP || ovl_must_copy_xattr(name))
+                               break;
+
+                       /* Ignore failure to copy unknown xattrs */
+                       error = 0;
+               }
        }
        kfree(value);
 out:
index 8e57d53..279009d 100644 (file)
@@ -42,7 +42,7 @@ int ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
        return err;
 }
 
-static struct dentry *ovl_lookup_temp(struct dentry *workdir)
+struct dentry *ovl_lookup_temp(struct dentry *workdir)
 {
        struct dentry *temp;
        char name[20];
@@ -243,6 +243,9 @@ static int ovl_instantiate(struct dentry *dentry, struct inode *inode,
 
        ovl_dir_modified(dentry->d_parent, false);
        ovl_dentry_set_upper_alias(dentry);
+       ovl_dentry_update_reval(dentry, newdentry,
+                       DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE);
+
        if (!hardlink) {
                /*
                 * ovl_obtain_alias() can be called after ovl_create_real()
@@ -819,6 +822,28 @@ static bool ovl_pure_upper(struct dentry *dentry)
               !ovl_test_flag(OVL_WHITEOUTS, d_inode(dentry));
 }
 
+static void ovl_drop_nlink(struct dentry *dentry)
+{
+       struct inode *inode = d_inode(dentry);
+       struct dentry *alias;
+
+       /* Try to find another, hashed alias */
+       spin_lock(&inode->i_lock);
+       hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
+               if (alias != dentry && !d_unhashed(alias))
+                       break;
+       }
+       spin_unlock(&inode->i_lock);
+
+       /*
+        * Changes to underlying layers may cause i_nlink to lose sync with
+        * reality.  In this case prevent the link count from going to zero
+        * prematurely.
+        */
+       if (inode->i_nlink > !!alias)
+               drop_nlink(inode);
+}
+
 static int ovl_do_remove(struct dentry *dentry, bool is_dir)
 {
        int err;
@@ -856,7 +881,7 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
                if (is_dir)
                        clear_nlink(dentry->d_inode);
                else
-                       drop_nlink(dentry->d_inode);
+                       ovl_drop_nlink(dentry);
        }
        ovl_nlink_end(dentry);
 
@@ -1201,7 +1226,7 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
                if (new_is_dir)
                        clear_nlink(d_inode(new));
                else
-                       drop_nlink(d_inode(new));
+                       ovl_drop_nlink(new);
        }
 
        ovl_dir_modified(old->d_parent, ovl_type_origin(old) ||
index 6f54d70..475c61f 100644 (file)
@@ -308,29 +308,35 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb,
                ovl_set_flag(OVL_UPPERDATA, inode);
 
        dentry = d_find_any_alias(inode);
-       if (!dentry) {
-               dentry = d_alloc_anon(inode->i_sb);
-               if (!dentry)
-                       goto nomem;
-               oe = ovl_alloc_entry(lower ? 1 : 0);
-               if (!oe)
-                       goto nomem;
-
-               if (lower) {
-                       oe->lowerstack->dentry = dget(lower);
-                       oe->lowerstack->layer = lowerpath->layer;
-               }
-               dentry->d_fsdata = oe;
-               if (upper_alias)
-                       ovl_dentry_set_upper_alias(dentry);
+       if (dentry)
+               goto out_iput;
+
+       dentry = d_alloc_anon(inode->i_sb);
+       if (unlikely(!dentry))
+               goto nomem;
+       oe = ovl_alloc_entry(lower ? 1 : 0);
+       if (!oe)
+               goto nomem;
+
+       if (lower) {
+               oe->lowerstack->dentry = dget(lower);
+               oe->lowerstack->layer = lowerpath->layer;
        }
+       dentry->d_fsdata = oe;
+       if (upper_alias)
+               ovl_dentry_set_upper_alias(dentry);
+
+       ovl_dentry_update_reval(dentry, upper,
+                       DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE);
 
        return d_instantiate_anon(dentry, inode);
 
 nomem:
-       iput(inode);
        dput(dentry);
-       return ERR_PTR(-ENOMEM);
+       dentry = ERR_PTR(-ENOMEM);
+out_iput:
+       iput(inode);
+       return dentry;
 }
 
 /* Get the upper or lower dentry in stach whose on layer @idx */
index 79e8994..b0d42ec 100644 (file)
@@ -79,6 +79,7 @@ static int ovl_map_dev_ino(struct dentry *dentry, struct kstat *stat, int fsid)
 {
        bool samefs = ovl_same_fs(dentry->d_sb);
        unsigned int xinobits = ovl_xino_bits(dentry->d_sb);
+       unsigned int xinoshift = 64 - xinobits;
 
        if (samefs) {
                /*
@@ -89,22 +90,22 @@ static int ovl_map_dev_ino(struct dentry *dentry, struct kstat *stat, int fsid)
                stat->dev = dentry->d_sb->s_dev;
                return 0;
        } else if (xinobits) {
-               unsigned int shift = 64 - xinobits;
                /*
                 * All inode numbers of underlying fs should not be using the
                 * high xinobits, so we use high xinobits to partition the
                 * overlay st_ino address space. The high bits holds the fsid
-                * (upper fsid is 0). This way overlay inode numbers are unique
-                * and all inodes use overlay st_dev. Inode numbers are also
-                * persistent for a given layer configuration.
+                * (upper fsid is 0). The lowest xinobit is reserved for mapping
+                * the non-peresistent inode numbers range in case of overflow.
+                * This way all overlay inode numbers are unique and use the
+                * overlay st_dev.
                 */
-               if (stat->ino >> shift) {
-                       pr_warn_ratelimited("inode number too big (%pd2, ino=%llu, xinobits=%d)\n",
-                                           dentry, stat->ino, xinobits);
-               } else {
-                       stat->ino |= ((u64)fsid) << shift;
+               if (likely(!(stat->ino >> xinoshift))) {
+                       stat->ino |= ((u64)fsid) << (xinoshift + 1);
                        stat->dev = dentry->d_sb->s_dev;
                        return 0;
+               } else if (ovl_xino_warn(dentry->d_sb)) {
+                       pr_warn_ratelimited("inode number too big (%pd2, ino=%llu, xinobits=%d)\n",
+                                           dentry, stat->ino, xinobits);
                }
        }
 
@@ -504,7 +505,7 @@ static const struct address_space_operations ovl_aops = {
 
 /*
  * It is possible to stack overlayfs instance on top of another
- * overlayfs instance as lower layer. We need to annonate the
+ * overlayfs instance as lower layer. We need to annotate the
  * stackable i_mutex locks according to stack level of the super
  * block instance. An overlayfs instance can never be in stack
  * depth 0 (there is always a real fs below it).  An overlayfs
@@ -561,27 +562,73 @@ static inline void ovl_lockdep_annotate_inode_mutex_key(struct inode *inode)
 #endif
 }
 
-static void ovl_fill_inode(struct inode *inode, umode_t mode, dev_t rdev,
-                          unsigned long ino, int fsid)
+static void ovl_next_ino(struct inode *inode)
+{
+       struct ovl_fs *ofs = inode->i_sb->s_fs_info;
+
+       inode->i_ino = atomic_long_inc_return(&ofs->last_ino);
+       if (unlikely(!inode->i_ino))
+               inode->i_ino = atomic_long_inc_return(&ofs->last_ino);
+}
+
+static void ovl_map_ino(struct inode *inode, unsigned long ino, int fsid)
 {
        int xinobits = ovl_xino_bits(inode->i_sb);
+       unsigned int xinoshift = 64 - xinobits;
 
        /*
         * When d_ino is consistent with st_ino (samefs or i_ino has enough
         * bits to encode layer), set the same value used for st_ino to i_ino,
         * so inode number exposed via /proc/locks and a like will be
         * consistent with d_ino and st_ino values. An i_ino value inconsistent
-        * with d_ino also causes nfsd readdirplus to fail.  When called from
-        * ovl_new_inode(), ino arg is 0, so i_ino will be updated to real
-        * upper inode i_ino on ovl_inode_init() or ovl_inode_update().
+        * with d_ino also causes nfsd readdirplus to fail.
         */
-       if (ovl_same_dev(inode->i_sb)) {
-               inode->i_ino = ino;
-               if (xinobits && fsid && !(ino >> (64 - xinobits)))
-                       inode->i_ino |= (unsigned long)fsid << (64 - xinobits);
-       } else {
-               inode->i_ino = get_next_ino();
+       inode->i_ino = ino;
+       if (ovl_same_fs(inode->i_sb)) {
+               return;
+       } else if (xinobits && likely(!(ino >> xinoshift))) {
+               inode->i_ino |= (unsigned long)fsid << (xinoshift + 1);
+               return;
+       }
+
+       /*
+        * For directory inodes on non-samefs with xino disabled or xino
+        * overflow, we allocate a non-persistent inode number, to be used for
+        * resolving st_ino collisions in ovl_map_dev_ino().
+        *
+        * To avoid ino collision with legitimate xino values from upper
+        * layer (fsid 0), use the lowest xinobit to map the non
+        * persistent inode numbers to the unified st_ino address space.
+        */
+       if (S_ISDIR(inode->i_mode)) {
+               ovl_next_ino(inode);
+               if (xinobits) {
+                       inode->i_ino &= ~0UL >> xinobits;
+                       inode->i_ino |= 1UL << xinoshift;
+               }
        }
+}
+
+void ovl_inode_init(struct inode *inode, struct ovl_inode_params *oip,
+                   unsigned long ino, int fsid)
+{
+       struct inode *realinode;
+
+       if (oip->upperdentry)
+               OVL_I(inode)->__upperdentry = oip->upperdentry;
+       if (oip->lowerpath && oip->lowerpath->dentry)
+               OVL_I(inode)->lower = igrab(d_inode(oip->lowerpath->dentry));
+       if (oip->lowerdata)
+               OVL_I(inode)->lowerdata = igrab(d_inode(oip->lowerdata));
+
+       realinode = ovl_inode_real(inode);
+       ovl_copyattr(realinode, inode);
+       ovl_copyflags(realinode, inode);
+       ovl_map_ino(inode, ino, fsid);
+}
+
+static void ovl_fill_inode(struct inode *inode, umode_t mode, dev_t rdev)
+{
        inode->i_mode = mode;
        inode->i_flags |= S_NOCMTIME;
 #ifdef CONFIG_FS_POSIX_ACL
@@ -719,7 +766,7 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, dev_t rdev)
 
        inode = new_inode(sb);
        if (inode)
-               ovl_fill_inode(inode, mode, rdev, 0, 0);
+               ovl_fill_inode(inode, mode, rdev);
 
        return inode;
 }
@@ -891,7 +938,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
        struct dentry *lowerdentry = lowerpath ? lowerpath->dentry : NULL;
        bool bylower = ovl_hash_bylower(sb, upperdentry, lowerdentry,
                                        oip->index);
-       int fsid = bylower ? oip->lowerpath->layer->fsid : 0;
+       int fsid = bylower ? lowerpath->layer->fsid : 0;
        bool is_dir, metacopy = false;
        unsigned long ino = 0;
        int err = oip->newinode ? -EEXIST : -ENOMEM;
@@ -941,9 +988,11 @@ struct inode *ovl_get_inode(struct super_block *sb,
                        err = -ENOMEM;
                        goto out_err;
                }
+               ino = realinode->i_ino;
+               fsid = lowerpath->layer->fsid;
        }
-       ovl_fill_inode(inode, realinode->i_mode, realinode->i_rdev, ino, fsid);
-       ovl_inode_init(inode, upperdentry, lowerdentry, oip->lowerdata);
+       ovl_fill_inode(inode, realinode->i_mode, realinode->i_rdev);
+       ovl_inode_init(inode, oip, ino, fsid);
 
        if (upperdentry && ovl_is_impuredir(upperdentry))
                ovl_set_flag(OVL_IMPURE, inode);
index ed9e129..0db23ba 100644 (file)
@@ -845,7 +845,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
                if (err)
                        goto out;
 
-               if (upperdentry && unlikely(ovl_dentry_remote(upperdentry))) {
+               if (upperdentry && upperdentry->d_flags & DCACHE_OP_REAL) {
                        dput(upperdentry);
                        err = -EREMOTE;
                        goto out;
@@ -1076,6 +1076,9 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
                        goto out_free_oe;
        }
 
+       ovl_dentry_update_reval(dentry, upperdentry,
+                       DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE);
+
        revert_creds(old_cred);
        if (origin_path) {
                dput(origin_path->dentry);
index 3d3f2b8..e6f3670 100644 (file)
@@ -48,6 +48,12 @@ enum ovl_entry_flag {
        OVL_E_CONNECTED,
 };
 
+enum {
+       OVL_XINO_OFF,
+       OVL_XINO_AUTO,
+       OVL_XINO_ON,
+};
+
 /*
  * The tuple (fh,uuid) is a universal unique identifier for a copy up origin,
  * where:
@@ -87,7 +93,7 @@ struct ovl_fb {
        u8 flags;       /* OVL_FH_FLAG_* */
        u8 type;        /* fid_type of fid */
        uuid_t uuid;    /* uuid of filesystem */
-       u32 fid[0];     /* file identifier should be 32bit aligned in-memory */
+       u32 fid[];      /* file identifier should be 32bit aligned in-memory */
 } __packed;
 
 /* In-memory and on-wire format for overlay file handle */
@@ -230,6 +236,8 @@ bool ovl_index_all(struct super_block *sb);
 bool ovl_verify_lower(struct super_block *sb);
 struct ovl_entry *ovl_alloc_entry(unsigned int numlower);
 bool ovl_dentry_remote(struct dentry *dentry);
+void ovl_dentry_update_reval(struct dentry *dentry, struct dentry *upperdentry,
+                            unsigned int mask);
 bool ovl_dentry_weird(struct dentry *dentry);
 enum ovl_path_type ovl_path_type(struct dentry *dentry);
 void ovl_path_upper(struct dentry *dentry, struct path *path);
@@ -264,8 +272,6 @@ void ovl_set_upperdata(struct inode *inode);
 bool ovl_redirect_dir(struct super_block *sb);
 const char *ovl_dentry_get_redirect(struct dentry *dentry);
 void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect);
-void ovl_inode_init(struct inode *inode, struct dentry *upperdentry,
-                   struct dentry *lowerdentry, struct dentry *lowerdata);
 void ovl_inode_update(struct inode *inode, struct dentry *upperdentry);
 void ovl_dir_modified(struct dentry *dentry, bool impurity);
 u64 ovl_dentry_version_get(struct dentry *dentry);
@@ -301,6 +307,16 @@ static inline bool ovl_is_impuredir(struct dentry *dentry)
        return ovl_check_dir_xattr(dentry, OVL_XATTR_IMPURE);
 }
 
+/*
+ * With xino=auto, we do best effort to keep all inodes on same st_dev and
+ * d_ino consistent with st_ino.
+ * With xino=on, we do the same effort but we warn if we failed.
+ */
+static inline bool ovl_xino_warn(struct super_block *sb)
+{
+       return OVL_FS(sb)->config.xino == OVL_XINO_ON;
+}
+
 /* All layers on same fs? */
 static inline bool ovl_same_fs(struct super_block *sb)
 {
@@ -410,6 +426,8 @@ struct ovl_inode_params {
        char *redirect;
        struct dentry *lowerdata;
 };
+void ovl_inode_init(struct inode *inode, struct ovl_inode_params *oip,
+                   unsigned long ino, int fsid);
 struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, dev_t rdev);
 struct inode *ovl_lookup_inode(struct super_block *sb, struct dentry *real,
                               bool is_upper);
@@ -451,6 +469,7 @@ struct ovl_cattr {
 struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
                               struct ovl_cattr *attr);
 int ovl_cleanup(struct inode *dir, struct dentry *dentry);
+struct dentry *ovl_lookup_temp(struct dentry *workdir);
 struct dentry *ovl_create_temp(struct dentry *workdir, struct ovl_cattr *attr);
 
 /* file.c */
index 89015ea..5762d80 100644 (file)
@@ -75,6 +75,8 @@ struct ovl_fs {
        struct inode *indexdir_trap;
        /* -1: disabled, 0: same fs, 1..32: number of unused ino bits */
        int xino_mode;
+       /* For allocation of non-persistent inode numbers */
+       atomic_long_t last_ino;
 };
 
 static inline struct ovl_fs *OVL_FS(struct super_block *sb)
index 40ac9ce..e452ff7 100644 (file)
@@ -438,15 +438,23 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
 
 /* Map inode number to lower fs unique range */
 static u64 ovl_remap_lower_ino(u64 ino, int xinobits, int fsid,
-                              const char *name, int namelen)
+                              const char *name, int namelen, bool warn)
 {
-       if (ino >> (64 - xinobits)) {
-               pr_warn_ratelimited("d_ino too big (%.*s, ino=%llu, xinobits=%d)\n",
-                                   namelen, name, ino, xinobits);
+       unsigned int xinoshift = 64 - xinobits;
+
+       if (unlikely(ino >> xinoshift)) {
+               if (warn) {
+                       pr_warn_ratelimited("d_ino too big (%.*s, ino=%llu, xinobits=%d)\n",
+                                           namelen, name, ino, xinobits);
+               }
                return ino;
        }
 
-       return ino | ((u64)fsid) << (64 - xinobits);
+       /*
+        * The lowest xinobit is reserved for mapping the non-peresistent inode
+        * numbers range, but this range is only exposed via st_ino, not here.
+        */
+       return ino | ((u64)fsid) << (xinoshift + 1);
 }
 
 /*
@@ -515,7 +523,8 @@ get:
        } else if (xinobits && !OVL_TYPE_UPPER(type)) {
                ino = ovl_remap_lower_ino(ino, xinobits,
                                          ovl_layer_lower(this)->fsid,
-                                         p->name, p->len);
+                                         p->name, p->len,
+                                         ovl_xino_warn(dir->d_sb));
        }
 
 out:
@@ -645,6 +654,7 @@ struct ovl_readdir_translate {
        u64 parent_ino;
        int fsid;
        int xinobits;
+       bool xinowarn;
 };
 
 static int ovl_fill_real(struct dir_context *ctx, const char *name,
@@ -665,7 +675,7 @@ static int ovl_fill_real(struct dir_context *ctx, const char *name,
                        ino = p->ino;
        } else if (rdt->xinobits) {
                ino = ovl_remap_lower_ino(ino, rdt->xinobits, rdt->fsid,
-                                         name, namelen);
+                                         name, namelen, rdt->xinowarn);
        }
 
        return orig_ctx->actor(orig_ctx, name, namelen, offset, ino, d_type);
@@ -696,6 +706,7 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
                .ctx.actor = ovl_fill_real,
                .orig_ctx = ctx,
                .xinobits = ovl_xino_bits(dir->d_sb),
+               .xinowarn = ovl_xino_warn(dir->d_sb),
        };
 
        if (rdt.xinobits && lower_layer)
index ac967f1..732ad54 100644 (file)
@@ -113,53 +113,54 @@ bug:
        return dentry;
 }
 
-static int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags)
+static int ovl_revalidate_real(struct dentry *d, unsigned int flags, bool weak)
 {
-       struct ovl_entry *oe = dentry->d_fsdata;
-       unsigned int i;
        int ret = 1;
 
-       for (i = 0; i < oe->numlower; i++) {
-               struct dentry *d = oe->lowerstack[i].dentry;
-
-               if (d->d_flags & DCACHE_OP_REVALIDATE) {
-                       ret = d->d_op->d_revalidate(d, flags);
-                       if (ret < 0)
-                               return ret;
-                       if (!ret) {
-                               if (!(flags & LOOKUP_RCU))
-                                       d_invalidate(d);
-                               return -ESTALE;
-                       }
+       if (weak) {
+               if (d->d_flags & DCACHE_OP_WEAK_REVALIDATE)
+                       ret =  d->d_op->d_weak_revalidate(d, flags);
+       } else if (d->d_flags & DCACHE_OP_REVALIDATE) {
+               ret = d->d_op->d_revalidate(d, flags);
+               if (!ret) {
+                       if (!(flags & LOOKUP_RCU))
+                               d_invalidate(d);
+                       ret = -ESTALE;
                }
        }
-       return 1;
+       return ret;
 }
 
-static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags)
+static int ovl_dentry_revalidate_common(struct dentry *dentry,
+                                       unsigned int flags, bool weak)
 {
        struct ovl_entry *oe = dentry->d_fsdata;
+       struct dentry *upper;
        unsigned int i;
        int ret = 1;
 
-       for (i = 0; i < oe->numlower; i++) {
-               struct dentry *d = oe->lowerstack[i].dentry;
+       upper = ovl_dentry_upper(dentry);
+       if (upper)
+               ret = ovl_revalidate_real(upper, flags, weak);
 
-               if (d->d_flags & DCACHE_OP_WEAK_REVALIDATE) {
-                       ret = d->d_op->d_weak_revalidate(d, flags);
-                       if (ret <= 0)
-                               break;
-               }
+       for (i = 0; ret > 0 && i < oe->numlower; i++) {
+               ret = ovl_revalidate_real(oe->lowerstack[i].dentry, flags,
+                                         weak);
        }
        return ret;
 }
 
-static const struct dentry_operations ovl_dentry_operations = {
-       .d_release = ovl_dentry_release,
-       .d_real = ovl_d_real,
-};
+static int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags)
+{
+       return ovl_dentry_revalidate_common(dentry, flags, false);
+}
+
+static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags)
+{
+       return ovl_dentry_revalidate_common(dentry, flags, true);
+}
 
-static const struct dentry_operations ovl_reval_dentry_operations = {
+static const struct dentry_operations ovl_dentry_operations = {
        .d_release = ovl_dentry_release,
        .d_real = ovl_d_real,
        .d_revalidate = ovl_dentry_revalidate,
@@ -316,12 +317,6 @@ static const char *ovl_redirect_mode_def(void)
        return ovl_redirect_dir_def ? "on" : "off";
 }
 
-enum {
-       OVL_XINO_OFF,
-       OVL_XINO_AUTO,
-       OVL_XINO_ON,
-};
-
 static const char * const ovl_xino_str[] = {
        "off",
        "auto",
@@ -751,13 +746,12 @@ static int ovl_mount_dir(const char *name, struct path *path)
                ovl_unescape(tmp);
                err = ovl_mount_dir_noesc(tmp, path);
 
-               if (!err)
-                       if (ovl_dentry_remote(path->dentry)) {
-                               pr_err("filesystem on '%s' not supported as upperdir\n",
-                                      tmp);
-                               path_put_init(path);
-                               err = -EINVAL;
-                       }
+               if (!err && path->dentry->d_flags & DCACHE_OP_REAL) {
+                       pr_err("filesystem on '%s' not supported as upperdir\n",
+                              tmp);
+                       path_put_init(path);
+                       err = -EINVAL;
+               }
                kfree(tmp);
        }
        return err;
@@ -778,7 +772,7 @@ static int ovl_check_namelen(struct path *path, struct ovl_fs *ofs,
 }
 
 static int ovl_lower_dir(const char *name, struct path *path,
-                        struct ovl_fs *ofs, int *stack_depth, bool *remote)
+                        struct ovl_fs *ofs, int *stack_depth)
 {
        int fh_type;
        int err;
@@ -793,9 +787,6 @@ static int ovl_lower_dir(const char *name, struct path *path,
 
        *stack_depth = max(*stack_depth, path->mnt->mnt_sb->s_stack_depth);
 
-       if (ovl_dentry_remote(path->dentry))
-               *remote = true;
-
        /*
         * The inodes index feature and NFS export need to encode and decode
         * file handles, so they require that all layers support them.
@@ -1074,11 +1065,73 @@ out:
        return err;
 }
 
+/*
+ * Returns 1 if RENAME_WHITEOUT is supported, 0 if not supported and
+ * negative values if error is encountered.
+ */
+static int ovl_check_rename_whiteout(struct dentry *workdir)
+{
+       struct inode *dir = d_inode(workdir);
+       struct dentry *temp;
+       struct dentry *dest;
+       struct dentry *whiteout;
+       struct name_snapshot name;
+       int err;
+
+       inode_lock_nested(dir, I_MUTEX_PARENT);
+
+       temp = ovl_create_temp(workdir, OVL_CATTR(S_IFREG | 0));
+       err = PTR_ERR(temp);
+       if (IS_ERR(temp))
+               goto out_unlock;
+
+       dest = ovl_lookup_temp(workdir);
+       err = PTR_ERR(dest);
+       if (IS_ERR(dest)) {
+               dput(temp);
+               goto out_unlock;
+       }
+
+       /* Name is inline and stable - using snapshot as a copy helper */
+       take_dentry_name_snapshot(&name, temp);
+       err = ovl_do_rename(dir, temp, dir, dest, RENAME_WHITEOUT);
+       if (err) {
+               if (err == -EINVAL)
+                       err = 0;
+               goto cleanup_temp;
+       }
+
+       whiteout = lookup_one_len(name.name.name, workdir, name.name.len);
+       err = PTR_ERR(whiteout);
+       if (IS_ERR(whiteout))
+               goto cleanup_temp;
+
+       err = ovl_is_whiteout(whiteout);
+
+       /* Best effort cleanup of whiteout and temp file */
+       if (err)
+               ovl_cleanup(dir, whiteout);
+       dput(whiteout);
+
+cleanup_temp:
+       ovl_cleanup(dir, temp);
+       release_dentry_name_snapshot(&name);
+       dput(temp);
+       dput(dest);
+
+out_unlock:
+       inode_unlock(dir);
+
+       return err;
+}
+
 static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
                            struct path *workpath)
 {
        struct vfsmount *mnt = ofs->upper_mnt;
        struct dentry *temp;
+       bool rename_whiteout;
+       bool d_type;
        int fh_type;
        int err;
 
@@ -1104,11 +1157,8 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
        if (err < 0)
                goto out;
 
-       /*
-        * We allowed this configuration and don't want to break users over
-        * kernel upgrade. So warn instead of erroring out.
-        */
-       if (!err)
+       d_type = err;
+       if (!d_type)
                pr_warn("upper fs needs to support d_type.\n");
 
        /* Check if upper/work fs supports O_TMPFILE */
@@ -1119,6 +1169,16 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
        else
                pr_warn("upper fs does not support tmpfile.\n");
 
+
+       /* Check if upper/work fs supports RENAME_WHITEOUT */
+       err = ovl_check_rename_whiteout(ofs->workdir);
+       if (err < 0)
+               goto out;
+
+       rename_whiteout = err;
+       if (!rename_whiteout)
+               pr_warn("upper fs does not support RENAME_WHITEOUT.\n");
+
        /*
         * Check if upper/work fs supports trusted.overlay.* xattr
         */
@@ -1133,6 +1193,18 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
                vfs_removexattr(ofs->workdir, OVL_XATTR_OPAQUE);
        }
 
+       /*
+        * We allowed sub-optimal upper fs configuration and don't want to break
+        * users over kernel upgrade, but we never allowed remote upper fs, so
+        * we can enforce strict requirements for remote upper fs.
+        */
+       if (ovl_dentry_remote(ofs->workdir) &&
+           (!d_type || !rename_whiteout || ofs->noxattr)) {
+               pr_err("upper fs missing required features.\n");
+               err = -EINVAL;
+               goto out;
+       }
+
        /* Check if upper/work fs supports file handles */
        fh_type = ovl_can_decode_fh(ofs->workdir->d_sb);
        if (ofs->config.index && !fh_type) {
@@ -1401,11 +1473,12 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
 
        /*
         * When all layers on same fs, overlay can use real inode numbers.
-        * With mount option "xino=on", mounter declares that there are enough
-        * free high bits in underlying fs to hold the unique fsid.
+        * With mount option "xino=<on|auto>", mounter declares that there are
+        * enough free high bits in underlying fs to hold the unique fsid.
         * If overlayfs does encounter underlying inodes using the high xino
         * bits reserved for fsid, it emits a warning and uses the original
-        * inode number.
+        * inode number or a non persistent inode number allocated from a
+        * dedicated range.
         */
        if (ofs->numfs - !ofs->upper_mnt == 1) {
                if (ofs->config.xino == OVL_XINO_ON)
@@ -1413,14 +1486,16 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
                ofs->xino_mode = 0;
        } else if (ofs->config.xino == OVL_XINO_OFF) {
                ofs->xino_mode = -1;
-       } else if (ofs->config.xino == OVL_XINO_ON && ofs->xino_mode < 0) {
+       } else if (ofs->xino_mode < 0) {
                /*
                 * This is a roundup of number of bits needed for encoding
-                * fsid, where fsid 0 is reserved for upper fs even with
-                * lower only overlay.
+                * fsid, where fsid 0 is reserved for upper fs (even with
+                * lower only overlay) +1 extra bit is reserved for the non
+                * persistent inode number range that is used for resolving
+                * xino lower bits overflow.
                 */
-               BUILD_BUG_ON(ilog2(OVL_MAX_STACK) > 31);
-               ofs->xino_mode = ilog2(ofs->numfs - 1) + 1;
+               BUILD_BUG_ON(ilog2(OVL_MAX_STACK) > 30);
+               ofs->xino_mode = ilog2(ofs->numfs - 1) + 2;
        }
 
        if (ofs->xino_mode > 0) {
@@ -1440,7 +1515,6 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb,
        char *lowertmp, *lower;
        struct path *stack = NULL;
        unsigned int stacklen, numlower = 0, i;
-       bool remote = false;
        struct ovl_entry *oe;
 
        err = -ENOMEM;
@@ -1472,7 +1546,7 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb,
        lower = lowertmp;
        for (numlower = 0; numlower < stacklen; numlower++) {
                err = ovl_lower_dir(lower, &stack[numlower], ofs,
-                                   &sb->s_stack_depth, &remote);
+                                   &sb->s_stack_depth);
                if (err)
                        goto out_err;
 
@@ -1500,11 +1574,6 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb,
                oe->lowerstack[i].layer = &ofs->layers[i+1];
        }
 
-       if (remote)
-               sb->s_d_op = &ovl_reval_dentry_operations;
-       else
-               sb->s_d_op = &ovl_dentry_operations;
-
 out:
        for (i = 0; i < numlower; i++)
                path_put(&stack[i]);
@@ -1589,6 +1658,44 @@ static int ovl_check_overlapping_layers(struct super_block *sb,
        return 0;
 }
 
+static struct dentry *ovl_get_root(struct super_block *sb,
+                                  struct dentry *upperdentry,
+                                  struct ovl_entry *oe)
+{
+       struct dentry *root;
+       struct ovl_path *lowerpath = &oe->lowerstack[0];
+       unsigned long ino = d_inode(lowerpath->dentry)->i_ino;
+       int fsid = lowerpath->layer->fsid;
+       struct ovl_inode_params oip = {
+               .upperdentry = upperdentry,
+               .lowerpath = lowerpath,
+       };
+
+       root = d_make_root(ovl_new_inode(sb, S_IFDIR, 0));
+       if (!root)
+               return NULL;
+
+       root->d_fsdata = oe;
+
+       if (upperdentry) {
+               /* Root inode uses upper st_ino/i_ino */
+               ino = d_inode(upperdentry)->i_ino;
+               fsid = 0;
+               ovl_dentry_set_upper_alias(root);
+               if (ovl_is_impuredir(upperdentry))
+                       ovl_set_flag(OVL_IMPURE, d_inode(root));
+       }
+
+       /* Root is always merge -> can have whiteouts */
+       ovl_set_flag(OVL_WHITEOUTS, d_inode(root));
+       ovl_dentry_set_flag(OVL_E_CONNECTED, root);
+       ovl_set_upperdata(d_inode(root));
+       ovl_inode_init(d_inode(root), &oip, ino, fsid);
+       ovl_dentry_update_reval(root, upperdentry, DCACHE_OP_WEAK_REVALIDATE);
+
+       return root;
+}
+
 static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct path upperpath = { };
@@ -1598,6 +1705,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        struct cred *cred;
        int err;
 
+       sb->s_d_op = &ovl_dentry_operations;
+
        err = -ENOMEM;
        ofs = kzalloc(sizeof(struct ovl_fs), GFP_KERNEL);
        if (!ofs)
@@ -1624,6 +1733,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
        sb->s_stack_depth = 0;
        sb->s_maxbytes = MAX_LFS_FILESIZE;
+       atomic_long_set(&ofs->last_ino, 1);
        /* Assume underlaying fs uses 32bit inodes unless proven otherwise */
        if (ofs->config.xino != OVL_XINO_OFF) {
                ofs->xino_mode = BITS_PER_LONG - 32;
@@ -1710,25 +1820,11 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_flags |= SB_POSIXACL;
 
        err = -ENOMEM;
-       root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, 0));
+       root_dentry = ovl_get_root(sb, upperpath.dentry, oe);
        if (!root_dentry)
                goto out_free_oe;
 
-       root_dentry->d_fsdata = oe;
-
        mntput(upperpath.mnt);
-       if (upperpath.dentry) {
-               ovl_dentry_set_upper_alias(root_dentry);
-               if (ovl_is_impuredir(upperpath.dentry))
-                       ovl_set_flag(OVL_IMPURE, d_inode(root_dentry));
-       }
-
-       /* Root is always merge -> can have whiteouts */
-       ovl_set_flag(OVL_WHITEOUTS, d_inode(root_dentry));
-       ovl_dentry_set_flag(OVL_E_CONNECTED, root_dentry);
-       ovl_set_upperdata(d_inode(root_dentry));
-       ovl_inode_init(d_inode(root_dentry), upperpath.dentry,
-                      ovl_dentry_lower(root_dentry), NULL);
 
        sb->s_root = root_dentry;
 
index 042f7eb..36b6078 100644 (file)
@@ -93,8 +93,24 @@ struct ovl_entry *ovl_alloc_entry(unsigned int numlower)
 bool ovl_dentry_remote(struct dentry *dentry)
 {
        return dentry->d_flags &
-               (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE |
-                DCACHE_OP_REAL);
+               (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE);
+}
+
+void ovl_dentry_update_reval(struct dentry *dentry, struct dentry *upperdentry,
+                            unsigned int mask)
+{
+       struct ovl_entry *oe = OVL_E(dentry);
+       unsigned int i, flags = 0;
+
+       if (upperdentry)
+               flags |= upperdentry->d_flags;
+       for (i = 0; i < oe->numlower; i++)
+               flags |= oe->lowerstack[i].dentry->d_flags;
+
+       spin_lock(&dentry->d_lock);
+       dentry->d_flags &= ~mask;
+       dentry->d_flags |= flags & mask;
+       spin_unlock(&dentry->d_lock);
 }
 
 bool ovl_dentry_weird(struct dentry *dentry)
@@ -386,24 +402,6 @@ void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect)
        oi->redirect = redirect;
 }
 
-void ovl_inode_init(struct inode *inode, struct dentry *upperdentry,
-                   struct dentry *lowerdentry, struct dentry *lowerdata)
-{
-       struct inode *realinode = d_inode(upperdentry ?: lowerdentry);
-
-       if (upperdentry)
-               OVL_I(inode)->__upperdentry = upperdentry;
-       if (lowerdentry)
-               OVL_I(inode)->lower = igrab(d_inode(lowerdentry));
-       if (lowerdata)
-               OVL_I(inode)->lowerdata = igrab(d_inode(lowerdata));
-
-       ovl_copyattr(realinode, inode);
-       ovl_copyflags(realinode, inode);
-       if (!inode->i_ino)
-               inode->i_ino = realinode->i_ino;
-}
-
 void ovl_inode_update(struct inode *inode, struct dentry *upperdentry)
 {
        struct inode *upperinode = d_inode(upperdentry);
@@ -416,8 +414,6 @@ void ovl_inode_update(struct inode *inode, struct dentry *upperdentry)
        smp_wmb();
        OVL_I(inode)->__upperdentry = upperdentry;
        if (inode_unhashed(inode)) {
-               if (!inode->i_ino)
-                       inode->i_ino = upperinode->i_ino;
                inode->i_private = upperinode;
                __insert_inode_hash(inode, (unsigned long) upperinode);
        }
index 74f948a..6042b64 100644 (file)
@@ -1839,9 +1839,9 @@ void proc_pid_evict_inode(struct proc_inode *ei)
        struct pid *pid = ei->pid;
 
        if (S_ISDIR(ei->vfs_inode.i_mode)) {
-               spin_lock(&pid->wait_pidfd.lock);
+               spin_lock(&pid->lock);
                hlist_del_init_rcu(&ei->sibling_inodes);
-               spin_unlock(&pid->wait_pidfd.lock);
+               spin_unlock(&pid->lock);
        }
 
        put_pid(pid);
@@ -1877,9 +1877,9 @@ struct inode *proc_pid_make_inode(struct super_block * sb,
        /* Let the pid remember us for quick removal */
        ei->pid = pid;
        if (S_ISDIR(mode)) {
-               spin_lock(&pid->wait_pidfd.lock);
+               spin_lock(&pid->lock);
                hlist_add_head_rcu(&ei->sibling_inodes, &pid->inodes);
-               spin_unlock(&pid->wait_pidfd.lock);
+               spin_unlock(&pid->lock);
        }
 
        task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid);
@@ -3273,7 +3273,7 @@ static const struct inode_operations proc_tgid_base_inode_operations = {
 
 void proc_flush_pid(struct pid *pid)
 {
-       proc_invalidate_siblings_dcache(&pid->inodes, &pid->wait_pidfd.lock);
+       proc_invalidate_siblings_dcache(&pid->inodes, &pid->lock);
        put_pid(pid);
 }
 
index 59d819c..bbfa9b1 100644 (file)
@@ -331,7 +331,8 @@ COMPAT_SYSCALL_DEFINE3(lseek, unsigned int, fd, compat_off_t, offset, unsigned i
 }
 #endif
 
-#if !defined(CONFIG_64BIT) || defined(CONFIG_COMPAT)
+#if !defined(CONFIG_64BIT) || defined(CONFIG_COMPAT) || \
+       defined(__ARCH_WANT_SYS_LLSEEK)
 SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
                unsigned long, offset_low, loff_t __user *, result,
                unsigned int, whence)
index 79781eb..70f5fdf 100644 (file)
@@ -232,9 +232,12 @@ Fill:
                loff_t pos = m->index;
 
                p = m->op->next(m, p, &m->index);
-               if (pos == m->index)
-                       /* Buggy ->next function */
+               if (pos == m->index) {
+                       pr_info_ratelimited("buggy seq_file .next function %ps "
+                               "did not updated position index\n",
+                               m->op->next);
                        m->index++;
+               }
                if (!p || IS_ERR(p)) {
                        err = PTR_ERR(p);
                        break;
index 3fd8546..736ebc5 100644 (file)
@@ -5,7 +5,7 @@
  * http://www.ecma.ch
  *
  * Copyright (c) 2001-2002  Ben Fennema
- * Copyright (c) 2017-2019  Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (c) 2017-2019  Pali Rohár <pali@kernel.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 35e61b2..d5fbfab 100644 (file)
@@ -5,7 +5,7 @@
  * http://www.osta.org
  *
  * Copyright (c) 2001-2004  Ben Fennema
- * Copyright (c) 2017-2019  Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (c) 2017-2019  Pali Rohár <pali@kernel.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 00266de..c526c5e 100644 (file)
@@ -328,6 +328,38 @@ xfs_validate_sb_common(
                return -EFSCORRUPTED;
        }
 
+       /* Validate the realtime geometry; stolen from xfs_repair */
+       if (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE ||
+           sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) {
+               xfs_notice(mp,
+                       "realtime extent sanity check failed");
+               return -EFSCORRUPTED;
+       }
+
+       if (sbp->sb_rblocks == 0) {
+               if (sbp->sb_rextents != 0 || sbp->sb_rbmblocks != 0 ||
+                   sbp->sb_rextslog != 0 || sbp->sb_frextents != 0) {
+                       xfs_notice(mp,
+                               "realtime zeroed geometry check failed");
+                       return -EFSCORRUPTED;
+               }
+       } else {
+               uint64_t        rexts;
+               uint64_t        rbmblocks;
+
+               rexts = div_u64(sbp->sb_rblocks, sbp->sb_rextsize);
+               rbmblocks = howmany_64(sbp->sb_rextents,
+                                      NBBY * sbp->sb_blocksize);
+
+               if (sbp->sb_rextents != rexts ||
+                   sbp->sb_rextslog != xfs_highbit32(sbp->sb_rextents) ||
+                   sbp->sb_rbmblocks != rbmblocks) {
+                       xfs_notice(mp,
+                               "realtime geometry sanity check failed");
+                       return -EFSCORRUPTED;
+               }
+       }
+
        if (sbp->sb_unit) {
                if (!xfs_sb_version_hasdalign(sbp) ||
                    sbp->sb_unit > sbp->sb_width ||
index f880141..9ec3eaf 100644 (file)
@@ -327,6 +327,9 @@ xfs_buf_free(
 
                        __free_page(page);
                }
+               if (current->reclaim_state)
+                       current->reclaim_state->reclaimed_slab +=
+                                                       bp->b_page_count;
        } else if (bp->b_flags & _XBF_KMEM)
                kmem_free(bp->b_addr);
        _xfs_buf_free_pages(bp);
@@ -2114,9 +2117,11 @@ xfs_buf_delwri_pushbuf(
 int __init
 xfs_buf_init(void)
 {
-       xfs_buf_zone = kmem_cache_create("xfs_buf",
-                                        sizeof(struct xfs_buf), 0,
-                                        SLAB_HWCACHE_ALIGN, NULL);
+       xfs_buf_zone = kmem_cache_create("xfs_buf", sizeof(struct xfs_buf), 0,
+                                        SLAB_HWCACHE_ALIGN |
+                                        SLAB_RECLAIM_ACCOUNT |
+                                        SLAB_MEM_SPREAD,
+                                        NULL);
        if (!xfs_buf_zone)
                goto out;
 
index 711376c..af2c8e5 100644 (file)
@@ -1105,8 +1105,8 @@ xfs_qm_dqflush(
         * Get the buffer containing the on-disk dquot
         */
        error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno,
-                                  mp->m_quotainfo->qi_dqchunklen, 0, &bp,
-                                  &xfs_dquot_buf_ops);
+                                  mp->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK,
+                                  &bp, &xfs_dquot_buf_ops);
        if (error)
                goto out_unlock;
 
@@ -1177,7 +1177,7 @@ xfs_qm_dqflush(
 
 out_unlock:
        xfs_dqfunlock(dqp);
-       return -EIO;
+       return error;
 }
 
 /*
index cf65e2e..baad174 100644 (file)
@@ -189,7 +189,8 @@ xfs_qm_dquot_logitem_push(
                if (!xfs_buf_delwri_queue(bp, buffer_list))
                        rval = XFS_ITEM_FLUSHING;
                xfs_buf_relse(bp);
-       }
+       } else if (error == -EAGAIN)
+               rval = XFS_ITEM_LOCKED;
 
        spin_lock(&lip->li_ailp->ail_lock);
 out_unlock:
index f1372f9..5a4b011 100644 (file)
@@ -15,7 +15,6 @@
 #include "xfs_trans.h"
 #include "xfs_inode_item.h"
 #include "xfs_icache.h"
-#include "xfs_log.h"
 #include "xfs_pnfs.h"
 
 /*
@@ -221,18 +220,7 @@ STATIC int
 xfs_fs_nfs_commit_metadata(
        struct inode            *inode)
 {
-       struct xfs_inode        *ip = XFS_I(inode);
-       struct xfs_mount        *mp = ip->i_mount;
-       xfs_lsn_t               lsn = 0;
-
-       xfs_ilock(ip, XFS_ILOCK_SHARED);
-       if (xfs_ipincount(ip))
-               lsn = ip->i_itemp->ili_last_lsn;
-       xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
-       if (!lsn)
-               return 0;
-       return xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, NULL);
+       return xfs_log_force_inode(XFS_I(inode));
 }
 
 const struct export_operations xfs_export_operations = {
index b8a4a3f..4b8bdec 100644 (file)
@@ -80,19 +80,9 @@ xfs_dir_fsync(
        int                     datasync)
 {
        struct xfs_inode        *ip = XFS_I(file->f_mapping->host);
-       struct xfs_mount        *mp = ip->i_mount;
-       xfs_lsn_t               lsn = 0;
 
        trace_xfs_dir_fsync(ip);
-
-       xfs_ilock(ip, XFS_ILOCK_SHARED);
-       if (xfs_ipincount(ip))
-               lsn = ip->i_itemp->ili_last_lsn;
-       xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
-       if (!lsn)
-               return 0;
-       return xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, NULL);
+       return xfs_log_force_inode(ip);
 }
 
 STATIC int
@@ -1069,7 +1059,11 @@ xfs_file_remap_range(
 
        ret = xfs_reflink_update_dest(dest, pos_out + len, cowextsize,
                        remap_flags);
+       if (ret)
+               goto out_unlock;
 
+       if (mp->m_flags & XFS_MOUNT_WSYNC)
+               xfs_log_force_inode(dest);
 out_unlock:
        xfs_reflink_remap_unlock(file_in, file_out);
        if (ret)
index 14b922f..d177278 100644 (file)
@@ -1200,8 +1200,7 @@ xfs_create(
        unlock_dp_on_error = false;
 
        error = xfs_dir_createname(tp, dp, name, ip->i_ino,
-                                  resblks ?
-                                       resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
+                                       resblks - XFS_IALLOC_SPACE_RES(mp));
        if (error) {
                ASSERT(error != -ENOSPC);
                goto out_trans_cancel;
@@ -2504,6 +2503,88 @@ out:
 }
 
 /*
+ * Look up the inode number specified and mark it stale if it is found. If it is
+ * dirty, return the inode so it can be attached to the cluster buffer so it can
+ * be processed appropriately when the cluster free transaction completes.
+ */
+static struct xfs_inode *
+xfs_ifree_get_one_inode(
+       struct xfs_perag        *pag,
+       struct xfs_inode        *free_ip,
+       xfs_ino_t               inum)
+{
+       struct xfs_mount        *mp = pag->pag_mount;
+       struct xfs_inode        *ip;
+
+retry:
+       rcu_read_lock();
+       ip = radix_tree_lookup(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, inum));
+
+       /* Inode not in memory, nothing to do */
+       if (!ip)
+               goto out_rcu_unlock;
+
+       /*
+        * because this is an RCU protected lookup, we could find a recently
+        * freed or even reallocated inode during the lookup. We need to check
+        * under the i_flags_lock for a valid inode here. Skip it if it is not
+        * valid, the wrong inode or stale.
+        */
+       spin_lock(&ip->i_flags_lock);
+       if (ip->i_ino != inum || __xfs_iflags_test(ip, XFS_ISTALE)) {
+               spin_unlock(&ip->i_flags_lock);
+               goto out_rcu_unlock;
+       }
+       spin_unlock(&ip->i_flags_lock);
+
+       /*
+        * Don't try to lock/unlock the current inode, but we _cannot_ skip the
+        * other inodes that we did not find in the list attached to the buffer
+        * and are not already marked stale. If we can't lock it, back off and
+        * retry.
+        */
+       if (ip != free_ip) {
+               if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
+                       rcu_read_unlock();
+                       delay(1);
+                       goto retry;
+               }
+
+               /*
+                * Check the inode number again in case we're racing with
+                * freeing in xfs_reclaim_inode().  See the comments in that
+                * function for more information as to why the initial check is
+                * not sufficient.
+                */
+               if (ip->i_ino != inum) {
+                       xfs_iunlock(ip, XFS_ILOCK_EXCL);
+                       goto out_rcu_unlock;
+               }
+       }
+       rcu_read_unlock();
+
+       xfs_iflock(ip);
+       xfs_iflags_set(ip, XFS_ISTALE);
+
+       /*
+        * We don't need to attach clean inodes or those only with unlogged
+        * changes (which we throw away, anyway).
+        */
+       if (!ip->i_itemp || xfs_inode_clean(ip)) {
+               ASSERT(ip != free_ip);
+               xfs_ifunlock(ip);
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+               goto out_no_inode;
+       }
+       return ip;
+
+out_rcu_unlock:
+       rcu_read_unlock();
+out_no_inode:
+       return NULL;
+}
+
+/*
  * A big issue when freeing the inode cluster is that we _cannot_ skip any
  * inodes that are in memory - they all must be marked stale and attached to
  * the cluster buffer.
@@ -2603,77 +2684,11 @@ xfs_ifree_cluster(
                 * even trying to lock them.
                 */
                for (i = 0; i < igeo->inodes_per_cluster; i++) {
-retry:
-                       rcu_read_lock();
-                       ip = radix_tree_lookup(&pag->pag_ici_root,
-                                       XFS_INO_TO_AGINO(mp, (inum + i)));
-
-                       /* Inode not in memory, nothing to do */
-                       if (!ip) {
-                               rcu_read_unlock();
+                       ip = xfs_ifree_get_one_inode(pag, free_ip, inum + i);
+                       if (!ip)
                                continue;
-                       }
-
-                       /*
-                        * because this is an RCU protected lookup, we could
-                        * find a recently freed or even reallocated inode
-                        * during the lookup. We need to check under the
-                        * i_flags_lock for a valid inode here. Skip it if it
-                        * is not valid, the wrong inode or stale.
-                        */
-                       spin_lock(&ip->i_flags_lock);
-                       if (ip->i_ino != inum + i ||
-                           __xfs_iflags_test(ip, XFS_ISTALE)) {
-                               spin_unlock(&ip->i_flags_lock);
-                               rcu_read_unlock();
-                               continue;
-                       }
-                       spin_unlock(&ip->i_flags_lock);
-
-                       /*
-                        * Don't try to lock/unlock the current inode, but we
-                        * _cannot_ skip the other inodes that we did not find
-                        * in the list attached to the buffer and are not
-                        * already marked stale. If we can't lock it, back off
-                        * and retry.
-                        */
-                       if (ip != free_ip) {
-                               if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
-                                       rcu_read_unlock();
-                                       delay(1);
-                                       goto retry;
-                               }
-
-                               /*
-                                * Check the inode number again in case we're
-                                * racing with freeing in xfs_reclaim_inode().
-                                * See the comments in that function for more
-                                * information as to why the initial check is
-                                * not sufficient.
-                                */
-                               if (ip->i_ino != inum + i) {
-                                       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-                                       rcu_read_unlock();
-                                       continue;
-                               }
-                       }
-                       rcu_read_unlock();
-
-                       xfs_iflock(ip);
-                       xfs_iflags_set(ip, XFS_ISTALE);
 
-                       /*
-                        * we don't need to attach clean inodes or those only
-                        * with unlogged changes (which we throw away, anyway).
-                        */
                        iip = ip->i_itemp;
-                       if (!iip || xfs_inode_clean(ip)) {
-                               ASSERT(ip != free_ip);
-                               xfs_ifunlock(ip);
-                               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-                               continue;
-                       }
-
                        iip->ili_last_fields = iip->ili_fields;
                        iip->ili_fields = 0;
                        iip->ili_fsync_fields = 0;
@@ -3930,3 +3945,22 @@ xfs_irele(
        trace_xfs_irele(ip, _RET_IP_);
        iput(VFS_I(ip));
 }
+
+/*
+ * Ensure all commited transactions touching the inode are written to the log.
+ */
+int
+xfs_log_force_inode(
+       struct xfs_inode        *ip)
+{
+       xfs_lsn_t               lsn = 0;
+
+       xfs_ilock(ip, XFS_ILOCK_SHARED);
+       if (xfs_ipincount(ip))
+               lsn = ip->i_itemp->ili_last_lsn;
+       xfs_iunlock(ip, XFS_ILOCK_SHARED);
+
+       if (!lsn)
+               return 0;
+       return xfs_log_force_lsn(ip->i_mount, lsn, XFS_LOG_SYNC, NULL);
+}
index 492e539..c6a63f6 100644 (file)
@@ -426,6 +426,7 @@ int         xfs_itruncate_extents_flags(struct xfs_trans **,
                                struct xfs_inode *, int, xfs_fsize_t, int);
 void           xfs_iext_realloc(xfs_inode_t *, int, int);
 
+int            xfs_log_force_inode(struct xfs_inode *ip);
 void           xfs_iunpin_wait(xfs_inode_t *);
 #define xfs_ipincount(ip)      ((unsigned int) atomic_read(&ip->i_pincount))
 
index 4a3d13d..f779cca 100644 (file)
@@ -552,7 +552,8 @@ xfs_inode_item_push(
                if (!xfs_buf_delwri_queue(bp, buffer_list))
                        rval = XFS_ITEM_FLUSHING;
                xfs_buf_relse(bp);
-       }
+       } else if (error == -EAGAIN)
+               rval = XFS_ITEM_LOCKED;
 
        spin_lock(&lip->li_ailp->ail_lock);
 out_unlock:
@@ -730,29 +731,27 @@ xfs_iflush_done(
         * holding the lock before removing the inode from the AIL.
         */
        if (need_ail) {
-               bool                    mlip_changed = false;
+               xfs_lsn_t       tail_lsn = 0;
 
                /* this is an opencoded batch version of xfs_trans_ail_delete */
                spin_lock(&ailp->ail_lock);
                list_for_each_entry(blip, &tmp, li_bio_list) {
                        if (INODE_ITEM(blip)->ili_logged &&
-                           blip->li_lsn == INODE_ITEM(blip)->ili_flush_lsn)
-                               mlip_changed |= xfs_ail_delete_one(ailp, blip);
-                       else {
+                           blip->li_lsn == INODE_ITEM(blip)->ili_flush_lsn) {
+                               /*
+                                * xfs_ail_update_finish() only cares about the
+                                * lsn of the first tail item removed, any
+                                * others will be at the same or higher lsn so
+                                * we just ignore them.
+                                */
+                               xfs_lsn_t lsn = xfs_ail_delete_one(ailp, blip);
+                               if (!tail_lsn && lsn)
+                                       tail_lsn = lsn;
+                       } else {
                                xfs_clear_li_failed(blip);
                        }
                }
-
-               if (mlip_changed) {
-                       if (!XFS_FORCED_SHUTDOWN(ailp->ail_mount))
-                               xlog_assign_tail_lsn_locked(ailp->ail_mount);
-                       if (list_empty(&ailp->ail_head))
-                               wake_up_all(&ailp->ail_empty);
-               }
-               spin_unlock(&ailp->ail_lock);
-
-               if (mlip_changed)
-                       xfs_log_space_wake(ailp->ail_mount);
+               xfs_ail_update_finish(ailp, tail_lsn);
        }
 
        /*
index 4a53768..00fda2e 100644 (file)
 kmem_zone_t    *xfs_log_ticket_zone;
 
 /* Local miscellaneous function prototypes */
-STATIC int
-xlog_commit_record(
-       struct xlog             *log,
-       struct xlog_ticket      *ticket,
-       struct xlog_in_core     **iclog,
-       xfs_lsn_t               *commitlsnp);
-
 STATIC struct xlog *
 xlog_alloc_log(
        struct xfs_mount        *mp,
@@ -66,14 +59,6 @@ xlog_grant_push_ail(
        struct xlog             *log,
        int                     need_bytes);
 STATIC void
-xlog_regrant_reserve_log_space(
-       struct xlog             *log,
-       struct xlog_ticket      *ticket);
-STATIC void
-xlog_ungrant_log_space(
-       struct xlog             *log,
-       struct xlog_ticket      *ticket);
-STATIC void
 xlog_sync(
        struct xlog             *log,
        struct xlog_in_core     *iclog);
@@ -478,73 +463,6 @@ out_error:
        return error;
 }
 
-
-/*
- * NOTES:
- *
- *     1. currblock field gets updated at startup and after in-core logs
- *             marked as with WANT_SYNC.
- */
-
-/*
- * This routine is called when a user of a log manager ticket is done with
- * the reservation.  If the ticket was ever used, then a commit record for
- * the associated transaction is written out as a log operation header with
- * no data.  The flag XLOG_TIC_INITED is set when the first write occurs with
- * a given ticket.  If the ticket was one with a permanent reservation, then
- * a few operations are done differently.  Permanent reservation tickets by
- * default don't release the reservation.  They just commit the current
- * transaction with the belief that the reservation is still needed.  A flag
- * must be passed in before permanent reservations are actually released.
- * When these type of tickets are not released, they need to be set into
- * the inited state again.  By doing this, a start record will be written
- * out when the next write occurs.
- */
-xfs_lsn_t
-xfs_log_done(
-       struct xfs_mount        *mp,
-       struct xlog_ticket      *ticket,
-       struct xlog_in_core     **iclog,
-       bool                    regrant)
-{
-       struct xlog             *log = mp->m_log;
-       xfs_lsn_t               lsn = 0;
-
-       if (XLOG_FORCED_SHUTDOWN(log) ||
-           /*
-            * If nothing was ever written, don't write out commit record.
-            * If we get an error, just continue and give back the log ticket.
-            */
-           (((ticket->t_flags & XLOG_TIC_INITED) == 0) &&
-            (xlog_commit_record(log, ticket, iclog, &lsn)))) {
-               lsn = (xfs_lsn_t) -1;
-               regrant = false;
-       }
-
-
-       if (!regrant) {
-               trace_xfs_log_done_nonperm(log, ticket);
-
-               /*
-                * Release ticket if not permanent reservation or a specific
-                * request has been made to release a permanent reservation.
-                */
-               xlog_ungrant_log_space(log, ticket);
-       } else {
-               trace_xfs_log_done_perm(log, ticket);
-
-               xlog_regrant_reserve_log_space(log, ticket);
-               /* If this ticket was a permanent reservation and we aren't
-                * trying to release it, reset the inited flags; so next time
-                * we write, a start record will be written out.
-                */
-               ticket->t_flags |= XLOG_TIC_INITED;
-       }
-
-       xfs_log_ticket_put(ticket);
-       return lsn;
-}
-
 static bool
 __xlog_state_release_iclog(
        struct xlog             *log,
@@ -869,32 +787,44 @@ xlog_wait_on_iclog(
 }
 
 /*
- * Final log writes as part of unmount.
- *
- * Mark the filesystem clean as unmount happens.  Note that during relocation
- * this routine needs to be executed as part of source-bag while the
- * deallocation must not be done until source-end.
+ * Write out an unmount record using the ticket provided. We have to account for
+ * the data space used in the unmount ticket as this write is not done from a
+ * transaction context that has already done the accounting for us.
  */
-
-/* Actually write the unmount record to disk. */
-static void
-xfs_log_write_unmount_record(
-       struct xfs_mount        *mp)
+static int
+xlog_write_unmount_record(
+       struct xlog             *log,
+       struct xlog_ticket      *ticket,
+       xfs_lsn_t               *lsn,
+       uint                    flags)
 {
-       /* the data section must be 32 bit size aligned */
-       struct xfs_unmount_log_format magic = {
+       struct xfs_unmount_log_format ulf = {
                .magic = XLOG_UNMOUNT_TYPE,
        };
        struct xfs_log_iovec reg = {
-               .i_addr = &magic,
-               .i_len = sizeof(magic),
+               .i_addr = &ulf,
+               .i_len = sizeof(ulf),
                .i_type = XLOG_REG_TYPE_UNMOUNT,
        };
        struct xfs_log_vec vec = {
                .lv_niovecs = 1,
                .lv_iovecp = &reg,
        };
-       struct xlog             *log = mp->m_log;
+
+       /* account for space used by record data */
+       ticket->t_curr_res -= sizeof(ulf);
+       return xlog_write(log, &vec, ticket, lsn, NULL, flags, false);
+}
+
+/*
+ * Mark the filesystem clean by writing an unmount record to the head of the
+ * log.
+ */
+static void
+xlog_unmount_write(
+       struct xlog             *log)
+{
+       struct xfs_mount        *mp = log->l_mp;
        struct xlog_in_core     *iclog;
        struct xlog_ticket      *tic = NULL;
        xfs_lsn_t               lsn;
@@ -905,23 +835,7 @@ xfs_log_write_unmount_record(
        if (error)
                goto out_err;
 
-       /*
-        * If we think the summary counters are bad, clear the unmount header
-        * flag in the unmount record so that the summary counters will be
-        * recalculated during log recovery at next mount.  Refer to
-        * xlog_check_unmount_rec for more details.
-        */
-       if (XFS_TEST_ERROR(xfs_fs_has_sickness(mp, XFS_SICK_FS_COUNTERS), mp,
-                       XFS_ERRTAG_FORCE_SUMMARY_RECALC)) {
-               xfs_alert(mp, "%s: will fix summary counters at next mount",
-                               __func__);
-               flags &= ~XLOG_UNMOUNT_TRANS;
-       }
-
-       /* remove inited flag, and account for space used */
-       tic->t_flags = 0;
-       tic->t_curr_res -= sizeof(magic);
-       error = xlog_write(log, &vec, tic, &lsn, NULL, flags);
+       error = xlog_write_unmount_record(log, tic, &lsn, flags);
        /*
         * At this point, we're umounting anyway, so there's no point in
         * transitioning log state to IOERROR. Just continue...
@@ -943,8 +857,7 @@ out_err:
 
        if (tic) {
                trace_xfs_log_umount_write(log, tic);
-               xlog_ungrant_log_space(log, tic);
-               xfs_log_ticket_put(tic);
+               xfs_log_ticket_ungrant(log, tic);
        }
 }
 
@@ -987,8 +900,22 @@ xfs_log_unmount_write(
 
        if (XLOG_FORCED_SHUTDOWN(log))
                return;
+
+       /*
+        * If we think the summary counters are bad, avoid writing the unmount
+        * record to force log recovery at next mount, after which the summary
+        * counters will be recalculated.  Refer to xlog_check_unmount_rec for
+        * more details.
+        */
+       if (XFS_TEST_ERROR(xfs_fs_has_sickness(mp, XFS_SICK_FS_COUNTERS), mp,
+                       XFS_ERRTAG_FORCE_SUMMARY_RECALC)) {
+               xfs_alert(mp, "%s: will fix summary counters at next mount",
+                               __func__);
+               return;
+       }
+
        xfs_log_unmount_verify_iclog(log);
-       xfs_log_write_unmount_record(mp);
+       xlog_unmount_write(log);
 }
 
 /*
@@ -1515,20 +1442,17 @@ out:
        return ERR_PTR(error);
 }      /* xlog_alloc_log */
 
-
 /*
  * Write out the commit record of a transaction associated with the given
- * ticket Return the lsn of the commit record.
+ * ticket to close off a running log write. Return the lsn of the commit record.
  */
-STATIC int
+int
 xlog_commit_record(
        struct xlog             *log,
        struct xlog_ticket      *ticket,
        struct xlog_in_core     **iclog,
-       xfs_lsn_t               *commitlsnp)
+       xfs_lsn_t               *lsn)
 {
-       struct xfs_mount *mp = log->l_mp;
-       int     error;
        struct xfs_log_iovec reg = {
                .i_addr = NULL,
                .i_len = 0,
@@ -1538,12 +1462,15 @@ xlog_commit_record(
                .lv_niovecs = 1,
                .lv_iovecp = &reg,
        };
+       int     error;
+
+       if (XLOG_FORCED_SHUTDOWN(log))
+               return -EIO;
 
-       ASSERT_ALWAYS(iclog);
-       error = xlog_write(log, &vec, ticket, commitlsnp, iclog,
-                                       XLOG_COMMIT_TRANS);
+       error = xlog_write(log, &vec, ticket, lsn, iclog, XLOG_COMMIT_TRANS,
+                          false);
        if (error)
-               xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
+               xfs_force_shutdown(log->l_mp, SHUTDOWN_LOG_IO_ERROR);
        return error;
 }
 
@@ -1761,7 +1688,15 @@ xlog_write_iclog(
        iclog->ic_bio.bi_iter.bi_sector = log->l_logBBstart + bno;
        iclog->ic_bio.bi_end_io = xlog_bio_end_io;
        iclog->ic_bio.bi_private = iclog;
-       iclog->ic_bio.bi_opf = REQ_OP_WRITE | REQ_META | REQ_SYNC | REQ_FUA;
+
+       /*
+        * We use REQ_SYNC | REQ_IDLE here to tell the block layer the are more
+        * IOs coming immediately after this one. This prevents the block layer
+        * writeback throttle from throttling log writes behind background
+        * metadata writeback and causing priority inversions.
+        */
+       iclog->ic_bio.bi_opf = REQ_OP_WRITE | REQ_META | REQ_SYNC |
+                               REQ_IDLE | REQ_FUA;
        if (need_flush)
                iclog->ic_bio.bi_opf |= REQ_PREFLUSH;
 
@@ -1981,7 +1916,7 @@ xlog_dealloc_log(
        log->l_mp->m_log = NULL;
        destroy_workqueue(log->l_ioend_workqueue);
        kmem_free(log);
-}      /* xlog_dealloc_log */
+}
 
 /*
  * Update counters atomically now that memcpy is done.
@@ -2118,23 +2053,21 @@ xlog_print_trans(
 }
 
 /*
- * Calculate the potential space needed by the log vector.  Each region gets
- * its own xlog_op_header_t and may need to be double word aligned.
+ * Calculate the potential space needed by the log vector.  We may need a start
+ * record, and each region gets its own struct xlog_op_header and may need to be
+ * double word aligned.
  */
 static int
 xlog_write_calc_vec_length(
        struct xlog_ticket      *ticket,
-       struct xfs_log_vec      *log_vector)
+       struct xfs_log_vec      *log_vector,
+       bool                    need_start_rec)
 {
        struct xfs_log_vec      *lv;
-       int                     headers = 0;
+       int                     headers = need_start_rec ? 1 : 0;
        int                     len = 0;
        int                     i;
 
-       /* acct for start rec of xact */
-       if (ticket->t_flags & XLOG_TIC_INITED)
-               headers++;
-
        for (lv = log_vector; lv; lv = lv->lv_next) {
                /* we don't write ordered log vectors */
                if (lv->lv_buf_len == XFS_LOG_VEC_ORDERED)
@@ -2156,27 +2089,16 @@ xlog_write_calc_vec_length(
        return len;
 }
 
-/*
- * If first write for transaction, insert start record  We can't be trying to
- * commit if we are inited.  We can't have any "partial_copy" if we are inited.
- */
-static int
+static void
 xlog_write_start_rec(
        struct xlog_op_header   *ophdr,
        struct xlog_ticket      *ticket)
 {
-       if (!(ticket->t_flags & XLOG_TIC_INITED))
-               return 0;
-
        ophdr->oh_tid   = cpu_to_be32(ticket->t_tid);
        ophdr->oh_clientid = ticket->t_clientid;
        ophdr->oh_len = 0;
        ophdr->oh_flags = XLOG_START_TRANS;
        ophdr->oh_res2 = 0;
-
-       ticket->t_flags &= ~XLOG_TIC_INITED;
-
-       return sizeof(struct xlog_op_header);
 }
 
 static xlog_op_header_t *
@@ -2365,13 +2287,14 @@ xlog_write(
        struct xlog_ticket      *ticket,
        xfs_lsn_t               *start_lsn,
        struct xlog_in_core     **commit_iclog,
-       uint                    flags)
+       uint                    flags,
+       bool                    need_start_rec)
 {
        struct xlog_in_core     *iclog = NULL;
-       struct xfs_log_iovec    *vecp;
-       struct xfs_log_vec      *lv;
+       struct xfs_log_vec      *lv = log_vector;
+       struct xfs_log_iovec    *vecp = lv->lv_iovecp;
+       int                     index = 0;
        int                     len;
-       int                     index;
        int                     partial_copy = 0;
        int                     partial_copy_len = 0;
        int                     contwr = 0;
@@ -2379,25 +2302,13 @@ xlog_write(
        int                     data_cnt = 0;
        int                     error = 0;
 
-       *start_lsn = 0;
-
-       len = xlog_write_calc_vec_length(ticket, log_vector);
-
        /*
-        * Region headers and bytes are already accounted for.
-        * We only need to take into account start records and
-        * split regions in this function.
+        * If this is a commit or unmount transaction, we don't need a start
+        * record to be written.  We do, however, have to account for the
+        * commit or unmount header that gets written. Hence we always have
+        * to account for an extra xlog_op_header here.
         */
-       if (ticket->t_flags & XLOG_TIC_INITED)
-               ticket->t_curr_res -= sizeof(xlog_op_header_t);
-
-       /*
-        * Commit record headers need to be accounted for. These
-        * come in as separate writes so are easy to detect.
-        */
-       if (flags & (XLOG_COMMIT_TRANS | XLOG_UNMOUNT_TRANS))
-               ticket->t_curr_res -= sizeof(xlog_op_header_t);
-
+       ticket->t_curr_res -= sizeof(struct xlog_op_header);
        if (ticket->t_curr_res < 0) {
                xfs_alert_tag(log->l_mp, XFS_PTAG_LOGRES,
                     "ctx ticket reservation ran out. Need to up reservation");
@@ -2405,9 +2316,8 @@ xlog_write(
                xfs_force_shutdown(log->l_mp, SHUTDOWN_LOG_IO_ERROR);
        }
 
-       index = 0;
-       lv = log_vector;
-       vecp = lv->lv_iovecp;
+       len = xlog_write_calc_vec_length(ticket, log_vector, need_start_rec);
+       *start_lsn = 0;
        while (lv && (!lv->lv_niovecs || index < lv->lv_niovecs)) {
                void            *ptr;
                int             log_offset;
@@ -2431,7 +2341,6 @@ xlog_write(
                while (lv && (!lv->lv_niovecs || index < lv->lv_niovecs)) {
                        struct xfs_log_iovec    *reg;
                        struct xlog_op_header   *ophdr;
-                       int                     start_rec_copy;
                        int                     copy_len;
                        int                     copy_off;
                        bool                    ordered = false;
@@ -2447,11 +2356,15 @@ xlog_write(
                        ASSERT(reg->i_len % sizeof(int32_t) == 0);
                        ASSERT((unsigned long)ptr % sizeof(int32_t) == 0);
 
-                       start_rec_copy = xlog_write_start_rec(ptr, ticket);
-                       if (start_rec_copy) {
-                               record_cnt++;
+                       /*
+                        * Before we start formatting log vectors, we need to
+                        * write a start record. Only do this for the first
+                        * iclog we write to.
+                        */
+                       if (need_start_rec) {
+                               xlog_write_start_rec(ptr, ticket);
                                xlog_write_adv_cnt(&ptr, &len, &log_offset,
-                                                  start_rec_copy);
+                                               sizeof(struct xlog_op_header));
                        }
 
                        ophdr = xlog_write_setup_ophdr(log, ptr, ticket, flags);
@@ -2483,8 +2396,13 @@ xlog_write(
                                xlog_write_adv_cnt(&ptr, &len, &log_offset,
                                                   copy_len);
                        }
-                       copy_len += start_rec_copy + sizeof(xlog_op_header_t);
+                       copy_len += sizeof(struct xlog_op_header);
                        record_cnt++;
+                       if (need_start_rec) {
+                               copy_len += sizeof(struct xlog_op_header);
+                               record_cnt++;
+                               need_start_rec = false;
+                       }
                        data_cnt += contwr ? copy_len : 0;
 
                        error = xlog_write_copy_finish(log, iclog, flags,
@@ -2541,14 +2459,6 @@ next_lv:
        return error;
 }
 
-
-/*****************************************************************************
- *
- *             State Machine functions
- *
- *****************************************************************************
- */
-
 static void
 xlog_state_activate_iclog(
        struct xlog_in_core     *iclog,
@@ -2909,7 +2819,7 @@ xlog_state_done_syncing(
         */
        wake_up_all(&iclog->ic_write_wait);
        spin_unlock(&log->l_icloglock);
-       xlog_state_do_callback(log);    /* also cleans log */
+       xlog_state_do_callback(log);
 }
 
 /*
@@ -3029,21 +2939,21 @@ restart:
 
        *logoffsetp = log_offset;
        return 0;
-}      /* xlog_state_get_iclog_space */
-
-/* The first cnt-1 times through here we don't need to
- * move the grant write head because the permanent
- * reservation has reserved cnt times the unit amount.
- * Release part of current permanent unit reservation and
- * reset current reservation to be one units worth.  Also
- * move grant reservation head forward.
+}
+
+/*
+ * The first cnt-1 times a ticket goes through here we don't need to move the
+ * grant write head because the permanent reservation has reserved cnt times the
+ * unit amount.  Release part of current permanent unit reservation and reset
+ * current reservation to be one units worth.  Also move grant reservation head
+ * forward.
  */
-STATIC void
-xlog_regrant_reserve_log_space(
+void
+xfs_log_ticket_regrant(
        struct xlog             *log,
        struct xlog_ticket      *ticket)
 {
-       trace_xfs_log_regrant_reserve_enter(log, ticket);
+       trace_xfs_log_ticket_regrant(log, ticket);
 
        if (ticket->t_cnt > 0)
                ticket->t_cnt--;
@@ -3055,21 +2965,20 @@ xlog_regrant_reserve_log_space(
        ticket->t_curr_res = ticket->t_unit_res;
        xlog_tic_reset_res(ticket);
 
-       trace_xfs_log_regrant_reserve_sub(log, ticket);
+       trace_xfs_log_ticket_regrant_sub(log, ticket);
 
        /* just return if we still have some of the pre-reserved space */
-       if (ticket->t_cnt > 0)
-               return;
+       if (!ticket->t_cnt) {
+               xlog_grant_add_space(log, &log->l_reserve_head.grant,
+                                    ticket->t_unit_res);
+               trace_xfs_log_ticket_regrant_exit(log, ticket);
 
-       xlog_grant_add_space(log, &log->l_reserve_head.grant,
-                                       ticket->t_unit_res);
-
-       trace_xfs_log_regrant_reserve_exit(log, ticket);
-
-       ticket->t_curr_res = ticket->t_unit_res;
-       xlog_tic_reset_res(ticket);
-}      /* xlog_regrant_reserve_log_space */
+               ticket->t_curr_res = ticket->t_unit_res;
+               xlog_tic_reset_res(ticket);
+       }
 
+       xfs_log_ticket_put(ticket);
+}
 
 /*
  * Give back the space left from a reservation.
@@ -3085,18 +2994,19 @@ xlog_regrant_reserve_log_space(
  * space, the count will stay at zero and the only space remaining will be
  * in the current reservation field.
  */
-STATIC void
-xlog_ungrant_log_space(
+void
+xfs_log_ticket_ungrant(
        struct xlog             *log,
        struct xlog_ticket      *ticket)
 {
-       int     bytes;
+       int                     bytes;
+
+       trace_xfs_log_ticket_ungrant(log, ticket);
 
        if (ticket->t_cnt > 0)
                ticket->t_cnt--;
 
-       trace_xfs_log_ungrant_enter(log, ticket);
-       trace_xfs_log_ungrant_sub(log, ticket);
+       trace_xfs_log_ticket_ungrant_sub(log, ticket);
 
        /*
         * If this is a permanent reservation ticket, we may be able to free
@@ -3111,18 +3021,15 @@ xlog_ungrant_log_space(
        xlog_grant_sub_space(log, &log->l_reserve_head.grant, bytes);
        xlog_grant_sub_space(log, &log->l_write_head.grant, bytes);
 
-       trace_xfs_log_ungrant_exit(log, ticket);
+       trace_xfs_log_ticket_ungrant_exit(log, ticket);
 
        xfs_log_space_wake(log->l_mp);
+       xfs_log_ticket_put(ticket);
 }
 
 /*
- * Mark the current iclog in the ring as WANT_SYNC and move the current iclog
- * pointer to the next iclog in the ring.
- *
- * When called from xlog_state_get_iclog_space(), the exact size of the iclog
- * has not yet been determined, all we know is that we have run out of space in
- * the current iclog.
+ * This routine will mark the current iclog in the ring as WANT_SYNC and move
+ * the current iclog pointer to the next iclog in the ring.
  */
 STATIC void
 xlog_state_switch_iclogs(
@@ -3167,7 +3074,7 @@ xlog_state_switch_iclogs(
        }
        ASSERT(iclog == log->l_iclog);
        log->l_iclog = iclog->ic_next;
-}      /* xlog_state_switch_iclogs */
+}
 
 /*
  * Write out all data in the in-core log as of this exact moment in time.
@@ -3374,13 +3281,6 @@ xfs_log_force_lsn(
        return ret;
 }
 
-/*****************************************************************************
- *
- *             TICKET functions
- *
- *****************************************************************************
- */
-
 /*
  * Free a used ticket when its refcount falls to zero.
  */
@@ -3529,7 +3429,6 @@ xlog_ticket_alloc(
        tic->t_ocnt             = cnt;
        tic->t_tid              = prandom_u32();
        tic->t_clientid         = client;
-       tic->t_flags            = XLOG_TIC_INITED;
        if (permanent)
                tic->t_flags |= XLOG_TIC_PERM_RESERV;
 
@@ -3538,13 +3437,6 @@ xlog_ticket_alloc(
        return tic;
 }
 
-
-/******************************************************************************
- *
- *             Log debug routines
- *
- ******************************************************************************
- */
 #if defined(DEBUG)
 /*
  * Make sure that the destination ptr is within the valid data region of
@@ -3630,7 +3522,7 @@ xlog_verify_tail_lsn(
        if (blocks < BTOBB(iclog->ic_offset) + 1)
                xfs_emerg(log->l_mp, "%s: ran out of log space", __func__);
     }
-}      /* xlog_verify_tail_lsn */
+}
 
 /*
  * Perform a number of checks on the iclog before writing to disk.
@@ -3733,7 +3625,7 @@ xlog_verify_iclog(
                }
                ptr += sizeof(xlog_op_header_t) + op_len;
        }
-}      /* xlog_verify_iclog */
+}
 #endif
 
 /*
index cc77cc3..1412d69 100644 (file)
@@ -105,10 +105,6 @@ struct xfs_log_item;
 struct xfs_item_ops;
 struct xfs_trans;
 
-xfs_lsn_t xfs_log_done(struct xfs_mount *mp,
-                      struct xlog_ticket *ticket,
-                      struct xlog_in_core **iclog,
-                      bool regrant);
 int      xfs_log_force(struct xfs_mount *mp, uint flags);
 int      xfs_log_force_lsn(struct xfs_mount *mp, xfs_lsn_t lsn, uint flags,
                int *log_forced);
index 64cc0bf..b43f0e8 100644 (file)
@@ -669,6 +669,11 @@ xlog_cil_push_work(
        ASSERT(push_seq <= ctx->sequence);
 
        /*
+        * Wake up any background push waiters now this context is being pushed.
+        */
+       wake_up_all(&ctx->push_wait);
+
+       /*
         * Check if we've anything to push. If there is nothing, then we don't
         * move on to a new sequence number and so we have to be able to push
         * this sequence again later.
@@ -744,6 +749,7 @@ xlog_cil_push_work(
         */
        INIT_LIST_HEAD(&new_ctx->committing);
        INIT_LIST_HEAD(&new_ctx->busy_extents);
+       init_waitqueue_head(&new_ctx->push_wait);
        new_ctx->sequence = ctx->sequence + 1;
        new_ctx->cil = cil;
        cil->xc_ctx = new_ctx;
@@ -801,7 +807,7 @@ xlog_cil_push_work(
        lvhdr.lv_iovecp = &lhdr;
        lvhdr.lv_next = ctx->lv_chain;
 
-       error = xlog_write(log, &lvhdr, tic, &ctx->start_lsn, NULL, 0);
+       error = xlog_write(log, &lvhdr, tic, &ctx->start_lsn, NULL, 0, true);
        if (error)
                goto out_abort_free_ticket;
 
@@ -839,10 +845,11 @@ restart:
        }
        spin_unlock(&cil->xc_push_lock);
 
-       /* xfs_log_done always frees the ticket on error. */
-       commit_lsn = xfs_log_done(log->l_mp, tic, &commit_iclog, false);
-       if (commit_lsn == -1)
-               goto out_abort;
+       error = xlog_commit_record(log, tic, &commit_iclog, &commit_lsn);
+       if (error)
+               goto out_abort_free_ticket;
+
+       xfs_log_ticket_ungrant(log, tic);
 
        spin_lock(&commit_iclog->ic_callback_lock);
        if (commit_iclog->ic_state == XLOG_STATE_IOERROR) {
@@ -875,7 +882,7 @@ out_skip:
        return;
 
 out_abort_free_ticket:
-       xfs_log_ticket_put(tic);
+       xfs_log_ticket_ungrant(log, tic);
 out_abort:
        ASSERT(XLOG_FORCED_SHUTDOWN(log));
        xlog_cil_committed(ctx);
@@ -890,7 +897,7 @@ out_abort:
  */
 static void
 xlog_cil_push_background(
-       struct xlog     *log)
+       struct xlog     *log) __releases(cil->xc_ctx_lock)
 {
        struct xfs_cil  *cil = log->l_cilp;
 
@@ -904,14 +911,36 @@ xlog_cil_push_background(
         * don't do a background push if we haven't used up all the
         * space available yet.
         */
-       if (cil->xc_ctx->space_used < XLOG_CIL_SPACE_LIMIT(log))
+       if (cil->xc_ctx->space_used < XLOG_CIL_SPACE_LIMIT(log)) {
+               up_read(&cil->xc_ctx_lock);
                return;
+       }
 
        spin_lock(&cil->xc_push_lock);
        if (cil->xc_push_seq < cil->xc_current_sequence) {
                cil->xc_push_seq = cil->xc_current_sequence;
                queue_work(log->l_mp->m_cil_workqueue, &cil->xc_push_work);
        }
+
+       /*
+        * Drop the context lock now, we can't hold that if we need to sleep
+        * because we are over the blocking threshold. The push_lock is still
+        * held, so blocking threshold sleep/wakeup is still correctly
+        * serialised here.
+        */
+       up_read(&cil->xc_ctx_lock);
+
+       /*
+        * If we are well over the space limit, throttle the work that is being
+        * done until the push work on this context has begun.
+        */
+       if (cil->xc_ctx->space_used >= XLOG_CIL_BLOCKING_SPACE_LIMIT(log)) {
+               trace_xfs_log_cil_wait(log, cil->xc_ctx->ticket);
+               ASSERT(cil->xc_ctx->space_used < log->l_logsize);
+               xlog_wait(&cil->xc_ctx->push_wait, &cil->xc_push_lock);
+               return;
+       }
+
        spin_unlock(&cil->xc_push_lock);
 
 }
@@ -1007,7 +1036,10 @@ xfs_log_commit_cil(
        if (commit_lsn)
                *commit_lsn = xc_commit_lsn;
 
-       xfs_log_done(mp, tp->t_ticket, NULL, regrant);
+       if (regrant && !XLOG_FORCED_SHUTDOWN(log))
+               xfs_log_ticket_regrant(log, tp->t_ticket);
+       else
+               xfs_log_ticket_ungrant(log, tp->t_ticket);
        tp->t_ticket = NULL;
        xfs_trans_unreserve_and_mod_sb(tp);
 
@@ -1028,9 +1060,9 @@ xfs_log_commit_cil(
                if (lip->li_ops->iop_committing)
                        lip->li_ops->iop_committing(lip, xc_commit_lsn);
        }
-       xlog_cil_push_background(log);
 
-       up_read(&cil->xc_ctx_lock);
+       /* xlog_cil_push_background() releases cil->xc_ctx_lock */
+       xlog_cil_push_background(log);
 }
 
 /*
@@ -1189,6 +1221,7 @@ xlog_cil_init(
 
        INIT_LIST_HEAD(&ctx->committing);
        INIT_LIST_HEAD(&ctx->busy_extents);
+       init_waitqueue_head(&ctx->push_wait);
        ctx->sequence = 1;
        ctx->cil = cil;
        cil->xc_ctx = ctx;
index 2b0aec3..ec22c7a 100644 (file)
@@ -51,13 +51,11 @@ enum xlog_iclog_state {
 };
 
 /*
- * Flags to log ticket
+ * Log ticket flags
  */
-#define XLOG_TIC_INITED                0x1     /* has been initialized */
-#define XLOG_TIC_PERM_RESERV   0x2     /* permanent reservation */
+#define XLOG_TIC_PERM_RESERV   0x1     /* permanent reservation */
 
 #define XLOG_TIC_FLAGS \
-       { XLOG_TIC_INITED,      "XLOG_TIC_INITED" }, \
        { XLOG_TIC_PERM_RESERV, "XLOG_TIC_PERM_RESERV" }
 
 /*
@@ -242,6 +240,7 @@ struct xfs_cil_ctx {
        struct xfs_log_vec      *lv_chain;      /* logvecs being pushed */
        struct list_head        iclog_entry;
        struct list_head        committing;     /* ctx committing list */
+       wait_queue_head_t       push_wait;      /* background push throttle */
        struct work_struct      discard_endio_work;
 };
 
@@ -318,13 +317,53 @@ struct xfs_cil {
  * tries to keep 25% of the log free, so we need to keep below that limit or we
  * risk running out of free log space to start any new transactions.
  *
- * In order to keep background CIL push efficient, we will set a lower
- * threshold at which background pushing is attempted without blocking current
- * transaction commits.  A separate, higher bound defines when CIL pushes are
- * enforced to ensure we stay within our maximum checkpoint size bounds.
- * threshold, yet give us plenty of space for aggregation on large logs.
+ * In order to keep background CIL push efficient, we only need to ensure the
+ * CIL is large enough to maintain sufficient in-memory relogging to avoid
+ * repeated physical writes of frequently modified metadata. If we allow the CIL
+ * to grow to a substantial fraction of the log, then we may be pinning hundreds
+ * of megabytes of metadata in memory until the CIL flushes. This can cause
+ * issues when we are running low on memory - pinned memory cannot be reclaimed,
+ * and the CIL consumes a lot of memory. Hence we need to set an upper physical
+ * size limit for the CIL that limits the maximum amount of memory pinned by the
+ * CIL but does not limit performance by reducing relogging efficiency
+ * significantly.
+ *
+ * As such, the CIL push threshold ends up being the smaller of two thresholds:
+ * - a threshold large enough that it allows CIL to be pushed and progress to be
+ *   made without excessive blocking of incoming transaction commits. This is
+ *   defined to be 12.5% of the log space - half the 25% push threshold of the
+ *   AIL.
+ * - small enough that it doesn't pin excessive amounts of memory but maintains
+ *   close to peak relogging efficiency. This is defined to be 16x the iclog
+ *   buffer window (32MB) as measurements have shown this to be roughly the
+ *   point of diminishing performance increases under highly concurrent
+ *   modification workloads.
+ *
+ * To prevent the CIL from overflowing upper commit size bounds, we introduce a
+ * new threshold at which we block committing transactions until the background
+ * CIL commit commences and switches to a new context. While this is not a hard
+ * limit, it forces the process committing a transaction to the CIL to block and
+ * yeild the CPU, giving the CIL push work a chance to be scheduled and start
+ * work. This prevents a process running lots of transactions from overfilling
+ * the CIL because it is not yielding the CPU. We set the blocking limit at
+ * twice the background push space threshold so we keep in line with the AIL
+ * push thresholds.
+ *
+ * Note: this is not a -hard- limit as blocking is applied after the transaction
+ * is inserted into the CIL and the push has been triggered. It is largely a
+ * throttling mechanism that allows the CIL push to be scheduled and run. A hard
+ * limit will be difficult to implement without introducing global serialisation
+ * in the CIL commit fast path, and it's not at all clear that we actually need
+ * such hard limits given the ~7 years we've run without a hard limit before
+ * finding the first situation where a checkpoint size overflow actually
+ * occurred. Hence the simple throttle, and an ASSERT check to tell us that
+ * we've overrun the max size.
  */
-#define XLOG_CIL_SPACE_LIMIT(log)      (log->l_logsize >> 3)
+#define XLOG_CIL_SPACE_LIMIT(log)      \
+       min_t(int, (log)->l_logsize >> 3, BBTOB(XLOG_TOTAL_REC_SHIFT(log)) << 4)
+
+#define XLOG_CIL_BLOCKING_SPACE_LIMIT(log)     \
+       (XLOG_CIL_SPACE_LIMIT(log) * 2)
 
 /*
  * ticket grant locks, queues and accounting have their own cachlines
@@ -439,14 +478,14 @@ xlog_write_adv_cnt(void **ptr, int *len, int *off, size_t bytes)
 
 void   xlog_print_tic_res(struct xfs_mount *mp, struct xlog_ticket *ticket);
 void   xlog_print_trans(struct xfs_trans *);
-int
-xlog_write(
-       struct xlog             *log,
-       struct xfs_log_vec      *log_vector,
-       struct xlog_ticket      *tic,
-       xfs_lsn_t               *start_lsn,
-       struct xlog_in_core     **commit_iclog,
-       uint                    flags);
+int    xlog_write(struct xlog *log, struct xfs_log_vec *log_vector,
+               struct xlog_ticket *tic, xfs_lsn_t *start_lsn,
+               struct xlog_in_core **commit_iclog, uint flags,
+               bool need_start_rec);
+int    xlog_commit_record(struct xlog *log, struct xlog_ticket *ticket,
+               struct xlog_in_core **iclog, xfs_lsn_t *lsn);
+void   xfs_log_ticket_ungrant(struct xlog *log, struct xlog_ticket *ticket);
+void   xfs_log_ticket_regrant(struct xlog *log, struct xlog_ticket *ticket);
 
 /*
  * When we crack an atomic LSN, we sample it first so that the value will not
index 88ab09e..50c4342 100644 (file)
@@ -167,6 +167,7 @@ typedef struct xfs_mount {
        struct xfs_kobj         m_error_meta_kobj;
        struct xfs_error_cfg    m_error_cfg[XFS_ERR_CLASS_MAX][XFS_ERR_ERRNO_MAX];
        struct xstats           m_stats;        /* per-fs stats */
+       struct ratelimit_state  m_flush_inodes_ratelimit;
 
        struct workqueue_struct *m_buf_workqueue;
        struct workqueue_struct *m_unwritten_workqueue;
index cabdb75..c225691 100644 (file)
@@ -121,12 +121,11 @@ xfs_qm_dqpurge(
 {
        struct xfs_mount        *mp = dqp->q_mount;
        struct xfs_quotainfo    *qi = mp->m_quotainfo;
+       int                     error = -EAGAIN;
 
        xfs_dqlock(dqp);
-       if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0) {
-               xfs_dqunlock(dqp);
-               return -EAGAIN;
-       }
+       if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0)
+               goto out_unlock;
 
        dqp->dq_flags |= XFS_DQ_FREEING;
 
@@ -139,7 +138,6 @@ xfs_qm_dqpurge(
         */
        if (XFS_DQ_IS_DIRTY(dqp)) {
                struct xfs_buf  *bp = NULL;
-               int             error;
 
                /*
                 * We don't care about getting disk errors here. We need
@@ -149,6 +147,8 @@ xfs_qm_dqpurge(
                if (!error) {
                        error = xfs_bwrite(bp);
                        xfs_buf_relse(bp);
+               } else if (error == -EAGAIN) {
+                       goto out_unlock;
                }
                xfs_dqflock(dqp);
        }
@@ -174,6 +174,10 @@ xfs_qm_dqpurge(
 
        xfs_qm_dqdestroy(dqp);
        return 0;
+
+out_unlock:
+       xfs_dqunlock(dqp);
+       return error;
 }
 
 /*
index 2094386..abf06bf 100644 (file)
@@ -528,6 +528,9 @@ xfs_flush_inodes(
 {
        struct super_block      *sb = mp->m_super;
 
+       if (!__ratelimit(&mp->m_flush_inodes_ratelimit))
+               return;
+
        if (down_read_trylock(&sb->s_umount)) {
                sync_inodes_sb(sb);
                up_read(&sb->s_umount);
@@ -1366,6 +1369,17 @@ xfs_fc_fill_super(
        if (error)
                goto out_free_names;
 
+       /*
+        * Cap the number of invocations of xfs_flush_inodes to 16 for every
+        * quarter of a second.  The magic numbers here were determined by
+        * observation neither to cause stalls in writeback when there are a
+        * lot of IO threads and the fs is near ENOSPC, nor cause any fstest
+        * regressions.  YMMV.
+        */
+       ratelimit_state_init(&mp->m_flush_inodes_ratelimit, HZ / 4, 16);
+       ratelimit_set_flags(&mp->m_flush_inodes_ratelimit,
+                       RATELIMIT_MSG_ON_RELEASE);
+
        error = xfs_init_mount_workqueues(mp);
        if (error)
                goto out_close_devices;
@@ -1861,7 +1875,8 @@ xfs_init_zones(void)
 
        xfs_ili_zone = kmem_cache_create("xfs_ili",
                                         sizeof(struct xfs_inode_log_item), 0,
-                                        SLAB_MEM_SPREAD, NULL);
+                                        SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+                                        NULL);
        if (!xfs_ili_zone)
                goto out_destroy_inode_zone;
 
index fa0fa3c..13fb4b9 100644 (file)
@@ -176,7 +176,6 @@ xfs_symlink(
                return -ENAMETOOLONG;
        ASSERT(pathlen > 0);
 
-       udqp = gdqp = NULL;
        prid = xfs_get_initial_prid(dp);
 
        /*
index efc7751..a4323a6 100644 (file)
@@ -1001,8 +1001,6 @@ DECLARE_EVENT_CLASS(xfs_loggrant_class,
 DEFINE_EVENT(xfs_loggrant_class, name, \
        TP_PROTO(struct xlog *log, struct xlog_ticket *tic), \
        TP_ARGS(log, tic))
-DEFINE_LOGGRANT_EVENT(xfs_log_done_nonperm);
-DEFINE_LOGGRANT_EVENT(xfs_log_done_perm);
 DEFINE_LOGGRANT_EVENT(xfs_log_umount_write);
 DEFINE_LOGGRANT_EVENT(xfs_log_grant_sleep);
 DEFINE_LOGGRANT_EVENT(xfs_log_grant_wake);
@@ -1011,12 +1009,13 @@ DEFINE_LOGGRANT_EVENT(xfs_log_reserve);
 DEFINE_LOGGRANT_EVENT(xfs_log_reserve_exit);
 DEFINE_LOGGRANT_EVENT(xfs_log_regrant);
 DEFINE_LOGGRANT_EVENT(xfs_log_regrant_exit);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_enter);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_exit);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_sub);
-DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_enter);
-DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_exit);
-DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_sub);
+DEFINE_LOGGRANT_EVENT(xfs_log_ticket_regrant);
+DEFINE_LOGGRANT_EVENT(xfs_log_ticket_regrant_exit);
+DEFINE_LOGGRANT_EVENT(xfs_log_ticket_regrant_sub);
+DEFINE_LOGGRANT_EVENT(xfs_log_ticket_ungrant);
+DEFINE_LOGGRANT_EVENT(xfs_log_ticket_ungrant_sub);
+DEFINE_LOGGRANT_EVENT(xfs_log_ticket_ungrant_exit);
+DEFINE_LOGGRANT_EVENT(xfs_log_cil_wait);
 
 DECLARE_EVENT_CLASS(xfs_log_item_class,
        TP_PROTO(struct xfs_log_item *lip),
index 1adc6bc..28b983f 100644 (file)
@@ -9,6 +9,7 @@
 #include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_log_format.h"
+#include "xfs_log_priv.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 #include "xfs_extent_busy.h"
@@ -150,8 +151,9 @@ xfs_trans_reserve(
        uint                    blocks,
        uint                    rtextents)
 {
-       int             error = 0;
-       bool            rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
+       struct xfs_mount        *mp = tp->t_mountp;
+       int                     error = 0;
+       bool                    rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
 
        /* Mark this thread as being in a transaction */
        current_set_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
@@ -162,7 +164,7 @@ xfs_trans_reserve(
         * fail if the count would go below zero.
         */
        if (blocks > 0) {
-               error = xfs_mod_fdblocks(tp->t_mountp, -((int64_t)blocks), rsvd);
+               error = xfs_mod_fdblocks(mp, -((int64_t)blocks), rsvd);
                if (error != 0) {
                        current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
                        return -ENOSPC;
@@ -191,9 +193,9 @@ xfs_trans_reserve(
 
                if (tp->t_ticket != NULL) {
                        ASSERT(resp->tr_logflags & XFS_TRANS_PERM_LOG_RES);
-                       error = xfs_log_regrant(tp->t_mountp, tp->t_ticket);
+                       error = xfs_log_regrant(mp, tp->t_ticket);
                } else {
-                       error = xfs_log_reserve(tp->t_mountp,
+                       error = xfs_log_reserve(mp,
                                                resp->tr_logres,
                                                resp->tr_logcount,
                                                &tp->t_ticket, XFS_TRANSACTION,
@@ -213,7 +215,7 @@ xfs_trans_reserve(
         * fail if the count would go below zero.
         */
        if (rtextents > 0) {
-               error = xfs_mod_frextents(tp->t_mountp, -((int64_t)rtextents));
+               error = xfs_mod_frextents(mp, -((int64_t)rtextents));
                if (error) {
                        error = -ENOSPC;
                        goto undo_log;
@@ -229,7 +231,7 @@ xfs_trans_reserve(
         */
 undo_log:
        if (resp->tr_logres > 0) {
-               xfs_log_done(tp->t_mountp, tp->t_ticket, NULL, false);
+               xfs_log_ticket_ungrant(mp->m_log, tp->t_ticket);
                tp->t_ticket = NULL;
                tp->t_log_res = 0;
                tp->t_flags &= ~XFS_TRANS_PERM_LOG_RES;
@@ -237,7 +239,7 @@ undo_log:
 
 undo_blocks:
        if (blocks > 0) {
-               xfs_mod_fdblocks(tp->t_mountp, (int64_t)blocks, rsvd);
+               xfs_mod_fdblocks(mp, (int64_t)blocks, rsvd);
                tp->t_blk_res = 0;
        }
 
@@ -1004,9 +1006,10 @@ out_unreserve:
         */
        xfs_trans_unreserve_and_mod_dquots(tp);
        if (tp->t_ticket) {
-               commit_lsn = xfs_log_done(mp, tp->t_ticket, NULL, regrant);
-               if (commit_lsn == -1 && !error)
-                       error = -EIO;
+               if (regrant && !XLOG_FORCED_SHUTDOWN(mp->m_log))
+                       xfs_log_ticket_regrant(mp->m_log, tp->t_ticket);
+               else
+                       xfs_log_ticket_ungrant(mp->m_log, tp->t_ticket);
                tp->t_ticket = NULL;
        }
        current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
@@ -1065,7 +1068,7 @@ xfs_trans_cancel(
        xfs_trans_unreserve_and_mod_dquots(tp);
 
        if (tp->t_ticket) {
-               xfs_log_done(mp, tp->t_ticket, NULL, false);
+               xfs_log_ticket_ungrant(mp->m_log, tp->t_ticket);
                tp->t_ticket = NULL;
        }
 
index 2ef0dfb..5642535 100644 (file)
@@ -109,17 +109,25 @@ xfs_ail_next(
  * We need the AIL lock in order to get a coherent read of the lsn of the last
  * item in the AIL.
  */
+static xfs_lsn_t
+__xfs_ail_min_lsn(
+       struct xfs_ail          *ailp)
+{
+       struct xfs_log_item     *lip = xfs_ail_min(ailp);
+
+       if (lip)
+               return lip->li_lsn;
+       return 0;
+}
+
 xfs_lsn_t
 xfs_ail_min_lsn(
        struct xfs_ail          *ailp)
 {
-       xfs_lsn_t               lsn = 0;
-       struct xfs_log_item     *lip;
+       xfs_lsn_t               lsn;
 
        spin_lock(&ailp->ail_lock);
-       lip = xfs_ail_min(ailp);
-       if (lip)
-               lsn = lip->li_lsn;
+       lsn = __xfs_ail_min_lsn(ailp);
        spin_unlock(&ailp->ail_lock);
 
        return lsn;
@@ -681,6 +689,28 @@ xfs_ail_push_all_sync(
        finish_wait(&ailp->ail_empty, &wait);
 }
 
+void
+xfs_ail_update_finish(
+       struct xfs_ail          *ailp,
+       xfs_lsn_t               old_lsn) __releases(ailp->ail_lock)
+{
+       struct xfs_mount        *mp = ailp->ail_mount;
+
+       /* if the tail lsn hasn't changed, don't do updates or wakeups. */
+       if (!old_lsn || old_lsn == __xfs_ail_min_lsn(ailp)) {
+               spin_unlock(&ailp->ail_lock);
+               return;
+       }
+
+       if (!XFS_FORCED_SHUTDOWN(mp))
+               xlog_assign_tail_lsn_locked(mp);
+
+       if (list_empty(&ailp->ail_head))
+               wake_up_all(&ailp->ail_empty);
+       spin_unlock(&ailp->ail_lock);
+       xfs_log_space_wake(mp);
+}
+
 /*
  * xfs_trans_ail_update - bulk AIL insertion operation.
  *
@@ -712,7 +742,7 @@ xfs_trans_ail_update_bulk(
        xfs_lsn_t               lsn) __releases(ailp->ail_lock)
 {
        struct xfs_log_item     *mlip;
-       int                     mlip_changed = 0;
+       xfs_lsn_t               tail_lsn = 0;
        int                     i;
        LIST_HEAD(tmp);
 
@@ -727,9 +757,10 @@ xfs_trans_ail_update_bulk(
                                continue;
 
                        trace_xfs_ail_move(lip, lip->li_lsn, lsn);
+                       if (mlip == lip && !tail_lsn)
+                               tail_lsn = lip->li_lsn;
+
                        xfs_ail_delete(ailp, lip);
-                       if (mlip == lip)
-                               mlip_changed = 1;
                } else {
                        trace_xfs_ail_insert(lip, 0, lsn);
                }
@@ -740,23 +771,23 @@ xfs_trans_ail_update_bulk(
        if (!list_empty(&tmp))
                xfs_ail_splice(ailp, cur, &tmp, lsn);
 
-       if (mlip_changed) {
-               if (!XFS_FORCED_SHUTDOWN(ailp->ail_mount))
-                       xlog_assign_tail_lsn_locked(ailp->ail_mount);
-               spin_unlock(&ailp->ail_lock);
-
-               xfs_log_space_wake(ailp->ail_mount);
-       } else {
-               spin_unlock(&ailp->ail_lock);
-       }
+       xfs_ail_update_finish(ailp, tail_lsn);
 }
 
-bool
+/*
+ * Delete one log item from the AIL.
+ *
+ * If this item was at the tail of the AIL, return the LSN of the log item so
+ * that we can use it to check if the LSN of the tail of the log has moved
+ * when finishing up the AIL delete process in xfs_ail_update_finish().
+ */
+xfs_lsn_t
 xfs_ail_delete_one(
        struct xfs_ail          *ailp,
        struct xfs_log_item     *lip)
 {
        struct xfs_log_item     *mlip = xfs_ail_min(ailp);
+       xfs_lsn_t               lsn = lip->li_lsn;
 
        trace_xfs_ail_delete(lip, mlip->li_lsn, lip->li_lsn);
        xfs_ail_delete(ailp, lip);
@@ -764,7 +795,9 @@ xfs_ail_delete_one(
        clear_bit(XFS_LI_IN_AIL, &lip->li_flags);
        lip->li_lsn = 0;
 
-       return mlip == lip;
+       if (mlip == lip)
+               return lsn;
+       return 0;
 }
 
 /**
@@ -792,10 +825,10 @@ void
 xfs_trans_ail_delete(
        struct xfs_ail          *ailp,
        struct xfs_log_item     *lip,
-       int                     shutdown_type) __releases(ailp->ail_lock)
+       int                     shutdown_type)
 {
        struct xfs_mount        *mp = ailp->ail_mount;
-       bool                    mlip_changed;
+       xfs_lsn_t               tail_lsn;
 
        if (!test_bit(XFS_LI_IN_AIL, &lip->li_flags)) {
                spin_unlock(&ailp->ail_lock);
@@ -808,17 +841,8 @@ xfs_trans_ail_delete(
                return;
        }
 
-       mlip_changed = xfs_ail_delete_one(ailp, lip);
-       if (mlip_changed) {
-               if (!XFS_FORCED_SHUTDOWN(mp))
-                       xlog_assign_tail_lsn_locked(mp);
-               if (list_empty(&ailp->ail_head))
-                       wake_up_all(&ailp->ail_empty);
-       }
-
-       spin_unlock(&ailp->ail_lock);
-       if (mlip_changed)
-               xfs_log_space_wake(ailp->ail_mount);
+       tail_lsn = xfs_ail_delete_one(ailp, lip);
+       xfs_ail_update_finish(ailp, tail_lsn);
 }
 
 int
index 2e073c1..35655ea 100644 (file)
@@ -91,9 +91,11 @@ xfs_trans_ail_update(
        xfs_trans_ail_update_bulk(ailp, NULL, &lip, 1, lsn);
 }
 
-bool xfs_ail_delete_one(struct xfs_ail *ailp, struct xfs_log_item *lip);
+xfs_lsn_t xfs_ail_delete_one(struct xfs_ail *ailp, struct xfs_log_item *lip);
+void xfs_ail_update_finish(struct xfs_ail *ailp, xfs_lsn_t old_lsn)
+                       __releases(ailp->ail_lock);
 void xfs_trans_ail_delete(struct xfs_ail *ailp, struct xfs_log_item *lip,
-               int shutdown_type) __releases(ailp->ail_lock);
+               int shutdown_type);
 
 static inline void
 xfs_trans_ail_remove(
index b3f1082..1c4fd95 100644 (file)
@@ -163,7 +163,7 @@ static inline int cpumask_to_vpset(struct hv_vpset *vpset,
        return nr_bank;
 }
 
-void hyperv_report_panic(struct pt_regs *regs, long err);
+void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die);
 void hyperv_report_panic_msg(phys_addr_t pa, size_t size);
 bool hv_is_hyperv_initialized(void);
 bool hv_is_hibernation_supported(void);
index 25f0523..531ca87 100644 (file)
@@ -248,8 +248,7 @@ int omap_dm_timers_active(void);
 
 /*
  * The below are inlined to optimize code size for system timers. Other code
- * should not need these at all, see
- * include/linux/platform_data/pwm_omap_dmtimer.h
+ * should not need these at all.
  */
 #if defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP2PLUS)
 static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
index 9ecb3c1..4e6dc84 100644 (file)
@@ -33,8 +33,7 @@ bool __must_check curve25519(u8 mypublic[CURVE25519_KEY_SIZE],
                             const u8 secret[CURVE25519_KEY_SIZE],
                             const u8 basepoint[CURVE25519_KEY_SIZE])
 {
-       if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519) &&
-           (!IS_ENABLED(CONFIG_CRYPTO_CURVE25519_X86) || IS_ENABLED(CONFIG_AS_ADX)))
+       if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519))
                curve25519_arch(mypublic, secret, basepoint);
        else
                curve25519_generic(mypublic, secret, basepoint);
@@ -50,8 +49,7 @@ __must_check curve25519_generate_public(u8 pub[CURVE25519_KEY_SIZE],
                                    CURVE25519_KEY_SIZE)))
                return false;
 
-       if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519) &&
-           (!IS_ENABLED(CONFIG_CRYPTO_CURVE25519_X86) || IS_ENABLED(CONFIG_AS_ADX)))
+       if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519))
                curve25519_base_arch(pub, secret);
        else
                curve25519_generic(pub, secret, curve25519_base_point);
index 7aa2f93..b0dcc07 100644 (file)
@@ -42,9 +42,10 @@ int analogix_dp_resume(struct analogix_dp_device *dp);
 int analogix_dp_suspend(struct analogix_dp_device *dp);
 
 struct analogix_dp_device *
-analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-                struct analogix_dp_plat_data *plat_data);
+analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data);
+int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev);
 void analogix_dp_unbind(struct analogix_dp_device *dp);
+void analogix_dp_remove(struct analogix_dp_device *dp);
 
 int analogix_dp_start_crc(struct drm_connector *connector);
 int analogix_dp_stop_crc(struct drm_connector *connector);
index dcef359..aed382c 100644 (file)
@@ -136,7 +136,7 @@ struct drm_sg_mem {
  * Kernel side of a mapping
  */
 struct drm_local_map {
-       resource_size_t offset;  /**< Requested physical address (0 for SAREA)*/
+       dma_addr_t offset;       /**< Requested physical address (0 for SAREA)*/
        unsigned long size;      /**< Requested physical size (bytes) */
        enum drm_map_type type;  /**< Type of memory to map */
        enum drm_map_flags flags;        /**< Flags */
diff --git a/include/dt-bindings/clock/k210-clk.h b/include/dt-bindings/clock/k210-clk.h
new file mode 100644 (file)
index 0000000..5a2fd64
--- /dev/null
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+#ifndef K210_CLK_H
+#define K210_CLK_H
+
+/*
+ * Arbitrary identifiers for clocks.
+ * The structure is: in0 -> pll0 -> aclk -> cpu
+ *
+ * Since we use the hardware defaults for now, set all these to the same clock.
+ */
+#define K210_CLK_PLL0   0
+#define K210_CLK_PLL1   0
+#define K210_CLK_ACLK   0
+#define K210_CLK_CPU    0
+
+#endif /* K210_CLK_H */
index 9e1256a..0ce7dfc 100644 (file)
@@ -6,6 +6,7 @@
  * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
  *
  * Copyright (C) 2019 Jacek Anaszewski <jacek.anaszewski@gmail.com>
+ * Copyright (C) 2020 Pavel Machek <pavel@ucw.cz>
  */
 
 #ifndef __DT_BINDINGS_LEDS_H
 #define LED_COLOR_ID_MAX       8
 
 /* Standard LED functions */
+/* Keyboard LEDs, usually it would be input4::capslock etc. */
+/*   Obsolete equivalent: "shift-key-light" */
+#define LED_FUNCTION_CAPSLOCK "capslock"
+#define LED_FUNCTION_SCROLLLOCK "scrolllock"
+#define LED_FUNCTION_NUMLOCK "numlock"
+/*   Obsolete equivalents: "tpacpi::thinklight" (IBM/Lenovo Thinkpads),
+     "lp5523:kb{1,2,3,4,5,6}" (Nokia N900) */
+#define LED_FUNCTION_KBD_BACKLIGHT "kbd_backlight"
+
+/* System LEDs, usually found on system body.
+   platform::mute (etc) is sometimes seen, :mute would be better */
+#define LED_FUNCTION_POWER "power"
+#define LED_FUNCTION_DISK "disk"
+
+/*   Obsolete: "platform:*:charging" (allwinner sun50i) */
+#define LED_FUNCTION_CHARGING "charging"
+/*   Used RGB notification LEDs common on phones.
+     Obsolete equivalents: "status-led:{red,green,blue}" (Motorola Droid 4),
+     "lp5523:{r,g,b}" (Nokia N900) */
+#define LED_FUNCTION_STATUS "status"
+
+#define LED_FUNCTION_MICMUTE "micmute"
+#define LED_FUNCTION_MUTE "mute"
+
+/* Miscelleaus functions. Use functions above if you can. */
 #define LED_FUNCTION_ACTIVITY "activity"
 #define LED_FUNCTION_ALARM "alarm"
 #define LED_FUNCTION_BACKLIGHT "backlight"
 #define LED_FUNCTION_BLUETOOTH "bluetooth"
 #define LED_FUNCTION_BOOT "boot"
 #define LED_FUNCTION_CPU "cpu"
-#define LED_FUNCTION_CAPSLOCK "capslock"
-#define LED_FUNCTION_CHARGING "charging"
 #define LED_FUNCTION_DEBUG "debug"
-#define LED_FUNCTION_DISK "disk"
 #define LED_FUNCTION_DISK_ACTIVITY "disk-activity"
 #define LED_FUNCTION_DISK_ERR "disk-err"
 #define LED_FUNCTION_DISK_READ "disk-read"
 #define LED_FUNCTION_FLASH "flash"
 #define LED_FUNCTION_HEARTBEAT "heartbeat"
 #define LED_FUNCTION_INDICATOR "indicator"
-#define LED_FUNCTION_KBD_BACKLIGHT "kbd_backlight"
 #define LED_FUNCTION_LAN "lan"
 #define LED_FUNCTION_MAIL "mail"
 #define LED_FUNCTION_MTD "mtd"
-#define LED_FUNCTION_MICMUTE "micmute"
-#define LED_FUNCTION_MUTE "mute"
-#define LED_FUNCTION_NUMLOCK "numlock"
 #define LED_FUNCTION_PANIC "panic"
 #define LED_FUNCTION_PROGRAMMING "programming"
-#define LED_FUNCTION_POWER "power"
 #define LED_FUNCTION_RX "rx"
 #define LED_FUNCTION_SD "sd"
-#define LED_FUNCTION_SCROLLLOCK "scrolllock"
 #define LED_FUNCTION_STANDBY "standby"
-#define LED_FUNCTION_STATUS "status"
 #define LED_FUNCTION_TORCH "torch"
 #define LED_FUNCTION_TX "tx"
 #define LED_FUNCTION_USB "usb"
index 9f70b78..d661cd0 100644 (file)
@@ -416,9 +416,30 @@ extern void acpi_osi_setup(char *str);
 extern bool acpi_osi_is_win8(void);
 
 #ifdef CONFIG_ACPI_NUMA
-int acpi_map_pxm_to_online_node(int pxm);
 int acpi_map_pxm_to_node(int pxm);
 int acpi_get_node(acpi_handle handle);
+
+/**
+ * acpi_map_pxm_to_online_node - Map proximity ID to online node
+ * @pxm: ACPI proximity ID
+ *
+ * This is similar to acpi_map_pxm_to_node(), but always returns an online
+ * node.  When the mapped node from a given proximity ID is offline, it
+ * looks up the node distance table and returns the nearest online node.
+ *
+ * ACPI device drivers, which are called after the NUMA initialization has
+ * completed in the kernel, can call this interface to obtain their device
+ * NUMA topology from ACPI tables.  Such drivers do not have to deal with
+ * offline nodes.  A node may be offline when a device proximity ID is
+ * unique, SRAT memory entry does not exist, or NUMA is disabled, ex.
+ * "numa=off" on x86.
+ */
+static inline int acpi_map_pxm_to_online_node(int pxm)
+{
+       int node = acpi_map_pxm_to_node(pxm);
+
+       return numa_map_to_online_node(node);
+}
 #else
 static inline int acpi_map_pxm_to_online_node(int pxm)
 {
index e4a6949..35f8ffe 100644 (file)
@@ -46,6 +46,7 @@ struct blkcg_gq;
 struct blkcg {
        struct cgroup_subsys_state      css;
        spinlock_t                      lock;
+       refcount_t                      online_pin;
 
        struct radix_tree_root          blkg_tree;
        struct blkcg_gq __rcu           *blkg_hint;
@@ -56,7 +57,6 @@ struct blkcg {
        struct list_head                all_blkcgs_node;
 #ifdef CONFIG_CGROUP_WRITEBACK
        struct list_head                cgwb_list;
-       refcount_t                      cgwb_refcnt;
 #endif
 };
 
@@ -412,47 +412,38 @@ static inline struct blkcg *cpd_to_blkcg(struct blkcg_policy_data *cpd)
 
 extern void blkcg_destroy_blkgs(struct blkcg *blkcg);
 
-#ifdef CONFIG_CGROUP_WRITEBACK
-
 /**
- * blkcg_cgwb_get - get a reference for blkcg->cgwb_list
+ * blkcg_pin_online - pin online state
  * @blkcg: blkcg of interest
  *
- * This is used to track the number of active wb's related to a blkcg.
+ * While pinned, a blkcg is kept online.  This is primarily used to
+ * impedance-match blkg and cgwb lifetimes so that blkg doesn't go offline
+ * while an associated cgwb is still active.
  */
-static inline void blkcg_cgwb_get(struct blkcg *blkcg)
+static inline void blkcg_pin_online(struct blkcg *blkcg)
 {
-       refcount_inc(&blkcg->cgwb_refcnt);
+       refcount_inc(&blkcg->online_pin);
 }
 
 /**
- * blkcg_cgwb_put - put a reference for @blkcg->cgwb_list
+ * blkcg_unpin_online - unpin online state
  * @blkcg: blkcg of interest
  *
- * This is used to track the number of active wb's related to a blkcg.
- * When this count goes to zero, all active wb has finished so the
+ * This is primarily used to impedance-match blkg and cgwb lifetimes so
+ * that blkg doesn't go offline while an associated cgwb is still active.
+ * When this count goes to zero, all active cgwbs have finished so the
  * blkcg can continue destruction by calling blkcg_destroy_blkgs().
- * This work may occur in cgwb_release_workfn() on the cgwb_release
- * workqueue.
  */
-static inline void blkcg_cgwb_put(struct blkcg *blkcg)
+static inline void blkcg_unpin_online(struct blkcg *blkcg)
 {
-       if (refcount_dec_and_test(&blkcg->cgwb_refcnt))
+       do {
+               if (!refcount_dec_and_test(&blkcg->online_pin))
+                       break;
                blkcg_destroy_blkgs(blkcg);
+               blkcg = blkcg_parent(blkcg);
+       } while (blkcg);
 }
 
-#else
-
-static inline void blkcg_cgwb_get(struct blkcg *blkcg) { }
-
-static inline void blkcg_cgwb_put(struct blkcg *blkcg)
-{
-       /* wb isn't being accounted, so trigger destruction right away */
-       blkcg_destroy_blkgs(blkcg);
-}
-
-#endif
-
 /**
  * blkg_path - format cgroup path of blkg
  * @blkg: blkg of interest
index cb21c5c..ebf5ba6 100644 (file)
@@ -444,8 +444,9 @@ union ceph_mds_request_args {
        } __attribute__ ((packed)) lookupino;
 } __attribute__ ((packed));
 
-#define CEPH_MDS_FLAG_REPLAY        1  /* this is a replayed op */
-#define CEPH_MDS_FLAG_WANT_DENTRY   2  /* want dentry in reply */
+#define CEPH_MDS_FLAG_REPLAY           1 /* this is a replayed op */
+#define CEPH_MDS_FLAG_WANT_DENTRY      2 /* want dentry in reply */
+#define CEPH_MDS_FLAG_ASYNC            4 /* request is asynchronous */
 
 struct ceph_mds_request_head {
        __le64 oldest_client_tid;
@@ -530,6 +531,9 @@ struct ceph_mds_reply_lease {
        __le32 seq;
 } __attribute__ ((packed));
 
+#define CEPH_LEASE_VALID        (1 | 2) /* old and new bit values */
+#define CEPH_LEASE_PRIMARY_LINK 4       /* primary linkage */
+
 struct ceph_mds_reply_dirfrag {
        __le32 frag;            /* fragment */
        __le32 auth;            /* auth mds, if this is a delegation point */
@@ -564,6 +568,7 @@ struct ceph_filelock {
 #define CEPH_FILE_MODE_RDWR       3  /* RD | WR */
 #define CEPH_FILE_MODE_LAZY       4  /* lazy io */
 #define CEPH_FILE_MODE_BITS       4
+#define CEPH_FILE_MODE_MASK       ((1 << CEPH_FILE_MODE_BITS) - 1)
 
 int ceph_flags_to_mode(int flags);
 
@@ -655,10 +660,19 @@ int ceph_flags_to_mode(int flags);
 #define CEPH_CAP_ANY      (CEPH_CAP_ANY_RD | CEPH_CAP_ANY_EXCL | \
                           CEPH_CAP_ANY_FILE_WR | CEPH_CAP_FILE_LAZYIO | \
                           CEPH_CAP_PIN)
+#define CEPH_CAP_ALL_FILE (CEPH_CAP_PIN | CEPH_CAP_ANY_SHARED | \
+                          CEPH_CAP_AUTH_EXCL | CEPH_CAP_XATTR_EXCL | \
+                          CEPH_CAP_ANY_FILE_RD | CEPH_CAP_ANY_FILE_WR)
 
 #define CEPH_CAP_LOCKS (CEPH_LOCK_IFILE | CEPH_LOCK_IAUTH | CEPH_LOCK_ILINK | \
                        CEPH_LOCK_IXATTR)
 
+/* cap masks async dir operations */
+#define CEPH_CAP_DIR_CREATE    CEPH_CAP_FILE_CACHE
+#define CEPH_CAP_DIR_UNLINK    CEPH_CAP_FILE_RD
+#define CEPH_CAP_ANY_DIR_OPS   (CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_RD | \
+                                CEPH_CAP_FILE_WREXTEND | CEPH_CAP_FILE_LAZYIO)
+
 int ceph_caps_for_mode(int mode);
 
 enum {
index cf5e840..8b3a1a7 100644 (file)
@@ -2,22 +2,8 @@
 #ifndef _FS_CEPH_DEBUGFS_H
 #define _FS_CEPH_DEBUGFS_H
 
-#include <linux/ceph/ceph_debug.h>
 #include <linux/ceph/types.h>
 
-#define CEPH_DEFINE_SHOW_FUNC(name)                                    \
-static int name##_open(struct inode *inode, struct file *file)         \
-{                                                                      \
-       return single_open(file, name, inode->i_private);               \
-}                                                                      \
-                                                                       \
-static const struct file_operations name##_fops = {                    \
-       .open           = name##_open,                                  \
-       .read           = seq_read,                                     \
-       .llseek         = seq_lseek,                                    \
-       .release        = single_release,                               \
-};
-
 /* debugfs.c */
 extern void ceph_debugfs_init(void);
 extern void ceph_debugfs_cleanup(void);
index ec73ebc..525b7c3 100644 (file)
@@ -272,6 +272,7 @@ extern struct kmem_cache *ceph_cap_flush_cachep;
 extern struct kmem_cache *ceph_dentry_cachep;
 extern struct kmem_cache *ceph_file_cachep;
 extern struct kmem_cache *ceph_dir_file_cachep;
+extern struct kmem_cache *ceph_mds_request_cachep;
 
 /* ceph_common.c */
 extern bool libceph_compatible(void *data);
index 5a62dbd..9d9f745 100644 (file)
@@ -509,23 +509,6 @@ int ceph_osdc_call(struct ceph_osd_client *osdc,
                   struct page *req_page, size_t req_len,
                   struct page **resp_pages, size_t *resp_len);
 
-extern int ceph_osdc_readpages(struct ceph_osd_client *osdc,
-                              struct ceph_vino vino,
-                              struct ceph_file_layout *layout,
-                              u64 off, u64 *plen,
-                              u32 truncate_seq, u64 truncate_size,
-                              struct page **pages, int nr_pages,
-                              int page_align);
-
-extern int ceph_osdc_writepages(struct ceph_osd_client *osdc,
-                               struct ceph_vino vino,
-                               struct ceph_file_layout *layout,
-                               struct ceph_snap_context *sc,
-                               u64 off, u64 len,
-                               u32 truncate_seq, u64 truncate_size,
-                               struct timespec64 *mtime,
-                               struct page **pages, int nr_pages);
-
 int ceph_osdc_copy_from(struct ceph_osd_client *osdc,
                        u64 src_snapid, u64 src_version,
                        struct ceph_object_id *src_oid,
index 190184b..6ff79fe 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/numa.h>
 
 /*
  * There is always at least global CMA area and a few optional
@@ -24,10 +25,19 @@ extern phys_addr_t cma_get_base(const struct cma *cma);
 extern unsigned long cma_get_size(const struct cma *cma);
 extern const char *cma_get_name(const struct cma *cma);
 
-extern int __init cma_declare_contiguous(phys_addr_t base,
+extern int __init cma_declare_contiguous_nid(phys_addr_t base,
                        phys_addr_t size, phys_addr_t limit,
                        phys_addr_t alignment, unsigned int order_per_bit,
-                       bool fixed, const char *name, struct cma **res_cma);
+                       bool fixed, const char *name, struct cma **res_cma,
+                       int nid);
+static inline int __init cma_declare_contiguous(phys_addr_t base,
+                       phys_addr_t size, phys_addr_t limit,
+                       phys_addr_t alignment, unsigned int order_per_bit,
+                       bool fixed, const char *name, struct cma **res_cma)
+{
+       return cma_declare_contiguous_nid(base, size, limit, alignment,
+                       order_per_bit, fixed, name, res_cma, NUMA_NO_NODE);
+}
 extern int cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
                                        unsigned int order_per_bit,
                                        const char *name,
index 328c2db..d7af5d2 100644 (file)
@@ -13,6 +13,7 @@
 typedef unsigned long dax_entry_t;
 
 struct iomap_ops;
+struct iomap;
 struct dax_device;
 struct dax_operations {
        /*
@@ -34,6 +35,8 @@ struct dax_operations {
        /* copy_to_iter: required operation for fs-dax direct-i/o */
        size_t (*copy_to_iter)(struct dax_device *, pgoff_t, void *, size_t,
                        struct iov_iter *);
+       /* zero_page_range: required operation. Zero page range   */
+       int (*zero_page_range)(struct dax_device *, pgoff_t, size_t);
 };
 
 extern struct attribute_group dax_attribute_group;
@@ -199,6 +202,8 @@ 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,
                size_t bytes, struct iov_iter *i);
+int dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
+                       size_t nr_pages);
 void dax_flush(struct dax_device *dax_dev, void *addr, size_t size);
 
 ssize_t dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
@@ -210,20 +215,8 @@ vm_fault_t dax_finish_sync_fault(struct vm_fault *vmf,
 int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index);
 int dax_invalidate_mapping_entry_sync(struct address_space *mapping,
                                      pgoff_t index);
-
-#ifdef CONFIG_FS_DAX
-int __dax_zero_page_range(struct block_device *bdev,
-               struct dax_device *dax_dev, sector_t sector,
-               unsigned int offset, unsigned int length);
-#else
-static inline int __dax_zero_page_range(struct block_device *bdev,
-               struct dax_device *dax_dev, sector_t sector,
-               unsigned int offset, unsigned int length)
-{
-       return -ENXIO;
-}
-#endif
-
+int dax_iomap_zero(loff_t pos, unsigned offset, unsigned size,
+                       struct iomap *iomap);
 static inline bool dax_mapping(struct address_space *mapping)
 {
        return mapping->host && IS_DAX(mapping->host);
index 4635f95..79a6e37 100644 (file)
@@ -75,7 +75,7 @@ void devfreq_cooling_unregister(struct thermal_cooling_device *dfc);
 
 #else /* !CONFIG_DEVFREQ_THERMAL */
 
-struct thermal_cooling_device *
+static inline struct thermal_cooling_device *
 of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
                                  struct devfreq_cooling_power *dfc_power)
 {
index 475668c..af48d9d 100644 (file)
@@ -141,6 +141,8 @@ typedef long (*dm_dax_direct_access_fn) (struct dm_target *ti, pgoff_t pgoff,
                long nr_pages, void **kaddr, pfn_t *pfn);
 typedef size_t (*dm_dax_copy_iter_fn)(struct dm_target *ti, pgoff_t pgoff,
                void *addr, size_t bytes, struct iov_iter *i);
+typedef int (*dm_dax_zero_page_range_fn)(struct dm_target *ti, pgoff_t pgoff,
+               size_t nr_pages);
 #define PAGE_SECTORS (PAGE_SIZE / 512)
 
 void dm_error(const char *message);
@@ -195,6 +197,7 @@ struct target_type {
        dm_dax_direct_access_fn direct_access;
        dm_dax_copy_iter_fn dax_copy_from_iter;
        dm_dax_copy_iter_fn dax_copy_to_iter;
+       dm_dax_zero_page_range_fn dax_zero_page_range;
 
        /* For internal device-mapper use. */
        struct list_head list;
index 1311f27..ac8e37c 100644 (file)
@@ -42,9 +42,8 @@ struct device_node;
 struct fwnode_handle;
 struct iommu_ops;
 struct iommu_group;
-struct iommu_fwspec;
 struct dev_pin_info;
-struct iommu_param;
+struct dev_iommu;
 
 /**
  * struct subsys_interface - interfaces to device functions
@@ -513,8 +512,7 @@ struct dev_links_info {
  *             gone away. This should be set by the allocator of the
  *             device (i.e. the bus driver that discovered the device).
  * @iommu_group: IOMMU group the device belongs to.
- * @iommu_fwspec: IOMMU-specific properties supplied by firmware.
- * @iommu_param: Per device generic IOMMU runtime data
+ * @iommu:     Per device generic IOMMU runtime data
  *
  * @offline_disabled: If set, the device is permanently online.
  * @offline:   Set after successful invocation of bus type's .offline().
@@ -613,8 +611,7 @@ struct device {
 
        void    (*release)(struct device *dev);
        struct iommu_group      *iommu_group;
-       struct iommu_fwspec     *iommu_fwspec;
-       struct iommu_param      *iommu_param;
+       struct dev_iommu        *iommu;
 
        bool                    offline_disabled:1;
        bool                    offline:1;
index 5ea0587..43a1cef 100644 (file)
@@ -895,4 +895,16 @@ static inline spinlock_t *huge_pte_lock(struct hstate *h,
        return ptl;
 }
 
+#if defined(CONFIG_HUGETLB_PAGE) && defined(CONFIG_CMA)
+extern void __init hugetlb_cma_reserve(int order);
+extern void __init hugetlb_cma_check(void);
+#else
+static inline __init void hugetlb_cma_reserve(int order)
+{
+}
+static inline __init void hugetlb_cma_check(void)
+{
+}
+#endif
+
 #endif /* _LINUX_HUGETLB_H */
index bb331e6..7bc961d 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/irqreturn.h>
 #include <linux/platform_data/cros_ec_commands.h>
 #include <linux/platform_data/cros_ec_proto.h>
+#include <linux/platform_data/cros_ec_sensorhub.h>
 
 enum {
        CROS_EC_SENSOR_X,
@@ -29,8 +30,7 @@ enum {
  */
 #define CROS_EC_SAMPLE_SIZE  (sizeof(s64) * 2)
 
-/* Minimum sampling period to use when device is suspending */
-#define CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY 1000  /* 1 second */
+typedef irqreturn_t (*cros_ec_sensors_capture_t)(int irq, void *p);
 
 /**
  * struct cros_ec_sensors_core_state - state data for EC sensors IIO driver
@@ -50,7 +50,9 @@ enum {
  *                             the timestamp. The timestamp is always last and
  *                             is always 8-byte aligned.
  * @read_ec_sensors_data:      function used for accessing sensors values
- * @cuur_sampl_freq:           current sampling period
+ * @fifo_max_event_count:      Size of the EC sensor FIFO
+ * @frequencies:               Table of known available frequencies:
+ *                             0, Min and Max in mHz
  */
 struct cros_ec_sensors_core_state {
        struct cros_ec_device *ec;
@@ -73,101 +75,34 @@ struct cros_ec_sensors_core_state {
        int (*read_ec_sensors_data)(struct iio_dev *indio_dev,
                                    unsigned long scan_mask, s16 *data);
 
-       int curr_sampl_freq;
-
-       /* Table of known available frequencies : 0, Min and Max in mHz */
-       int frequencies[3];
+       u32 fifo_max_event_count;
+       int frequencies[6];
 };
 
-/**
- * cros_ec_sensors_read_lpc() - retrieve data from EC shared memory
- * @indio_dev: pointer to IIO device
- * @scan_mask: bitmap of the sensor indices to scan
- * @data:      location to store data
- *
- * This is the safe function for reading the EC data. It guarantees that the
- * data sampled was not modified by the EC while being read.
- *
- * Return: 0 on success, -errno on failure.
- */
 int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev, unsigned long scan_mask,
                             s16 *data);
 
-/**
- * cros_ec_sensors_read_cmd() - retrieve data using the EC command protocol
- * @indio_dev: pointer to IIO device
- * @scan_mask: bitmap of the sensor indices to scan
- * @data:      location to store data
- *
- * Return: 0 on success, -errno on failure.
- */
 int cros_ec_sensors_read_cmd(struct iio_dev *indio_dev, unsigned long scan_mask,
                             s16 *data);
 
 struct platform_device;
-/**
- * cros_ec_sensors_core_init() - basic initialization of the core structure
- * @pdev:              platform device created for the sensors
- * @indio_dev:         iio device structure of the device
- * @physical_device:   true if the device refers to a physical device
- *
- * Return: 0 on success, -errno on failure.
- */
 int cros_ec_sensors_core_init(struct platform_device *pdev,
-                             struct iio_dev *indio_dev, bool physical_device);
+                             struct iio_dev *indio_dev, bool physical_device,
+                             cros_ec_sensors_capture_t trigger_capture,
+                             cros_ec_sensorhub_push_data_cb_t push_data);
 
-/**
- * cros_ec_sensors_capture() - the trigger handler function
- * @irq:       the interrupt number.
- * @p:         a pointer to the poll function.
- *
- * On a trigger event occurring, if the pollfunc is attached then this
- * handler is called as a threaded interrupt (and hence may sleep). It
- * is responsible for grabbing data from the device and pushing it into
- * the associated buffer.
- *
- * Return: IRQ_HANDLED
- */
 irqreturn_t cros_ec_sensors_capture(int irq, void *p);
+int cros_ec_sensors_push_data(struct iio_dev *indio_dev,
+                             s16 *data,
+                             s64 timestamp);
 
-/**
- * cros_ec_motion_send_host_cmd() - send motion sense host command
- * @st:                pointer to state information for device
- * @opt_length:        optional length to reduce the response size, useful on the data
- *             path. Otherwise, the maximal allowed response size is used
- *
- * When called, the sub-command is assumed to be set in param->cmd.
- *
- * Return: 0 on success, -errno on failure.
- */
 int cros_ec_motion_send_host_cmd(struct cros_ec_sensors_core_state *st,
                                 u16 opt_length);
 
-/**
- * cros_ec_sensors_core_read() - function to request a value from the sensor
- * @st:                pointer to state information for device
- * @chan:      channel specification structure table
- * @val:       will contain one element making up the returned value
- * @val2:      will contain another element making up the returned value
- * @mask:      specifies which values to be requested
- *
- * Return:     the type of value returned by the device
- */
 int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st,
                              struct iio_chan_spec const *chan,
                              int *val, int *val2, long mask);
 
-/**
- * cros_ec_sensors_core_read_avail() - get available values
- * @indio_dev:         pointer to state information for device
- * @chan:      channel specification structure table
- * @vals:      list of available values
- * @type:      type of data returned
- * @length:    number of data returned in the array
- * @mask:      specifies which values to be requested
- *
- * Return:     an error code, IIO_AVAIL_RANGE or IIO_AVAIL_LIST
- */
 int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev,
                                    struct iio_chan_spec const *chan,
                                    const int **vals,
@@ -175,23 +110,12 @@ int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev,
                                    int *length,
                                    long mask);
 
-/**
- * cros_ec_sensors_core_write() - function to write a value to the sensor
- * @st:                pointer to state information for device
- * @chan:      channel specification structure table
- * @val:       first part of value to write
- * @val2:      second part of value to write
- * @mask:      specifies which values to write
- *
- * Return:     the type of value returned by the device
- */
 int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st,
                               struct iio_chan_spec const *chan,
                               int val, int val2, long mask);
 
-extern const struct dev_pm_ops cros_ec_sensors_pm_ops;
-
 /* List of extended channel specification for all sensors */
 extern const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[];
+extern const struct attribute *cros_ec_sensor_fifo_attributes[];
 
 #endif  /* __CROS_EC_SENSORS_CORE_H */
index eed58ed..17f56a0 100644 (file)
@@ -629,6 +629,8 @@ static inline clockid_t iio_device_get_clock(const struct iio_dev *indio_dev)
        return indio_dev->clock_id;
 }
 
+int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id);
+
 /**
  * dev_to_iio_dev() - Get IIO device struct from a device struct
  * @dev:               The device embedded in the IIO device
index b1c44bb..8394c56 100644 (file)
@@ -77,8 +77,6 @@ void *devm_memremap(struct device *dev, resource_size_t offset,
                size_t size, unsigned long flags);
 void devm_memunmap(struct device *dev, void *addr);
 
-void *__devm_memremap_pages(struct device *dev, struct resource *res);
-
 #ifdef CONFIG_PCI
 /*
  * The PCI specifications (Rev 3.0, 3.2.5 "Transaction Ordering and
index d1b5f4d..7ef8b0b 100644 (file)
@@ -365,17 +365,20 @@ struct iommu_fault_param {
 };
 
 /**
- * struct iommu_param - collection of per-device IOMMU data
+ * struct dev_iommu - Collection of per-device IOMMU data
  *
  * @fault_param: IOMMU detected device fault reporting data
+ * @fwspec:     IOMMU fwspec data
+ * @priv:       IOMMU Driver private data
  *
  * TODO: migrate other per device data pointers under iommu_dev_data, e.g.
  *     struct iommu_group      *iommu_group;
- *     struct iommu_fwspec     *iommu_fwspec;
  */
-struct iommu_param {
+struct dev_iommu {
        struct mutex lock;
-       struct iommu_fault_param *fault_param;
+       struct iommu_fault_param        *fault_param;
+       struct iommu_fwspec             *fwspec;
+       void                            *priv;
 };
 
 int  iommu_device_register(struct iommu_device *iommu);
@@ -588,11 +591,10 @@ struct iommu_group *fsl_mc_device_group(struct device *dev);
 struct iommu_fwspec {
        const struct iommu_ops  *ops;
        struct fwnode_handle    *iommu_fwnode;
-       void                    *iommu_priv;
        u32                     flags;
        u32                     num_pasid_bits;
        unsigned int            num_ids;
-       u32                     ids[1];
+       u32                     ids[];
 };
 
 /* ATS is supported */
@@ -614,13 +616,26 @@ const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode);
 
 static inline struct iommu_fwspec *dev_iommu_fwspec_get(struct device *dev)
 {
-       return dev->iommu_fwspec;
+       if (dev->iommu)
+               return dev->iommu->fwspec;
+       else
+               return NULL;
 }
 
 static inline void dev_iommu_fwspec_set(struct device *dev,
                                        struct iommu_fwspec *fwspec)
 {
-       dev->iommu_fwspec = fwspec;
+       dev->iommu->fwspec = fwspec;
+}
+
+static inline void *dev_iommu_priv_get(struct device *dev)
+{
+       return dev->iommu->priv;
+}
+
+static inline void dev_iommu_priv_set(struct device *dev, void *priv)
+{
+       dev->iommu->priv = priv;
 }
 
 int iommu_probe_device(struct device *dev);
@@ -1073,6 +1088,10 @@ static inline int iommu_sva_unbind_gpasid(struct iommu_domain *domain,
        return -ENODEV;
 }
 
+static inline struct iommu_fwspec *dev_iommu_fwspec_get(struct device *dev)
+{
+       return NULL;
+}
 #endif /* CONFIG_IOMMU_API */
 
 #ifdef CONFIG_IOMMU_DEBUGFS
index 75353e5..2451962 100644 (file)
@@ -25,6 +25,7 @@ struct device_node;
  * LED Core
  */
 
+/* This is obsolete/useless. We now support variable maximum brightness. */
 enum led_brightness {
        LED_OFF         = 0,
        LED_ON          = 1,
diff --git a/include/linux/leds_pwm.h b/include/linux/leds_pwm.h
deleted file mode 100644 (file)
index 93d101d..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * PWM LED driver data - see drivers/leds/leds-pwm.c
- */
-#ifndef __LINUX_LEDS_PWM_H
-#define __LINUX_LEDS_PWM_H
-
-struct led_pwm {
-       const char      *name;
-       const char      *default_trigger;
-       unsigned        pwm_id __deprecated;
-       u8              active_low;
-       unsigned        max_brightness;
-       unsigned        pwm_period_ns;
-};
-
-struct led_pwm_platform_data {
-       int                     num_leds;
-       struct led_pwm  *leds;
-};
-
-#endif
index 9df091b..18da405 100644 (file)
@@ -37,6 +37,8 @@ enum {
        NDD_WORK_PENDING = 4,
        /* ignore / filter NSLABEL_FLAG_LOCAL for this DIMM, i.e. no aliasing */
        NDD_NOBLK = 5,
+       /* dimm supports namespace labels */
+       NDD_LABELING = 6,
 
        /* need to set a limit somewhere, but yes, this is likely overkill */
        ND_IOCTL_MAX_BUFLEN = SZ_4M,
index 079d17d..6bc37a7 100644 (file)
@@ -348,6 +348,9 @@ static inline int memblock_get_region_node(const struct memblock_region *r)
 
 phys_addr_t memblock_phys_alloc_range(phys_addr_t size, phys_addr_t align,
                                      phys_addr_t start, phys_addr_t end);
+phys_addr_t memblock_alloc_range_nid(phys_addr_t size,
+                                     phys_addr_t align, phys_addr_t start,
+                                     phys_addr_t end, int nid, bool exact_nid);
 phys_addr_t memblock_phys_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid);
 
 static inline phys_addr_t memblock_phys_alloc(phys_addr_t size,
index ef55115..93d9ada 100644 (file)
@@ -58,13 +58,14 @@ enum {
 };
 
 /*
- * Restrictions for the memory hotplug:
- * flags:  MHP_ flags
- * altmap: alternative allocator for memmap array
+ * Extended parameters for memory hotplug:
+ * altmap: alternative allocator for memmap array (optional)
+ * pgprot: page protection flags to apply to newly created page tables
+ *     (required)
  */
-struct mhp_restrictions {
-       unsigned long flags;
+struct mhp_params {
        struct vmem_altmap *altmap;
+       pgprot_t pgprot;
 };
 
 /*
@@ -114,7 +115,7 @@ extern int restore_online_page_callback(online_page_callback_t callback);
 extern int try_online_node(int nid);
 
 extern int arch_add_memory(int nid, u64 start, u64 size,
-                       struct mhp_restrictions *restrictions);
+                          struct mhp_params *params);
 extern u64 max_mem_size;
 
 extern int memhp_online_type_from_str(const char *str);
@@ -135,17 +136,17 @@ extern void __remove_pages(unsigned long start_pfn, unsigned long nr_pages,
 
 /* reasonably generic interface to expand the physical pages */
 extern int __add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
-                      struct mhp_restrictions *restrictions);
+                      struct mhp_params *params);
 
 #ifndef CONFIG_ARCH_HAS_ADD_PAGES
 static inline int add_pages(int nid, unsigned long start_pfn,
-               unsigned long nr_pages, struct mhp_restrictions *restrictions)
+               unsigned long nr_pages, struct mhp_params *params)
 {
-       return __add_pages(nid, start_pfn, nr_pages, restrictions);
+       return __add_pages(nid, start_pfn, nr_pages, params);
 }
 #else /* ARCH_HAS_ADD_PAGES */
 int add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
-             struct mhp_restrictions *restrictions);
+             struct mhp_params *params);
 #endif /* ARCH_HAS_ADD_PAGES */
 
 #ifdef CONFIG_NUMA
index 8b37c4c..5f5b2df 100644 (file)
@@ -134,6 +134,7 @@ struct dev_pagemap *get_dev_pagemap(unsigned long pfn,
 
 unsigned long vmem_altmap_offset(struct vmem_altmap *altmap);
 void vmem_altmap_free(struct vmem_altmap *altmap, unsigned long nr_pfns);
+unsigned long memremap_compat_align(void);
 #else
 static inline void *devm_memremap_pages(struct device *dev,
                struct dev_pagemap *pgmap)
@@ -167,6 +168,12 @@ static inline void vmem_altmap_free(struct vmem_altmap *altmap,
                unsigned long nr_pfns)
 {
 }
+
+/* when memremap_pages() is disabled all archs can remap a single page */
+static inline unsigned long memremap_compat_align(void)
+{
+       return PAGE_SIZE;
+}
 #endif /* CONFIG_ZONE_DEVICE */
 
 static inline void put_dev_pagemap(struct dev_pagemap *pgmap)
@@ -174,4 +181,5 @@ static inline void put_dev_pagemap(struct dev_pagemap *pgmap)
        if (pgmap)
                percpu_ref_put(pgmap->ref);
 }
+
 #endif /* _LINUX_MEMREMAP_H_ */
diff --git a/include/linux/mfd/iqs62x.h b/include/linux/mfd/iqs62x.h
new file mode 100644 (file)
index 0000000..043d3b6
--- /dev/null
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Azoteq IQS620A/621/622/624/625 Multi-Function Sensors
+ *
+ * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
+ */
+
+#ifndef __LINUX_MFD_IQS62X_H
+#define __LINUX_MFD_IQS62X_H
+
+#define IQS620_PROD_NUM                                0x41
+#define IQS621_PROD_NUM                                0x46
+#define IQS622_PROD_NUM                                0x42
+#define IQS624_PROD_NUM                                0x43
+#define IQS625_PROD_NUM                                0x4E
+
+#define IQS621_ALS_FLAGS                       0x16
+#define IQS622_ALS_FLAGS                       0x14
+
+#define IQS624_HALL_UI                         0x70
+#define IQS624_HALL_UI_WHL_EVENT               BIT(4)
+#define IQS624_HALL_UI_INT_EVENT               BIT(3)
+#define IQS624_HALL_UI_AUTO_CAL                        BIT(2)
+
+#define IQS624_INTERVAL_DIV                    0x7D
+
+#define IQS620_GLBL_EVENT_MASK                 0xD7
+#define IQS620_GLBL_EVENT_MASK_PMU             BIT(6)
+
+#define IQS62X_NUM_KEYS                                16
+#define IQS62X_NUM_EVENTS                      (IQS62X_NUM_KEYS + 5)
+
+#define IQS62X_EVENT_SIZE                      10
+
+enum iqs62x_ui_sel {
+       IQS62X_UI_PROX,
+       IQS62X_UI_SAR1,
+};
+
+enum iqs62x_event_reg {
+       IQS62X_EVENT_NONE,
+       IQS62X_EVENT_SYS,
+       IQS62X_EVENT_PROX,
+       IQS62X_EVENT_HYST,
+       IQS62X_EVENT_HALL,
+       IQS62X_EVENT_ALS,
+       IQS62X_EVENT_IR,
+       IQS62X_EVENT_WHEEL,
+       IQS62X_EVENT_INTER,
+       IQS62X_EVENT_UI_LO,
+       IQS62X_EVENT_UI_HI,
+};
+
+enum iqs62x_event_flag {
+       /* keys */
+       IQS62X_EVENT_PROX_CH0_T,
+       IQS62X_EVENT_PROX_CH0_P,
+       IQS62X_EVENT_PROX_CH1_T,
+       IQS62X_EVENT_PROX_CH1_P,
+       IQS62X_EVENT_PROX_CH2_T,
+       IQS62X_EVENT_PROX_CH2_P,
+       IQS62X_EVENT_HYST_POS_T,
+       IQS62X_EVENT_HYST_POS_P,
+       IQS62X_EVENT_HYST_NEG_T,
+       IQS62X_EVENT_HYST_NEG_P,
+       IQS62X_EVENT_SAR1_ACT,
+       IQS62X_EVENT_SAR1_QRD,
+       IQS62X_EVENT_SAR1_MOVE,
+       IQS62X_EVENT_SAR1_HALT,
+       IQS62X_EVENT_WHEEL_UP,
+       IQS62X_EVENT_WHEEL_DN,
+
+       /* switches */
+       IQS62X_EVENT_HALL_N_T,
+       IQS62X_EVENT_HALL_N_P,
+       IQS62X_EVENT_HALL_S_T,
+       IQS62X_EVENT_HALL_S_P,
+
+       /* everything else */
+       IQS62X_EVENT_SYS_RESET,
+};
+
+struct iqs62x_event_data {
+       u16 ui_data;
+       u8 als_flags;
+       u8 ir_flags;
+       u8 interval;
+};
+
+struct iqs62x_event_desc {
+       enum iqs62x_event_reg reg;
+       u8 mask;
+       u8 val;
+};
+
+struct iqs62x_dev_desc {
+       const char *dev_name;
+       const struct mfd_cell *sub_devs;
+       int num_sub_devs;
+
+       u8 prod_num;
+       u8 sw_num;
+       const u8 *cal_regs;
+       int num_cal_regs;
+
+       u8 prox_mask;
+       u8 sar_mask;
+       u8 hall_mask;
+       u8 hyst_mask;
+       u8 temp_mask;
+       u8 als_mask;
+       u8 ir_mask;
+
+       u8 prox_settings;
+       u8 als_flags;
+       u8 hall_flags;
+       u8 hyst_shift;
+
+       u8 interval;
+       u8 interval_div;
+
+       u8 clk_div;
+       const char *fw_name;
+       const enum iqs62x_event_reg (*event_regs)[IQS62X_EVENT_SIZE];
+};
+
+struct iqs62x_core {
+       const struct iqs62x_dev_desc *dev_desc;
+       struct i2c_client *client;
+       struct regmap *regmap;
+       struct blocking_notifier_head nh;
+       struct list_head fw_blk_head;
+       struct completion fw_done;
+       enum iqs62x_ui_sel ui_sel;
+};
+
+extern const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS];
+
+#endif /* __LINUX_MFD_IQS62X_H */
index a59bf32..e07f6e6 100644 (file)
@@ -620,7 +620,5 @@ struct rk808 {
        long                            variant;
        const struct regmap_config      *regmap_cfg;
        const struct regmap_irq_chip    *regmap_irq_chip;
-       void                            (*pm_pwroff_fn)(void);
-       void                            (*pm_pwroff_prep_fn)(void);
 };
 #endif /* __LINUX_REGULATOR_RK808_H */
index d62ef48..fba0df1 100644 (file)
 #define RN5T618_INTPOL                 0x9c
 #define RN5T618_INTEN                  0x9d
 #define RN5T618_INTMON                 0x9e
+
+#define RN5T618_RTC_SECONDS     0xA0
+#define RN5T618_RTC_MDAY        0xA4
+#define RN5T618_RTC_MONTH       0xA5
+#define RN5T618_RTC_YEAR        0xA6
+#define RN5T618_RTC_ADJUST      0xA7
+#define RN5T618_RTC_ALARM_Y_SEC 0xA8
+#define RN5T618_RTC_DAL_MONTH   0xAC
+#define RN5T618_RTC_CTRL1       0xAE
+#define RN5T618_RTC_CTRL2       0xAF
+
 #define RN5T618_PREVINDAC              0xb0
 #define RN5T618_BATDAC                 0xb1
 #define RN5T618_CHGCTL1                        0xb3
@@ -242,9 +253,24 @@ enum {
        RC5T619,
 };
 
+/* RN5T618 IRQ definitions */
+enum {
+       RN5T618_IRQ_SYS = 0,
+       RN5T618_IRQ_DCDC,
+       RN5T618_IRQ_RTC,
+       RN5T618_IRQ_ADC,
+       RN5T618_IRQ_GPIO,
+       RN5T618_IRQ_CHG,
+       RN5T618_NR_IRQS,
+};
+
 struct rn5t618 {
        struct regmap *regmap;
+       struct device *dev;
        long variant;
+
+       int irq;
+       struct regmap_irq_chip_data *irq_data;
 };
 
 #endif /* __LINUX_MFD_RN5T618_H */
diff --git a/include/linux/mfd/sc27xx-pmic.h b/include/linux/mfd/sc27xx-pmic.h
new file mode 100644 (file)
index 0000000..57e45c0
--- /dev/null
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_MFD_SC27XX_PMIC_H
+#define __LINUX_MFD_SC27XX_PMIC_H
+
+extern enum usb_charger_type sprd_pmic_detect_charger_type(struct device *dev);
+
+#endif /* __LINUX_MFD_SC27XX_PMIC_H */
index 986986f..75aa94d 100644 (file)
@@ -89,7 +89,6 @@ enum wm831x_watchdog_action {
 
 struct wm831x_watchdog_pdata {
        enum wm831x_watchdog_action primary, secondary;
-       int update_gpio;
        unsigned int software:1;
 };
 
index e2f938c..5a32342 100644 (file)
@@ -343,6 +343,20 @@ extern unsigned int kobjsize(const void *objp);
 /* Bits set in the VMA until the stack is in its final location */
 #define VM_STACK_INCOMPLETE_SETUP      (VM_RAND_READ | VM_SEQ_READ)
 
+#define TASK_EXEC ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0)
+
+/* Common data flag combinations */
+#define VM_DATA_FLAGS_TSK_EXEC (VM_READ | VM_WRITE | TASK_EXEC | \
+                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_FLAGS_NON_EXEC (VM_READ | VM_WRITE | VM_MAYREAD | \
+                                VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_FLAGS_EXEC     (VM_READ | VM_WRITE | VM_EXEC | \
+                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#ifndef VM_DATA_DEFAULT_FLAGS          /* arch can override this */
+#define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_EXEC
+#endif
+
 #ifndef VM_STACK_DEFAULT_FLAGS         /* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
 #endif
@@ -355,6 +369,10 @@ extern unsigned int kobjsize(const void *objp);
 
 #define VM_STACK_FLAGS (VM_STACK | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT)
 
+/* VMA basic access permission flags */
+#define VM_ACCESS_FLAGS (VM_READ | VM_WRITE | VM_EXEC)
+
+
 /*
  * Special vmas that are non-mergable, non-mlock()able.
  */
@@ -632,7 +650,7 @@ static inline bool vma_is_foreign(struct vm_area_struct *vma)
 
 static inline bool vma_is_accessible(struct vm_area_struct *vma)
 {
-       return vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC);
+       return vma->vm_flags & VM_ACCESS_FLAGS;
 }
 
 #ifdef CONFIG_SHMEM
@@ -1909,6 +1927,18 @@ static inline void sync_mm_rss(struct mm_struct *mm)
 }
 #endif
 
+#ifndef CONFIG_ARCH_HAS_PTE_SPECIAL
+static inline int pte_special(pte_t pte)
+{
+       return 0;
+}
+
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+       return pte;
+}
+#endif
+
 #ifndef CONFIG_ARCH_HAS_PTE_DEVMAP
 static inline int pte_devmap(pte_t pte)
 {
@@ -2689,6 +2719,8 @@ struct vm_area_struct *find_extend_vma(struct mm_struct *, unsigned long addr);
 int remap_pfn_range(struct vm_area_struct *, unsigned long addr,
                        unsigned long pfn, unsigned long size, pgprot_t);
 int vm_insert_page(struct vm_area_struct *, unsigned long addr, struct page *);
+int vm_insert_pages(struct vm_area_struct *vma, unsigned long addr,
+                       struct page **pages, unsigned long *num);
 int vm_map_pages(struct vm_area_struct *vma, struct page **pages,
                                unsigned long num);
 int vm_map_pages_zero(struct vm_area_struct *vma, struct page **pages,
index e9892bf..1b9de7d 100644 (file)
@@ -1127,6 +1127,7 @@ static inline unsigned long section_nr_to_pfn(unsigned long sec)
 #define SECTION_ALIGN_DOWN(pfn)        ((pfn) & PAGE_SECTION_MASK)
 
 #define SUBSECTION_SHIFT 21
+#define SUBSECTION_SIZE (1UL << SUBSECTION_SHIFT)
 
 #define PFN_SUBSECTION_SHIFT (SUBSECTION_SHIFT - PAGE_SHIFT)
 #define PAGES_PER_SUBSECTION (1UL << PFN_SUBSECTION_SHIFT)
index 110b0e5..a42df80 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #ifndef _LINUX_NUMA_H
 #define _LINUX_NUMA_H
-
+#include <linux/types.h>
 
 #ifdef CONFIG_NODES_SHIFT
 #define NODES_SHIFT     CONFIG_NODES_SHIFT
 
 #define        NUMA_NO_NODE    (-1)
 
+/* optionally keep NUMA memory info available post init */
+#ifdef CONFIG_NUMA_KEEP_MEMINFO
+#define __initdata_or_meminfo
+#else
+#define __initdata_or_meminfo __initdata
+#endif
+
+#ifdef CONFIG_NUMA
+/* Generic implementation available */
+int numa_map_to_online_node(int node);
+
+/*
+ * Optional architecture specific implementation, users need a "depends
+ * on $ARCH"
+ */
+int phys_to_target_node(phys_addr_t addr);
+#else
+static inline int numa_map_to_online_node(int node)
+{
+       return NUMA_NO_NODE;
+}
+
+static inline int phys_to_target_node(phys_addr_t addr)
+{
+       return NUMA_NO_NODE;
+}
+#endif
+
 #endif /* _LINUX_NUMA_H */
index 6d0d70f..10f8162 100644 (file)
@@ -270,8 +270,6 @@ struct nvme_fc_remote_port {
  *
  * Host/Initiator Transport Entrypoints/Parameters:
  *
- * @module:  The LLDD module using the interface
- *
  * @localport_delete:  The LLDD initiates deletion of a localport via
  *       nvme_fc_deregister_localport(). However, the teardown is
  *       asynchronous. This routine is called upon the completion of the
@@ -385,8 +383,6 @@ struct nvme_fc_remote_port {
  *       Value is Mandatory. Allowed to be zero.
  */
 struct nvme_fc_port_template {
-       struct module   *module;
-
        /* initiator-based functions */
        void    (*localport_delete)(struct nvme_fc_local_port *);
        void    (*remoteport_delete)(struct nvme_fc_remote_port *);
index 01a0d4e..cc896f0 100644 (file)
@@ -60,6 +60,7 @@ struct pid
 {
        refcount_t count;
        unsigned int level;
+       spinlock_t lock;
        /* lists of tasks that use this pid */
        struct hlist_head tasks[PIDTYPE_MAX];
        struct hlist_head inodes;
index ba59147..3832433 100644 (file)
@@ -125,6 +125,9 @@ struct cros_ec_command {
  * @host_event_wake_mask: Mask of host events that cause wake from suspend.
  * @last_event_time: exact time from the hard irq when we got notified of
  *     a new event.
+ * @notifier_ready: The notifier_block to let the kernel re-query EC
+ *                 communication protocol when the EC sends
+ *                 EC_HOST_EVENT_INTERFACE_READY.
  * @ec: The platform_device used by the mfd driver to interface with the
  *      main EC.
  * @pd: The platform_device used by the mfd driver to interface with the
@@ -166,6 +169,7 @@ struct cros_ec_device {
        u32 host_event_wake_mask;
        u32 last_resume_result;
        ktime_t last_event_time;
+       struct notifier_block notifier_ready;
 
        /* The platform devices used by the mfd driver */
        struct platform_device *ec;
index bef7ffc..c588be8 100644 (file)
@@ -8,8 +8,13 @@
 #ifndef __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H
 #define __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H
 
+#include <linux/ktime.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
 #include <linux/platform_data/cros_ec_commands.h>
 
+struct iio_dev;
+
 /**
  * struct cros_ec_sensor_platform - ChromeOS EC sensor platform information.
  * @sensor_num: Id of the sensor, as reported by the EC.
@@ -19,12 +24,170 @@ struct cros_ec_sensor_platform {
 };
 
 /**
+ * typedef cros_ec_sensorhub_push_data_cb_t - Callback function to send datum
+ *                                           to specific sensors.
+ *
+ * @indio_dev: The IIO device that will process the sample.
+ * @data: Vector array of the ring sample.
+ * @timestamp: Timestamp in host timespace when the sample was acquired by
+ *             the EC.
+ */
+typedef int (*cros_ec_sensorhub_push_data_cb_t)(struct iio_dev *indio_dev,
+                                               s16 *data,
+                                               s64 timestamp);
+
+struct cros_ec_sensorhub_sensor_push_data {
+       struct iio_dev *indio_dev;
+       cros_ec_sensorhub_push_data_cb_t push_data_cb;
+};
+
+enum {
+       CROS_EC_SENSOR_LAST_TS,
+       CROS_EC_SENSOR_NEW_TS,
+       CROS_EC_SENSOR_ALL_TS
+};
+
+struct cros_ec_sensors_ring_sample {
+       u8  sensor_id;
+       u8  flag;
+       s16 vector[3];
+       s64 timestamp;
+} __packed;
+
+/* State used for cros_ec_ring_fix_overflow */
+struct cros_ec_sensors_ec_overflow_state {
+       s64 offset;
+       s64 last;
+};
+
+/* Length of the filter, how long to remember entries for */
+#define CROS_EC_SENSORHUB_TS_HISTORY_SIZE 64
+
+/**
+ * struct cros_ec_sensors_ts_filter_state - Timestamp filetr state.
+ *
+ * @x_offset: x is EC interrupt time. x_offset its last value.
+ * @y_offset: y is the difference between AP and EC time, y_offset its last
+ *            value.
+ * @x_history: The past history of x, relative to x_offset.
+ * @y_history: The past history of y, relative to y_offset.
+ * @m_history: rate between y and x.
+ * @history_len: Amount of valid historic data in the arrays.
+ * @temp_buf: Temporary buffer used when updating the filter.
+ * @median_m: median value of m_history
+ * @median_error: final error to apply to AP interrupt timestamp to get the
+ *                "true timestamp" the event occurred.
+ */
+struct cros_ec_sensors_ts_filter_state {
+       s64 x_offset, y_offset;
+       s64 x_history[CROS_EC_SENSORHUB_TS_HISTORY_SIZE];
+       s64 y_history[CROS_EC_SENSORHUB_TS_HISTORY_SIZE];
+       s64 m_history[CROS_EC_SENSORHUB_TS_HISTORY_SIZE];
+       int history_len;
+
+       s64 temp_buf[CROS_EC_SENSORHUB_TS_HISTORY_SIZE];
+
+       s64 median_m;
+       s64 median_error;
+};
+
+/* struct cros_ec_sensors_ts_batch_state - State of batch of a single sensor.
+ *
+ * Use to store information to batch data using median fileter information.
+ *
+ * @penul_ts: last but one batch timestamp (penultimate timestamp).
+ *           Used for timestamp spreading calculations
+ *           when a batch shows up.
+ * @penul_len: last but one batch length.
+ * @last_ts: Last batch timestam.
+ * @last_len: Last batch length.
+ * @newest_sensor_event: Last sensor timestamp.
+ */
+struct cros_ec_sensors_ts_batch_state {
+       s64 penul_ts;
+       int penul_len;
+       s64 last_ts;
+       int last_len;
+       s64 newest_sensor_event;
+};
+
+/*
  * struct cros_ec_sensorhub - Sensor Hub device data.
  *
+ * @dev: Device object, mostly used for logging.
  * @ec: Embedded Controller where the hub is located.
+ * @sensor_num: Number of MEMS sensors present in the EC.
+ * @msg: Structure to send FIFO requests.
+ * @params: Pointer to parameters in msg.
+ * @resp: Pointer to responses in msg.
+ * @cmd_lock : Lock for sending msg.
+ * @notifier: Notifier to kick the FIFO interrupt.
+ * @ring: Preprocessed ring to store events.
+ * @fifo_timestamp: Array for event timestamp and spreading.
+ * @fifo_info: Copy of FIFO information coming from the EC.
+ * @fifo_size: Size of the ring.
+ * @batch_state: Per sensor information of the last batches received.
+ * @overflow_a: For handling timestamp overflow for a time (sensor events)
+ * @overflow_b: For handling timestamp overflow for b time (ec interrupts)
+ * @filter: Medium fileter structure.
+ * @tight_timestamps: Set to truen when EC support tight timestamping:
+ *                   The timestamps reported from the EC have low jitter.
+ *                   Timestamps also come before every sample. Set either
+ *                   by feature bits coming from the EC or userspace.
+ * @future_timestamp_count: Statistics used to compute shaved time.
+ *                         This occurs when timestamp interpolation from EC
+ *                         time to AP time accidentally puts timestamps in
+ *                         the future. These timestamps are clamped to
+ *                         `now` and these count/total_ns maintain the
+ *                         statistics for how much time was removed in a
+ *                         given period.
+ * @future_timestamp_total_ns: Total amount of time shaved.
+ * @push_data: Array of callback to send datums to iio sensor object.
  */
 struct cros_ec_sensorhub {
+       struct device *dev;
        struct cros_ec_dev *ec;
+       int sensor_num;
+
+       struct cros_ec_command *msg;
+       struct ec_params_motion_sense *params;
+       struct ec_response_motion_sense *resp;
+       struct mutex cmd_lock;  /* Lock for protecting msg structure. */
+
+       struct notifier_block notifier;
+
+       struct cros_ec_sensors_ring_sample *ring;
+
+       ktime_t fifo_timestamp[CROS_EC_SENSOR_ALL_TS];
+       struct ec_response_motion_sense_fifo_info *fifo_info;
+       int fifo_size;
+
+       struct cros_ec_sensors_ts_batch_state *batch_state;
+
+       struct cros_ec_sensors_ec_overflow_state overflow_a;
+       struct cros_ec_sensors_ec_overflow_state overflow_b;
+
+       struct cros_ec_sensors_ts_filter_state filter;
+
+       int tight_timestamps;
+
+       s32 future_timestamp_count;
+       s64 future_timestamp_total_ns;
+
+       struct cros_ec_sensorhub_sensor_push_data *push_data;
 };
 
+int cros_ec_sensorhub_register_push_data(struct cros_ec_sensorhub *sensorhub,
+                                        u8 sensor_num,
+                                        struct iio_dev *indio_dev,
+                                        cros_ec_sensorhub_push_data_cb_t cb);
+
+void cros_ec_sensorhub_unregister_push_data(struct cros_ec_sensorhub *sensorhub,
+                                           u8 sensor_num);
+
+int cros_ec_sensorhub_ring_add(struct cros_ec_sensorhub *sensorhub);
+void cros_ec_sensorhub_ring_remove(void *arg);
+int cros_ec_sensorhub_ring_fifo_enable(struct cros_ec_sensorhub *sensorhub,
+                                      bool on);
+
 #endif   /* __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H */
diff --git a/include/linux/platform_data/cros_usbpd_notify.h b/include/linux/platform_data/cros_usbpd_notify.h
new file mode 100644 (file)
index 0000000..4f27917
--- /dev/null
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ChromeOS EC Power Delivery Notifier Driver
+ *
+ * Copyright 2020 Google LLC
+ */
+
+#ifndef __LINUX_PLATFORM_DATA_CROS_USBPD_NOTIFY_H
+#define __LINUX_PLATFORM_DATA_CROS_USBPD_NOTIFY_H
+
+#include <linux/notifier.h>
+
+int cros_usbpd_register_notify(struct notifier_block *nb);
+
+void cros_usbpd_unregister_notify(struct notifier_block *nb);
+
+#endif  /* __LINUX_PLATFORM_DATA_CROS_USBPD_NOTIFY_H */
diff --git a/include/linux/platform_data/leds-kirkwood-ns2.h b/include/linux/platform_data/leds-kirkwood-ns2.h
deleted file mode 100644 (file)
index eb8a686..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Platform data structure for Network Space v2 LED driver
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __LEDS_KIRKWOOD_NS2_H
-#define __LEDS_KIRKWOOD_NS2_H
-
-enum ns2_led_modes {
-       NS_V2_LED_OFF,
-       NS_V2_LED_ON,
-       NS_V2_LED_SATA,
-};
-
-struct ns2_led_modval {
-       enum ns2_led_modes      mode;
-       int                     cmd_level;
-       int                     slow_level;
-};
-
-struct ns2_led {
-       const char      *name;
-       const char      *default_trigger;
-       unsigned        cmd;
-       unsigned        slow;
-       int             num_modes;
-       struct ns2_led_modval *modval;
-};
-
-struct ns2_led_platform_data {
-       int             num_leds;
-       struct ns2_led  *leds;
-};
-
-#endif /* __LEDS_KIRKWOOD_NS2_H */
diff --git a/include/linux/platform_data/pwm_omap_dmtimer.h b/include/linux/platform_data/pwm_omap_dmtimer.h
deleted file mode 100644 (file)
index e7d521e..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * include/linux/platform_data/pwm_omap_dmtimer.h
- *
- * OMAP Dual-Mode Timer PWM platform data
- *
- * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
- * Tarun Kanti DebBarma <tarun.kanti@ti.com>
- * Thara Gopinath <thara@ti.com>
- *
- * Platform device conversion and hwmod support.
- *
- * Copyright (C) 2005 Nokia Corporation
- * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
- * PWM and clock framework support by Timo Teras.
- *
- * This program 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; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __PWM_OMAP_DMTIMER_PDATA_H
-#define __PWM_OMAP_DMTIMER_PDATA_H
-
-/* clock sources */
-#define PWM_OMAP_DMTIMER_SRC_SYS_CLK                   0x00
-#define PWM_OMAP_DMTIMER_SRC_32_KHZ                    0x01
-#define PWM_OMAP_DMTIMER_SRC_EXT_CLK                   0x02
-
-/* timer interrupt enable bits */
-#define PWM_OMAP_DMTIMER_INT_CAPTURE                   (1 << 2)
-#define PWM_OMAP_DMTIMER_INT_OVERFLOW                  (1 << 1)
-#define PWM_OMAP_DMTIMER_INT_MATCH                     (1 << 0)
-
-/* trigger types */
-#define PWM_OMAP_DMTIMER_TRIGGER_NONE                  0x00
-#define PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW              0x01
-#define PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE  0x02
-
-struct omap_dm_timer;
-typedef struct omap_dm_timer pwm_omap_dmtimer;
-
-struct pwm_omap_dmtimer_pdata {
-       pwm_omap_dmtimer *(*request_by_node)(struct device_node *np);
-       pwm_omap_dmtimer *(*request_specific)(int timer_id);
-       pwm_omap_dmtimer *(*request)(void);
-
-       int     (*free)(pwm_omap_dmtimer *timer);
-
-       void    (*enable)(pwm_omap_dmtimer *timer);
-       void    (*disable)(pwm_omap_dmtimer *timer);
-
-       int     (*get_irq)(pwm_omap_dmtimer *timer);
-       int     (*set_int_enable)(pwm_omap_dmtimer *timer, unsigned int value);
-       int     (*set_int_disable)(pwm_omap_dmtimer *timer, u32 mask);
-
-       struct clk *(*get_fclk)(pwm_omap_dmtimer *timer);
-
-       int     (*start)(pwm_omap_dmtimer *timer);
-       int     (*stop)(pwm_omap_dmtimer *timer);
-       int     (*set_source)(pwm_omap_dmtimer *timer, int source);
-
-       int     (*set_load)(pwm_omap_dmtimer *timer, int autoreload,
-                       unsigned int value);
-       int     (*set_match)(pwm_omap_dmtimer *timer, int enable,
-                       unsigned int match);
-       int     (*set_pwm)(pwm_omap_dmtimer *timer, int def_on,
-                       int toggle, int trigger);
-       int     (*set_prescaler)(pwm_omap_dmtimer *timer, int prescaler);
-
-       unsigned int (*read_counter)(pwm_omap_dmtimer *timer);
-       int     (*write_counter)(pwm_omap_dmtimer *timer, unsigned int value);
-       unsigned int (*read_status)(pwm_omap_dmtimer *timer);
-       int     (*write_status)(pwm_omap_dmtimer *timer, unsigned int value);
-};
-
-#endif /* __PWM_OMAP_DMTIMER_PDATA_H */
index afede15..25f46a9 100644 (file)
@@ -8,8 +8,8 @@
 #ifndef WILCO_EC_H
 #define WILCO_EC_H
 
-#include <linux/device.h>
-#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
 
 /* Message flags for using the mailbox() interface */
 #define WILCO_EC_FLAG_NO_RESPONSE      BIT(0) /* EC does not respond */
 /* Normal commands have a maximum 32 bytes of data */
 #define EC_MAILBOX_DATA_SIZE           32
 
+struct device;
+struct resource;
+struct platform_device;
+
 /**
  * struct wilco_ec_device - Wilco Embedded Controller handle.
  * @dev: Device handle.
index 7a91b35..4ca0832 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * bq2415x charger driver
  *
- * Copyright (C) 2011-2013  Pali Rohár <pali.rohar@gmail.com>
+ * Copyright (C) 2011-2013  Pali Rohár <pali@kernel.org>
  */
 
 #ifndef BQ2415X_CHARGER_H
index 1e6108b..e061635 100644 (file)
@@ -202,7 +202,6 @@ __printf(1, 2) void dump_stack_set_arch_desc(const char *fmt, ...);
 void dump_stack_print_info(const char *log_lvl);
 void show_regs_print_info(const char *log_lvl);
 extern asmlinkage void dump_stack(void) __cold;
-extern void printk_safe_init(void);
 extern void printk_safe_flush(void);
 extern void printk_safe_flush_on_panic(void);
 #else
@@ -269,10 +268,6 @@ static inline void dump_stack(void)
 {
 }
 
-static inline void printk_safe_init(void)
-{
-}
-
 static inline void printk_safe_flush(void)
 {
 }
index 0ef808d..2635b2a 100644 (file)
@@ -71,7 +71,8 @@ struct pwm_state {
  * @chip: PWM chip providing this PWM device
  * @chip_data: chip-private data associated with the PWM device
  * @args: PWM arguments
- * @state: curent PWM channel state
+ * @state: last applied state
+ * @last: last implemented state (for PWM_DEBUG)
  */
 struct pwm_device {
        const char *label;
@@ -83,6 +84,7 @@ struct pwm_device {
 
        struct pwm_args args;
        struct pwm_state state;
+       struct pwm_state last;
 };
 
 /**
index 8ea265a..06086cb 100644 (file)
@@ -16,8 +16,6 @@ struct platform_pwm_backlight_data {
        unsigned int *levels;
        unsigned int post_pwm_on_delay;
        unsigned int pwm_off_delay;
-       /* TODO remove once all users are switched to gpiod_* API */
-       int enable_gpio;
        int (*init)(struct device *dev);
        int (*notify)(struct device *dev, int brightness);
        void (*notify_after)(struct device *dev, int brightness);
index 0ac50cf..0e3ee25 100644 (file)
  * atomic operations, then the count will continue to edge closer to 0. If it
  * reaches a value of 1 before /any/ of the threads reset it to the saturated
  * value, then a concurrent refcount_dec_and_test() may erroneously free the
- * underlying object. Given the precise timing details involved with the
- * round-robin scheduling of each thread manipulating the refcount and the need
- * to hit the race multiple times in succession, there doesn't appear to be a
- * practical avenue of attack even if using refcount_add() operations with
- * larger increments.
+ * underlying object.
+ * Linux limits the maximum number of tasks to PID_MAX_LIMIT, which is currently
+ * 0x400000 (and can't easily be raised in the future beyond FUTEX_TID_MASK).
+ * With the current PID limit, if no batched refcounting operations are used and
+ * the attacker can't repeatedly trigger kernel oopses in the middle of refcount
+ * operations, this makes it impossible for a saturated refcount to leave the
+ * saturation range, even if it is possible for multiple uses of the same
+ * refcount to nest in the context of a single task:
+ *
+ *     (UINT_MAX+1-REFCOUNT_SATURATED) / PID_MAX_LIMIT =
+ *     0x40000000 / 0x400000 = 0x100 = 256
+ *
+ * If hundreds of references are added/removed with a single refcounting
+ * operation, it may potentially be possible to leave the saturation range; but
+ * given the precise timing details involved with the round-robin scheduling of
+ * each thread manipulating the refcount and the need to hit the race multiple
+ * times in succession, there doesn't appear to be a practical avenue of attack
+ * even if using refcount_add() operations with larger increments.
  *
  * Memory ordering
  * ===============
index 03a3893..6d45488 100644 (file)
@@ -501,7 +501,7 @@ static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
  * :ref:`Documentation/core-api/mm-api.rst <mm-api-gfp-flags>`
  *
  * The recommended usage of the @flags is described at
- * :ref:`Documentation/core-api/memory-allocation.rst <memory-allocation>`
+ * :ref:`Documentation/core-api/memory-allocation.rst <memory_allocation>`
  *
  * Below is a brief outline of the most useful GFP flags
  *
index edf4bec..0b85761 100644 (file)
@@ -11,9 +11,6 @@ struct corgi_lcd_platform_data {
        int     default_intensity;
        int     limit_mask;
 
-       int     gpio_backlight_on;      /* -1 if n/a */
-       int     gpio_backlight_cont;    /* -1 if n/a */
-
        void (*notify)(int intensity);
        void (*kick_battery)(void);
 };
index 126913c..c91b1e3 100644 (file)
@@ -364,6 +364,9 @@ struct thermal_trip {
 
 /* Function declarations */
 #ifdef CONFIG_THERMAL_OF
+int thermal_zone_of_get_sensor_id(struct device_node *tz_np,
+                                 struct device_node *sensor_np,
+                                 u32 *id);
 struct thermal_zone_device *
 thermal_zone_of_sensor_register(struct device *dev, int id, void *data,
                                const struct thermal_zone_of_device_ops *ops);
@@ -375,6 +378,13 @@ struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
 void devm_thermal_zone_of_sensor_unregister(struct device *dev,
                                            struct thermal_zone_device *tz);
 #else
+
+static inline int thermal_zone_of_get_sensor_id(struct device_node *tz_np,
+                                        struct device_node *sensor_np,
+                                        u32 *id)
+{
+       return -ENOENT;
+}
 static inline struct thermal_zone_device *
 thermal_zone_of_sensor_register(struct device *dev, int id, void *data,
                                const struct thermal_zone_of_device_ops *ops)
diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h
new file mode 100644 (file)
index 0000000..733acfb
--- /dev/null
@@ -0,0 +1,253 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_VDPA_H
+#define _LINUX_VDPA_H
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/vhost_iotlb.h>
+
+/**
+ * vDPA callback definition.
+ * @callback: interrupt callback function
+ * @private: the data passed to the callback function
+ */
+struct vdpa_callback {
+       irqreturn_t (*callback)(void *data);
+       void *private;
+};
+
+/**
+ * vDPA device - representation of a vDPA device
+ * @dev: underlying device
+ * @dma_dev: the actual device that is performing DMA
+ * @config: the configuration ops for this device.
+ * @index: device index
+ */
+struct vdpa_device {
+       struct device dev;
+       struct device *dma_dev;
+       const struct vdpa_config_ops *config;
+       unsigned int index;
+};
+
+/**
+ * vDPA_config_ops - operations for configuring a vDPA device.
+ * Note: vDPA device drivers are required to implement all of the
+ * operations unless it is mentioned to be optional in the following
+ * list.
+ *
+ * @set_vq_address:            Set the address of virtqueue
+ *                             @vdev: vdpa device
+ *                             @idx: virtqueue index
+ *                             @desc_area: address of desc area
+ *                             @driver_area: address of driver area
+ *                             @device_area: address of device area
+ *                             Returns integer: success (0) or error (< 0)
+ * @set_vq_num:                        Set the size of virtqueue
+ *                             @vdev: vdpa device
+ *                             @idx: virtqueue index
+ *                             @num: the size of virtqueue
+ * @kick_vq:                   Kick the virtqueue
+ *                             @vdev: vdpa device
+ *                             @idx: virtqueue index
+ * @set_vq_cb:                 Set the interrupt callback function for
+ *                             a virtqueue
+ *                             @vdev: vdpa device
+ *                             @idx: virtqueue index
+ *                             @cb: virtio-vdev interrupt callback structure
+ * @set_vq_ready:              Set ready status for a virtqueue
+ *                             @vdev: vdpa device
+ *                             @idx: virtqueue index
+ *                             @ready: ready (true) not ready(false)
+ * @get_vq_ready:              Get ready status for a virtqueue
+ *                             @vdev: vdpa device
+ *                             @idx: virtqueue index
+ *                             Returns boolean: ready (true) or not (false)
+ * @set_vq_state:              Set the state for a virtqueue
+ *                             @vdev: vdpa device
+ *                             @idx: virtqueue index
+ *                             @state: virtqueue state (last_avail_idx)
+ *                             Returns integer: success (0) or error (< 0)
+ * @get_vq_state:              Get the state for a virtqueue
+ *                             @vdev: vdpa device
+ *                             @idx: virtqueue index
+ *                             Returns virtqueue state (last_avail_idx)
+ * @get_vq_align:              Get the virtqueue align requirement
+ *                             for the device
+ *                             @vdev: vdpa device
+ *                             Returns virtqueue algin requirement
+ * @get_features:              Get virtio features supported by the device
+ *                             @vdev: vdpa device
+ *                             Returns the virtio features support by the
+ *                             device
+ * @set_features:              Set virtio features supported by the driver
+ *                             @vdev: vdpa device
+ *                             @features: feature support by the driver
+ *                             Returns integer: success (0) or error (< 0)
+ * @set_config_cb:             Set the config interrupt callback
+ *                             @vdev: vdpa device
+ *                             @cb: virtio-vdev interrupt callback structure
+ * @get_vq_num_max:            Get the max size of virtqueue
+ *                             @vdev: vdpa device
+ *                             Returns u16: max size of virtqueue
+ * @get_device_id:             Get virtio device id
+ *                             @vdev: vdpa device
+ *                             Returns u32: virtio device id
+ * @get_vendor_id:             Get id for the vendor that provides this device
+ *                             @vdev: vdpa device
+ *                             Returns u32: virtio vendor id
+ * @get_status:                        Get the device status
+ *                             @vdev: vdpa device
+ *                             Returns u8: virtio device status
+ * @set_status:                        Set the device status
+ *                             @vdev: vdpa device
+ *                             @status: virtio device status
+ * @get_config:                        Read from device specific configuration space
+ *                             @vdev: vdpa device
+ *                             @offset: offset from the beginning of
+ *                             configuration space
+ *                             @buf: buffer used to read to
+ *                             @len: the length to read from
+ *                             configuration space
+ * @set_config:                        Write to device specific configuration space
+ *                             @vdev: vdpa device
+ *                             @offset: offset from the beginning of
+ *                             configuration space
+ *                             @buf: buffer used to write from
+ *                             @len: the length to write to
+ *                             configuration space
+ * @get_generation:            Get device config generation (optional)
+ *                             @vdev: vdpa device
+ *                             Returns u32: device generation
+ * @set_map:                   Set device memory mapping (optional)
+ *                             Needed for device that using device
+ *                             specific DMA translation (on-chip IOMMU)
+ *                             @vdev: vdpa device
+ *                             @iotlb: vhost memory mapping to be
+ *                             used by the vDPA
+ *                             Returns integer: success (0) or error (< 0)
+ * @dma_map:                   Map an area of PA to IOVA (optional)
+ *                             Needed for device that using device
+ *                             specific DMA translation (on-chip IOMMU)
+ *                             and preferring incremental map.
+ *                             @vdev: vdpa device
+ *                             @iova: iova to be mapped
+ *                             @size: size of the area
+ *                             @pa: physical address for the map
+ *                             @perm: device access permission (VHOST_MAP_XX)
+ *                             Returns integer: success (0) or error (< 0)
+ * @dma_unmap:                 Unmap an area of IOVA (optional but
+ *                             must be implemented with dma_map)
+ *                             Needed for device that using device
+ *                             specific DMA translation (on-chip IOMMU)
+ *                             and preferring incremental unmap.
+ *                             @vdev: vdpa device
+ *                             @iova: iova to be unmapped
+ *                             @size: size of the area
+ *                             Returns integer: success (0) or error (< 0)
+ * @free:                      Free resources that belongs to vDPA (optional)
+ *                             @vdev: vdpa device
+ */
+struct vdpa_config_ops {
+       /* Virtqueue ops */
+       int (*set_vq_address)(struct vdpa_device *vdev,
+                             u16 idx, u64 desc_area, u64 driver_area,
+                             u64 device_area);
+       void (*set_vq_num)(struct vdpa_device *vdev, u16 idx, u32 num);
+       void (*kick_vq)(struct vdpa_device *vdev, u16 idx);
+       void (*set_vq_cb)(struct vdpa_device *vdev, u16 idx,
+                         struct vdpa_callback *cb);
+       void (*set_vq_ready)(struct vdpa_device *vdev, u16 idx, bool ready);
+       bool (*get_vq_ready)(struct vdpa_device *vdev, u16 idx);
+       int (*set_vq_state)(struct vdpa_device *vdev, u16 idx, u64 state);
+       u64 (*get_vq_state)(struct vdpa_device *vdev, u16 idx);
+
+       /* Device ops */
+       u16 (*get_vq_align)(struct vdpa_device *vdev);
+       u64 (*get_features)(struct vdpa_device *vdev);
+       int (*set_features)(struct vdpa_device *vdev, u64 features);
+       void (*set_config_cb)(struct vdpa_device *vdev,
+                             struct vdpa_callback *cb);
+       u16 (*get_vq_num_max)(struct vdpa_device *vdev);
+       u32 (*get_device_id)(struct vdpa_device *vdev);
+       u32 (*get_vendor_id)(struct vdpa_device *vdev);
+       u8 (*get_status)(struct vdpa_device *vdev);
+       void (*set_status)(struct vdpa_device *vdev, u8 status);
+       void (*get_config)(struct vdpa_device *vdev, unsigned int offset,
+                          void *buf, unsigned int len);
+       void (*set_config)(struct vdpa_device *vdev, unsigned int offset,
+                          const void *buf, unsigned int len);
+       u32 (*get_generation)(struct vdpa_device *vdev);
+
+       /* DMA ops */
+       int (*set_map)(struct vdpa_device *vdev, struct vhost_iotlb *iotlb);
+       int (*dma_map)(struct vdpa_device *vdev, u64 iova, u64 size,
+                      u64 pa, u32 perm);
+       int (*dma_unmap)(struct vdpa_device *vdev, u64 iova, u64 size);
+
+       /* Free device resources */
+       void (*free)(struct vdpa_device *vdev);
+};
+
+struct vdpa_device *__vdpa_alloc_device(struct device *parent,
+                                       const struct vdpa_config_ops *config,
+                                       size_t size);
+
+#define vdpa_alloc_device(dev_struct, member, parent, config)   \
+                         container_of(__vdpa_alloc_device( \
+                                      parent, config, \
+                                      sizeof(dev_struct) + \
+                                      BUILD_BUG_ON_ZERO(offsetof( \
+                                      dev_struct, member))), \
+                                      dev_struct, member)
+
+int vdpa_register_device(struct vdpa_device *vdev);
+void vdpa_unregister_device(struct vdpa_device *vdev);
+
+/**
+ * vdpa_driver - operations for a vDPA driver
+ * @driver: underlying device driver
+ * @probe: the function to call when a device is found.  Returns 0 or -errno.
+ * @remove: the function to call when a device is removed.
+ */
+struct vdpa_driver {
+       struct device_driver driver;
+       int (*probe)(struct vdpa_device *vdev);
+       void (*remove)(struct vdpa_device *vdev);
+};
+
+#define vdpa_register_driver(drv) \
+       __vdpa_register_driver(drv, THIS_MODULE)
+int __vdpa_register_driver(struct vdpa_driver *drv, struct module *owner);
+void vdpa_unregister_driver(struct vdpa_driver *drv);
+
+#define module_vdpa_driver(__vdpa_driver) \
+       module_driver(__vdpa_driver, vdpa_register_driver,      \
+                     vdpa_unregister_driver)
+
+static inline struct vdpa_driver *drv_to_vdpa(struct device_driver *driver)
+{
+       return container_of(driver, struct vdpa_driver, driver);
+}
+
+static inline struct vdpa_device *dev_to_vdpa(struct device *_dev)
+{
+       return container_of(_dev, struct vdpa_device, dev);
+}
+
+static inline void *vdpa_get_drvdata(const struct vdpa_device *vdev)
+{
+       return dev_get_drvdata(&vdev->dev);
+}
+
+static inline void vdpa_set_drvdata(struct vdpa_device *vdev, void *data)
+{
+       dev_set_drvdata(&vdev->dev, data);
+}
+
+static inline struct device *vdpa_get_dma_dev(struct vdpa_device *vdev)
+{
+       return vdev->dma_dev;
+}
+#endif /* _LINUX_VDPA_H */
diff --git a/include/linux/vhost_iotlb.h b/include/linux/vhost_iotlb.h
new file mode 100644 (file)
index 0000000..6b09b78
--- /dev/null
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_VHOST_IOTLB_H
+#define _LINUX_VHOST_IOTLB_H
+
+#include <linux/interval_tree_generic.h>
+
+struct vhost_iotlb_map {
+       struct rb_node rb;
+       struct list_head link;
+       u64 start;
+       u64 last;
+       u64 size;
+       u64 addr;
+#define VHOST_MAP_RO 0x1
+#define VHOST_MAP_WO 0x2
+#define VHOST_MAP_RW 0x3
+       u32 perm;
+       u32 flags_padding;
+       u64 __subtree_last;
+};
+
+#define VHOST_IOTLB_FLAG_RETIRE 0x1
+
+struct vhost_iotlb {
+       struct rb_root_cached root;
+       struct list_head list;
+       unsigned int limit;
+       unsigned int nmaps;
+       unsigned int flags;
+};
+
+int vhost_iotlb_add_range(struct vhost_iotlb *iotlb, u64 start, u64 last,
+                         u64 addr, unsigned int perm);
+void vhost_iotlb_del_range(struct vhost_iotlb *iotlb, u64 start, u64 last);
+
+struct vhost_iotlb *vhost_iotlb_alloc(unsigned int limit, unsigned int flags);
+void vhost_iotlb_free(struct vhost_iotlb *iotlb);
+void vhost_iotlb_reset(struct vhost_iotlb *iotlb);
+
+struct vhost_iotlb_map *
+vhost_iotlb_itree_first(struct vhost_iotlb *iotlb, u64 start, u64 last);
+struct vhost_iotlb_map *
+vhost_iotlb_itree_next(struct vhost_iotlb_map *map, u64 start, u64 last);
+
+void vhost_iotlb_map_free(struct vhost_iotlb *iotlb,
+                         struct vhost_iotlb_map *map);
+#endif
index d237087..bd0503c 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/virtio_byteorder.h>
 #include <linux/uio.h>
 #include <linux/slab.h>
+#include <linux/dma-direction.h>
+#include <linux/vhost_iotlb.h>
 #include <asm/barrier.h>
 
 /* virtio_ring with information needed for host access. */
@@ -39,6 +41,9 @@ struct vringh {
        /* The vring (note: it may contain user pointers!) */
        struct vring vring;
 
+       /* IOTLB for this vring */
+       struct vhost_iotlb *iotlb;
+
        /* The function to call to notify the guest about added buffers */
        void (*notify)(struct vringh *);
 };
@@ -248,4 +253,35 @@ static inline __virtio64 cpu_to_vringh64(const struct vringh *vrh, u64 val)
 {
        return __cpu_to_virtio64(vringh_is_little_endian(vrh), val);
 }
+
+void vringh_set_iotlb(struct vringh *vrh, struct vhost_iotlb *iotlb);
+
+int vringh_init_iotlb(struct vringh *vrh, u64 features,
+                     unsigned int num, bool weak_barriers,
+                     struct vring_desc *desc,
+                     struct vring_avail *avail,
+                     struct vring_used *used);
+
+int vringh_getdesc_iotlb(struct vringh *vrh,
+                        struct vringh_kiov *riov,
+                        struct vringh_kiov *wiov,
+                        u16 *head,
+                        gfp_t gfp);
+
+ssize_t vringh_iov_pull_iotlb(struct vringh *vrh,
+                             struct vringh_kiov *riov,
+                             void *dst, size_t len);
+ssize_t vringh_iov_push_iotlb(struct vringh *vrh,
+                             struct vringh_kiov *wiov,
+                             const void *src, size_t len);
+
+void vringh_abandon_iotlb(struct vringh *vrh, unsigned int num);
+
+int vringh_complete_iotlb(struct vringh *vrh, u16 head, u32 len);
+
+bool vringh_notify_enable_iotlb(struct vringh *vrh);
+void vringh_notify_disable_iotlb(struct vringh *vrh);
+
+int vringh_need_notify_iotlb(struct vringh *vrh);
+
 #endif /* _LINUX_VRINGH_H */
index 78bac99..d4825b8 100644 (file)
@@ -351,7 +351,7 @@ struct snd_soc_dai {
 
        /* bit field */
        unsigned int probed:1;
-       unsigned int started:1;
+       unsigned int started[SNDRV_PCM_STREAM_LAST + 1];
 };
 
 static inline struct snd_soc_pcm_stream *
index 8134924..e6b6cb0 100644 (file)
@@ -36,12 +36,10 @@ struct btrfs_ioctl_vol_args {
 #define BTRFS_DEVICE_PATH_NAME_MAX     1024
 #define BTRFS_SUBVOL_NAME_MAX          4039
 
-/*
- * Deprecated since 5.7:
- *
- * BTRFS_SUBVOL_CREATE_ASYNC   (1ULL << 0)
- */
-
+#ifndef __KERNEL__
+/* Deprecated since 5.7 */
+# define BTRFS_SUBVOL_CREATE_ASYNC     (1ULL << 0)
+#endif
 #define BTRFS_SUBVOL_RDONLY            (1ULL << 1)
 #define BTRFS_SUBVOL_QGROUP_INHERIT    (1ULL << 2)
 
index 6923dc7..b6a835d 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
 /*
  * Input event codes
  *
index 40d028e..9fe72e4 100644 (file)
 #define VHOST_VSOCK_SET_GUEST_CID      _IOW(VHOST_VIRTIO, 0x60, __u64)
 #define VHOST_VSOCK_SET_RUNNING                _IOW(VHOST_VIRTIO, 0x61, int)
 
+/* VHOST_VDPA specific defines */
+
+/* Get the device id. The device ids follow the same definition of
+ * the device id defined in virtio-spec.
+ */
+#define VHOST_VDPA_GET_DEVICE_ID       _IOR(VHOST_VIRTIO, 0x70, __u32)
+/* Get and set the status. The status bits follow the same definition
+ * of the device status defined in virtio-spec.
+ */
+#define VHOST_VDPA_GET_STATUS          _IOR(VHOST_VIRTIO, 0x71, __u8)
+#define VHOST_VDPA_SET_STATUS          _IOW(VHOST_VIRTIO, 0x72, __u8)
+/* Get and set the device config. The device config follows the same
+ * definition of the device config defined in virtio-spec.
+ */
+#define VHOST_VDPA_GET_CONFIG          _IOR(VHOST_VIRTIO, 0x73, \
+                                            struct vhost_vdpa_config)
+#define VHOST_VDPA_SET_CONFIG          _IOW(VHOST_VIRTIO, 0x74, \
+                                            struct vhost_vdpa_config)
+/* Enable/disable the ring. */
+#define VHOST_VDPA_SET_VRING_ENABLE    _IOW(VHOST_VIRTIO, 0x75, \
+                                            struct vhost_vring_state)
+/* Get the max ring size. */
+#define VHOST_VDPA_GET_VRING_NUM       _IOR(VHOST_VIRTIO, 0x76, __u16)
+
 #endif
index c907290..669457c 100644 (file)
@@ -119,6 +119,14 @@ struct vhost_scsi_target {
        unsigned short reserved;
 };
 
+/* VHOST_VDPA specific definitions */
+
+struct vhost_vdpa_config {
+       __u32 off;
+       __u32 len;
+       __u8 buf[0];
+};
+
 /* Feature bits */
 /* Log all write descriptors. Can be changed while device is active. */
 #define VHOST_F_LOG_ALL 26
index 237e36a..48e3c29 100644 (file)
 #define VIRTIO_IOMMU_F_MMIO                    5
 
 struct virtio_iommu_range_64 {
-       __le64                                  start;
-       __le64                                  end;
+       __u64                                   start;
+       __u64                                   end;
 };
 
 struct virtio_iommu_range_32 {
-       __le32                                  start;
-       __le32                                  end;
+       __u32                                   start;
+       __u32                                   end;
 };
 
 struct virtio_iommu_config {
        /* Supported page sizes */
-       __le64                                  page_size_mask;
+       __u64                                   page_size_mask;
        /* Supported IOVA range */
        struct virtio_iommu_range_64            input_range;
        /* Max domain ID size */
        struct virtio_iommu_range_32            domain_range;
        /* Probe buffer size */
-       __le32                                  probe_size;
+       __u32                                   probe_size;
 };
 
 /* Request types */
index a3715a3..19d23e5 100644 (file)
@@ -57,6 +57,9 @@
                                         * Steering */
 #define VIRTIO_NET_F_CTRL_MAC_ADDR 23  /* Set MAC address */
 
+#define VIRTIO_NET_F_HASH_REPORT  57   /* Supports hash report */
+#define VIRTIO_NET_F_RSS         60    /* Supports RSS RX steering */
+#define VIRTIO_NET_F_RSC_EXT     61    /* extended coalescing info */
 #define VIRTIO_NET_F_STANDBY     62    /* Act as standby for another device
                                         * with the same MAC.
                                         */
 #define VIRTIO_NET_S_LINK_UP   1       /* Link is up */
 #define VIRTIO_NET_S_ANNOUNCE  2       /* Announcement is needed */
 
+/* supported/enabled hash types */
+#define VIRTIO_NET_RSS_HASH_TYPE_IPv4          (1 << 0)
+#define VIRTIO_NET_RSS_HASH_TYPE_TCPv4         (1 << 1)
+#define VIRTIO_NET_RSS_HASH_TYPE_UDPv4         (1 << 2)
+#define VIRTIO_NET_RSS_HASH_TYPE_IPv6          (1 << 3)
+#define VIRTIO_NET_RSS_HASH_TYPE_TCPv6         (1 << 4)
+#define VIRTIO_NET_RSS_HASH_TYPE_UDPv6         (1 << 5)
+#define VIRTIO_NET_RSS_HASH_TYPE_IP_EX         (1 << 6)
+#define VIRTIO_NET_RSS_HASH_TYPE_TCP_EX        (1 << 7)
+#define VIRTIO_NET_RSS_HASH_TYPE_UDP_EX        (1 << 8)
+
 struct virtio_net_config {
        /* The config defining mac address (if VIRTIO_NET_F_MAC) */
        __u8 mac[ETH_ALEN];
@@ -92,6 +106,12 @@ struct virtio_net_config {
         * Any other value stands for unknown.
         */
        __u8 duplex;
+       /* maximum size of RSS key */
+       __u8 rss_max_key_size;
+       /* maximum number of indirection table entries */
+       __le16 rss_max_indirection_table_length;
+       /* bitmask of supported VIRTIO_NET_RSS_HASH_ types */
+       __le32 supported_hash_types;
 } __attribute__((packed));
 
 /*
@@ -104,6 +124,7 @@ struct virtio_net_config {
 struct virtio_net_hdr_v1 {
 #define VIRTIO_NET_HDR_F_NEEDS_CSUM    1       /* Use csum_start, csum_offset */
 #define VIRTIO_NET_HDR_F_DATA_VALID    2       /* Csum is valid */
+#define VIRTIO_NET_HDR_F_RSC_INFO      4       /* rsc info in csum_ fields */
        __u8 flags;
 #define VIRTIO_NET_HDR_GSO_NONE                0       /* Not a GSO frame */
 #define VIRTIO_NET_HDR_GSO_TCPV4       1       /* GSO frame, IPv4 TCP (TSO) */
@@ -113,11 +134,46 @@ struct virtio_net_hdr_v1 {
        __u8 gso_type;
        __virtio16 hdr_len;     /* Ethernet + IP + tcp/udp hdrs */
        __virtio16 gso_size;    /* Bytes to append to hdr_len per frame */
-       __virtio16 csum_start;  /* Position to start checksumming from */
-       __virtio16 csum_offset; /* Offset after that to place checksum */
+       union {
+               struct {
+                       __virtio16 csum_start;
+                       __virtio16 csum_offset;
+               };
+               /* Checksum calculation */
+               struct {
+                       /* Position to start checksumming from */
+                       __virtio16 start;
+                       /* Offset after that to place checksum */
+                       __virtio16 offset;
+               } csum;
+               /* Receive Segment Coalescing */
+               struct {
+                       /* Number of coalesced segments */
+                       __le16 segments;
+                       /* Number of duplicated acks */
+                       __le16 dup_acks;
+               } rsc;
+       };
        __virtio16 num_buffers; /* Number of merged rx buffers */
 };
 
+struct virtio_net_hdr_v1_hash {
+       struct virtio_net_hdr_v1 hdr;
+       __le32 hash_value;
+#define VIRTIO_NET_HASH_REPORT_NONE            0
+#define VIRTIO_NET_HASH_REPORT_IPv4            1
+#define VIRTIO_NET_HASH_REPORT_TCPv4           2
+#define VIRTIO_NET_HASH_REPORT_UDPv4           3
+#define VIRTIO_NET_HASH_REPORT_IPv6            4
+#define VIRTIO_NET_HASH_REPORT_TCPv6           5
+#define VIRTIO_NET_HASH_REPORT_UDPv6           6
+#define VIRTIO_NET_HASH_REPORT_IPv6_EX         7
+#define VIRTIO_NET_HASH_REPORT_TCPv6_EX        8
+#define VIRTIO_NET_HASH_REPORT_UDPv6_EX        9
+       __le16 hash_report;
+       __le16 padding;
+};
+
 #ifndef VIRTIO_NET_NO_LEGACY
 /* This header comes first in the scatter-gather list.
  * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, it must
@@ -228,7 +284,9 @@ struct virtio_net_ctrl_mac {
 
 /*
  * Control Receive Flow Steering
- *
+ */
+#define VIRTIO_NET_CTRL_MQ   4
+/*
  * The command VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET
  * enables Receive Flow Steering, specifying the number of the transmit and
  * receive queues that will be used. After the command is consumed and acked by
@@ -241,12 +299,48 @@ struct virtio_net_ctrl_mq {
        __virtio16 virtqueue_pairs;
 };
 
-#define VIRTIO_NET_CTRL_MQ   4
  #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET        0
  #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN        1
  #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX        0x8000
 
 /*
+ * The command VIRTIO_NET_CTRL_MQ_RSS_CONFIG has the same effect as
+ * VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET does and additionally configures
+ * the receive steering to use a hash calculated for incoming packet
+ * to decide on receive virtqueue to place the packet. The command
+ * also provides parameters to calculate a hash and receive virtqueue.
+ */
+struct virtio_net_rss_config {
+       __le32 hash_types;
+       __le16 indirection_table_mask;
+       __le16 unclassified_queue;
+       __le16 indirection_table[1/* + indirection_table_mask */];
+       __le16 max_tx_vq;
+       __u8 hash_key_length;
+       __u8 hash_key_data[/* hash_key_length */];
+};
+
+ #define VIRTIO_NET_CTRL_MQ_RSS_CONFIG          1
+
+/*
+ * The command VIRTIO_NET_CTRL_MQ_HASH_CONFIG requests the device
+ * to include in the virtio header of the packet the value of the
+ * calculated hash and the report type of hash. It also provides
+ * parameters for hash calculation. The command requires feature
+ * VIRTIO_NET_F_HASH_REPORT to be negotiated to extend the
+ * layout of virtio header as defined in virtio_net_hdr_v1_hash.
+ */
+struct virtio_net_hash_config {
+       __le32 hash_types;
+       /* for compatibility with virtio_net_rss_config */
+       __le16 reserved[4];
+       __u8 hash_key_length;
+       __u8 hash_key_data[/* hash_key_length */];
+};
+
+ #define VIRTIO_NET_CTRL_MQ_HASH_CONFIG         2
+
+/*
  * Control network offloads
  *
  * Reconfigures the network offloads that Guest can handle.
index c0e6a05..12b0dcb 100644 (file)
@@ -14,8 +14,8 @@
 
 unsigned xen_evtchn_nr_channels(void);
 
-int bind_evtchn_to_irq(unsigned int evtchn);
-int bind_evtchn_to_irqhandler(unsigned int evtchn,
+int bind_evtchn_to_irq(evtchn_port_t evtchn);
+int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
                              irq_handler_t handler,
                              unsigned long irqflags, const char *devname,
                              void *dev_id);
@@ -31,9 +31,9 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
                           const char *devname,
                           void *dev_id);
 int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
-                                  unsigned int remote_port);
+                                  evtchn_port_t remote_port);
 int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
-                                         unsigned int remote_port,
+                                         evtchn_port_t remote_port,
                                          irq_handler_t handler,
                                          unsigned long irqflags,
                                          const char *devname,
@@ -54,15 +54,15 @@ int xen_set_irq_priority(unsigned irq, unsigned priority);
 /*
  * Allow extra references to event channels exposed to userspace by evtchn
  */
-int evtchn_make_refcounted(unsigned int evtchn);
-int evtchn_get(unsigned int evtchn);
-void evtchn_put(unsigned int evtchn);
+int evtchn_make_refcounted(evtchn_port_t evtchn);
+int evtchn_get(evtchn_port_t evtchn);
+void evtchn_put(evtchn_port_t evtchn);
 
 void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector);
-void rebind_evtchn_irq(int evtchn, int irq);
+void rebind_evtchn_irq(evtchn_port_t evtchn, int irq);
 int xen_set_affinity_evtchn(struct irq_desc *desc, unsigned int tcpu);
 
-static inline void notify_remote_via_evtchn(int port)
+static inline void notify_remote_via_evtchn(evtchn_port_t port)
 {
        struct evtchn_send send = { .port = port };
        (void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
@@ -86,9 +86,9 @@ void xen_poll_irq(int irq);
 void xen_poll_irq_timeout(int irq, u64 timeout);
 
 /* Determine the IRQ which is bound to an event channel */
-unsigned irq_from_evtchn(unsigned int evtchn);
+unsigned int irq_from_evtchn(evtchn_port_t evtchn);
 int irq_from_virq(unsigned int cpu, unsigned int virq);
-unsigned int evtchn_from_irq(unsigned irq);
+evtchn_port_t evtchn_from_irq(unsigned irq);
 
 #ifdef CONFIG_XEN_PVHVM
 /* Xen HVM evtchn vector callback */
index 45650c9..cf80e33 100644 (file)
@@ -220,7 +220,7 @@ struct evtchn_expand_array {
 #define EVTCHNOP_set_priority    13
 struct evtchn_set_priority {
        /* IN parameters. */
-       uint32_t port;
+       evtchn_port_t port;
        uint32_t priority;
 };
 
index 8c0d1ed..5a8315e 100644 (file)
@@ -47,6 +47,7 @@
 #include <xen/interface/grant_table.h>
 #include <xen/interface/io/xenbus.h>
 #include <xen/interface/io/xs_wire.h>
+#include <xen/interface/event_channel.h>
 
 #define XENBUS_MAX_RING_GRANT_ORDER 4
 #define XENBUS_MAX_RING_GRANTS      (1U << XENBUS_MAX_RING_GRANT_ORDER)
@@ -212,8 +213,8 @@ int xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs,
 
 int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr);
 
-int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port);
-int xenbus_free_evtchn(struct xenbus_device *dev, int port);
+int xenbus_alloc_evtchn(struct xenbus_device *dev, evtchn_port_t *port);
+int xenbus_free_evtchn(struct xenbus_device *dev, evtchn_port_t port);
 
 enum xenbus_state xenbus_read_driver_state(const char *path);
 
index 574b721..9e22ee8 100644 (file)
@@ -16,6 +16,10 @@ config GCC_VERSION
        default $(shell,$(srctree)/scripts/gcc-version.sh $(CC)) if CC_IS_GCC
        default 0
 
+config LD_VERSION
+       int
+       default $(shell,$(LD) --version | $(srctree)/scripts/ld-version.sh)
+
 config CC_IS_CLANG
        def_bool $(success,$(CC) --version | head -n 1 | grep -q clang)
 
index 6246a06..d45e967 100644 (file)
@@ -35,4 +35,4 @@ include/generated/compile.h: FORCE
        @$($(quiet)chk_compile.h)
        $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@   \
        "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)"    \
-       "$(CONFIG_PREEMPT_RT)" "$(CC) $(KBUILD_CFLAGS)"
+       "$(CONFIG_PREEMPT_RT)" "$(CC)" "$(LD)"
index e488213..a48617f 100644 (file)
@@ -913,7 +913,6 @@ asmlinkage __visible void __init start_kernel(void)
        boot_init_stack_canary();
 
        time_init();
-       printk_safe_init();
        perf_event_init();
        profile_init();
        call_function_init();
index 97638eb..7acccfd 100644 (file)
@@ -764,13 +764,13 @@ static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
                        total++;
        }
 
+       *new_pos = pos + 1;
        if (total >= ids->in_use)
                return NULL;
 
        for (; pos < ipc_mni; pos++) {
                ipc = idr_find(&ids->ipcs_idr, pos);
                if (ipc != NULL) {
-                       *new_pos = pos + 1;
                        rcu_read_lock();
                        ipc_lock_object(ipc);
                        return ipc;
index 2031ed1..9e1777c 100644 (file)
@@ -137,9 +137,12 @@ static const char *const maperr2str[] = {
        [MAP_ERR_CHECKED] = "dma map error checked",
 };
 
-static const char *type2name[5] = { "single", "page",
-                                   "scather-gather", "coherent",
-                                   "resource" };
+static const char *type2name[] = {
+       [dma_debug_single] = "single",
+       [dma_debug_sg] = "scather-gather",
+       [dma_debug_coherent] = "coherent",
+       [dma_debug_resource] = "resource",
+};
 
 static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE",
                                   "DMA_FROM_DEVICE", "DMA_NONE" };
index a856005..8f4bbda 100644 (file)
@@ -39,7 +39,8 @@ static inline struct page *dma_direct_to_page(struct device *dev,
 
 u64 dma_direct_get_required_mask(struct device *dev)
 {
-       u64 max_dma = phys_to_dma_direct(dev, (max_pfn - 1) << PAGE_SHIFT);
+       phys_addr_t phys = (phys_addr_t)(max_pfn - 1) << PAGE_SHIFT;
+       u64 max_dma = phys_to_dma_direct(dev, phys);
 
        return (1ULL << (fls64(max_dma) - 1)) * 2 - 1;
 }
index 55e4441..bc9b98a 100644 (file)
@@ -983,16 +983,10 @@ perf_cgroup_set_shadow_time(struct perf_event *event, u64 now)
        event->shadow_ctx_time = now - t->timestamp;
 }
 
-/*
- * Update cpuctx->cgrp so that it is set when first cgroup event is added and
- * cleared when last cgroup event is removed.
- */
 static inline void
-list_update_cgroup_event(struct perf_event *event,
-                        struct perf_event_context *ctx, bool add)
+perf_cgroup_event_enable(struct perf_event *event, struct perf_event_context *ctx)
 {
        struct perf_cpu_context *cpuctx;
-       struct list_head *cpuctx_entry;
 
        if (!is_cgroup_event(event))
                return;
@@ -1009,28 +1003,41 @@ list_update_cgroup_event(struct perf_event *event,
         * because if the first would mismatch, the second would not try again
         * and we would leave cpuctx->cgrp unset.
         */
-       if (add && !cpuctx->cgrp) {
+       if (ctx->is_active && !cpuctx->cgrp) {
                struct perf_cgroup *cgrp = perf_cgroup_from_task(current, ctx);
 
                if (cgroup_is_descendant(cgrp->css.cgroup, event->cgrp->css.cgroup))
                        cpuctx->cgrp = cgrp;
        }
 
-       if (add && ctx->nr_cgroups++)
+       if (ctx->nr_cgroups++)
                return;
-       else if (!add && --ctx->nr_cgroups)
+
+       list_add(&cpuctx->cgrp_cpuctx_entry,
+                       per_cpu_ptr(&cgrp_cpuctx_list, event->cpu));
+}
+
+static inline void
+perf_cgroup_event_disable(struct perf_event *event, struct perf_event_context *ctx)
+{
+       struct perf_cpu_context *cpuctx;
+
+       if (!is_cgroup_event(event))
+               return;
+
+       /*
+        * Because cgroup events are always per-cpu events,
+        * @ctx == &cpuctx->ctx.
+        */
+       cpuctx = container_of(ctx, struct perf_cpu_context, ctx);
+
+       if (--ctx->nr_cgroups)
                return;
 
-       /* no cgroup running */
-       if (!add)
+       if (ctx->is_active && cpuctx->cgrp)
                cpuctx->cgrp = NULL;
 
-       cpuctx_entry = &cpuctx->cgrp_cpuctx_entry;
-       if (add)
-               list_add(cpuctx_entry,
-                        per_cpu_ptr(&cgrp_cpuctx_list, event->cpu));
-       else
-               list_del(cpuctx_entry);
+       list_del(&cpuctx->cgrp_cpuctx_entry);
 }
 
 #else /* !CONFIG_CGROUP_PERF */
@@ -1096,11 +1103,14 @@ static inline u64 perf_cgroup_event_time(struct perf_event *event)
 }
 
 static inline void
-list_update_cgroup_event(struct perf_event *event,
-                        struct perf_event_context *ctx, bool add)
+perf_cgroup_event_enable(struct perf_event *event, struct perf_event_context *ctx)
 {
 }
 
+static inline void
+perf_cgroup_event_disable(struct perf_event *event, struct perf_event_context *ctx)
+{
+}
 #endif
 
 /*
@@ -1791,13 +1801,14 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx)
                add_event_to_groups(event, ctx);
        }
 
-       list_update_cgroup_event(event, ctx, true);
-
        list_add_rcu(&event->event_entry, &ctx->event_list);
        ctx->nr_events++;
        if (event->attr.inherit_stat)
                ctx->nr_stat++;
 
+       if (event->state > PERF_EVENT_STATE_OFF)
+               perf_cgroup_event_enable(event, ctx);
+
        ctx->generation++;
 }
 
@@ -1976,8 +1987,6 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx)
 
        event->attach_state &= ~PERF_ATTACH_CONTEXT;
 
-       list_update_cgroup_event(event, ctx, false);
-
        ctx->nr_events--;
        if (event->attr.inherit_stat)
                ctx->nr_stat--;
@@ -1994,8 +2003,10 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx)
         * of error state is by explicit re-enabling
         * of the event
         */
-       if (event->state > PERF_EVENT_STATE_OFF)
+       if (event->state > PERF_EVENT_STATE_OFF) {
+               perf_cgroup_event_disable(event, ctx);
                perf_event_set_state(event, PERF_EVENT_STATE_OFF);
+       }
 
        ctx->generation++;
 }
@@ -2226,6 +2237,7 @@ event_sched_out(struct perf_event *event,
 
        if (READ_ONCE(event->pending_disable) >= 0) {
                WRITE_ONCE(event->pending_disable, -1);
+               perf_cgroup_event_disable(event, ctx);
                state = PERF_EVENT_STATE_OFF;
        }
        perf_event_set_state(event, state);
@@ -2363,6 +2375,7 @@ static void __perf_event_disable(struct perf_event *event,
                event_sched_out(event, cpuctx, ctx);
 
        perf_event_set_state(event, PERF_EVENT_STATE_OFF);
+       perf_cgroup_event_disable(event, ctx);
 }
 
 /*
@@ -2746,7 +2759,7 @@ static int  __perf_install_in_context(void *info)
        }
 
 #ifdef CONFIG_CGROUP_PERF
-       if (is_cgroup_event(event)) {
+       if (event->state > PERF_EVENT_STATE_OFF && is_cgroup_event(event)) {
                /*
                 * If the current cgroup doesn't match the event's
                 * cgroup, we should not try to schedule it.
@@ -2906,6 +2919,7 @@ static void __perf_event_enable(struct perf_event *event,
                ctx_sched_out(ctx, cpuctx, EVENT_TIME);
 
        perf_event_set_state(event, PERF_EVENT_STATE_INACTIVE);
+       perf_cgroup_event_enable(event, ctx);
 
        if (!ctx->is_active)
                return;
@@ -3508,7 +3522,8 @@ static void cpu_ctx_sched_out(struct perf_cpu_context *cpuctx,
 
 static bool perf_less_group_idx(const void *l, const void *r)
 {
-       const struct perf_event *le = l, *re = r;
+       const struct perf_event *le = *(const struct perf_event **)l;
+       const struct perf_event *re = *(const struct perf_event **)r;
 
        return le->group_index < re->group_index;
 }
@@ -3616,8 +3631,10 @@ static int merge_sched_in(struct perf_event *event, void *data)
        }
 
        if (event->state == PERF_EVENT_STATE_INACTIVE) {
-               if (event->attr.pinned)
+               if (event->attr.pinned) {
+                       perf_cgroup_event_disable(event, ctx);
                        perf_event_set_state(event, PERF_EVENT_STATE_ERROR);
+               }
 
                *can_add_hw = 0;
                ctx->rotate_necessary = 1;
@@ -6917,9 +6934,12 @@ static u64 perf_virt_to_phys(u64 virt)
                 * Try IRQ-safe __get_user_pages_fast first.
                 * If failed, leave phys_addr as 0.
                 */
-               if ((current->mm != NULL) &&
-                   (__get_user_pages_fast(virt, 1, 0, &p) == 1))
-                       phys_addr = page_to_phys(p) + virt % PAGE_SIZE;
+               if (current->mm != NULL) {
+                       pagefault_disable();
+                       if (__get_user_pages_fast(virt, 1, 0, &p) == 1)
+                               phys_addr = page_to_phys(p) + virt % PAGE_SIZE;
+                       pagefault_enable();
+               }
 
                if (p)
                        put_page(p);
index 5e891c3..82babf5 100644 (file)
@@ -108,9 +108,9 @@ static void *gcov_seq_next(struct seq_file *seq, void *data, loff_t *pos)
 {
        struct gcov_iterator *iter = data;
 
+       (*pos)++;
        if (gcov_iter_next(iter))
                return NULL;
-       (*pos)++;
 
        return iter;
 }
index 8b2b311..37c3c4b 100644 (file)
@@ -120,7 +120,7 @@ out:
  * invoke it.
  *
  * If module auto-loading support is disabled then this function
- * becomes a no-operation.
+ * simply returns -ENOENT.
  */
 int __request_module(bool wait, const char *fmt, ...)
 {
@@ -137,7 +137,7 @@ int __request_module(bool wait, const char *fmt, ...)
        WARN_ON_ONCE(wait && current_is_async());
 
        if (!modprobe_path[0])
-               return 0;
+               return -ENOENT;
 
        va_start(args, fmt);
        ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args);
index 1511690..ac10db6 100644 (file)
@@ -3952,10 +3952,36 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
        return ret;
 }
 
+static inline short task_wait_context(struct task_struct *curr)
+{
+       /*
+        * Set appropriate wait type for the context; for IRQs we have to take
+        * into account force_irqthread as that is implied by PREEMPT_RT.
+        */
+       if (curr->hardirq_context) {
+               /*
+                * Check if force_irqthreads will run us threaded.
+                */
+               if (curr->hardirq_threaded || curr->irq_config)
+                       return LD_WAIT_CONFIG;
+
+               return LD_WAIT_SPIN;
+       } else if (curr->softirq_context) {
+               /*
+                * Softirqs are always threaded.
+                */
+               return LD_WAIT_CONFIG;
+       }
+
+       return LD_WAIT_MAX;
+}
+
 static int
 print_lock_invalid_wait_context(struct task_struct *curr,
                                struct held_lock *hlock)
 {
+       short curr_inner;
+
        if (!debug_locks_off())
                return 0;
        if (debug_locks_silent)
@@ -3971,6 +3997,10 @@ print_lock_invalid_wait_context(struct task_struct *curr,
        print_lock(hlock);
 
        pr_warn("other info that might help us debug this:\n");
+
+       curr_inner = task_wait_context(curr);
+       pr_warn("context-{%d:%d}\n", curr_inner, curr_inner);
+
        lockdep_print_held_locks(curr);
 
        pr_warn("stack backtrace:\n");
@@ -4017,26 +4047,7 @@ static int check_wait_context(struct task_struct *curr, struct held_lock *next)
        }
        depth++;
 
-       /*
-        * Set appropriate wait type for the context; for IRQs we have to take
-        * into account force_irqthread as that is implied by PREEMPT_RT.
-        */
-       if (curr->hardirq_context) {
-               /*
-                * Check if force_irqthreads will run us threaded.
-                */
-               if (curr->hardirq_threaded || curr->irq_config)
-                       curr_inner = LD_WAIT_CONFIG;
-               else
-                       curr_inner = LD_WAIT_SPIN;
-       } else if (curr->softirq_context) {
-               /*
-                * Softirqs are always threaded.
-                */
-               curr_inner = LD_WAIT_CONFIG;
-       } else {
-               curr_inner = LD_WAIT_MAX;
-       }
+       curr_inner = task_wait_context(curr);
 
        for (; depth < curr->lockdep_depth; depth++) {
                struct held_lock *prev = curr->held_locks + depth;
index a008a1b..8bbafe3 100644 (file)
@@ -118,14 +118,15 @@ static int percpu_rwsem_wake_function(struct wait_queue_entry *wq_entry,
                                      unsigned int mode, int wake_flags,
                                      void *key)
 {
-       struct task_struct *p = get_task_struct(wq_entry->private);
        bool reader = wq_entry->flags & WQ_FLAG_CUSTOM;
        struct percpu_rw_semaphore *sem = key;
+       struct task_struct *p;
 
        /* concurrent against percpu_down_write(), can get stolen */
        if (!__percpu_rwsem_trylock(sem, reader))
                return 1;
 
+       p = get_task_struct(wq_entry->private);
        list_del_init(&wq_entry->entry);
        smp_store_release(&wq_entry->private, NULL);
 
index 3447f3b..646f1e2 100644 (file)
@@ -1515,7 +1515,7 @@ struct module_sect_attr {
 struct module_sect_attrs {
        struct attribute_group grp;
        unsigned int nsections;
-       struct module_sect_attr attrs[0];
+       struct module_sect_attr attrs[];
 };
 
 static ssize_t module_sect_show(struct module_attribute *mattr,
@@ -1608,7 +1608,7 @@ static void remove_sect_attrs(struct module *mod)
 struct module_notes_attrs {
        struct kobject *dir;
        unsigned int notes;
-       struct bin_attribute attrs[0];
+       struct bin_attribute attrs[];
 };
 
 static ssize_t module_notes_read(struct file *filp, struct kobject *kobj,
index bc21c0f..c835b84 100644 (file)
@@ -256,6 +256,7 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t *set_tid,
 
        get_pid_ns(ns);
        refcount_set(&pid->count, 1);
+       spin_lock_init(&pid->lock);
        for (type = 0; type < PIDTYPE_MAX; ++type)
                INIT_HLIST_HEAD(&pid->tasks[type]);
 
index ef90eb1..7959449 100644 (file)
@@ -196,6 +196,50 @@ unlock:
        return res;
 }
 
+struct compat_resume_swap_area {
+       compat_loff_t offset;
+       u32 dev;
+} __packed;
+
+static int snapshot_set_swap_area(struct snapshot_data *data,
+               void __user *argp)
+{
+       sector_t offset;
+       dev_t swdev;
+
+       if (swsusp_swap_in_use())
+               return -EPERM;
+
+       if (in_compat_syscall()) {
+               struct compat_resume_swap_area swap_area;
+
+               if (copy_from_user(&swap_area, argp, sizeof(swap_area)))
+                       return -EFAULT;
+               swdev = new_decode_dev(swap_area.dev);
+               offset = swap_area.offset;
+       } else {
+               struct resume_swap_area swap_area;
+
+               if (copy_from_user(&swap_area, argp, sizeof(swap_area)))
+                       return -EFAULT;
+               swdev = new_decode_dev(swap_area.dev);
+               offset = swap_area.offset;
+       }
+
+       /*
+        * User space encodes device types as two-byte values,
+        * so we need to recode them
+        */
+       if (!swdev) {
+               data->swap = -1;
+               return -EINVAL;
+       }
+       data->swap = swap_type_of(swdev, offset, NULL);
+       if (data->swap < 0)
+               return -ENODEV;
+       return 0;
+}
+
 static long snapshot_ioctl(struct file *filp, unsigned int cmd,
                                                        unsigned long arg)
 {
@@ -351,34 +395,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
                break;
 
        case SNAPSHOT_SET_SWAP_AREA:
-               if (swsusp_swap_in_use()) {
-                       error = -EPERM;
-               } else {
-                       struct resume_swap_area swap_area;
-                       dev_t swdev;
-
-                       error = copy_from_user(&swap_area, (void __user *)arg,
-                                       sizeof(struct resume_swap_area));
-                       if (error) {
-                               error = -EFAULT;
-                               break;
-                       }
-
-                       /*
-                        * User space encodes device types as two-byte values,
-                        * so we need to recode them
-                        */
-                       swdev = new_decode_dev(swap_area.dev);
-                       if (swdev) {
-                               offset = swap_area.offset;
-                               data->swap = swap_type_of(swdev, offset, NULL);
-                               if (data->swap < 0)
-                                       error = -ENODEV;
-                       } else {
-                               data->swap = -1;
-                               error = -EINVAL;
-                       }
-               }
+               error = snapshot_set_swap_area(data, (void __user *)arg);
                break;
 
        default:
@@ -393,12 +410,6 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 }
 
 #ifdef CONFIG_COMPAT
-
-struct compat_resume_swap_area {
-       compat_loff_t offset;
-       u32 dev;
-} __packed;
-
 static long
 snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
@@ -409,33 +420,13 @@ snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case SNAPSHOT_AVAIL_SWAP_SIZE:
        case SNAPSHOT_ALLOC_SWAP_PAGE:
        case SNAPSHOT_CREATE_IMAGE:
+       case SNAPSHOT_SET_SWAP_AREA:
                return snapshot_ioctl(file, cmd,
                                      (unsigned long) compat_ptr(arg));
-
-       case SNAPSHOT_SET_SWAP_AREA: {
-               struct compat_resume_swap_area __user *u_swap_area =
-                       compat_ptr(arg);
-               struct resume_swap_area swap_area;
-               mm_segment_t old_fs;
-               int err;
-
-               err = get_user(swap_area.offset, &u_swap_area->offset);
-               err |= get_user(swap_area.dev, &u_swap_area->dev);
-               if (err)
-                       return -EFAULT;
-               old_fs = get_fs();
-               set_fs(KERNEL_DS);
-               err = snapshot_ioctl(file, SNAPSHOT_SET_SWAP_AREA,
-                                    (unsigned long) &swap_area);
-               set_fs(old_fs);
-               return err;
-       }
-
        default:
                return snapshot_ioctl(file, cmd, arg);
        }
 }
-
 #endif /* CONFIG_COMPAT */
 
 static const struct file_operations snapshot_fops = {
index c8e6ab6..b2b0f52 100644 (file)
@@ -23,6 +23,9 @@ __printf(1, 0) int vprintk_func(const char *fmt, va_list args);
 void __printk_safe_enter(void);
 void __printk_safe_exit(void);
 
+void printk_safe_init(void);
+bool printk_percpu_data_ready(void);
+
 #define printk_safe_enter_irqsave(flags)       \
        do {                                    \
                local_irq_save(flags);          \
@@ -64,4 +67,6 @@ __printf(1, 0) int vprintk_func(const char *fmt, va_list args) { return 0; }
 #define printk_safe_enter_irq() local_irq_disable()
 #define printk_safe_exit_irq() local_irq_enable()
 
+static inline void printk_safe_init(void) { }
+static inline bool printk_percpu_data_ready(void) { return false; }
 #endif /* CONFIG_PRINTK */
index 633f41a..9a9b615 100644 (file)
@@ -460,6 +460,18 @@ static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
 static char *log_buf = __log_buf;
 static u32 log_buf_len = __LOG_BUF_LEN;
 
+/*
+ * We cannot access per-CPU data (e.g. per-CPU flush irq_work) before
+ * per_cpu_areas are initialised. This variable is set to true when
+ * it's safe to access per-CPU data.
+ */
+static bool __printk_percpu_data_ready __read_mostly;
+
+bool printk_percpu_data_ready(void)
+{
+       return __printk_percpu_data_ready;
+}
+
 /* Return log buffer address */
 char *log_buf_addr_get(void)
 {
@@ -1146,12 +1158,28 @@ static void __init log_buf_add_cpu(void)
 static inline void log_buf_add_cpu(void) {}
 #endif /* CONFIG_SMP */
 
+static void __init set_percpu_data_ready(void)
+{
+       printk_safe_init();
+       /* Make sure we set this flag only after printk_safe() init is done */
+       barrier();
+       __printk_percpu_data_ready = true;
+}
+
 void __init setup_log_buf(int early)
 {
        unsigned long flags;
        char *new_log_buf;
        unsigned int free;
 
+       /*
+        * Some archs call setup_log_buf() multiple times - first is very
+        * early, e.g. from setup_arch(), and second - when percpu_areas
+        * are initialised.
+        */
+       if (!early)
+               set_percpu_data_ready();
+
        if (log_buf != __log_buf)
                return;
 
@@ -2975,6 +3003,9 @@ static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = {
 
 void wake_up_klogd(void)
 {
+       if (!printk_percpu_data_ready())
+               return;
+
        preempt_disable();
        if (waitqueue_active(&log_wait)) {
                this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
@@ -2985,6 +3016,9 @@ void wake_up_klogd(void)
 
 void defer_console_output(void)
 {
+       if (!printk_percpu_data_ready())
+               return;
+
        preempt_disable();
        __this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT);
        irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
index b4045e7..d9a659a 100644 (file)
@@ -27,7 +27,6 @@
  * There are situations when we want to make sure that all buffers
  * were handled or when IRQs are blocked.
  */
-static int printk_safe_irq_ready __read_mostly;
 
 #define SAFE_LOG_BUF_LEN ((1 << CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT) -    \
                                sizeof(atomic_t) -                      \
@@ -51,7 +50,7 @@ static DEFINE_PER_CPU(struct printk_safe_seq_buf, nmi_print_seq);
 /* Get flushed in a more safe context. */
 static void queue_flush_work(struct printk_safe_seq_buf *s)
 {
-       if (printk_safe_irq_ready)
+       if (printk_percpu_data_ready())
                irq_work_queue(&s->work);
 }
 
@@ -402,14 +401,6 @@ void __init printk_safe_init(void)
 #endif
        }
 
-       /*
-        * In the highly unlikely event that a NMI were to trigger at
-        * this moment. Make sure IRQ work is set up before this
-        * variable is set.
-        */
-       barrier();
-       printk_safe_irq_ready = 1;
-
        /* Flush pending messages that did not have scheduled IRQ works. */
        printk_safe_flush();
 }
index a2694ba..3a61a3b 100644 (file)
@@ -2119,12 +2119,6 @@ int select_task_rq(struct task_struct *p, int cpu, int sd_flags, int wake_flags)
        return cpu;
 }
 
-static void update_avg(u64 *avg, u64 sample)
-{
-       s64 diff = sample - *avg;
-       *avg += diff >> 3;
-}
-
 void sched_set_stop_task(int cpu, struct task_struct *stop)
 {
        struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
@@ -4126,7 +4120,8 @@ static inline void sched_submit_work(struct task_struct *tsk)
         * it wants to wake up a task to maintain concurrency.
         * As this function is called inside the schedule() context,
         * we disable preemption to avoid it calling schedule() again
-        * in the possible wakeup of a kworker.
+        * in the possible wakeup of a kworker and because wq_worker_sleeping()
+        * requires it.
         */
        if (tsk->flags & (PF_WQ_WORKER | PF_IO_WORKER)) {
                preempt_disable();
@@ -6699,7 +6694,6 @@ void __init sched_init(void)
 
                rq_attach_root(rq, &def_root_domain);
 #ifdef CONFIG_NO_HZ_COMMON
-               rq->last_load_update_tick = jiffies;
                rq->last_blocked_load_update_tick = jiffies;
                atomic_set(&rq->nohz_flags, 0);
 #endif
index 8331bc0..a562df5 100644 (file)
@@ -816,10 +816,12 @@ static int __init init_sched_debug_procfs(void)
 
 __initcall(init_sched_debug_procfs);
 
-#define __P(F) SEQ_printf(m, "%-45s:%21Ld\n",       #F, (long long)F)
-#define   P(F) SEQ_printf(m, "%-45s:%21Ld\n",       #F, (long long)p->F)
-#define __PN(F)        SEQ_printf(m, "%-45s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)F))
-#define   PN(F)        SEQ_printf(m, "%-45s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)p->F))
+#define __PS(S, F) SEQ_printf(m, "%-45s:%21Ld\n", S, (long long)(F))
+#define __P(F) __PS(#F, F)
+#define   P(F) __PS(#F, p->F)
+#define __PSN(S, F) SEQ_printf(m, "%-45s:%14Ld.%06ld\n", S, SPLIT_NS((long long)(F)))
+#define __PN(F) __PSN(#F, F)
+#define   PN(F) __PSN(#F, p->F)
 
 
 #ifdef CONFIG_NUMA_BALANCING
@@ -868,18 +870,9 @@ void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns,
        SEQ_printf(m,
                "---------------------------------------------------------"
                "----------\n");
-#define __P(F) \
-       SEQ_printf(m, "%-45s:%21Ld\n", #F, (long long)F)
-#define P(F) \
-       SEQ_printf(m, "%-45s:%21Ld\n", #F, (long long)p->F)
-#define P_SCHEDSTAT(F) \
-       SEQ_printf(m, "%-45s:%21Ld\n", #F, (long long)schedstat_val(p->F))
-#define __PN(F) \
-       SEQ_printf(m, "%-45s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)F))
-#define PN(F) \
-       SEQ_printf(m, "%-45s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)p->F))
-#define PN_SCHEDSTAT(F) \
-       SEQ_printf(m, "%-45s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)schedstat_val(p->F)))
+
+#define P_SCHEDSTAT(F)  __PS(#F, schedstat_val(p->F))
+#define PN_SCHEDSTAT(F) __PSN(#F, schedstat_val(p->F))
 
        PN(se.exec_start);
        PN(se.vruntime);
@@ -939,10 +932,8 @@ void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns,
        }
 
        __P(nr_switches);
-       SEQ_printf(m, "%-45s:%21Ld\n",
-                  "nr_voluntary_switches", (long long)p->nvcsw);
-       SEQ_printf(m, "%-45s:%21Ld\n",
-                  "nr_involuntary_switches", (long long)p->nivcsw);
+       __PS("nr_voluntary_switches", p->nvcsw);
+       __PS("nr_involuntary_switches", p->nivcsw);
 
        P(se.load.weight);
 #ifdef CONFIG_SMP
@@ -956,6 +947,12 @@ void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns,
        P(se.avg.util_est.ewma);
        P(se.avg.util_est.enqueued);
 #endif
+#ifdef CONFIG_UCLAMP_TASK
+       __PS("uclamp.min", p->uclamp[UCLAMP_MIN].value);
+       __PS("uclamp.max", p->uclamp[UCLAMP_MAX].value);
+       __PS("effective uclamp.min", uclamp_eff_value(p, UCLAMP_MIN));
+       __PS("effective uclamp.max", uclamp_eff_value(p, UCLAMP_MAX));
+#endif
        P(policy);
        P(prio);
        if (task_has_dl_policy(p)) {
@@ -963,11 +960,7 @@ void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns,
                P(dl.deadline);
        }
 #undef PN_SCHEDSTAT
-#undef PN
-#undef __PN
 #undef P_SCHEDSTAT
-#undef P
-#undef __P
 
        {
                unsigned int this_cpu = raw_smp_processor_id();
@@ -975,8 +968,7 @@ void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns,
 
                t0 = cpu_clock(this_cpu);
                t1 = cpu_clock(this_cpu);
-               SEQ_printf(m, "%-45s:%21Ld\n",
-                          "clock-delta", (long long)(t1-t0));
+               __PS("clock-delta", t1-t0);
        }
 
        sched_show_numa(p, m);
index 1ea3ddd..02f323b 100644 (file)
@@ -4836,11 +4836,10 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
                resched_curr(rq);
 }
 
-static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b, u64 remaining)
+static void distribute_cfs_runtime(struct cfs_bandwidth *cfs_b)
 {
        struct cfs_rq *cfs_rq;
-       u64 runtime;
-       u64 starting_runtime = remaining;
+       u64 runtime, remaining = 1;
 
        rcu_read_lock();
        list_for_each_entry_rcu(cfs_rq, &cfs_b->throttled_cfs_rq,
@@ -4855,10 +4854,13 @@ static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b, u64 remaining)
                /* By the above check, this should never be true */
                SCHED_WARN_ON(cfs_rq->runtime_remaining > 0);
 
+               raw_spin_lock(&cfs_b->lock);
                runtime = -cfs_rq->runtime_remaining + 1;
-               if (runtime > remaining)
-                       runtime = remaining;
-               remaining -= runtime;
+               if (runtime > cfs_b->runtime)
+                       runtime = cfs_b->runtime;
+               cfs_b->runtime -= runtime;
+               remaining = cfs_b->runtime;
+               raw_spin_unlock(&cfs_b->lock);
 
                cfs_rq->runtime_remaining += runtime;
 
@@ -4873,8 +4875,6 @@ next:
                        break;
        }
        rcu_read_unlock();
-
-       return starting_runtime - remaining;
 }
 
 /*
@@ -4885,7 +4885,6 @@ next:
  */
 static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun, unsigned long flags)
 {
-       u64 runtime;
        int throttled;
 
        /* no need to continue the timer with no bandwidth constraint */
@@ -4914,24 +4913,17 @@ static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun, u
        cfs_b->nr_throttled += overrun;
 
        /*
-        * This check is repeated as we are holding onto the new bandwidth while
-        * we unthrottle. This can potentially race with an unthrottled group
-        * trying to acquire new bandwidth from the global pool. This can result
-        * in us over-using our runtime if it is all used during this loop, but
-        * only by limited amounts in that extreme case.
+        * This check is repeated as we release cfs_b->lock while we unthrottle.
         */
        while (throttled && cfs_b->runtime > 0 && !cfs_b->distribute_running) {
-               runtime = cfs_b->runtime;
                cfs_b->distribute_running = 1;
                raw_spin_unlock_irqrestore(&cfs_b->lock, flags);
                /* we can't nest cfs_b->lock while distributing bandwidth */
-               runtime = distribute_cfs_runtime(cfs_b, runtime);
+               distribute_cfs_runtime(cfs_b);
                raw_spin_lock_irqsave(&cfs_b->lock, flags);
 
                cfs_b->distribute_running = 0;
                throttled = !list_empty(&cfs_b->throttled_cfs_rq);
-
-               lsub_positive(&cfs_b->runtime, runtime);
        }
 
        /*
@@ -5065,10 +5057,9 @@ static void do_sched_cfs_slack_timer(struct cfs_bandwidth *cfs_b)
        if (!runtime)
                return;
 
-       runtime = distribute_cfs_runtime(cfs_b, runtime);
+       distribute_cfs_runtime(cfs_b);
 
        raw_spin_lock_irqsave(&cfs_b->lock, flags);
-       lsub_positive(&cfs_b->runtime, runtime);
        cfs_b->distribute_running = 0;
        raw_spin_unlock_irqrestore(&cfs_b->lock, flags);
 }
@@ -6080,8 +6071,7 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int t
        struct cpumask *cpus = this_cpu_cpumask_var_ptr(select_idle_mask);
        struct sched_domain *this_sd;
        u64 avg_cost, avg_idle;
-       u64 time, cost;
-       s64 delta;
+       u64 time;
        int this = smp_processor_id();
        int cpu, nr = INT_MAX;
 
@@ -6119,9 +6109,7 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int t
        }
 
        time = cpu_clock(this) - time;
-       cost = this_sd->avg_scan_cost;
-       delta = (s64)(time - cost) / 8;
-       this_sd->avg_scan_cost += delta;
+       update_avg(&this_sd->avg_scan_cost, time);
 
        return cpu;
 }
@@ -9048,6 +9036,14 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
 
                sds->avg_load = (sds->total_load * SCHED_CAPACITY_SCALE) /
                                sds->total_capacity;
+               /*
+                * If the local group is more loaded than the selected
+                * busiest group don't try to pull any tasks.
+                */
+               if (local->avg_load >= busiest->avg_load) {
+                       env->imbalance = 0;
+                       return;
+               }
        }
 
        /*
index 0f616bf..db3a576 100644 (file)
@@ -195,6 +195,12 @@ static inline int task_has_dl_policy(struct task_struct *p)
 
 #define cap_scale(v, s) ((v)*(s) >> SCHED_CAPACITY_SHIFT)
 
+static inline void update_avg(u64 *avg, u64 sample)
+{
+       s64 diff = sample - *avg;
+       *avg += diff / 8;
+}
+
 /*
  * !! For sched_setattr_nocheck() (kernel) only !!
  *
@@ -882,7 +888,6 @@ struct rq {
 #endif
 #ifdef CONFIG_NO_HZ_COMMON
 #ifdef CONFIG_SMP
-       unsigned long           last_load_update_tick;
        unsigned long           last_blocked_load_update_tick;
        unsigned int            has_blocked_load;
 #endif /* CONFIG_SMP */
index e6ba064..3b30288 100644 (file)
@@ -447,6 +447,7 @@ const struct proc_ns_operations timens_operations = {
 
 const struct proc_ns_operations timens_for_children_operations = {
        .name           = "time_for_children",
+       .real_ns_name   = "time",
        .type           = CLONE_NEWTIME,
        .get            = timens_for_children_get,
        .put            = timens_put,
index dd34a1b..3a74736 100644 (file)
@@ -1088,14 +1088,10 @@ register_snapshot_trigger(char *glob, struct event_trigger_ops *ops,
                          struct event_trigger_data *data,
                          struct trace_event_file *file)
 {
-       int ret = register_trigger(glob, ops, data, file);
-
-       if (ret > 0 && tracing_alloc_snapshot_instance(file->tr) != 0) {
-               unregister_trigger(glob, ops, data, file);
-               ret = 0;
-       }
+       if (tracing_alloc_snapshot_instance(file->tr) != 0)
+               return 0;
 
-       return ret;
+       return register_trigger(glob, ops, data, file);
 }
 
 static int
index a53cc2b..11b1596 100644 (file)
@@ -69,6 +69,7 @@ static struct ctl_table user_table[] = {
        UCOUNT_ENTRY("max_net_namespaces"),
        UCOUNT_ENTRY("max_mnt_namespaces"),
        UCOUNT_ENTRY("max_cgroup_namespaces"),
+       UCOUNT_ENTRY("max_time_namespaces"),
 #ifdef CONFIG_INOTIFY_USER
        UCOUNT_ENTRY("max_inotify_instances"),
        UCOUNT_ENTRY("max_inotify_watches"),
@@ -81,6 +82,8 @@ bool setup_userns_sysctls(struct user_namespace *ns)
 {
 #ifdef CONFIG_SYSCTL
        struct ctl_table *tbl;
+
+       BUILD_BUG_ON(ARRAY_SIZE(user_table) != UCOUNT_COUNTS + 1);
        setup_sysctl_set(&ns->set, &set_root, set_is_seen);
        tbl = kmemdup(user_table, sizeof(user_table), GFP_KERNEL);
        if (tbl) {
index 3816a18..891ccad 100644 (file)
@@ -858,7 +858,8 @@ void wq_worker_running(struct task_struct *task)
  * @task: task going to sleep
  *
  * This function is called from schedule() when a busy worker is
- * going to sleep.
+ * going to sleep. Preemption needs to be disabled to protect ->sleeping
+ * assignment.
  */
 void wq_worker_sleeping(struct task_struct *task)
 {
@@ -875,7 +876,8 @@ void wq_worker_sleeping(struct task_struct *task)
 
        pool = worker->pool;
 
-       if (WARN_ON_ONCE(worker->sleeping))
+       /* Return if preempted before wq_worker_running() was reached */
+       if (worker->sleeping)
                return;
 
        worker->sleeping = 1;
index bc7e563..5d53f96 100644 (file)
@@ -615,6 +615,9 @@ config ARCH_HAS_PMEM_API
 config MEMREGION
        bool
 
+config ARCH_HAS_MEMREMAP_COMPAT_ALIGN
+       bool
+
 # use memcpy to implement user copies for nommu architectures
 config UACCESS_MEMCPY
        bool
index bf1b476..6d5e500 100644 (file)
@@ -34,10 +34,8 @@ const struct raid6_calls * const raid6_algos[] = {
        &raid6_avx512x2,
        &raid6_avx512x1,
 #endif
-#ifdef CONFIG_AS_AVX2
        &raid6_avx2x2,
        &raid6_avx2x1,
-#endif
        &raid6_sse2x2,
        &raid6_sse2x1,
        &raid6_sse1x2,
@@ -51,11 +49,9 @@ const struct raid6_calls * const raid6_algos[] = {
        &raid6_avx512x2,
        &raid6_avx512x1,
 #endif
-#ifdef CONFIG_AS_AVX2
        &raid6_avx2x4,
        &raid6_avx2x2,
        &raid6_avx2x1,
-#endif
        &raid6_sse2x4,
        &raid6_sse2x2,
        &raid6_sse2x1,
@@ -97,13 +93,11 @@ void (*raid6_datap_recov)(int, size_t, int, void **);
 EXPORT_SYMBOL_GPL(raid6_datap_recov);
 
 const struct raid6_recov_calls *const raid6_recov_algos[] = {
+#ifdef CONFIG_X86
 #ifdef CONFIG_AS_AVX512
        &raid6_recov_avx512,
 #endif
-#ifdef CONFIG_AS_AVX2
        &raid6_recov_avx2,
-#endif
-#ifdef CONFIG_AS_SSSE3
        &raid6_recov_ssse3,
 #endif
 #ifdef CONFIG_S390
index 87184b6..f299476 100644 (file)
@@ -13,8 +13,6 @@
  *
  */
 
-#ifdef CONFIG_AS_AVX2
-
 #include <linux/raid/pq.h>
 #include "x86.h"
 
@@ -470,5 +468,3 @@ const struct raid6_calls raid6_avx2x4 = {
        1                       /* Has cache hints */
 };
 #endif
-
-#endif /* CONFIG_AS_AVX2 */
index 7a3b5e7..4e80954 100644 (file)
@@ -4,8 +4,6 @@
  * Author: Jim Kukunas <james.t.kukunas@linux.intel.com>
  */
 
-#ifdef CONFIG_AS_AVX2
-
 #include <linux/raid/pq.h>
 #include "x86.h"
 
@@ -313,7 +311,3 @@ const struct raid6_recov_calls raid6_recov_avx2 = {
 #endif
        .priority = 2,
 };
-
-#else
-#warning "your version of binutils lacks AVX2 support"
-#endif
index 1de97d2..4bfa3c6 100644 (file)
@@ -3,8 +3,6 @@
  * Copyright (C) 2012 Intel Corporation
  */
 
-#ifdef CONFIG_AS_SSSE3
-
 #include <linux/raid/pq.h>
 #include "x86.h"
 
@@ -328,7 +326,3 @@ const struct raid6_recov_calls raid6_recov_ssse3 = {
 #endif
        .priority = 1,
 };
-
-#else
-#warning "your version of binutils lacks SSSE3 support"
-#endif
index 3ab8720..a4c7cd7 100644 (file)
@@ -34,14 +34,9 @@ endif
 
 ifeq ($(IS_X86),yes)
         OBJS   += mmx.o sse1.o sse2.o avx2.o recov_ssse3.o recov_avx2.o avx512.o recov_avx512.o
-        CFLAGS += $(shell echo "pshufb %xmm0, %xmm0" |         \
-                    gcc -c -x assembler - >&/dev/null &&       \
-                    rm ./-.o && echo -DCONFIG_AS_SSSE3=1)
-        CFLAGS += $(shell echo "vpbroadcastb %xmm0, %ymm1" |   \
-                    gcc -c -x assembler - >&/dev/null &&       \
-                    rm ./-.o && echo -DCONFIG_AS_AVX2=1)
+        CFLAGS += -DCONFIG_X86
        CFLAGS += $(shell echo "vpmovm2b %k1, %zmm5" |          \
-                   gcc -c -x assembler - >&/dev/null &&        \
+                   gcc -c -x assembler - >/dev/null 2>&1 &&    \
                    rm ./-.o && echo -DCONFIG_AS_AVX512=1)
 else ifeq ($(HAS_NEON),yes)
         OBJS   += neon.o neon1.o neon2.o neon4.o neon8.o recov_neon.o recov_neon_inner.o
index 6910214..c1acc34 100644 (file)
@@ -139,6 +139,10 @@ config HAVE_FAST_GUP
 config ARCH_KEEP_MEMBLOCK
        bool
 
+# Keep arch NUMA mapping infrastructure post-init.
+config NUMA_KEEP_MEMINFO
+       bool
+
 config MEMORY_ISOLATION
        bool
 
@@ -154,6 +158,7 @@ config MEMORY_HOTPLUG
        bool "Allow for memory hot-add"
        depends on SPARSEMEM || X86_64_ACPI_NUMA
        depends on ARCH_ENABLE_MEMORY_HOTPLUG
+       select NUMA_KEEP_MEMINFO if NUMA
 
 config MEMORY_HOTPLUG_SPARSE
        def_bool y
index 62f05f6..c81b4f3 100644 (file)
@@ -491,8 +491,8 @@ static void cgwb_release_workfn(struct work_struct *work)
        css_put(wb->blkcg_css);
        mutex_unlock(&wb->bdi->cgwb_release_mutex);
 
-       /* triggers blkg destruction if cgwb_refcnt becomes zero */
-       blkcg_cgwb_put(blkcg);
+       /* triggers blkg destruction if no online users left */
+       blkcg_unpin_online(blkcg);
 
        fprop_local_destroy_percpu(&wb->memcg_completions);
        percpu_ref_exit(&wb->refcnt);
@@ -592,7 +592,7 @@ static int cgwb_create(struct backing_dev_info *bdi,
                        list_add_tail_rcu(&wb->bdi_node, &bdi->wb_list);
                        list_add(&wb->memcg_node, memcg_cgwb_list);
                        list_add(&wb->blkcg_node, blkcg_cgwb_list);
-                       blkcg_cgwb_get(blkcg);
+                       blkcg_pin_online(blkcg);
                        css_get(memcg_css);
                        css_get(blkcg_css);
                }
index be55d19..0463ad2 100644 (file)
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -220,7 +220,7 @@ int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
 }
 
 /**
- * cma_declare_contiguous() - reserve custom contiguous area
+ * cma_declare_contiguous_nid() - reserve custom contiguous area
  * @base: Base address of the reserved area optional, use 0 for any
  * @size: Size of the reserved area (in bytes),
  * @limit: End address of the reserved memory (optional, 0 for any).
@@ -229,6 +229,7 @@ int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
  * @fixed: hint about where to place the reserved area
  * @name: The name of the area. See function cma_init_reserved_mem()
  * @res_cma: Pointer to store the created cma region.
+ * @nid: nid of the free area to find, %NUMA_NO_NODE for any node
  *
  * This function reserves memory from early allocator. It should be
  * called by arch specific code once the early allocator (memblock or bootmem)
@@ -238,10 +239,11 @@ int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
  * If @fixed is true, reserve contiguous area at exactly @base.  If false,
  * reserve in range from @base to @limit.
  */
-int __init cma_declare_contiguous(phys_addr_t base,
+int __init cma_declare_contiguous_nid(phys_addr_t base,
                        phys_addr_t size, phys_addr_t limit,
                        phys_addr_t alignment, unsigned int order_per_bit,
-                       bool fixed, const char *name, struct cma **res_cma)
+                       bool fixed, const char *name, struct cma **res_cma,
+                       int nid)
 {
        phys_addr_t memblock_end = memblock_end_of_DRAM();
        phys_addr_t highmem_start;
@@ -336,14 +338,14 @@ int __init cma_declare_contiguous(phys_addr_t base,
                 * memory in case of failure.
                 */
                if (base < highmem_start && limit > highmem_start) {
-                       addr = memblock_phys_alloc_range(size, alignment,
-                                                        highmem_start, limit);
+                       addr = memblock_alloc_range_nid(size, alignment,
+                                       highmem_start, limit, nid, false);
                        limit = highmem_start;
                }
 
                if (!addr) {
-                       addr = memblock_phys_alloc_range(size, alignment, base,
-                                                        limit);
+                       addr = memblock_alloc_range_nid(size, alignment, base,
+                                       limit, nid, false);
                        if (!addr) {
                                ret = -ENOMEM;
                                goto err;
index a212305..6076df8 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -1326,10 +1326,12 @@ retry:
                 * start trying again otherwise it can loop forever.
                 */
 
-               if (fatal_signal_pending(current))
+               if (fatal_signal_pending(current)) {
+                       if (!pages_done)
+                               pages_done = -EINTR;
                        break;
+               }
 
-               *locked = 1;
                ret = down_read_killable(&mm->mmap_sem);
                if (ret) {
                        BUG_ON(ret > 0);
@@ -1338,6 +1340,7 @@ retry:
                        break;
                }
 
+               *locked = 1;
                ret = __get_user_pages(tsk, mm, start, 1, flags | FOLL_TRIED,
                                       pages, NULL, locked);
                if (!*locked) {
index f5fb53f..cd45915 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/jhash.h>
 #include <linux/numa.h>
 #include <linux/llist.h>
+#include <linux/cma.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -44,6 +45,9 @@
 int hugetlb_max_hstate __read_mostly;
 unsigned int default_hstate_idx;
 struct hstate hstates[HUGE_MAX_HSTATE];
+
+static struct cma *hugetlb_cma[MAX_NUMNODES];
+
 /*
  * Minimum page order among possible hugepage sizes, set to a proper value
  * at boot time.
@@ -1228,6 +1232,14 @@ static void destroy_compound_gigantic_page(struct page *page,
 
 static void free_gigantic_page(struct page *page, unsigned int order)
 {
+       /*
+        * If the page isn't allocated using the cma allocator,
+        * cma_release() returns false.
+        */
+       if (IS_ENABLED(CONFIG_CMA) &&
+           cma_release(hugetlb_cma[page_to_nid(page)], page, 1 << order))
+               return;
+
        free_contig_range(page_to_pfn(page), 1 << order);
 }
 
@@ -1237,6 +1249,21 @@ static struct page *alloc_gigantic_page(struct hstate *h, gfp_t gfp_mask,
 {
        unsigned long nr_pages = 1UL << huge_page_order(h);
 
+       if (IS_ENABLED(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 (page)
+                               return page;
+               }
+       }
+
        return alloc_contig_pages(nr_pages, gfp_mask, nid, nodemask);
 }
 
@@ -1281,8 +1308,14 @@ static void update_and_free_page(struct hstate *h, struct page *page)
        set_compound_page_dtor(page, NULL_COMPOUND_DTOR);
        set_page_refcounted(page);
        if (hstate_is_gigantic(h)) {
+               /*
+                * Temporarily drop the hugetlb_lock, because
+                * we might block in free_gigantic_page().
+                */
+               spin_unlock(&hugetlb_lock);
                destroy_compound_gigantic_page(page, huge_page_order(h));
                free_gigantic_page(page, huge_page_order(h));
+               spin_lock(&hugetlb_lock);
        } else {
                __free_pages(page, huge_page_order(h));
        }
@@ -2539,6 +2572,10 @@ static void __init hugetlb_hstate_alloc_pages(struct hstate *h)
 
        for (i = 0; i < h->max_huge_pages; ++i) {
                if (hstate_is_gigantic(h)) {
+                       if (IS_ENABLED(CONFIG_CMA) && hugetlb_cma[0]) {
+                               pr_warn_once("HugeTLB: hugetlb_cma is enabled, skip boot time allocation\n");
+                               break;
+                       }
                        if (!alloc_bootmem_huge_page(h))
                                break;
                } else if (!alloc_pool_huge_page(h,
@@ -3194,6 +3231,7 @@ static int __init hugetlb_init(void)
                        default_hstate.max_huge_pages = default_hstate_max_huge_pages;
        }
 
+       hugetlb_cma_check();
        hugetlb_init_hstates();
        gather_bootmem_prealloc();
        report_hugepages();
@@ -5506,3 +5544,74 @@ void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason)
                spin_unlock(&hugetlb_lock);
        }
 }
+
+#ifdef CONFIG_CMA
+static unsigned long hugetlb_cma_size __initdata;
+static bool cma_reserve_called __initdata;
+
+static int __init cmdline_parse_hugetlb_cma(char *p)
+{
+       hugetlb_cma_size = memparse(p, &p);
+       return 0;
+}
+
+early_param("hugetlb_cma", cmdline_parse_hugetlb_cma);
+
+void __init hugetlb_cma_reserve(int order)
+{
+       unsigned long size, reserved, per_node;
+       int nid;
+
+       cma_reserve_called = true;
+
+       if (!hugetlb_cma_size)
+               return;
+
+       if (hugetlb_cma_size < (PAGE_SIZE << order)) {
+               pr_warn("hugetlb_cma: cma area should be at least %lu MiB\n",
+                       (PAGE_SIZE << order) / SZ_1M);
+               return;
+       }
+
+       /*
+        * If 3 GB area is requested on a machine with 4 numa nodes,
+        * let's allocate 1 GB on first three nodes and ignore the last one.
+        */
+       per_node = DIV_ROUND_UP(hugetlb_cma_size, nr_online_nodes);
+       pr_info("hugetlb_cma: reserve %lu MiB, up to %lu MiB per node\n",
+               hugetlb_cma_size / SZ_1M, per_node / SZ_1M);
+
+       reserved = 0;
+       for_each_node_state(nid, N_ONLINE) {
+               int res;
+
+               size = min(per_node, hugetlb_cma_size - reserved);
+               size = round_up(size, PAGE_SIZE << order);
+
+               res = cma_declare_contiguous_nid(0, size, 0, PAGE_SIZE << order,
+                                                0, false, "hugetlb",
+                                                &hugetlb_cma[nid], nid);
+               if (res) {
+                       pr_warn("hugetlb_cma: reservation failed: err %d, node %d",
+                               res, nid);
+                       continue;
+               }
+
+               reserved += size;
+               pr_info("hugetlb_cma: reserved %lu MiB on node %d\n",
+                       size / SZ_1M, nid);
+
+               if (reserved >= hugetlb_cma_size)
+                       break;
+       }
+}
+
+void __init hugetlb_cma_check(void)
+{
+       if (!hugetlb_cma_size || cma_reserve_called)
+               return;
+
+       pr_warn("hugetlb_cma: the option isn't supported by current arch\n");
+}
+
+#endif /* CONFIG_CMA */
index 4d06bba..c79ba6f 100644 (file)
@@ -1349,7 +1349,7 @@ __next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone,
  * Return:
  * Physical address of allocated memory block on success, %0 on failure.
  */
-static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size,
+phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size,
                                        phys_addr_t align, phys_addr_t start,
                                        phys_addr_t end, int nid,
                                        bool exact_nid)
index 05b4ec2..5beea03 100644 (file)
@@ -2336,6 +2336,9 @@ static unsigned long calculate_high_delay(struct mem_cgroup *memcg,
                usage = page_counter_read(&memcg->memory);
                high = READ_ONCE(memcg->high);
 
+               if (usage <= high)
+                       continue;
+
                /*
                 * Prevent division by 0 in overage calculation by acting as if
                 * it was a threshold of 1 page
index 19874d1..f703fe8 100644 (file)
@@ -1419,8 +1419,7 @@ void zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
 }
 EXPORT_SYMBOL_GPL(zap_vma_ptes);
 
-pte_t *__get_locked_pte(struct mm_struct *mm, unsigned long addr,
-                       spinlock_t **ptl)
+static pmd_t *walk_to_pmd(struct mm_struct *mm, unsigned long addr)
 {
        pgd_t *pgd;
        p4d_t *p4d;
@@ -1439,9 +1438,40 @@ pte_t *__get_locked_pte(struct mm_struct *mm, unsigned long addr,
                return NULL;
 
        VM_BUG_ON(pmd_trans_huge(*pmd));
+       return pmd;
+}
+
+pte_t *__get_locked_pte(struct mm_struct *mm, unsigned long addr,
+                       spinlock_t **ptl)
+{
+       pmd_t *pmd = walk_to_pmd(mm, addr);
+
+       if (!pmd)
+               return NULL;
        return pte_alloc_map_lock(mm, pmd, addr, ptl);
 }
 
+static int validate_page_before_insert(struct page *page)
+{
+       if (PageAnon(page) || PageSlab(page) || page_has_type(page))
+               return -EINVAL;
+       flush_dcache_page(page);
+       return 0;
+}
+
+static int insert_page_into_pte_locked(struct mm_struct *mm, pte_t *pte,
+                       unsigned long addr, struct page *page, pgprot_t prot)
+{
+       if (!pte_none(*pte))
+               return -EBUSY;
+       /* Ok, finally just insert the thing.. */
+       get_page(page);
+       inc_mm_counter_fast(mm, mm_counter_file(page));
+       page_add_file_rmap(page, false);
+       set_pte_at(mm, addr, pte, mk_pte(page, prot));
+       return 0;
+}
+
 /*
  * This is the old fallback for page remapping.
  *
@@ -1457,31 +1487,135 @@ static int insert_page(struct vm_area_struct *vma, unsigned long addr,
        pte_t *pte;
        spinlock_t *ptl;
 
-       retval = -EINVAL;
-       if (PageAnon(page) || PageSlab(page) || page_has_type(page))
+       retval = validate_page_before_insert(page);
+       if (retval)
                goto out;
        retval = -ENOMEM;
-       flush_dcache_page(page);
        pte = get_locked_pte(mm, addr, &ptl);
        if (!pte)
                goto out;
-       retval = -EBUSY;
-       if (!pte_none(*pte))
-               goto out_unlock;
-
-       /* Ok, finally just insert the thing.. */
-       get_page(page);
-       inc_mm_counter_fast(mm, mm_counter_file(page));
-       page_add_file_rmap(page, false);
-       set_pte_at(mm, addr, pte, mk_pte(page, prot));
-
-       retval = 0;
-out_unlock:
+       retval = insert_page_into_pte_locked(mm, pte, addr, page, prot);
        pte_unmap_unlock(pte, ptl);
 out:
        return retval;
 }
 
+#ifdef pte_index
+static int insert_page_in_batch_locked(struct mm_struct *mm, pmd_t *pmd,
+                       unsigned long addr, struct page *page, pgprot_t prot)
+{
+       int err;
+
+       if (!page_count(page))
+               return -EINVAL;
+       err = validate_page_before_insert(page);
+       return err ? err : insert_page_into_pte_locked(
+               mm, pte_offset_map(pmd, addr), addr, page, prot);
+}
+
+/* insert_pages() amortizes the cost of spinlock operations
+ * when inserting pages in a loop. Arch *must* define pte_index.
+ */
+static int insert_pages(struct vm_area_struct *vma, unsigned long addr,
+                       struct page **pages, unsigned long *num, pgprot_t prot)
+{
+       pmd_t *pmd = NULL;
+       spinlock_t *pte_lock = NULL;
+       struct mm_struct *const mm = vma->vm_mm;
+       unsigned long curr_page_idx = 0;
+       unsigned long remaining_pages_total = *num;
+       unsigned long pages_to_write_in_pmd;
+       int ret;
+more:
+       ret = -EFAULT;
+       pmd = walk_to_pmd(mm, addr);
+       if (!pmd)
+               goto out;
+
+       pages_to_write_in_pmd = min_t(unsigned long,
+               remaining_pages_total, PTRS_PER_PTE - pte_index(addr));
+
+       /* Allocate the PTE if necessary; takes PMD lock once only. */
+       ret = -ENOMEM;
+       if (pte_alloc(mm, pmd))
+               goto out;
+       pte_lock = pte_lockptr(mm, pmd);
+
+       while (pages_to_write_in_pmd) {
+               int pte_idx = 0;
+               const int batch_size = min_t(int, pages_to_write_in_pmd, 8);
+
+               spin_lock(pte_lock);
+               for (; pte_idx < batch_size; ++pte_idx) {
+                       int err = insert_page_in_batch_locked(mm, pmd,
+                               addr, pages[curr_page_idx], prot);
+                       if (unlikely(err)) {
+                               spin_unlock(pte_lock);
+                               ret = err;
+                               remaining_pages_total -= pte_idx;
+                               goto out;
+                       }
+                       addr += PAGE_SIZE;
+                       ++curr_page_idx;
+               }
+               spin_unlock(pte_lock);
+               pages_to_write_in_pmd -= batch_size;
+               remaining_pages_total -= batch_size;
+       }
+       if (remaining_pages_total)
+               goto more;
+       ret = 0;
+out:
+       *num = remaining_pages_total;
+       return ret;
+}
+#endif  /* ifdef pte_index */
+
+/**
+ * vm_insert_pages - insert multiple pages into user vma, batching the pmd lock.
+ * @vma: user vma to map to
+ * @addr: target start user address of these pages
+ * @pages: source kernel pages
+ * @num: in: number of pages to map. out: number of pages that were *not*
+ * mapped. (0 means all pages were successfully mapped).
+ *
+ * Preferred over vm_insert_page() when inserting multiple pages.
+ *
+ * In case of error, we may have mapped a subset of the provided
+ * pages. It is the caller's responsibility to account for this case.
+ *
+ * The same restrictions apply as in vm_insert_page().
+ */
+int vm_insert_pages(struct vm_area_struct *vma, unsigned long addr,
+                       struct page **pages, unsigned long *num)
+{
+#ifdef pte_index
+       const unsigned long end_addr = addr + (*num * PAGE_SIZE) - 1;
+
+       if (addr < vma->vm_start || end_addr >= vma->vm_end)
+               return -EFAULT;
+       if (!(vma->vm_flags & VM_MIXEDMAP)) {
+               BUG_ON(down_read_trylock(&vma->vm_mm->mmap_sem));
+               BUG_ON(vma->vm_flags & VM_PFNMAP);
+               vma->vm_flags |= VM_MIXEDMAP;
+       }
+       /* Defer page refcount checking till we're about to map that page. */
+       return insert_pages(vma, addr, pages, num, vma->vm_page_prot);
+#else
+       unsigned long idx = 0, pgcount = *num;
+       int err;
+
+       for (; idx < pgcount; ++idx) {
+               err = vm_insert_page(vma, addr + (PAGE_SIZE * idx), pages[idx]);
+               if (err)
+                       break;
+       }
+       *num = pgcount - idx;
+       return err;
+#endif  /* ifdef pte_index */
+}
+EXPORT_SYMBOL(vm_insert_pages);
+
 /**
  * vm_insert_page - insert single page into user vma
  * @vma: user vma to map to
index 635e8e2..fc0aad0 100644 (file)
@@ -304,12 +304,15 @@ static int check_hotplug_memory_addressable(unsigned long pfn,
  * add the new pages.
  */
 int __ref __add_pages(int nid, unsigned long pfn, unsigned long nr_pages,
-               struct mhp_restrictions *restrictions)
+               struct mhp_params *params)
 {
        const unsigned long end_pfn = pfn + nr_pages;
        unsigned long cur_nr_pages;
        int err;
-       struct vmem_altmap *altmap = restrictions->altmap;
+       struct vmem_altmap *altmap = params->altmap;
+
+       if (WARN_ON_ONCE(!params->pgprot.pgprot))
+               return -EINVAL;
 
        err = check_hotplug_memory_addressable(pfn, nr_pages);
        if (err)
@@ -1002,7 +1005,7 @@ static int online_memory_block(struct memory_block *mem, void *arg)
  */
 int __ref add_memory_resource(int nid, struct resource *res)
 {
-       struct mhp_restrictions restrictions = {};
+       struct mhp_params params = { .pgprot = PAGE_KERNEL };
        u64 start, size;
        bool new_node = false;
        int ret;
@@ -1030,7 +1033,7 @@ int __ref add_memory_resource(int nid, struct resource *res)
        new_node = ret;
 
        /* call arch's memory hotadd */
-       ret = arch_add_memory(nid, start, size, &restrictions);
+       ret = arch_add_memory(nid, start, size, &params);
        if (ret < 0)
                goto error;
 
index b4a039d..48ba972 100644 (file)
@@ -127,6 +127,32 @@ static struct mempolicy default_policy = {
 
 static struct mempolicy preferred_node_policy[MAX_NUMNODES];
 
+/**
+ * numa_map_to_online_node - Find closest online node
+ * @nid: Node id to start the search
+ *
+ * Lookup the next closest node by distance if @nid is not online.
+ */
+int numa_map_to_online_node(int node)
+{
+       int min_dist = INT_MAX, dist, n, min_node;
+
+       if (node == NUMA_NO_NODE || node_online(node))
+               return node;
+
+       min_node = node;
+       for_each_online_node(n) {
+               dist = node_distance(node, n);
+               if (dist < min_dist) {
+                       min_dist = dist;
+                       min_node = n;
+               }
+       }
+
+       return min_node;
+}
+EXPORT_SYMBOL_GPL(numa_map_to_online_node);
+
 struct mempolicy *get_task_policy(struct task_struct *p)
 {
        struct mempolicy *pol = p->mempolicy;
@@ -896,12 +922,15 @@ static void get_policy_nodemask(struct mempolicy *p, nodemask_t *nodes)
 
 static int lookup_node(struct mm_struct *mm, unsigned long addr)
 {
-       struct page *p;
+       struct page *p = NULL;
        int err;
 
        int locked = 1;
        err = get_user_pages_locked(addr & PAGE_MASK, 1, 0, &p, &locked);
-       if (err >= 0) {
+       if (err == 0) {
+               /* E.g. GUP interrupted by fatal signal */
+               err = -EFAULT;
+       } else if (err > 0) {
                err = page_to_nid(p);
                put_page(p);
        }
index 9b2c97c..03e38b7 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/mm.h>
 #include <linux/pfn_t.h>
 #include <linux/swap.h>
+#include <linux/mmzone.h>
 #include <linux/swapops.h>
 #include <linux/types.h>
 #include <linux/wait_bit.h>
 
 static DEFINE_XARRAY(pgmap_array);
 
+/*
+ * The memremap() and memremap_pages() interfaces are alternately used
+ * to map persistent memory namespaces. These interfaces place different
+ * constraints on the alignment and size of the mapping (namespace).
+ * memremap() can map individual PAGE_SIZE pages. memremap_pages() can
+ * only map subsections (2MB), and at least one architecture (PowerPC)
+ * the minimum mapping granularity of memremap_pages() is 16MB.
+ *
+ * The role of memremap_compat_align() is to communicate the minimum
+ * arch supported alignment of a namespace such that it can freely
+ * switch modes without violating the arch constraint. Namely, do not
+ * allow a namespace to be PAGE_SIZE aligned since that namespace may be
+ * reconfigured into a mode that requires SUBSECTION_SIZE alignment.
+ */
+#ifndef CONFIG_ARCH_HAS_MEMREMAP_COMPAT_ALIGN
+unsigned long memremap_compat_align(void)
+{
+       return SUBSECTION_SIZE;
+}
+EXPORT_SYMBOL_GPL(memremap_compat_align);
+#endif
+
 #ifdef CONFIG_DEV_PAGEMAP_OPS
 DEFINE_STATIC_KEY_FALSE(devmap_managed_key);
 EXPORT_SYMBOL(devmap_managed_key);
@@ -161,13 +184,13 @@ void *memremap_pages(struct dev_pagemap *pgmap, int nid)
 {
        struct resource *res = &pgmap->res;
        struct dev_pagemap *conflict_pgmap;
-       struct mhp_restrictions restrictions = {
+       struct mhp_params params = {
                /*
                 * We do not want any optional features only our own memmap
                 */
                .altmap = pgmap_altmap(pgmap),
+               .pgprot = PAGE_KERNEL,
        };
-       pgprot_t pgprot = PAGE_KERNEL;
        int error, is_ram;
        bool need_devmap_managed = true;
 
@@ -194,7 +217,10 @@ void *memremap_pages(struct dev_pagemap *pgmap, int nid)
                }
                break;
        case MEMORY_DEVICE_DEVDAX:
+               need_devmap_managed = false;
+               break;
        case MEMORY_DEVICE_PCI_P2PDMA:
+               params.pgprot = pgprot_noncached(params.pgprot);
                need_devmap_managed = false;
                break;
        default:
@@ -259,8 +285,8 @@ void *memremap_pages(struct dev_pagemap *pgmap, int nid)
        if (nid < 0)
                nid = numa_mem_id();
 
-       error = track_pfn_remap(NULL, &pgprot, PHYS_PFN(res->start), 0,
-                       resource_size(res));
+       error = track_pfn_remap(NULL, &params.pgprot, PHYS_PFN(res->start),
+                               0, resource_size(res));
        if (error)
                goto err_pfn_remap;
 
@@ -279,7 +305,7 @@ void *memremap_pages(struct dev_pagemap *pgmap, int nid)
         */
        if (pgmap->type == MEMORY_DEVICE_PRIVATE) {
                error = add_pages(nid, PHYS_PFN(res->start),
-                               PHYS_PFN(resource_size(res)), &restrictions);
+                               PHYS_PFN(resource_size(res)), &params);
        } else {
                error = kasan_add_zero_shadow(__va(res->start), resource_size(res));
                if (error) {
@@ -288,7 +314,7 @@ void *memremap_pages(struct dev_pagemap *pgmap, int nid)
                }
 
                error = arch_add_memory(nid, res->start, resource_size(res),
-                                       &restrictions);
+                                       &params);
        }
 
        if (!error) {
@@ -296,7 +322,7 @@ void *memremap_pages(struct dev_pagemap *pgmap, int nid)
 
                zone = &NODE_DATA(nid)->node_zones[ZONE_DEVICE];
                move_pfn_range_to_zone(zone, PHYS_PFN(res->start),
-                               PHYS_PFN(resource_size(res)), restrictions.altmap);
+                               PHYS_PFN(resource_size(res)), params.altmap);
        }
 
        mem_hotplug_done();
index 8d77dbb..f609e9e 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1224,7 +1224,7 @@ static int anon_vma_compatible(struct vm_area_struct *a, struct vm_area_struct *
        return a->vm_end == b->vm_start &&
                mpol_equal(vma_policy(a), vma_policy(b)) &&
                a->vm_file == b->vm_file &&
-               !((a->vm_flags ^ b->vm_flags) & ~(VM_READ|VM_WRITE|VM_EXEC|VM_SOFTDIRTY)) &&
+               !((a->vm_flags ^ b->vm_flags) & ~(VM_ACCESS_FLAGS | VM_SOFTDIRTY)) &&
                b->vm_pgoff == a->vm_pgoff + ((b->vm_start - a->vm_start) >> PAGE_SHIFT);
 }
 
@@ -2123,6 +2123,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
        info.low_limit = mm->mmap_base;
        info.high_limit = mmap_end;
        info.align_mask = 0;
+       info.align_offset = 0;
        return vm_unmapped_area(&info);
 }
 #endif
@@ -2164,6 +2165,7 @@ arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr,
        info.low_limit = max(PAGE_SIZE, mmap_min_addr);
        info.high_limit = arch_get_mmap_base(addr, mm->mmap_base);
        info.align_mask = 0;
+       info.align_offset = 0;
        addr = vm_unmapped_area(&info);
 
        /*
index 1d823b0..494192c 100644 (file)
@@ -419,7 +419,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
         */
        if (arch_has_pfn_modify_check() &&
            (vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP)) &&
-           (newflags & (VM_READ|VM_WRITE|VM_EXEC)) == 0) {
+           (newflags & VM_ACCESS_FLAGS) == 0) {
                pgprot_t new_pgprot = vm_get_page_prot(newflags);
 
                error = walk_page_range(current->mm, start, end,
@@ -598,7 +598,7 @@ static int do_mprotect_pkey(unsigned long start, size_t len,
                newflags |= (vma->vm_flags & ~mask_off_old_flags);
 
                /* newflags >> 4 shift VM_MAY% in place of VM_% */
-               if ((newflags & ~(newflags >> 4)) & (VM_READ | VM_WRITE | VM_EXEC)) {
+               if ((newflags & ~(newflags >> 4)) & VM_ACCESS_FLAGS) {
                        error = -EACCES;
                        goto out;
                }
index 114c56c..69827d4 100644 (file)
@@ -103,8 +103,8 @@ struct pcpu_drain {
        struct zone *zone;
        struct work_struct work;
 };
-DEFINE_MUTEX(pcpu_drain_mutex);
-DEFINE_PER_CPU(struct pcpu_drain, pcpu_drain);
+static DEFINE_MUTEX(pcpu_drain_mutex);
+static DEFINE_PER_CPU(struct pcpu_drain, pcpu_drain);
 
 #ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY
 volatile unsigned long latent_entropy __latent_entropy;
@@ -3224,6 +3224,7 @@ int __isolate_free_page(struct page *page, unsigned int order)
  * __putback_isolated_page - Return a now-isolated page back where we got it
  * @page: Page that was isolated
  * @order: Order of the isolated page
+ * @mt: The page's pageblock's migratetype
  *
  * This function is meant to return a page pulled from the free lists via
  * __isolate_free_page back to the free lists they were pulled from.
index 93ec4a5..23c7500 100644 (file)
@@ -731,7 +731,7 @@ static void kmemcg_rcufn(struct rcu_head *head)
        /*
         * We need to grab blocking locks.  Bounce to ->work.  The
         * work item shares the space with the RCU head and can't be
-        * initialized eariler.
+        * initialized earlier.
         */
        INIT_WORK(&s->memcg_params.work, kmemcg_workfn);
        queue_work(memcg_kmem_cache_wq, &s->memcg_params.work);
index 7cb992e..1344f23 100644 (file)
@@ -383,11 +383,11 @@ static int client_options_show(struct seq_file *s, void *p)
        return 0;
 }
 
-CEPH_DEFINE_SHOW_FUNC(monmap_show)
-CEPH_DEFINE_SHOW_FUNC(osdmap_show)
-CEPH_DEFINE_SHOW_FUNC(monc_show)
-CEPH_DEFINE_SHOW_FUNC(osdc_show)
-CEPH_DEFINE_SHOW_FUNC(client_options_show)
+DEFINE_SHOW_ATTRIBUTE(monmap);
+DEFINE_SHOW_ATTRIBUTE(osdmap);
+DEFINE_SHOW_ATTRIBUTE(monc);
+DEFINE_SHOW_ATTRIBUTE(osdc);
+DEFINE_SHOW_ATTRIBUTE(client_options);
 
 void __init ceph_debugfs_init(void)
 {
@@ -414,31 +414,31 @@ void ceph_debugfs_client_init(struct ceph_client *client)
                                                      0400,
                                                      client->debugfs_dir,
                                                      client,
-                                                     &monc_show_fops);
+                                                     &monc_fops);
 
        client->osdc.debugfs_file = debugfs_create_file("osdc",
                                                      0400,
                                                      client->debugfs_dir,
                                                      client,
-                                                     &osdc_show_fops);
+                                                     &osdc_fops);
 
        client->debugfs_monmap = debugfs_create_file("monmap",
                                        0400,
                                        client->debugfs_dir,
                                        client,
-                                       &monmap_show_fops);
+                                       &monmap_fops);
 
        client->debugfs_osdmap = debugfs_create_file("osdmap",
                                        0400,
                                        client->debugfs_dir,
                                        client,
-                                       &osdmap_show_fops);
+                                       &osdmap_fops);
 
        client->debugfs_options = debugfs_create_file("client_options",
                                        0400,
                                        client->debugfs_dir,
                                        client,
-                                       &client_options_show_fops);
+                                       &client_options_fops);
 }
 
 void ceph_debugfs_client_cleanup(struct ceph_client *client)
index 9d9e4e4..3d8c801 100644 (file)
@@ -467,7 +467,7 @@ static void ceph_monc_handle_map(struct ceph_mon_client *monc,
                                 struct ceph_msg *msg)
 {
        struct ceph_client *client = monc->client;
-       struct ceph_monmap *monmap = NULL, *old = monc->monmap;
+       struct ceph_monmap *monmap;
        void *p, *end;
 
        mutex_lock(&monc->mutex);
@@ -484,13 +484,13 @@ static void ceph_monc_handle_map(struct ceph_mon_client *monc,
                goto out;
        }
 
-       if (ceph_check_fsid(monc->client, &monmap->fsid) < 0) {
+       if (ceph_check_fsid(client, &monmap->fsid) < 0) {
                kfree(monmap);
                goto out;
        }
 
-       client->monc.monmap = monmap;
-       kfree(old);
+       kfree(monc->monmap);
+       monc->monmap = monmap;
 
        __ceph_monc_got_map(monc, CEPH_SUB_MONMAP, monc->monmap->epoch);
        client->have_fsid = true;
index af868d3..998e26b 100644 (file)
@@ -3483,9 +3483,6 @@ static int ceph_redirect_decode(void **p, void *end,
                goto e_inval;
        }
 
-       len = ceph_decode_32(p);
-       *p += len; /* skip osd_instructions */
-
        /* skip the rest */
        *p = struct_end;
 out:
@@ -5228,85 +5225,6 @@ void ceph_osdc_stop(struct ceph_osd_client *osdc)
        ceph_msgpool_destroy(&osdc->msgpool_op_reply);
 }
 
-/*
- * Read some contiguous pages.  If we cross a stripe boundary, shorten
- * *plen.  Return number of bytes read, or error.
- */
-int ceph_osdc_readpages(struct ceph_osd_client *osdc,
-                       struct ceph_vino vino, struct ceph_file_layout *layout,
-                       u64 off, u64 *plen,
-                       u32 truncate_seq, u64 truncate_size,
-                       struct page **pages, int num_pages, int page_align)
-{
-       struct ceph_osd_request *req;
-       int rc = 0;
-
-       dout("readpages on ino %llx.%llx on %llu~%llu\n", vino.ino,
-            vino.snap, off, *plen);
-       req = ceph_osdc_new_request(osdc, layout, vino, off, plen, 0, 1,
-                                   CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ,
-                                   NULL, truncate_seq, truncate_size,
-                                   false);
-       if (IS_ERR(req))
-               return PTR_ERR(req);
-
-       /* it may be a short read due to an object boundary */
-       osd_req_op_extent_osd_data_pages(req, 0,
-                               pages, *plen, page_align, false, false);
-
-       dout("readpages  final extent is %llu~%llu (%llu bytes align %d)\n",
-            off, *plen, *plen, page_align);
-
-       rc = ceph_osdc_start_request(osdc, req, false);
-       if (!rc)
-               rc = ceph_osdc_wait_request(osdc, req);
-
-       ceph_osdc_put_request(req);
-       dout("readpages result %d\n", rc);
-       return rc;
-}
-EXPORT_SYMBOL(ceph_osdc_readpages);
-
-/*
- * do a synchronous write on N pages
- */
-int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino,
-                        struct ceph_file_layout *layout,
-                        struct ceph_snap_context *snapc,
-                        u64 off, u64 len,
-                        u32 truncate_seq, u64 truncate_size,
-                        struct timespec64 *mtime,
-                        struct page **pages, int num_pages)
-{
-       struct ceph_osd_request *req;
-       int rc = 0;
-       int page_align = off & ~PAGE_MASK;
-
-       req = ceph_osdc_new_request(osdc, layout, vino, off, &len, 0, 1,
-                                   CEPH_OSD_OP_WRITE, CEPH_OSD_FLAG_WRITE,
-                                   snapc, truncate_seq, truncate_size,
-                                   true);
-       if (IS_ERR(req))
-               return PTR_ERR(req);
-
-       /* it may be a short write due to an object boundary */
-       osd_req_op_extent_osd_data_pages(req, 0, pages, len, page_align,
-                               false, false);
-       dout("writepages %llu~%llu (%llu bytes)\n", off, len, len);
-
-       req->r_mtime = *mtime;
-       rc = ceph_osdc_start_request(osdc, req, true);
-       if (!rc)
-               rc = ceph_osdc_wait_request(osdc, req);
-
-       ceph_osdc_put_request(req);
-       if (rc == 0)
-               rc = len;
-       dout("writepages result %d\n", rc);
-       return rc;
-}
-EXPORT_SYMBOL(ceph_osdc_writepages);
-
 static int osd_req_op_copy_from_init(struct ceph_osd_request *req,
                                     u64 src_snapid, u64 src_version,
                                     struct ceph_object_id *src_oid,
index 292e71d..0e0ded8 100644 (file)
@@ -83,7 +83,7 @@ nf_tables-objs := nf_tables_core.o nf_tables_api.o nft_chain_filter.o \
                  nft_set_pipapo.o
 
 ifdef CONFIG_X86_64
-ifneq (,$(findstring -DCONFIG_AS_AVX2=1,$(KBUILD_CFLAGS)))
+ifndef CONFIG_UML
 nf_tables-objs += nft_set_pipapo_avx2.o
 endif
 endif
index 9adfbc7..9780bd9 100644 (file)
@@ -3291,7 +3291,7 @@ static const struct nft_set_type *nft_set_types[] = {
        &nft_set_rhash_type,
        &nft_set_bitmap_type,
        &nft_set_rbtree_type,
-#if defined(CONFIG_X86_64) && defined(CONFIG_AS_AVX2)
+#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
        &nft_set_pipapo_avx2_type,
 #endif
        &nft_set_pipapo_type,
index 87aabf6..8b5acc6 100644 (file)
@@ -2201,7 +2201,7 @@ const struct nft_set_type nft_set_pipapo_type = {
        },
 };
 
-#if defined(CONFIG_X86_64) && defined(CONFIG_AS_AVX2)
+#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
 const struct nft_set_type nft_set_pipapo_avx2_type = {
        .features       = NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_OBJECT |
                          NFT_SET_TIMEOUT,
index 396caf7..394bcb7 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 #ifndef _NFT_SET_PIPAPO_AVX2_H
 
-#ifdef CONFIG_AS_AVX2
+#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
 #include <asm/fpu/xstate.h>
 #define NFT_PIPAPO_ALIGN       (XSAVE_YMM_SIZE / BITS_PER_BYTE)
 
@@ -9,6 +9,6 @@ bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
                            const u32 *key, const struct nft_set_ext **ext);
 bool nft_pipapo_avx2_estimate(const struct nft_set_desc *desc, u32 features,
                              struct nft_set_estimate *est);
-#endif /* CONFIG_AS_AVX2 */
+#endif /* defined(CONFIG_X86_64) && !defined(CONFIG_UML) */
 
 #endif /* _NFT_SET_PIPAPO_AVX2_H */
index 8074f14..c264da2 100644 (file)
@@ -48,9 +48,6 @@ $(error-if,$(failure,command -v $(LD)),linker '$(LD)' not found)
 # Fail if the linker is gold as it's not capable of linking the kernel proper
 $(error-if,$(success, $(LD) -v | grep -q gold), gold linker '$(LD)' not supported)
 
-# gcc version including patch level
-gcc-version := $(shell,$(srctree)/scripts/gcc-version.sh $(CC))
-
 # machine bit flags
 #  $(m32-flag): -m32 if the compiler supports it, or an empty string otherwise.
 #  $(m64-flag): -m64 if the compiler supports it, or an empty string otherwise.
index 5e75802..95ecf97 100644 (file)
@@ -2,10 +2,6 @@
 ###
 # scripts contains sources for various helper programs used throughout
 # the kernel for the build process.
-# ---------------------------------------------------------------------------
-# kallsyms:      Find all symbols in vmlinux
-
-HOST_EXTRACFLAGS += -I$(srctree)/tools/include
 
 always-$(CONFIG_BUILD_BIN2C)                   += bin2c
 always-$(CONFIG_KALLSYMS)                      += kallsyms
index a1730d4..9fcbfac 100644 (file)
@@ -46,7 +46,7 @@ include $(kbuild-file)
 include scripts/Makefile.lib
 
 # Do not include host rules unless needed
-ifneq ($(hostprogs)$(hostlibs-y)$(hostlibs-m)$(hostcxxlibs-y)$(hostcxxlibs-m),)
+ifneq ($(hostprogs)$(hostcxxlibs-y)$(hostcxxlibs-m),)
 include scripts/Makefile.host
 endif
 
@@ -65,7 +65,6 @@ endif
 
 ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
 lib-target := $(obj)/lib.a
-real-obj-y += $(obj)/lib-ksyms.o
 endif
 
 ifdef need-builtin
@@ -410,22 +409,6 @@ $(lib-target): $(lib-y) FORCE
 
 targets += $(lib-target)
 
-dummy-object = $(obj)/.lib_exports.o
-ksyms-lds = $(dot-target).lds
-
-quiet_cmd_export_list = EXPORTS $@
-cmd_export_list = $(OBJDUMP) -h $< | \
-       sed -ne '/___ksymtab/s/.*+\([^ ]*\).*/EXTERN(\1)/p' >$(ksyms-lds);\
-       rm -f $(dummy-object);\
-       echo | $(CC) $(a_flags) -c -o $(dummy-object) -x assembler -;\
-       $(LD) $(ld_flags) -r -o $@ -T $(ksyms-lds) $(dummy-object);\
-       rm $(dummy-object) $(ksyms-lds)
-
-$(obj)/lib-ksyms.o: $(lib-target) FORCE
-       $(call if_changed,export_list)
-
-targets += $(obj)/lib-ksyms.o
-
 endif
 
 # NOTE:
index 1e42065..075f0cc 100644 (file)
@@ -30,7 +30,6 @@ subdir-ymn    := $(addprefix $(obj)/,$(subdir-ymn))
 __clean-files  := $(extra-y) $(extra-m) $(extra-)       \
                   $(always) $(always-y) $(always-m) $(always-) $(targets) $(clean-files)   \
                   $(hostprogs) $(hostprogs-y) $(hostprogs-m) $(hostprogs-) \
-                  $(hostlibs-y) $(hostlibs-m) $(hostlibs-) \
                   $(hostcxxlibs-y) $(hostcxxlibs-m)
 
 __clean-files   := $(filter-out $(no-clean-files), $(__clean-files))
index ca08f2f..4aea7cf 100644 (file)
@@ -49,6 +49,7 @@ KBUILD_CFLAGS += -Wno-format
 KBUILD_CFLAGS += -Wno-sign-compare
 KBUILD_CFLAGS += -Wno-format-zero-length
 KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast)
+KBUILD_CFLAGS += -Wno-tautological-constant-out-of-range-compare
 endif
 
 endif
index 3b7121d..2045855 100644 (file)
@@ -39,7 +39,6 @@ $(obj)/%.tab.c $(obj)/%.tab.h: $(src)/%.y FORCE
 # They are linked as C++ code to the executable qconf
 
 __hostprogs := $(sort $(hostprogs))
-host-cshlib := $(sort $(hostlibs-y) $(hostlibs-m))
 host-cxxshlib := $(sort $(hostcxxlibs-y) $(hostcxxlibs-m))
 
 # C code
@@ -63,7 +62,6 @@ host-cxxmulti := $(foreach m,$(__hostprogs),$(if $($(m)-cxxobjs),$(m)))
 host-cxxobjs   := $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs)))
 
 # Object (.o) files used by the shared libaries
-host-cshobjs   := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs))))
 host-cxxshobjs := $(sort $(foreach m,$(host-cxxshlib),$($(m:.so=-objs))))
 
 host-csingle   := $(addprefix $(obj)/,$(host-csingle))
@@ -71,9 +69,7 @@ host-cmulti   := $(addprefix $(obj)/,$(host-cmulti))
 host-cobjs     := $(addprefix $(obj)/,$(host-cobjs))
 host-cxxmulti  := $(addprefix $(obj)/,$(host-cxxmulti))
 host-cxxobjs   := $(addprefix $(obj)/,$(host-cxxobjs))
-host-cshlib    := $(addprefix $(obj)/,$(host-cshlib))
 host-cxxshlib  := $(addprefix $(obj)/,$(host-cxxshlib))
-host-cshobjs   := $(addprefix $(obj)/,$(host-cshobjs))
 host-cxxshobjs := $(addprefix $(obj)/,$(host-cxxshobjs))
 
 #####
@@ -141,13 +137,6 @@ $(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE
        $(call if_changed_dep,host-cxxobjs)
 
 # Compile .c file, create position independent .o file
-# host-cshobjs -> .o
-quiet_cmd_host-cshobjs = HOSTCC  -fPIC $@
-      cmd_host-cshobjs = $(HOSTCC) $(hostc_flags) -fPIC -c -o $@ $<
-$(host-cshobjs): $(obj)/%.o: $(src)/%.c FORCE
-       $(call if_changed_dep,host-cshobjs)
-
-# Compile .c file, create position independent .o file
 # Note that plugin capable gcc versions can be either C or C++ based
 # therefore plugin source files have to be compilable in both C and C++ mode.
 # This is why a C++ compiler is invoked on a .c file.
@@ -158,16 +147,6 @@ $(host-cxxshobjs): $(obj)/%.o: $(src)/%.c FORCE
        $(call if_changed_dep,host-cxxshobjs)
 
 # Link a shared library, based on position independent .o files
-# *.o -> .so shared library (host-cshlib)
-quiet_cmd_host-cshlib  = HOSTLLD -shared $@
-      cmd_host-cshlib  = $(HOSTCC) $(KBUILD_HOSTLDFLAGS) -shared -o $@ \
-                         $(addprefix $(obj)/, $($(target-stem)-objs)) \
-                         $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem).so)
-$(host-cshlib): FORCE
-       $(call if_changed,host-cshlib)
-$(call multi_depend, $(host-cshlib), .so, -objs)
-
-# Link a shared library, based on position independent .o files
 # *.o -> .so shared library (host-cxxshlib)
 quiet_cmd_host-cxxshlib        = HOSTLLD -shared $@
       cmd_host-cxxshlib        = $(HOSTCXX) $(KBUILD_HOSTLDFLAGS) -shared -o $@ \
@@ -178,4 +157,4 @@ $(host-cxxshlib): FORCE
 $(call multi_depend, $(host-cxxshlib), .so, -objs)
 
 targets += $(host-csingle)  $(host-cmulti) $(host-cobjs)\
-          $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs) $(host-cxxshlib) $(host-cxxshobjs)
+          $(host-cxxmulti) $(host-cxxobjs) $(host-cxxshlib) $(host-cxxshobjs)
diff --git a/scripts/dummy-tools/gcc b/scripts/dummy-tools/gcc
new file mode 100755 (executable)
index 0000000..33487e9
--- /dev/null
@@ -0,0 +1,91 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Staring v4.18, Kconfig evaluates compiler capabilities, and hides CONFIG
+# options your compiler does not support. This works well if you configure and
+# build the kernel on the same host machine.
+#
+# It is inconvenient if you prepare the .config that is carried to a different
+# build environment (typically this happens when you package the kernel for
+# distros) because using a different compiler potentially produces different
+# CONFIG options than the real build environment. So, you probably want to make
+# as many options visible as possible. In other words, you need to create a
+# super-set of CONFIG options that cover any build environment. If some of the
+# CONFIG options turned out to be unsupported on the build machine, they are
+# automatically disabled by the nature of Kconfig.
+#
+# However, it is not feasible to get a full-featured compiler for every arch.
+# Hence these dummy toolchains to make all compiler tests pass.
+#
+# Usage:
+#
+# From the top directory of the source tree, run
+#
+#   $ make CROSS_COMPILE=scripts/dummy-tools/ oldconfig
+#
+# Most of compiler features are tested by cc-option, which simply checks the
+# exit code of $(CC). This script does nothing and just exits with 0 in most
+# cases. So, $(cc-option, ...) is evaluated as 'y'.
+#
+# This scripts caters to more checks; handle --version and pre-process __GNUC__
+# etc. to pretend to be GCC, and also do right things to satisfy some scripts.
+
+# Check if the first parameter appears in the rest. Succeeds if found.
+# This helper is useful if a particular option was passed to this script.
+# Typically used like this:
+#   arg_contain <word-you-are-searching-for> "$@"
+arg_contain ()
+{
+       search="$1"
+       shift
+
+       while [ $# -gt 0 ]
+       do
+               if [ "$search" = "$1" ]; then
+                       return 0
+               fi
+               shift
+       done
+
+       return 1
+}
+
+# To set CONFIG_CC_IS_GCC=y
+if arg_contain --version "$@"; then
+       echo "gcc (scripts/dummy-tools/gcc)"
+       exit 0
+fi
+
+if arg_contain -E "$@"; then
+       # For scripts/gcc-version.sh; This emulates GCC 20.0.0
+       if arg_contain - "$@"; then
+               sed 's/^__GNUC__$/20/; s/^__GNUC_MINOR__$/0/; s/^__GNUC_PATCHLEVEL__$/0/'
+               exit 0
+       else
+               echo "no input files" >&2
+               exit 1
+       fi
+fi
+
+if arg_contain -S "$@"; then
+       # For scripts/gcc-x86-*-has-stack-protector.sh
+       if arg_contain -fstack-protector "$@"; then
+               echo "%gs"
+               exit 0
+       fi
+fi
+
+# For scripts/gcc-plugin.sh
+if arg_contain -print-file-name=plugin "$@"; then
+       plugin_dir=$(mktemp -d)
+
+       sed -n 's/.*#include "\(.*\)"/\1/p' $(dirname $0)/../gcc-plugins/gcc-common.h |
+       while read header
+       do
+               mkdir -p $plugin_dir/include/$(dirname $header)
+               touch $plugin_dir/include/$header
+       done
+
+       echo $plugin_dir
+       exit 0
+fi
diff --git a/scripts/dummy-tools/ld b/scripts/dummy-tools/ld
new file mode 100755 (executable)
index 0000000..f682330
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+
+# Dummy script that always succeeds.
+
+# Check if the first parameter appears in the rest. Succeeds if found.
+# This helper is useful if a particular option was passed to this script.
+# Typically used like this:
+#   arg_contain <word-you-are-searching-for> "$@"
+arg_contain ()
+{
+       search="$1"
+       shift
+
+       while [ $# -gt 0 ]
+       do
+               if [ "$search" = "$1" ]; then
+                       return 0
+               fi
+               shift
+       done
+
+       return 1
+}
+
+if arg_contain --version "$@" || arg_contain -v "$@"; then
+       progname=$(basename $0)
+       echo "GNU $progname (scripts/dummy-tools/$progname) 2.50"
+       exit 0
+fi
diff --git a/scripts/dummy-tools/nm b/scripts/dummy-tools/nm
new file mode 120000 (symlink)
index 0000000..c0648b3
--- /dev/null
@@ -0,0 +1 @@
+ld
\ No newline at end of file
diff --git a/scripts/dummy-tools/objcopy b/scripts/dummy-tools/objcopy
new file mode 120000 (symlink)
index 0000000..c0648b3
--- /dev/null
@@ -0,0 +1 @@
+ld
\ No newline at end of file
index d3caefe..b79fd0b 100755 (executable)
@@ -1,49 +1,14 @@
 #!/bin/sh
 # SPDX-License-Identifier: GPL-2.0
-srctree=$(dirname "$0")
-
-SHOW_ERROR=
-if [ "$1" = "--show-error" ] ; then
-       SHOW_ERROR=1
-       shift || true
-fi
-
-gccplugins_dir=$($3 -print-file-name=plugin)
-plugincc=$($1 -E -x c++ - -o /dev/null -I"${srctree}"/gcc-plugins -I"${gccplugins_dir}"/include 2>&1 <<EOF
-#include "gcc-common.h"
-#if BUILDING_GCC_VERSION >= 4008 || defined(ENABLE_BUILD_WITH_CXX)
-#warning $2 CXX
-#else
-#warning $1 CC
-#endif
-EOF
-)
 
-if [ $? -ne 0 ]
-then
-       if [ -n "$SHOW_ERROR" ] ; then
-               echo "${plugincc}" >&2
-       fi
-       exit 1
-fi
+set -e
 
-case "$plugincc" in
-       *"$1 CC"*)
-               echo "$1"
-               exit 0
-               ;;
-
-       *"$2 CXX"*)
-               # the c++ compiler needs another test, see below
-               ;;
+srctree=$(dirname "$0")
 
-       *)
-               exit 1
-               ;;
-esac
+gccplugins_dir=$($* -print-file-name=plugin)
 
 # we need a c++ compiler that supports the designated initializer GNU extension
-plugincc=$($2 -c -x c++ -std=gnu++98 - -fsyntax-only -I"${srctree}"/gcc-plugins -I"${gccplugins_dir}"/include 2>&1 <<EOF
+$HOSTCC -c -x c++ -std=gnu++98 - -fsyntax-only -I $srctree/gcc-plugins -I $gccplugins_dir/include 2>/dev/null <<EOF
 #include "gcc-common.h"
 class test {
 public:
@@ -52,15 +17,3 @@ public:
        .test = 1
 };
 EOF
-)
-
-if [ $? -eq 0 ]
-then
-       echo "$2"
-       exit 0
-fi
-
-if [ -n "$SHOW_ERROR" ] ; then
-       echo "${plugincc}" >&2
-fi
-exit 1
index f8ca236..013ba3a 100644 (file)
@@ -1,13 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-preferred-plugin-hostcc := $(if-success,[ $(gcc-version) -ge 40800 ],$(HOSTCXX),$(HOSTCC))
-
-config PLUGIN_HOSTCC
-       string
-       default "$(shell,$(srctree)/scripts/gcc-plugin.sh "$(preferred-plugin-hostcc)" "$(HOSTCXX)" "$(CC)")" if CC_IS_GCC
-       help
-         Host compiler used to build GCC plugins.  This can be $(HOSTCXX),
-         $(HOSTCC), or a null string if GCC plugin is unsupported.
-
 config HAVE_GCC_PLUGINS
        bool
        help
@@ -17,7 +8,8 @@ config HAVE_GCC_PLUGINS
 menuconfig GCC_PLUGINS
        bool "GCC plugins"
        depends on HAVE_GCC_PLUGINS
-       depends on PLUGIN_HOSTCC != ""
+       depends on CC_IS_GCC && GCC_VERSION >= 40800
+       depends on $(success,$(srctree)/scripts/gcc-plugin.sh $(CC))
        default y
        help
          GCC plugins are loadable modules that provide extra features to the
index efff009..f22858b 100644 (file)
@@ -1,18 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0
-PLUGINCC := $(CONFIG_PLUGIN_HOSTCC:"%"=%)
 GCC_PLUGINS_DIR := $(shell $(CC) -print-file-name=plugin)
 
-ifeq ($(PLUGINCC),$(HOSTCC))
-  HOSTLIBS := hostlibs
-  HOST_EXTRACFLAGS += -I$(GCC_PLUGINS_DIR)/include -I$(src) -std=gnu99 -ggdb
-  export HOST_EXTRACFLAGS
-else
-  HOSTLIBS := hostcxxlibs
-  HOST_EXTRACXXFLAGS += -I$(GCC_PLUGINS_DIR)/include -I$(src) -std=gnu++98 -fno-rtti
-  HOST_EXTRACXXFLAGS += -fno-exceptions -fasynchronous-unwind-tables -ggdb
-  HOST_EXTRACXXFLAGS += -Wno-narrowing -Wno-unused-variable -Wno-c++11-compat
-  export HOST_EXTRACXXFLAGS
-endif
+HOST_EXTRACXXFLAGS += -I$(GCC_PLUGINS_DIR)/include -I$(src) -std=gnu++98 -fno-rtti
+HOST_EXTRACXXFLAGS += -fno-exceptions -fasynchronous-unwind-tables -ggdb
+HOST_EXTRACXXFLAGS += -Wno-narrowing -Wno-unused-variable -Wno-c++11-compat
 
 $(obj)/randomize_layout_plugin.o: $(objtree)/$(obj)/randomize_layout_seed.h
 quiet_cmd_create_randomize_layout_seed = GENSEED $@
@@ -22,9 +13,9 @@ $(objtree)/$(obj)/randomize_layout_seed.h: FORCE
        $(call if_changed,create_randomize_layout_seed)
 targets = randomize_layout_seed.h randomize_layout_hash.h
 
-$(HOSTLIBS)-y := $(foreach p,$(GCC_PLUGIN),$(if $(findstring /,$(p)),,$(p)))
-always-y := $($(HOSTLIBS)-y)
+hostcxxlibs-y := $(foreach p,$(GCC_PLUGIN),$(if $(findstring /,$(p)),,$(p)))
+always-y := $(hostcxxlibs-y)
 
-$(foreach p,$($(HOSTLIBS)-y:%.so=%),$(eval $(p)-objs := $(p).o))
+$(foreach p,$(hostcxxlibs-y:%.so=%),$(eval $(p)-objs := $(p).o))
 
 clean-files += *.so
index 50a5245..c0ac8f7 100644 (file)
@@ -154,9 +154,9 @@ void ConfigItem::updateMenu(void)
 
                if (!sym_is_changeable(sym) && list->optMode == normalOpt) {
                        setPixmap(promptColIdx, QIcon());
-                       setText(noColIdx, QString::null);
-                       setText(modColIdx, QString::null);
-                       setText(yesColIdx, QString::null);
+                       setText(noColIdx, QString());
+                       setText(modColIdx, QString());
+                       setText(yesColIdx, QString());
                        break;
                }
                expr = sym_get_tristate_value(sym);
@@ -276,7 +276,7 @@ void ConfigLineEdit::show(ConfigItem* i)
        if (sym_get_string_value(item->menu->sym))
                setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
        else
-               setText(QString::null);
+               setText(QString());
        Parent::show();
        setFocus();
 }
@@ -316,7 +316,10 @@ ConfigList::ConfigList(ConfigView* p, const char *name)
        setVerticalScrollMode(ScrollPerPixel);
        setHorizontalScrollMode(ScrollPerPixel);
 
-       setHeaderLabels(QStringList() << "Option" << "Name" << "N" << "M" << "Y" << "Value");
+       if (mode == symbolMode)
+               setHeaderLabels(QStringList() << "Item" << "Name" << "N" << "M" << "Y" << "Value");
+       else
+               setHeaderLabels(QStringList() << "Option" << "Name" << "N" << "M" << "Y" << "Value");
 
        connect(this, SIGNAL(itemSelectionChanged(void)),
                SLOT(updateSelection(void)));
@@ -397,6 +400,11 @@ void ConfigList::updateSelection(void)
        struct menu *menu;
        enum prop_type type;
 
+       if (mode == symbolMode)
+               setHeaderLabels(QStringList() << "Item" << "Name" << "N" << "M" << "Y" << "Value");
+       else
+               setHeaderLabels(QStringList() << "Option" << "Name" << "N" << "M" << "Y" << "Value");
+
        if (selectedItems().count() == 0)
                return;
 
@@ -625,7 +633,7 @@ void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
                        last = item;
                        continue;
                }
-       hide:
+hide:
                if (item && item->menu == child) {
                        last = parent->firstChild();
                        if (last == item)
@@ -690,7 +698,7 @@ void ConfigList::updateMenuList(ConfigList *parent, struct menu* menu)
                        last = item;
                        continue;
                }
-       hide:
+hide:
                if (item && item->menu == child) {
                        last = (ConfigItem*)parent->topLevelItem(0);
                        if (last == item)
@@ -734,7 +742,10 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
                type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
                if (type == P_MENU && rootEntry != menu &&
                    mode != fullMode && mode != menuMode) {
-                       emit menuSelected(menu);
+                       if (mode == menuMode)
+                               emit menuSelected(menu);
+                       else
+                               emit itemSelected(menu);
                        break;
                }
        case Qt::Key_Space:
@@ -826,7 +837,7 @@ void ConfigList::mouseMoveEvent(QMouseEvent* e)
 
 void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
 {
-       QPoint p = e->pos(); // TODO: Check if this works(was contentsToViewport).
+       QPoint p = e->pos();
        ConfigItem* item = (ConfigItem*)itemAt(p);
        struct menu *menu;
        enum prop_type ptype;
@@ -841,9 +852,12 @@ void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
        if (!menu)
                goto skip;
        ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
-       if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
-               emit menuSelected(menu);
-       else if (menu->sym)
+       if (ptype == P_MENU) {
+               if (mode == singleMode)
+                       emit itemSelected(menu);
+               else if (mode == symbolMode)
+                       emit menuSelected(menu);
+       } else if (menu->sym)
                changeValue(item);
 
 skip:
@@ -1223,10 +1237,11 @@ QMenu* ConfigInfoView::createStandardContextMenu(const QPoint & pos)
 {
        QMenu* popup = Parent::createStandardContextMenu(pos);
        QAction* action = new QAction("Show Debug Info", popup);
-         action->setCheckable(true);
-         connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
-         connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
-         action->setChecked(showDebug());
+
+       action->setCheckable(true);
+       connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
+       connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
+       action->setChecked(showDebug());
        popup->addSeparator();
        popup->addAction(action);
        return popup;
@@ -1352,21 +1367,32 @@ ConfigMainWindow::ConfigMainWindow(void)
        if ((x.isValid())&&(y.isValid()))
                move(x.toInt(), y.toInt());
 
-       split1 = new QSplitter(this);
+       QWidget *widget = new QWidget(this);
+       QVBoxLayout *layout = new QVBoxLayout(widget);
+       setCentralWidget(widget);
+
+       split1 = new QSplitter(widget);
        split1->setOrientation(Qt::Horizontal);
-       setCentralWidget(split1);
+       split1->setChildrenCollapsible(false);
 
-       menuView = new ConfigView(split1, "menu");
+       menuView = new ConfigView(widget, "menu");
        menuList = menuView->list;
 
-       split2 = new QSplitter(split1);
+       split2 = new QSplitter(widget);
+       split2->setChildrenCollapsible(false);
        split2->setOrientation(Qt::Vertical);
 
        // create config tree
-       configView = new ConfigView(split2, "config");
+       configView = new ConfigView(widget, "config");
        configList = configView->list;
 
-       helpText = new ConfigInfoView(split2, "help");
+       helpText = new ConfigInfoView(widget, "help");
+
+       layout->addWidget(split2);
+       split2->addWidget(split1);
+       split1->addWidget(configView);
+       split1->addWidget(menuView);
+       split2->addWidget(helpText);
 
        setTabOrder(configList, helpText);
        configList->setFocus();
@@ -1484,6 +1510,8 @@ ConfigMainWindow::ConfigMainWindow(void)
                helpText, SLOT(setInfo(struct menu *)));
        connect(configList, SIGNAL(menuSelected(struct menu *)),
                SLOT(changeMenu(struct menu *)));
+       connect(configList, SIGNAL(itemSelected(struct menu *)),
+               SLOT(changeItens(struct menu *)));
        connect(configList, SIGNAL(parentSelected()),
                SLOT(goBack()));
        connect(menuList, SIGNAL(menuChanged(struct menu *)),
@@ -1580,15 +1608,26 @@ void ConfigMainWindow::searchConfig(void)
        searchWindow->show();
 }
 
-void ConfigMainWindow::changeMenu(struct menu *menu)
+void ConfigMainWindow::changeItens(struct menu *menu)
 {
        configList->setRootMenu(menu);
+
        if (configList->rootEntry->parent == &rootmenu)
                backAction->setEnabled(false);
        else
                backAction->setEnabled(true);
 }
 
+void ConfigMainWindow::changeMenu(struct menu *menu)
+{
+       menuList->setRootMenu(menu);
+
+       if (menuList->rootEntry->parent == &rootmenu)
+               backAction->setEnabled(false);
+       else
+               backAction->setEnabled(true);
+}
+
 void ConfigMainWindow::setMenuLink(struct menu *menu)
 {
        struct menu *parent;
@@ -1698,14 +1737,14 @@ void ConfigMainWindow::showSplitView(void)
        fullViewAction->setEnabled(true);
        fullViewAction->setChecked(false);
 
-       configList->mode = symbolMode;
+       configList->mode = menuMode;
        if (configList->rootEntry == &rootmenu)
                configList->updateListAll();
        else
                configList->setRootMenu(&rootmenu);
        configList->setAllOpen(true);
        configApp->processEvents();
-       menuList->mode = menuMode;
+       menuList->mode = symbolMode;
        menuList->setRootMenu(&rootmenu);
        menuList->setAllOpen(true);
        menuView->show();
@@ -1733,7 +1772,6 @@ void ConfigMainWindow::showFullView(void)
 
 /*
  * ask for saving configuration before quitting
- * TODO ask only when something changed
  */
 void ConfigMainWindow::closeEvent(QCloseEvent* e)
 {
index 45bfe9b..c879d79 100644 (file)
@@ -71,6 +71,7 @@ public slots:
 signals:
        void menuChanged(struct menu *menu);
        void menuSelected(struct menu *menu);
+       void itemSelected(struct menu *menu);
        void parentSelected(void);
        void gotFocus(struct menu *);
 
@@ -298,6 +299,7 @@ public:
        ConfigMainWindow(void);
 public slots:
        void changeMenu(struct menu *);
+       void changeItens(struct menu *);
        void setMenuLink(struct menu *);
        void listFocusChanged(void);
        void goBack(void);
index 3ff26e5..5b80a46 100755 (executable)
@@ -7,6 +7,7 @@ SMP=$3
 PREEMPT=$4
 PREEMPT_RT=$5
 CC=$6
+LD=$7
 
 vecho() { [ "${quiet}" = "silent_" ] || echo "$@" ; }
 
@@ -61,7 +62,10 @@ UTS_VERSION="$(echo $UTS_VERSION $CONFIG_FLAGS $TIMESTAMP | cut -b -$UTS_LEN)"
   printf '#define LINUX_COMPILE_BY "%s"\n' "$LINUX_COMPILE_BY"
   echo \#define LINUX_COMPILE_HOST \"$LINUX_COMPILE_HOST\"
 
-  echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | grep ' version ' | sed 's/[[:space:]]*$//'`\"
+  CC_VERSION=$($CC -v 2>&1 | grep ' version ' | sed 's/[[:space:]]*$//')
+  LD_VERSION=$($LD -v | head -n1 | sed 's/(compatible with [^)]*)//' \
+                     | sed 's/[[:space:]]*$//')
+  printf '#define LINUX_COMPILER "%s"\n' "$CC_VERSION, $LD_VERSION"
 } > .tmpcompile
 
 # Only replace the real compile.h if the new one is different,
index 415f3f1..d0cde66 100644 (file)
@@ -139,6 +139,8 @@ static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos)
        n = key_serial_next(p, v);
        if (n)
                *_pos = key_node_serial(n);
+       else
+               (*_pos)++;
        return n;
 }
 
index 70ecdc7..c21b922 100644 (file)
@@ -1035,14 +1035,14 @@ static int str_read(char **strp, gfp_t flags, void *fp, u32 len)
        if (!str)
                return -ENOMEM;
 
-       /* it's expected the caller should free the str */
-       *strp = str;
-
        rc = next_entry(str, fp, len);
-       if (rc)
+       if (rc) {
+               kfree(str);
                return rc;
+       }
 
        str[len] = '\0';
+       *strp = str;
        return 0;
 }
 
index fbda4eb..59d62f0 100644 (file)
@@ -197,7 +197,8 @@ int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin)
 }
 
 static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug,
-                                        snd_pcm_sframes_t frames)
+                                        snd_pcm_sframes_t frames,
+                                        bool check_size)
 {
        struct snd_pcm_plugin *plugin, *plugin_next;
 
@@ -209,7 +210,7 @@ static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug,
                        if (frames < 0)
                                return frames;
                }
-               if (frames > plugin->buf_frames)
+               if (check_size && frames > plugin->buf_frames)
                        frames = plugin->buf_frames;
                plugin = plugin_next;
        }
@@ -217,13 +218,14 @@ static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug,
 }
 
 static snd_pcm_sframes_t calc_src_frames(struct snd_pcm_substream *plug,
-                                        snd_pcm_sframes_t frames)
+                                        snd_pcm_sframes_t frames,
+                                        bool check_size)
 {
        struct snd_pcm_plugin *plugin, *plugin_prev;
 
        plugin = snd_pcm_plug_last(plug);
        while (plugin && frames > 0) {
-               if (frames > plugin->buf_frames)
+               if (check_size && frames > plugin->buf_frames)
                        frames = plugin->buf_frames;
                plugin_prev = plugin->prev;
                if (plugin->src_frames) {
@@ -242,9 +244,9 @@ snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_p
                return -ENXIO;
        switch (snd_pcm_plug_stream(plug)) {
        case SNDRV_PCM_STREAM_PLAYBACK:
-               return calc_src_frames(plug, drv_frames);
+               return calc_src_frames(plug, drv_frames, false);
        case SNDRV_PCM_STREAM_CAPTURE:
-               return calc_dst_frames(plug, drv_frames);
+               return calc_dst_frames(plug, drv_frames, false);
        default:
                snd_BUG();
                return -EINVAL;
@@ -257,9 +259,9 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc
                return -ENXIO;
        switch (snd_pcm_plug_stream(plug)) {
        case SNDRV_PCM_STREAM_PLAYBACK:
-               return calc_dst_frames(plug, clt_frames);
+               return calc_dst_frames(plug, clt_frames, false);
        case SNDRV_PCM_STREAM_CAPTURE:
-               return calc_src_frames(plug, clt_frames);
+               return calc_src_frames(plug, clt_frames, false);
        default:
                snd_BUG();
                return -EINVAL;
@@ -622,7 +624,7 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st
                src_channels = dst_channels;
                plugin = next;
        }
-       return snd_pcm_plug_client_size(plug, frames);
+       return calc_src_frames(plug, frames, true);
 }
 
 snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *dst_channels_final, snd_pcm_uframes_t size)
@@ -632,7 +634,7 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, str
        snd_pcm_sframes_t frames = size;
        int err;
 
-       frames = snd_pcm_plug_slave_size(plug, frames);
+       frames = calc_src_frames(plug, frames, true);
        if (frames < 0)
                return frames;
 
index f5fd62e..841523f 100644 (file)
@@ -290,8 +290,12 @@ int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct hda_beep *beep = codec->beep;
+       int chs = get_amp_channels(kcontrol);
+
        if (beep && (!beep->enabled || !ctl_has_mute(kcontrol))) {
-               ucontrol->value.integer.value[0] =
+               if (chs & 1)
+                       ucontrol->value.integer.value[0] = beep->enabled;
+               if (chs & 2)
                        ucontrol->value.integer.value[1] = beep->enabled;
                return 0;
        }
index 92a042e..bd09359 100644 (file)
@@ -2076,6 +2076,17 @@ static void pcm_mmap_prepare(struct snd_pcm_substream *substream,
 #endif
 }
 
+/* Blacklist for skipping the whole probe:
+ * some HD-audio PCI entries are exposed without any codecs, and such devices
+ * should be ignored from the beginning.
+ */
+static const struct snd_pci_quirk driver_blacklist[] = {
+       SND_PCI_QUIRK(0x1043, 0x874f, "ASUS ROG Zenith II / Strix", 0),
+       SND_PCI_QUIRK(0x1462, 0xcb59, "MSI TRX40 Creator", 0),
+       SND_PCI_QUIRK(0x1462, 0xcb60, "MSI TRX40", 0),
+       {}
+};
+
 static const struct hda_controller_ops pci_hda_ops = {
        .disable_msi_reset_irq = disable_msi_reset_irq,
        .pcm_mmap_prepare = pcm_mmap_prepare,
@@ -2092,6 +2103,11 @@ static int azx_probe(struct pci_dev *pci,
        bool schedule_probe;
        int err;
 
+       if (snd_pci_quirk_lookup(pci, driver_blacklist)) {
+               dev_info(&pci->dev, "Skipping the blacklisted device\n");
+               return -ENODEV;
+       }
+
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
        if (!enable[dev]) {
index f66a481..de2826f 100644 (file)
@@ -86,6 +86,14 @@ struct alc_spec {
 
        unsigned int gpio_mute_led_mask;
        unsigned int gpio_mic_led_mask;
+       unsigned int mute_led_coef_idx;
+       unsigned int mute_led_coefbit_mask;
+       unsigned int mute_led_coefbit_on;
+       unsigned int mute_led_coefbit_off;
+       unsigned int mic_led_coef_idx;
+       unsigned int mic_led_coefbit_mask;
+       unsigned int mic_led_coefbit_on;
+       unsigned int mic_led_coefbit_off;
 
        hda_nid_t headset_mic_pin;
        hda_nid_t headphone_mic_pin;
@@ -2447,6 +2455,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
        SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1462, 0x1275, "MSI-GL63", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
@@ -4178,6 +4187,111 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
        }
 }
 
+/* update mute-LED according to the speaker mute state via COEF bit */
+static void alc_fixup_mute_led_coefbit_hook(void *private_data, int enabled)
+{
+       struct hda_codec *codec = private_data;
+       struct alc_spec *spec = codec->spec;
+
+       if (spec->mute_led_polarity)
+               enabled = !enabled;
+
+       /* temporarily power up/down for setting COEF bit */
+       enabled ? alc_update_coef_idx(codec, spec->mute_led_coef_idx,
+               spec->mute_led_coefbit_mask, spec->mute_led_coefbit_off) :
+                 alc_update_coef_idx(codec, spec->mute_led_coef_idx,
+               spec->mute_led_coefbit_mask, spec->mute_led_coefbit_on);
+}
+
+static void alc285_fixup_hp_mute_led_coefbit(struct hda_codec *codec,
+                                         const struct hda_fixup *fix,
+                                         int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mute_led_polarity = 0;
+               spec->mute_led_coef_idx = 0x0b;
+               spec->mute_led_coefbit_mask = 1<<3;
+               spec->mute_led_coefbit_on = 1<<3;
+               spec->mute_led_coefbit_off = 0;
+               spec->gen.vmaster_mute.hook = alc_fixup_mute_led_coefbit_hook;
+               spec->gen.vmaster_mute_enum = 1;
+       }
+}
+
+static void alc236_fixup_hp_mute_led_coefbit(struct hda_codec *codec,
+                                         const struct hda_fixup *fix,
+                                         int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mute_led_polarity = 0;
+               spec->mute_led_coef_idx = 0x34;
+               spec->mute_led_coefbit_mask = 1<<5;
+               spec->mute_led_coefbit_on = 0;
+               spec->mute_led_coefbit_off = 1<<5;
+               spec->gen.vmaster_mute.hook = alc_fixup_mute_led_coefbit_hook;
+               spec->gen.vmaster_mute_enum = 1;
+       }
+}
+
+/* turn on/off mic-mute LED per capture hook by coef bit */
+static void alc_hp_cap_micmute_update(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (spec->gen.micmute_led.led_value)
+               alc_update_coef_idx(codec, spec->mic_led_coef_idx,
+                       spec->mic_led_coefbit_mask, spec->mic_led_coefbit_on);
+       else
+               alc_update_coef_idx(codec, spec->mic_led_coef_idx,
+                       spec->mic_led_coefbit_mask, spec->mic_led_coefbit_off);
+}
+
+static void alc285_fixup_hp_coef_micmute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mic_led_coef_idx = 0x19;
+               spec->mic_led_coefbit_mask = 1<<13;
+               spec->mic_led_coefbit_on = 1<<13;
+               spec->mic_led_coefbit_off = 0;
+               snd_hda_gen_add_micmute_led(codec, alc_hp_cap_micmute_update);
+       }
+}
+
+static void alc236_fixup_hp_coef_micmute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mic_led_coef_idx = 0x35;
+               spec->mic_led_coefbit_mask = 3<<2;
+               spec->mic_led_coefbit_on = 2<<2;
+               spec->mic_led_coefbit_off = 1<<2;
+               snd_hda_gen_add_micmute_led(codec, alc_hp_cap_micmute_update);
+       }
+}
+
+static void alc285_fixup_hp_mute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
+       alc285_fixup_hp_coef_micmute_led(codec, fix, action);
+}
+
+static void alc236_fixup_hp_mute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc236_fixup_hp_mute_led_coefbit(codec, fix, action);
+       alc236_fixup_hp_coef_micmute_led(codec, fix, action);
+}
+
 #if IS_REACHABLE(CONFIG_INPUT)
 static void gpio2_mic_hotkey_event(struct hda_codec *codec,
                                   struct hda_jack_callback *event)
@@ -5964,6 +6078,8 @@ enum {
        ALC285_FIXUP_THINKPAD_HEADSET_JACK,
        ALC294_FIXUP_ASUS_HPE,
        ALC285_FIXUP_HP_GPIO_LED,
+       ALC285_FIXUP_HP_MUTE_LED,
+       ALC236_FIXUP_HP_MUTE_LED,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -7089,6 +7205,14 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc285_fixup_hp_gpio_led,
        },
+       [ALC285_FIXUP_HP_MUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_hp_mute_led,
+       },
+       [ALC236_FIXUP_HP_MUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc236_fixup_hp_mute_led,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -7234,6 +7358,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8497, "HP Envy x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
        SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3),
        SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED),
        SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -7325,6 +7451,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Yoga 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
        SND_PCI_QUIRK(0x17aa, 0x2293, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
+       SND_PCI_QUIRK(0x17aa, 0x22be, "Thinkpad X1 Carbon 8th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
        SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
index 91f83ce..9aa12a6 100644 (file)
@@ -536,7 +536,7 @@ static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol,
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
        mutex_lock(&ice->gpio_mutex);
-       ucontrol->value.integer.value[0] = wm_get(ice, WM_ADC_MUX) & 0x1f;
+       ucontrol->value.enumerated.item[0] = wm_get(ice, WM_ADC_MUX) & 0x1f;
        mutex_unlock(&ice->gpio_mutex);
        return 0;
 }
@@ -550,7 +550,7 @@ static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&ice->gpio_mutex);
        oval = wm_get(ice, WM_ADC_MUX);
-       nval = (oval & 0xe0) | ucontrol->value.integer.value[0];
+       nval = (oval & 0xe0) | ucontrol->value.enumerated.item[0];
        if (nval != oval) {
                wm_put(ice, WM_ADC_MUX, nval);
                change = 1;
index 3a3c47e..f160d35 100644 (file)
@@ -139,6 +139,7 @@ static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream,
                rv_writel(adata->tdm_fmt, rtd->acp3x_base + frmt_reg);
        }
        val = rv_readl(rtd->acp3x_base + reg_val);
+       val &= ~ACP3x_ITER_IRER_SAMP_LEN_MASK;
        val = val | (rtd->xfer_resolution  << 3);
        rv_writel(val, rtd->acp3x_base + reg_val);
        return 0;
index 21e7ac0..03fe939 100644 (file)
@@ -76,6 +76,8 @@
 #define ACP_POWERED_OFF                        0x02
 #define ACP_POWER_OFF_IN_PROGRESS      0x03
 
+#define ACP3x_ITER_IRER_SAMP_LEN_MASK  0x38
+
 struct acp3x_platform_info {
        u16 play_i2s_instance;
        u16 cap_i2s_instance;
index e46c390..b7a1efc 100644 (file)
@@ -181,7 +181,7 @@ bcm63xx_pcm_pointer(struct snd_soc_component *component,
        snd_pcm_uframes_t x;
        struct bcm63xx_runtime_data *prtd = substream->runtime->private_data;
 
-       if ((void *)prtd->dma_addr_next == NULL)
+       if (!prtd->dma_addr_next)
                prtd->dma_addr_next = substream->runtime->dma_addr;
 
        x = bytes_to_frames(substream->runtime,
index 5f25b9f..8a02791 100644 (file)
@@ -137,6 +137,9 @@ struct cs4270_private {
 
        /* power domain regulators */
        struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+
+       /* reset gpio */
+       struct gpio_desc *reset_gpio;
 };
 
 static const struct snd_soc_dapm_widget cs4270_dapm_widgets[] = {
@@ -649,6 +652,22 @@ static const struct regmap_config cs4270_regmap = {
 };
 
 /**
+ * cs4270_i2c_remove - deinitialize the I2C interface of the CS4270
+ * @i2c_client: the I2C client object
+ *
+ * This function puts the chip into low power mode when the i2c device
+ * is removed.
+ */
+static int cs4270_i2c_remove(struct i2c_client *i2c_client)
+{
+       struct cs4270_private *cs4270 = i2c_get_clientdata(i2c_client);
+
+       gpiod_set_value_cansleep(cs4270->reset_gpio, 0);
+
+       return 0;
+}
+
+/**
  * cs4270_i2c_probe - initialize the I2C interface of the CS4270
  * @i2c_client: the I2C client object
  * @id: the I2C device ID (ignored)
@@ -660,7 +679,6 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
        const struct i2c_device_id *id)
 {
        struct cs4270_private *cs4270;
-       struct gpio_desc *reset_gpiod;
        unsigned int val;
        int ret, i;
 
@@ -679,10 +697,21 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
        if (ret < 0)
                return ret;
 
-       reset_gpiod = devm_gpiod_get_optional(&i2c_client->dev, "reset",
-                                             GPIOD_OUT_HIGH);
-       if (PTR_ERR(reset_gpiod) == -EPROBE_DEFER)
-               return -EPROBE_DEFER;
+       /* reset the device */
+       cs4270->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, "reset",
+                                                    GPIOD_OUT_LOW);
+       if (IS_ERR(cs4270->reset_gpio)) {
+               dev_dbg(&i2c_client->dev, "Error getting CS4270 reset GPIO\n");
+               return PTR_ERR(cs4270->reset_gpio);
+       }
+
+       if (cs4270->reset_gpio) {
+               dev_dbg(&i2c_client->dev, "Found reset GPIO\n");
+               gpiod_set_value_cansleep(cs4270->reset_gpio, 1);
+       }
+
+       /* Sleep 500ns before i2c communications */
+       ndelay(500);
 
        cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap);
        if (IS_ERR(cs4270->regmap))
@@ -735,6 +764,7 @@ static struct i2c_driver cs4270_i2c_driver = {
        },
        .id_table = cs4270_id,
        .probe = cs4270_i2c_probe,
+       .remove = cs4270_i2c_remove,
 };
 
 module_i2c_driver(cs4270_i2c_driver);
index 92d6701..6ba1849 100644 (file)
@@ -3758,6 +3758,14 @@ static const struct dmi_system_id dmi_platform_data[] = {
                },
                .driver_data = (void *)&kahlee_platform_data,
        },
+       {
+               .ident = "Medion E1239T",
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MEDION"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "E1239T MD60568"),
+               },
+               .driver_data = (void *)&intel_braswell_platform_data,
+       },
        { }
 };
 
index c9268a2..d36f560 100644 (file)
@@ -3703,7 +3703,7 @@ static const struct acpi_device_id rt5682_acpi_match[] = {
 MODULE_DEVICE_TABLE(acpi, rt5682_acpi_match);
 #endif
 
-static struct i2c_driver rt5682_i2c_driver = {
+static struct i2c_driver __maybe_unused rt5682_i2c_driver = {
        .driver = {
                .name = "rt5682",
                .of_match_table = of_match_ptr(rt5682_of_match),
@@ -3713,7 +3713,10 @@ static struct i2c_driver rt5682_i2c_driver = {
        .shutdown = rt5682_i2c_shutdown,
        .id_table = rt5682_i2c_id,
 };
+
+#ifdef CONFIG_I2C
 module_i2c_driver(rt5682_i2c_driver);
+#endif
 
 MODULE_DESCRIPTION("ASoC RT5682 driver");
 MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
index f883c93..69f3af4 100644 (file)
@@ -50,6 +50,8 @@ static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv,
 {
        int ret = 0;
 
+       WARN_ON(!mutex_is_locked(&drv->lock));
+
        ret = sst_fill_byte_control(drv, ipc_msg,
                                block, task_id, pipe_id, len, cmd_data);
        if (ret < 0)
@@ -966,7 +968,9 @@ static int sst_set_be_modules(struct snd_soc_dapm_widget *w,
        dev_dbg(c->dev, "Enter: widget=%s\n", w->name);
 
        if (SND_SOC_DAPM_EVENT_ON(event)) {
+               mutex_lock(&drv->lock);
                ret = sst_send_slot_map(drv);
+               mutex_unlock(&drv->lock);
                if (ret)
                        return ret;
                ret = sst_send_pipe_module_params(w, k);
index 13db285..053c277 100644 (file)
@@ -223,9 +223,9 @@ int sst_prepare_and_post_msg(struct intel_sst_drv *sst,
                size_t mbox_data_len, const void *mbox_data, void **data,
                bool large, bool fill_dsp, bool sync, bool response)
 {
+       struct sst_block *block = NULL;
        struct ipc_post *msg = NULL;
        struct ipc_dsp_hdr dsp_hdr;
-       struct sst_block *block;
        int ret = 0, pvt_id;
 
        pvt_id = sst_assign_pvt_id(sst);
index 6c2fdb5..af2f502 100644 (file)
@@ -254,7 +254,6 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = {
                .no_pcm = 1,
                .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
                        SND_SOC_DAIFMT_CBS_CFS,
-               .ignore_suspend = 1,
                .ignore_pmdown_time = 1,
                .be_hw_params_fixup = broadwell_ssp0_fixup,
                .ops = &bdw_rt5650_ops,
index 6b4b640..cc41a34 100644 (file)
@@ -340,7 +340,6 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = {
                .no_pcm = 1,
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                        SND_SOC_DAIFMT_CBS_CFS,
-               .ignore_suspend = 1,
                .ignore_pmdown_time = 1,
                .be_hw_params_fixup = broadwell_ssp0_fixup,
                .ops = &bdw_rt5677_ops,
index acb4e36..f9a8336 100644 (file)
@@ -217,7 +217,6 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
                .init = broadwell_rt286_codec_init,
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                        SND_SOC_DAIFMT_CBS_CFS,
-               .ignore_suspend = 1,
                .ignore_pmdown_time = 1,
                .be_hw_params_fixup = broadwell_ssp0_fixup,
                .ops = &broadwell_rt286_ops,
index 33fb8ea..08f4ae9 100644 (file)
@@ -591,6 +591,17 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                                        BYT_RT5640_SSP0_AIF1 |
                                        BYT_RT5640_MCLK_EN),
        },
+       {
+               /* MPMAN MPWIN895CL */
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MPMAN"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MPWIN8900CL"),
+               },
+               .driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+                                       BYT_RT5640_MONO_SPEAKER |
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
        {       /* MSI S100 tablet */
                .matches = {
                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),
index 3ed53d7..74af090 100644 (file)
@@ -162,7 +162,6 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = {
                .no_pcm = 1,
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                        SND_SOC_DAIFMT_CBS_CFS,
-               .ignore_suspend = 1,
                .ignore_pmdown_time = 1,
                .be_hw_params_fixup = haswell_ssp0_fixup,
                .ops = &haswell_rt5640_ops,
index f6c7cdd..125af00 100644 (file)
@@ -78,7 +78,7 @@ struct q6asm_dai_data {
 };
 
 static const struct snd_pcm_hardware q6asm_dai_hardware_capture = {
-       .info =                 (SNDRV_PCM_INFO_MMAP |
+       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                SNDRV_PCM_INFO_MMAP_VALID |
                                SNDRV_PCM_INFO_INTERLEAVED |
@@ -100,7 +100,7 @@ static const struct snd_pcm_hardware q6asm_dai_hardware_capture = {
 };
 
 static struct snd_pcm_hardware q6asm_dai_hardware_playback = {
-       .info =                 (SNDRV_PCM_INFO_MMAP |
+       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                SNDRV_PCM_INFO_MMAP_VALID |
                                SNDRV_PCM_INFO_INTERLEAVED |
index 19142f6..8f3cad8 100644 (file)
@@ -295,12 +295,12 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
 {
        int ret = 0;
 
-       if (!dai->started &&
+       if (!dai->started[substream->stream] &&
            dai->driver->ops->startup)
                ret = dai->driver->ops->startup(substream, dai);
 
        if (ret == 0)
-               dai->started = 1;
+               dai->started[substream->stream] = 1;
 
        return ret;
 }
@@ -308,11 +308,11 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
 void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
                         struct snd_pcm_substream *substream)
 {
-       if (dai->started &&
+       if (dai->started[substream->stream] &&
            dai->driver->ops->shutdown)
                dai->driver->ops->shutdown(substream, dai);
 
-       dai->started = 0;
+       dai->started[substream->stream] = 0;
 }
 
 int snd_soc_dai_prepare(struct snd_soc_dai *dai,
index 04da792..679ed60 100644 (file)
@@ -802,7 +802,13 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i,
                        val = max - val;
                p->connect = !!val;
        } else {
-               p->connect = 0;
+               /* since a virtual mixer has no backing registers to
+                * decide which path to connect, it will try to match
+                * with initial state.  This is to ensure
+                * that the default mixer choice will be
+                * correctly powered up during initialization.
+                */
+               p->connect = invert;
        }
 }
 
index 652657d..55ffb34 100644 (file)
@@ -825,7 +825,7 @@ int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
        unsigned int regbase = mc->regbase;
        unsigned int regcount = mc->regcount;
        unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
-       unsigned int regwmask = (1<<regwshift)-1;
+       unsigned int regwmask = (1UL<<regwshift)-1;
        unsigned int invert = mc->invert;
        unsigned long mask = (1UL<<mc->nbits)-1;
        long min = mc->min;
@@ -874,7 +874,7 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
        unsigned int regbase = mc->regbase;
        unsigned int regcount = mc->regcount;
        unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
-       unsigned int regwmask = (1<<regwshift)-1;
+       unsigned int regwmask = (1UL<<regwshift)-1;
        unsigned int invert = mc->invert;
        unsigned long mask = (1UL<<mc->nbits)-1;
        long max = mc->max;
index e256d43..289aebc 100644 (file)
@@ -2324,7 +2324,8 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                switch (cmd) {
                case SNDRV_PCM_TRIGGER_START:
                        if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
-                           (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+                           (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
+                           (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
                                continue;
 
                        ret = dpcm_do_trigger(dpcm, be_substream, cmd);
@@ -2354,7 +2355,8 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                        be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
                        break;
                case SNDRV_PCM_TRIGGER_STOP:
-                       if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
+                       if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
+                           (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
                                continue;
 
                        if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
index 1f81cd2..87f75ed 100644 (file)
@@ -362,7 +362,7 @@ static int soc_tplg_add_kcontrol(struct soc_tplg *tplg,
        struct snd_soc_component *comp = tplg->comp;
 
        return soc_tplg_add_dcontrol(comp->card->snd_card,
-                               comp->dev, k, NULL, comp, kcontrol);
+                               comp->dev, k, comp->name_prefix, comp, kcontrol);
 }
 
 /* remove a mixer kcontrol */
index 1f2e0be..64af082 100644 (file)
@@ -597,7 +597,7 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
        }
 
        if (sdev->fw_state == SOF_FW_BOOT_COMPLETE)
-               dev_info(sdev->dev, "firmware boot complete\n");
+               dev_dbg(sdev->dev, "firmware boot complete\n");
        else
                return -EIO; /* FW boots but fw_ready op failed */
 
index 2bd280c..0d0c9af 100644 (file)
@@ -1556,8 +1556,10 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
 
        ret = snd_soc_register_component(&pdev->dev, &stm32_component,
                                         &sai->cpu_dai_drv, 1);
-       if (ret)
+       if (ret) {
+               snd_dmaengine_pcm_unregister(&pdev->dev);
                return ret;
+       }
 
        if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
                conf = &stm32_sai_pcm_config_spdif;
index 5ebca80..72b575c 100644 (file)
@@ -359,6 +359,14 @@ static const struct usbmix_name_map corsair_virtuoso_map[] = {
        { 0 }
 };
 
+/* Some mobos shipped with a dummy HD-audio show the invalid GET_MIN/GET_MAX
+ * response for Input Gain Pad (id=19, control=12).  Skip it.
+ */
+static const struct usbmix_name_map asus_rog_map[] = {
+       { 19, NULL, 12 }, /* FU, Input Gain Pad */
+       {}
+};
+
 /*
  * Control map entries
  */
@@ -488,6 +496,26 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .id = USB_ID(0x1b1c, 0x0a42),
                .map = corsair_virtuoso_map,
        },
+       {       /* Gigabyte TRX40 Aorus Pro WiFi */
+               .id = USB_ID(0x0414, 0xa002),
+               .map = asus_rog_map,
+       },
+       {       /* ASUS ROG Zenith II */
+               .id = USB_ID(0x0b05, 0x1916),
+               .map = asus_rog_map,
+       },
+       {       /* ASUS ROG Strix */
+               .id = USB_ID(0x0b05, 0x1917),
+               .map = asus_rog_map,
+       },
+       {       /* MSI TRX40 Creator */
+               .id = USB_ID(0x0db0, 0x0d64),
+               .map = asus_rog_map,
+       },
+       {       /* MSI TRX40 */
+               .id = USB_ID(0x0db0, 0x543d),
+               .map = asus_rog_map,
+       },
        { 0 } /* terminator */
 };
 
index 1c87192..e009d58 100644 (file)
@@ -3592,5 +3592,47 @@ 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.
+        *
+        * 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.
+        */
+       USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0017),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8, // outputs
+                                       .iface = 0,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x01,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC|
+                                               USB_ENDPOINT_SYNC_ASYNC,
+                                       .rates = SNDRV_PCM_RATE_48000,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 48000 }
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 #undef USB_DEVICE_VENDOR_SPEC
index 86f192a..a8ece17 100644 (file)
@@ -1827,6 +1827,7 @@ struct registration_quirk {
 
 static const struct registration_quirk registration_quirks[] = {
        REG_QUIRK_ENTRY(0x0951, 0x16d8, 2),     /* Kingston HyperX AMP */
+       REG_QUIRK_ENTRY(0x0951, 0x16ed, 2),     /* Kingston HyperX Cloud Alpha S */
        { 0 }                                   /* terminator */
 };
 
index d29a86c..d77d786 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2008 Eric Piel
  * Copyright 2009 Pavel Machek <pavel@ucw.cz>
  * Copyright 2012 Sonal Santan
- * Copyright 2014 Pali Rohár <pali.rohar@gmail.com>
+ * Copyright 2014 Pali Rohár <pali@kernel.org>
  */
 
 #include <stdio.h>
index ee08aef..f591c4d 100644 (file)
@@ -3,9 +3,15 @@ include ../scripts/Makefile.include
 include ../scripts/Makefile.arch
 
 # always use the host compiler
+ifneq ($(LLVM),)
+HOSTAR ?= llvm-ar
+HOSTCC ?= clang
+HOSTLD ?= ld.lld
+else
 HOSTAR ?= ar
 HOSTCC ?= gcc
 HOSTLD ?= ld
+endif
 AR      = $(HOSTAR)
 CC      = $(HOSTCC)
 LD      = $(HOSTLD)
index dbebf05..47f9cc9 100644 (file)
@@ -21,8 +21,8 @@ DRIVERS := ../../../drivers
 NVDIMM_SRC := $(DRIVERS)/nvdimm
 ACPI_SRC := $(DRIVERS)/acpi/nfit
 DAX_SRC := $(DRIVERS)/dax
-ccflags-y := -I$(src)/$(NVDIMM_SRC)/
-ccflags-y += -I$(src)/$(ACPI_SRC)/
+ccflags-y := -I$(srctree)/drivers/nvdimm/
+ccflags-y += -I$(srctree)/drivers/acpi/nfit/
 
 obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o
 obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o
index fb3c3d7..75baebf 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
-ccflags-y := -I$(src)/../../../../drivers/nvdimm/
-ccflags-y += -I$(src)/../../../../drivers/acpi/nfit/
+ccflags-y := -I$(srctree)/drivers/nvdimm/
+ccflags-y += -I$(srctree)/drivers/acpi/nfit/
 
 obj-m += nfit_test.o
 obj-m += nfit_test_iomap.o
index bf6422a..a8ee5c4 100644 (file)
@@ -3164,7 +3164,9 @@ static __init int nfit_test_init(void)
        mcsafe_test();
        dax_pmem_test();
        dax_pmem_core_test();
+#ifdef CONFIG_DEV_DAX_PMEM_COMPAT
        dax_pmem_compat_test();
+#endif
 
        nfit_test_setup(nfit_test_lookup, nfit_test_evaluate_dsm);
 
index 8b944cf..3702dbc 100755 (executable)
@@ -61,6 +61,8 @@ ALL_TESTS="$ALL_TESTS 0006:10:1"
 ALL_TESTS="$ALL_TESTS 0007:5:1"
 ALL_TESTS="$ALL_TESTS 0008:150:1"
 ALL_TESTS="$ALL_TESTS 0009:150:1"
+ALL_TESTS="$ALL_TESTS 0010:1:1"
+ALL_TESTS="$ALL_TESTS 0011:1:1"
 
 # Kselftest framework requirement - SKIP code is 4.
 ksft_skip=4
@@ -149,6 +151,7 @@ function load_req_mod()
 
 test_finish()
 {
+       echo "$MODPROBE" > /proc/sys/kernel/modprobe
        echo "Test completed"
 }
 
@@ -443,6 +446,30 @@ kmod_test_0009()
        config_expect_result ${FUNCNAME[0]} SUCCESS
 }
 
+kmod_test_0010()
+{
+       kmod_defaults_driver
+       config_num_threads 1
+       echo "/KMOD_TEST_NONEXISTENT" > /proc/sys/kernel/modprobe
+       config_trigger ${FUNCNAME[0]}
+       config_expect_result ${FUNCNAME[0]} -ENOENT
+       echo "$MODPROBE" > /proc/sys/kernel/modprobe
+}
+
+kmod_test_0011()
+{
+       kmod_defaults_driver
+       config_num_threads 1
+       # This causes the kernel to not even try executing modprobe.  The error
+       # code is still -ENOENT like when modprobe doesn't exist, so we can't
+       # easily test for the exact difference.  But this still is a useful test
+       # since there was a bug where request_module() returned 0 in this case.
+       echo > /proc/sys/kernel/modprobe
+       config_trigger ${FUNCNAME[0]}
+       config_expect_result ${FUNCNAME[0]} -ENOENT
+       echo "$MODPROBE" > /proc/sys/kernel/modprobe
+}
+
 list_tests()
 {
        echo "Test ID list:"
@@ -460,6 +487,8 @@ list_tests()
        echo "0007 x $(get_test_count 0007) - multithreaded tests with default setup test request_module() and get_fs_type()"
        echo "0008 x $(get_test_count 0008) - multithreaded - push kmod_concurrent over max_modprobes for request_module()"
        echo "0009 x $(get_test_count 0009) - multithreaded - push kmod_concurrent over max_modprobes for get_fs_type()"
+       echo "0010 x $(get_test_count 0010) - test nonexistent modprobe path"
+       echo "0011 x $(get_test_count 0011) - test completely disabling module autoloading"
 }
 
 usage()
@@ -505,18 +534,23 @@ function test_num()
        fi
 }
 
-function get_test_count()
+function get_test_data()
 {
        test_num $1
-       TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
+       local field_num=$(echo $1 | sed 's/^0*//')
+       echo $ALL_TESTS | awk '{print $'$field_num'}'
+}
+
+function get_test_count()
+{
+       TEST_DATA=$(get_test_data $1)
        LAST_TWO=${TEST_DATA#*:*}
        echo ${LAST_TWO%:*}
 }
 
 function get_test_enabled()
 {
-       test_num $1
-       TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
+       TEST_DATA=$(get_test_data $1)
        echo ${TEST_DATA#*:*:}
 }
 
@@ -611,6 +645,7 @@ test_reqs
 allow_user_defaults
 load_req_mod
 
+MODPROBE=$(</proc/sys/kernel/modprobe)
 trap "test_finish" EXIT
 
 parse_args $@
index f988d2f..8a8d0f4 100755 (executable)
@@ -41,6 +41,11 @@ for dev in `ls -1 /sys/bus/pci/devices/ | grep '\.0$'` ; do
                continue;
        fi
 
+       if [ "ahci" = "$(basename $(realpath /sys/bus/pci/devices/$dev/driver))" ] ; then
+               echo "$dev, Skipped: ahci doesn't support recovery"
+               continue
+       fi
+
        # Don't inject errosr into an already-frozen PE. This happens with
        # PEs that contain multiple PCI devices (e.g. multi-function cards)
        # and injecting new errors during the recovery process will probably
index 0b0db8d..5881e97 100644 (file)
@@ -25,6 +25,7 @@ $(OUTPUT)/tm-unavailable: CFLAGS += -O0 -pthread -m64 -Wno-error=uninitialized -
 $(OUTPUT)/tm-trap: CFLAGS += -O0 -pthread -m64
 $(OUTPUT)/tm-signal-context-force-tm: CFLAGS += -pthread -m64
 $(OUTPUT)/tm-signal-pagefault: CFLAGS += -pthread -m64
+$(OUTPUT)/tm-poison: CFLAGS += -m64
 
 SIGNAL_CONTEXT_CHK_TESTS := $(patsubst %,$(OUTPUT)/%,$(SIGNAL_CONTEXT_CHK_TESTS))
 $(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S
index 83ec6e4..7eb3216 100644 (file)
@@ -46,7 +46,7 @@ static void   start_daemon_mode(void);
 
 pthread_t event_tid;
 pthread_mutex_t input_lock;
-void usage()
+void usage(void)
 {
        printf("Usage: tmon [OPTION...]\n");
        printf("  -c, --control         cooling device in control\n");
@@ -62,7 +62,7 @@ void usage()
        exit(0);
 }
 
-void version()
+void version(void)
 {
        printf("TMON version %s\n", VERSION);
        exit(EXIT_SUCCESS);
@@ -70,7 +70,6 @@ void version()
 
 static void tmon_cleanup(void)
 {
-
        syslog(LOG_INFO, "TMON exit cleanup\n");
        fflush(stdout);
        refresh();
@@ -96,7 +95,6 @@ static void tmon_cleanup(void)
        exit(1);
 }
 
-
 static void tmon_sig_handler(int sig)
 {
        syslog(LOG_INFO, "TMON caught signal %d\n", sig);
@@ -120,7 +118,6 @@ static void tmon_sig_handler(int sig)
        tmon_exit = true;
 }
 
-
 static void start_syslog(void)
 {
        if (debug_on)
@@ -167,7 +164,6 @@ static void prepare_logging(void)
                return;
        }
 
-
        fprintf(tmon_log, "#----------- THERMAL SYSTEM CONFIG -------------\n");
        for (i = 0; i < ptdata.nr_tz_sensor; i++) {
                char binding_str[33]; /* size of long + 1 */
@@ -175,7 +171,7 @@ static void prepare_logging(void)
 
                memset(binding_str, 0, sizeof(binding_str));
                for (j = 0; j < 32; j++)
-                       binding_str[j] = (ptdata.tzi[i].cdev_binding & 1<<j) ?
+                       binding_str[j] = (ptdata.tzi[i].cdev_binding & (1 << j)) ?
                                '1' : '0';
 
                fprintf(tmon_log, "#thermal zone %s%02d cdevs binding: %32s\n",
@@ -187,7 +183,6 @@ static void prepare_logging(void)
                                trip_type_name[ptdata.tzi[i].tp[j].type],
                                ptdata.tzi[i].tp[j].temp);
                }
-
        }
 
        for (i = 0; i < ptdata.nr_cooling_dev; i++)
@@ -219,7 +214,6 @@ static struct option opts[] = {
        { 0, 0, NULL, 0 }
 };
 
-
 int main(int argc, char **argv)
 {
        int err = 0;
@@ -283,7 +277,7 @@ int main(int argc, char **argv)
        if (signal(SIGINT, tmon_sig_handler) == SIG_ERR)
                syslog(LOG_DEBUG, "Cannot handle SIGINT\n");
        if (signal(SIGTERM, tmon_sig_handler) == SIG_ERR)
-               syslog(LOG_DEBUG, "Cannot handle SIGINT\n");
+               syslog(LOG_DEBUG, "Cannot handle SIGTERM\n");
 
        if (probe_thermal_sysfs()) {
                pthread_mutex_destroy(&input_lock);
@@ -328,8 +322,7 @@ int main(int argc, char **argv)
                        show_cooling_device();
                }
                time_elapsed += ticktime;
-               controller_handler(trec[0].temp[target_tz_index] / 1000,
-                               &yk);
+               controller_handler(trec[0].temp[target_tz_index] / 1000, &yk);
                trec[0].pid_out_pct = yk;
                if (!dialogue_on)
                        show_control_w();
@@ -340,14 +333,15 @@ int main(int argc, char **argv)
        return 0;
 }
 
-static void start_daemon_mode()
+static void start_daemon_mode(void)
 {
        daemon_mode = 1;
        /* fork */
        pid_t   sid, pid = fork();
-       if (pid < 0) {
+
+       if (pid < 0)
                exit(EXIT_FAILURE);
-       else if (pid > 0)
+       else if (pid > 0)
                /* kill parent */
                exit(EXIT_SUCCESS);
 
@@ -366,11 +360,9 @@ static void start_daemon_mode()
        if ((chdir("/")) < 0)
                exit(EXIT_FAILURE);
 
-
        sleep(10);
 
        close(STDIN_FILENO);
        close(STDOUT_FILENO);
        close(STDERR_FILENO);
-
 }
index 8e2a908..f33f32f 100644 (file)
@@ -8,7 +8,32 @@ CFLAGS += -g -O2 -Werror -Wall -I. -I../include/ -I ../../usr/include/ -Wno-poin
 vpath %.c ../../drivers/virtio ../../drivers/vhost
 mod:
        ${MAKE} -C `pwd`/../.. M=`pwd`/vhost_test V=${V}
-.PHONY: all test mod clean
+
+#oot: build vhost as an out of tree module for a distro kernel
+#no effort is taken to make it actually build or work, but tends to mostly work
+#if the distro kernel is very close to upstream
+#unsupported! this is a development tool only, don't use the
+#resulting modules in production!
+OOT_KSRC=/lib/modules/$$(uname -r)/build
+OOT_VHOST=`pwd`/../../drivers/vhost
+#Everyone depends on vhost
+#Tweak the below to enable more modules
+OOT_CONFIGS=\
+       CONFIG_VHOST=m \
+       CONFIG_VHOST_NET=n \
+       CONFIG_VHOST_SCSI=n \
+       CONFIG_VHOST_VSOCK=n
+OOT_BUILD=KCFLAGS="-I "${OOT_VHOST} ${MAKE} -C ${OOT_KSRC} V=${V}
+oot-build:
+       echo "UNSUPPORTED! Don't use the resulting modules in production!"
+       ${OOT_BUILD} M=`pwd`/vhost_test
+       ${OOT_BUILD} M=${OOT_VHOST} ${OOT_CONFIGS}
+
+oot-clean: oot-build
+oot: oot-build
+oot-clean: OOT_BUILD+=clean
+
+.PHONY: all test mod clean vhost oot oot-clean oot-build
 clean:
        ${RM} *.o vringh_test virtio_test vhost_test/*.o vhost_test/.*.cmd \
               vhost_test/Module.symvers vhost_test/modules.order *.d
index a339ef3..b568a95 100644 (file)
@@ -93,7 +93,7 @@ no-header-test += asm-generic/%
 
 extra-y := $(patsubst $(obj)/%.h,%.hdrtest, $(shell find $(obj) -name '*.h' 2>/dev/null))
 
-# Include the header to detect missing include guard.
+# Include the header twice to detect missing include guard.
 quiet_cmd_hdrtest = HDRTEST $<
       cmd_hdrtest = \
                $(CC) $(c_flags) -S -o /dev/null -x c /dev/null \