Merge branches 'clk-mvebu', 'clk-const', 'clk-imx' and 'clk-rockchip' into clk-next
authorStephen Boyd <sboyd@kernel.org>
Tue, 29 Mar 2022 17:18:56 +0000 (10:18 -0700)
committerStephen Boyd <sboyd@kernel.org>
Tue, 29 Mar 2022 17:18:56 +0000 (10:18 -0700)
 - Mark mux table as const in clk-mux
 - Make the all_lists array const

* clk-mvebu:
  clk: mvebu: use time_is_before_eq_jiffies() instead of open coding it

* clk-const:
  clk: Mark clk_core_evict_parent_cache_subtree() 'target' const
  clk: Mark 'all_lists' as const
  clk: pistachio: Declare mux table as const u32[]
  clk: qcom: Declare mux table as const u32[]
  clk: mmp: Declare mux tables as const u32[]
  clk: hisilicon: Remove unnecessary cast of mux table to u32 *
  clk: mux: Declare u32 *table parameter as const
  clk: nxp: Declare mux table parameter as const u32 *
  clk: nxp: Remove unused variable

* clk-imx: (28 commits)
  dt-bindings: clock: drop useless consumer example
  clk: imx: Select MXC_CLK for i.MX93 clock driver
  clk: imx: remove redundant re-assignment of pll->base
  MAINTAINERS: clk: imx: add git tree and dt-bindings files
  clk: imx: pll14xx: Support dynamic rates
  clk: imx: pll14xx: Add pr_fmt
  clk: imx: pll14xx: explicitly return lowest rate
  clk: imx: pll14xx: name variables after usage
  clk: imx: pll14xx: consolidate rate calculation
  clk: imx: pll14xx: Use FIELD_GET/FIELD_PREP
  clk: imx: pll14xx: Drop wrong shifting
  clk: imx: pll14xx: Use register defines consistently
  clk: imx8mp: remove SYS PLL 1/2 clock gates
  clk: imx8mn: remove SYS PLL 1/2 clock gates
  clk: imx8mm: remove SYS PLL 1/2 clock gates
  clk: imx: add i.MX93 clk
  clk: imx: support fracn gppll
  clk: imx: add i.MX93 composite clk
  dt-bindings: clock: add i.MX93 clock definition
  dt-bindings: clock: Add imx93 clock support
  ...

* clk-rockchip:
  clk: rockchip: re-add rational best approximation algorithm to the fractional divider
  clk/rockchip: Use of_device_get_match_data()
  clk: rockchip: Add CLK_SET_RATE_PARENT to the HDMI reference clock on rk3568
  clk: rockchip: drop CLK_SET_RATE_PARENT from dclk_vop* on rk3568
  clk: rockchip: Add more PLL rates for rk3568

1126 files changed:
.mailmap
Documentation/ABI/testing/sysfs-driver-aspeed-uart-routing
Documentation/accounting/psi.rst
Documentation/admin-guide/gpio/index.rst
Documentation/arm/marvell.rst
Documentation/arm64/silicon-errata.rst
Documentation/dev-tools/kselftest.rst
Documentation/dev-tools/kunit/usage.rst
Documentation/devicetree/bindings/arm/omap/omap.txt
Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/cs2000-cp.txt [deleted file]
Documentation/devicetree/bindings/clock/microchip,mpfs.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/renesas,9series.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/clock/renesas,cpg-div6-clock.yaml
Documentation/devicetree/bindings/clock/renesas,rzg2l-cpg.yaml
Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.yaml
Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml
Documentation/devicetree/bindings/net/can/tcan4x5x.txt
Documentation/devicetree/bindings/net/qcom,ipa.yaml
Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
Documentation/filesystems/netfs_library.rst
Documentation/gpu/todo.rst
Documentation/index.rst
Documentation/kernel-hacking/locking.rst
Documentation/tools/index.rst [new file with mode: 0644]
Documentation/tools/rtla/index.rst [new file with mode: 0644]
Documentation/userspace-api/ioctl/ioctl-number.rst
Documentation/virt/kvm/api.rst
Documentation/vm/page_table_check.rst
MAINTAINERS
Makefile
arch/arm/Kconfig
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/am335x-wega.dtsi
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/imx23-evk.dts
arch/arm/boot/dts/imx6qdl-udoo.dtsi
arch/arm/boot/dts/imx7ulp.dtsi
arch/arm/boot/dts/meson.dtsi
arch/arm/boot/dts/meson8.dtsi
arch/arm/boot/dts/meson8b.dtsi
arch/arm/boot/dts/omap3-beagle-ab4.dts [new file with mode: 0644]
arch/arm/boot/dts/omap3-beagle.dts
arch/arm/boot/dts/spear320-hmi.dts
arch/arm/boot/dts/ste-ux500-samsung-skomer.dts
arch/arm/crypto/blake2s-shash.c
arch/arm/include/asm/assembler.h
arch/arm/include/asm/processor.h
arch/arm/include/asm/uaccess.h
arch/arm/mach-omap2/display.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-socfpga/Kconfig
arch/arm/probes/kprobes/Makefile
arch/arm64/Kconfig
arch/arm64/Kconfig.platforms
arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts
arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi
arch/arm64/boot/dts/amlogic/meson-gx.dtsi
arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m5.dts
arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi
arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28.dts
arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
arch/arm64/boot/dts/freescale/imx8mq.dtsi
arch/arm64/boot/dts/freescale/mba8mx.dtsi
arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts
arch/arm64/boot/dts/ti/k3-j721s2.dtsi
arch/arm64/include/asm/cputype.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/stacktrace.c
arch/arm64/kernel/vdso/Makefile
arch/arm64/kvm/arm.c
arch/arm64/kvm/handle_exit.c
arch/arm64/kvm/hyp/exception.c
arch/arm64/kvm/hyp/include/hyp/switch.h
arch/arm64/kvm/hyp/pgtable.c
arch/arm64/kvm/hyp/vgic-v3-sr.c
arch/arm64/kvm/vgic/vgic-v3.c
arch/arm64/mm/extable.c
arch/arm64/tools/cpucaps
arch/ia64/Kconfig
arch/ia64/pci/fixup.c
arch/mips/boot/dts/ingenic/ci20.dts
arch/mips/cavium-octeon/octeon-memcpy.S
arch/mips/include/asm/asm.h
arch/mips/include/asm/ftrace.h
arch/mips/include/asm/r4kcache.h
arch/mips/include/asm/unaligned-emul.h
arch/mips/kernel/mips-r2-to-r6-emul.c
arch/mips/kernel/r2300_fpu.S
arch/mips/kernel/r4k_fpu.S
arch/mips/kernel/relocate_kernel.S
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-n64.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/syscall.c
arch/mips/kvm/mips.c
arch/mips/kvm/vz.c
arch/mips/lib/csum_partial.S
arch/mips/lib/memcpy.S
arch/mips/lib/memset.S
arch/mips/lib/strncpy_user.S
arch/mips/lib/strnlen_user.S
arch/mips/loongson64/vbios_quirk.c
arch/powerpc/include/asm/book3s/32/mmu-hash.h
arch/powerpc/include/asm/book3s/32/pgtable.h
arch/powerpc/include/asm/book3s/64/pgtable.h
arch/powerpc/include/asm/fixmap.h
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/kvm_book3s_64.h
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/asm/nohash/32/pgtable.h
arch/powerpc/include/asm/nohash/64/pgtable.h
arch/powerpc/include/asm/ppc-opcode.h
arch/powerpc/include/asm/syscall.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/kernel/interrupt_64.S
arch/powerpc/kernel/time.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_nested.c
arch/powerpc/mm/book3s32/mmu.c
arch/powerpc/mm/kasan/book3s_32.c
arch/powerpc/mm/pgtable.c
arch/powerpc/net/bpf_jit_comp.c
arch/powerpc/net/bpf_jit_comp32.c
arch/powerpc/net/bpf_jit_comp64.c
arch/powerpc/perf/core-book3s.c
arch/riscv/Makefile
arch/riscv/kernel/cpu-hotplug.c
arch/riscv/kernel/head.S
arch/riscv/kernel/stacktrace.c
arch/riscv/kvm/vcpu.c
arch/riscv/kvm/vcpu_sbi_base.c
arch/riscv/mm/extable.c
arch/riscv/mm/init.c
arch/s390/Kconfig
arch/s390/configs/debug_defconfig
arch/s390/configs/defconfig
arch/s390/configs/zfcpdump_defconfig
arch/s390/hypfs/hypfs_vm.c
arch/s390/include/asm/uaccess.h
arch/s390/kernel/module.c
arch/s390/kernel/nmi.c
arch/s390/kvm/kvm-s390.c
arch/s390/lib/Makefile
arch/s390/lib/test_modules.c [new file with mode: 0644]
arch/s390/lib/test_modules.h [new file with mode: 0644]
arch/s390/lib/test_modules_helpers.c [new file with mode: 0644]
arch/x86/Kconfig
arch/x86/crypto/blake2s-shash.c
arch/x86/events/intel/core.c
arch/x86/events/intel/lbr.c
arch/x86/events/intel/pt.c
arch/x86/events/intel/uncore.c
arch/x86/events/intel/uncore.h
arch/x86/events/intel/uncore_discovery.c
arch/x86/events/intel/uncore_discovery.h
arch/x86/events/intel/uncore_snb.c
arch/x86/events/intel/uncore_snbep.c
arch/x86/events/perf_event.h
arch/x86/events/rapl.c
arch/x86/include/asm/bug.h
arch/x86/include/asm/kvm-x86-ops.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/xen/cpuid.h
arch/x86/include/asm/xen/hypervisor.h
arch/x86/include/uapi/asm/kvm.h
arch/x86/kernel/cpu/mce/amd.c
arch/x86/kernel/cpu/mce/intel.c
arch/x86/kernel/cpu/sgx/encl.c
arch/x86/kernel/resource.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/lapic.c
arch/x86/kvm/svm/nested.c
arch/x86/kvm/svm/sev.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/svm/svm.h
arch/x86/kvm/svm/svm_onhyperv.h
arch/x86/kvm/vmx/capabilities.h
arch/x86/kvm/vmx/evmcs.c
arch/x86/kvm/vmx/evmcs.h
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/vmcs12.c
arch/x86/kvm/vmx/vmcs12.h
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/kvm/xen.c
arch/x86/pci/fixup.c
arch/x86/xen/enlighten_hvm.c
arch/x86/xen/enlighten_pv.c
arch/x86/xen/smp_pv.c
arch/x86/xen/vga.c
block/bio-integrity.c
block/blk-core.c
block/blk-ia-ranges.c
block/blk-mq.c
block/fops.c
crypto/algapi.c
crypto/api.c
crypto/blake2s_generic.c
drivers/accessibility/speakup/speakup_dectlk.c
drivers/acpi/Kconfig
drivers/acpi/arm64/iort.c
drivers/acpi/ec.c
drivers/acpi/sleep.c
drivers/acpi/x86/s2idle.c
drivers/ata/libata-core.c
drivers/ata/pata_platform.c
drivers/ata/sata_fsl.c
drivers/base/power/wakeup.c
drivers/block/loop.c
drivers/block/loop.h
drivers/bus/mhi/pci_generic.c
drivers/char/random.c
drivers/clk/.kunitconfig [new file with mode: 0644]
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/at91/at91rm9200.c
drivers/clk/at91/at91sam9260.c
drivers/clk/at91/at91sam9g45.c
drivers/clk/at91/at91sam9n12.c
drivers/clk/at91/at91sam9rl.c
drivers/clk/at91/at91sam9x5.c
drivers/clk/at91/clk-master.c
drivers/clk/at91/dt-compat.c
drivers/clk/at91/pmc.h
drivers/clk/at91/sam9x60.c
drivers/clk/at91/sama5d2.c
drivers/clk/at91/sama5d3.c
drivers/clk/at91/sama5d4.c
drivers/clk/at91/sama7g5.c
drivers/clk/clk-cs2000-cp.c
drivers/clk/clk-fixed-factor.c
drivers/clk/clk-gate_test.c [new file with mode: 0644]
drivers/clk/clk-mux.c
drivers/clk/clk-renesas-pcie.c [new file with mode: 0644]
drivers/clk/clk-si5341.c
drivers/clk/clk-stm32mp1.c
drivers/clk/clk.c
drivers/clk/hisilicon/clk.c
drivers/clk/mediatek/clk-apmixed.c
drivers/clk/mediatek/clk-cpumux.c
drivers/clk/mediatek/clk-cpumux.h
drivers/clk/mediatek/clk-gate.c
drivers/clk/mediatek/clk-gate.h
drivers/clk/mediatek/clk-mt2701.c
drivers/clk/mediatek/clk-mt2712.c
drivers/clk/mediatek/clk-mt6765.c
drivers/clk/mediatek/clk-mt6779.c
drivers/clk/mediatek/clk-mt6797.c
drivers/clk/mediatek/clk-mt7622.c
drivers/clk/mediatek/clk-mt7629.c
drivers/clk/mediatek/clk-mt7986-apmixed.c
drivers/clk/mediatek/clk-mt8135.c
drivers/clk/mediatek/clk-mt8167.c
drivers/clk/mediatek/clk-mt8173.c
drivers/clk/mediatek/clk-mt8183.c
drivers/clk/mediatek/clk-mt8192.c
drivers/clk/mediatek/clk-mt8195-apmixedsys.c
drivers/clk/mediatek/clk-mt8195-apusys_pll.c
drivers/clk/mediatek/clk-mt8195-cam.c
drivers/clk/mediatek/clk-mt8195-ccu.c
drivers/clk/mediatek/clk-mt8195-img.c
drivers/clk/mediatek/clk-mt8195-imp_iic_wrap.c
drivers/clk/mediatek/clk-mt8195-infra_ao.c
drivers/clk/mediatek/clk-mt8195-ipe.c
drivers/clk/mediatek/clk-mt8195-mfg.c
drivers/clk/mediatek/clk-mt8195-peri_ao.c
drivers/clk/mediatek/clk-mt8195-scp_adsp.c
drivers/clk/mediatek/clk-mt8195-topckgen.c
drivers/clk/mediatek/clk-mt8195-vdec.c
drivers/clk/mediatek/clk-mt8195-vdo0.c
drivers/clk/mediatek/clk-mt8195-vdo1.c
drivers/clk/mediatek/clk-mt8195-venc.c
drivers/clk/mediatek/clk-mt8195-vpp0.c
drivers/clk/mediatek/clk-mt8195-vpp1.c
drivers/clk/mediatek/clk-mt8195-wpe.c
drivers/clk/mediatek/clk-mt8516.c
drivers/clk/mediatek/clk-mtk.c
drivers/clk/mediatek/clk-mtk.h
drivers/clk/mediatek/clk-mux.c
drivers/clk/mediatek/clk-mux.h
drivers/clk/mediatek/clk-pll.c
drivers/clk/mediatek/clk-pll.h [new file with mode: 0644]
drivers/clk/mediatek/reset.c
drivers/clk/microchip/Kconfig [new file with mode: 0644]
drivers/clk/microchip/Makefile
drivers/clk/microchip/clk-mpfs.c [new file with mode: 0644]
drivers/clk/mmp/clk-of-mmp2.c
drivers/clk/mvebu/armada-37xx-periph.c
drivers/clk/nxp/clk-lpc18xx-cgu.c
drivers/clk/pistachio/clk-pistachio.c
drivers/clk/qcom/kpss-xcc.c
drivers/clk/renesas/Kconfig
drivers/clk/renesas/Makefile
drivers/clk/renesas/r8a77990-cpg-mssr.c
drivers/clk/renesas/r8a77995-cpg-mssr.c
drivers/clk/renesas/r8a779a0-cpg-mssr.c
drivers/clk/renesas/r8a779f0-cpg-mssr.c
drivers/clk/renesas/r9a07g044-cpg.c
drivers/clk/renesas/rzg2l-cpg.c
drivers/clk/renesas/rzg2l-cpg.h
drivers/clk/rockchip/clk-rk3568.c
drivers/clk/rockchip/clk.c
drivers/clk/zynqmp/clk-gate-zynqmp.c
drivers/clk/zynqmp/clk-mux-zynqmp.c
drivers/clk/zynqmp/divider.c
drivers/clk/zynqmp/pll.c
drivers/clocksource/timer-ti-dm-systimer.c
drivers/connector/cn_proc.c
drivers/counter/counter-core.c
drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c
drivers/dma-buf/dma-heap.c
drivers/edac/altera_edac.c
drivers/edac/xgene_edac.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/libstub/arm64-stub.c
drivers/gpio/gpio-aggregator.c
drivers/gpio/gpio-sifive.c
drivers/gpio/gpio-sim.c
drivers/gpio/gpiolib-cdev.c
drivers/gpio/gpiolib-sysfs.c
drivers/gpio/gpiolib.h
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c
drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.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/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c
drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c
drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c
drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.c
drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c
drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h
drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c
drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c
drivers/gpu/drm/amd/display/dc/inc/core_types.h
drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
drivers/gpu/drm/amd/display/dc/inc/resource.h
drivers/gpu/drm/amd/pm/amdgpu_pm.c
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
drivers/gpu/drm/ast/ast_tables.h
drivers/gpu/drm/bridge/nwl-dsi.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_panel_orientation_quirks.c
drivers/gpu/drm/drm_privacy_screen.c
drivers/gpu/drm/drm_privacy_screen_x86.c
drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_drrs.c
drivers/gpu/drm/i915/display/intel_overlay.c
drivers/gpu/drm/i915/display/intel_tc.c
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
drivers/gpu/drm/i915/gem/i915_gem_object_types.h
drivers/gpu/drm/i915/gem/i915_gem_pages.c
drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c
drivers/gpu/drm/i915/gt/intel_gt.c
drivers/gpu/drm/i915/gt/intel_gt.h
drivers/gpu/drm/i915/gt/intel_gt_types.h
drivers/gpu/drm/i915/gt/uc/intel_guc.h
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_mm.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_vma.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_pm.h
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/i915/intel_uncore.h
drivers/gpu/drm/kmb/kmb_plane.c
drivers/gpu/drm/msm/adreno/a6xx_gpu.c
drivers/gpu/drm/msm/adreno/adreno_device.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c
drivers/gpu/drm/msm/dsi/dsi.c
drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/msm/msm_gpu.h
drivers/gpu/drm/msm/msm_gpu_devfreq.c
drivers/gpu/drm/mxsfb/mxsfb_kms.c
drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
drivers/gpu/drm/rockchip/rockchip_vop_reg.c
drivers/gpu/drm/vc4/vc4_crtc.c
drivers/gpu/drm/vc4/vc4_dsi.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/vc4/vc4_hdmi.h
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/hv/hv_balloon.c
drivers/hwmon/adt7470.c
drivers/hwmon/lm90.c
drivers/hwmon/nct6775.c
drivers/hwmon/pmbus/ir38064.c
drivers/iio/industrialio-buffer.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/ucma.c
drivers/infiniband/hw/hfi1/ipoib.h
drivers/infiniband/hw/hfi1/ipoib_main.c
drivers/infiniband/hw/hfi1/ipoib_tx.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/sw/rdmavt/qp.c
drivers/infiniband/sw/siw/siw.h
drivers/infiniband/sw/siw/siw_qp_rx.c
drivers/infiniband/sw/siw/siw_verbs.c
drivers/input/touchscreen/wm97xx-core.c
drivers/iommu/amd/init.c
drivers/iommu/intel/irq_remapping.c
drivers/iommu/ioasid.c
drivers/iommu/iommu.c
drivers/iommu/omap-iommu.c
drivers/irqchip/irq-apple-aic.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-loongson-pch-msi.c
drivers/irqchip/irq-realtek-rtl.c
drivers/irqchip/irq-sifive-plic.c
drivers/md/dm.c
drivers/md/md.c
drivers/misc/eeprom/at25.c
drivers/misc/eeprom/ee1004.c
drivers/misc/fastrpc.c
drivers/mmc/core/sd.c
drivers/mmc/host/moxart-mmc.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sh_mmcif.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_main.c
drivers/net/can/flexcan/flexcan-core.c
drivers/net/can/flexcan/flexcan.h
drivers/net/can/m_can/m_can.c
drivers/net/can/m_can/tcan4x5x-regmap.c
drivers/net/dsa/Kconfig
drivers/net/dsa/bcm_sf2.c
drivers/net/dsa/lantiq_gswip.c
drivers/net/dsa/mt7530.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/ocelot/felix_vsc9959.c
drivers/net/dsa/ocelot/seville_vsc9953.c
drivers/net/dsa/qca/ar9331.c
drivers/net/ethernet/3com/typhoon.c
drivers/net/ethernet/8390/etherh.c
drivers/net/ethernet/amd/declance.c
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
drivers/net/ethernet/amd/xgbe/xgbe-pci.c
drivers/net/ethernet/aquantia/atlantic/aq_filters.c
drivers/net/ethernet/broadcom/sb1250-mac.c
drivers/net/ethernet/cadence/macb_main.c
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
drivers/net/ethernet/freescale/fec_mpc52xx.c
drivers/net/ethernet/google/gve/gve.h
drivers/net/ethernet/google/gve/gve_adminq.c
drivers/net/ethernet/google/gve/gve_main.c
drivers/net/ethernet/google/gve/gve_rx.c
drivers/net/ethernet/google/gve/gve_rx_dqo.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
drivers/net/ethernet/i825xx/ether1.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/ibm/ibmvnic.h
drivers/net/ethernet/intel/e1000e/e1000.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_register.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
drivers/net/ethernet/intel/ice/ice.h
drivers/net/ethernet/intel/ice/ice_common.c
drivers/net/ethernet/intel/ice/ice_lag.c
drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/litex/Kconfig
drivers/net/ethernet/marvell/octeontx2/af/cgx.c
drivers/net/ethernet/marvell/octeontx2/af/lmac_common.h
drivers/net/ethernet/marvell/octeontx2/af/mbox.h
drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h
drivers/net/ethernet/marvell/octeontx2/af/rpm.c
drivers/net/ethernet/marvell/octeontx2/af/rpm.h
drivers/net/ethernet/marvell/octeontx2/af/rvu.c
drivers/net/ethernet/marvell/octeontx2/af/rvu.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en/qos.c
drivers/net/ethernet/mellanox/mlx5/core/en/rep/bond.c
drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c
drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c
drivers/net/ethernet/mellanox/mlx5/core/esw/diag/bridge_tracepoint.h
drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c
drivers/net/ethernet/mellanox/mlx5/core/port.c
drivers/net/ethernet/microchip/lan966x/lan966x_mac.c
drivers/net/ethernet/microchip/lan966x/lan966x_main.c
drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c
drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
drivers/net/ethernet/mscc/ocelot.c
drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
drivers/net/ethernet/seeq/ether3.c
drivers/net/ethernet/smsc/smc911x.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c
drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
drivers/net/ethernet/ti/cpsw_priv.c
drivers/net/ethernet/tundra/tsi108_eth.c
drivers/net/hamradio/yam.c
drivers/net/ieee802154/at86rf230.c
drivers/net/ieee802154/ca8210.c
drivers/net/ieee802154/mac802154_hwsim.c
drivers/net/ieee802154/mcr20a.c
drivers/net/ipa/ipa_power.c
drivers/net/ipa/ipa_power.h
drivers/net/ipa/ipa_uc.c
drivers/net/macsec.c
drivers/net/mdio/mdio-aspeed.c
drivers/net/phy/at803x.c
drivers/net/phy/broadcom.c
drivers/net/phy/marvell.c
drivers/net/phy/phy_device.c
drivers/net/phy/sfp-bus.c
drivers/net/usb/ax88179_178a.c
drivers/net/usb/ipheth.c
drivers/net/usb/qmi_wwan.c
drivers/net/veth.c
drivers/nvme/host/core.c
drivers/nvme/host/fabrics.c
drivers/nvme/host/fabrics.h
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/host/tcp.c
drivers/pci/controller/cadence/pci-j721e.c
drivers/pci/controller/dwc/pcie-kirin.c
drivers/pci/controller/pcie-mt7621.c
drivers/pci/msi/irqdomain.c
drivers/pci/msi/legacy.c
drivers/pci/msi/msi.c
drivers/pci/pcie/portdrv_core.c
drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c
drivers/phy/broadcom/Kconfig
drivers/phy/broadcom/phy-brcm-usb.c
drivers/phy/cadence/phy-cadence-sierra.c
drivers/phy/mediatek/phy-mtk-tphy.c
drivers/phy/phy-core-mipi-dphy.c
drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
drivers/phy/st/phy-stm32-usbphyc.c
drivers/phy/ti/phy-j721e-wiz.c
drivers/phy/xilinx/phy-zynqmp.c
drivers/pinctrl/Makefile
drivers/pinctrl/bcm/Kconfig
drivers/pinctrl/bcm/pinctrl-bcm2835.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/intel/pinctrl-intel.c
drivers/pinctrl/pinctrl-microchip-sgpio.c
drivers/pinctrl/pinctrl-thunderbay.c
drivers/pinctrl/pinctrl-zynqmp.c
drivers/pinctrl/sunxi/pinctrl-sun50i-h616.c
drivers/platform/surface/Kconfig
drivers/platform/x86/amd-pmc.c
drivers/platform/x86/asus-tf103c-dock.c
drivers/platform/x86/intel/crystal_cove_charger.c
drivers/platform/x86/intel/speed_select_if/isst_if_common.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/touchscreen_dmi.c
drivers/platform/x86/x86-android-tablets.c
drivers/regulator/max20086-regulator.c
drivers/remoteproc/Kconfig
drivers/remoteproc/qcom_q6v5.c
drivers/rpmsg/rpmsg_char.c
drivers/s390/cio/device.c
drivers/s390/scsi/zfcp_fc.c
drivers/scsi/3w-sas.c
drivers/scsi/53c700.c
drivers/scsi/bfa/bfad.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/elx/libefc/efc_els.c
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/myrs.c
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_sas.c
drivers/scsi/pm8001/pm80xx_hwi.c
drivers/scsi/pm8001/pm80xx_hwi.h
drivers/scsi/qedf/qedf_io.c
drivers/scsi/qedf/qedf_main.c
drivers/scsi/scsi_scan.c
drivers/scsi/ufs/ufshcd-pltfrm.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshci.h
drivers/soc/aspeed/aspeed-lpc-ctrl.c
drivers/soc/samsung/Kconfig
drivers/spi/spi-bcm-qspi.c
drivers/spi/spi-meson-spicc.c
drivers/spi/spi-mt65xx.c
drivers/spi/spi-stm32-qspi.c
drivers/spi/spi-stm32.c
drivers/spi/spi-uniphier.c
drivers/staging/fbtft/fbtft.h
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
drivers/target/iscsi/iscsi_target_tpg.c
drivers/tee/optee/core.c
drivers/tee/optee/ffa_abi.c
drivers/tee/optee/notif.c
drivers/tee/optee/optee_private.h
drivers/tee/optee/smc_abi.c
drivers/tty/n_gsm.c
drivers/tty/n_tty.c
drivers/tty/rpmsg_tty.c
drivers/tty/serial/8250/8250_of.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/8250/8250_pericom.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/stm32-usart.c
drivers/tty/vt/vt_ioctl.c
drivers/usb/cdns3/drd.c
drivers/usb/common/ulpi.c
drivers/usb/core/hcd.c
drivers/usb/core/port.c
drivers/usb/core/urb.c
drivers/usb/dwc2/gadget.c
drivers/usb/dwc3/dwc3-xilinx.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/composite.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_sourcesink.c
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/function/rndis.c
drivers/usb/gadget/legacy/raw_gadget.c
drivers/usb/gadget/udc/at91_udc.c
drivers/usb/gadget/udc/renesas_usb3.c
drivers/usb/host/xhci-plat.c
drivers/usb/misc/usb251xb.c
drivers/usb/serial/ch341.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/option.c
drivers/usb/storage/unusual_devs.h
drivers/usb/typec/port-mapper.c
drivers/usb/typec/tcpm/tcpci.c
drivers/usb/typec/tcpm/tcpci.h
drivers/usb/typec/tcpm/tcpm.c
drivers/usb/typec/ucsi/ucsi_ccg.c
drivers/video/console/Kconfig
drivers/video/fbdev/core/bitblit.c
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbcon.h
drivers/video/fbdev/core/fbcon_ccw.c
drivers/video/fbdev/core/fbcon_cw.c
drivers/video/fbdev/core/fbcon_rotate.h
drivers/video/fbdev/core/fbcon_ud.c
drivers/video/fbdev/core/fbmem.c
drivers/video/fbdev/core/tileblit.c
drivers/video/fbdev/hyperv_fb.c
drivers/video/fbdev/skeletonfb.c
drivers/xen/pci.c
fs/9p/fid.c
fs/Kconfig
fs/Makefile
fs/binfmt_elf.c
fs/binfmt_misc.c
fs/btrfs/block-group.c
fs/btrfs/ctree.h
fs/btrfs/ioctl.c
fs/btrfs/qgroup.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-checker.c
fs/btrfs/tree-log.c
fs/cachefiles/io.c
fs/ceph/caps.c
fs/ceph/file.c
fs/cifs/cifs_swn.c
fs/cifs/connect.c
fs/cifs/dfs_cache.c
fs/cifs/file.c
fs/cifs/fscache.c
fs/cifs/fscache.h
fs/cifs/inode.c
fs/cifs/sess.c
fs/cifs/smb1ops.c
fs/cifs/transport.c
fs/configfs/dir.c
fs/devpts/inode.c
fs/erofs/data.c
fs/erofs/zdata.c
fs/erofs/zmap.c
fs/ext4/acl.c
fs/ext4/ext4.h
fs/ext4/ext4_jbd2.h
fs/ext4/extents.c
fs/ext4/fast_commit.c
fs/ext4/hash.c
fs/ext4/indirect.c
fs/ext4/inline.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/migrate.c
fs/ext4/namei.c
fs/ext4/orphan.c
fs/ext4/super.c
fs/ext4/sysfs.c
fs/ext4/xattr.c
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/hash.c
fs/f2fs/namei.c
fs/f2fs/recovery.c
fs/f2fs/super.c
fs/f2fs/sysfs.c
fs/file_table.c
fs/gfs2/file.c
fs/gfs2/glock.c
fs/io_uring.c
fs/iomap/buffered-io.c
fs/jbd2/commit.c
fs/jbd2/journal.c
fs/jbd2/transaction.c
fs/ksmbd/auth.c
fs/ksmbd/smb2pdu.c
fs/ksmbd/smb_common.c
fs/ksmbd/transport_rdma.c
fs/ksmbd/vfs.h
fs/libfs.c
fs/lockd/svcsubs.c
fs/namei.c
fs/nfs/callback.h
fs/nfs/callback_proc.c
fs/nfs/callback_xdr.c
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/filelayout/filelayout.h
fs/nfs/filelayout/filelayoutdev.c
fs/nfs/internal.h
fs/nfs/nfs3proc.c
fs/nfs/nfs42proc.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4client.c
fs/nfs/nfs4namespace.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/sysfs.c
fs/nfsd/nfs3proc.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/trace.h
fs/nfsd/vfs.c
fs/nfsd/vfs.h
fs/notify/fanotify/fanotify_user.c
fs/ocfs2/stackglue.c
fs/ocfs2/suballoc.c
fs/overlayfs/copy_up.c
fs/proc/task_mmu.c
fs/quota/dquot.c
fs/super.c
fs/sync.c
fs/udf/inode.c
fs/unicode/Kconfig
fs/unicode/Makefile
fs/xfs/xfs_aops.c
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_file.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_pnfs.c
fs/xfs/xfs_super.c
include/crypto/internal/blake2s.h
include/dt-bindings/clock/at91.h
include/dt-bindings/clock/cirrus,cs2000-cp.h [new file with mode: 0644]
include/dt-bindings/clock/dra7.h
include/dt-bindings/clock/microchip,mpfs-clock.h [new file with mode: 0644]
include/dt-bindings/clock/r9a07g054-cpg.h [new file with mode: 0644]
include/linux/ata.h
include/linux/blkdev.h
include/linux/ceph/libceph.h
include/linux/ceph/messenger.h
include/linux/clk-provider.h
include/linux/compiler.h
include/linux/ethtool.h
include/linux/fb.h
include/linux/fs.h
include/linux/fsnotify.h
include/linux/if_vlan.h
include/linux/iomap.h
include/linux/jbd2.h
include/linux/kfence.h
include/linux/kvm_host.h
include/linux/libata.h
include/linux/lsm_hook_defs.h
include/linux/memcontrol.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/netdevice.h
include/linux/netfs.h
include/linux/nfs.h
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/nfs_xdr.h
include/linux/page_table_check.h
include/linux/perf_event.h
include/linux/pgtable.h
include/linux/pid_namespace.h
include/linux/psi.h
include/linux/psi_types.h
include/linux/quota.h
include/linux/sched.h
include/linux/skbuff.h
include/linux/suspend.h
include/linux/sysctl.h
include/linux/usb/role.h
include/net/addrconf.h
include/net/ax25.h
include/net/bonding.h
include/net/dst_metadata.h
include/net/ip.h
include/net/ip6_fib.h
include/net/neighbour.h
include/net/route.h
include/net/tcp.h
include/sound/pcm.h
include/trace/events/skb.h
include/trace/events/sunrpc.h
include/trace/perf.h
include/trace/trace_events.h
include/uapi/linux/cyclades.h [new file with mode: 0644]
include/uapi/linux/kvm.h
include/uapi/linux/netfilter/nf_conntrack_common.h
include/uapi/linux/perf_event.h
include/uapi/linux/smc_diag.h
include/uapi/sound/asound.h
include/uapi/xen/gntdev.h
include/xen/xenbus_dev.h
ipc/sem.c
kernel/async.c
kernel/audit.c
kernel/auditsc.c
kernel/bpf/bpf_lsm.c
kernel/bpf/ringbuf.c
kernel/bpf/stackmap.c
kernel/bpf/trampoline.c
kernel/cgroup/cgroup-v1.c
kernel/cgroup/cgroup.c
kernel/cgroup/cpuset.c
kernel/events/core.c
kernel/module.c
kernel/power/main.c
kernel/power/process.c
kernel/power/snapshot.c
kernel/power/suspend.c
kernel/power/wakelock.c
kernel/printk/sysctl.c
kernel/rcu/tasks.h
kernel/sched/core.c
kernel/sched/core_sched.c
kernel/sched/fair.c
kernel/sched/membarrier.c
kernel/sched/pelt.h
kernel/sched/psi.c
kernel/seccomp.c
kernel/signal.c
kernel/stackleak.c
kernel/trace/Kconfig
kernel/trace/trace.c
kernel/trace/trace_events_hist.c
kernel/ucount.c
lib/crypto/blake2s.c
lib/sbitmap.c
lib/test_kasan.c
mm/debug_vm_pgtable.c
mm/gup.c
mm/kfence/core.c
mm/kfence/kfence_test.c
mm/khugepaged.c
mm/kmemleak.c
mm/memcontrol.c
mm/memory-failure.c
mm/page_isolation.c
mm/page_table_check.c
mm/vmscan.c
net/8021q/vlan.h
net/8021q/vlan_dev.c
net/8021q/vlan_netlink.c
net/ax25/af_ax25.c
net/ax25/ax25_dev.c
net/ax25/ax25_route.c
net/bridge/br_vlan.c
net/bridge/netfilter/nft_reject_bridge.c
net/can/isotp.c
net/ceph/ceph_common.c
net/ceph/messenger.c
net/ceph/messenger_v1.c
net/ceph/messenger_v2.c
net/core/neighbour.c
net/core/net-procfs.c
net/core/rtnetlink.c
net/core/skbuff.c
net/dsa/dsa2.c
net/ieee802154/nl802154.c
net/ipv4/ip_output.c
net/ipv4/ipmr.c
net/ipv4/netfilter/Kconfig
net/ipv4/ping.c
net/ipv4/raw.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv6/addrconf.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/Makefile
net/ipv6/netfilter/nf_flow_table_ipv6.c [deleted file]
net/ipv6/route.c
net/mpls/af_mpls.c
net/mptcp/pm_netlink.c
net/mptcp/protocol.h
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_netbios_ns.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_byteorder.c
net/netfilter/nft_connlimit.c
net/netfilter/nft_ct.c
net/netfilter/nft_exthdr.c
net/netfilter/nft_payload.c
net/packet/af_packet.c
net/rxrpc/call_event.c
net/rxrpc/output.c
net/sched/cls_api.c
net/sched/sch_api.c
net/sched/sch_htb.c
net/smc/af_smc.c
net/smc/smc.h
net/smc/smc_diag.c
net/smc/smc_pnet.c
net/sunrpc/auth_gss/gss_generic_token.c
net/sunrpc/clnt.c
net/sunrpc/rpc_pipe.c
net/sunrpc/sysfs.c
net/sunrpc/xprtrdma/backchannel.c
net/sunrpc/xprtrdma/frwr_ops.c
net/sunrpc/xprtrdma/rpc_rdma.c
net/sunrpc/xprtrdma/transport.c
net/sunrpc/xprtrdma/verbs.c
net/sunrpc/xprtsock.c
net/tipc/link.c
net/tipc/monitor.c
net/tipc/name_distr.c
samples/seccomp/dropper.c
scripts/Makefile
scripts/Makefile.extrawarn
scripts/kconfig/confdata.c
scripts/kconfig/preprocess.c
security/integrity/digsig_asymmetric.c
security/integrity/ima/ima_fs.c
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_template.c
security/integrity/integrity_audit.c
security/security.c
security/selinux/ss/conditional.c
sound/core/pcm_native.c
sound/hda/intel-sdw-acpi.c
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/patch_realtek.c
sound/soc/amd/acp/acp-mach-common.c
sound/soc/codecs/cpcap.c
sound/soc/codecs/hdmi-codec.c
sound/soc/codecs/lpass-rx-macro.c
sound/soc/codecs/max9759.c
sound/soc/codecs/rt5682-i2c.c
sound/soc/codecs/rt5682.c
sound/soc/codecs/rt5682.h
sound/soc/codecs/wcd938x.c
sound/soc/fsl/pcm030-audio-fabric.c
sound/soc/generic/simple-card.c
sound/soc/mediatek/Kconfig
sound/soc/qcom/qdsp6/q6apm-dai.c
sound/soc/soc-acpi.c
sound/soc/soc-ops.c
sound/soc/soc-pcm.c
sound/soc/xilinx/xlnx_formatter_pcm.c
sound/usb/mixer.c
sound/usb/quirks-table.h
tools/arch/x86/include/asm/cpufeatures.h
tools/arch/x86/include/uapi/asm/kvm.h
tools/bpf/resolve_btfids/Makefile
tools/bpf/runqslower/runqslower.bpf.c
tools/bpf/runqslower/runqslower.c
tools/bpf/runqslower/runqslower.h
tools/include/uapi/linux/kvm.h
tools/include/uapi/linux/lirc.h [deleted file]
tools/include/uapi/linux/perf_event.h
tools/include/uapi/linux/prctl.h
tools/include/uapi/sound/asound.h
tools/lib/perf/mmap.c
tools/lib/perf/tests/test-evsel.c
tools/objtool/check.c
tools/perf/builtin-ftrace.c
tools/perf/trace/beauty/prctl_option.sh
tools/perf/util/annotate.c
tools/perf/util/bpf_counter_cgroup.c
tools/perf/util/machine.c
tools/perf/util/map_symbol.h
tools/perf/util/perf_event_attr_fprintf.c
tools/perf/util/session.c
tools/perf/util/sort.c
tools/perf/util/stat-display.c
tools/perf/util/synthetic-events.c
tools/scripts/Makefile.include
tools/testing/kunit/kunit_kernel.py
tools/testing/kunit/run_checks.py
tools/testing/scatterlist/linux/mm.h
tools/testing/selftests/arm64/fp/sve-ptrace.c
tools/testing/selftests/bpf/test_lirc_mode2_user.c
tools/testing/selftests/clone3/clone3.c
tools/testing/selftests/cpufreq/main.sh
tools/testing/selftests/exec/Makefile
tools/testing/selftests/futex/Makefile
tools/testing/selftests/ir/ir_loopback.c
tools/testing/selftests/kselftest_harness.h
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/include/kvm_util_base.h
tools/testing/selftests/kvm/include/x86_64/processor.h
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/lib/x86_64/processor.c
tools/testing/selftests/kvm/x86_64/amx_test.c
tools/testing/selftests/kvm/x86_64/smm_test.c
tools/testing/selftests/mincore/mincore_selftest.c
tools/testing/selftests/net/ioam6_parser.c
tools/testing/selftests/net/mptcp/mptcp_join.sh
tools/testing/selftests/netfilter/nft_concat_range.sh
tools/testing/selftests/netfilter/nft_nat.sh
tools/testing/selftests/netfilter/nft_zones_many.sh
tools/testing/selftests/openat2/Makefile
tools/testing/selftests/openat2/helpers.h
tools/testing/selftests/openat2/openat2_test.c
tools/testing/selftests/perf_events/sigtrap_threads.c
tools/testing/selftests/pidfd/pidfd.h
tools/testing/selftests/pidfd/pidfd_fdinfo_test.c
tools/testing/selftests/pidfd/pidfd_test.c
tools/testing/selftests/pidfd/pidfd_wait.c
tools/testing/selftests/rtc/settings
tools/testing/selftests/vDSO/vdso_test_abi.c
tools/testing/selftests/vm/userfaultfd.c
tools/testing/selftests/zram/zram.sh
tools/testing/selftests/zram/zram01.sh
tools/testing/selftests/zram/zram02.sh
tools/testing/selftests/zram/zram_lib.sh
tools/tracing/Makefile
tools/tracing/rtla/Makefile
tools/tracing/rtla/src/osnoise.c
tools/tracing/rtla/src/osnoise_hist.c
tools/tracing/rtla/src/osnoise_top.c
tools/tracing/rtla/src/timerlat_hist.c
tools/tracing/rtla/src/timerlat_top.c
tools/tracing/rtla/src/trace.c
tools/tracing/rtla/src/utils.c
usr/include/Makefile
virt/kvm/eventfd.c
virt/kvm/kvm_main.c

index b157f88..8cd44b0 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -70,6 +70,7 @@ Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@bootlin.com>
 Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@free-electrons.com>
 Brian Avery <b.avery@hp.com>
 Brian King <brking@us.ibm.com>
+Brian Silverman <bsilver16384@gmail.com> <brian.silverman@bluerivertech.com>
 Changbin Du <changbin.du@intel.com> <changbin.du@gmail.com>
 Changbin Du <changbin.du@intel.com> <changbin.du@intel.com>
 Chao Yu <chao@kernel.org> <chao2.yu@samsung.com>
@@ -79,6 +80,9 @@ Chris Chiu <chris.chiu@canonical.com> <chiu@endlessos.org>
 Christian Borntraeger <borntraeger@linux.ibm.com> <borntraeger@de.ibm.com>
 Christian Borntraeger <borntraeger@linux.ibm.com> <cborntra@de.ibm.com>
 Christian Borntraeger <borntraeger@linux.ibm.com> <borntrae@de.ibm.com>
+Christian Brauner <brauner@kernel.org> <christian@brauner.io>
+Christian Brauner <brauner@kernel.org> <christian.brauner@canonical.com>
+Christian Brauner <brauner@kernel.org> <christian.brauner@ubuntu.com>
 Christophe Ricard <christophe.ricard@gmail.com>
 Christoph Hellwig <hch@lst.de>
 Colin Ian King <colin.king@intel.com> <colin.king@canonical.com>
index b363827..910df0e 100644 (file)
@@ -1,4 +1,4 @@
-What:          /sys/bus/platform/drivers/aspeed-uart-routing/*/uart*
+What:          /sys/bus/platform/drivers/aspeed-uart-routing/\*/uart\*
 Date:          September 2021
 Contact:       Oskar Senft <osk@google.com>
                Chia-Wei Wang <chiawei_wang@aspeedtech.com>
@@ -9,7 +9,7 @@ Description:    Selects the RX source of the UARTx device.
                depends on the selected file.
 
                e.g.
-               cat /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1
+               cat /sys/bus/platform/drivers/aspeed-uart-routing/\*.uart_routing/uart1
                [io1] io2 io3 io4 uart2 uart3 uart4 io6
 
                In this case, UART1 gets its input from IO1 (physical serial port 1).
@@ -17,7 +17,7 @@ Description:  Selects the RX source of the UARTx device.
 Users:         OpenBMC.  Proposed changes should be mailed to
                openbmc@lists.ozlabs.org
 
-What:          /sys/bus/platform/drivers/aspeed-uart-routing/*/io*
+What:          /sys/bus/platform/drivers/aspeed-uart-routing/\*/io\*
 Date:          September 2021
 Contact:       Oskar Senft <osk@google.com>
                Chia-Wei Wang <chiawei_wang@aspeedtech.com>
index f2b3439..860fe65 100644 (file)
@@ -92,7 +92,8 @@ Triggers can be set on more than one psi metric and more than one trigger
 for the same psi metric can be specified. However for each trigger a separate
 file descriptor is required to be able to poll it separately from others,
 therefore for each trigger a separate open() syscall should be made even
-when opening the same psi interface file.
+when opening the same psi interface file. Write operations to a file descriptor
+with an already existing psi trigger will fail with EBUSY.
 
 Monitors activate only when system enters stall state for the monitored
 psi metric and deactivates upon exit from the stall state. While system is
index 7db3675..f6861ca 100644 (file)
@@ -10,6 +10,7 @@ gpio
     gpio-aggregator
     sysfs
     gpio-mockup
+    gpio-sim
 
 .. only::  subproject and html
 
index 9485a5a..2f41caa 100644 (file)
@@ -266,10 +266,12 @@ Avanta family
 -------------
 
   Flavors:
+       - 88F6500
        - 88F6510
        - 88F6530P
        - 88F6550
        - 88F6560
+       - 88F6601
 
   Homepage:
        https://web.archive.org/web/20181005145041/http://www.marvell.com/broadband/
index 5342e89..ea281dd 100644 (file)
@@ -52,6 +52,12 @@ stable kernels.
 | Allwinner      | A64/R18         | UNKNOWN1        | SUN50I_ERRATUM_UNKNOWN1     |
 +----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A510     | #2064142        | ARM64_ERRATUM_2064142       |
++----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A510     | #2038923        | ARM64_ERRATUM_2038923       |
++----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A510     | #1902691        | ARM64_ERRATUM_1902691       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A53      | #826319         | ARM64_ERRATUM_826319        |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A53      | #827319         | ARM64_ERRATUM_827319        |
@@ -92,12 +98,20 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A77      | #1508412        | ARM64_ERRATUM_1508412       |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A510     | #2051678        | ARM64_ERRATUM_2051678       |
++----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A510     | #2077057        | ARM64_ERRATUM_2077057       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A710     | #2119858        | ARM64_ERRATUM_2119858       |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A710     | #2054223        | ARM64_ERRATUM_2054223       |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A710     | #2224489        | ARM64_ERRATUM_2224489       |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-X2       | #2119858        | ARM64_ERRATUM_2119858       |
++----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-X2       | #2224489        | ARM64_ERRATUM_2224489       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Neoverse-N1     | #1188873,1418040| ARM64_ERRATUM_1418040       |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Neoverse-N1     | #1349291        | N/A                         |
index dcefee7..a833ecf 100644 (file)
@@ -7,6 +7,14 @@ directory. These are intended to be small tests to exercise individual code
 paths in the kernel. Tests are intended to be run after building, installing
 and booting a kernel.
 
+Kselftest from mainline can be run on older stable kernels. Running tests
+from mainline offers the best coverage. Several test rings run mainline
+kselftest suite on stable releases. The reason is that when a new test
+gets added to test existing code to regression test a bug, we should be
+able to run that test on an older kernel. Hence, it is important to keep
+code that can still test an older kernel and make sure it skips the test
+gracefully on newer releases.
+
 You can find additional information on Kselftest framework, how to
 write new tests using the framework on Kselftest wiki:
 
index 76af931..1c83e7d 100644 (file)
@@ -242,7 +242,7 @@ example:
 
        int rectangle_area(struct shape *this)
        {
-               struct rectangle *self = container_of(this, struct shape, parent);
+               struct rectangle *self = container_of(this, struct rectangle, parent);
 
                return self->length * self->width;
        };
index e77635c..fa8b316 100644 (file)
@@ -119,6 +119,9 @@ Boards (incomplete list of examples):
 - OMAP3 BeagleBoard : Low cost community board
   compatible = "ti,omap3-beagle", "ti,omap3430", "ti,omap3"
 
+- OMAP3 BeagleBoard A to B4 : Early BeagleBoard revisions A to B4 with a timer quirk
+  compatible = "ti,omap3-beagle-ab4", "ti,omap3-beagle", "ti,omap3430", "ti,omap3"
+
 - OMAP3 Tobi with Overo : Commercial expansion board with daughter board
   compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3430", "ti,omap3"
 
diff --git a/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml b/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml
new file mode 100644 (file)
index 0000000..0abd6ba
--- /dev/null
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/cirrus,cs2000-cp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Binding CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier
+
+maintainers:
+  - Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+description: |
+  The CS2000-CP is an extremely versatile system clocking device that
+  utilizes a programmable phase lock loop.
+
+  Link: https://www.cirrus.com/products/cs2000/
+
+properties:
+  compatible:
+    enum:
+      - cirrus,cs2000-cp
+
+  clocks:
+    description:
+      Common clock binding for CLK_IN, XTI/REF_CLK
+    minItems: 2
+    maxItems: 2
+
+  clock-names:
+    items:
+      - const: clk_in
+      - const: ref_clk
+
+  '#clock-cells':
+    const: 0
+
+  reg:
+    maxItems: 1
+
+  cirrus,aux-output-source:
+    description:
+      Specifies the function of the auxiliary clock output pin
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum:
+      - 0 # CS2000CP_AUX_OUTPUT_REF_CLK:  ref_clk input
+      - 1 # CS2000CP_AUX_OUTPUT_CLK_IN:   clk_in input
+      - 2 # CS2000CP_AUX_OUTPUT_CLK_OUT:  clk_out output
+      - 3 # CS2000CP_AUX_OUTPUT_PLL_LOCK: pll lock status
+    default: 0
+
+  cirrus,clock-skip:
+    description:
+      This mode allows the PLL to maintain lock even when CLK_IN
+      has missing pulses for up to 20 ms.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+  cirrus,dynamic-mode:
+    description:
+      In dynamic mode, the CLK_IN input is used to drive the
+      digital PLL of the silicon.
+      If not given, the static mode shall be used to derive the
+      output signal directly from the REF_CLK input.
+    $ref: /schemas/types.yaml#/definitions/flag
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/cirrus,cs2000-cp.h>
+
+    i2c@0 {
+      reg = <0x0 0x100>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      clock-controller@4f {
+        #clock-cells = <0>;
+        compatible = "cirrus,cs2000-cp";
+        reg = <0x4f>;
+        clocks = <&rcar_sound 0>, <&x12_clk>;
+        clock-names = "clk_in", "ref_clk";
+        cirrus,aux-output-source = <CS2000CP_AUX_OUTPUT_CLK_OUT>;
+      };
+    };
diff --git a/Documentation/devicetree/bindings/clock/cs2000-cp.txt b/Documentation/devicetree/bindings/clock/cs2000-cp.txt
deleted file mode 100644 (file)
index 54e6df0..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier
-
-Required properties:
-
-- compatible:          "cirrus,cs2000-cp"
-- reg:                 The chip select number on the I2C bus
-- clocks:              common clock binding for CLK_IN, XTI/REF_CLK
-- clock-names:         CLK_IN : clk_in, XTI/REF_CLK : ref_clk
-- #clock-cells:                must be <0>
-
-Example:
-
-&i2c2 {
-       ...
-       cs2000: clk_multiplier@4f {
-               #clock-cells = <0>;
-               compatible = "cirrus,cs2000-cp";
-               reg = <0x4f>;
-               clocks = <&rcar_sound 0>, <&x12_clk>;
-               clock-names = "clk_in", "ref_clk";
-       };
-};
diff --git a/Documentation/devicetree/bindings/clock/microchip,mpfs.yaml b/Documentation/devicetree/bindings/clock/microchip,mpfs.yaml
new file mode 100644 (file)
index 0000000..0c15afa
--- /dev/null
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/microchip,mpfs.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip PolarFire Clock Control Module Binding
+
+maintainers:
+  - Daire McNamara <daire.mcnamara@microchip.com>
+
+description: |
+  Microchip PolarFire clock control (CLKCFG) is an integrated clock controller,
+  which gates and enables all peripheral clocks.
+
+  This device tree binding describes 33 gate clocks.  Clocks are referenced by
+  user nodes by the CLKCFG node phandle and the clock index in the group, from
+  0 to 32.
+
+properties:
+  compatible:
+    const: microchip,mpfs-clkcfg
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 1
+    description: |
+      The clock consumer should specify the desired clock by having the clock
+      ID in its "clocks" phandle cell. See include/dt-bindings/clock/microchip,mpfs-clock.h
+      for the full list of PolarFire clock IDs.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+  # Clock Config node:
+  - |
+    #include <dt-bindings/clock/microchip,mpfs-clock.h>
+    soc {
+            #address-cells = <2>;
+            #size-cells = <2>;
+            clkcfg: clock-controller@20002000 {
+                compatible = "microchip,mpfs-clkcfg";
+                reg = <0x0 0x20002000 0x0 0x1000>;
+                clocks = <&ref>;
+                #clock-cells = <1>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/clock/renesas,9series.yaml b/Documentation/devicetree/bindings/clock/renesas,9series.yaml
new file mode 100644 (file)
index 0000000..102eb95
--- /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/clock/renesas,9series.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Binding for Renesas 9-series I2C PCIe clock generators
+
+description: |
+  The Renesas 9-series are I2C PCIe clock generators providing
+  from 1 to 20 output clocks.
+
+  When referencing the provided clock in the DT using phandle
+  and clock specifier, the following mapping applies:
+
+  - 9FGV0241:
+    0 -- DIF0
+    1 -- DIF1
+
+maintainers:
+  - Marek Vasut <marex@denx.de>
+
+properties:
+  compatible:
+    enum:
+      - renesas,9fgv0241
+
+  reg:
+    description: I2C device address
+    enum: [ 0x68, 0x6a ]
+
+  '#clock-cells':
+    const: 1
+
+  clocks:
+    items:
+      - description: XTal input clock
+
+  renesas,out-amplitude-microvolt:
+    enum: [ 600000, 700000, 800000, 900000 ]
+    description: Output clock signal amplitude
+
+  renesas,out-spread-spectrum:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [ 100000, 99750, 99500 ]
+    description: Output clock down spread in pcm (1/1000 of percent)
+
+patternProperties:
+  "^DIF[0-19]$":
+    type: object
+    description:
+      Description of one of the outputs (DIF0..DIF19).
+
+    properties:
+      renesas,slew-rate:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [ 2000000, 3000000 ]
+        description: Output clock slew rate select in V/ns
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    /* 25MHz reference crystal */
+    ref25: ref25m {
+        compatible = "fixed-clock";
+        #clock-cells = <0>;
+        clock-frequency = <25000000>;
+    };
+
+    i2c@0 {
+        reg = <0x0 0x100>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        rs9: clock-generator@6a {
+            compatible = "renesas,9fgv0241";
+            reg = <0x6a>;
+            #clock-cells = <1>;
+
+            clocks = <&ref25m>;
+
+            DIF0 {
+                renesas,slew-rate = <3000000>;
+            };
+        };
+    };
+
+...
index c55a7c4..2197c95 100644 (file)
@@ -51,6 +51,18 @@ additionalProperties: false
 examples:
   - |
     #include <dt-bindings/clock/r8a73a4-clock.h>
+
+    cpg_clocks: cpg_clocks@e6150000 {
+            compatible = "renesas,r8a73a4-cpg-clocks";
+            reg = <0xe6150000 0x10000>;
+            clocks = <&extal1_clk>, <&extal2_clk>;
+            #clock-cells = <1>;
+            clock-output-names = "main", "pll0", "pll1", "pll2",
+                                  "pll2s", "pll2h", "z", "z2",
+                                  "i", "m3", "b", "m1", "m2",
+                                  "zx", "zs", "hp";
+    };
+
     sdhi2_clk: sdhi2_clk@e615007c {
             compatible = "renesas,r8a73a4-div6-clock", "renesas,cpg-div6-clock";
             reg = <0xe615007c 4>;
index 30b2e3d..bd3af8f 100644 (file)
@@ -4,13 +4,13 @@
 $id: "http://devicetree.org/schemas/clock/renesas,rzg2l-cpg.yaml#"
 $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 
-title: Renesas RZ/G2L Clock Pulse Generator / Module Standby Mode
+title: Renesas RZ/{G2L,V2L} Clock Pulse Generator / Module Standby Mode
 
 maintainers:
   - Geert Uytterhoeven <geert+renesas@glider.be>
 
 description: |
-  On Renesas RZ/G2L SoC, the CPG (Clock Pulse Generator) and Module
+  On Renesas RZ/{G2L,V2L} SoC, the CPG (Clock Pulse Generator) and Module
   Standby Mode share the same register block.
 
   They provide the following functionalities:
@@ -22,7 +22,9 @@ description: |
 
 properties:
   compatible:
-    const: renesas,r9a07g044-cpg  # RZ/G2{L,LC}
+    enum:
+      - renesas,r9a07g044-cpg  # RZ/G2{L,LC}
+      - renesas,r9a07g054-cpg  # RZ/V2L
 
   reg:
     maxItems: 1
@@ -40,9 +42,9 @@ properties:
     description: |
       - For CPG core clocks, the two clock specifier cells must be "CPG_CORE"
         and a core clock reference, as defined in
-        <dt-bindings/clock/r9a07g044-cpg.h>
+        <dt-bindings/clock/r9a07g*-cpg.h>
       - For module clocks, the two clock specifier cells must be "CPG_MOD" and
-        a module number, as defined in the <dt-bindings/clock/r9a07g044-cpg.h>.
+        a module number, as defined in the <dt-bindings/clock/r9a07g0*-cpg.h>.
     const: 2
 
   '#power-domain-cells':
@@ -56,7 +58,7 @@ properties:
   '#reset-cells':
     description:
       The single reset specifier cell must be the module number, as defined in
-      the <dt-bindings/clock/r9a07g044-cpg.h>.
+      the <dt-bindings/clock/r9a07g0*-cpg.h>.
     const: 1
 
 required:
index 79d0358..620f017 100644 (file)
@@ -36,6 +36,7 @@ properties:
           - renesas,intc-ex-r8a77980    # R-Car V3H
           - renesas,intc-ex-r8a77990    # R-Car E3
           - renesas,intc-ex-r8a77995    # R-Car D3
+          - renesas,intc-ex-r8a779a0    # R-Car V3U
       - const: renesas,irqc
 
   '#interrupt-cells':
index 28b6b17..27092c6 100644 (file)
@@ -35,6 +35,10 @@ description:
   contains a specific memory layout, which is documented in chapter 8 of the
   SiFive U5 Coreplex Series Manual <https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf>.
 
+  The thead,c900-plic is different from sifive,plic-1.0.0 in opensbi, the
+  T-HEAD PLIC implementation requires setting a delegation bit to allow access
+  from S-mode. So add thead,c900-plic to distinguish them.
+
 maintainers:
   - Sagar Kadam <sagar.kadam@sifive.com>
   - Paul Walmsley  <paul.walmsley@sifive.com>
@@ -42,12 +46,17 @@ maintainers:
 
 properties:
   compatible:
-    items:
-      - enum:
-          - sifive,fu540-c000-plic
-          - starfive,jh7100-plic
-          - canaan,k210-plic
-      - const: sifive,plic-1.0.0
+    oneOf:
+      - items:
+          - enum:
+              - sifive,fu540-c000-plic
+              - starfive,jh7100-plic
+              - canaan,k210-plic
+          - const: sifive,plic-1.0.0
+      - items:
+          - enum:
+              - allwinner,sun20i-d1-plic
+          - const: thead,c900-plic
 
   reg:
     maxItems: 1
@@ -62,6 +71,7 @@ properties:
 
   interrupts-extended:
     minItems: 1
+    maxItems: 15872
     description:
       Specifies which contexts are connected to the PLIC, with "-1" specifying
       that a context is not present. Each node pointed to should be a
@@ -90,12 +100,11 @@ examples:
       #interrupt-cells = <1>;
       compatible = "sifive,fu540-c000-plic", "sifive,plic-1.0.0";
       interrupt-controller;
-      interrupts-extended = <
-        &cpu0_intc 11
-        &cpu1_intc 11 &cpu1_intc 9
-        &cpu2_intc 11 &cpu2_intc 9
-        &cpu3_intc 11 &cpu3_intc 9
-        &cpu4_intc 11 &cpu4_intc 9>;
+      interrupts-extended = <&cpu0_intc 11>,
+                            <&cpu1_intc 11>, <&cpu1_intc 9>,
+                            <&cpu2_intc 11>, <&cpu2_intc 9>,
+                            <&cpu3_intc 11>, <&cpu3_intc 9>,
+                            <&cpu4_intc 11>, <&cpu4_intc 9>;
       reg = <0xc000000 0x4000000>;
       riscv,ndev = <10>;
     };
index 0968b40..e3501bf 100644 (file)
@@ -31,7 +31,7 @@ tcan4x5x: tcan4x5x@0 {
                #address-cells = <1>;
                #size-cells = <1>;
                spi-max-frequency = <10000000>;
-               bosch,mram-cfg = <0x0 0 0 32 0 0 1 1>;
+               bosch,mram-cfg = <0x0 0 0 16 0 0 1 1>;
                interrupt-parent = <&gpio1>;
                interrupts = <14 IRQ_TYPE_LEVEL_LOW>;
                device-state-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
index b86edf6..58ecc62 100644 (file)
@@ -107,6 +107,10 @@ properties:
           - const: imem
           - const: config
 
+  qcom,qmp:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: phandle to the AOSS side-channel message RAM
+
   qcom,smem-states:
     $ref: /schemas/types.yaml#/definitions/phandle-array
     description: State bits used in by the AP to signal the modem.
@@ -222,6 +226,8 @@ examples:
                                      "imem",
                                      "config";
 
+                qcom,qmp = <&aoss_qmp>;
+
                 qcom,smem-states = <&ipa_smp2p_out 0>,
                                    <&ipa_smp2p_out 1>;
                 qcom,smem-state-names = "ipa-clock-enabled-valid",
index 5dd2092..3ec2d7b 100644 (file)
@@ -23,8 +23,9 @@ properties:
     minItems: 1
     maxItems: 256
     items:
-      minimum: 0
-      maximum: 256
+      items:
+        - minimum: 0
+          maximum: 256
     description:
       Chip select used by the device.
 
index 136f8da..4f373a8 100644 (file)
@@ -462,6 +462,10 @@ operation table looks like the following::
                             struct iov_iter *iter,
                             netfs_io_terminated_t term_func,
                             void *term_func_priv);
+
+               int (*query_occupancy)(struct netfs_cache_resources *cres,
+                                      loff_t start, size_t len, size_t granularity,
+                                      loff_t *_data_start, size_t *_data_len);
        };
 
 With a termination handler function pointer::
@@ -536,6 +540,18 @@ The methods defined in the table are:
    indicating whether the termination is definitely happening in the caller's
    context.
 
+ * ``query_occupancy()``
+
+   [Required] Called to find out where the next piece of data is within a
+   particular region of the cache.  The start and length of the region to be
+   queried are passed in, along with the granularity to which the answer needs
+   to be aligned.  The function passes back the start and length of the data,
+   if any, available within that region.  Note that there may be a hole at the
+   front.
+
+   It returns 0 if some data was found, -ENODATA if there was no usable data
+   within the region or -ENOBUFS if there is no caching on this file.
+
 Note that these methods are passed a pointer to the cache resource structure,
 not the read request structure as they could be used in other situations where
 there isn't a read request structure as well, such as writing dirty data to the
index da138dd..a1212b5 100644 (file)
@@ -300,30 +300,6 @@ Contact: Daniel Vetter, Noralf Tronnes
 
 Level: Advanced
 
-Garbage collect fbdev scrolling acceleration
---------------------------------------------
-
-Scroll acceleration has been disabled in fbcon. Now it works as the old
-SCROLL_REDRAW mode. A ton of code was removed in fbcon.c and the hook bmove was
-removed from fbcon_ops.
-Remaining tasks:
-
-- a bunch of the hooks in fbcon_ops could be removed or simplified by calling
-  directly instead of the function table (with a switch on p->rotate)
-
-- fb_copyarea is unused after this, and can be deleted from all drivers
-
-- after that, fb_copyarea can be deleted from fb_ops in include/linux/fb.h as
-  well as cfb_copyarea
-
-Note that not all acceleration code can be deleted, since clearing and cursor
-support is still accelerated, which might be good candidates for further
-deletion projects.
-
-Contact: Daniel Vetter
-
-Level: Intermediate
-
 idr_init_base()
 ---------------
 
index 2b4de39..b58692d 100644 (file)
@@ -166,6 +166,7 @@ to ReStructured Text format, or are simply too old.
 .. toctree::
    :maxdepth: 2
 
+   tools/index
    staging/index
    watch_queue
 
index e6cd406..4cbd50e 100644 (file)
@@ -295,7 +295,7 @@ Pete Zaitcev gives the following summary:
 
 -  If you are in a process context (any syscall) and want to lock other
    process out, use a mutex. You can take a mutex and sleep
-   (``copy_from_user*(`` or ``kmalloc(x,GFP_KERNEL)``).
+   (``copy_from_user()`` or ``kmalloc(x,GFP_KERNEL)``).
 
 -  Otherwise (== data can be touched in an interrupt), use
    spin_lock_irqsave() and
diff --git a/Documentation/tools/index.rst b/Documentation/tools/index.rst
new file mode 100644 (file)
index 0000000..0bb1e61
--- /dev/null
@@ -0,0 +1,20 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============
+Kernel tools
+============
+
+This book covers user-space tools that are shipped with the kernel source;
+more additions are needed here:
+
+.. toctree::
+   :maxdepth: 1
+
+   rtla/index
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/tools/rtla/index.rst b/Documentation/tools/rtla/index.rst
new file mode 100644 (file)
index 0000000..840f0bf
--- /dev/null
@@ -0,0 +1,26 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================================
+The realtime Linux analysis tool
+================================
+
+RTLA provides a set of tools for the analysis of the kernel's realtime
+behavior on specific hardware.
+
+.. toctree::
+   :maxdepth: 1
+
+   rtla
+   rtla-osnoise
+   rtla-osnoise-hist
+   rtla-osnoise-top
+   rtla-timerlat
+   rtla-timerlat-hist
+   rtla-timerlat-top
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
index 687efcf..e6fce2c 100644 (file)
@@ -115,6 +115,7 @@ Code  Seq#    Include File                                           Comments
 'B'   00-1F  linux/cciss_ioctl.h                                     conflict!
 'B'   00-0F  include/linux/pmu.h                                     conflict!
 'B'   C0-FF  advanced bbus                                           <mailto:maassen@uni-freiburg.de>
+'B'   00-0F  xen/xenbus_dev.h                                        conflict!
 'C'   all    linux/soundcard.h                                       conflict!
 'C'   01-2F  linux/capi.h                                            conflict!
 'C'   F0-FF  drivers/net/wan/cosa.h                                  conflict!
@@ -134,6 +135,7 @@ Code  Seq#    Include File                                           Comments
 'F'   80-8F  linux/arcfb.h                                           conflict!
 'F'   DD     video/sstfb.h                                           conflict!
 'G'   00-3F  drivers/misc/sgi-gru/grulib.h                           conflict!
+'G'   00-0F  xen/gntalloc.h, xen/gntdev.h                            conflict!
 'H'   00-7F  linux/hiddev.h                                          conflict!
 'H'   00-0F  linux/hidraw.h                                          conflict!
 'H'   01     linux/mei.h                                             conflict!
@@ -176,6 +178,7 @@ Code  Seq#    Include File                                           Comments
 'P'   60-6F  sound/sscape_ioctl.h                                    conflict!
 'P'   00-0F  drivers/usb/class/usblp.c                               conflict!
 'P'   01-09  drivers/misc/pci_endpoint_test.c                        conflict!
+'P'   00-0F  xen/privcmd.h                                           conflict!
 'Q'   all    linux/soundcard.h
 'R'   00-1F  linux/random.h                                          conflict!
 'R'   01     linux/rfkill.h                                          conflict!
index bb8cfdd..a426710 100644 (file)
@@ -3268,6 +3268,7 @@ number.
 
 :Capability: KVM_CAP_DEVICE_CTRL, KVM_CAP_VM_ATTRIBUTES for vm device,
              KVM_CAP_VCPU_ATTRIBUTES for vcpu device
+             KVM_CAP_SYS_ATTRIBUTES for system (/dev/kvm) device (no set)
 :Type: device ioctl, vm ioctl, vcpu ioctl
 :Parameters: struct kvm_device_attr
 :Returns: 0 on success, -1 on error
@@ -3302,7 +3303,8 @@ transferred is defined by the particular attribute.
 ------------------------
 
 :Capability: KVM_CAP_DEVICE_CTRL, KVM_CAP_VM_ATTRIBUTES for vm device,
-            KVM_CAP_VCPU_ATTRIBUTES for vcpu device
+             KVM_CAP_VCPU_ATTRIBUTES for vcpu device
+             KVM_CAP_SYS_ATTRIBUTES for system (/dev/kvm) device
 :Type: device ioctl, vm ioctl, vcpu ioctl
 :Parameters: struct kvm_device_attr
 :Returns: 0 on success, -1 on error
index 81f521f..1a09472 100644 (file)
@@ -9,7 +9,7 @@ Page Table Check
 Introduction
 ============
 
-Page table check allows to hardern the kernel by ensuring that some types of
+Page table check allows to harden the kernel by ensuring that some types of
 the memory corruptions are prevented.
 
 Page table check performs extra verifications at the time when new pages become
index 1593312..3ef38d9 100644 (file)
@@ -190,8 +190,9 @@ M:  Johannes Berg <johannes@sipsolutions.net>
 L:     linux-wireless@vger.kernel.org
 S:     Maintained
 W:     https://wireless.wiki.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
+Q:     https://patchwork.kernel.org/project/linux-wireless/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
 F:     Documentation/driver-api/80211/cfg80211.rst
 F:     Documentation/networking/regulatory.rst
 F:     include/linux/ieee80211.h
@@ -1619,6 +1620,7 @@ M:        Olof Johansson <olof@lixom.net>
 M:     soc@kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
+C:     irc://irc.libera.chat/armlinux
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git
 F:     arch/arm/boot/dts/Makefile
 F:     arch/arm64/boot/dts/Makefile
@@ -1626,6 +1628,7 @@ F:        arch/arm64/boot/dts/Makefile
 ARM SUB-ARCHITECTURES
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
+C:     irc://irc.libera.chat/armlinux
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git
 F:     arch/arm/mach-*/
 F:     arch/arm/plat-*/
@@ -1779,6 +1782,7 @@ F:        drivers/irqchip/irq-apple-aic.c
 F:     drivers/mailbox/apple-mailbox.c
 F:     drivers/pinctrl/pinctrl-apple-gpio.c
 F:     drivers/soc/apple/*
+F:     drivers/watchdog/apple_wdt.c
 F:     include/dt-bindings/interrupt-controller/apple-aic.h
 F:     include/dt-bindings/pinctrl/apple.h
 F:     include/linux/apple-mailbox.h
@@ -2569,10 +2573,13 @@ N:      rockchip
 
 ARM/SAMSUNG S3C, S5P AND EXYNOS ARM ARCHITECTURES
 M:     Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+R:     Alim Akhtar <alim.akhtar@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-samsung-soc@vger.kernel.org
 S:     Maintained
+C:     irc://irc.libera.chat/linux-exynos
 Q:     https://patchwork.kernel.org/project/linux-samsung-soc/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git
 F:     Documentation/arm/samsung/
 F:     Documentation/devicetree/bindings/arm/samsung/
 F:     Documentation/devicetree/bindings/power/pd-samsung.yaml
@@ -4156,9 +4163,8 @@ N:        csky
 K:     csky
 
 CA8210 IEEE-802.15.4 RADIO DRIVER
-M:     Harry Morris <h.morris@cascoda.com>
 L:     linux-wpan@vger.kernel.org
-S:     Maintained
+S:     Orphan
 W:     https://github.com/Cascoda/ca8210-linux.git
 F:     Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
 F:     drivers/net/ieee802154/ca8210.c
@@ -5772,7 +5778,7 @@ F:        tools/testing/selftests/dma/
 
 DMA-BUF HEAPS FRAMEWORK
 M:     Sumit Semwal <sumit.semwal@linaro.org>
-R:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
+R:     Benjamin Gaignard <benjamin.gaignard@collabora.com>
 R:     Liam Mark <lmark@codeaurora.org>
 R:     Laura Abbott <labbott@redhat.com>
 R:     Brian Starkey <Brian.Starkey@arm.com>
@@ -6502,7 +6508,7 @@ F:        Documentation/devicetree/bindings/display/rockchip/
 F:     drivers/gpu/drm/rockchip/
 
 DRM DRIVERS FOR STI
-M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
+M:     Alain Volmat <alain.volmat@foss.st.com>
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
 T:     git git://anongit.freedesktop.org/drm/drm-misc
@@ -6511,8 +6517,8 @@ F:        drivers/gpu/drm/sti
 
 DRM DRIVERS FOR STM
 M:     Yannick Fertre <yannick.fertre@foss.st.com>
+M:     Raphael Gallais-Pou <raphael.gallais-pou@foss.st.com>
 M:     Philippe Cornu <philippe.cornu@foss.st.com>
-M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
 T:     git git://anongit.freedesktop.org/drm/drm-misc
@@ -7208,8 +7214,10 @@ F:       drivers/net/mdio/of_mdio.c
 F:     drivers/net/pcs/
 F:     drivers/net/phy/
 F:     include/dt-bindings/net/qca-ar803x.h
+F:     include/linux/linkmode.h
 F:     include/linux/*mdio*.h
 F:     include/linux/mdio/*.h
+F:     include/linux/mii.h
 F:     include/linux/of_net.h
 F:     include/linux/phy.h
 F:     include/linux/phy_fixed.h
@@ -7573,6 +7581,12 @@ S:       Maintained
 W:     http://floatingpoint.sourceforge.net/emulator/index.html
 F:     arch/x86/math-emu/
 
+FRAMEBUFFER CORE
+M:     Daniel Vetter <daniel@ffwll.ch>
+F:     drivers/video/fbdev/core/
+S:     Odd Fixes
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+
 FRAMEBUFFER LAYER
 M:     Helge Deller <deller@gmx.de>
 L:     linux-fbdev@vger.kernel.org
@@ -10877,6 +10891,12 @@ 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
+R:     Sergey Shtylyov <s.shtylyov@omp.ru>
+L:     linux-ide@vger.kernel.org
+F:     drivers/ata/ata_*.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
@@ -11366,8 +11386,9 @@ M:      Johannes Berg <johannes@sipsolutions.net>
 L:     linux-wireless@vger.kernel.org
 S:     Maintained
 W:     https://wireless.wiki.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
+Q:     https://patchwork.kernel.org/project/linux-wireless/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
 F:     Documentation/networking/mac80211-injection.rst
 F:     Documentation/networking/mac80211_hwsim/mac80211_hwsim.rst
 F:     drivers/net/wireless/mac80211_hwsim.[ch]
@@ -12396,7 +12417,7 @@ F:      include/uapi/linux/membarrier.h
 F:     kernel/sched/membarrier.c
 
 MEMBLOCK
-M:     Mike Rapoport <rppt@linux.ibm.com>
+M:     Mike Rapoport <rppt@kernel.org>
 L:     linux-mm@kvack.org
 S:     Maintained
 F:     Documentation/core-api/boot-time-mm.rst
@@ -13294,8 +13315,8 @@ W:      http://www.iptables.org/
 W:     http://www.nftables.org/
 Q:     http://patchwork.ozlabs.org/project/netfilter-devel/list/
 C:     irc://irc.libera.chat/netfilter
-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
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next.git
 F:     include/linux/netfilter*
 F:     include/linux/netfilter/
 F:     include/net/netfilter/
@@ -13374,9 +13395,10 @@ NETWORKING DRIVERS (WIRELESS)
 M:     Kalle Valo <kvalo@kernel.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
+W:     https://wireless.wiki.kernel.org/
+Q:     https://patchwork.kernel.org/project/linux-wireless/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
 F:     Documentation/devicetree/bindings/net/wireless/
 F:     drivers/net/wireless/
 
@@ -13449,7 +13471,11 @@ L:     netdev@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
 F:     arch/x86/net/*
+F:     include/linux/ip.h
+F:     include/linux/ipv6*
+F:     include/net/fib*
 F:     include/net/ip*
+F:     include/net/route.h
 F:     net/ipv4/
 F:     net/ipv6/
 
@@ -13510,10 +13536,6 @@ 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/
-
 NETXEN (1/10) GbE SUPPORT
 M:     Manish Chopra <manishc@marvell.com>
 M:     Rahul Verma <rahulv@marvell.com>
@@ -13561,7 +13583,7 @@ F:      tools/testing/selftests/nci/
 
 NFS, SUNRPC, AND LOCKD CLIENTS
 M:     Trond Myklebust <trond.myklebust@hammerspace.com>
-M:     Anna Schumaker <anna.schumaker@netapp.com>
+M:     Anna Schumaker <anna@kernel.org>
 L:     linux-nfs@vger.kernel.org
 S:     Maintained
 W:     http://client.linux-nfs.org
@@ -14382,6 +14404,7 @@ M:      Rob Herring <robh+dt@kernel.org>
 M:     Frank Rowand <frowand.list@gmail.com>
 L:     devicetree@vger.kernel.org
 S:     Maintained
+C:     irc://irc.libera.chat/devicetree
 W:     http://www.devicetree.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
 F:     Documentation/ABI/testing/sysfs-firmware-ofw
@@ -14393,6 +14416,7 @@ OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
 M:     Rob Herring <robh+dt@kernel.org>
 L:     devicetree@vger.kernel.org
 S:     Maintained
+C:     irc://irc.libera.chat/devicetree
 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/
@@ -15283,9 +15307,11 @@ PIN CONTROLLER - SAMSUNG
 M:     Tomasz Figa <tomasz.figa@gmail.com>
 M:     Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
 M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
+R:     Alim Akhtar <alim.akhtar@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-samsung-soc@vger.kernel.org
 S:     Maintained
+C:     irc://irc.libera.chat/linux-exynos
 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
@@ -16467,6 +16493,14 @@ F:     Documentation/devicetree/bindings/i2c/renesas,rmobile-iic.yaml
 F:     drivers/i2c/busses/i2c-rcar.c
 F:     drivers/i2c/busses/i2c-sh_mobile.c
 
+RENESAS R-CAR SATA DRIVER
+R:     Sergey Shtylyov <s.shtylyov@omp.ru>
+S:     Supported
+L:     linux-ide@vger.kernel.org
+L:     linux-renesas-soc@vger.kernel.org
+F:     Documentation/devicetree/bindings/ata/renesas,rcar-sata.yaml
+F:     drivers/ata/sata_rcar.c
+
 RENESAS R-CAR THERMAL DRIVERS
 M:     Niklas Söderlund <niklas.soderlund@ragnatech.se>
 L:     linux-renesas-soc@vger.kernel.org
@@ -16535,8 +16569,9 @@ M:      Johannes Berg <johannes@sipsolutions.net>
 L:     linux-wireless@vger.kernel.org
 S:     Maintained
 W:     https://wireless.wiki.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
+Q:     https://patchwork.kernel.org/project/linux-wireless/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
 F:     Documentation/ABI/stable/sysfs-class-rfkill
 F:     Documentation/driver-api/rfkill.rst
 F:     include/linux/rfkill.h
@@ -16801,8 +16836,8 @@ F:      drivers/video/fbdev/savage/
 S390
 M:     Heiko Carstens <hca@linux.ibm.com>
 M:     Vasily Gorbik <gor@linux.ibm.com>
-M:     Christian Borntraeger <borntraeger@linux.ibm.com>
-R:     Alexander Gordeev <agordeev@linux.ibm.com>
+M:     Alexander Gordeev <agordeev@linux.ibm.com>
+R:     Christian Borntraeger <borntraeger@linux.ibm.com>
 R:     Sven Schnelle <svens@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
 S:     Supported
@@ -17073,6 +17108,7 @@ 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>
+R:     Alim Akhtar <alim.akhtar@samsung.com>
 L:     linux-samsung-soc@vger.kernel.org
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk.git
@@ -17709,6 +17745,21 @@ S:     Maintained
 W:     http://www.winischhofer.at/linuxsisusbvga.shtml
 F:     drivers/usb/misc/sisusbvga/
 
+SL28 CPLD MFD DRIVER
+M:     Michael Walle <michael@walle.cc>
+S:     Maintained
+F:     Documentation/devicetree/bindings/gpio/kontron,sl28cpld-gpio.yaml
+F:     Documentation/devicetree/bindings/hwmon/kontron,sl28cpld-hwmon.yaml
+F:     Documentation/devicetree/bindings/interrupt-controller/kontron,sl28cpld-intc.yaml
+F:     Documentation/devicetree/bindings/mfd/kontron,sl28cpld.yaml
+F:     Documentation/devicetree/bindings/pwm/kontron,sl28cpld-pwm.yaml
+F:     Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml
+F:     drivers/gpio/gpio-sl28cpld.c
+F:     drivers/hwmon/sl28cpld-hwmon.c
+F:     drivers/irqchip/irq-sl28cpld.c
+F:     drivers/pwm/pwm-sl28cpld.c
+F:     drivers/watchdog/sl28cpld_wdt.c
+
 SLAB ALLOCATOR
 M:     Christoph Lameter <cl@linux.com>
 M:     Pekka Enberg <penberg@kernel.org>
@@ -18425,7 +18476,7 @@ F:      Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt
 F:     sound/soc/sti/
 
 STI CEC DRIVER
-M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
+M:     Alain Volmat <alain.volmat@foss.st.com>
 S:     Maintained
 F:     Documentation/devicetree/bindings/media/stih-cec.txt
 F:     drivers/media/cec/platform/sti/
@@ -19579,6 +19630,14 @@ F:     Documentation/trace/timerlat-tracer.rst
 F:     Documentation/trace/hwlat_detector.rst
 F:     arch/*/kernel/trace.c
 
+Real-time Linux Analysis (RTLA) tools
+M:     Daniel Bristot de Oliveira <bristot@kernel.org>
+M:     Steven Rostedt <rostedt@goodmis.org>
+L:     linux-trace-devel@vger.kernel.org
+S:     Maintained
+F:     Documentation/tools/rtla/
+F:     tools/tracing/rtla/
+
 TRADITIONAL CHINESE DOCUMENTATION
 M:     Hu Haowen <src.res@email.cn>
 L:     linux-doc-tw-discuss@lists.sourceforge.net
index 0fb4f94..51e142f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,8 +2,8 @@
 VERSION = 5
 PATCHLEVEL = 17
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
-NAME = Gobble Gobble
+EXTRAVERSION = -rc4
+NAME = Superb Owl
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
index fabe391..4c97cb4 100644 (file)
@@ -83,6 +83,7 @@ config ARM
        select HAVE_EBPF_JIT if !CPU_ENDIAN_BE32
        select HAVE_CONTEXT_TRACKING
        select HAVE_C_RECORDMCOUNT
+       select HAVE_BUILDTIME_MCOUNT_SORT
        select HAVE_DEBUG_KMEMLEAK if !XIP_KERNEL
        select HAVE_DMA_CONTIGUOUS if MMU
        select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU
index 235ad55..e41eca7 100644 (file)
@@ -806,6 +806,7 @@ dtb-$(CONFIG_ARCH_OMAP3) += \
        logicpd-som-lv-37xx-devkit.dtb \
        omap3430-sdp.dtb \
        omap3-beagle.dtb \
+       omap3-beagle-ab4.dtb \
        omap3-beagle-xm.dtb \
        omap3-beagle-xm-ab.dtb \
        omap3-cm-t3517.dtb \
index 673159d..f957fea 100644 (file)
@@ -55,7 +55,7 @@
                2 1 0 0 /* # 0: INACTIVE, 1: TX, 2: RX */
        >;
        tx-num-evt = <16>;
-       rt-num-evt = <16>;
+       rx-num-evt = <16>;
        status = "okay";
 };
 
index 6b485cb..42bff11 100644 (file)
                target-module@48210000 {
                        compatible = "ti,sysc-omap4-simple", "ti,sysc";
                        power-domains = <&prm_mpu>;
-                       clocks = <&mpu_clkctrl DRA7_MPU_CLKCTRL 0>;
+                       clocks = <&mpu_clkctrl DRA7_MPU_MPU_CLKCTRL 0>;
                        clock-names = "fck";
                        #address-cells = <1>;
                        #size-cells = <1>;
                              <0x58000014 4>;
                        reg-names = "rev", "syss";
                        ti,syss-mask = <1>;
-                       clocks = <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 0>,
-                                <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 9>,
-                                <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 10>,
-                                <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 11>;
+                       clocks = <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 0>,
+                                <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 9>,
+                                <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 10>,
+                                <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 11>;
                        clock-names = "fck", "hdmi_clk", "sys_clk", "tv_clk";
                        #address-cells = <1>;
                        #size-cells = <1>;
                                                         SYSC_OMAP2_SOFTRESET |
                                                         SYSC_OMAP2_AUTOIDLE)>;
                                        ti,syss-mask = <1>;
-                                       clocks = <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 8>;
+                                       clocks = <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 8>;
                                        clock-names = "fck";
                                        #address-cells = <1>;
                                        #size-cells = <1>;
                                                        <SYSC_IDLE_SMART>,
                                                        <SYSC_IDLE_SMART_WKUP>;
                                        ti,sysc-mask = <(SYSC_OMAP4_SOFTRESET)>;
-                                       clocks = <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 9>,
-                                                <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 8>;
+                                       clocks = <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 9>,
+                                                <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 8>;
                                        clock-names = "fck", "dss_clk";
                                        #address-cells = <1>;
                                        #size-cells = <1>;
                                compatible = "vivante,gc";
                                reg = <0x0 0x700>;
                                interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&dss_clkctrl DRA7_BB2D_CLKCTRL 0>;
+                               clocks = <&dss_clkctrl DRA7_DSS_BB2D_CLKCTRL 0>;
                                clock-names = "core";
                        };
                };
        ti,no-reset-on-init;
        ti,no-idle;
        timer@0 {
-               assigned-clocks = <&wkupaon_clkctrl DRA7_TIMER1_CLKCTRL 24>;
+               assigned-clocks = <&wkupaon_clkctrl DRA7_WKUPAON_TIMER1_CLKCTRL 24>;
                assigned-clock-parents = <&sys_32k_ck>;
        };
 };
index 8cbaf1c..3b609d9 100644 (file)
@@ -79,7 +79,6 @@
                                                MX23_PAD_LCD_RESET__GPIO_1_18
                                                MX23_PAD_PWM3__GPIO_1_29
                                                MX23_PAD_PWM4__GPIO_1_30
-                                               MX23_PAD_SSP1_DETECT__SSP1_DETECT
                                        >;
                                        fsl,drive-strength = <MXS_DRIVE_4mA>;
                                        fsl,voltage = <MXS_VOLTAGE_HIGH>;
index d07d8f8..ccfa8e3 100644 (file)
@@ -5,6 +5,8 @@
  * Author: Fabio Estevam <fabio.estevam@freescale.com>
  */
 
+#include <dt-bindings/gpio/gpio.h>
+
 / {
        aliases {
                backlight = &backlight;
                                MX6QDL_PAD_SD3_DAT1__SD3_DATA1          0x17059
                                MX6QDL_PAD_SD3_DAT2__SD3_DATA2          0x17059
                                MX6QDL_PAD_SD3_DAT3__SD3_DATA3          0x17059
+                               MX6QDL_PAD_SD3_DAT5__GPIO7_IO00         0x1b0b0
                        >;
                };
 
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       non-removable;
+       cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
index b7ea37a..bcec98b 100644 (file)
                        interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&pcc2 IMX7ULP_CLK_WDG1>;
                        assigned-clocks = <&pcc2 IMX7ULP_CLK_WDG1>;
-                       assigned-clocks-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>;
+                       assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>;
                        timeout-sec = <40>;
                };
 
index 3be7cba..26eaba3 100644 (file)
@@ -59,7 +59,7 @@
                        };
 
                        uart_A: serial@84c0 {
-                               compatible = "amlogic,meson6-uart", "amlogic,meson-uart";
+                               compatible = "amlogic,meson6-uart";
                                reg = <0x84c0 0x18>;
                                interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
                                fifo-size = <128>;
@@ -67,7 +67,7 @@
                        };
 
                        uart_B: serial@84dc {
-                               compatible = "amlogic,meson6-uart", "amlogic,meson-uart";
+                               compatible = "amlogic,meson6-uart";
                                reg = <0x84dc 0x18>;
                                interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>;
                                status = "disabled";
                        };
 
                        uart_C: serial@8700 {
-                               compatible = "amlogic,meson6-uart", "amlogic,meson-uart";
+                               compatible = "amlogic,meson6-uart";
                                reg = <0x8700 0x18>;
                                interrupts = <GIC_SPI 93 IRQ_TYPE_EDGE_RISING>;
                                status = "disabled";
                        };
 
                        uart_AO: serial@4c0 {
-                               compatible = "amlogic,meson6-uart", "amlogic,meson-ao-uart", "amlogic,meson-uart";
+                               compatible = "amlogic,meson6-uart", "amlogic,meson-ao-uart";
                                reg = <0x4c0 0x18>;
                                interrupts = <GIC_SPI 90 IRQ_TYPE_EDGE_RISING>;
                                status = "disabled";
index f80ddc9..9997a5d 100644 (file)
 };
 
 &uart_AO {
-       compatible = "amlogic,meson8-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_CLK81>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8-uart", "amlogic,meson-ao-uart";
+       clocks = <&xtal>, <&clkc CLKID_CLK81>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &uart_A {
-       compatible = "amlogic,meson8-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_UART0>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8-uart";
+       clocks = <&xtal>, <&clkc CLKID_UART0>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &uart_B {
-       compatible = "amlogic,meson8-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_UART1>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8-uart";
+       clocks = <&xtal>, <&clkc CLKID_UART0>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &uart_C {
-       compatible = "amlogic,meson8-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_UART2>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8-uart";
+       clocks = <&xtal>, <&clkc CLKID_UART0>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &usb0 {
index b49b7cb..94f1c03 100644 (file)
 };
 
 &uart_AO {
-       compatible = "amlogic,meson8b-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_CLK81>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8b-uart", "amlogic,meson-ao-uart";
+       clocks = <&xtal>, <&clkc CLKID_CLK81>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &uart_A {
-       compatible = "amlogic,meson8b-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_UART0>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8b-uart";
+       clocks = <&xtal>, <&clkc CLKID_UART0>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &uart_B {
-       compatible = "amlogic,meson8b-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_UART1>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8b-uart";
+       clocks = <&xtal>, <&clkc CLKID_UART0>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &uart_C {
-       compatible = "amlogic,meson8b-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_UART2>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8b-uart";
+       clocks = <&xtal>, <&clkc CLKID_UART0>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &usb0 {
diff --git a/arch/arm/boot/dts/omap3-beagle-ab4.dts b/arch/arm/boot/dts/omap3-beagle-ab4.dts
new file mode 100644 (file)
index 0000000..990ff2d
--- /dev/null
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/dts-v1/;
+
+#include "omap3-beagle.dts"
+
+/ {
+       model = "TI OMAP3 BeagleBoard A to B4";
+       compatible = "ti,omap3-beagle-ab4", "ti,omap3-beagle", "ti,omap3430", "ti,omap3";
+};
+
+/*
+ * Workaround for capacitor C70 issue, see "Boards revision A and < B5"
+ * section at https://elinux.org/BeagleBoard_Community
+ */
+
+/* Unusable as clocksource because of unreliable oscillator */
+&counter32k {
+       status = "disabled";
+};
+
+/* Unusable as clockevent because of unreliable oscillator, allow to idle */
+&timer1_target {
+       /delete-property/ti,no-reset-on-init;
+       /delete-property/ti,no-idle;
+       timer@0 {
+               /delete-property/ti,timer-alwon;
+       };
+};
+
+/* Preferred always-on timer for clocksource */
+&timer12_target {
+       ti,no-reset-on-init;
+       ti,no-idle;
+       timer@0 {
+               /* Always clocked by secure_32k_fck */
+       };
+};
+
+/* Preferred timer for clockevent */
+&timer2_target {
+       ti,no-reset-on-init;
+       ti,no-idle;
+       timer@0 {
+               assigned-clocks = <&gpt2_fck>;
+               assigned-clock-parents = <&sys_ck>;
+       };
+};
index f9f34b8..0548b39 100644 (file)
        phys = <0 &hsusb2_phy>;
 };
 
-/* Unusable as clocksource because of unreliable oscillator */
-&counter32k {
-       status = "disabled";
-};
-
-/* Unusable as clockevent because if unreliable oscillator, allow to idle */
-&timer1_target {
-       /delete-property/ti,no-reset-on-init;
-       /delete-property/ti,no-idle;
-       timer@0 {
-               /delete-property/ti,timer-alwon;
-       };
-};
-
-/* Preferred always-on timer for clocksource */
-&timer12_target {
-       ti,no-reset-on-init;
-       ti,no-idle;
-       timer@0 {
-               /* Always clocked by secure_32k_fck */
-       };
-};
-
-/* Preferred timer for clockevent */
-&timer2_target {
-       ti,no-reset-on-init;
-       ti,no-idle;
-       timer@0 {
-               assigned-clocks = <&gpt2_fck>;
-               assigned-clock-parents = <&sys_ck>;
-       };
-};
-
 &twl_gpio {
        ti,use-leds;
        /* pullups: BIT(1) */
index 367ba48..b587e4e 100644 (file)
                                        #address-cells = <1>;
                                        #size-cells = <0>;
                                        reg = <0x41>;
-                                       irq-over-gpio;
                                        irq-gpios = <&gpiopinctrl 29 0x4>;
                                        id = <0>;
                                        blocks = <0x5>;
index 580ca49..f8c5899 100644 (file)
                        cap-sd-highspeed;
                        cap-mmc-highspeed;
                        /* All direction control is used */
-                       st,sig-dir-cmd;
-                       st,sig-dir-dat0;
-                       st,sig-dir-dat2;
-                       st,sig-dir-dat31;
                        st,sig-pin-fbclk;
                        full-pwr-cycle;
                        vmmc-supply = <&ab8500_ldo_aux3_reg>;
index 17c1c3b..763c73b 100644 (file)
 static int crypto_blake2s_update_arm(struct shash_desc *desc,
                                     const u8 *in, unsigned int inlen)
 {
-       return crypto_blake2s_update(desc, in, inlen, blake2s_compress);
+       return crypto_blake2s_update(desc, in, inlen, false);
 }
 
 static int crypto_blake2s_final_arm(struct shash_desc *desc, u8 *out)
 {
-       return crypto_blake2s_final(desc, out, blake2s_compress);
+       return crypto_blake2s_final(desc, out, false);
 }
 
 #define BLAKE2S_ALG(name, driver_name, digest_size)                    \
index 7d23d4b..6fe6796 100644 (file)
  */
 #define ALT_UP(instr...)                                       \
        .pushsection ".alt.smp.init", "a"                       ;\
+       .align  2                                               ;\
        .long   9998b - .                                       ;\
 9997:  instr                                                   ;\
        .if . - 9997b == 2                                      ;\
        .popsection
 #define ALT_UP_B(label)                                        \
        .pushsection ".alt.smp.init", "a"                       ;\
+       .align  2                                               ;\
        .long   9998b - .                                       ;\
        W(b)    . + (label - 9998b)                                     ;\
        .popsection
index 6af68ed..bdc35c0 100644 (file)
@@ -96,6 +96,7 @@ unsigned long __get_wchan(struct task_struct *p);
 #define __ALT_SMP_ASM(smp, up)                                         \
        "9998:  " smp "\n"                                              \
        "       .pushsection \".alt.smp.init\", \"a\"\n"                \
+       "       .align  2\n"                                            \
        "       .long   9998b - .\n"                                    \
        "       " up "\n"                                               \
        "       .popsection\n"
index 36fbc33..32dbfd8 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/string.h>
 #include <asm/memory.h>
 #include <asm/domain.h>
+#include <asm/unaligned.h>
 #include <asm/unified.h>
 #include <asm/compiler.h>
 
@@ -497,7 +498,10 @@ do {                                                                       \
        }                                                               \
        default: __err = __get_user_bad(); break;                       \
        }                                                               \
-       *(type *)(dst) = __val;                                         \
+       if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))         \
+               put_unaligned(__val, (type *)(dst));                    \
+       else                                                            \
+               *(type *)(dst) = __val; /* aligned by caller */         \
        if (__err)                                                      \
                goto err_label;                                         \
 } while (0)
@@ -507,7 +511,9 @@ do {                                                                        \
        const type *__pk_ptr = (dst);                                   \
        unsigned long __dst = (unsigned long)__pk_ptr;                  \
        int __err = 0;                                                  \
-       type __val = *(type *)src;                                      \
+       type __val = IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) \
+                    ? get_unaligned((type *)(src))                     \
+                    : *(type *)(src);  /* aligned by caller */         \
        switch (sizeof(type)) {                                         \
        case 1: __put_user_asm_byte(__val, __dst, __err, ""); break;    \
        case 2: __put_user_asm_half(__val, __dst, __err, ""); break;    \
index 6daaa64..21413a9 100644 (file)
@@ -263,9 +263,9 @@ static int __init omapdss_init_of(void)
        }
 
        r = of_platform_populate(node, NULL, NULL, &pdev->dev);
+       put_device(&pdev->dev);
        if (r) {
                pr_err("Unable to populate DSS submodule devices\n");
-               put_device(&pdev->dev);
                return r;
        }
 
index ccb0e37..31d1a21 100644 (file)
@@ -752,8 +752,10 @@ static int __init _init_clkctrl_providers(void)
 
        for_each_matching_node(np, ti_clkctrl_match_table) {
                ret = _setup_clkctrl_provider(np);
-               if (ret)
+               if (ret) {
+                       of_node_put(np);
                        break;
+               }
        }
 
        return ret;
index 43ddec6..594edf9 100644 (file)
@@ -2,6 +2,7 @@
 menuconfig ARCH_INTEL_SOCFPGA
        bool "Altera SOCFPGA family"
        depends on ARCH_MULTI_V7
+       select ARCH_HAS_RESET_CONTROLLER
        select ARCH_SUPPORTS_BIG_ENDIAN
        select ARM_AMBA
        select ARM_GIC
@@ -18,6 +19,7 @@ menuconfig ARCH_INTEL_SOCFPGA
        select PL310_ERRATA_727915
        select PL310_ERRATA_753970 if PL310
        select PL310_ERRATA_769419
+       select RESET_CONTROLLER
 
 if ARCH_INTEL_SOCFPGA
 config SOCFPGA_SUSPEND
index 14db56f..6159010 100644 (file)
@@ -1,4 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
+KASAN_SANITIZE_actions-common.o := n
+KASAN_SANITIZE_actions-arm.o := n
+KASAN_SANITIZE_actions-thumb.o := n
 obj-$(CONFIG_KPROBES)          += core.o actions-common.o checkers-common.o
 obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o
 test-kprobes-objs              := test-core.o
index 6978140..09b885c 100644 (file)
@@ -670,15 +670,42 @@ config ARM64_ERRATUM_1508412
 config ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE
        bool
 
+config ARM64_ERRATUM_2051678
+       bool "Cortex-A510: 2051678: disable Hardware Update of the page table dirty bit"
+       default y
+       help
+         This options adds the workaround for ARM Cortex-A510 erratum ARM64_ERRATUM_2051678.
+         Affected Coretex-A510 might not respect the ordering rules for
+         hardware update of the page table's dirty bit. The workaround
+         is to not enable the feature on affected CPUs.
+
+         If unsure, say Y.
+
+config ARM64_ERRATUM_2077057
+       bool "Cortex-A510: 2077057: workaround software-step corrupting SPSR_EL2"
+       help
+         This option adds the workaround for ARM Cortex-A510 erratum 2077057.
+         Affected Cortex-A510 may corrupt SPSR_EL2 when the a step exception is
+         expected, but a Pointer Authentication trap is taken instead. The
+         erratum causes SPSR_EL1 to be copied to SPSR_EL2, which could allow
+         EL1 to cause a return to EL2 with a guest controlled ELR_EL2.
+
+         This can only happen when EL2 is stepping EL1.
+
+         When these conditions occur, the SPSR_EL2 value is unchanged from the
+         previous guest entry, and can be restored from the in-memory copy.
+
+         If unsure, say Y.
+
 config ARM64_ERRATUM_2119858
-       bool "Cortex-A710: 2119858: workaround TRBE overwriting trace data in FILL mode"
+       bool "Cortex-A710/X2: 2119858: workaround TRBE overwriting trace data in FILL mode"
        default y
        depends on CORESIGHT_TRBE
        select ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE
        help
-         This option adds the workaround for ARM Cortex-A710 erratum 2119858.
+         This option adds the workaround for ARM Cortex-A710/X2 erratum 2119858.
 
-         Affected Cortex-A710 cores could overwrite up to 3 cache lines of trace
+         Affected Cortex-A710/X2 cores could overwrite up to 3 cache lines of trace
          data at the base of the buffer (pointed to by TRBASER_EL1) in FILL mode in
          the event of a WRAP event.
 
@@ -761,14 +788,14 @@ config ARM64_ERRATUM_2253138
          If unsure, say Y.
 
 config ARM64_ERRATUM_2224489
-       bool "Cortex-A710: 2224489: workaround TRBE writing to address out-of-range"
+       bool "Cortex-A710/X2: 2224489: workaround TRBE writing to address out-of-range"
        depends on CORESIGHT_TRBE
        default y
        select ARM64_WORKAROUND_TRBE_WRITE_OUT_OF_RANGE
        help
-         This option adds the workaround for ARM Cortex-A710 erratum 2224489.
+         This option adds the workaround for ARM Cortex-A710/X2 erratum 2224489.
 
-         Affected Cortex-A710 cores might write to an out-of-range address, not reserved
+         Affected Cortex-A710/X2 cores might write to an out-of-range address, not reserved
          for TRBE. Under some conditions, the TRBE might generate a write to the next
          virtually addressed page following the last page of the TRBE address space
          (i.e., the TRBLIMITR_EL1.LIMIT), instead of wrapping around to the base.
@@ -778,6 +805,65 @@ config ARM64_ERRATUM_2224489
 
          If unsure, say Y.
 
+config ARM64_ERRATUM_2064142
+       bool "Cortex-A510: 2064142: workaround TRBE register writes while disabled"
+       depends on COMPILE_TEST # Until the CoreSight TRBE driver changes are in
+       default y
+       help
+         This option adds the workaround for ARM Cortex-A510 erratum 2064142.
+
+         Affected Cortex-A510 core might fail to write into system registers after the
+         TRBE has been disabled. Under some conditions after the TRBE has been disabled
+         writes into TRBE registers TRBLIMITR_EL1, TRBPTR_EL1, TRBBASER_EL1, TRBSR_EL1,
+         and TRBTRG_EL1 will be ignored and will not be effected.
+
+         Work around this in the driver by executing TSB CSYNC and DSB after collection
+         is stopped and before performing a system register write to one of the affected
+         registers.
+
+         If unsure, say Y.
+
+config ARM64_ERRATUM_2038923
+       bool "Cortex-A510: 2038923: workaround TRBE corruption with enable"
+       depends on COMPILE_TEST # Until the CoreSight TRBE driver changes are in
+       default y
+       help
+         This option adds the workaround for ARM Cortex-A510 erratum 2038923.
+
+         Affected Cortex-A510 core might cause an inconsistent view on whether trace is
+         prohibited within the CPU. As a result, the trace buffer or trace buffer state
+         might be corrupted. This happens after TRBE buffer has been enabled by setting
+         TRBLIMITR_EL1.E, followed by just a single context synchronization event before
+         execution changes from a context, in which trace is prohibited to one where it
+         isn't, or vice versa. In these mentioned conditions, the view of whether trace
+         is prohibited is inconsistent between parts of the CPU, and the trace buffer or
+         the trace buffer state might be corrupted.
+
+         Work around this in the driver by preventing an inconsistent view of whether the
+         trace is prohibited or not based on TRBLIMITR_EL1.E by immediately following a
+         change to TRBLIMITR_EL1.E with at least one ISB instruction before an ERET, or
+         two ISB instructions if no ERET is to take place.
+
+         If unsure, say Y.
+
+config ARM64_ERRATUM_1902691
+       bool "Cortex-A510: 1902691: workaround TRBE trace corruption"
+       depends on COMPILE_TEST # Until the CoreSight TRBE driver changes are in
+       default y
+       help
+         This option adds the workaround for ARM Cortex-A510 erratum 1902691.
+
+         Affected Cortex-A510 core might cause trace data corruption, when being written
+         into the memory. Effectively TRBE is broken and hence cannot be used to capture
+         trace data.
+
+         Work around this problem in the driver by just preventing TRBE initialization on
+         affected cpus. The firmware must have disabled the access to TRBE for the kernel
+         on such implementations. This will cover the kernel for any firmware that doesn't
+         do this already.
+
+         If unsure, say Y.
+
 config CAVIUM_ERRATUM_22375
        bool "Cavium erratum 22375, 24313"
        default y
index 7d5d588..2169744 100644 (file)
@@ -309,9 +309,6 @@ config ARCH_VISCONTI
        help
          This enables support for Toshiba Visconti SoCs Family.
 
-config ARCH_VULCAN
-       def_bool n
-
 config ARCH_XGENE
        bool "AppliedMicro X-Gene SOC Family"
        help
index 517519e..f84d4b4 100644 (file)
                        no-map;
                };
 
+               /* 32 MiB reserved for ARM Trusted Firmware (BL32) */
+               secmon_reserved_bl32: secmon@5300000 {
+                       reg = <0x0 0x05300000 0x0 0x2000000>;
+                       no-map;
+               };
+
                linux,cma {
                        compatible = "shared-dma-pool";
                        reusable;
index d8838dd..4fb31c2 100644 (file)
                regulator-always-on;
        };
 
-       reserved-memory {
-               /* TEE Reserved Memory */
-               bl32_reserved: bl32@5000000 {
-                       reg = <0x0 0x05300000 0x0 0x2000000>;
-                       no-map;
-               };
-       };
-
        sdio_pwrseq: sdio-pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
index 3e968b2..fd3fa82 100644 (file)
@@ -17,7 +17,7 @@
                rtc1 = &vrtc;
        };
 
-       dioo2133: audio-amplifier-0 {
+       dio2133: audio-amplifier-0 {
                compatible = "simple-audio-amplifier";
                enable-gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>;
                VCC-supply = <&vcc_5v>;
                audio-widgets = "Line", "Lineout";
                audio-aux-devs = <&tdmout_b>, <&tdmout_c>, <&tdmin_a>,
                                 <&tdmin_b>, <&tdmin_c>, <&tdmin_lb>,
-                                <&dioo2133>;
+                                <&dio2133>;
                audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1",
                                "TDMOUT_B IN 1", "FRDDR_B OUT 1",
                                "TDMOUT_B IN 2", "FRDDR_C OUT 1",
index 6b457b2..aa14ea0 100644 (file)
                        no-map;
                };
 
+               /* 32 MiB reserved for ARM Trusted Firmware (BL32) */
+               secmon_reserved_bl32: secmon@5300000 {
+                       reg = <0x0 0x05300000 0x0 0x2000000>;
+                       no-map;
+               };
+
                linux,cma {
                        compatible = "shared-dma-pool";
                        reusable;
index 212c6aa..5751c48 100644 (file)
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <3300000>;
 
-               enable-gpio = <&gpio GPIOE_2 GPIO_ACTIVE_HIGH>;
+               enable-gpio = <&gpio_ao GPIOE_2 GPIO_ACTIVE_HIGH>;
                enable-active-high;
                regulator-always-on;
 
index 0bd1e98..ddb1b34 100644 (file)
@@ -48,7 +48,7 @@
                regulator-max-microvolt = <3300000>;
                vin-supply = <&vcc_5v>;
 
-               enable-gpio = <&gpio GPIOE_2 GPIO_ACTIVE_HIGH>;
+               enable-gpio = <&gpio_ao GPIOE_2 GPIO_OPEN_DRAIN>;
                enable-active-high;
                regulator-always-on;
 
index 4274758..a5d79f2 100644 (file)
                regulator-always-on;
        };
 
-       reserved-memory {
-               /* TEE Reserved Memory */
-               bl32_reserved: bl32@5000000 {
-                       reg = <0x0 0x05300000 0x0 0x2000000>;
-                       no-map;
-               };
-       };
-
        sdio_pwrseq: sdio-pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
index d74e738..c03f4e1 100644 (file)
        };
 };
 
+&ftm_alarm0 {
+       status = "okay";
+};
+
 &gpio1 {
        gpio-line-names =
                "", "", "", "", "", "", "", "",
index f3e3418..2d4a472 100644 (file)
        status = "okay";
 
        ports {
-               port@1 {
-                       reg = <1>;
+               port@0 {
+                       reg = <0>;
 
                        mipi1_sensor_ep: endpoint {
                                remote-endpoint = <&camera1_ep>;
index 2df2510..e92ebb6 100644 (file)
                                assigned-clock-rates = <0>, <0>, <0>, <594000000>;
                                status = "disabled";
 
-                               port@0 {
+                               port {
                                        lcdif_mipi_dsi: endpoint {
                                                remote-endpoint = <&mipi_dsi_lcdif_in>;
                                        };
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       port@0 {
-                                               reg = <0>;
+                                       port@1 {
+                                               reg = <1>;
 
                                                csi1_mipi_ep: endpoint {
                                                        remote-endpoint = <&csi1_ep>;
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       port@0 {
-                                               reg = <0>;
+                                       port@1 {
+                                               reg = <1>;
 
                                                csi2_mipi_ep: endpoint {
                                                        remote-endpoint = <&csi2_ep>;
index f27e3c8..ce6d5bd 100644 (file)
@@ -91,7 +91,7 @@
 
        sound {
                compatible = "fsl,imx-audio-tlv320aic32x4";
-               model = "tqm-tlv320aic32";
+               model = "imx-audio-tlv320aic32x4";
                ssi-controller = <&sai3>;
                audio-codec = <&tlv320aic3x04>;
        };
index a5a24f9..b210cc0 100644 (file)
        model = "Texas Instruments J721S2 EVM";
 
        chosen {
-               stdout-path = "serial10:115200n8";
-               bootargs = "console=ttyS10,115200n8 earlycon=ns16550a,mmio32,2880000";
+               stdout-path = "serial2:115200n8";
+               bootargs = "console=ttyS2,115200n8 earlycon=ns16550a,mmio32,2880000";
+       };
+
+       aliases {
+               serial1 = &mcu_uart0;
+               serial2 = &main_uart8;
+               mmc0 = &main_sdhci0;
+               mmc1 = &main_sdhci1;
+               can0 = &main_mcan16;
+               can1 = &mcu_mcan0;
+               can2 = &mcu_mcan1;
        };
 
        evm_12v0: fixedregulator-evm12v0 {
index 80d3cae..fe5234c 100644 (file)
        #address-cells = <2>;
        #size-cells = <2>;
 
-       aliases {
-               serial0 = &wkup_uart0;
-               serial1 = &mcu_uart0;
-               serial2 = &main_uart0;
-               serial3 = &main_uart1;
-               serial4 = &main_uart2;
-               serial5 = &main_uart3;
-               serial6 = &main_uart4;
-               serial7 = &main_uart5;
-               serial8 = &main_uart6;
-               serial9 = &main_uart7;
-               serial10 = &main_uart8;
-               serial11 = &main_uart9;
-               mmc0 = &main_sdhci0;
-               mmc1 = &main_sdhci1;
-               can0 = &main_mcan16;
-               can1 = &mcu_mcan0;
-               can2 = &mcu_mcan1;
-               can3 = &main_mcan3;
-               can4 = &main_mcan5;
-       };
-
        chosen { };
 
        cpus {
index 19b8441..999b914 100644 (file)
@@ -73,7 +73,9 @@
 #define ARM_CPU_PART_CORTEX_A76                0xD0B
 #define ARM_CPU_PART_NEOVERSE_N1       0xD0C
 #define ARM_CPU_PART_CORTEX_A77                0xD0D
+#define ARM_CPU_PART_CORTEX_A510       0xD46
 #define ARM_CPU_PART_CORTEX_A710       0xD47
+#define ARM_CPU_PART_CORTEX_X2         0xD48
 #define ARM_CPU_PART_NEOVERSE_N2       0xD49
 
 #define APM_CPU_PART_POTENZA           0x000
 #define MIDR_CORTEX_A76        MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76)
 #define MIDR_NEOVERSE_N1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N1)
 #define MIDR_CORTEX_A77        MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77)
+#define MIDR_CORTEX_A510 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A510)
 #define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710)
+#define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
 #define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2)
 #define MIDR_THUNDERX  MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
 #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
index 9e1c1ae..b217941 100644 (file)
@@ -347,6 +347,7 @@ static const struct midr_range trbe_overwrite_fill_mode_cpus[] = {
 #endif
 #ifdef CONFIG_ARM64_ERRATUM_2119858
        MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
+       MIDR_RANGE(MIDR_CORTEX_X2, 0, 0, 2, 0),
 #endif
        {},
 };
@@ -371,6 +372,7 @@ static struct midr_range trbe_write_out_of_range_cpus[] = {
 #endif
 #ifdef CONFIG_ARM64_ERRATUM_2224489
        MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
+       MIDR_RANGE(MIDR_CORTEX_X2, 0, 0, 2, 0),
 #endif
        {},
 };
@@ -597,6 +599,41 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
                .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE,
                CAP_MIDR_RANGE_LIST(trbe_write_out_of_range_cpus),
        },
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_2077057
+       {
+               .desc = "ARM erratum 2077057",
+               .capability = ARM64_WORKAROUND_2077057,
+               .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
+               ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2),
+       },
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_2064142
+       {
+               .desc = "ARM erratum 2064142",
+               .capability = ARM64_WORKAROUND_2064142,
+
+               /* Cortex-A510 r0p0 - r0p2 */
+               ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2)
+       },
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_2038923
+       {
+               .desc = "ARM erratum 2038923",
+               .capability = ARM64_WORKAROUND_2038923,
+
+               /* Cortex-A510 r0p0 - r0p2 */
+               ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2)
+       },
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_1902691
+       {
+               .desc = "ARM erratum 1902691",
+               .capability = ARM64_WORKAROUND_1902691,
+
+               /* Cortex-A510 r0p0 - r0p1 */
+               ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 1)
+       },
 #endif
        {
        }
index a46ab3b..e5f23da 100644 (file)
@@ -1645,6 +1645,9 @@ static bool cpu_has_broken_dbm(void)
                MIDR_ALL_VERSIONS(MIDR_CORTEX_A55),
                /* Kryo4xx Silver (rdpe => r1p0) */
                MIDR_REV(MIDR_QCOM_KRYO_4XX_SILVER, 0xd, 0xe),
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_2051678
+               MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2),
 #endif
                {},
        };
index 0fb58fe..e4103e0 100644 (file)
@@ -33,8 +33,8 @@
  */
 
 
-static void start_backtrace(struct stackframe *frame, unsigned long fp,
-                           unsigned long pc)
+static notrace void start_backtrace(struct stackframe *frame, unsigned long fp,
+                                   unsigned long pc)
 {
        frame->fp = fp;
        frame->pc = pc;
@@ -55,6 +55,7 @@ static void start_backtrace(struct stackframe *frame, unsigned long fp,
        frame->prev_fp = 0;
        frame->prev_type = STACK_TYPE_UNKNOWN;
 }
+NOKPROBE_SYMBOL(start_backtrace);
 
 /*
  * Unwind from one frame record (A) to the next frame record (B).
index 6081349..172452f 100644 (file)
@@ -29,8 +29,11 @@ ldflags-y := -shared -soname=linux-vdso.so.1 --hash-style=sysv       \
 ccflags-y := -fno-common -fno-builtin -fno-stack-protector -ffixed-x18
 ccflags-y += -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO
 
+# -Wmissing-prototypes and -Wmissing-declarations are removed from
+# the CFLAGS of vgettimeofday.c to make possible to build the
+# kernel with CONFIG_WERROR enabled.
 CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE) -Os $(CC_FLAGS_SCS) $(GCC_PLUGINS_CFLAGS) \
-                               $(CC_FLAGS_LTO)
+                               $(CC_FLAGS_LTO) -Wmissing-prototypes -Wmissing-declarations
 KASAN_SANITIZE                 := n
 KCSAN_SANITIZE                 := n
 UBSAN_SANITIZE                 := n
index a4a0063..ecc5958 100644 (file)
@@ -797,6 +797,24 @@ static bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu, int *ret)
                        xfer_to_guest_mode_work_pending();
 }
 
+/*
+ * Actually run the vCPU, entering an RCU extended quiescent state (EQS) while
+ * the vCPU is running.
+ *
+ * This must be noinstr as instrumentation may make use of RCU, and this is not
+ * safe during the EQS.
+ */
+static int noinstr kvm_arm_vcpu_enter_exit(struct kvm_vcpu *vcpu)
+{
+       int ret;
+
+       guest_state_enter_irqoff();
+       ret = kvm_call_hyp_ret(__kvm_vcpu_run, vcpu);
+       guest_state_exit_irqoff();
+
+       return ret;
+}
+
 /**
  * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
  * @vcpu:      The VCPU pointer
@@ -881,9 +899,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                 * Enter the guest
                 */
                trace_kvm_entry(*vcpu_pc(vcpu));
-               guest_enter_irqoff();
+               guest_timing_enter_irqoff();
 
-               ret = kvm_call_hyp_ret(__kvm_vcpu_run, vcpu);
+               ret = kvm_arm_vcpu_enter_exit(vcpu);
 
                vcpu->mode = OUTSIDE_GUEST_MODE;
                vcpu->stat.exits++;
@@ -918,26 +936,23 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                kvm_arch_vcpu_ctxsync_fp(vcpu);
 
                /*
-                * We may have taken a host interrupt in HYP mode (ie
-                * while executing the guest). This interrupt is still
-                * pending, as we haven't serviced it yet!
+                * We must ensure that any pending interrupts are taken before
+                * we exit guest timing so that timer ticks are accounted as
+                * guest time. Transiently unmask interrupts so that any
+                * pending interrupts are taken.
                 *
-                * We're now back in SVC mode, with interrupts
-                * disabled.  Enabling the interrupts now will have
-                * the effect of taking the interrupt again, in SVC
-                * mode this time.
+                * Per ARM DDI 0487G.b section D1.13.4, an ISB (or other
+                * context synchronization event) is necessary to ensure that
+                * pending interrupts are taken.
                 */
                local_irq_enable();
+               isb();
+               local_irq_disable();
+
+               guest_timing_exit_irqoff();
+
+               local_irq_enable();
 
-               /*
-                * We do local_irq_enable() before calling guest_exit() so
-                * that if a timer interrupt hits while running the guest we
-                * account that tick as being spent in the guest.  We enable
-                * preemption after calling guest_exit() so that if we get
-                * preempted we make sure ticks after that is not counted as
-                * guest time.
-                */
-               guest_exit();
                trace_kvm_exit(ret, kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
 
                /* Exit types that need handling before we can be preempted */
index fd2dd26..e3140ab 100644 (file)
@@ -228,6 +228,14 @@ int handle_exit(struct kvm_vcpu *vcpu, int exception_index)
 {
        struct kvm_run *run = vcpu->run;
 
+       if (ARM_SERROR_PENDING(exception_index)) {
+               /*
+                * The SError is handled by handle_exit_early(). If the guest
+                * survives it will re-execute the original instruction.
+                */
+               return 1;
+       }
+
        exception_index = ARM_EXCEPTION_CODE(exception_index);
 
        switch (exception_index) {
index 0418399..c5d0097 100644 (file)
@@ -38,7 +38,10 @@ static inline void __vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
 
 static void __vcpu_write_spsr(struct kvm_vcpu *vcpu, u64 val)
 {
-       write_sysreg_el1(val, SYS_SPSR);
+       if (has_vhe())
+               write_sysreg_el1(val, SYS_SPSR);
+       else
+               __vcpu_sys_reg(vcpu, SPSR_EL1) = val;
 }
 
 static void __vcpu_write_spsr_abt(struct kvm_vcpu *vcpu, u64 val)
index 58e14f8..701cfb9 100644 (file)
@@ -402,6 +402,24 @@ static inline bool kvm_hyp_handle_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
        return false;
 }
 
+static inline void synchronize_vcpu_pstate(struct kvm_vcpu *vcpu, u64 *exit_code)
+{
+       /*
+        * Check for the conditions of Cortex-A510's #2077057. When these occur
+        * SPSR_EL2 can't be trusted, but isn't needed either as it is
+        * unchanged from the value in vcpu_gp_regs(vcpu)->pstate.
+        * Are we single-stepping the guest, and took a PAC exception from the
+        * active-not-pending state?
+        */
+       if (cpus_have_final_cap(ARM64_WORKAROUND_2077057)               &&
+           vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP                 &&
+           *vcpu_cpsr(vcpu) & DBG_SPSR_SS                              &&
+           ESR_ELx_EC(read_sysreg_el2(SYS_ESR)) == ESR_ELx_EC_PAC)
+               write_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR);
+
+       vcpu->arch.ctxt.regs.pstate = read_sysreg_el2(SYS_SPSR);
+}
+
 /*
  * Return true when we were able to fixup the guest exit and should return to
  * the guest, false when we should restore the host state and return to the
@@ -413,7 +431,7 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
         * Save PSTATE early so that we can evaluate the vcpu mode
         * early on.
         */
-       vcpu->arch.ctxt.regs.pstate = read_sysreg_el2(SYS_SPSR);
+       synchronize_vcpu_pstate(vcpu, exit_code);
 
        /*
         * Check whether we want to repaint the state one way or
@@ -424,7 +442,8 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
        if (ARM_EXCEPTION_CODE(*exit_code) != ARM_EXCEPTION_IRQ)
                vcpu->arch.fault.esr_el2 = read_sysreg_el2(SYS_ESR);
 
-       if (ARM_SERROR_PENDING(*exit_code)) {
+       if (ARM_SERROR_PENDING(*exit_code) &&
+           ARM_EXCEPTION_CODE(*exit_code) != ARM_EXCEPTION_IRQ) {
                u8 esr_ec = kvm_vcpu_trap_get_class(vcpu);
 
                /*
index 844a6f0..2cb3867 100644 (file)
@@ -983,13 +983,9 @@ static int stage2_unmap_walker(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
         */
        stage2_put_pte(ptep, mmu, addr, level, mm_ops);
 
-       if (need_flush) {
-               kvm_pte_t *pte_follow = kvm_pte_follow(pte, mm_ops);
-
-               dcache_clean_inval_poc((unsigned long)pte_follow,
-                                   (unsigned long)pte_follow +
-                                           kvm_granule_size(level));
-       }
+       if (need_flush && mm_ops->dcache_clean_inval_poc)
+               mm_ops->dcache_clean_inval_poc(kvm_pte_follow(pte, mm_ops),
+                                              kvm_granule_size(level));
 
        if (childp)
                mm_ops->put_page(childp);
@@ -1151,15 +1147,13 @@ static int stage2_flush_walker(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
        struct kvm_pgtable *pgt = arg;
        struct kvm_pgtable_mm_ops *mm_ops = pgt->mm_ops;
        kvm_pte_t pte = *ptep;
-       kvm_pte_t *pte_follow;
 
        if (!kvm_pte_valid(pte) || !stage2_pte_cacheable(pgt, pte))
                return 0;
 
-       pte_follow = kvm_pte_follow(pte, mm_ops);
-       dcache_clean_inval_poc((unsigned long)pte_follow,
-                           (unsigned long)pte_follow +
-                                   kvm_granule_size(level));
+       if (mm_ops->dcache_clean_inval_poc)
+               mm_ops->dcache_clean_inval_poc(kvm_pte_follow(pte, mm_ops),
+                                              kvm_granule_size(level));
        return 0;
 }
 
index 20db2f2..4fb419f 100644 (file)
@@ -983,6 +983,9 @@ static void __vgic_v3_read_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
        val = ((vtr >> 29) & 7) << ICC_CTLR_EL1_PRI_BITS_SHIFT;
        /* IDbits */
        val |= ((vtr >> 23) & 7) << ICC_CTLR_EL1_ID_BITS_SHIFT;
+       /* SEIS */
+       if (kvm_vgic_global_state.ich_vtr_el2 & ICH_VTR_SEIS_MASK)
+               val |= BIT(ICC_CTLR_EL1_SEIS_SHIFT);
        /* A3V */
        val |= ((vtr >> 21) & 1) << ICC_CTLR_EL1_A3V_SHIFT;
        /* EOImode */
index a33d436..b549af8 100644 (file)
@@ -609,6 +609,18 @@ static int __init early_gicv4_enable(char *buf)
 }
 early_param("kvm-arm.vgic_v4_enable", early_gicv4_enable);
 
+static const struct midr_range broken_seis[] = {
+       MIDR_ALL_VERSIONS(MIDR_APPLE_M1_ICESTORM),
+       MIDR_ALL_VERSIONS(MIDR_APPLE_M1_FIRESTORM),
+       {},
+};
+
+static bool vgic_v3_broken_seis(void)
+{
+       return ((kvm_vgic_global_state.ich_vtr_el2 & ICH_VTR_SEIS_MASK) &&
+               is_midr_in_range_list(read_cpuid_id(), broken_seis));
+}
+
 /**
  * vgic_v3_probe - probe for a VGICv3 compatible interrupt controller
  * @info:      pointer to the GIC description
@@ -676,9 +688,10 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
                group1_trap = true;
        }
 
-       if (kvm_vgic_global_state.ich_vtr_el2 & ICH_VTR_SEIS_MASK) {
-               kvm_info("GICv3 with locally generated SEI\n");
+       if (vgic_v3_broken_seis()) {
+               kvm_info("GICv3 with broken locally generated SEI\n");
 
+               kvm_vgic_global_state.ich_vtr_el2 &= ~ICH_VTR_SEIS_MASK;
                group0_trap = true;
                group1_trap = true;
                if (ich_vtr_el2 & ICH_VTR_TDS_MASK)
index c0181e6..4894553 100644 (file)
@@ -40,8 +40,8 @@ static bool
 ex_handler_load_unaligned_zeropad(const struct exception_table_entry *ex,
                                  struct pt_regs *regs)
 {
-       int reg_data = FIELD_GET(EX_DATA_REG_DATA, ex->type);
-       int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->type);
+       int reg_data = FIELD_GET(EX_DATA_REG_DATA, ex->data);
+       int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->data);
        unsigned long data, addr, offset;
 
        addr = pt_regs_read_reg(regs, reg_addr);
index 870c395..9c65b1e 100644 (file)
@@ -55,6 +55,10 @@ WORKAROUND_1418040
 WORKAROUND_1463225
 WORKAROUND_1508412
 WORKAROUND_1542419
+WORKAROUND_1902691
+WORKAROUND_2038923
+WORKAROUND_2064142
+WORKAROUND_2077057
 WORKAROUND_TRBE_OVERWRITE_FILL_MODE
 WORKAROUND_TSB_FLUSH_FAILURE
 WORKAROUND_TRBE_WRITE_OUT_OF_RANGE
index 7039528..a7e0157 100644 (file)
@@ -318,7 +318,7 @@ config ARCH_PROC_KCORE_TEXT
        depends on PROC_KCORE
 
 config IA64_MCA_RECOVERY
-       tristate "MCA recovery from errors other than TLB."
+       bool "MCA recovery from errors other than TLB."
 
 config IA64_PALINFO
        tristate "/proc/pal support"
index acb55a4..2bcdd7d 100644 (file)
@@ -76,5 +76,5 @@ static void pci_fixup_video(struct pci_dev *pdev)
                }
        }
 }
-DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
-                               PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID,
+                              PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
index 3e336b3..ab6e3dc 100644 (file)
@@ -83,6 +83,8 @@
                label = "HDMI OUT";
                type = "a";
 
+               ddc-en-gpios = <&gpa 25 GPIO_ACTIVE_HIGH>;
+
                port {
                        hdmi_con: endpoint {
                                remote-endpoint = <&dw_hdmi_out>;
                gpio = <&gpf 14 GPIO_ACTIVE_LOW>;
                enable-active-high;
        };
-
-       hdmi_power: fixedregulator@3 {
-               compatible = "regulator-fixed";
-
-               regulator-name = "hdmi_power";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-
-               gpio = <&gpa 25 0>;
-               enable-active-high;
-       };
 };
 
 &ext {
        pinctrl-names = "default";
        pinctrl-0 = <&pins_hdmi_ddc>;
 
-       hdmi-5v-supply = <&hdmi_power>;
-
        ports {
                #address-cells = <1>;
                #size-cells = <0>;
index 0a515cd..25860fb 100644 (file)
@@ -74,7 +74,7 @@
 #define EXC(inst_reg,addr,handler)             \
 9:     inst_reg, addr;                         \
        .section __ex_table,"a";                \
-       PTR     9b, handler;                    \
+       PTR_WD  9b, handler;                    \
        .previous
 
 /*
index 6ffdd4b..336ac9b 100644 (file)
@@ -285,7 +285,7 @@ symbol              =       value
 
 #define PTR_SCALESHIFT 2
 
-#define PTR            .word
+#define PTR_WD         .word
 #define PTRSIZE                4
 #define PTRLOG         2
 #endif
@@ -310,7 +310,7 @@ symbol              =       value
 
 #define PTR_SCALESHIFT 3
 
-#define PTR            .dword
+#define PTR_WD         .dword
 #define PTRSIZE                8
 #define PTRLOG         3
 #endif
index b463f2a..db497a8 100644 (file)
@@ -32,7 +32,7 @@ do {                                                  \
                ".previous\n"                           \
                                                        \
                ".section\t__ex_table,\"a\"\n\t"        \
-               STR(PTR) "\t1b, 3b\n\t"                 \
+               STR(PTR_WD) "\t1b, 3b\n\t"              \
                ".previous\n"                           \
                                                        \
                : [tmp_dst] "=&r" (dst), [tmp_err] "=r" (error)\
@@ -54,7 +54,7 @@ do {                                          \
                ".previous\n"                   \
                                                \
                ".section\t__ex_table,\"a\"\n\t"\
-               STR(PTR) "\t1b, 3b\n\t"         \
+               STR(PTR_WD) "\t1b, 3b\n\t"      \
                ".previous\n"                   \
                                                \
                : [tmp_err] "=r" (error)        \
index af37885..431a1c9 100644 (file)
@@ -119,7 +119,7 @@ static inline void flush_scache_line(unsigned long addr)
        "       j       2b                      \n"             \
        "       .previous                       \n"             \
        "       .section __ex_table,\"a\"       \n"             \
-       "       "STR(PTR)" 1b, 3b               \n"             \
+       "       "STR(PTR_WD)" 1b, 3b            \n"             \
        "       .previous"                                      \
        : "+r" (__err)                                          \
        : "i" (op), "r" (addr), "i" (-EFAULT));                 \
@@ -142,7 +142,7 @@ static inline void flush_scache_line(unsigned long addr)
        "       j       2b                      \n"             \
        "       .previous                       \n"             \
        "       .section __ex_table,\"a\"       \n"             \
-       "       "STR(PTR)" 1b, 3b               \n"             \
+       "       "STR(PTR_WD)" 1b, 3b            \n"             \
        "       .previous"                                      \
        : "+r" (__err)                                          \
        : "i" (op), "r" (addr), "i" (-EFAULT));                 \
index 2022b18..9af0f4d 100644 (file)
@@ -20,8 +20,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -41,8 +41,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -74,10 +74,10 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -102,8 +102,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -125,8 +125,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -145,8 +145,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -178,10 +178,10 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -223,14 +223,14 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
-               STR(PTR)"\t5b, 11b\n\t"             \
-               STR(PTR)"\t6b, 11b\n\t"             \
-               STR(PTR)"\t7b, 11b\n\t"             \
-               STR(PTR)"\t8b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
+               STR(PTR_WD)"\t5b, 11b\n\t"          \
+               STR(PTR_WD)"\t6b, 11b\n\t"          \
+               STR(PTR_WD)"\t7b, 11b\n\t"          \
+               STR(PTR_WD)"\t8b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -255,8 +255,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"              \
-               STR(PTR)"\t2b, 4b\n\t"              \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=r" (res)                        \
                : "r" (value), "r" (addr), "i" (-EFAULT));\
@@ -276,8 +276,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=r" (res)                                \
                : "r" (value), "r" (addr), "i" (-EFAULT));  \
@@ -296,8 +296,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=r" (res)                                \
                : "r" (value), "r" (addr), "i" (-EFAULT));  \
@@ -325,10 +325,10 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (res)                               \
                : "r" (value), "r" (addr), "i" (-EFAULT)    \
@@ -365,14 +365,14 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
-               STR(PTR)"\t5b, 11b\n\t"             \
-               STR(PTR)"\t6b, 11b\n\t"             \
-               STR(PTR)"\t7b, 11b\n\t"             \
-               STR(PTR)"\t8b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
+               STR(PTR_WD)"\t5b, 11b\n\t"          \
+               STR(PTR_WD)"\t6b, 11b\n\t"          \
+               STR(PTR_WD)"\t7b, 11b\n\t"          \
+               STR(PTR_WD)"\t8b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (res)                               \
                : "r" (value), "r" (addr), "i" (-EFAULT)    \
@@ -398,8 +398,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -419,8 +419,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -452,10 +452,10 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -481,8 +481,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -504,8 +504,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -524,8 +524,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -557,10 +557,10 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -602,14 +602,14 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
-               STR(PTR)"\t5b, 11b\n\t"             \
-               STR(PTR)"\t6b, 11b\n\t"             \
-               STR(PTR)"\t7b, 11b\n\t"             \
-               STR(PTR)"\t8b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
+               STR(PTR_WD)"\t5b, 11b\n\t"          \
+               STR(PTR_WD)"\t6b, 11b\n\t"          \
+               STR(PTR_WD)"\t7b, 11b\n\t"          \
+               STR(PTR_WD)"\t8b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -632,8 +632,8 @@ do {                                                 \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=r" (res)                        \
                : "r" (value), "r" (addr), "i" (-EFAULT));\
@@ -653,8 +653,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=r" (res)                                \
                : "r" (value), "r" (addr), "i" (-EFAULT));  \
@@ -673,8 +673,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=r" (res)                                \
                : "r" (value), "r" (addr), "i" (-EFAULT));  \
@@ -703,10 +703,10 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (res)                               \
                : "r" (value), "r" (addr), "i" (-EFAULT)    \
@@ -743,14 +743,14 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
-               STR(PTR)"\t5b, 11b\n\t"             \
-               STR(PTR)"\t6b, 11b\n\t"             \
-               STR(PTR)"\t7b, 11b\n\t"             \
-               STR(PTR)"\t8b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
+               STR(PTR_WD)"\t5b, 11b\n\t"          \
+               STR(PTR_WD)"\t6b, 11b\n\t"          \
+               STR(PTR_WD)"\t7b, 11b\n\t"          \
+               STR(PTR_WD)"\t8b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (res)                               \
                : "r" (value), "r" (addr), "i" (-EFAULT)    \
index a39ec75..750fe56 100644 (file)
@@ -1258,10 +1258,10 @@ fpu_emul:
                        "       j       10b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -1333,10 +1333,10 @@ fpu_emul:
                        "       j       10b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -1404,10 +1404,10 @@ fpu_emul:
                        "       j       9b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -1474,10 +1474,10 @@ fpu_emul:
                        "       j       9b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -1589,14 +1589,14 @@ fpu_emul:
                        "       j       9b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
-                       STR(PTR) " 5b,8b\n"
-                       STR(PTR) " 6b,8b\n"
-                       STR(PTR) " 7b,8b\n"
-                       STR(PTR) " 0b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
+                       STR(PTR_WD) " 5b,8b\n"
+                       STR(PTR_WD) " 6b,8b\n"
+                       STR(PTR_WD) " 7b,8b\n"
+                       STR(PTR_WD) " 0b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -1708,14 +1708,14 @@ fpu_emul:
                        "       j      9b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
-                       STR(PTR) " 5b,8b\n"
-                       STR(PTR) " 6b,8b\n"
-                       STR(PTR) " 7b,8b\n"
-                       STR(PTR) " 0b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
+                       STR(PTR_WD) " 5b,8b\n"
+                       STR(PTR_WD) " 6b,8b\n"
+                       STR(PTR_WD) " 7b,8b\n"
+                       STR(PTR_WD) " 0b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -1827,14 +1827,14 @@ fpu_emul:
                        "       j       9b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
-                       STR(PTR) " 5b,8b\n"
-                       STR(PTR) " 6b,8b\n"
-                       STR(PTR) " 7b,8b\n"
-                       STR(PTR) " 0b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
+                       STR(PTR_WD) " 5b,8b\n"
+                       STR(PTR_WD) " 6b,8b\n"
+                       STR(PTR_WD) " 7b,8b\n"
+                       STR(PTR_WD) " 0b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -1945,14 +1945,14 @@ fpu_emul:
                        "       j       9b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
-                       STR(PTR) " 5b,8b\n"
-                       STR(PTR) " 6b,8b\n"
-                       STR(PTR) " 7b,8b\n"
-                       STR(PTR) " 0b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
+                       STR(PTR_WD) " 5b,8b\n"
+                       STR(PTR_WD) " 6b,8b\n"
+                       STR(PTR_WD) " 7b,8b\n"
+                       STR(PTR_WD) " 0b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -2007,7 +2007,7 @@ fpu_emul:
                        "j      2b\n"
                        ".previous\n"
                        ".section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,3b\n"
+                       STR(PTR_WD) " 1b,3b\n"
                        ".previous\n"
                        : "=&r"(res), "+&r"(err)
                        : "r"(vaddr), "i"(SIGSEGV)
@@ -2065,7 +2065,7 @@ fpu_emul:
                        "j      2b\n"
                        ".previous\n"
                        ".section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,3b\n"
+                       STR(PTR_WD) " 1b,3b\n"
                        ".previous\n"
                        : "+&r"(res), "+&r"(err)
                        : "r"(vaddr), "i"(SIGSEGV));
@@ -2126,7 +2126,7 @@ fpu_emul:
                        "j      2b\n"
                        ".previous\n"
                        ".section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,3b\n"
+                       STR(PTR_WD) " 1b,3b\n"
                        ".previous\n"
                        : "=&r"(res), "+&r"(err)
                        : "r"(vaddr), "i"(SIGSEGV)
@@ -2189,7 +2189,7 @@ fpu_emul:
                        "j      2b\n"
                        ".previous\n"
                        ".section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,3b\n"
+                       STR(PTR_WD) " 1b,3b\n"
                        ".previous\n"
                        : "+&r"(res), "+&r"(err)
                        : "r"(vaddr), "i"(SIGSEGV));
index cbf6db9..2748c55 100644 (file)
 #define EX(a,b)                                                        \
 9:     a,##b;                                                  \
        .section __ex_table,"a";                                \
-       PTR     9b,fault;                                       \
+       PTR_WD  9b,fault;                                       \
        .previous
 
 #define EX2(a,b)                                               \
 9:     a,##b;                                                  \
        .section __ex_table,"a";                                \
-       PTR     9b,fault;                                       \
-       PTR     9b+4,fault;                                     \
+       PTR_WD  9b,fault;                                       \
+       PTR_WD  9b+4,fault;                                     \
        .previous
 
        .set    mips1
index b91e911..2e687c6 100644 (file)
@@ -31,7 +31,7 @@
 .ex\@: \insn   \reg, \src
        .set    pop
        .section __ex_table,"a"
-       PTR     .ex\@, fault
+       PTR_WD  .ex\@, fault
        .previous
        .endm
 
index f3c908a..cfde14b 100644 (file)
@@ -147,10 +147,10 @@ LEAF(kexec_smp_wait)
 
 kexec_args:
        EXPORT(kexec_args)
-arg0:  PTR             0x0
-arg1:  PTR             0x0
-arg2:  PTR             0x0
-arg3:  PTR             0x0
+arg0:  PTR_WD          0x0
+arg1:  PTR_WD          0x0
+arg2:  PTR_WD          0x0
+arg3:  PTR_WD          0x0
        .size   kexec_args,PTRSIZE*4
 
 #ifdef CONFIG_SMP
@@ -161,10 +161,10 @@ arg3:     PTR             0x0
  */
 secondary_kexec_args:
        EXPORT(secondary_kexec_args)
-s_arg0: PTR            0x0
-s_arg1: PTR            0x0
-s_arg2: PTR            0x0
-s_arg3: PTR            0x0
+s_arg0: PTR_WD         0x0
+s_arg1: PTR_WD         0x0
+s_arg2: PTR_WD         0x0
+s_arg3: PTR_WD         0x0
        .size   secondary_kexec_args,PTRSIZE*4
 kexec_flag:
        LONG            0x1
@@ -173,17 +173,17 @@ kexec_flag:
 
 kexec_start_address:
        EXPORT(kexec_start_address)
-       PTR             0x0
+       PTR_WD          0x0
        .size           kexec_start_address, PTRSIZE
 
 kexec_indirection_page:
        EXPORT(kexec_indirection_page)
-       PTR             0
+       PTR_WD          0
        .size           kexec_indirection_page, PTRSIZE
 
 relocate_new_kernel_end:
 
 relocate_new_kernel_size:
        EXPORT(relocate_new_kernel_size)
-       PTR             relocate_new_kernel_end - relocate_new_kernel
+       PTR_WD          relocate_new_kernel_end - relocate_new_kernel
        .size           relocate_new_kernel_size, PTRSIZE
index b1b2e10..9bfce5f 100644 (file)
@@ -72,10 +72,10 @@ loads_done:
        .set    pop
 
        .section __ex_table,"a"
-       PTR     load_a4, bad_stack_a4
-       PTR     load_a5, bad_stack_a5
-       PTR     load_a6, bad_stack_a6
-       PTR     load_a7, bad_stack_a7
+       PTR_WD  load_a4, bad_stack_a4
+       PTR_WD  load_a5, bad_stack_a5
+       PTR_WD  load_a6, bad_stack_a6
+       PTR_WD  load_a7, bad_stack_a7
        .previous
 
        lw      t0, TI_FLAGS($28)       # syscall tracing enabled?
@@ -216,7 +216,7 @@ einval: li  v0, -ENOSYS
 #endif /* CONFIG_MIPS_MT_FPAFF */
 
 #define __SYSCALL_WITH_COMPAT(nr, native, compat)      __SYSCALL(nr, native)
-#define __SYSCALL(nr, entry)   PTR entry
+#define __SYSCALL(nr, entry)   PTR_WD entry
        .align  2
        .type   sys_call_table, @object
 EXPORT(sys_call_table)
index f650c55..97456b2 100644 (file)
@@ -101,7 +101,7 @@ not_n32_scall:
 
        END(handle_sysn32)
 
-#define __SYSCALL(nr, entry)   PTR entry
+#define __SYSCALL(nr, entry)   PTR_WD entry
        .type   sysn32_call_table, @object
 EXPORT(sysn32_call_table)
 #include <asm/syscall_table_n32.h>
index 5d7bfc6..5f6ed4b 100644 (file)
@@ -109,7 +109,7 @@ illegal_syscall:
        j       n64_syscall_exit
        END(handle_sys64)
 
-#define __SYSCALL(nr, entry)   PTR entry
+#define __SYSCALL(nr, entry)   PTR_WD entry
        .align  3
        .type   sys_call_table, @object
 EXPORT(sys_call_table)
index cedc8bd..d3c2616 100644 (file)
@@ -73,10 +73,10 @@ load_a7: lw a7, 28(t0)              # argument #8 from usp
 loads_done:
 
        .section __ex_table,"a"
-       PTR     load_a4, bad_stack_a4
-       PTR     load_a5, bad_stack_a5
-       PTR     load_a6, bad_stack_a6
-       PTR     load_a7, bad_stack_a7
+       PTR_WD  load_a4, bad_stack_a4
+       PTR_WD  load_a5, bad_stack_a5
+       PTR_WD  load_a6, bad_stack_a6
+       PTR_WD  load_a7, bad_stack_a7
        .previous
 
        li      t1, _TIF_WORK_SYSCALL_ENTRY
@@ -214,7 +214,7 @@ einval: li  v0, -ENOSYS
        END(sys32_syscall)
 
 #define __SYSCALL_WITH_COMPAT(nr, native, compat)      __SYSCALL(nr, compat)
-#define __SYSCALL(nr, entry)   PTR entry
+#define __SYSCALL(nr, entry)   PTR_WD entry
        .align  3
        .type   sys32_call_table,@object
 EXPORT(sys32_call_table)
index 5512cd5..ae93a60 100644 (file)
@@ -122,8 +122,8 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)
                "       j       3b                                      \n"
                "       .previous                                       \n"
                "       .section __ex_table,\"a\"                       \n"
-               "       "STR(PTR)"      1b, 4b                          \n"
-               "       "STR(PTR)"      2b, 4b                          \n"
+               "       "STR(PTR_WD)"   1b, 4b                          \n"
+               "       "STR(PTR_WD)"   2b, 4b                          \n"
                "       .previous                                       \n"
                "       .set    pop                                     \n"
                : [old] "=&r" (old),
@@ -152,8 +152,8 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)
                "       j       3b                                      \n"
                "       .previous                                       \n"
                "       .section __ex_table,\"a\"                       \n"
-               "       "STR(PTR)"      1b, 5b                          \n"
-               "       "STR(PTR)"      2b, 5b                          \n"
+               "       "STR(PTR_WD)"   1b, 5b                          \n"
+               "       "STR(PTR_WD)"   2b, 5b                          \n"
                "       .previous                                       \n"
                "       .set    pop                                     \n"
                : [old] "=&r" (old),
index e59cb62..a25e0b7 100644 (file)
@@ -414,6 +414,24 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
        return -ENOIOCTLCMD;
 }
 
+/*
+ * Actually run the vCPU, entering an RCU extended quiescent state (EQS) while
+ * the vCPU is running.
+ *
+ * This must be noinstr as instrumentation may make use of RCU, and this is not
+ * safe during the EQS.
+ */
+static int noinstr kvm_mips_vcpu_enter_exit(struct kvm_vcpu *vcpu)
+{
+       int ret;
+
+       guest_state_enter_irqoff();
+       ret = kvm_mips_callbacks->vcpu_run(vcpu);
+       guest_state_exit_irqoff();
+
+       return ret;
+}
+
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 {
        int r = -EINTR;
@@ -434,7 +452,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
        lose_fpu(1);
 
        local_irq_disable();
-       guest_enter_irqoff();
+       guest_timing_enter_irqoff();
        trace_kvm_enter(vcpu);
 
        /*
@@ -445,10 +463,23 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
         */
        smp_store_mb(vcpu->mode, IN_GUEST_MODE);
 
-       r = kvm_mips_callbacks->vcpu_run(vcpu);
+       r = kvm_mips_vcpu_enter_exit(vcpu);
+
+       /*
+        * We must ensure that any pending interrupts are taken before
+        * we exit guest timing so that timer ticks are accounted as
+        * guest time. Transiently unmask interrupts so that any
+        * pending interrupts are taken.
+        *
+        * TODO: is there a barrier which ensures that pending interrupts are
+        * recognised? Currently this just hopes that the CPU takes any pending
+        * interrupts between the enable and disable.
+        */
+       local_irq_enable();
+       local_irq_disable();
 
        trace_kvm_out(vcpu);
-       guest_exit_irqoff();
+       guest_timing_exit_irqoff();
        local_irq_enable();
 
 out:
@@ -1168,7 +1199,7 @@ static void kvm_mips_set_c0_status(void)
 /*
  * Return value is in the form (errcode<<2 | RESUME_FLAG_HOST | RESUME_FLAG_NV)
  */
-int kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
+static int __kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *run = vcpu->run;
        u32 cause = vcpu->arch.host_cp0_cause;
@@ -1357,6 +1388,17 @@ int kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
        return ret;
 }
 
+int noinstr kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
+{
+       int ret;
+
+       guest_state_exit_irqoff();
+       ret = __kvm_mips_handle_exit(vcpu);
+       guest_state_enter_irqoff();
+
+       return ret;
+}
+
 /* Enable FPU for guest and restore context */
 void kvm_own_fpu(struct kvm_vcpu *vcpu)
 {
index 4adca5a..c706f58 100644 (file)
@@ -458,8 +458,8 @@ void kvm_vz_acquire_htimer(struct kvm_vcpu *vcpu)
 /**
  * _kvm_vz_save_htimer() - Switch to software emulation of guest timer.
  * @vcpu:      Virtual CPU.
- * @compare:   Pointer to write compare value to.
- * @cause:     Pointer to write cause value to.
+ * @out_compare: Pointer to write compare value to.
+ * @out_cause: Pointer to write cause value to.
  *
  * Save VZ guest timer state and switch to software emulation of guest CP0
  * timer. The hard timer must already be in use, so preemption should be
@@ -1541,11 +1541,14 @@ static int kvm_trap_vz_handle_guest_exit(struct kvm_vcpu *vcpu)
 }
 
 /**
- * kvm_trap_vz_handle_cop_unusuable() - Guest used unusable coprocessor.
+ * kvm_trap_vz_handle_cop_unusable() - Guest used unusable coprocessor.
  * @vcpu:      Virtual CPU context.
  *
  * Handle when the guest attempts to use a coprocessor which hasn't been allowed
  * by the root context.
+ *
+ * Return: value indicating whether to resume the host or the guest
+ *        (RESUME_HOST or RESUME_GUEST)
  */
 static int kvm_trap_vz_handle_cop_unusable(struct kvm_vcpu *vcpu)
 {
@@ -1592,6 +1595,9 @@ static int kvm_trap_vz_handle_cop_unusable(struct kvm_vcpu *vcpu)
  *
  * Handle when the guest attempts to use MSA when it is disabled in the root
  * context.
+ *
+ * Return: value indicating whether to resume the host or the guest
+ *        (RESUME_HOST or RESUME_GUEST)
  */
 static int kvm_trap_vz_handle_msa_disabled(struct kvm_vcpu *vcpu)
 {
index a46db08..7767137 100644 (file)
@@ -347,7 +347,7 @@ EXPORT_SYMBOL(csum_partial)
        .if \mode == LEGACY_MODE;               \
 9:             insn reg, addr;                 \
                .section __ex_table,"a";        \
-               PTR     9b, .L_exc;             \
+               PTR_WD  9b, .L_exc;             \
                .previous;                      \
        /* This is enabled in EVA mode */       \
        .else;                                  \
@@ -356,7 +356,7 @@ EXPORT_SYMBOL(csum_partial)
                    ((\to == USEROP) && (type == ST_INSN));     \
 9:                     __BUILD_EVA_INSN(insn##e, reg, addr);   \
                        .section __ex_table,"a";                \
-                       PTR     9b, .L_exc;                     \
+                       PTR_WD  9b, .L_exc;                     \
                        .previous;                              \
                .else;                                          \
                        /* EVA without exception */             \
index 277c322..18a43f2 100644 (file)
        .if \mode == LEGACY_MODE;                               \
 9:             insn reg, addr;                                 \
                .section __ex_table,"a";                        \
-               PTR     9b, handler;                            \
+               PTR_WD  9b, handler;                            \
                .previous;                                      \
        /* This is assembled in EVA mode */                     \
        .else;                                                  \
                    ((\to == USEROP) && (type == ST_INSN));     \
 9:                     __BUILD_EVA_INSN(insn##e, reg, addr);   \
                        .section __ex_table,"a";                \
-                       PTR     9b, handler;                    \
+                       PTR_WD  9b, handler;                    \
                        .previous;                              \
                .else;                                          \
                        /*                                      \
index b0baa3c..0b342ba 100644 (file)
@@ -52,7 +52,7 @@
 9:             ___BUILD_EVA_INSN(insn, reg, addr);     \
        .endif;                                         \
        .section __ex_table,"a";                        \
-       PTR     9b, handler;                            \
+       PTR_WD  9b, handler;                            \
        .previous
 
        .macro  f_fill64 dst, offset, val, fixup, mode
index 556acf6..13aaa99 100644 (file)
@@ -15,7 +15,7 @@
 #define EX(insn,reg,addr,handler)                      \
 9:     insn    reg, addr;                              \
        .section __ex_table,"a";                        \
-       PTR     9b, handler;                            \
+       PTR_WD  9b, handler;                            \
        .previous
 
 /*
@@ -59,7 +59,7 @@ LEAF(__strncpy_from_user_asm)
        jr              ra
 
        .section        __ex_table,"a"
-       PTR             1b, .Lfault
+       PTR_WD          1b, .Lfault
        .previous
 
        EXPORT_SYMBOL(__strncpy_from_user_asm)
index 92b63f2..6de31b6 100644 (file)
@@ -14,7 +14,7 @@
 #define EX(insn,reg,addr,handler)                      \
 9:     insn    reg, addr;                              \
        .section __ex_table,"a";                        \
-       PTR     9b, handler;                            \
+       PTR_WD  9b, handler;                            \
        .previous
 
 /*
index 9a29e94..3115d4d 100644 (file)
@@ -3,7 +3,7 @@
 #include <linux/pci.h>
 #include <loongson.h>
 
-static void pci_fixup_radeon(struct pci_dev *pdev)
+static void pci_fixup_video(struct pci_dev *pdev)
 {
        struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
 
@@ -22,8 +22,7 @@ static void pci_fixup_radeon(struct pci_dev *pdev)
        res->flags = IORESOURCE_MEM | IORESOURCE_ROM_SHADOW |
                     IORESOURCE_PCI_FIXED;
 
-       dev_info(&pdev->dev, "BAR %d: assigned %pR for Radeon ROM\n",
-                PCI_ROM_RESOURCE, res);
+       dev_info(&pdev->dev, "Video device with shadowed ROM at %pR\n", res);
 }
-DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, 0x9615,
-                               PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_radeon);
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_ATI, 0x9615,
+                              PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
index 7be2786..78c6a5f 100644 (file)
@@ -223,6 +223,8 @@ static __always_inline void update_user_segments(u32 val)
        update_user_segment(15, val);
 }
 
+int __init find_free_bat(void);
+unsigned int bat_block_size(unsigned long base, unsigned long top);
 #endif /* !__ASSEMBLY__ */
 
 /* We happily ignore the smaller BATs on 601, we don't actually use
index 609c80f..f8b94f7 100644 (file)
@@ -178,6 +178,7 @@ static inline bool pte_user(pte_t pte)
 #ifndef __ASSEMBLY__
 
 int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot);
+void unmap_kernel_page(unsigned long va);
 
 #endif /* !__ASSEMBLY__ */
 
index 33e073d..875730d 100644 (file)
@@ -1082,6 +1082,8 @@ static inline int map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t p
        return hash__map_kernel_page(ea, pa, prot);
 }
 
+void unmap_kernel_page(unsigned long va);
+
 static inline int __meminit vmemmap_create_mapping(unsigned long start,
                                                   unsigned long page_size,
                                                   unsigned long phys)
index 947b5b9..a832aea 100644 (file)
@@ -111,8 +111,10 @@ static inline void __set_fixmap(enum fixed_addresses idx,
                BUILD_BUG_ON(idx >= __end_of_fixed_addresses);
        else if (WARN_ON(idx >= __end_of_fixed_addresses))
                return;
-
-       map_kernel_page(__fix_to_virt(idx), phys, flags);
+       if (pgprot_val(flags))
+               map_kernel_page(__fix_to_virt(idx), phys, flags);
+       else
+               unmap_kernel_page(__fix_to_virt(idx));
 }
 
 #define __early_set_fixmap     __set_fixmap
index a58fb4a..674e5aa 100644 (file)
@@ -473,7 +473,7 @@ static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
        return !(regs->msr & MSR_EE);
 }
 
-static inline bool should_hard_irq_enable(void)
+static __always_inline bool should_hard_irq_enable(void)
 {
        return false;
 }
index fe07558..827038a 100644 (file)
@@ -39,7 +39,6 @@ struct kvm_nested_guest {
        pgd_t *shadow_pgtable;          /* our page table for this guest */
        u64 l1_gr_to_hr;                /* L1's addr of part'n-scoped table */
        u64 process_table;              /* process table entry for this guest */
-       u64 hfscr;                      /* HFSCR that the L1 requested for this nested guest */
        long refcnt;                    /* number of pointers to this struct */
        struct mutex tlb_lock;          /* serialize page faults and tlbies */
        struct kvm_nested_guest *next;
index a770443..d9bf60b 100644 (file)
@@ -818,6 +818,7 @@ struct kvm_vcpu_arch {
 
        /* For support of nested guests */
        struct kvm_nested_guest *nested;
+       u64 nested_hfscr;       /* HFSCR that the L1 requested for the nested guest */
        u32 nested_vcpu_id;
        gpa_t nested_io_gpr;
 #endif
index b67742e..d959c2a 100644 (file)
@@ -64,6 +64,7 @@ extern int icache_44x_need_flush;
 #ifndef __ASSEMBLY__
 
 int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot);
+void unmap_kernel_page(unsigned long va);
 
 #endif /* !__ASSEMBLY__ */
 
index a3313e8..2816d15 100644 (file)
@@ -308,6 +308,7 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
 #define __swp_entry_to_pte(x)          __pte((x).val)
 
 int map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot);
+void unmap_kernel_page(unsigned long va);
 extern int __meminit vmemmap_create_mapping(unsigned long start,
                                            unsigned long page_size,
                                            unsigned long phys);
index efad070..9675303 100644 (file)
 #define PPC_RAW_LDX(r, base, b)                (0x7c00002a | ___PPC_RT(r) | ___PPC_RA(base) | ___PPC_RB(b))
 #define PPC_RAW_LHZ(r, base, i)                (0xa0000000 | ___PPC_RT(r) | ___PPC_RA(base) | IMM_L(i))
 #define PPC_RAW_LHBRX(r, base, b)      (0x7c00062c | ___PPC_RT(r) | ___PPC_RA(base) | ___PPC_RB(b))
+#define PPC_RAW_LWBRX(r, base, b)      (0x7c00042c | ___PPC_RT(r) | ___PPC_RA(base) | ___PPC_RB(b))
 #define PPC_RAW_LDBRX(r, base, b)      (0x7c000428 | ___PPC_RT(r) | ___PPC_RA(base) | ___PPC_RB(b))
 #define PPC_RAW_STWCX(s, a, b)         (0x7c00012d | ___PPC_RS(s) | ___PPC_RA(a) | ___PPC_RB(b))
 #define PPC_RAW_CMPWI(a, i)            (0x2c000000 | ___PPC_RA(a) | IMM_L(i))
index 52d05b4..25fc8ad 100644 (file)
@@ -90,7 +90,7 @@ static inline void syscall_get_arguments(struct task_struct *task,
        unsigned long val, mask = -1UL;
        unsigned int n = 6;
 
-       if (is_32bit_task())
+       if (is_tsk_32bit_task(task))
                mask = 0xffffffff;
 
        while (n--) {
@@ -105,7 +105,7 @@ static inline void syscall_get_arguments(struct task_struct *task,
 
 static inline int syscall_get_arch(struct task_struct *task)
 {
-       if (is_32bit_task())
+       if (is_tsk_32bit_task(task))
                return AUDIT_ARCH_PPC;
        else if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))
                return AUDIT_ARCH_PPC64LE;
index 5725029..d6e649b 100644 (file)
@@ -168,8 +168,10 @@ static inline bool test_thread_local_flags(unsigned int flags)
 
 #ifdef CONFIG_COMPAT
 #define is_32bit_task()        (test_thread_flag(TIF_32BIT))
+#define is_tsk_32bit_task(tsk) (test_tsk_thread_flag(tsk, TIF_32BIT))
 #else
 #define is_32bit_task()        (IS_ENABLED(CONFIG_PPC32))
+#define is_tsk_32bit_task(tsk) (IS_ENABLED(CONFIG_PPC32))
 #endif
 
 #if defined(CONFIG_PPC64)
index 92088f8..7bab2d7 100644 (file)
@@ -30,6 +30,7 @@ COMPAT_SYS_CALL_TABLE:
        .ifc \srr,srr
        mfspr   r11,SPRN_SRR0
        ld      r12,_NIP(r1)
+       clrrdi  r11,r11,2
        clrrdi  r12,r12,2
 100:   tdne    r11,r12
        EMIT_WARN_ENTRY 100b,__FILE__,__LINE__,(BUGFLAG_WARNING | BUGFLAG_ONCE)
@@ -40,6 +41,7 @@ COMPAT_SYS_CALL_TABLE:
        .else
        mfspr   r11,SPRN_HSRR0
        ld      r12,_NIP(r1)
+       clrrdi  r11,r11,2
        clrrdi  r12,r12,2
 100:   tdne    r11,r12
        EMIT_WARN_ENTRY 100b,__FILE__,__LINE__,(BUGFLAG_WARNING | BUGFLAG_ONCE)
index 62361cc..cd0b8b7 100644 (file)
@@ -649,8 +649,9 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(timer_interrupt)
                __this_cpu_inc(irq_stat.timer_irqs_event);
        } else {
                now = *next_tb - now;
-               if (now <= decrementer_max)
-                       set_dec_or_work(now);
+               if (now > decrementer_max)
+                       now = decrementer_max;
+               set_dec_or_work(now);
                __this_cpu_inc(irq_stat.timer_irqs_others);
        }
 
index d1817cd..84c89f0 100644 (file)
@@ -1816,7 +1816,6 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu,
 
 static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu)
 {
-       struct kvm_nested_guest *nested = vcpu->arch.nested;
        int r;
        int srcu_idx;
 
@@ -1922,7 +1921,7 @@ static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu)
                 * it into a HEAI.
                 */
                if (!(vcpu->arch.hfscr_permitted & (1UL << cause)) ||
-                                       (nested->hfscr & (1UL << cause))) {
+                               (vcpu->arch.nested_hfscr & (1UL << cause))) {
                        vcpu->arch.trap = BOOK3S_INTERRUPT_H_EMUL_ASSIST;
 
                        /*
index 8f8daae..9d373f8 100644 (file)
@@ -363,7 +363,7 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu)
        /* set L1 state to L2 state */
        vcpu->arch.nested = l2;
        vcpu->arch.nested_vcpu_id = l2_hv.vcpu_token;
-       l2->hfscr = l2_hv.hfscr;
+       vcpu->arch.nested_hfscr = l2_hv.hfscr;
        vcpu->arch.regs = l2_regs;
 
        /* Guest must always run with ME enabled, HV disabled. */
index 94045b2..203735c 100644 (file)
@@ -76,7 +76,7 @@ unsigned long p_block_mapped(phys_addr_t pa)
        return 0;
 }
 
-static int __init find_free_bat(void)
+int __init find_free_bat(void)
 {
        int b;
        int n = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
@@ -100,7 +100,7 @@ static int __init find_free_bat(void)
  * - block size has to be a power of two. This is calculated by finding the
  *   highest bit set to 1.
  */
-static unsigned int block_size(unsigned long base, unsigned long top)
+unsigned int bat_block_size(unsigned long base, unsigned long top)
 {
        unsigned int max_size = SZ_256M;
        unsigned int base_shift = (ffs(base) - 1) & 31;
@@ -145,7 +145,7 @@ static unsigned long __init __mmu_mapin_ram(unsigned long base, unsigned long to
        int idx;
 
        while ((idx = find_free_bat()) != -1 && base != top) {
-               unsigned int size = block_size(base, top);
+               unsigned int size = bat_block_size(base, top);
 
                if (size < 128 << 10)
                        break;
@@ -201,12 +201,12 @@ void mmu_mark_initmem_nx(void)
        unsigned long size;
 
        for (i = 0; i < nb - 1 && base < top;) {
-               size = block_size(base, top);
+               size = bat_block_size(base, top);
                setibat(i++, PAGE_OFFSET + base, base, size, PAGE_KERNEL_TEXT);
                base += size;
        }
        if (base < top) {
-               size = block_size(base, top);
+               size = bat_block_size(base, top);
                if ((top - base) > size) {
                        size <<= 1;
                        if (strict_kernel_rwx_enabled() && base + size > border)
index 35b287b..450a67e 100644 (file)
@@ -10,48 +10,51 @@ int __init kasan_init_region(void *start, size_t size)
 {
        unsigned long k_start = (unsigned long)kasan_mem_to_shadow(start);
        unsigned long k_end = (unsigned long)kasan_mem_to_shadow(start + size);
-       unsigned long k_cur = k_start;
-       int k_size = k_end - k_start;
-       int k_size_base = 1 << (ffs(k_size) - 1);
+       unsigned long k_nobat = k_start;
+       unsigned long k_cur;
+       phys_addr_t phys;
        int ret;
-       void *block;
 
-       block = memblock_alloc(k_size, k_size_base);
-
-       if (block && k_size_base >= SZ_128K && k_start == ALIGN(k_start, k_size_base)) {
-               int shift = ffs(k_size - k_size_base);
-               int k_size_more = shift ? 1 << (shift - 1) : 0;
-
-               setbat(-1, k_start, __pa(block), k_size_base, PAGE_KERNEL);
-               if (k_size_more >= SZ_128K)
-                       setbat(-1, k_start + k_size_base, __pa(block) + k_size_base,
-                              k_size_more, PAGE_KERNEL);
-               if (v_block_mapped(k_start))
-                       k_cur = k_start + k_size_base;
-               if (v_block_mapped(k_start + k_size_base))
-                       k_cur = k_start + k_size_base + k_size_more;
-
-               update_bats();
+       while (k_nobat < k_end) {
+               unsigned int k_size = bat_block_size(k_nobat, k_end);
+               int idx = find_free_bat();
+
+               if (idx == -1)
+                       break;
+               if (k_size < SZ_128K)
+                       break;
+               phys = memblock_phys_alloc_range(k_size, k_size, 0,
+                                                MEMBLOCK_ALLOC_ANYWHERE);
+               if (!phys)
+                       break;
+
+               setbat(idx, k_nobat, phys, k_size, PAGE_KERNEL);
+               k_nobat += k_size;
        }
+       if (k_nobat != k_start)
+               update_bats();
 
-       if (!block)
-               block = memblock_alloc(k_size, PAGE_SIZE);
-       if (!block)
-               return -ENOMEM;
+       if (k_nobat < k_end) {
+               phys = memblock_phys_alloc_range(k_end - k_nobat, PAGE_SIZE, 0,
+                                                MEMBLOCK_ALLOC_ANYWHERE);
+               if (!phys)
+                       return -ENOMEM;
+       }
 
        ret = kasan_init_shadow_page_tables(k_start, k_end);
        if (ret)
                return ret;
 
-       kasan_update_early_region(k_start, k_cur, __pte(0));
+       kasan_update_early_region(k_start, k_nobat, __pte(0));
 
-       for (; k_cur < k_end; k_cur += PAGE_SIZE) {
+       for (k_cur = k_nobat; k_cur < k_end; k_cur += PAGE_SIZE) {
                pmd_t *pmd = pmd_off_k(k_cur);
-               void *va = block + k_cur - k_start;
-               pte_t pte = pfn_pte(PHYS_PFN(__pa(va)), PAGE_KERNEL);
+               pte_t pte = pfn_pte(PHYS_PFN(phys + k_cur - k_nobat), PAGE_KERNEL);
 
                __set_pte_at(&init_mm, k_cur, pte_offset_kernel(pmd, k_cur), pte, 0);
        }
        flush_tlb_kernel_range(k_start, k_end);
+       memset(kasan_mem_to_shadow(start), 0, k_end - k_start);
+
        return 0;
 }
index abb3198..6ec5a7d 100644 (file)
@@ -206,6 +206,15 @@ void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
        __set_pte_at(mm, addr, ptep, pte, 0);
 }
 
+void unmap_kernel_page(unsigned long va)
+{
+       pmd_t *pmdp = pmd_off_k(va);
+       pte_t *ptep = pte_offset_kernel(pmdp, va);
+
+       pte_clear(&init_mm, va, ptep);
+       flush_tlb_kernel_range(va, va + PAGE_SIZE);
+}
+
 /*
  * This is called when relaxing access to a PTE. It's also called in the page
  * fault path when we don't hit any of the major fault cases, ie, a minor
index d6ffdd0..56dd1f4 100644 (file)
@@ -23,15 +23,15 @@ static void bpf_jit_fill_ill_insns(void *area, unsigned int size)
        memset32(area, BREAKPOINT_INSTRUCTION, size / 4);
 }
 
-/* Fix the branch target addresses for subprog calls */
-static int bpf_jit_fixup_subprog_calls(struct bpf_prog *fp, u32 *image,
-                                      struct codegen_context *ctx, u32 *addrs)
+/* Fix updated addresses (for subprog calls, ldimm64, et al) during extra pass */
+static int bpf_jit_fixup_addresses(struct bpf_prog *fp, u32 *image,
+                                  struct codegen_context *ctx, u32 *addrs)
 {
        const struct bpf_insn *insn = fp->insnsi;
        bool func_addr_fixed;
        u64 func_addr;
        u32 tmp_idx;
-       int i, ret;
+       int i, j, ret;
 
        for (i = 0; i < fp->len; i++) {
                /*
@@ -66,6 +66,23 @@ static int bpf_jit_fixup_subprog_calls(struct bpf_prog *fp, u32 *image,
                         * of the JITed sequence remains unchanged.
                         */
                        ctx->idx = tmp_idx;
+               } else if (insn[i].code == (BPF_LD | BPF_IMM | BPF_DW)) {
+                       tmp_idx = ctx->idx;
+                       ctx->idx = addrs[i] / 4;
+#ifdef CONFIG_PPC32
+                       PPC_LI32(ctx->b2p[insn[i].dst_reg] - 1, (u32)insn[i + 1].imm);
+                       PPC_LI32(ctx->b2p[insn[i].dst_reg], (u32)insn[i].imm);
+                       for (j = ctx->idx - addrs[i] / 4; j < 4; j++)
+                               EMIT(PPC_RAW_NOP());
+#else
+                       func_addr = ((u64)(u32)insn[i].imm) | (((u64)(u32)insn[i + 1].imm) << 32);
+                       PPC_LI64(b2p[insn[i].dst_reg], func_addr);
+                       /* overwrite rest with nops */
+                       for (j = ctx->idx - addrs[i] / 4; j < 5; j++)
+                               EMIT(PPC_RAW_NOP());
+#endif
+                       ctx->idx = tmp_idx;
+                       i++;
                }
        }
 
@@ -200,13 +217,13 @@ skip_init_ctx:
                /*
                 * Do not touch the prologue and epilogue as they will remain
                 * unchanged. Only fix the branch target address for subprog
-                * calls in the body.
+                * calls in the body, and ldimm64 instructions.
                 *
                 * This does not change the offsets and lengths of the subprog
                 * call instruction sequences and hence, the size of the JITed
                 * image as well.
                 */
-               bpf_jit_fixup_subprog_calls(fp, code_base, &cgctx, addrs);
+               bpf_jit_fixup_addresses(fp, code_base, &cgctx, addrs);
 
                /* There is no need to perform the usual passes. */
                goto skip_codegen_passes;
index faaebd4..cf8dd8a 100644 (file)
@@ -191,6 +191,9 @@ void bpf_jit_emit_func_call_rel(u32 *image, struct codegen_context *ctx, u64 fun
 
        if (image && rel < 0x2000000 && rel >= -0x2000000) {
                PPC_BL_ABS(func);
+               EMIT(PPC_RAW_NOP());
+               EMIT(PPC_RAW_NOP());
+               EMIT(PPC_RAW_NOP());
        } else {
                /* Load function address into r0 */
                EMIT(PPC_RAW_LIS(_R0, IMM_H(func)));
@@ -290,6 +293,8 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
                bool func_addr_fixed;
                u64 func_addr;
                u32 true_cond;
+               u32 tmp_idx;
+               int j;
 
                /*
                 * addrs[] maps a BPF bytecode address into a real offset from
@@ -905,8 +910,12 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
                 * 16 byte instruction that uses two 'struct bpf_insn'
                 */
                case BPF_LD | BPF_IMM | BPF_DW: /* dst = (u64) imm */
+                       tmp_idx = ctx->idx;
                        PPC_LI32(dst_reg_h, (u32)insn[i + 1].imm);
                        PPC_LI32(dst_reg, (u32)insn[i].imm);
+                       /* padding to allow full 4 instructions for later patching */
+                       for (j = ctx->idx - tmp_idx; j < 4; j++)
+                               EMIT(PPC_RAW_NOP());
                        /* Adjust for two bpf instructions */
                        addrs[++i] = ctx->idx * 4;
                        break;
index 9eae8d8..e1e8c93 100644 (file)
@@ -319,6 +319,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
                u64 imm64;
                u32 true_cond;
                u32 tmp_idx;
+               int j;
 
                /*
                 * addrs[] maps a BPF bytecode address into a real offset from
@@ -633,17 +634,21 @@ bpf_alu32_trunc:
                                EMIT(PPC_RAW_MR(dst_reg, b2p[TMP_REG_1]));
                                break;
                        case 64:
-                               /*
-                                * Way easier and faster(?) to store the value
-                                * into stack and then use ldbrx
-                                *
-                                * ctx->seen will be reliable in pass2, but
-                                * the instructions generated will remain the
-                                * same across all passes
-                                */
+                               /* Store the value to stack and then use byte-reverse loads */
                                PPC_BPF_STL(dst_reg, 1, bpf_jit_stack_local(ctx));
                                EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], 1, bpf_jit_stack_local(ctx)));
-                               EMIT(PPC_RAW_LDBRX(dst_reg, 0, b2p[TMP_REG_1]));
+                               if (cpu_has_feature(CPU_FTR_ARCH_206)) {
+                                       EMIT(PPC_RAW_LDBRX(dst_reg, 0, b2p[TMP_REG_1]));
+                               } else {
+                                       EMIT(PPC_RAW_LWBRX(dst_reg, 0, b2p[TMP_REG_1]));
+                                       if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))
+                                               EMIT(PPC_RAW_SLDI(dst_reg, dst_reg, 32));
+                                       EMIT(PPC_RAW_LI(b2p[TMP_REG_2], 4));
+                                       EMIT(PPC_RAW_LWBRX(b2p[TMP_REG_2], b2p[TMP_REG_2], b2p[TMP_REG_1]));
+                                       if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+                                               EMIT(PPC_RAW_SLDI(b2p[TMP_REG_2], b2p[TMP_REG_2], 32));
+                                       EMIT(PPC_RAW_OR(dst_reg, dst_reg, b2p[TMP_REG_2]));
+                               }
                                break;
                        }
                        break;
@@ -848,9 +853,13 @@ emit_clear:
                case BPF_LD | BPF_IMM | BPF_DW: /* dst = (u64) imm */
                        imm64 = ((u64)(u32) insn[i].imm) |
                                    (((u64)(u32) insn[i+1].imm) << 32);
+                       tmp_idx = ctx->idx;
+                       PPC_LI64(dst_reg, imm64);
+                       /* padding to allow full 5 instructions for later patching */
+                       for (j = ctx->idx - tmp_idx; j < 5; j++)
+                               EMIT(PPC_RAW_NOP());
                        /* Adjust for two bpf instructions */
                        addrs[++i] = ctx->idx * 4;
-                       PPC_LI64(dst_reg, imm64);
                        break;
 
                /*
index a684901..b5b42cf 100644 (file)
@@ -776,6 +776,34 @@ static void pmao_restore_workaround(bool ebb)
        mtspr(SPRN_PMC6, pmcs[5]);
 }
 
+/*
+ * If the perf subsystem wants performance monitor interrupts as soon as
+ * possible (e.g., to sample the instruction address and stack chain),
+ * this should return true. The IRQ masking code can then enable MSR[EE]
+ * in some places (e.g., interrupt handlers) that allows PMI interrupts
+ * through to improve accuracy of profiles, at the cost of some performance.
+ *
+ * The PMU counters can be enabled by other means (e.g., sysfs raw SPR
+ * access), but in that case there is no need for prompt PMI handling.
+ *
+ * This currently returns true if any perf counter is being used. It
+ * could possibly return false if only events are being counted rather than
+ * samples being taken, but for now this is good enough.
+ */
+bool power_pmu_wants_prompt_pmi(void)
+{
+       struct cpu_hw_events *cpuhw;
+
+       /*
+        * This could simply test local_paca->pmcregs_in_use if that were not
+        * under ifdef KVM.
+        */
+       if (!ppmu)
+               return false;
+
+       cpuhw = this_cpu_ptr(&cpu_hw_events);
+       return cpuhw->n_events;
+}
 #endif /* CONFIG_PPC64 */
 
 static void perf_event_interrupt(struct pt_regs *regs);
@@ -1327,9 +1355,20 @@ static void power_pmu_disable(struct pmu *pmu)
                 * Otherwise provide a warning if there is PMI pending, but
                 * no counter is found overflown.
                 */
-               if (any_pmc_overflown(cpuhw))
-                       clear_pmi_irq_pending();
-               else
+               if (any_pmc_overflown(cpuhw)) {
+                       /*
+                        * Since power_pmu_disable runs under local_irq_save, it
+                        * could happen that code hits a PMC overflow without PMI
+                        * pending in paca. Hence only clear PMI pending if it was
+                        * set.
+                        *
+                        * If a PMI is pending, then MSR[EE] must be disabled (because
+                        * the masked PMI handler disabling EE). So it is safe to
+                        * call clear_pmi_irq_pending().
+                        */
+                       if (pmi_irq_pending())
+                               clear_pmi_irq_pending();
+               } else
                        WARN_ON(pmi_irq_pending());
 
                val = mmcra = cpuhw->mmcr.mmcra;
@@ -2438,36 +2477,6 @@ static void perf_event_interrupt(struct pt_regs *regs)
        perf_sample_event_took(sched_clock() - start_clock);
 }
 
-/*
- * If the perf subsystem wants performance monitor interrupts as soon as
- * possible (e.g., to sample the instruction address and stack chain),
- * this should return true. The IRQ masking code can then enable MSR[EE]
- * in some places (e.g., interrupt handlers) that allows PMI interrupts
- * though to improve accuracy of profiles, at the cost of some performance.
- *
- * The PMU counters can be enabled by other means (e.g., sysfs raw SPR
- * access), but in that case there is no need for prompt PMI handling.
- *
- * This currently returns true if any perf counter is being used. It
- * could possibly return false if only events are being counted rather than
- * samples being taken, but for now this is good enough.
- */
-bool power_pmu_wants_prompt_pmi(void)
-{
-       struct cpu_hw_events *cpuhw;
-
-       /*
-        * This could simply test local_paca->pmcregs_in_use if that were not
-        * under ifdef KVM.
-        */
-
-       if (!ppmu)
-               return false;
-
-       cpuhw = this_cpu_ptr(&cpu_hw_events);
-       return cpuhw->n_events;
-}
-
 static int power_pmu_prepare_cpu(unsigned int cpu)
 {
        struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
index 8a107ed..7d81102 100644 (file)
@@ -50,6 +50,12 @@ riscv-march-$(CONFIG_ARCH_RV32I)     := rv32ima
 riscv-march-$(CONFIG_ARCH_RV64I)       := rv64ima
 riscv-march-$(CONFIG_FPU)              := $(riscv-march-y)fd
 riscv-march-$(CONFIG_RISCV_ISA_C)      := $(riscv-march-y)c
+
+# Newer binutils versions default to ISA spec version 20191213 which moves some
+# instructions from the I extension to the Zicsr and Zifencei extensions.
+toolchain-need-zicsr-zifencei := $(call cc-option-yn, -march=$(riscv-march-y)_zicsr_zifencei)
+riscv-march-$(toolchain-need-zicsr-zifencei) := $(riscv-march-y)_zicsr_zifencei
+
 KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y))
 KBUILD_AFLAGS += -march=$(riscv-march-y)
 
index be7f05b..f7a832e 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/sched/hotplug.h>
 #include <asm/irq.h>
 #include <asm/cpu_ops.h>
+#include <asm/numa.h>
 #include <asm/sbi.h>
 
 bool cpu_has_hotplug(unsigned int cpu)
@@ -40,6 +41,7 @@ int __cpu_disable(void)
                return ret;
 
        remove_cpu_topology(cpu);
+       numa_remove_cpu(cpu);
        set_cpu_online(cpu, false);
        irq_migrate_all_off_this_cpu();
 
index 2363b43..ec07f99 100644 (file)
        add \reg, \reg, t0
 .endm
 .macro XIP_FIXUP_FLASH_OFFSET reg
-       la t1, __data_loc
-       li t0, XIP_OFFSET_MASK
-       and t1, t1, t0
-       li t1, XIP_OFFSET
-       sub t0, t0, t1
-       sub \reg, \reg, t0
+       la t0, __data_loc
+       REG_L t1, _xip_phys_offset
+       sub \reg, \reg, t1
+       add \reg, \reg, t0
 .endm
 _xip_fixup: .dword CONFIG_PHYS_RAM_BASE - CONFIG_XIP_PHYS_ADDR - XIP_OFFSET
+_xip_phys_offset: .dword CONFIG_XIP_PHYS_ADDR + XIP_OFFSET
 #else
 .macro XIP_FIXUP_OFFSET reg
 .endm
index 201ee20..14d2b53 100644 (file)
@@ -22,15 +22,16 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
                             bool (*fn)(void *, unsigned long), void *arg)
 {
        unsigned long fp, sp, pc;
+       int level = 0;
 
        if (regs) {
                fp = frame_pointer(regs);
                sp = user_stack_pointer(regs);
                pc = instruction_pointer(regs);
        } else if (task == NULL || task == current) {
-               fp = (unsigned long)__builtin_frame_address(1);
-               sp = (unsigned long)__builtin_frame_address(0);
-               pc = (unsigned long)__builtin_return_address(0);
+               fp = (unsigned long)__builtin_frame_address(0);
+               sp = sp_in_global;
+               pc = (unsigned long)walk_stackframe;
        } else {
                /* task blocked in __switch_to */
                fp = task->thread.s[0];
@@ -42,7 +43,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
                unsigned long low, high;
                struct stackframe *frame;
 
-               if (unlikely(!__kernel_text_address(pc) || !fn(arg, pc)))
+               if (unlikely(!__kernel_text_address(pc) || (level++ >= 1 && !fn(arg, pc))))
                        break;
 
                /* Validate frame pointer */
index 0c5239e..6241660 100644 (file)
@@ -90,6 +90,7 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
 int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpu_context *cntx;
+       struct kvm_vcpu_csr *reset_csr = &vcpu->arch.guest_reset_csr;
 
        /* Mark this VCPU never ran */
        vcpu->arch.ran_atleast_once = false;
@@ -106,6 +107,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
        cntx->hstatus |= HSTATUS_SPVP;
        cntx->hstatus |= HSTATUS_SPV;
 
+       /* By default, make CY, TM, and IR counters accessible in VU mode */
+       reset_csr->scounteren = 0x7;
+
        /* Setup VCPU timer */
        kvm_riscv_vcpu_timer_init(vcpu);
 
@@ -699,6 +703,20 @@ static void kvm_riscv_update_hvip(struct kvm_vcpu *vcpu)
        csr_write(CSR_HVIP, csr->hvip);
 }
 
+/*
+ * Actually run the vCPU, entering an RCU extended quiescent state (EQS) while
+ * the vCPU is running.
+ *
+ * This must be noinstr as instrumentation may make use of RCU, and this is not
+ * safe during the EQS.
+ */
+static void noinstr kvm_riscv_vcpu_enter_exit(struct kvm_vcpu *vcpu)
+{
+       guest_state_enter_irqoff();
+       __kvm_riscv_switch_to(&vcpu->arch);
+       guest_state_exit_irqoff();
+}
+
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 {
        int ret;
@@ -790,9 +808,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                        continue;
                }
 
-               guest_enter_irqoff();
+               guest_timing_enter_irqoff();
 
-               __kvm_riscv_switch_to(&vcpu->arch);
+               kvm_riscv_vcpu_enter_exit(vcpu);
 
                vcpu->mode = OUTSIDE_GUEST_MODE;
                vcpu->stat.exits++;
@@ -812,25 +830,21 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                kvm_riscv_vcpu_sync_interrupts(vcpu);
 
                /*
-                * We may have taken a host interrupt in VS/VU-mode (i.e.
-                * while executing the guest). This interrupt is still
-                * pending, as we haven't serviced it yet!
+                * We must ensure that any pending interrupts are taken before
+                * we exit guest timing so that timer ticks are accounted as
+                * guest time. Transiently unmask interrupts so that any
+                * pending interrupts are taken.
                 *
-                * We're now back in HS-mode with interrupts disabled
-                * so enabling the interrupts now will have the effect
-                * of taking the interrupt again, in HS-mode this time.
+                * There's no barrier which ensures that pending interrupts are
+                * recognised, so we just hope that the CPU takes any pending
+                * interrupts between the enable and disable.
                 */
                local_irq_enable();
+               local_irq_disable();
 
-               /*
-                * We do local_irq_enable() before calling guest_exit() so
-                * that if a timer interrupt hits while running the guest
-                * we account that tick as being spent in the guest. We
-                * enable preemption after calling guest_exit() so that if
-                * we get preempted we make sure ticks after that is not
-                * counted as guest time.
-                */
-               guest_exit();
+               guest_timing_exit_irqoff();
+
+               local_irq_enable();
 
                preempt_enable();
 
index 4ecf377..48f4310 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/kvm_host.h>
+#include <linux/version.h>
 #include <asm/csr.h>
 #include <asm/sbi.h>
 #include <asm/kvm_vcpu_timer.h>
@@ -32,7 +33,7 @@ static int kvm_sbi_ext_base_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
                *out_val = KVM_SBI_IMPID;
                break;
        case SBI_EXT_BASE_GET_IMP_VERSION:
-               *out_val = 0;
+               *out_val = LINUX_VERSION_CODE;
                break;
        case SBI_EXT_BASE_PROBE_EXT:
                if ((cp->a0 >= SBI_EXT_EXPERIMENTAL_START &&
index 05978f7..35484d8 100644 (file)
@@ -33,7 +33,7 @@ static inline void regs_set_gpr(struct pt_regs *regs, unsigned int offset,
        if (unlikely(offset > MAX_REG_OFFSET))
                return;
 
-       if (!offset)
+       if (offset)
                *(unsigned long *)((unsigned long)regs + offset) = val;
 }
 
@@ -43,8 +43,8 @@ static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex,
        int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
        int reg_zero = FIELD_GET(EX_DATA_REG_ZERO, ex->data);
 
-       regs_set_gpr(regs, reg_err, -EFAULT);
-       regs_set_gpr(regs, reg_zero, 0);
+       regs_set_gpr(regs, reg_err * sizeof(unsigned long), -EFAULT);
+       regs_set_gpr(regs, reg_zero * sizeof(unsigned long), 0);
 
        regs->epc = get_ex_fixup(ex);
        return true;
index cf4d018..c272941 100644 (file)
@@ -232,6 +232,7 @@ static pmd_t __maybe_unused early_dtb_pmd[PTRS_PER_PMD] __initdata __aligned(PAG
 
 #ifdef CONFIG_XIP_KERNEL
 #define pt_ops                 (*(struct pt_alloc_ops *)XIP_FIXUP(&pt_ops))
+#define riscv_pfn_base         (*(unsigned long  *)XIP_FIXUP(&riscv_pfn_base))
 #define trampoline_pg_dir      ((pgd_t *)XIP_FIXUP(trampoline_pg_dir))
 #define fixmap_pte             ((pte_t *)XIP_FIXUP(fixmap_pte))
 #define early_pg_dir           ((pgd_t *)XIP_FIXUP(early_pg_dir))
@@ -522,6 +523,7 @@ static uintptr_t __init best_map_size(phys_addr_t base, phys_addr_t size)
 }
 
 #ifdef CONFIG_XIP_KERNEL
+#define phys_ram_base  (*(phys_addr_t *)XIP_FIXUP(&phys_ram_base))
 extern char _xiprom[], _exiprom[], __data_loc;
 
 /* called from head.S with MMU off */
index 9750f92..be9f39f 100644 (file)
@@ -945,6 +945,9 @@ config S390_GUEST
 
 endmenu
 
+config S390_MODULES_SANITY_TEST_HELPERS
+       def_bool n
+
 menu "Selftests"
 
 config S390_UNWIND_SELFTEST
@@ -971,4 +974,16 @@ config S390_KPROBES_SANITY_TEST
 
          Say N if you are unsure.
 
+config S390_MODULES_SANITY_TEST
+       def_tristate n
+       depends on KUNIT
+       default KUNIT_ALL_TESTS
+       prompt "Enable s390 specific modules tests"
+       select S390_MODULES_SANITY_TEST_HELPERS
+       help
+         This option enables an s390 specific modules test. This option is
+         not useful for distributions or general kernels, but only for
+         kernel developers working on architecture code.
+
+         Say N if you are unsure.
 endmenu
index 7fe8975..498bed9 100644 (file)
@@ -63,6 +63,7 @@ CONFIG_APPLDATA_BASE=y
 CONFIG_KVM=m
 CONFIG_S390_UNWIND_SELFTEST=m
 CONFIG_S390_KPROBES_SANITY_TEST=m
+CONFIG_S390_MODULES_SANITY_TEST=m
 CONFIG_KPROBES=y
 CONFIG_JUMP_LABEL=y
 CONFIG_STATIC_KEYS_SELFTEST=y
@@ -96,7 +97,6 @@ CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
 CONFIG_KSM=y
 CONFIG_TRANSPARENT_HUGEPAGE=y
-CONFIG_FRONTSWAP=y
 CONFIG_CMA_DEBUG=y
 CONFIG_CMA_DEBUGFS=y
 CONFIG_CMA_SYSFS=y
@@ -109,6 +109,7 @@ CONFIG_DEFERRED_STRUCT_PAGE_INIT=y
 CONFIG_IDLE_PAGE_TRACKING=y
 CONFIG_PERCPU_STATS=y
 CONFIG_GUP_TEST=y
+CONFIG_ANON_VMA_NAME=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -116,7 +117,6 @@ CONFIG_UNIX=y
 CONFIG_UNIX_DIAG=m
 CONFIG_XFRM_USER=m
 CONFIG_NET_KEY=m
-CONFIG_NET_SWITCHDEV=y
 CONFIG_SMC=m
 CONFIG_SMC_DIAG=m
 CONFIG_INET=y
@@ -185,7 +185,6 @@ CONFIG_NF_CT_NETLINK_TIMEOUT=m
 CONFIG_NF_TABLES=m
 CONFIG_NF_TABLES_INET=y
 CONFIG_NFT_CT=m
-CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
@@ -391,6 +390,7 @@ CONFIG_OPENVSWITCH=m
 CONFIG_VSOCKETS=m
 CONFIG_VIRTIO_VSOCKETS=m
 CONFIG_NETLINK_DIAG=m
+CONFIG_NET_SWITCHDEV=y
 CONFIG_CGROUP_NET_PRIO=y
 CONFIG_NET_PKTGEN=m
 CONFIG_PCI=y
@@ -400,6 +400,7 @@ CONFIG_PCI_IOV=y
 CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_S390=y
 CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_SAFE=y
 CONFIG_CONNECTOR=y
 CONFIG_ZRAM=y
 CONFIG_BLK_DEV_LOOP=m
@@ -501,6 +502,7 @@ CONFIG_NLMON=m
 # CONFIG_NET_VENDOR_DEC is not set
 # CONFIG_NET_VENDOR_DLINK is not set
 # CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_ENGLEDER is not set
 # CONFIG_NET_VENDOR_EZCHIP is not set
 # CONFIG_NET_VENDOR_GOOGLE is not set
 # CONFIG_NET_VENDOR_HUAWEI is not set
@@ -511,7 +513,6 @@ CONFIG_NLMON=m
 CONFIG_MLX4_EN=m
 CONFIG_MLX5_CORE=m
 CONFIG_MLX5_CORE_EN=y
-CONFIG_MLX5_ESWITCH=y
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_MICROCHIP is not set
 # CONFIG_NET_VENDOR_MICROSEMI is not set
@@ -542,6 +543,7 @@ CONFIG_MLX5_ESWITCH=y
 # CONFIG_NET_VENDOR_SYNOPSYS is not set
 # CONFIG_NET_VENDOR_TEHUTI is not set
 # CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VERTEXCOM is not set
 # CONFIG_NET_VENDOR_VIA is not set
 # CONFIG_NET_VENDOR_WIZNET is not set
 # CONFIG_NET_VENDOR_XILINX is not set
@@ -592,6 +594,7 @@ CONFIG_VIRTIO_BALLOON=m
 CONFIG_VIRTIO_INPUT=y
 CONFIG_VHOST_NET=m
 CONFIG_VHOST_VSOCK=m
+# CONFIG_SURFACE_PLATFORMS is not set
 CONFIG_S390_CCW_IOMMU=y
 CONFIG_S390_AP_IOMMU=y
 CONFIG_EXT4_FS=y
@@ -756,9 +759,6 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
 CONFIG_CRYPTO_STATS=y
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 CONFIG_ZCRYPT=m
 CONFIG_PKEY=m
 CONFIG_CRYPTO_PAES_S390=m
@@ -774,6 +774,8 @@ CONFIG_CRYPTO_GHASH_S390=m
 CONFIG_CRYPTO_CRC32_S390=y
 CONFIG_CRYPTO_DEV_VIRTIO=m
 CONFIG_CORDIC=m
+CONFIG_CRYPTO_LIB_CURVE25519=m
+CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 CONFIG_CRC32_SELFTEST=y
 CONFIG_CRC4=m
 CONFIG_CRC7=m
@@ -807,7 +809,6 @@ CONFIG_SLUB_DEBUG_ON=y
 CONFIG_SLUB_STATS=y
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_VM=y
-CONFIG_DEBUG_VM_VMACACHE=y
 CONFIG_DEBUG_VM_PGFLAGS=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m
@@ -819,12 +820,11 @@ CONFIG_PANIC_ON_OOPS=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_WQ_WATCHDOG=y
 CONFIG_TEST_LOCKUP=m
-CONFIG_DEBUG_TIMEKEEPING=y
 CONFIG_PROVE_LOCKING=y
 CONFIG_LOCK_STAT=y
-CONFIG_DEBUG_LOCKDEP=y
 CONFIG_DEBUG_ATOMIC_SLEEP=y
 CONFIG_DEBUG_LOCKING_API_SELFTESTS=y
+CONFIG_DEBUG_IRQFLAGS=y
 CONFIG_DEBUG_SG=y
 CONFIG_DEBUG_NOTIFIERS=y
 CONFIG_BUG_ON_DATA_CORRUPTION=y
index 466780c..61e36b9 100644 (file)
@@ -61,6 +61,7 @@ CONFIG_APPLDATA_BASE=y
 CONFIG_KVM=m
 CONFIG_S390_UNWIND_SELFTEST=m
 CONFIG_S390_KPROBES_SANITY_TEST=m
+CONFIG_S390_MODULES_SANITY_TEST=m
 CONFIG_KPROBES=y
 CONFIG_JUMP_LABEL=y
 # CONFIG_GCC_PLUGINS is not set
@@ -91,7 +92,6 @@ CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
 CONFIG_KSM=y
 CONFIG_TRANSPARENT_HUGEPAGE=y
-CONFIG_FRONTSWAP=y
 CONFIG_CMA_SYSFS=y
 CONFIG_CMA_AREAS=7
 CONFIG_MEM_SOFT_DIRTY=y
@@ -101,6 +101,7 @@ CONFIG_ZSMALLOC_STAT=y
 CONFIG_DEFERRED_STRUCT_PAGE_INIT=y
 CONFIG_IDLE_PAGE_TRACKING=y
 CONFIG_PERCPU_STATS=y
+CONFIG_ANON_VMA_NAME=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -108,7 +109,6 @@ CONFIG_UNIX=y
 CONFIG_UNIX_DIAG=m
 CONFIG_XFRM_USER=m
 CONFIG_NET_KEY=m
-CONFIG_NET_SWITCHDEV=y
 CONFIG_SMC=m
 CONFIG_SMC_DIAG=m
 CONFIG_INET=y
@@ -177,7 +177,6 @@ CONFIG_NF_CT_NETLINK_TIMEOUT=m
 CONFIG_NF_TABLES=m
 CONFIG_NF_TABLES_INET=y
 CONFIG_NFT_CT=m
-CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
@@ -382,6 +381,7 @@ CONFIG_OPENVSWITCH=m
 CONFIG_VSOCKETS=m
 CONFIG_VIRTIO_VSOCKETS=m
 CONFIG_NETLINK_DIAG=m
+CONFIG_NET_SWITCHDEV=y
 CONFIG_CGROUP_NET_PRIO=y
 CONFIG_NET_PKTGEN=m
 CONFIG_PCI=y
@@ -391,6 +391,7 @@ CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_S390=y
 CONFIG_UEVENT_HELPER=y
 CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_SAFE=y
 CONFIG_CONNECTOR=y
 CONFIG_ZRAM=y
 CONFIG_BLK_DEV_LOOP=m
@@ -492,6 +493,7 @@ CONFIG_NLMON=m
 # CONFIG_NET_VENDOR_DEC is not set
 # CONFIG_NET_VENDOR_DLINK is not set
 # CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_ENGLEDER is not set
 # CONFIG_NET_VENDOR_EZCHIP is not set
 # CONFIG_NET_VENDOR_GOOGLE is not set
 # CONFIG_NET_VENDOR_HUAWEI is not set
@@ -502,7 +504,6 @@ CONFIG_NLMON=m
 CONFIG_MLX4_EN=m
 CONFIG_MLX5_CORE=m
 CONFIG_MLX5_CORE_EN=y
-CONFIG_MLX5_ESWITCH=y
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_MICROCHIP is not set
 # CONFIG_NET_VENDOR_MICROSEMI is not set
@@ -533,6 +534,7 @@ CONFIG_MLX5_ESWITCH=y
 # CONFIG_NET_VENDOR_SYNOPSYS is not set
 # CONFIG_NET_VENDOR_TEHUTI is not set
 # CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VERTEXCOM is not set
 # CONFIG_NET_VENDOR_VIA is not set
 # CONFIG_NET_VENDOR_WIZNET is not set
 # CONFIG_NET_VENDOR_XILINX is not set
@@ -582,6 +584,7 @@ CONFIG_VIRTIO_BALLOON=m
 CONFIG_VIRTIO_INPUT=y
 CONFIG_VHOST_NET=m
 CONFIG_VHOST_VSOCK=m
+# CONFIG_SURFACE_PLATFORMS is not set
 CONFIG_S390_CCW_IOMMU=y
 CONFIG_S390_AP_IOMMU=y
 CONFIG_EXT4_FS=y
@@ -743,9 +746,6 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
 CONFIG_CRYPTO_STATS=y
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 CONFIG_ZCRYPT=m
 CONFIG_PKEY=m
 CONFIG_CRYPTO_PAES_S390=m
@@ -762,6 +762,8 @@ CONFIG_CRYPTO_CRC32_S390=y
 CONFIG_CRYPTO_DEV_VIRTIO=m
 CONFIG_CORDIC=m
 CONFIG_PRIME_NUMBERS=m
+CONFIG_CRYPTO_LIB_CURVE25519=m
+CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 CONFIG_CRC4=m
 CONFIG_CRC7=m
 CONFIG_CRC8=m
index eed3b9a..c55c668 100644 (file)
@@ -1,6 +1,7 @@
 # CONFIG_SWAP is not set
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BPF_SYSCALL=y
 # CONFIG_CPU_ISOLATION is not set
 # CONFIG_UTS_NS is not set
 # CONFIG_TIME_NS is not set
@@ -34,6 +35,7 @@ CONFIG_NET=y
 # CONFIG_PCPU_DEV_REFCNT is not set
 # CONFIG_ETHTOOL_NETLINK is not set
 CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_SAFE=y
 CONFIG_BLK_DEV_RAM=y
 # CONFIG_DCSSBLK is not set
 # CONFIG_DASD is not set
@@ -58,6 +60,7 @@ CONFIG_ZFCP=y
 # CONFIG_HID is not set
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_VHOST_MENU is not set
+# CONFIG_SURFACE_PLATFORMS is not set
 # CONFIG_IOMMU_SUPPORT is not set
 # CONFIG_DNOTIFY is not set
 # CONFIG_INOTIFY_USER is not set
index 33f973f..e8f15db 100644 (file)
@@ -20,6 +20,7 @@
 
 static char local_guest[] = "        ";
 static char all_guests[] = "*       ";
+static char *all_groups = all_guests;
 static char *guest_query;
 
 struct diag2fc_data {
@@ -62,10 +63,11 @@ static int diag2fc(int size, char* query, void *addr)
 
        memcpy(parm_list.userid, query, NAME_LEN);
        ASCEBC(parm_list.userid, NAME_LEN);
-       parm_list.addr = (unsigned long) addr ;
+       memcpy(parm_list.aci_grp, all_groups, NAME_LEN);
+       ASCEBC(parm_list.aci_grp, NAME_LEN);
+       parm_list.addr = (unsigned long)addr;
        parm_list.size = size;
        parm_list.fmt = 0x02;
-       memset(parm_list.aci_grp, 0x40, NAME_LEN);
        rc = -1;
 
        diag_stat_inc(DIAG_STAT_X2FC);
index 147cb35..d74e26b 100644 (file)
@@ -47,8 +47,6 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n);
 int __put_user_bad(void) __attribute__((noreturn));
 int __get_user_bad(void) __attribute__((noreturn));
 
-#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
-
 union oac {
        unsigned int val;
        struct {
@@ -71,6 +69,8 @@ union oac {
        };
 };
 
+#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
+
 #define __put_get_user_asm(to, from, size, oac_spec)                   \
 ({                                                                     \
        int __rc;                                                       \
index d52d853..b032e55 100644 (file)
@@ -33,7 +33,7 @@
 #define DEBUGP(fmt , ...)
 #endif
 
-#define PLT_ENTRY_SIZE 20
+#define PLT_ENTRY_SIZE 22
 
 void *module_alloc(unsigned long size)
 {
@@ -341,27 +341,26 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
        case R_390_PLTOFF32:    /* 32 bit offset from GOT to PLT. */
        case R_390_PLTOFF64:    /* 16 bit offset from GOT to PLT. */
                if (info->plt_initialized == 0) {
-                       unsigned int insn[5];
-                       unsigned int *ip = me->core_layout.base +
-                                          me->arch.plt_offset +
-                                          info->plt_offset;
-
-                       insn[0] = 0x0d10e310;   /* basr 1,0  */
-                       insn[1] = 0x100a0004;   /* lg   1,10(1) */
+                       unsigned char insn[PLT_ENTRY_SIZE];
+                       char *plt_base;
+                       char *ip;
+
+                       plt_base = me->core_layout.base + me->arch.plt_offset;
+                       ip = plt_base + info->plt_offset;
+                       *(int *)insn = 0x0d10e310;      /* basr 1,0  */
+                       *(int *)&insn[4] = 0x100c0004;  /* lg   1,12(1) */
                        if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) {
-                               unsigned int *ij;
-                               ij = me->core_layout.base +
-                                       me->arch.plt_offset +
-                                       me->arch.plt_size - PLT_ENTRY_SIZE;
-                               insn[2] = 0xa7f40000 +  /* j __jump_r1 */
-                                       (unsigned int)(u16)
-                                       (((unsigned long) ij - 8 -
-                                         (unsigned long) ip) / 2);
+                               char *jump_r1;
+
+                               jump_r1 = plt_base + me->arch.plt_size -
+                                       PLT_ENTRY_SIZE;
+                               /* brcl 0xf,__jump_r1 */
+                               *(short *)&insn[8] = 0xc0f4;
+                               *(int *)&insn[10] = (jump_r1 - (ip + 8)) / 2;
                        } else {
-                               insn[2] = 0x07f10000;   /* br %r1 */
+                               *(int *)&insn[8] = 0x07f10000;  /* br %r1 */
                        }
-                       insn[3] = (unsigned int) (val >> 32);
-                       insn[4] = (unsigned int) val;
+                       *(long *)&insn[14] = val;
 
                        write(ip, insn, sizeof(insn));
                        info->plt_initialized = 1;
index 0c9e894..651a519 100644 (file)
@@ -264,7 +264,14 @@ static int notrace s390_validate_registers(union mci mci, int umode)
                /* Validate vector registers */
                union ctlreg0 cr0;
 
-               if (!mci.vr) {
+               /*
+                * The vector validity must only be checked if not running a
+                * KVM guest. For KVM guests the machine check is forwarded by
+                * KVM and it is the responsibility of the guest to take
+                * appropriate actions. The host vector or FPU values have been
+                * saved by KVM and will be restored by KVM.
+                */
+               if (!mci.vr && !test_cpu_flag(CIF_MCCK_GUEST)) {
                        /*
                         * Vector registers can't be restored. If the kernel
                         * currently uses vector registers the system is
@@ -307,11 +314,21 @@ static int notrace s390_validate_registers(union mci mci, int umode)
        if (cr2.gse) {
                if (!mci.gs) {
                        /*
-                        * Guarded storage register can't be restored and
-                        * the current processes uses guarded storage.
-                        * It has to be terminated.
+                        * 2 cases:
+                        * - machine check in kernel or userspace
+                        * - machine check while running SIE (KVM guest)
+                        * For kernel or userspace the userspace values of
+                        * guarded storage control can not be recreated, the
+                        * process must be terminated.
+                        * For SIE the guest values of guarded storage can not
+                        * be recreated. This is either due to a bug or due to
+                        * GS being disabled in the guest. The guest will be
+                        * notified by KVM code and the guests machine check
+                        * handling must take care of this.  The host values
+                        * are saved by KVM and are not affected.
                         */
-                       kill_task = 1;
+                       if (!test_cpu_flag(CIF_MCCK_GUEST))
+                               kill_task = 1;
                } else {
                        load_gs_cb((struct gs_cb *)mcesa->guarded_storage_save_area);
                }
index 577f1ea..2296b1f 100644 (file)
@@ -4667,6 +4667,8 @@ static long kvm_s390_guest_sida_op(struct kvm_vcpu *vcpu,
                return -EINVAL;
        if (mop->size + mop->sida_offset > sida_size(vcpu->arch.sie_block))
                return -E2BIG;
+       if (!kvm_s390_pv_cpu_is_protected(vcpu))
+               return -EINVAL;
 
        switch (mop->op) {
        case KVM_S390_MEMOP_SIDA_READ:
index 707cd46..69feb8e 100644 (file)
@@ -17,4 +17,7 @@ KASAN_SANITIZE_uaccess.o := n
 obj-$(CONFIG_S390_UNWIND_SELFTEST) += test_unwind.o
 CFLAGS_test_unwind.o += -fno-optimize-sibling-calls
 
+obj-$(CONFIG_S390_MODULES_SANITY_TEST) += test_modules.o
+obj-$(CONFIG_S390_MODULES_SANITY_TEST_HELPERS) += test_modules_helpers.o
+
 lib-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
diff --git a/arch/s390/lib/test_modules.c b/arch/s390/lib/test_modules.c
new file mode 100644 (file)
index 0000000..9894009
--- /dev/null
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <kunit/test.h>
+#include <linux/module.h>
+
+#include "test_modules.h"
+
+/*
+ * Test that modules with many relocations are loaded properly.
+ */
+static void test_modules_many_vmlinux_relocs(struct kunit *test)
+{
+       int result = 0;
+
+#define CALL_RETURN(i) result += test_modules_return_ ## i()
+       REPEAT_10000(CALL_RETURN);
+       KUNIT_ASSERT_EQ(test, result, 49995000);
+}
+
+static struct kunit_case modules_testcases[] = {
+       KUNIT_CASE(test_modules_many_vmlinux_relocs),
+       {}
+};
+
+static struct kunit_suite modules_test_suite = {
+       .name = "modules_test_s390",
+       .test_cases = modules_testcases,
+};
+
+kunit_test_suites(&modules_test_suite);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/s390/lib/test_modules.h b/arch/s390/lib/test_modules.h
new file mode 100644 (file)
index 0000000..6371fcf
--- /dev/null
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef TEST_MODULES_H
+#define TEST_MODULES_H
+
+#define __REPEAT_10000_3(f, x) \
+       f(x ## 0); \
+       f(x ## 1); \
+       f(x ## 2); \
+       f(x ## 3); \
+       f(x ## 4); \
+       f(x ## 5); \
+       f(x ## 6); \
+       f(x ## 7); \
+       f(x ## 8); \
+       f(x ## 9)
+#define __REPEAT_10000_2(f, x) \
+       __REPEAT_10000_3(f, x ## 0); \
+       __REPEAT_10000_3(f, x ## 1); \
+       __REPEAT_10000_3(f, x ## 2); \
+       __REPEAT_10000_3(f, x ## 3); \
+       __REPEAT_10000_3(f, x ## 4); \
+       __REPEAT_10000_3(f, x ## 5); \
+       __REPEAT_10000_3(f, x ## 6); \
+       __REPEAT_10000_3(f, x ## 7); \
+       __REPEAT_10000_3(f, x ## 8); \
+       __REPEAT_10000_3(f, x ## 9)
+#define __REPEAT_10000_1(f, x) \
+       __REPEAT_10000_2(f, x ## 0); \
+       __REPEAT_10000_2(f, x ## 1); \
+       __REPEAT_10000_2(f, x ## 2); \
+       __REPEAT_10000_2(f, x ## 3); \
+       __REPEAT_10000_2(f, x ## 4); \
+       __REPEAT_10000_2(f, x ## 5); \
+       __REPEAT_10000_2(f, x ## 6); \
+       __REPEAT_10000_2(f, x ## 7); \
+       __REPEAT_10000_2(f, x ## 8); \
+       __REPEAT_10000_2(f, x ## 9)
+#define REPEAT_10000(f) \
+       __REPEAT_10000_1(f, 0); \
+       __REPEAT_10000_1(f, 1); \
+       __REPEAT_10000_1(f, 2); \
+       __REPEAT_10000_1(f, 3); \
+       __REPEAT_10000_1(f, 4); \
+       __REPEAT_10000_1(f, 5); \
+       __REPEAT_10000_1(f, 6); \
+       __REPEAT_10000_1(f, 7); \
+       __REPEAT_10000_1(f, 8); \
+       __REPEAT_10000_1(f, 9)
+
+#define DECLARE_RETURN(i) int test_modules_return_ ## i(void)
+REPEAT_10000(DECLARE_RETURN);
+
+#endif
diff --git a/arch/s390/lib/test_modules_helpers.c b/arch/s390/lib/test_modules_helpers.c
new file mode 100644 (file)
index 0000000..1670349
--- /dev/null
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/export.h>
+
+#include "test_modules.h"
+
+#define DEFINE_RETURN(i) \
+       int test_modules_return_ ## i(void) \
+       { \
+               return 1 ## i - 10000; \
+       } \
+       EXPORT_SYMBOL_GPL(test_modules_return_ ## i)
+REPEAT_10000(DEFINE_RETURN);
index ebe8fc7..9f5bd41 100644 (file)
@@ -186,6 +186,7 @@ config X86
        select HAVE_CONTEXT_TRACKING_OFFSTACK   if HAVE_CONTEXT_TRACKING
        select HAVE_C_RECORDMCOUNT
        select HAVE_OBJTOOL_MCOUNT              if STACK_VALIDATION
+       select HAVE_BUILDTIME_MCOUNT_SORT
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DMA_CONTIGUOUS
        select HAVE_DYNAMIC_FTRACE
index f9e2fec..59ae28a 100644 (file)
 static int crypto_blake2s_update_x86(struct shash_desc *desc,
                                     const u8 *in, unsigned int inlen)
 {
-       return crypto_blake2s_update(desc, in, inlen, blake2s_compress);
+       return crypto_blake2s_update(desc, in, inlen, false);
 }
 
 static int crypto_blake2s_final_x86(struct shash_desc *desc, u8 *out)
 {
-       return crypto_blake2s_final(desc, out, blake2s_compress);
+       return crypto_blake2s_final(desc, out, false);
 }
 
 #define BLAKE2S_ALG(name, driver_name, digest_size)                    \
index fd9f908..a3c7ca8 100644 (file)
@@ -4703,6 +4703,19 @@ static __initconst const struct x86_pmu intel_pmu = {
        .lbr_read               = intel_pmu_lbr_read_64,
        .lbr_save               = intel_pmu_lbr_save,
        .lbr_restore            = intel_pmu_lbr_restore,
+
+       /*
+        * SMM has access to all 4 rings and while traditionally SMM code only
+        * ran in CPL0, 2021-era firmware is starting to make use of CPL3 in SMM.
+        *
+        * Since the EVENTSEL.{USR,OS} CPL filtering makes no distinction
+        * between SMM or not, this results in what should be pure userspace
+        * counters including SMM data.
+        *
+        * This is a clear privilege issue, therefore globally disable
+        * counting SMM by default.
+        */
+       .attr_freeze_on_smi     = 1,
 };
 
 static __init void intel_clovertown_quirk(void)
@@ -6236,6 +6249,19 @@ __init int intel_pmu_init(void)
                        pmu->num_counters = x86_pmu.num_counters;
                        pmu->num_counters_fixed = x86_pmu.num_counters_fixed;
                }
+
+               /*
+                * Quirk: For some Alder Lake machine, when all E-cores are disabled in
+                * a BIOS, the leaf 0xA will enumerate all counters of P-cores. However,
+                * the X86_FEATURE_HYBRID_CPU is still set. The above codes will
+                * mistakenly add extra counters for P-cores. Correct the number of
+                * counters here.
+                */
+               if ((pmu->num_counters > 8) || (pmu->num_counters_fixed > 4)) {
+                       pmu->num_counters = x86_pmu.num_counters;
+                       pmu->num_counters_fixed = x86_pmu.num_counters_fixed;
+               }
+
                pmu->max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, pmu->num_counters);
                pmu->unconstrained = (struct event_constraint)
                                        __EVENT_CONSTRAINT(0, (1ULL << pmu->num_counters) - 1,
@@ -6340,6 +6366,8 @@ __init int intel_pmu_init(void)
        }
 
        if (x86_pmu.lbr_nr) {
+               intel_pmu_lbr_init();
+
                pr_cont("%d-deep LBR, ", x86_pmu.lbr_nr);
 
                /* only support branch_stack snapshot for perfmon >= v2 */
index 8043213..669c2be 100644 (file)
@@ -8,14 +8,6 @@
 
 #include "../perf_event.h"
 
-static const enum {
-       LBR_EIP_FLAGS           = 1,
-       LBR_TSX                 = 2,
-} lbr_desc[LBR_FORMAT_MAX_KNOWN + 1] = {
-       [LBR_FORMAT_EIP_FLAGS]  = LBR_EIP_FLAGS,
-       [LBR_FORMAT_EIP_FLAGS2] = LBR_EIP_FLAGS | LBR_TSX,
-};
-
 /*
  * Intel LBR_SELECT bits
  * Intel Vol3a, April 2011, Section 16.7 Table 16-10
@@ -243,7 +235,7 @@ void intel_pmu_lbr_reset_64(void)
        for (i = 0; i < x86_pmu.lbr_nr; i++) {
                wrmsrl(x86_pmu.lbr_from + i, 0);
                wrmsrl(x86_pmu.lbr_to   + i, 0);
-               if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
+               if (x86_pmu.lbr_has_info)
                        wrmsrl(x86_pmu.lbr_info + i, 0);
        }
 }
@@ -305,11 +297,10 @@ enum {
  */
 static inline bool lbr_from_signext_quirk_needed(void)
 {
-       int lbr_format = x86_pmu.intel_cap.lbr_format;
        bool tsx_support = boot_cpu_has(X86_FEATURE_HLE) ||
                           boot_cpu_has(X86_FEATURE_RTM);
 
-       return !tsx_support && (lbr_desc[lbr_format] & LBR_TSX);
+       return !tsx_support && x86_pmu.lbr_has_tsx;
 }
 
 static DEFINE_STATIC_KEY_FALSE(lbr_from_quirk_key);
@@ -427,12 +418,12 @@ rdlbr_all(struct lbr_entry *lbr, unsigned int idx, bool need_info)
 
 void intel_pmu_lbr_restore(void *ctx)
 {
-       bool need_info = x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO;
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
        struct x86_perf_task_context *task_ctx = ctx;
-       int i;
-       unsigned lbr_idx, mask;
+       bool need_info = x86_pmu.lbr_has_info;
        u64 tos = task_ctx->tos;
+       unsigned lbr_idx, mask;
+       int i;
 
        mask = x86_pmu.lbr_nr - 1;
        for (i = 0; i < task_ctx->valid_lbrs; i++) {
@@ -444,7 +435,7 @@ void intel_pmu_lbr_restore(void *ctx)
                lbr_idx = (tos - i) & mask;
                wrlbr_from(lbr_idx, 0);
                wrlbr_to(lbr_idx, 0);
-               if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
+               if (need_info)
                        wrlbr_info(lbr_idx, 0);
        }
 
@@ -519,9 +510,9 @@ static void __intel_pmu_lbr_restore(void *ctx)
 
 void intel_pmu_lbr_save(void *ctx)
 {
-       bool need_info = x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO;
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
        struct x86_perf_task_context *task_ctx = ctx;
+       bool need_info = x86_pmu.lbr_has_info;
        unsigned lbr_idx, mask;
        u64 tos;
        int i;
@@ -816,7 +807,6 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
 {
        bool need_info = false, call_stack = false;
        unsigned long mask = x86_pmu.lbr_nr - 1;
-       int lbr_format = x86_pmu.intel_cap.lbr_format;
        u64 tos = intel_pmu_lbr_tos();
        int i;
        int out = 0;
@@ -831,9 +821,7 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
        for (i = 0; i < num; i++) {
                unsigned long lbr_idx = (tos - i) & mask;
                u64 from, to, mis = 0, pred = 0, in_tx = 0, abort = 0;
-               int skip = 0;
                u16 cycles = 0;
-               int lbr_flags = lbr_desc[lbr_format];
 
                from = rdlbr_from(lbr_idx, NULL);
                to   = rdlbr_to(lbr_idx, NULL);
@@ -845,37 +833,39 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
                if (call_stack && !from)
                        break;
 
-               if (lbr_format == LBR_FORMAT_INFO && need_info) {
-                       u64 info;
-
-                       info = rdlbr_info(lbr_idx, NULL);
-                       mis = !!(info & LBR_INFO_MISPRED);
-                       pred = !mis;
-                       in_tx = !!(info & LBR_INFO_IN_TX);
-                       abort = !!(info & LBR_INFO_ABORT);
-                       cycles = (info & LBR_INFO_CYCLES);
-               }
-
-               if (lbr_format == LBR_FORMAT_TIME) {
-                       mis = !!(from & LBR_FROM_FLAG_MISPRED);
-                       pred = !mis;
-                       skip = 1;
-                       cycles = ((to >> 48) & LBR_INFO_CYCLES);
-
-                       to = (u64)((((s64)to) << 16) >> 16);
-               }
-
-               if (lbr_flags & LBR_EIP_FLAGS) {
-                       mis = !!(from & LBR_FROM_FLAG_MISPRED);
-                       pred = !mis;
-                       skip = 1;
-               }
-               if (lbr_flags & LBR_TSX) {
-                       in_tx = !!(from & LBR_FROM_FLAG_IN_TX);
-                       abort = !!(from & LBR_FROM_FLAG_ABORT);
-                       skip = 3;
+               if (x86_pmu.lbr_has_info) {
+                       if (need_info) {
+                               u64 info;
+
+                               info = rdlbr_info(lbr_idx, NULL);
+                               mis = !!(info & LBR_INFO_MISPRED);
+                               pred = !mis;
+                               cycles = (info & LBR_INFO_CYCLES);
+                               if (x86_pmu.lbr_has_tsx) {
+                                       in_tx = !!(info & LBR_INFO_IN_TX);
+                                       abort = !!(info & LBR_INFO_ABORT);
+                               }
+                       }
+               } else {
+                       int skip = 0;
+
+                       if (x86_pmu.lbr_from_flags) {
+                               mis = !!(from & LBR_FROM_FLAG_MISPRED);
+                               pred = !mis;
+                               skip = 1;
+                       }
+                       if (x86_pmu.lbr_has_tsx) {
+                               in_tx = !!(from & LBR_FROM_FLAG_IN_TX);
+                               abort = !!(from & LBR_FROM_FLAG_ABORT);
+                               skip = 3;
+                       }
+                       from = (u64)((((s64)from) << skip) >> skip);
+
+                       if (x86_pmu.lbr_to_cycles) {
+                               cycles = ((to >> 48) & LBR_INFO_CYCLES);
+                               to = (u64)((((s64)to) << 16) >> 16);
+                       }
                }
-               from = (u64)((((s64)from) << skip) >> skip);
 
                /*
                 * Some CPUs report duplicated abort records,
@@ -903,37 +893,40 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
        cpuc->lbr_stack.hw_idx = tos;
 }
 
+static DEFINE_STATIC_KEY_FALSE(x86_lbr_mispred);
+static DEFINE_STATIC_KEY_FALSE(x86_lbr_cycles);
+static DEFINE_STATIC_KEY_FALSE(x86_lbr_type);
+
 static __always_inline int get_lbr_br_type(u64 info)
 {
-       if (!static_cpu_has(X86_FEATURE_ARCH_LBR) || !x86_pmu.lbr_br_type)
-               return 0;
+       int type = 0;
 
-       return (info & LBR_INFO_BR_TYPE) >> LBR_INFO_BR_TYPE_OFFSET;
+       if (static_branch_likely(&x86_lbr_type))
+               type = (info & LBR_INFO_BR_TYPE) >> LBR_INFO_BR_TYPE_OFFSET;
+
+       return type;
 }
 
 static __always_inline bool get_lbr_mispred(u64 info)
 {
-       if (static_cpu_has(X86_FEATURE_ARCH_LBR) && !x86_pmu.lbr_mispred)
-               return 0;
+       bool mispred = 0;
 
-       return !!(info & LBR_INFO_MISPRED);
-}
+       if (static_branch_likely(&x86_lbr_mispred))
+               mispred = !!(info & LBR_INFO_MISPRED);
 
-static __always_inline bool get_lbr_predicted(u64 info)
-{
-       if (static_cpu_has(X86_FEATURE_ARCH_LBR) && !x86_pmu.lbr_mispred)
-               return 0;
-
-       return !(info & LBR_INFO_MISPRED);
+       return mispred;
 }
 
 static __always_inline u16 get_lbr_cycles(u64 info)
 {
+       u16 cycles = info & LBR_INFO_CYCLES;
+
        if (static_cpu_has(X86_FEATURE_ARCH_LBR) &&
-           !(x86_pmu.lbr_timed_lbr && info & LBR_INFO_CYC_CNT_VALID))
-               return 0;
+           (!static_branch_likely(&x86_lbr_cycles) ||
+            !(info & LBR_INFO_CYC_CNT_VALID)))
+               cycles = 0;
 
-       return info & LBR_INFO_CYCLES;
+       return cycles;
 }
 
 static void intel_pmu_store_lbr(struct cpu_hw_events *cpuc,
@@ -961,7 +954,7 @@ static void intel_pmu_store_lbr(struct cpu_hw_events *cpuc,
                e->from         = from;
                e->to           = to;
                e->mispred      = get_lbr_mispred(info);
-               e->predicted    = get_lbr_predicted(info);
+               e->predicted    = !e->mispred;
                e->in_tx        = !!(info & LBR_INFO_IN_TX);
                e->abort        = !!(info & LBR_INFO_ABORT);
                e->cycles       = get_lbr_cycles(info);
@@ -1120,7 +1113,7 @@ static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event)
 
        if ((br_type & PERF_SAMPLE_BRANCH_NO_CYCLES) &&
            (br_type & PERF_SAMPLE_BRANCH_NO_FLAGS) &&
-           (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO))
+           x86_pmu.lbr_has_info)
                reg->config |= LBR_NO_INFO;
 
        return 0;
@@ -1706,6 +1699,38 @@ void intel_pmu_lbr_init_knl(void)
                x86_pmu.intel_cap.lbr_format = LBR_FORMAT_EIP_FLAGS;
 }
 
+void intel_pmu_lbr_init(void)
+{
+       switch (x86_pmu.intel_cap.lbr_format) {
+       case LBR_FORMAT_EIP_FLAGS2:
+               x86_pmu.lbr_has_tsx = 1;
+               fallthrough;
+       case LBR_FORMAT_EIP_FLAGS:
+               x86_pmu.lbr_from_flags = 1;
+               break;
+
+       case LBR_FORMAT_INFO:
+               x86_pmu.lbr_has_tsx = 1;
+               fallthrough;
+       case LBR_FORMAT_INFO2:
+               x86_pmu.lbr_has_info = 1;
+               break;
+
+       case LBR_FORMAT_TIME:
+               x86_pmu.lbr_from_flags = 1;
+               x86_pmu.lbr_to_cycles = 1;
+               break;
+       }
+
+       if (x86_pmu.lbr_has_info) {
+               /*
+                * Only used in combination with baseline pebs.
+                */
+               static_branch_enable(&x86_lbr_mispred);
+               static_branch_enable(&x86_lbr_cycles);
+       }
+}
+
 /*
  * LBR state size is variable based on the max number of registers.
  * This calculates the expected state size, which should match
@@ -1726,6 +1751,9 @@ static bool is_arch_lbr_xsave_available(void)
         * Check the LBR state with the corresponding software structure.
         * Disable LBR XSAVES support if the size doesn't match.
         */
+       if (xfeature_size(XFEATURE_LBR) == 0)
+               return false;
+
        if (WARN_ON(xfeature_size(XFEATURE_LBR) != get_lbr_state_size()))
                return false;
 
@@ -1765,6 +1793,12 @@ void __init intel_pmu_arch_lbr_init(void)
        x86_pmu.lbr_br_type = ecx.split.lbr_br_type;
        x86_pmu.lbr_nr = lbr_nr;
 
+       if (x86_pmu.lbr_mispred)
+               static_branch_enable(&x86_lbr_mispred);
+       if (x86_pmu.lbr_timed_lbr)
+               static_branch_enable(&x86_lbr_cycles);
+       if (x86_pmu.lbr_br_type)
+               static_branch_enable(&x86_lbr_type);
 
        arch_lbr_xsave = is_arch_lbr_xsave_available();
        if (arch_lbr_xsave) {
index 7f406c1..2d33bba 100644 (file)
@@ -897,8 +897,9 @@ static void pt_handle_status(struct pt *pt)
                 * means we are already losing data; need to let the decoder
                 * know.
                 */
-               if (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries) ||
-                   buf->output_off == pt_buffer_region_size(buf)) {
+               if (!buf->single &&
+                   (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries) ||
+                    buf->output_off == pt_buffer_region_size(buf))) {
                        perf_aux_output_flag(&pt->handle,
                                             PERF_AUX_FLAG_TRUNCATED);
                        advance++;
index f1ba6ab..e497da9 100644 (file)
@@ -1762,7 +1762,7 @@ static const struct intel_uncore_init_fun rkl_uncore_init __initconst = {
 
 static const struct intel_uncore_init_fun adl_uncore_init __initconst = {
        .cpu_init = adl_uncore_cpu_init,
-       .mmio_init = tgl_uncore_mmio_init,
+       .mmio_init = adl_uncore_mmio_init,
 };
 
 static const struct intel_uncore_init_fun icx_uncore_init __initconst = {
index b968798..2adeaf4 100644 (file)
@@ -584,10 +584,11 @@ void snb_uncore_cpu_init(void);
 void nhm_uncore_cpu_init(void);
 void skl_uncore_cpu_init(void);
 void icl_uncore_cpu_init(void);
-void adl_uncore_cpu_init(void);
 void tgl_uncore_cpu_init(void);
+void adl_uncore_cpu_init(void);
 void tgl_uncore_mmio_init(void);
 void tgl_l_uncore_mmio_init(void);
+void adl_uncore_mmio_init(void);
 int snb_pci2phy_map_init(int devid);
 
 /* uncore_snbep.c */
index 3049c64..6ddadb4 100644 (file)
@@ -494,8 +494,8 @@ void intel_generic_uncore_mmio_enable_box(struct intel_uncore_box *box)
        writel(0, box->io_addr);
 }
 
-static void intel_generic_uncore_mmio_enable_event(struct intel_uncore_box *box,
-                                            struct perf_event *event)
+void intel_generic_uncore_mmio_enable_event(struct intel_uncore_box *box,
+                                           struct perf_event *event)
 {
        struct hw_perf_event *hwc = &event->hw;
 
index 6d73561..cfaf558 100644 (file)
@@ -139,6 +139,8 @@ void intel_generic_uncore_mmio_disable_box(struct intel_uncore_box *box);
 void intel_generic_uncore_mmio_enable_box(struct intel_uncore_box *box);
 void intel_generic_uncore_mmio_disable_event(struct intel_uncore_box *box,
                                             struct perf_event *event);
+void intel_generic_uncore_mmio_enable_event(struct intel_uncore_box *box,
+                                           struct perf_event *event);
 
 void intel_generic_uncore_pci_init_box(struct intel_uncore_box *box);
 void intel_generic_uncore_pci_disable_box(struct intel_uncore_box *box);
index 0f63706..f698a55 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Nehalem/SandBridge/Haswell/Broadwell/Skylake uncore support */
 #include "uncore.h"
+#include "uncore_discovery.h"
 
 /* Uncore IMC PCI IDs */
 #define PCI_DEVICE_ID_INTEL_SNB_IMC            0x0100
 #define PCI_DEVICE_ID_INTEL_RKL_2_IMC          0x4c53
 #define PCI_DEVICE_ID_INTEL_ADL_1_IMC          0x4660
 #define PCI_DEVICE_ID_INTEL_ADL_2_IMC          0x4641
+#define PCI_DEVICE_ID_INTEL_ADL_3_IMC          0x4601
+#define PCI_DEVICE_ID_INTEL_ADL_4_IMC          0x4602
+#define PCI_DEVICE_ID_INTEL_ADL_5_IMC          0x4609
+#define PCI_DEVICE_ID_INTEL_ADL_6_IMC          0x460a
+#define PCI_DEVICE_ID_INTEL_ADL_7_IMC          0x4621
+#define PCI_DEVICE_ID_INTEL_ADL_8_IMC          0x4623
+#define PCI_DEVICE_ID_INTEL_ADL_9_IMC          0x4629
+#define PCI_DEVICE_ID_INTEL_ADL_10_IMC         0x4637
+#define PCI_DEVICE_ID_INTEL_ADL_11_IMC         0x463b
+#define PCI_DEVICE_ID_INTEL_ADL_12_IMC         0x4648
+#define PCI_DEVICE_ID_INTEL_ADL_13_IMC         0x4649
+#define PCI_DEVICE_ID_INTEL_ADL_14_IMC         0x4650
+#define PCI_DEVICE_ID_INTEL_ADL_15_IMC         0x4668
+#define PCI_DEVICE_ID_INTEL_ADL_16_IMC         0x4670
 
 /* SNB event control */
 #define SNB_UNC_CTL_EV_SEL_MASK                        0x000000ff
 
 DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
 DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(chmask, chmask, "config:8-11");
 DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
 DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
 DEFINE_UNCORE_FORMAT_ATTR(cmask5, cmask, "config:24-28");
@@ -1334,6 +1350,62 @@ static const struct pci_device_id tgl_uncore_pci_ids[] = {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_2_IMC),
                .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
        },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_3_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_4_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_5_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_6_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_7_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_8_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_9_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_10_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_11_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_12_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_13_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_14_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_15_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_16_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
        { /* end: all zeroes */ }
 };
 
@@ -1390,7 +1462,8 @@ static struct pci_dev *tgl_uncore_get_mc_dev(void)
 #define TGL_UNCORE_MMIO_IMC_MEM_OFFSET         0x10000
 #define TGL_UNCORE_PCI_IMC_MAP_SIZE            0xe000
 
-static void tgl_uncore_imc_freerunning_init_box(struct intel_uncore_box *box)
+static void __uncore_imc_init_box(struct intel_uncore_box *box,
+                                 unsigned int base_offset)
 {
        struct pci_dev *pdev = tgl_uncore_get_mc_dev();
        struct intel_uncore_pmu *pmu = box->pmu;
@@ -1417,11 +1490,17 @@ static void tgl_uncore_imc_freerunning_init_box(struct intel_uncore_box *box)
        addr |= ((resource_size_t)mch_bar << 32);
 #endif
 
+       addr += base_offset;
        box->io_addr = ioremap(addr, type->mmio_map_size);
        if (!box->io_addr)
                pr_warn("perf uncore: Failed to ioremap for %s.\n", type->name);
 }
 
+static void tgl_uncore_imc_freerunning_init_box(struct intel_uncore_box *box)
+{
+       __uncore_imc_init_box(box, 0);
+}
+
 static struct intel_uncore_ops tgl_uncore_imc_freerunning_ops = {
        .init_box       = tgl_uncore_imc_freerunning_init_box,
        .exit_box       = uncore_mmio_exit_box,
@@ -1469,3 +1548,136 @@ void tgl_uncore_mmio_init(void)
 }
 
 /* end of Tiger Lake MMIO uncore support */
+
+/* Alder Lake MMIO uncore support */
+#define ADL_UNCORE_IMC_BASE                    0xd900
+#define ADL_UNCORE_IMC_MAP_SIZE                        0x200
+#define ADL_UNCORE_IMC_CTR                     0xe8
+#define ADL_UNCORE_IMC_CTRL                    0xd0
+#define ADL_UNCORE_IMC_GLOBAL_CTL              0xc0
+#define ADL_UNCORE_IMC_BOX_CTL                 0xc4
+#define ADL_UNCORE_IMC_FREERUNNING_BASE                0xd800
+#define ADL_UNCORE_IMC_FREERUNNING_MAP_SIZE    0x100
+
+#define ADL_UNCORE_IMC_CTL_FRZ                 (1 << 0)
+#define ADL_UNCORE_IMC_CTL_RST_CTRL            (1 << 1)
+#define ADL_UNCORE_IMC_CTL_RST_CTRS            (1 << 2)
+#define ADL_UNCORE_IMC_CTL_INT                 (ADL_UNCORE_IMC_CTL_RST_CTRL | \
+                                               ADL_UNCORE_IMC_CTL_RST_CTRS)
+
+static void adl_uncore_imc_init_box(struct intel_uncore_box *box)
+{
+       __uncore_imc_init_box(box, ADL_UNCORE_IMC_BASE);
+
+       /* The global control in MC1 can control both MCs. */
+       if (box->io_addr && (box->pmu->pmu_idx == 1))
+               writel(ADL_UNCORE_IMC_CTL_INT, box->io_addr + ADL_UNCORE_IMC_GLOBAL_CTL);
+}
+
+static void adl_uncore_mmio_disable_box(struct intel_uncore_box *box)
+{
+       if (!box->io_addr)
+               return;
+
+       writel(ADL_UNCORE_IMC_CTL_FRZ, box->io_addr + uncore_mmio_box_ctl(box));
+}
+
+static void adl_uncore_mmio_enable_box(struct intel_uncore_box *box)
+{
+       if (!box->io_addr)
+               return;
+
+       writel(0, box->io_addr + uncore_mmio_box_ctl(box));
+}
+
+static struct intel_uncore_ops adl_uncore_mmio_ops = {
+       .init_box       = adl_uncore_imc_init_box,
+       .exit_box       = uncore_mmio_exit_box,
+       .disable_box    = adl_uncore_mmio_disable_box,
+       .enable_box     = adl_uncore_mmio_enable_box,
+       .disable_event  = intel_generic_uncore_mmio_disable_event,
+       .enable_event   = intel_generic_uncore_mmio_enable_event,
+       .read_counter   = uncore_mmio_read_counter,
+};
+
+#define ADL_UNC_CTL_CHMASK_MASK                        0x00000f00
+#define ADL_UNC_IMC_EVENT_MASK                 (SNB_UNC_CTL_EV_SEL_MASK | \
+                                                ADL_UNC_CTL_CHMASK_MASK | \
+                                                SNB_UNC_CTL_EDGE_DET)
+
+static struct attribute *adl_uncore_imc_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_chmask.attr,
+       &format_attr_edge.attr,
+       NULL,
+};
+
+static const struct attribute_group adl_uncore_imc_format_group = {
+       .name           = "format",
+       .attrs          = adl_uncore_imc_formats_attr,
+};
+
+static struct intel_uncore_type adl_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 5,
+       .num_boxes      = 2,
+       .perf_ctr_bits  = 64,
+       .perf_ctr       = ADL_UNCORE_IMC_CTR,
+       .event_ctl      = ADL_UNCORE_IMC_CTRL,
+       .event_mask     = ADL_UNC_IMC_EVENT_MASK,
+       .box_ctl        = ADL_UNCORE_IMC_BOX_CTL,
+       .mmio_offset    = 0,
+       .mmio_map_size  = ADL_UNCORE_IMC_MAP_SIZE,
+       .ops            = &adl_uncore_mmio_ops,
+       .format_group   = &adl_uncore_imc_format_group,
+};
+
+enum perf_adl_uncore_imc_freerunning_types {
+       ADL_MMIO_UNCORE_IMC_DATA_TOTAL,
+       ADL_MMIO_UNCORE_IMC_DATA_READ,
+       ADL_MMIO_UNCORE_IMC_DATA_WRITE,
+       ADL_MMIO_UNCORE_IMC_FREERUNNING_TYPE_MAX
+};
+
+static struct freerunning_counters adl_uncore_imc_freerunning[] = {
+       [ADL_MMIO_UNCORE_IMC_DATA_TOTAL]        = { 0x40, 0x0, 0x0, 1, 64 },
+       [ADL_MMIO_UNCORE_IMC_DATA_READ]         = { 0x58, 0x0, 0x0, 1, 64 },
+       [ADL_MMIO_UNCORE_IMC_DATA_WRITE]        = { 0xA0, 0x0, 0x0, 1, 64 },
+};
+
+static void adl_uncore_imc_freerunning_init_box(struct intel_uncore_box *box)
+{
+       __uncore_imc_init_box(box, ADL_UNCORE_IMC_FREERUNNING_BASE);
+}
+
+static struct intel_uncore_ops adl_uncore_imc_freerunning_ops = {
+       .init_box       = adl_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 adl_uncore_imc_free_running = {
+       .name                   = "imc_free_running",
+       .num_counters           = 3,
+       .num_boxes              = 2,
+       .num_freerunning_types  = ADL_MMIO_UNCORE_IMC_FREERUNNING_TYPE_MAX,
+       .mmio_map_size          = ADL_UNCORE_IMC_FREERUNNING_MAP_SIZE,
+       .freerunning            = adl_uncore_imc_freerunning,
+       .ops                    = &adl_uncore_imc_freerunning_ops,
+       .event_descs            = tgl_uncore_imc_events,
+       .format_group           = &tgl_uncore_imc_format_group,
+};
+
+static struct intel_uncore_type *adl_mmio_uncores[] = {
+       &adl_uncore_imc,
+       &adl_uncore_imc_free_running,
+       NULL
+};
+
+void adl_uncore_mmio_init(void)
+{
+       uncore_mmio_uncores = adl_mmio_uncores;
+}
+
+/* end of Alder Lake MMIO uncore support */
index 3660f69..ed86944 100644 (file)
@@ -5482,7 +5482,7 @@ static struct intel_uncore_type icx_uncore_imc = {
        .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,
+       .event_descs    = snr_uncore_imc_events,
        .perf_ctr       = SNR_IMC_MMIO_PMON_CTR0,
        .event_ctl      = SNR_IMC_MMIO_PMON_CTL0,
        .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,
index 9d376e5..150261d 100644 (file)
@@ -215,7 +215,8 @@ enum {
        LBR_FORMAT_EIP_FLAGS2   = 0x04,
        LBR_FORMAT_INFO         = 0x05,
        LBR_FORMAT_TIME         = 0x06,
-       LBR_FORMAT_MAX_KNOWN    = LBR_FORMAT_TIME,
+       LBR_FORMAT_INFO2        = 0x07,
+       LBR_FORMAT_MAX_KNOWN    = LBR_FORMAT_INFO2,
 };
 
 enum {
@@ -840,6 +841,11 @@ struct x86_pmu {
        bool            lbr_double_abort;          /* duplicated lbr aborts */
        bool            lbr_pt_coexist;            /* (LBR|BTS) may coexist with PT */
 
+       unsigned int    lbr_has_info:1;
+       unsigned int    lbr_has_tsx:1;
+       unsigned int    lbr_from_flags:1;
+       unsigned int    lbr_to_cycles:1;
+
        /*
         * Intel Architectural LBR CPUID Enumeration
         */
@@ -1392,6 +1398,8 @@ void intel_pmu_lbr_init_skl(void);
 
 void intel_pmu_lbr_init_knl(void);
 
+void intel_pmu_lbr_init(void);
+
 void intel_pmu_arch_lbr_init(void);
 
 void intel_pmu_pebs_data_source_nhm(void);
index 85feafa..77e3a47 100644 (file)
@@ -536,11 +536,14 @@ static struct perf_msr intel_rapl_spr_msrs[] = {
  * - perf_msr_probe(PERF_RAPL_MAX)
  * - want to use same event codes across both architectures
  */
-static struct perf_msr amd_rapl_msrs[PERF_RAPL_MAX] = {
-       [PERF_RAPL_PKG]  = { MSR_AMD_PKG_ENERGY_STATUS,  &rapl_events_pkg_group,   test_msr },
+static struct perf_msr amd_rapl_msrs[] = {
+       [PERF_RAPL_PP0]  = { 0, &rapl_events_cores_group, 0, false, 0 },
+       [PERF_RAPL_PKG]  = { MSR_AMD_PKG_ENERGY_STATUS,  &rapl_events_pkg_group,   test_msr, false, RAPL_MSR_MASK },
+       [PERF_RAPL_RAM]  = { 0, &rapl_events_ram_group,   0, false, 0 },
+       [PERF_RAPL_PP1]  = { 0, &rapl_events_gpu_group,   0, false, 0 },
+       [PERF_RAPL_PSYS] = { 0, &rapl_events_psys_group,  0, false, 0 },
 };
 
-
 static int rapl_cpu_offline(unsigned int cpu)
 {
        struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
index 84b8753..bab883c 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 
-#define _BUG_FLAGS(ins, flags)                                         \
+#define _BUG_FLAGS(ins, flags, extra)                                  \
 do {                                                                   \
        asm_inline volatile("1:\t" ins "\n"                             \
                     ".pushsection __bug_table,\"aw\"\n"                \
@@ -31,7 +31,8 @@ do {                                                                  \
                     "\t.word %c1"        "\t# bug_entry::line\n"       \
                     "\t.word %c2"        "\t# bug_entry::flags\n"      \
                     "\t.org 2b+%c3\n"                                  \
-                    ".popsection"                                      \
+                    ".popsection\n"                                    \
+                    extra                                              \
                     : : "i" (__FILE__), "i" (__LINE__),                \
                         "i" (flags),                                   \
                         "i" (sizeof(struct bug_entry)));               \
@@ -39,14 +40,15 @@ do {                                                                        \
 
 #else /* !CONFIG_DEBUG_BUGVERBOSE */
 
-#define _BUG_FLAGS(ins, flags)                                         \
+#define _BUG_FLAGS(ins, flags, extra)                                  \
 do {                                                                   \
        asm_inline volatile("1:\t" ins "\n"                             \
                     ".pushsection __bug_table,\"aw\"\n"                \
                     "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n"   \
                     "\t.word %c0"        "\t# bug_entry::flags\n"      \
                     "\t.org 2b+%c1\n"                                  \
-                    ".popsection"                                      \
+                    ".popsection\n"                                    \
+                    extra                                              \
                     : : "i" (flags),                                   \
                         "i" (sizeof(struct bug_entry)));               \
 } while (0)
@@ -55,7 +57,7 @@ do {                                                                  \
 
 #else
 
-#define _BUG_FLAGS(ins, flags)  asm volatile(ins)
+#define _BUG_FLAGS(ins, flags, extra)  asm volatile(ins)
 
 #endif /* CONFIG_GENERIC_BUG */
 
@@ -63,8 +65,8 @@ do {                                                                  \
 #define BUG()                                                  \
 do {                                                           \
        instrumentation_begin();                                \
-       _BUG_FLAGS(ASM_UD2, 0);                                 \
-       unreachable();                                          \
+       _BUG_FLAGS(ASM_UD2, 0, "");                             \
+       __builtin_unreachable();                                \
 } while (0)
 
 /*
@@ -75,9 +77,9 @@ do {                                                          \
  */
 #define __WARN_FLAGS(flags)                                    \
 do {                                                           \
+       __auto_type f = BUGFLAG_WARNING|(flags);                \
        instrumentation_begin();                                \
-       _BUG_FLAGS(ASM_UD2, BUGFLAG_WARNING|(flags));           \
-       annotate_reachable();                                   \
+       _BUG_FLAGS(ASM_UD2, f, ASM_REACHABLE);                  \
        instrumentation_end();                                  \
 } while (0)
 
index 631d504..d39e0de 100644 (file)
@@ -82,7 +82,7 @@ KVM_X86_OP_NULL(guest_apic_has_interrupt)
 KVM_X86_OP(load_eoi_exitmap)
 KVM_X86_OP(set_virtual_apic_mode)
 KVM_X86_OP_NULL(set_apic_access_page_addr)
-KVM_X86_OP(deliver_posted_interrupt)
+KVM_X86_OP(deliver_interrupt)
 KVM_X86_OP_NULL(sync_pir_to_irr)
 KVM_X86_OP(set_tss_addr)
 KVM_X86_OP(set_identity_map_addr)
index 1384517..6dcccb3 100644 (file)
@@ -1410,7 +1410,8 @@ struct kvm_x86_ops {
        void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
        void (*set_virtual_apic_mode)(struct kvm_vcpu *vcpu);
        void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu);
-       int (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector);
+       void (*deliver_interrupt)(struct kvm_lapic *apic, int delivery_mode,
+                                 int trig_mode, int vector);
        int (*sync_pir_to_irr)(struct kvm_vcpu *vcpu);
        int (*set_tss_addr)(struct kvm *kvm, unsigned int addr);
        int (*set_identity_map_addr)(struct kvm *kvm, u64 ident_addr);
@@ -1483,7 +1484,8 @@ struct kvm_x86_ops {
 
        int (*get_msr_feature)(struct kvm_msr_entry *entry);
 
-       bool (*can_emulate_instruction)(struct kvm_vcpu *vcpu, void *insn, int insn_len);
+       bool (*can_emulate_instruction)(struct kvm_vcpu *vcpu, int emul_type,
+                                       void *insn, int insn_len);
 
        bool (*apic_init_signal_blocked)(struct kvm_vcpu *vcpu);
        int (*enable_direct_tlbflush)(struct kvm_vcpu *vcpu);
@@ -1496,6 +1498,7 @@ struct kvm_x86_ops {
 };
 
 struct kvm_x86_nested_ops {
+       void (*leave_nested)(struct kvm_vcpu *vcpu);
        int (*check_events)(struct kvm_vcpu *vcpu);
        bool (*hv_timer_pending)(struct kvm_vcpu *vcpu);
        void (*triple_fault)(struct kvm_vcpu *vcpu);
@@ -1861,7 +1864,6 @@ int kvm_cpu_has_extint(struct kvm_vcpu *v);
 int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu);
 int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
 void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event);
-void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu);
 
 int kvm_pv_send_ipi(struct kvm *kvm, unsigned long ipi_bitmap_low,
                    unsigned long ipi_bitmap_high, u32 min,
index a963010..78e667a 100644 (file)
 /* Memory mapped from other domains has valid IOMMU entries */
 #define XEN_HVM_CPUID_IOMMU_MAPPINGS   (1u << 2)
 #define XEN_HVM_CPUID_VCPU_ID_PRESENT  (1u << 3) /* vcpu id is present in EBX */
+#define XEN_HVM_CPUID_DOMID_PRESENT    (1u << 4) /* domid is present in ECX */
+/*
+ * Bits 55:49 from the IO-APIC RTE and bits 11:5 from the MSI address can be
+ * used to store high bits for the Destination ID. This expands the Destination
+ * ID field from 8 to 15 bits, allowing to target APIC IDs up 32768.
+ */
+#define XEN_HVM_CPUID_EXT_DEST_ID      (1u << 5)
 
 /*
  * Leaf 6 (0x40000x05)
index 1bf2ad3..16f548a 100644 (file)
@@ -43,20 +43,6 @@ static inline uint32_t xen_cpuid_base(void)
        return hypervisor_cpuid_base("XenVMMXenVMM", 2);
 }
 
-#ifdef CONFIG_XEN
-extern bool __init xen_hvm_need_lapic(void);
-
-static inline bool __init xen_x2apic_para_available(void)
-{
-       return xen_hvm_need_lapic();
-}
-#else
-static inline bool __init xen_x2apic_para_available(void)
-{
-       return (xen_cpuid_base() != 0);
-}
-#endif
-
 struct pci_dev;
 
 #ifdef CONFIG_XEN_PV_DOM0
index 2da3316..bf6e960 100644 (file)
@@ -452,6 +452,9 @@ struct kvm_sync_regs {
 
 #define KVM_STATE_VMX_PREEMPTION_TIMER_DEADLINE        0x00000001
 
+/* attributes for system fd (group 0) */
+#define KVM_X86_XCOMP_GUEST_SUPP       0
+
 struct kvm_vmx_nested_state_data {
        __u8 vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
        __u8 shadow_vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
index a1e2f41..9f4b508 100644 (file)
@@ -423,7 +423,7 @@ static void threshold_restart_bank(void *_tr)
        u32 hi, lo;
 
        /* sysfs write might race against an offline operation */
-       if (this_cpu_read(threshold_banks))
+       if (!this_cpu_read(threshold_banks) && !tr->set_lvt_off)
                return;
 
        rdmsr(tr->b->address, lo, hi);
index bb9a46a..baafbb3 100644 (file)
@@ -486,6 +486,7 @@ static void intel_ppin_init(struct cpuinfo_x86 *c)
        case INTEL_FAM6_BROADWELL_X:
        case INTEL_FAM6_SKYLAKE_X:
        case INTEL_FAM6_ICELAKE_X:
+       case INTEL_FAM6_ICELAKE_D:
        case INTEL_FAM6_SAPPHIRERAPIDS_X:
        case INTEL_FAM6_XEON_PHI_KNL:
        case INTEL_FAM6_XEON_PHI_KNM:
index 001808e..48afe96 100644 (file)
@@ -410,6 +410,8 @@ void sgx_encl_release(struct kref *ref)
                }
 
                kfree(entry);
+               /* Invoke scheduler to prevent soft lockups. */
+               cond_resched();
        }
 
        xa_destroy(&encl->page_array);
index 9ae64f9..9b9fb78 100644 (file)
@@ -1,5 +1,4 @@
 // SPDX-License-Identifier: GPL-2.0
-#include <linux/dmi.h>
 #include <linux/ioport.h>
 #include <asm/e820/api.h>
 
@@ -24,31 +23,11 @@ static void resource_clip(struct resource *res, resource_size_t start,
                res->start = end + 1;
 }
 
-/*
- * Some BIOS-es contain a bug where they add addresses which map to
- * system RAM in the PCI host bridge window returned by the ACPI _CRS
- * method, see commit 4dc2287c1805 ("x86: avoid E820 regions when
- * allocating address space"). To avoid this Linux by default excludes
- * E820 reservations when allocating addresses since 2010.
- * In 2019 some systems have shown-up with E820 reservations which cover
- * the entire _CRS returned PCI host bridge window, causing all attempts
- * to assign memory to PCI BARs to fail if Linux uses E820 reservations.
- *
- * Ideally Linux would fully stop using E820 reservations, but then
- * the old systems this was added for will regress.
- * Instead keep the old behavior for old systems, while ignoring the
- * E820 reservations for any systems from now on.
- */
 static void remove_e820_regions(struct resource *avail)
 {
-       int i, year = dmi_get_bios_year();
+       int i;
        struct e820_entry *entry;
 
-       if (year >= 2018)
-               return;
-
-       pr_info_once("PCI: Removing E820 reservations from host bridge windows\n");
-
        for (i = 0; i < e820_table->nr_entries; i++) {
                entry = &e820_table->entries[i];
 
index 3902c28..494d4d3 100644 (file)
@@ -133,6 +133,7 @@ static int kvm_cpuid_check_equal(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2
                orig = &vcpu->arch.cpuid_entries[i];
                if (e2[i].function != orig->function ||
                    e2[i].index != orig->index ||
+                   e2[i].flags != orig->flags ||
                    e2[i].eax != orig->eax || e2[i].ebx != orig->ebx ||
                    e2[i].ecx != orig->ecx || e2[i].edx != orig->edx)
                        return -EINVAL;
@@ -196,10 +197,26 @@ void kvm_update_pv_runtime(struct kvm_vcpu *vcpu)
                vcpu->arch.pv_cpuid.features = best->eax;
 }
 
+/*
+ * Calculate guest's supported XCR0 taking into account guest CPUID data and
+ * supported_xcr0 (comprised of host configuration and KVM_SUPPORTED_XCR0).
+ */
+static u64 cpuid_get_supported_xcr0(struct kvm_cpuid_entry2 *entries, int nent)
+{
+       struct kvm_cpuid_entry2 *best;
+
+       best = cpuid_entry2_find(entries, nent, 0xd, 0);
+       if (!best)
+               return 0;
+
+       return (best->eax | ((u64)best->edx << 32)) & supported_xcr0;
+}
+
 static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *entries,
                                       int nent)
 {
        struct kvm_cpuid_entry2 *best;
+       u64 guest_supported_xcr0 = cpuid_get_supported_xcr0(entries, nent);
 
        best = cpuid_entry2_find(entries, nent, 1, 0);
        if (best) {
@@ -238,6 +255,21 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e
                                           vcpu->arch.ia32_misc_enable_msr &
                                           MSR_IA32_MISC_ENABLE_MWAIT);
        }
+
+       /*
+        * Bits 127:0 of the allowed SECS.ATTRIBUTES (CPUID.0x12.0x1) enumerate
+        * the supported XSAVE Feature Request Mask (XFRM), i.e. the enclave's
+        * requested XCR0 value.  The enclave's XFRM must be a subset of XCRO
+        * at the time of EENTER, thus adjust the allowed XFRM by the guest's
+        * supported XCR0.  Similar to XCR0 handling, FP and SSE are forced to
+        * '1' even on CPUs that don't support XSAVE.
+        */
+       best = cpuid_entry2_find(entries, nent, 0x12, 0x1);
+       if (best) {
+               best->ecx &= guest_supported_xcr0 & 0xffffffff;
+               best->edx &= guest_supported_xcr0 >> 32;
+               best->ecx |= XFEATURE_MASK_FPSSE;
+       }
 }
 
 void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu)
@@ -261,27 +293,8 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
                kvm_apic_set_version(vcpu);
        }
 
-       best = kvm_find_cpuid_entry(vcpu, 0xD, 0);
-       if (!best)
-               vcpu->arch.guest_supported_xcr0 = 0;
-       else
-               vcpu->arch.guest_supported_xcr0 =
-                       (best->eax | ((u64)best->edx << 32)) & supported_xcr0;
-
-       /*
-        * Bits 127:0 of the allowed SECS.ATTRIBUTES (CPUID.0x12.0x1) enumerate
-        * the supported XSAVE Feature Request Mask (XFRM), i.e. the enclave's
-        * requested XCR0 value.  The enclave's XFRM must be a subset of XCRO
-        * at the time of EENTER, thus adjust the allowed XFRM by the guest's
-        * supported XCR0.  Similar to XCR0 handling, FP and SSE are forced to
-        * '1' even on CPUs that don't support XSAVE.
-        */
-       best = kvm_find_cpuid_entry(vcpu, 0x12, 0x1);
-       if (best) {
-               best->ecx &= vcpu->arch.guest_supported_xcr0 & 0xffffffff;
-               best->edx &= vcpu->arch.guest_supported_xcr0 >> 32;
-               best->ecx |= XFEATURE_MASK_FPSSE;
-       }
+       vcpu->arch.guest_supported_xcr0 =
+               cpuid_get_supported_xcr0(vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent);
 
        kvm_update_pv_runtime(vcpu);
 
@@ -346,8 +359,14 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
         * KVM_SET_CPUID{,2} again. To support this legacy behavior, check
         * whether the supplied CPUID data is equal to what's already set.
         */
-       if (vcpu->arch.last_vmentry_cpu != -1)
-               return kvm_cpuid_check_equal(vcpu, e2, nent);
+       if (vcpu->arch.last_vmentry_cpu != -1) {
+               r = kvm_cpuid_check_equal(vcpu, e2, nent);
+               if (r)
+                       return r;
+
+               kvfree(e2);
+               return 0;
+       }
 
        r = kvm_check_cpuid(vcpu, e2, nent);
        if (r)
@@ -535,12 +554,13 @@ void kvm_set_cpu_caps(void)
        );
 
        kvm_cpu_cap_mask(CPUID_7_0_EBX,
-               F(FSGSBASE) | F(SGX) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) |
-               F(BMI2) | F(ERMS) | F(INVPCID) | F(RTM) | 0 /*MPX*/ | F(RDSEED) |
-               F(ADX) | F(SMAP) | F(AVX512IFMA) | F(AVX512F) | F(AVX512PF) |
-               F(AVX512ER) | F(AVX512CD) | F(CLFLUSHOPT) | F(CLWB) | F(AVX512DQ) |
-               F(SHA_NI) | F(AVX512BW) | F(AVX512VL) | 0 /*INTEL_PT*/
-       );
+               F(FSGSBASE) | F(SGX) | F(BMI1) | F(HLE) | F(AVX2) |
+               F(FDP_EXCPTN_ONLY) | F(SMEP) | F(BMI2) | F(ERMS) | F(INVPCID) |
+               F(RTM) | F(ZERO_FCS_FDS) | 0 /*MPX*/ | F(AVX512F) |
+               F(AVX512DQ) | F(RDSEED) | F(ADX) | F(SMAP) | F(AVX512IFMA) |
+               F(CLFLUSHOPT) | F(CLWB) | 0 /*INTEL_PT*/ | F(AVX512PF) |
+               F(AVX512ER) | F(AVX512CD) | F(SHA_NI) | F(AVX512BW) |
+               F(AVX512VL));
 
        kvm_cpu_cap_mask(CPUID_7_ECX,
                F(AVX512VBMI) | F(LA57) | F(PKU) | 0 /*OSPKE*/ | F(RDPID) |
@@ -887,13 +907,14 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
                }
                break;
        case 0xd: {
-               u64 guest_perm = xstate_get_guest_group_perm();
+               u64 permitted_xcr0 = supported_xcr0 & xstate_get_guest_group_perm();
+               u64 permitted_xss = supported_xss;
 
-               entry->eax &= supported_xcr0 & guest_perm;
-               entry->ebx = xstate_required_size(supported_xcr0, false);
+               entry->eax &= permitted_xcr0;
+               entry->ebx = xstate_required_size(permitted_xcr0, false);
                entry->ecx = entry->ebx;
-               entry->edx &= (supported_xcr0 & guest_perm) >> 32;
-               if (!supported_xcr0)
+               entry->edx &= permitted_xcr0 >> 32;
+               if (!permitted_xcr0)
                        break;
 
                entry = do_host_cpuid(array, function, 1);
@@ -902,20 +923,20 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
 
                cpuid_entry_override(entry, CPUID_D_1_EAX);
                if (entry->eax & (F(XSAVES)|F(XSAVEC)))
-                       entry->ebx = xstate_required_size(supported_xcr0 | supported_xss,
+                       entry->ebx = xstate_required_size(permitted_xcr0 | permitted_xss,
                                                          true);
                else {
-                       WARN_ON_ONCE(supported_xss != 0);
+                       WARN_ON_ONCE(permitted_xss != 0);
                        entry->ebx = 0;
                }
-               entry->ecx &= supported_xss;
-               entry->edx &= supported_xss >> 32;
+               entry->ecx &= permitted_xss;
+               entry->edx &= permitted_xss >> 32;
 
                for (i = 2; i < 64; ++i) {
                        bool s_state;
-                       if (supported_xcr0 & BIT_ULL(i))
+                       if (permitted_xcr0 & BIT_ULL(i))
                                s_state = false;
-                       else if (supported_xss & BIT_ULL(i))
+                       else if (permitted_xss & BIT_ULL(i))
                                s_state = true;
                        else
                                continue;
@@ -929,7 +950,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
                         * invalid sub-leafs.  Only valid sub-leafs should
                         * reach this point, and they should have a non-zero
                         * save state size.  Furthermore, check whether the
-                        * processor agrees with supported_xcr0/supported_xss
+                        * processor agrees with permitted_xcr0/permitted_xss
                         * on whether this is an XCR0- or IA32_XSS-managed area.
                         */
                        if (WARN_ON_ONCE(!entry->eax || (entry->ecx & 0x1) != s_state)) {
index baca9fa..d7e6fde 100644 (file)
@@ -1096,14 +1096,8 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                                                       apic->regs + APIC_TMR);
                }
 
-               if (static_call(kvm_x86_deliver_posted_interrupt)(vcpu, vector)) {
-                       kvm_lapic_set_irr(vector, apic);
-                       kvm_make_request(KVM_REQ_EVENT, vcpu);
-                       kvm_vcpu_kick(vcpu);
-               } else {
-                       trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode,
-                                                  trig_mode, vector);
-               }
+               static_call(kvm_x86_deliver_interrupt)(apic, delivery_mode,
+                                                      trig_mode, vector);
                break;
 
        case APIC_DM_REMRD:
@@ -2629,7 +2623,7 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
        kvm_apic_set_version(vcpu);
 
        apic_update_ppr(apic);
-       hrtimer_cancel(&apic->lapic_timer.timer);
+       cancel_apic_timer(apic);
        apic->lapic_timer.expired_tscdeadline = 0;
        apic_update_lvtt(apic);
        apic_manage_nmi_watchdog(apic, kvm_lapic_get_reg(apic, APIC_LVT0));
index cf20685..1218b5a 100644 (file)
@@ -983,9 +983,9 @@ void svm_free_nested(struct vcpu_svm *svm)
 /*
  * Forcibly leave nested mode in order to be able to reset the VCPU later on.
  */
-void svm_leave_nested(struct vcpu_svm *svm)
+void svm_leave_nested(struct kvm_vcpu *vcpu)
 {
-       struct kvm_vcpu *vcpu = &svm->vcpu;
+       struct vcpu_svm *svm = to_svm(vcpu);
 
        if (is_guest_mode(vcpu)) {
                svm->nested.nested_run_pending = 0;
@@ -1411,7 +1411,7 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
                return -EINVAL;
 
        if (!(kvm_state->flags & KVM_STATE_NESTED_GUEST_MODE)) {
-               svm_leave_nested(svm);
+               svm_leave_nested(vcpu);
                svm_set_gif(svm, !!(kvm_state->flags & KVM_STATE_NESTED_GIF_SET));
                return 0;
        }
@@ -1478,7 +1478,7 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
         */
 
        if (is_guest_mode(vcpu))
-               svm_leave_nested(svm);
+               svm_leave_nested(vcpu);
        else
                svm->nested.vmcb02.ptr->save = svm->vmcb01.ptr->save;
 
@@ -1532,6 +1532,7 @@ static bool svm_get_nested_state_pages(struct kvm_vcpu *vcpu)
 }
 
 struct kvm_x86_nested_ops svm_nested_ops = {
+       .leave_nested = svm_leave_nested,
        .check_events = svm_check_nested_events,
        .triple_fault = nested_svm_triple_fault,
        .get_nested_state_pages = svm_get_nested_state_pages,
index 6a22798..17b5345 100644 (file)
@@ -2100,8 +2100,13 @@ void __init sev_hardware_setup(void)
        if (!sev_enabled || !npt_enabled)
                goto out;
 
-       /* Does the CPU support SEV? */
-       if (!boot_cpu_has(X86_FEATURE_SEV))
+       /*
+        * SEV must obviously be supported in hardware.  Sanity check that the
+        * CPU supports decode assists, which is mandatory for SEV guests to
+        * support instruction emulation.
+        */
+       if (!boot_cpu_has(X86_FEATURE_SEV) ||
+           WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_DECODEASSISTS)))
                goto out;
 
        /* Retrieve SEV CPUID information */
index 2c99b18..a290efb 100644 (file)
@@ -290,7 +290,7 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
 
        if ((old_efer & EFER_SVME) != (efer & EFER_SVME)) {
                if (!(efer & EFER_SVME)) {
-                       svm_leave_nested(svm);
+                       svm_leave_nested(vcpu);
                        svm_set_gif(svm, true);
                        /* #GP intercept is still needed for vmware backdoor */
                        if (!enable_vmware_backdoor)
@@ -312,7 +312,11 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
                                return ret;
                        }
 
-                       if (svm_gp_erratum_intercept)
+                       /*
+                        * Never intercept #GP for SEV guests, KVM can't
+                        * decrypt guest memory to workaround the erratum.
+                        */
+                       if (svm_gp_erratum_intercept && !sev_guest(vcpu->kvm))
                                set_exception_intercept(svm, GP_VECTOR);
                }
        }
@@ -1010,9 +1014,10 @@ static void init_vmcb(struct kvm_vcpu *vcpu)
         * Guest access to VMware backdoor ports could legitimately
         * trigger #GP because of TSS I/O permission bitmap.
         * We intercept those #GP and allow access to them anyway
-        * as VMware does.
+        * as VMware does.  Don't intercept #GP for SEV guests as KVM can't
+        * decrypt guest memory to decode the faulting instruction.
         */
-       if (enable_vmware_backdoor)
+       if (enable_vmware_backdoor && !sev_guest(vcpu->kvm))
                set_exception_intercept(svm, GP_VECTOR);
 
        svm_set_intercept(svm, INTERCEPT_INTR);
@@ -2091,10 +2096,6 @@ static int gp_interception(struct kvm_vcpu *vcpu)
        if (error_code)
                goto reinject;
 
-       /* All SVM instructions expect page aligned RAX */
-       if (svm->vmcb->save.rax & ~PAGE_MASK)
-               goto reinject;
-
        /* Decode the instruction for usage later */
        if (x86_decode_emulated_instruction(vcpu, 0, NULL, 0) != EMULATION_OK)
                goto reinject;
@@ -2112,8 +2113,13 @@ static int gp_interception(struct kvm_vcpu *vcpu)
                if (!is_guest_mode(vcpu))
                        return kvm_emulate_instruction(vcpu,
                                EMULTYPE_VMWARE_GP | EMULTYPE_NO_DECODE);
-       } else
+       } else {
+               /* All SVM instructions expect page aligned RAX */
+               if (svm->vmcb->save.rax & ~PAGE_MASK)
+                       goto reinject;
+
                return emulate_svm_instr(vcpu, opcode);
+       }
 
 reinject:
        kvm_queue_exception_e(vcpu, GP_VECTOR, error_code);
@@ -3285,6 +3291,21 @@ static void svm_set_irq(struct kvm_vcpu *vcpu)
                SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
 }
 
+static void svm_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode,
+                                 int trig_mode, int vector)
+{
+       struct kvm_vcpu *vcpu = apic->vcpu;
+
+       if (svm_deliver_avic_intr(vcpu, vector)) {
+               kvm_lapic_set_irr(vector, apic);
+               kvm_make_request(KVM_REQ_EVENT, vcpu);
+               kvm_vcpu_kick(vcpu);
+       } else {
+               trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode,
+                                          trig_mode, vector);
+       }
+}
+
 static void svm_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -3609,7 +3630,7 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu)
        struct vcpu_svm *svm = to_svm(vcpu);
        unsigned long vmcb_pa = svm->current_vmcb->pa;
 
-       kvm_guest_enter_irqoff();
+       guest_state_enter_irqoff();
 
        if (sev_es_guest(vcpu->kvm)) {
                __svm_sev_es_vcpu_run(vmcb_pa);
@@ -3629,7 +3650,7 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu)
                vmload(__sme_page_pa(sd->save_area));
        }
 
-       kvm_guest_exit_irqoff();
+       guest_state_exit_irqoff();
 }
 
 static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
@@ -4252,79 +4273,140 @@ static void svm_enable_smi_window(struct kvm_vcpu *vcpu)
        }
 }
 
-static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, void *insn, int insn_len)
+static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
+                                       void *insn, int insn_len)
 {
        bool smep, smap, is_user;
        unsigned long cr4;
+       u64 error_code;
+
+       /* Emulation is always possible when KVM has access to all guest state. */
+       if (!sev_guest(vcpu->kvm))
+               return true;
+
+       /* #UD and #GP should never be intercepted for SEV guests. */
+       WARN_ON_ONCE(emul_type & (EMULTYPE_TRAP_UD |
+                                 EMULTYPE_TRAP_UD_FORCED |
+                                 EMULTYPE_VMWARE_GP));
 
        /*
-        * When the guest is an SEV-ES guest, emulation is not possible.
+        * Emulation is impossible for SEV-ES guests as KVM doesn't have access
+        * to guest register state.
         */
        if (sev_es_guest(vcpu->kvm))
                return false;
 
+       /*
+        * Emulation is possible if the instruction is already decoded, e.g.
+        * when completing I/O after returning from userspace.
+        */
+       if (emul_type & EMULTYPE_NO_DECODE)
+               return true;
+
+       /*
+        * Emulation is possible for SEV guests if and only if a prefilled
+        * buffer containing the bytes of the intercepted instruction is
+        * available. SEV guest memory is encrypted with a guest specific key
+        * and cannot be decrypted by KVM, i.e. KVM would read cyphertext and
+        * decode garbage.
+        *
+        * Inject #UD if KVM reached this point without an instruction buffer.
+        * In practice, this path should never be hit by a well-behaved guest,
+        * e.g. KVM doesn't intercept #UD or #GP for SEV guests, but this path
+        * is still theoretically reachable, e.g. via unaccelerated fault-like
+        * AVIC access, and needs to be handled by KVM to avoid putting the
+        * guest into an infinite loop.   Injecting #UD is somewhat arbitrary,
+        * but its the least awful option given lack of insight into the guest.
+        */
+       if (unlikely(!insn)) {
+               kvm_queue_exception(vcpu, UD_VECTOR);
+               return false;
+       }
+
+       /*
+        * Emulate for SEV guests if the insn buffer is not empty.  The buffer
+        * will be empty if the DecodeAssist microcode cannot fetch bytes for
+        * the faulting instruction because the code fetch itself faulted, e.g.
+        * the guest attempted to fetch from emulated MMIO or a guest page
+        * table used to translate CS:RIP resides in emulated MMIO.
+        */
+       if (likely(insn_len))
+               return true;
+
        /*
         * Detect and workaround Errata 1096 Fam_17h_00_0Fh.
         *
         * Errata:
-        * When CPU raise #NPF on guest data access and vCPU CR4.SMAP=1, it is
-        * possible that CPU microcode implementing DecodeAssist will fail
-        * to read bytes of instruction which caused #NPF. In this case,
-        * GuestIntrBytes field of the VMCB on a VMEXIT will incorrectly
-        * return 0 instead of the correct guest instruction bytes.
-        *
-        * This happens because CPU microcode reading instruction bytes
-        * uses a special opcode which attempts to read data using CPL=0
-        * privileges. The microcode reads CS:RIP and if it hits a SMAP
-        * fault, it gives up and returns no instruction bytes.
+        * When CPU raises #NPF on guest data access and vCPU CR4.SMAP=1, it is
+        * possible that CPU microcode implementing DecodeAssist will fail to
+        * read guest memory at CS:RIP and vmcb.GuestIntrBytes will incorrectly
+        * be '0'.  This happens because microcode reads CS:RIP using a _data_
+        * loap uop with CPL=0 privileges.  If the load hits a SMAP #PF, ucode
+        * gives up and does not fill the instruction bytes buffer.
         *
-        * Detection:
-        * We reach here in case CPU supports DecodeAssist, raised #NPF and
-        * returned 0 in GuestIntrBytes field of the VMCB.
-        * First, errata can only be triggered in case vCPU CR4.SMAP=1.
-        * Second, if vCPU CR4.SMEP=1, errata could only be triggered
-        * in case vCPU CPL==3 (Because otherwise guest would have triggered
-        * a SMEP fault instead of #NPF).
-        * Otherwise, vCPU CR4.SMEP=0, errata could be triggered by any vCPU CPL.
-        * As most guests enable SMAP if they have also enabled SMEP, use above
-        * logic in order to attempt minimize false-positive of detecting errata
-        * while still preserving all cases semantic correctness.
+        * As above, KVM reaches this point iff the VM is an SEV guest, the CPU
+        * supports DecodeAssist, a #NPF was raised, KVM's page fault handler
+        * triggered emulation (e.g. for MMIO), and the CPU returned 0 in the
+        * GuestIntrBytes field of the VMCB.
         *
-        * Workaround:
-        * To determine what instruction the guest was executing, the hypervisor
-        * will have to decode the instruction at the instruction pointer.
+        * This does _not_ mean that the erratum has been encountered, as the
+        * DecodeAssist will also fail if the load for CS:RIP hits a legitimate
+        * #PF, e.g. if the guest attempt to execute from emulated MMIO and
+        * encountered a reserved/not-present #PF.
         *
-        * In non SEV guest, hypervisor will be able to read the guest
-        * memory to decode the instruction pointer when insn_len is zero
-        * so we return true to indicate that decoding is possible.
+        * To hit the erratum, the following conditions must be true:
+        *    1. CR4.SMAP=1 (obviously).
+        *    2. CR4.SMEP=0 || CPL=3.  If SMEP=1 and CPL<3, the erratum cannot
+        *       have been hit as the guest would have encountered a SMEP
+        *       violation #PF, not a #NPF.
+        *    3. The #NPF is not due to a code fetch, in which case failure to
+        *       retrieve the instruction bytes is legitimate (see abvoe).
         *
-        * But in the SEV guest, the guest memory is encrypted with the
-        * guest specific key and hypervisor will not be able to decode the
-        * instruction pointer so we will not able to workaround it. Lets
-        * print the error and request to kill the guest.
+        * In addition, don't apply the erratum workaround if the #NPF occurred
+        * while translating guest page tables (see below).
         */
-       if (likely(!insn || insn_len))
-               return true;
-
-       /*
-        * If RIP is invalid, go ahead with emulation which will cause an
-        * internal error exit.
-        */
-       if (!kvm_vcpu_gfn_to_memslot(vcpu, kvm_rip_read(vcpu) >> PAGE_SHIFT))
-               return true;
+       error_code = to_svm(vcpu)->vmcb->control.exit_info_1;
+       if (error_code & (PFERR_GUEST_PAGE_MASK | PFERR_FETCH_MASK))
+               goto resume_guest;
 
        cr4 = kvm_read_cr4(vcpu);
        smep = cr4 & X86_CR4_SMEP;
        smap = cr4 & X86_CR4_SMAP;
        is_user = svm_get_cpl(vcpu) == 3;
        if (smap && (!smep || is_user)) {
-               if (!sev_guest(vcpu->kvm))
-                       return true;
-
                pr_err_ratelimited("KVM: SEV Guest triggered AMD Erratum 1096\n");
-               kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
+
+               /*
+                * If the fault occurred in userspace, arbitrarily inject #GP
+                * to avoid killing the guest and to hopefully avoid confusing
+                * the guest kernel too much, e.g. injecting #PF would not be
+                * coherent with respect to the guest's page tables.  Request
+                * triple fault if the fault occurred in the kernel as there's
+                * no fault that KVM can inject without confusing the guest.
+                * In practice, the triple fault is moot as no sane SEV kernel
+                * will execute from user memory while also running with SMAP=1.
+                */
+               if (is_user)
+                       kvm_inject_gp(vcpu, 0);
+               else
+                       kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
        }
 
+resume_guest:
+       /*
+        * If the erratum was not hit, simply resume the guest and let it fault
+        * again.  While awful, e.g. the vCPU may get stuck in an infinite loop
+        * if the fault is at CPL=0, it's the lesser of all evils.  Exiting to
+        * userspace will kill the guest, and letting the emulator read garbage
+        * will yield random behavior and potentially corrupt the guest.
+        *
+        * Simply resuming the guest is technically not a violation of the SEV
+        * architecture.  AMD's APM states that all code fetches and page table
+        * accesses for SEV guest are encrypted, regardless of the C-Bit.  The
+        * APM also states that encrypted accesses to MMIO are "ignored", but
+        * doesn't explicitly define "ignored", i.e. doing nothing and letting
+        * the guest spin is technically "ignoring" the access.
+        */
        return false;
 }
 
@@ -4478,7 +4560,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
        .pmu_ops = &amd_pmu_ops,
        .nested_ops = &svm_nested_ops,
 
-       .deliver_posted_interrupt = svm_deliver_avic_intr,
+       .deliver_interrupt = svm_deliver_interrupt,
        .dy_apicv_has_pending_interrupt = svm_dy_apicv_has_pending_interrupt,
        .update_pi_irte = svm_update_pi_irte,
        .setup_mce = svm_setup_mce,
index 47ef8f4..7352535 100644 (file)
@@ -304,11 +304,6 @@ static inline void vmcb_mark_all_clean(struct vmcb *vmcb)
                               & ~VMCB_ALWAYS_DIRTY_MASK;
 }
 
-static inline bool vmcb_is_clean(struct vmcb *vmcb, int bit)
-{
-       return (vmcb->control.clean & (1 << bit));
-}
-
 static inline void vmcb_mark_dirty(struct vmcb *vmcb, int bit)
 {
        vmcb->control.clean &= ~(1 << bit);
@@ -525,7 +520,7 @@ static inline bool nested_exit_on_nmi(struct vcpu_svm *svm)
 
 int enter_svm_guest_mode(struct kvm_vcpu *vcpu,
                         u64 vmcb_gpa, struct vmcb *vmcb12, bool from_vmrun);
-void svm_leave_nested(struct vcpu_svm *svm);
+void svm_leave_nested(struct kvm_vcpu *vcpu);
 void svm_free_nested(struct vcpu_svm *svm);
 int svm_allocate_nested(struct vcpu_svm *svm);
 int nested_svm_vmrun(struct kvm_vcpu *vcpu);
index c53b8bf..489ca56 100644 (file)
@@ -46,6 +46,9 @@ static inline void svm_hv_init_vmcb(struct vmcb *vmcb)
        if (npt_enabled &&
            ms_hyperv.nested_features & HV_X64_NESTED_ENLIGHTENED_TLB)
                hve->hv_enlightenments_control.enlightened_npt_tlb = 1;
+
+       if (ms_hyperv.nested_features & HV_X64_NESTED_MSR_BITMAP)
+               hve->hv_enlightenments_control.msr_bitmap = 1;
 }
 
 static inline void svm_hv_hardware_setup(void)
@@ -83,14 +86,7 @@ static inline void svm_hv_vmcb_dirty_nested_enlightenments(
        struct hv_enlightenments *hve =
                (struct hv_enlightenments *)vmcb->control.reserved_sw;
 
-       /*
-        * vmcb can be NULL if called during early vcpu init.
-        * And its okay not to mark vmcb dirty during vcpu init
-        * as we mark it dirty unconditionally towards end of vcpu
-        * init phase.
-        */
-       if (vmcb_is_clean(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS) &&
-           hve->hv_enlightenments_control.msr_bitmap)
+       if (hve->hv_enlightenments_control.msr_bitmap)
                vmcb_mark_dirty(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS);
 }
 
index 959b59d..3f430e2 100644 (file)
@@ -54,7 +54,6 @@ struct nested_vmx_msrs {
 
 struct vmcs_config {
        int size;
-       int order;
        u32 basic_cap;
        u32 revision_id;
        u32 pin_based_exec_ctrl;
index ba6f99f..87e3dc1 100644 (file)
@@ -12,8 +12,6 @@
 
 DEFINE_STATIC_KEY_FALSE(enable_evmcs);
 
-#if IS_ENABLED(CONFIG_HYPERV)
-
 #define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
 #define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
                {EVMCS1_OFFSET(name), clean_field}
@@ -296,6 +294,7 @@ const struct evmcs_field vmcs_field_to_evmcs_1[] = {
 };
 const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
 
+#if IS_ENABLED(CONFIG_HYPERV)
 __init void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf)
 {
        vmcs_conf->pin_based_exec_ctrl &= ~EVMCS1_UNSUPPORTED_PINCTRL;
@@ -362,6 +361,7 @@ void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata)
        case MSR_IA32_VMX_PROCBASED_CTLS2:
                ctl_high &= ~EVMCS1_UNSUPPORTED_2NDEXEC;
                break;
+       case MSR_IA32_VMX_TRUE_PINBASED_CTLS:
        case MSR_IA32_VMX_PINBASED_CTLS:
                ctl_high &= ~EVMCS1_UNSUPPORTED_PINCTRL;
                break;
index 16731d2..8d70f9a 100644 (file)
@@ -59,12 +59,12 @@ DECLARE_STATIC_KEY_FALSE(enable_evmcs);
         SECONDARY_EXEC_SHADOW_VMCS |                                   \
         SECONDARY_EXEC_TSC_SCALING |                                   \
         SECONDARY_EXEC_PAUSE_LOOP_EXITING)
-#define EVMCS1_UNSUPPORTED_VMEXIT_CTRL (VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL)
+#define EVMCS1_UNSUPPORTED_VMEXIT_CTRL                                 \
+       (VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |                           \
+        VM_EXIT_SAVE_VMX_PREEMPTION_TIMER)
 #define EVMCS1_UNSUPPORTED_VMENTRY_CTRL (VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL)
 #define EVMCS1_UNSUPPORTED_VMFUNC (VMX_VMFUNC_EPTP_SWITCHING)
 
-#if IS_ENABLED(CONFIG_HYPERV)
-
 struct evmcs_field {
        u16 offset;
        u16 clean_field;
@@ -73,26 +73,56 @@ struct evmcs_field {
 extern const struct evmcs_field vmcs_field_to_evmcs_1[];
 extern const unsigned int nr_evmcs_1_fields;
 
-static __always_inline int get_evmcs_offset(unsigned long field,
-                                           u16 *clean_field)
+static __always_inline int evmcs_field_offset(unsigned long field,
+                                             u16 *clean_field)
 {
        unsigned int index = ROL16(field, 6);
        const struct evmcs_field *evmcs_field;
 
-       if (unlikely(index >= nr_evmcs_1_fields)) {
-               WARN_ONCE(1, "KVM: accessing unsupported EVMCS field %lx\n",
-                         field);
+       if (unlikely(index >= nr_evmcs_1_fields))
                return -ENOENT;
-       }
 
        evmcs_field = &vmcs_field_to_evmcs_1[index];
 
+       /*
+        * Use offset=0 to detect holes in eVMCS. This offset belongs to
+        * 'revision_id' but this field has no encoding and is supposed to
+        * be accessed directly.
+        */
+       if (unlikely(!evmcs_field->offset))
+               return -ENOENT;
+
        if (clean_field)
                *clean_field = evmcs_field->clean_field;
 
        return evmcs_field->offset;
 }
 
+static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs,
+                                unsigned long field, u16 offset)
+{
+       /*
+        * vmcs12_read_any() doesn't care whether the supplied structure
+        * is 'struct vmcs12' or 'struct hv_enlightened_vmcs' as it takes
+        * the exact offset of the required field, use it for convenience
+        * here.
+        */
+       return vmcs12_read_any((void *)evmcs, field, offset);
+}
+
+#if IS_ENABLED(CONFIG_HYPERV)
+
+static __always_inline int get_evmcs_offset(unsigned long field,
+                                           u16 *clean_field)
+{
+       int offset = evmcs_field_offset(field, clean_field);
+
+       WARN_ONCE(offset < 0, "KVM: accessing unsupported EVMCS field %lx\n",
+                 field);
+
+       return offset;
+}
+
 static __always_inline void evmcs_write64(unsigned long field, u64 value)
 {
        u16 clean_field;
index f235f77..ba34e94 100644 (file)
@@ -7,6 +7,7 @@
 #include <asm/mmu_context.h>
 
 #include "cpuid.h"
+#include "evmcs.h"
 #include "hyperv.h"
 #include "mmu.h"
 #include "nested.h"
@@ -4851,18 +4852,20 @@ static struct vmcs *alloc_shadow_vmcs(struct kvm_vcpu *vcpu)
        struct loaded_vmcs *loaded_vmcs = vmx->loaded_vmcs;
 
        /*
-        * We should allocate a shadow vmcs for vmcs01 only when L1
-        * executes VMXON and free it when L1 executes VMXOFF.
-        * As it is invalid to execute VMXON twice, we shouldn't reach
-        * here when vmcs01 already have an allocated shadow vmcs.
+        * KVM allocates a shadow VMCS only when L1 executes VMXON and frees it
+        * when L1 executes VMXOFF or the vCPU is forced out of nested
+        * operation.  VMXON faults if the CPU is already post-VMXON, so it
+        * should be impossible to already have an allocated shadow VMCS.  KVM
+        * doesn't support virtualization of VMCS shadowing, so vmcs01 should
+        * always be the loaded VMCS.
         */
-       WARN_ON(loaded_vmcs == &vmx->vmcs01 && loaded_vmcs->shadow_vmcs);
+       if (WARN_ON(loaded_vmcs != &vmx->vmcs01 || loaded_vmcs->shadow_vmcs))
+               return loaded_vmcs->shadow_vmcs;
+
+       loaded_vmcs->shadow_vmcs = alloc_vmcs(true);
+       if (loaded_vmcs->shadow_vmcs)
+               vmcs_clear(loaded_vmcs->shadow_vmcs);
 
-       if (!loaded_vmcs->shadow_vmcs) {
-               loaded_vmcs->shadow_vmcs = alloc_vmcs(true);
-               if (loaded_vmcs->shadow_vmcs)
-                       vmcs_clear(loaded_vmcs->shadow_vmcs);
-       }
        return loaded_vmcs->shadow_vmcs;
 }
 
@@ -5099,27 +5102,49 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
        if (!nested_vmx_check_permission(vcpu))
                return 1;
 
-       /*
-        * In VMX non-root operation, when the VMCS-link pointer is INVALID_GPA,
-        * any VMREAD sets the ALU flags for VMfailInvalid.
-        */
-       if (vmx->nested.current_vmptr == INVALID_GPA ||
-           (is_guest_mode(vcpu) &&
-            get_vmcs12(vcpu)->vmcs_link_pointer == INVALID_GPA))
-               return nested_vmx_failInvalid(vcpu);
-
        /* Decode instruction info and find the field to read */
        field = kvm_register_read(vcpu, (((instr_info) >> 28) & 0xf));
 
-       offset = vmcs_field_to_offset(field);
-       if (offset < 0)
-               return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
+       if (!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
+               /*
+                * In VMX non-root operation, when the VMCS-link pointer is INVALID_GPA,
+                * any VMREAD sets the ALU flags for VMfailInvalid.
+                */
+               if (vmx->nested.current_vmptr == INVALID_GPA ||
+                   (is_guest_mode(vcpu) &&
+                    get_vmcs12(vcpu)->vmcs_link_pointer == INVALID_GPA))
+                       return nested_vmx_failInvalid(vcpu);
 
-       if (!is_guest_mode(vcpu) && is_vmcs12_ext_field(field))
-               copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
+               offset = get_vmcs12_field_offset(field);
+               if (offset < 0)
+                       return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
+
+               if (!is_guest_mode(vcpu) && is_vmcs12_ext_field(field))
+                       copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
 
-       /* Read the field, zero-extended to a u64 value */
-       value = vmcs12_read_any(vmcs12, field, offset);
+               /* Read the field, zero-extended to a u64 value */
+               value = vmcs12_read_any(vmcs12, field, offset);
+       } else {
+               /*
+                * Hyper-V TLFS (as of 6.0b) explicitly states, that while an
+                * enlightened VMCS is active VMREAD/VMWRITE instructions are
+                * unsupported. Unfortunately, certain versions of Windows 11
+                * don't comply with this requirement which is not enforced in
+                * genuine Hyper-V. Allow VMREAD from an enlightened VMCS as a
+                * workaround, as misbehaving guests will panic on VM-Fail.
+                * Note, enlightened VMCS is incompatible with shadow VMCS so
+                * all VMREADs from L2 should go to L1.
+                */
+               if (WARN_ON_ONCE(is_guest_mode(vcpu)))
+                       return nested_vmx_failInvalid(vcpu);
+
+               offset = evmcs_field_offset(field, NULL);
+               if (offset < 0)
+                       return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
+
+               /* Read the field, zero-extended to a u64 value */
+               value = evmcs_read_any(vmx->nested.hv_evmcs, field, offset);
+       }
 
        /*
         * Now copy part of this value to register or memory, as requested.
@@ -5214,7 +5239,7 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
 
        field = kvm_register_read(vcpu, (((instr_info) >> 28) & 0xf));
 
-       offset = vmcs_field_to_offset(field);
+       offset = get_vmcs12_field_offset(field);
        if (offset < 0)
                return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
 
@@ -6462,7 +6487,7 @@ static u64 nested_vmx_calc_vmcs_enum_msr(void)
        max_idx = 0;
        for (i = 0; i < nr_vmcs12_fields; i++) {
                /* The vmcs12 table is very, very sparsely populated. */
-               if (!vmcs_field_to_offset_table[i])
+               if (!vmcs12_field_offsets[i])
                        continue;
 
                idx = vmcs_field_index(VMCS12_IDX_TO_ENC(i));
@@ -6771,6 +6796,7 @@ __init int nested_vmx_hardware_setup(int (*exit_handlers[])(struct kvm_vcpu *))
 }
 
 struct kvm_x86_nested_ops vmx_nested_ops = {
+       .leave_nested = vmx_leave_nested,
        .check_events = vmx_check_nested_events,
        .hv_timer_pending = nested_vmx_preemption_timer_pending,
        .triple_fault = nested_vmx_triple_fault,
index cab6ba7..2251b60 100644 (file)
@@ -8,7 +8,7 @@
        FIELD(number, name),                                            \
        [ROL16(number##_HIGH, 6)] = VMCS12_OFFSET(name) + sizeof(u32)
 
-const unsigned short vmcs_field_to_offset_table[] = {
+const unsigned short vmcs12_field_offsets[] = {
        FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id),
        FIELD(POSTED_INTR_NV, posted_intr_nv),
        FIELD(GUEST_ES_SELECTOR, guest_es_selector),
@@ -151,4 +151,4 @@ const unsigned short vmcs_field_to_offset_table[] = {
        FIELD(HOST_RSP, host_rsp),
        FIELD(HOST_RIP, host_rip),
 };
-const unsigned int nr_vmcs12_fields = ARRAY_SIZE(vmcs_field_to_offset_table);
+const unsigned int nr_vmcs12_fields = ARRAY_SIZE(vmcs12_field_offsets);
index 2a45f02..746129d 100644 (file)
@@ -361,10 +361,10 @@ static inline void vmx_check_vmcs12_offsets(void)
        CHECK_OFFSET(guest_pml_index, 996);
 }
 
-extern const unsigned short vmcs_field_to_offset_table[];
+extern const unsigned short vmcs12_field_offsets[];
 extern const unsigned int nr_vmcs12_fields;
 
-static inline short vmcs_field_to_offset(unsigned long field)
+static inline short get_vmcs12_field_offset(unsigned long field)
 {
        unsigned short offset;
        unsigned int index;
@@ -377,7 +377,7 @@ static inline short vmcs_field_to_offset(unsigned long field)
                return -ENOENT;
 
        index = array_index_nospec(index, nr_vmcs12_fields);
-       offset = vmcs_field_to_offset_table[index];
+       offset = vmcs12_field_offsets[index];
        if (offset == 0)
                return -ENOENT;
        return offset;
index 4ac6760..6c27bd0 100644 (file)
@@ -1487,11 +1487,12 @@ static int vmx_rtit_ctl_check(struct kvm_vcpu *vcpu, u64 data)
        return 0;
 }
 
-static bool vmx_can_emulate_instruction(struct kvm_vcpu *vcpu, void *insn, int insn_len)
+static bool vmx_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
+                                       void *insn, int insn_len)
 {
        /*
         * Emulation of instructions in SGX enclaves is impossible as RIP does
-        * not point  tthe failing instruction, and even if it did, the code
+        * not point at the failing instruction, and even if it did, the code
         * stream is inaccessible.  Inject #UD instead of exiting to userspace
         * so that guest userspace can't DoS the guest simply by triggering
         * emulation (enclaves are CPL3 only).
@@ -2603,7 +2604,6 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,
                return -EIO;
 
        vmcs_conf->size = vmx_msr_high & 0x1fff;
-       vmcs_conf->order = get_order(vmcs_conf->size);
        vmcs_conf->basic_cap = vmx_msr_high & ~0x1fff;
 
        vmcs_conf->revision_id = vmx_msr_low;
@@ -2628,7 +2628,7 @@ struct vmcs *alloc_vmcs_cpu(bool shadow, int cpu, gfp_t flags)
        struct page *pages;
        struct vmcs *vmcs;
 
-       pages = __alloc_pages_node(node, flags, vmcs_config.order);
+       pages = __alloc_pages_node(node, flags, 0);
        if (!pages)
                return NULL;
        vmcs = page_address(pages);
@@ -2647,7 +2647,7 @@ struct vmcs *alloc_vmcs_cpu(bool shadow, int cpu, gfp_t flags)
 
 void free_vmcs(struct vmcs *vmcs)
 {
-       free_pages((unsigned long)vmcs, vmcs_config.order);
+       free_page((unsigned long)vmcs);
 }
 
 /*
@@ -4041,6 +4041,21 @@ static int vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
        return 0;
 }
 
+static void vmx_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode,
+                                 int trig_mode, int vector)
+{
+       struct kvm_vcpu *vcpu = apic->vcpu;
+
+       if (vmx_deliver_posted_interrupt(vcpu, vector)) {
+               kvm_lapic_set_irr(vector, apic);
+               kvm_make_request(KVM_REQ_EVENT, vcpu);
+               kvm_vcpu_kick(vcpu);
+       } else {
+               trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode,
+                                          trig_mode, vector);
+       }
+}
+
 /*
  * Set up the vmcs's constant host-state fields, i.e., host-state fields that
  * will not change in the lifetime of the guest.
@@ -4094,10 +4109,14 @@ void vmx_set_constant_host_state(struct vcpu_vmx *vmx)
        vmcs_write32(HOST_IA32_SYSENTER_CS, low32);
 
        /*
-        * If 32-bit syscall is enabled, vmx_vcpu_load_vcms rewrites
-        * HOST_IA32_SYSENTER_ESP.
+        * SYSENTER is used for 32-bit system calls on either 32-bit or
+        * 64-bit kernels.  It is always zero If neither is allowed, otherwise
+        * vmx_vcpu_load_vmcs loads it with the per-CPU entry stack (and may
+        * have already done so!).
         */
-       vmcs_writel(HOST_IA32_SYSENTER_ESP, 0);
+       if (!IS_ENABLED(CONFIG_IA32_EMULATION) && !IS_ENABLED(CONFIG_X86_32))
+               vmcs_writel(HOST_IA32_SYSENTER_ESP, 0);
+
        rdmsrl(MSR_IA32_SYSENTER_EIP, tmpl);
        vmcs_writel(HOST_IA32_SYSENTER_EIP, tmpl);   /* 22.2.3 */
 
@@ -4901,8 +4920,33 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
                dr6 = vmx_get_exit_qual(vcpu);
                if (!(vcpu->guest_debug &
                      (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) {
+                       /*
+                        * If the #DB was due to ICEBP, a.k.a. INT1, skip the
+                        * instruction.  ICEBP generates a trap-like #DB, but
+                        * despite its interception control being tied to #DB,
+                        * is an instruction intercept, i.e. the VM-Exit occurs
+                        * on the ICEBP itself.  Note, skipping ICEBP also
+                        * clears STI and MOVSS blocking.
+                        *
+                        * For all other #DBs, set vmcs.PENDING_DBG_EXCEPTIONS.BS
+                        * if single-step is enabled in RFLAGS and STI or MOVSS
+                        * blocking is active, as the CPU doesn't set the bit
+                        * on VM-Exit due to #DB interception.  VM-Entry has a
+                        * consistency check that a single-step #DB is pending
+                        * in this scenario as the previous instruction cannot
+                        * have toggled RFLAGS.TF 0=>1 (because STI and POP/MOV
+                        * don't modify RFLAGS), therefore the one instruction
+                        * delay when activating single-step breakpoints must
+                        * have already expired.  Note, the CPU sets/clears BS
+                        * as appropriate for all other VM-Exits types.
+                        */
                        if (is_icebp(intr_info))
                                WARN_ON(!skip_emulated_instruction(vcpu));
+                       else if ((vmx_get_rflags(vcpu) & X86_EFLAGS_TF) &&
+                                (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
+                                 (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)))
+                               vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS,
+                                           vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS) | DR6_BS);
 
                        kvm_queue_exception_p(vcpu, DB_VECTOR, dr6);
                        return 1;
@@ -5397,7 +5441,7 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu)
 {
        gpa_t gpa;
 
-       if (!vmx_can_emulate_instruction(vcpu, NULL, 0))
+       if (!vmx_can_emulate_instruction(vcpu, EMULTYPE_PF, NULL, 0))
                return 1;
 
        /*
@@ -6725,7 +6769,7 @@ static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu)
 static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
                                        struct vcpu_vmx *vmx)
 {
-       kvm_guest_enter_irqoff();
+       guest_state_enter_irqoff();
 
        /* L1D Flush includes CPU buffer clear to mitigate MDS */
        if (static_branch_unlikely(&vmx_l1d_should_flush))
@@ -6741,7 +6785,7 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
 
        vcpu->arch.cr2 = native_read_cr2();
 
-       kvm_guest_exit_irqoff();
+       guest_state_exit_irqoff();
 }
 
 static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
@@ -7739,7 +7783,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
        .hwapic_isr_update = vmx_hwapic_isr_update,
        .guest_apic_has_interrupt = vmx_guest_apic_has_interrupt,
        .sync_pir_to_irr = vmx_sync_pir_to_irr,
-       .deliver_posted_interrupt = vmx_deliver_posted_interrupt,
+       .deliver_interrupt = vmx_deliver_interrupt,
        .dy_apicv_has_pending_interrupt = pi_has_pending_interrupt,
 
        .set_tss_addr = vmx_set_tss_addr,
index 9e43d75..7131d73 100644 (file)
@@ -90,6 +90,8 @@
 u64 __read_mostly kvm_mce_cap_supported = MCG_CTL_P | MCG_SER_P;
 EXPORT_SYMBOL_GPL(kvm_mce_cap_supported);
 
+#define  ERR_PTR_USR(e)  ((void __user *)ERR_PTR(e))
+
 #define emul_to_vcpu(ctxt) \
        ((struct kvm_vcpu *)(ctxt)->vcpu)
 
@@ -3535,6 +3537,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                if (data & ~supported_xss)
                        return 1;
                vcpu->arch.ia32_xss = data;
+               kvm_update_cpuid_runtime(vcpu);
                break;
        case MSR_SMI_COUNT:
                if (!msr_info->host_initiated)
@@ -4229,6 +4232,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_SREGS2:
        case KVM_CAP_EXIT_ON_EMULATION_FAILURE:
        case KVM_CAP_VCPU_ATTRIBUTES:
+       case KVM_CAP_SYS_ATTRIBUTES:
                r = 1;
                break;
        case KVM_CAP_EXIT_HYPERCALL:
@@ -4331,7 +4335,49 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                break;
        }
        return r;
+}
+
+static inline void __user *kvm_get_attr_addr(struct kvm_device_attr *attr)
+{
+       void __user *uaddr = (void __user*)(unsigned long)attr->addr;
+
+       if ((u64)(unsigned long)uaddr != attr->addr)
+               return ERR_PTR_USR(-EFAULT);
+       return uaddr;
+}
+
+static int kvm_x86_dev_get_attr(struct kvm_device_attr *attr)
+{
+       u64 __user *uaddr = kvm_get_attr_addr(attr);
+
+       if (attr->group)
+               return -ENXIO;
+
+       if (IS_ERR(uaddr))
+               return PTR_ERR(uaddr);
+
+       switch (attr->attr) {
+       case KVM_X86_XCOMP_GUEST_SUPP:
+               if (put_user(supported_xcr0, uaddr))
+                       return -EFAULT;
+               return 0;
+       default:
+               return -ENXIO;
+               break;
+       }
+}
+
+static int kvm_x86_dev_has_attr(struct kvm_device_attr *attr)
+{
+       if (attr->group)
+               return -ENXIO;
 
+       switch (attr->attr) {
+       case KVM_X86_XCOMP_GUEST_SUPP:
+               return 0;
+       default:
+               return -ENXIO;
+       }
 }
 
 long kvm_arch_dev_ioctl(struct file *filp,
@@ -4422,6 +4468,22 @@ long kvm_arch_dev_ioctl(struct file *filp,
        case KVM_GET_SUPPORTED_HV_CPUID:
                r = kvm_ioctl_get_supported_hv_cpuid(NULL, argp);
                break;
+       case KVM_GET_DEVICE_ATTR: {
+               struct kvm_device_attr attr;
+               r = -EFAULT;
+               if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
+                       break;
+               r = kvm_x86_dev_get_attr(&attr);
+               break;
+       }
+       case KVM_HAS_DEVICE_ATTR: {
+               struct kvm_device_attr attr;
+               r = -EFAULT;
+               if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
+                       break;
+               r = kvm_x86_dev_has_attr(&attr);
+               break;
+       }
        default:
                r = -EINVAL;
                break;
@@ -4860,8 +4922,10 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
                vcpu->arch.apic->sipi_vector = events->sipi_vector;
 
        if (events->flags & KVM_VCPUEVENT_VALID_SMM) {
-               if (!!(vcpu->arch.hflags & HF_SMM_MASK) != events->smi.smm)
+               if (!!(vcpu->arch.hflags & HF_SMM_MASK) != events->smi.smm) {
+                       kvm_x86_ops.nested_ops->leave_nested(vcpu);
                        kvm_smm_changed(vcpu, events->smi.smm);
+               }
 
                vcpu->arch.smi_pending = events->smi.pending;
 
@@ -5022,11 +5086,11 @@ static int kvm_arch_tsc_has_attr(struct kvm_vcpu *vcpu,
 static int kvm_arch_tsc_get_attr(struct kvm_vcpu *vcpu,
                                 struct kvm_device_attr *attr)
 {
-       u64 __user *uaddr = (u64 __user *)(unsigned long)attr->addr;
+       u64 __user *uaddr = kvm_get_attr_addr(attr);
        int r;
 
-       if ((u64)(unsigned long)uaddr != attr->addr)
-               return -EFAULT;
+       if (IS_ERR(uaddr))
+               return PTR_ERR(uaddr);
 
        switch (attr->attr) {
        case KVM_VCPU_TSC_OFFSET:
@@ -5045,12 +5109,12 @@ static int kvm_arch_tsc_get_attr(struct kvm_vcpu *vcpu,
 static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu,
                                 struct kvm_device_attr *attr)
 {
-       u64 __user *uaddr = (u64 __user *)(unsigned long)attr->addr;
+       u64 __user *uaddr = kvm_get_attr_addr(attr);
        struct kvm *kvm = vcpu->kvm;
        int r;
 
-       if ((u64)(unsigned long)uaddr != attr->addr)
-               return -EFAULT;
+       if (IS_ERR(uaddr))
+               return PTR_ERR(uaddr);
 
        switch (attr->attr) {
        case KVM_VCPU_TSC_OFFSET: {
@@ -6810,6 +6874,13 @@ int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val,
 }
 EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system);
 
+static int kvm_can_emulate_insn(struct kvm_vcpu *vcpu, int emul_type,
+                               void *insn, int insn_len)
+{
+       return static_call(kvm_x86_can_emulate_instruction)(vcpu, emul_type,
+                                                           insn, insn_len);
+}
+
 int handle_ud(struct kvm_vcpu *vcpu)
 {
        static const char kvm_emulate_prefix[] = { __KVM_EMULATE_PREFIX };
@@ -6817,7 +6888,7 @@ int handle_ud(struct kvm_vcpu *vcpu)
        char sig[5]; /* ud2; .ascii "kvm" */
        struct x86_exception e;
 
-       if (unlikely(!static_call(kvm_x86_can_emulate_instruction)(vcpu, NULL, 0)))
+       if (unlikely(!kvm_can_emulate_insn(vcpu, emul_type, NULL, 0)))
                return 1;
 
        if (force_emulation_prefix &&
@@ -8193,7 +8264,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
        bool writeback = true;
        bool write_fault_to_spt;
 
-       if (unlikely(!static_call(kvm_x86_can_emulate_instruction)(vcpu, insn, insn_len)))
+       if (unlikely(!kvm_can_emulate_insn(vcpu, emulation_type, insn, insn_len)))
                return 1;
 
        vcpu->arch.l1tf_flush_l1d = true;
@@ -9706,7 +9777,7 @@ void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
                kvm_make_all_cpus_request(kvm, KVM_REQ_APIC_PAGE_RELOAD);
 }
 
-void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu)
+static void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu)
 {
        if (!lapic_in_kernel(vcpu))
                return;
@@ -9972,6 +10043,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                set_debugreg(0, 7);
        }
 
+       guest_timing_enter_irqoff();
+
        for (;;) {
                /*
                 * Assert that vCPU vs. VM APICv state is consistent.  An APICv
@@ -10056,7 +10129,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
         * of accounting via context tracking, but the loss of accuracy is
         * acceptable for all known use cases.
         */
-       vtime_account_guest_exit();
+       guest_timing_exit_irqoff();
 
        if (lapic_in_kernel(vcpu)) {
                s64 delta = vcpu->arch.apic->lapic_timer.advance_expire_delta;
@@ -11209,7 +11282,8 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 
                vcpu->arch.msr_misc_features_enables = 0;
 
-               vcpu->arch.xcr0 = XFEATURE_MASK_FP;
+               __kvm_set_xcr(vcpu, 0, XFEATURE_MASK_FP);
+               __kvm_set_msr(vcpu, MSR_IA32_XSS, 0, true);
        }
 
        /* All GPRs except RDX (handled below) are zeroed on RESET/INIT. */
@@ -11226,8 +11300,6 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
        cpuid_0x1 = kvm_find_cpuid_entry(vcpu, 1, 0);
        kvm_rdx_write(vcpu, cpuid_0x1 ? cpuid_0x1->eax : 0x600);
 
-       vcpu->arch.ia32_xss = 0;
-
        static_call(kvm_x86_vcpu_reset)(vcpu, init_event);
 
        kvm_set_rflags(vcpu, X86_EFLAGS_FIXED);
@@ -11571,8 +11643,6 @@ void kvm_arch_sync_events(struct kvm *kvm)
        kvm_free_pit(kvm);
 }
 
-#define  ERR_PTR_USR(e)  ((void __user *)ERR_PTR(e))
-
 /**
  * __x86_set_memory_region: Setup KVM internal memory slot
  *
index 635b75f..767ec7f 100644 (file)
 
 void kvm_spurious_fault(void);
 
-static __always_inline void kvm_guest_enter_irqoff(void)
-{
-       /*
-        * VMENTER enables interrupts (host state), but the kernel state is
-        * interrupts disabled when this is invoked. Also tell RCU about
-        * it. This is the same logic as for exit_to_user_mode().
-        *
-        * This ensures that e.g. latency analysis on the host observes
-        * guest mode as interrupt enabled.
-        *
-        * guest_enter_irqoff() informs context tracking about the
-        * transition to guest mode and if enabled adjusts RCU state
-        * accordingly.
-        */
-       instrumentation_begin();
-       trace_hardirqs_on_prepare();
-       lockdep_hardirqs_on_prepare(CALLER_ADDR0);
-       instrumentation_end();
-
-       guest_enter_irqoff();
-       lockdep_hardirqs_on(CALLER_ADDR0);
-}
-
-static __always_inline void kvm_guest_exit_irqoff(void)
-{
-       /*
-        * VMEXIT disables interrupts (host state), but tracing and lockdep
-        * have them in state 'on' as recorded before entering guest mode.
-        * Same as enter_from_user_mode().
-        *
-        * context_tracking_guest_exit() restores host context and reinstates
-        * RCU if enabled and required.
-        *
-        * This needs to be done immediately after VM-Exit, before any code
-        * that might contain tracepoints or call out to the greater world,
-        * e.g. before x86_spec_ctrl_restore_host().
-        */
-       lockdep_hardirqs_off(CALLER_ADDR0);
-       context_tracking_guest_exit();
-
-       instrumentation_begin();
-       trace_hardirqs_off_finish();
-       instrumentation_end();
-}
-
 #define KVM_NESTED_VMENTER_CONSISTENCY_CHECK(consistency_check)                \
 ({                                                                     \
        bool failed = (consistency_check);                              \
index 0e3f7d6..bad5753 100644 (file)
@@ -316,10 +316,7 @@ int __kvm_xen_has_interrupt(struct kvm_vcpu *v)
                                     "\tnotq %0\n"
                                     "\t" LOCK_PREFIX "andq %0, %2\n"
                                     "2:\n"
-                                    "\t.section .fixup,\"ax\"\n"
-                                    "3:\tjmp\t2b\n"
-                                    "\t.previous\n"
-                                    _ASM_EXTABLE_UA(1b, 3b)
+                                    _ASM_EXTABLE_UA(1b, 2b)
                                     : "=r" (evtchn_pending_sel),
                                       "+m" (vi->evtchn_pending_sel),
                                       "+m" (v->arch.xen.evtchn_pending_sel)
@@ -335,10 +332,7 @@ int __kvm_xen_has_interrupt(struct kvm_vcpu *v)
                                     "\tnotl %0\n"
                                     "\t" LOCK_PREFIX "andl %0, %2\n"
                                     "2:\n"
-                                    "\t.section .fixup,\"ax\"\n"
-                                    "3:\tjmp\t2b\n"
-                                    "\t.previous\n"
-                                    _ASM_EXTABLE_UA(1b, 3b)
+                                    _ASM_EXTABLE_UA(1b, 2b)
                                     : "=r" (evtchn_pending_sel32),
                                       "+m" (vi->evtchn_pending_sel),
                                       "+m" (v->arch.xen.evtchn_pending_sel)
index 2edd866..615a76d 100644 (file)
@@ -353,8 +353,8 @@ static void pci_fixup_video(struct pci_dev *pdev)
                }
        }
 }
-DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
-                               PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID,
+                              PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
 
 
 static const struct dmi_system_id msi_k8t_dmi_table[] = {
index 4230094..517a9d8 100644 (file)
@@ -9,6 +9,7 @@
 #include <xen/events.h>
 #include <xen/interface/memory.h>
 
+#include <asm/apic.h>
 #include <asm/cpu.h>
 #include <asm/smp.h>
 #include <asm/io_apic.h>
@@ -184,8 +185,7 @@ static int xen_cpu_dead_hvm(unsigned int cpu)
 
        if (xen_have_vector_callback && xen_feature(XENFEAT_hvm_safe_pvclock))
                xen_teardown_timer(cpu);
-
-       return 0;
+       return 0;
 }
 
 static bool no_vector_callback __initdata;
@@ -242,15 +242,14 @@ static __init int xen_parse_no_vector_callback(char *arg)
 }
 early_param("xen_no_vector_callback", xen_parse_no_vector_callback);
 
-bool __init xen_hvm_need_lapic(void)
+static __init bool xen_x2apic_available(void)
 {
-       if (xen_pv_domain())
-               return false;
-       if (!xen_hvm_domain())
-               return false;
-       if (xen_feature(XENFEAT_hvm_pirqs) && xen_have_vector_callback)
-               return false;
-       return true;
+       return x2apic_supported();
+}
+
+static bool __init msi_ext_dest_id(void)
+{
+       return cpuid_eax(xen_cpuid_base() + 4) & XEN_HVM_CPUID_EXT_DEST_ID;
 }
 
 static __init void xen_hvm_guest_late_init(void)
@@ -312,9 +311,10 @@ struct hypervisor_x86 x86_hyper_xen_hvm __initdata = {
        .detect                 = xen_platform_hvm,
        .type                   = X86_HYPER_XEN_HVM,
        .init.init_platform     = xen_hvm_guest_init,
-       .init.x2apic_available  = xen_x2apic_para_available,
+       .init.x2apic_available  = xen_x2apic_available,
        .init.init_mem_mapping  = xen_hvm_init_mem_mapping,
        .init.guest_late_init   = xen_hvm_guest_late_init,
+       .init.msi_ext_dest_id   = msi_ext_dest_id,
        .runtime.pin_vcpu       = xen_pin_vcpu,
        .ignore_nopv            = true,
 };
index 5004feb..d47c3d1 100644 (file)
@@ -1341,10 +1341,6 @@ asmlinkage __visible void __init xen_start_kernel(void)
 
                xen_acpi_sleep_register();
 
-               /* Avoid searching for BIOS MP tables */
-               x86_init.mpparse.find_smp_config = x86_init_noop;
-               x86_init.mpparse.get_smp_config = x86_init_uint_noop;
-
                xen_boot_params_init_edd();
 
 #ifdef CONFIG_ACPI
index 6a8f3b5..4a60192 100644 (file)
@@ -148,28 +148,12 @@ int xen_smp_intr_init_pv(unsigned int cpu)
        return rc;
 }
 
-static void __init xen_fill_possible_map(void)
-{
-       int i, rc;
-
-       if (xen_initial_domain())
-               return;
-
-       for (i = 0; i < nr_cpu_ids; i++) {
-               rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
-               if (rc >= 0) {
-                       num_processors++;
-                       set_cpu_possible(i, true);
-               }
-       }
-}
-
-static void __init xen_filter_cpu_maps(void)
+static void __init _get_smp_config(unsigned int early)
 {
        int i, rc;
        unsigned int subtract = 0;
 
-       if (!xen_initial_domain())
+       if (early)
                return;
 
        num_processors = 0;
@@ -210,7 +194,6 @@ static void __init xen_pv_smp_prepare_boot_cpu(void)
                 * sure the old memory can be recycled. */
                make_lowmem_page_readwrite(xen_initial_gdt);
 
-       xen_filter_cpu_maps();
        xen_setup_vcpu_info_placement();
 
        /*
@@ -476,5 +459,8 @@ static const struct smp_ops xen_smp_ops __initconst = {
 void __init xen_smp_init(void)
 {
        smp_ops = xen_smp_ops;
-       xen_fill_possible_map();
+
+       /* Avoid searching for BIOS MP tables */
+       x86_init.mpparse.find_smp_config = x86_init_noop;
+       x86_init.mpparse.get_smp_config = _get_smp_config;
 }
index 31b1e34..14ea32e 100644 (file)
@@ -57,6 +57,14 @@ void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size)
                screen_info->rsvd_size = info->u.vesa_lfb.rsvd_size;
                screen_info->rsvd_pos = info->u.vesa_lfb.rsvd_pos;
 
+               if (size >= offsetof(struct dom0_vga_console_info,
+                                    u.vesa_lfb.ext_lfb_base)
+                   + sizeof(info->u.vesa_lfb.ext_lfb_base)
+                   && info->u.vesa_lfb.ext_lfb_base) {
+                       screen_info->ext_lfb_base = info->u.vesa_lfb.ext_lfb_base;
+                       screen_info->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
+               }
+
                if (info->video_type == XEN_VGATYPE_EFI_LFB) {
                        screen_info->orig_video_isVGA = VIDEO_TYPE_EFI;
                        break;
@@ -66,14 +74,6 @@ void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size)
                                     u.vesa_lfb.mode_attrs)
                    + sizeof(info->u.vesa_lfb.mode_attrs))
                        screen_info->vesa_attributes = info->u.vesa_lfb.mode_attrs;
-
-               if (size >= offsetof(struct dom0_vga_console_info,
-                                    u.vesa_lfb.ext_lfb_base)
-                   + sizeof(info->u.vesa_lfb.ext_lfb_base)
-                   && info->u.vesa_lfb.ext_lfb_base) {
-                       screen_info->ext_lfb_base = info->u.vesa_lfb.ext_lfb_base;
-                       screen_info->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
-               }
                break;
        }
 }
index d251147..0827b19 100644 (file)
@@ -373,7 +373,7 @@ void bio_integrity_advance(struct bio *bio, unsigned int bytes_done)
        struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
        unsigned bytes = bio_integrity_bytes(bi, bytes_done >> 9);
 
-       bip->bip_iter.bi_sector += bytes_done >> 9;
+       bip->bip_iter.bi_sector += bio_integrity_intervals(bi, bytes_done >> 9);
        bvec_iter_advance(bip->bip_vec, &bip->bip_iter, bytes);
 }
 
index 97f8bc8..d93e3bb 100644 (file)
@@ -1061,20 +1061,32 @@ again:
 }
 
 static unsigned long __part_start_io_acct(struct block_device *part,
-                                         unsigned int sectors, unsigned int op)
+                                         unsigned int sectors, unsigned int op,
+                                         unsigned long start_time)
 {
        const int sgrp = op_stat_group(op);
-       unsigned long now = READ_ONCE(jiffies);
 
        part_stat_lock();
-       update_io_ticks(part, now, false);
+       update_io_ticks(part, start_time, false);
        part_stat_inc(part, ios[sgrp]);
        part_stat_add(part, sectors[sgrp], sectors);
        part_stat_local_inc(part, in_flight[op_is_write(op)]);
        part_stat_unlock();
 
-       return now;
+       return start_time;
+}
+
+/**
+ * bio_start_io_acct_time - start I/O accounting for bio based drivers
+ * @bio:       bio to start account for
+ * @start_time:        start time that should be passed back to bio_end_io_acct().
+ */
+void bio_start_io_acct_time(struct bio *bio, unsigned long start_time)
+{
+       __part_start_io_acct(bio->bi_bdev, bio_sectors(bio),
+                            bio_op(bio), start_time);
 }
+EXPORT_SYMBOL_GPL(bio_start_io_acct_time);
 
 /**
  * bio_start_io_acct - start I/O accounting for bio based drivers
@@ -1084,14 +1096,15 @@ static unsigned long __part_start_io_acct(struct block_device *part,
  */
 unsigned long bio_start_io_acct(struct bio *bio)
 {
-       return __part_start_io_acct(bio->bi_bdev, bio_sectors(bio), bio_op(bio));
+       return __part_start_io_acct(bio->bi_bdev, bio_sectors(bio),
+                                   bio_op(bio), jiffies);
 }
 EXPORT_SYMBOL_GPL(bio_start_io_acct);
 
 unsigned long disk_start_io_acct(struct gendisk *disk, unsigned int sectors,
                                 unsigned int op)
 {
-       return __part_start_io_acct(disk->part0, sectors, op);
+       return __part_start_io_acct(disk->part0, sectors, op, jiffies);
 }
 EXPORT_SYMBOL(disk_start_io_acct);
 
index b925f3d..18c68d8 100644 (file)
@@ -144,7 +144,7 @@ int disk_register_independent_access_ranges(struct gendisk *disk,
                                   &q->kobj, "%s", "independent_access_ranges");
        if (ret) {
                q->ia_ranges = NULL;
-               kfree(iars);
+               kobject_put(&iars->kobj);
                return ret;
        }
 
index f3bf335..1adfe48 100644 (file)
@@ -2922,6 +2922,8 @@ blk_status_t blk_insert_cloned_request(struct request_queue *q, struct request *
         */
        blk_mq_run_dispatch_ops(rq->q,
                        ret = blk_mq_request_issue_directly(rq, true));
+       if (ret)
+               blk_account_io_done(rq, ktime_get_ns());
        return ret;
 }
 EXPORT_SYMBOL_GPL(blk_insert_cloned_request);
index 26bf15c..4f59e0f 100644 (file)
@@ -566,34 +566,37 @@ static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
        struct block_device *bdev = iocb->ki_filp->private_data;
        loff_t size = bdev_nr_bytes(bdev);
-       size_t count = iov_iter_count(to);
        loff_t pos = iocb->ki_pos;
        size_t shorted = 0;
        ssize_t ret = 0;
+       size_t count;
 
-       if (unlikely(pos + count > size)) {
+       if (unlikely(pos + iov_iter_count(to) > size)) {
                if (pos >= size)
                        return 0;
                size -= pos;
-               if (count > size) {
-                       shorted = count - size;
-                       iov_iter_truncate(to, size);
-               }
+               shorted = iov_iter_count(to) - size;
+               iov_iter_truncate(to, size);
        }
 
+       count = iov_iter_count(to);
+       if (!count)
+               goto reexpand; /* skip atime */
+
        if (iocb->ki_flags & IOCB_DIRECT) {
                struct address_space *mapping = iocb->ki_filp->f_mapping;
 
                if (iocb->ki_flags & IOCB_NOWAIT) {
-                       if (filemap_range_needs_writeback(mapping, iocb->ki_pos,
-                                               iocb->ki_pos + count - 1))
-                               return -EAGAIN;
+                       if (filemap_range_needs_writeback(mapping, pos,
+                                                         pos + count - 1)) {
+                               ret = -EAGAIN;
+                               goto reexpand;
+                       }
                } else {
-                       ret = filemap_write_and_wait_range(mapping,
-                                               iocb->ki_pos,
-                                               iocb->ki_pos + count - 1);
+                       ret = filemap_write_and_wait_range(mapping, pos,
+                                                          pos + count - 1);
                        if (ret < 0)
-                               return ret;
+                               goto reexpand;
                }
 
                file_accessed(iocb->ki_filp);
@@ -603,12 +606,14 @@ static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
                        iocb->ki_pos += ret;
                        count -= ret;
                }
+               iov_iter_revert(to, count - iov_iter_count(to));
                if (ret < 0 || !count)
-                       return ret;
+                       goto reexpand;
        }
 
        ret = filemap_read(iocb, to, ret);
 
+reexpand:
        if (unlikely(shorted))
                iov_iter_reexpand(to, iov_iter_count(to) + shorted);
        return ret;
index a366cb3..76fdaa1 100644 (file)
@@ -1324,3 +1324,4 @@ module_exit(crypto_algapi_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Cryptographic algorithms API");
+MODULE_SOFTDEP("pre: cryptomgr");
index cf0869d..7ddfe94 100644 (file)
@@ -643,4 +643,3 @@ EXPORT_SYMBOL_GPL(crypto_req_done);
 
 MODULE_DESCRIPTION("Cryptographic core API");
 MODULE_LICENSE("GPL");
-MODULE_SOFTDEP("pre: cryptomgr");
index 72fe480..5f96a21 100644 (file)
 static int crypto_blake2s_update_generic(struct shash_desc *desc,
                                         const u8 *in, unsigned int inlen)
 {
-       return crypto_blake2s_update(desc, in, inlen, blake2s_compress_generic);
+       return crypto_blake2s_update(desc, in, inlen, true);
 }
 
 static int crypto_blake2s_final_generic(struct shash_desc *desc, u8 *out)
 {
-       return crypto_blake2s_final(desc, out, blake2s_compress_generic);
+       return crypto_blake2s_final(desc, out, true);
 }
 
 #define BLAKE2S_ALG(name, driver_name, digest_size)                    \
index 580ec79..78ca498 100644 (file)
@@ -44,6 +44,7 @@ static struct var_t vars[] = {
        { CAPS_START, .u.s = {"[:dv ap 160] " } },
        { CAPS_STOP, .u.s = {"[:dv ap 100 ] " } },
        { RATE, .u.n = {"[:ra %d] ", 180, 75, 650, 0, 0, NULL } },
+       { PITCH, .u.n = {"[:dv ap %d] ", 122, 50, 350, 0, 0, NULL } },
        { INFLECTION, .u.n = {"[:dv pr %d] ", 100, 0, 10000, 0, 0, NULL } },
        { VOL, .u.n = {"[:dv g5 %d] ", 86, 60, 86, 0, 0, NULL } },
        { PUNCT, .u.n = {"[:pu %c] ", 0, 0, 2, 0, 0, "nsa" } },
index ba45541..273741d 100644 (file)
@@ -11,6 +11,7 @@ menuconfig ACPI
        depends on ARCH_SUPPORTS_ACPI
        select PNP
        select NLS
+       select CRC32
        default y if X86
        help
          Advanced Configuration and Power Interface (ACPI) support for 
index 3b23fb7..f2f8f05 100644 (file)
@@ -1361,9 +1361,17 @@ static void __init arm_smmu_v3_pmcg_init_resources(struct resource *res,
        res[0].start = pmcg->page0_base_address;
        res[0].end = pmcg->page0_base_address + SZ_4K - 1;
        res[0].flags = IORESOURCE_MEM;
-       res[1].start = pmcg->page1_base_address;
-       res[1].end = pmcg->page1_base_address + SZ_4K - 1;
-       res[1].flags = IORESOURCE_MEM;
+       /*
+        * The initial version in DEN0049C lacked a way to describe register
+        * page 1, which makes it broken for most PMCG implementations; in
+        * that case, just let the driver fail gracefully if it expects to
+        * find a second memory resource.
+        */
+       if (node->revision > 0) {
+               res[1].start = pmcg->page1_base_address;
+               res[1].end = pmcg->page1_base_address + SZ_4K - 1;
+               res[1].flags = IORESOURCE_MEM;
+       }
 
        if (pmcg->overflow_gsiv)
                acpi_iort_register_irq(pmcg->overflow_gsiv, "overflow",
index 0077d2c..4671038 100644 (file)
@@ -2065,6 +2065,16 @@ bool acpi_ec_dispatch_gpe(void)
        if (acpi_any_gpe_status_set(first_ec->gpe))
                return true;
 
+       /*
+        * Cancel the SCI wakeup and process all pending events in case there
+        * are any wakeup ones in there.
+        *
+        * Note that if any non-EC GPEs are active at this point, the SCI will
+        * retrigger after the rearming in acpi_s2idle_wake(), so no events
+        * should be missed by canceling the wakeup here.
+        */
+       pm_system_cancel_wakeup();
+
        /*
         * Dispatch the EC GPE in-band, but do not report wakeup in any case
         * to allow the caller to process events properly after that.
index a60ff5d..d4fbea9 100644 (file)
@@ -736,21 +736,15 @@ bool acpi_s2idle_wake(void)
                        return true;
                }
 
-               /* Check non-EC GPE wakeups and dispatch the EC GPE. */
+               /*
+                * Check non-EC GPE wakeups and if there are none, cancel the
+                * SCI-related wakeup and dispatch the EC GPE.
+                */
                if (acpi_ec_dispatch_gpe()) {
                        pm_pr_dbg("ACPI non-EC GPE wakeup\n");
                        return true;
                }
 
-               /*
-                * Cancel the SCI wakeup and process all pending events in case
-                * there are any wakeup ones in there.
-                *
-                * Note that if any non-EC GPEs are active at this point, the
-                * SCI will retrigger after the rearming below, so no events
-                * should be missed by canceling the wakeup here.
-                */
-               pm_system_cancel_wakeup();
                acpi_os_wait_events_complete();
 
                /*
@@ -764,6 +758,7 @@ bool acpi_s2idle_wake(void)
                        return true;
                }
 
+               pm_wakeup_clear(acpi_sci_irq);
                rearm_wake_irq(acpi_sci_irq);
        }
 
index abc06e7..ed889f8 100644 (file)
@@ -424,15 +424,11 @@ static int lps0_device_attach(struct acpi_device *adev,
                mem_sleep_current = PM_SUSPEND_TO_IDLE;
 
        /*
-        * Some Intel based LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U don't
-        * use intel-hid or intel-vbtn but require the EC GPE to be enabled while
-        * suspended for certain wakeup devices to work, so mark it as wakeup-capable.
-        *
-        * Only enable on !AMD as enabling this universally causes problems for a number
-        * of AMD based systems.
+        * Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the
+        * EC GPE to be enabled while suspended for certain wakeup devices to
+        * work, so mark it as wakeup-capable.
         */
-       if (!acpi_s2idle_vendor_amd())
-               acpi_ec_mark_gpe_for_wake();
+       acpi_ec_mark_gpe_for_wake();
 
        return 0;
 }
index 67f8802..0c854ae 100644 (file)
@@ -2007,6 +2007,9 @@ static bool ata_log_supported(struct ata_device *dev, u8 log)
 {
        struct ata_port *ap = dev->link->ap;
 
+       if (dev->horkage & ATA_HORKAGE_NO_LOG_DIR)
+               return false;
+
        if (ata_read_log_page(dev, ATA_LOG_DIRECTORY, 0, ap->sector_buf, 1))
                return false;
        return get_unaligned_le16(&ap->sector_buf[log * 2]) ? true : false;
@@ -2445,23 +2448,21 @@ static void ata_dev_config_cpr(struct ata_device *dev)
        struct ata_cpr_log *cpr_log = NULL;
        u8 *desc, *buf = NULL;
 
-       if (!ata_identify_page_supported(dev,
-                                ATA_LOG_CONCURRENT_POSITIONING_RANGES))
+       if (ata_id_major_version(dev->id) < 11 ||
+           !ata_log_supported(dev, ATA_LOG_CONCURRENT_POSITIONING_RANGES))
                goto out;
 
        /*
-        * Read IDENTIFY DEVICE data log, page 0x47
-        * (concurrent positioning ranges). We can have at most 255 32B range
-        * descriptors plus a 64B header.
+        * Read the concurrent positioning ranges log (0x47). We can have at
+        * most 255 32B range descriptors plus a 64B header.
         */
        buf_len = (64 + 255 * 32 + 511) & ~511;
        buf = kzalloc(buf_len, GFP_KERNEL);
        if (!buf)
                goto out;
 
-       err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE,
-                                    ATA_LOG_CONCURRENT_POSITIONING_RANGES,
-                                    buf, buf_len >> 9);
+       err_mask = ata_read_log_page(dev, ATA_LOG_CONCURRENT_POSITIONING_RANGES,
+                                    0, buf, buf_len >> 9);
        if (err_mask)
                goto out;
 
@@ -4028,6 +4029,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
 
        /* devices that don't properly handle TRIM commands */
        { "SuperSSpeed S238*",          NULL,   ATA_HORKAGE_NOTRIM, },
+       { "M88V29*",                    NULL,   ATA_HORKAGE_NOTRIM, },
 
        /*
         * As defined, the DRAT (Deterministic Read After Trim) and RZAT
@@ -4073,6 +4075,13 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "WDC WD3000JD-*",             NULL,   ATA_HORKAGE_WD_BROKEN_LPM },
        { "WDC WD3200JD-*",             NULL,   ATA_HORKAGE_WD_BROKEN_LPM },
 
+       /*
+        * This sata dom device goes on a walkabout when the ATA_LOG_DIRECTORY
+        * log page is accessed. Ensure we never ask for this log page with
+        * these devices.
+        */
+       { "SATADOM-ML 3ME",             NULL,   ATA_HORKAGE_NO_LOG_DIR },
+
        /* End Marker */
        { }
 };
index 0283294..87c7c90 100644 (file)
@@ -128,6 +128,8 @@ int __pata_platform_probe(struct device *dev, struct resource *io_res,
        ap = host->ports[0];
 
        ap->ops = devm_kzalloc(dev, sizeof(*ap->ops), GFP_KERNEL);
+       if (!ap->ops)
+               return -ENOMEM;
        ap->ops->inherits = &ata_sff_port_ops;
        ap->ops->cable_detect = ata_cable_unknown;
        ap->ops->set_mode = pata_platform_set_mode;
index da01521..556034a 100644 (file)
@@ -322,7 +322,7 @@ static void fsl_sata_set_irq_coalescing(struct ata_host *host,
 static ssize_t fsl_sata_intr_coalescing_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       return sysfs_emit(buf, "%d      %d\n",
+       return sysfs_emit(buf, "%u      %u\n",
                        intr_coalescing_count, intr_coalescing_ticks);
 }
 
@@ -332,10 +332,8 @@ static ssize_t fsl_sata_intr_coalescing_store(struct device *dev,
 {
        unsigned int coalescing_count,  coalescing_ticks;
 
-       if (sscanf(buf, "%d%d",
-                               &coalescing_count,
-                               &coalescing_ticks) != 2) {
-               printk(KERN_ERR "fsl-sata: wrong parameter format.\n");
+       if (sscanf(buf, "%u%u", &coalescing_count, &coalescing_ticks) != 2) {
+               dev_err(dev, "fsl-sata: wrong parameter format.\n");
                return -EINVAL;
        }
 
@@ -359,7 +357,7 @@ static ssize_t fsl_sata_rx_watermark_show(struct device *dev,
        rx_watermark &= 0x1f;
        spin_unlock_irqrestore(&host->lock, flags);
 
-       return sysfs_emit(buf, "%d\n", rx_watermark);
+       return sysfs_emit(buf, "%u\n", rx_watermark);
 }
 
 static ssize_t fsl_sata_rx_watermark_store(struct device *dev,
@@ -373,8 +371,8 @@ static ssize_t fsl_sata_rx_watermark_store(struct device *dev,
        void __iomem *csr_base = host_priv->csr_base;
        u32 temp;
 
-       if (sscanf(buf, "%d", &rx_watermark) != 1) {
-               printk(KERN_ERR "fsl-sata: wrong parameter format.\n");
+       if (kstrtouint(buf, 10, &rx_watermark) < 0) {
+               dev_err(dev, "fsl-sata: wrong parameter format.\n");
                return -EINVAL;
        }
 
@@ -382,8 +380,8 @@ static ssize_t fsl_sata_rx_watermark_store(struct device *dev,
        temp = ioread32(csr_base + TRANSCFG);
        temp &= 0xffffffe0;
        iowrite32(temp | rx_watermark, csr_base + TRANSCFG);
-
        spin_unlock_irqrestore(&host->lock, flags);
+
        return strlen(buf);
 }
 
index 99bda0d..8666590 100644 (file)
@@ -34,7 +34,8 @@ suspend_state_t pm_suspend_target_state;
 bool events_check_enabled __read_mostly;
 
 /* First wakeup IRQ seen by the kernel in the last cycle. */
-unsigned int pm_wakeup_irq __read_mostly;
+static unsigned int wakeup_irq[2] __read_mostly;
+static DEFINE_RAW_SPINLOCK(wakeup_irq_lock);
 
 /* If greater than 0 and the system is suspending, terminate the suspend. */
 static atomic_t pm_abort_suspend __read_mostly;
@@ -942,19 +943,45 @@ void pm_system_cancel_wakeup(void)
        atomic_dec_if_positive(&pm_abort_suspend);
 }
 
-void pm_wakeup_clear(bool reset)
+void pm_wakeup_clear(unsigned int irq_number)
 {
-       pm_wakeup_irq = 0;
-       if (reset)
+       raw_spin_lock_irq(&wakeup_irq_lock);
+
+       if (irq_number && wakeup_irq[0] == irq_number)
+               wakeup_irq[0] = wakeup_irq[1];
+       else
+               wakeup_irq[0] = 0;
+
+       wakeup_irq[1] = 0;
+
+       raw_spin_unlock_irq(&wakeup_irq_lock);
+
+       if (!irq_number)
                atomic_set(&pm_abort_suspend, 0);
 }
 
 void pm_system_irq_wakeup(unsigned int irq_number)
 {
-       if (pm_wakeup_irq == 0) {
-               pm_wakeup_irq = irq_number;
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&wakeup_irq_lock, flags);
+
+       if (wakeup_irq[0] == 0)
+               wakeup_irq[0] = irq_number;
+       else if (wakeup_irq[1] == 0)
+               wakeup_irq[1] = irq_number;
+       else
+               irq_number = 0;
+
+       raw_spin_unlock_irqrestore(&wakeup_irq_lock, flags);
+
+       if (irq_number)
                pm_system_wakeup();
-       }
+}
+
+unsigned int pm_wakeup_irq(void)
+{
+       return wakeup_irq[0];
 }
 
 /**
index 01cbbfc..150012f 100644 (file)
@@ -1082,7 +1082,7 @@ out_putf:
        return error;
 }
 
-static void __loop_clr_fd(struct loop_device *lo)
+static void __loop_clr_fd(struct loop_device *lo, bool release)
 {
        struct file *filp;
        gfp_t gfp = lo->old_gfp_mask;
@@ -1144,6 +1144,8 @@ static void __loop_clr_fd(struct loop_device *lo)
        /* let user-space know about this change */
        kobject_uevent(&disk_to_dev(lo->lo_disk)->kobj, KOBJ_CHANGE);
        mapping_set_gfp_mask(filp->f_mapping, gfp);
+       /* This is safe: open() is still holding a reference. */
+       module_put(THIS_MODULE);
        blk_mq_unfreeze_queue(lo->lo_queue);
 
        disk_force_media_change(lo->lo_disk, DISK_EVENT_MEDIA_CHANGE);
@@ -1151,52 +1153,44 @@ static void __loop_clr_fd(struct loop_device *lo)
        if (lo->lo_flags & LO_FLAGS_PARTSCAN) {
                int err;
 
-               mutex_lock(&lo->lo_disk->open_mutex);
+               /*
+                * open_mutex has been held already in release path, so don't
+                * acquire it if this function is called in such case.
+                *
+                * If the reread partition isn't from release path, lo_refcnt
+                * must be at least one and it can only become zero when the
+                * current holder is released.
+                */
+               if (!release)
+                       mutex_lock(&lo->lo_disk->open_mutex);
                err = bdev_disk_changed(lo->lo_disk, false);
-               mutex_unlock(&lo->lo_disk->open_mutex);
+               if (!release)
+                       mutex_unlock(&lo->lo_disk->open_mutex);
                if (err)
                        pr_warn("%s: partition scan of loop%d failed (rc=%d)\n",
                                __func__, lo->lo_number, err);
                /* Device is gone, no point in returning error */
        }
 
+       /*
+        * lo->lo_state is set to Lo_unbound here after above partscan has
+        * finished. There cannot be anybody else entering __loop_clr_fd() as
+        * Lo_rundown state protects us from all the other places trying to
+        * change the 'lo' device.
+        */
        lo->lo_flags = 0;
        if (!part_shift)
                lo->lo_disk->flags |= GENHD_FL_NO_PART;
-
-       fput(filp);
-}
-
-static void loop_rundown_completed(struct loop_device *lo)
-{
        mutex_lock(&lo->lo_mutex);
        lo->lo_state = Lo_unbound;
        mutex_unlock(&lo->lo_mutex);
-       module_put(THIS_MODULE);
-}
-
-static void loop_rundown_workfn(struct work_struct *work)
-{
-       struct loop_device *lo = container_of(work, struct loop_device,
-                                             rundown_work);
-       struct block_device *bdev = lo->lo_device;
-       struct gendisk *disk = lo->lo_disk;
-
-       __loop_clr_fd(lo);
-       kobject_put(&bdev->bd_device.kobj);
-       module_put(disk->fops->owner);
-       loop_rundown_completed(lo);
-}
 
-static void loop_schedule_rundown(struct loop_device *lo)
-{
-       struct block_device *bdev = lo->lo_device;
-       struct gendisk *disk = lo->lo_disk;
-
-       __module_get(disk->fops->owner);
-       kobject_get(&bdev->bd_device.kobj);
-       INIT_WORK(&lo->rundown_work, loop_rundown_workfn);
-       queue_work(system_long_wq, &lo->rundown_work);
+       /*
+        * Need not hold lo_mutex to fput backing file. Calling fput holding
+        * lo_mutex triggers a circular lock dependency possibility warning as
+        * fput can take open_mutex which is usually taken before lo_mutex.
+        */
+       fput(filp);
 }
 
 static int loop_clr_fd(struct loop_device *lo)
@@ -1228,8 +1222,7 @@ static int loop_clr_fd(struct loop_device *lo)
        lo->lo_state = Lo_rundown;
        mutex_unlock(&lo->lo_mutex);
 
-       __loop_clr_fd(lo);
-       loop_rundown_completed(lo);
+       __loop_clr_fd(lo, false);
        return 0;
 }
 
@@ -1754,7 +1747,7 @@ static void lo_release(struct gendisk *disk, fmode_t mode)
                 * In autoclear mode, stop the loop thread
                 * and remove configuration after last close.
                 */
-               loop_schedule_rundown(lo);
+               __loop_clr_fd(lo, true);
                return;
        } else if (lo->lo_state == Lo_bound) {
                /*
index 918a7a2..082d4b6 100644 (file)
@@ -56,7 +56,6 @@ struct loop_device {
        struct gendisk          *lo_disk;
        struct mutex            lo_mutex;
        bool                    idr_visible;
-       struct work_struct      rundown_work;
 };
 
 struct loop_cmd {
index 3a258a6..b798958 100644 (file)
@@ -366,6 +366,7 @@ static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = {
        .config = &modem_foxconn_sdx55_config,
        .bar_num = MHI_PCI_DEFAULT_BAR_NUM,
        .dma_data_width = 32,
+       .mru_default = 32768,
        .sideband_wake = false,
 };
 
@@ -401,6 +402,7 @@ static const struct mhi_pci_dev_info mhi_mv31_info = {
        .config = &modem_mv31_config,
        .bar_num = MHI_PCI_DEFAULT_BAR_NUM,
        .dma_data_width = 32,
+       .mru_default = 32768,
 };
 
 static const struct mhi_channel_config mhi_sierra_em919x_channels[] = {
index 68613f0..3404a91 100644 (file)
@@ -762,7 +762,7 @@ static bool crng_init_try_arch(struct crng_state *crng)
        return arch_init;
 }
 
-static bool __init crng_init_try_arch_early(struct crng_state *crng)
+static bool __init crng_init_try_arch_early(void)
 {
        int i;
        bool arch_init = true;
@@ -774,7 +774,7 @@ static bool __init crng_init_try_arch_early(struct crng_state *crng)
                        rv = random_get_entropy();
                        arch_init = false;
                }
-               crng->state[i] ^= rv;
+               primary_crng.state[i] ^= rv;
        }
 
        return arch_init;
@@ -788,22 +788,20 @@ static void crng_initialize_secondary(struct crng_state *crng)
        crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
 }
 
-static void __init crng_initialize_primary(struct crng_state *crng)
+static void __init crng_initialize_primary(void)
 {
-       _extract_entropy(&crng->state[4], sizeof(u32) * 12);
-       if (crng_init_try_arch_early(crng) && trust_cpu && crng_init < 2) {
+       _extract_entropy(&primary_crng.state[4], sizeof(u32) * 12);
+       if (crng_init_try_arch_early() && trust_cpu && crng_init < 2) {
                invalidate_batched_entropy();
                numa_crng_init();
                crng_init = 2;
                pr_notice("crng init done (trusting CPU's manufacturer)\n");
        }
-       crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
+       primary_crng.init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
 }
 
-static void crng_finalize_init(struct crng_state *crng)
+static void crng_finalize_init(void)
 {
-       if (crng != &primary_crng || crng_init >= 2)
-               return;
        if (!system_wq) {
                /* We can't call numa_crng_init until we have workqueues,
                 * so mark this for processing later. */
@@ -814,6 +812,7 @@ static void crng_finalize_init(struct crng_state *crng)
        invalidate_batched_entropy();
        numa_crng_init();
        crng_init = 2;
+       crng_need_final_init = false;
        process_random_ready_list();
        wake_up_interruptible(&crng_init_wait);
        kill_fasync(&fasync, SIGIO, POLL_IN);
@@ -980,7 +979,8 @@ static void crng_reseed(struct crng_state *crng, bool use_input_pool)
        memzero_explicit(&buf, sizeof(buf));
        WRITE_ONCE(crng->init_time, jiffies);
        spin_unlock_irqrestore(&crng->lock, flags);
-       crng_finalize_init(crng);
+       if (crng == &primary_crng && crng_init < 2)
+               crng_finalize_init();
 }
 
 static void _extract_crng(struct crng_state *crng, u8 out[CHACHA_BLOCK_SIZE])
@@ -1697,8 +1697,8 @@ int __init rand_initialize(void)
 {
        init_std_data();
        if (crng_need_final_init)
-               crng_finalize_init(&primary_crng);
-       crng_initialize_primary(&primary_crng);
+               crng_finalize_init();
+       crng_initialize_primary();
        crng_global_init_time = jiffies;
        if (ratelimit_disable) {
                urandom_warning.interval = 0;
@@ -1856,7 +1856,10 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
                 */
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               input_pool.entropy_count = 0;
+               if (xchg(&input_pool.entropy_count, 0) && random_write_wakeup_bits) {
+                       wake_up_interruptible(&random_write_wait);
+                       kill_fasync(&fasync, SIGIO, POLL_OUT);
+               }
                return 0;
        case RNDRESEEDCRNG:
                if (!capable(CAP_SYS_ADMIN))
@@ -2205,13 +2208,15 @@ void add_hwgenerator_randomness(const char *buffer, size_t count,
                        return;
        }
 
-       /* Suspend writing if we're above the trickle threshold.
+       /* Throttle writing if we're above the trickle threshold.
         * We'll be woken up again once below random_write_wakeup_thresh,
-        * or when the calling thread is about to terminate.
+        * when the calling thread is about to terminate, or once
+        * CRNG_RESEED_INTERVAL has lapsed.
         */
-       wait_event_interruptible(random_write_wait,
+       wait_event_interruptible_timeout(random_write_wait,
                        !system_wq || kthread_should_stop() ||
-                       POOL_ENTROPY_BITS() <= random_write_wakeup_bits);
+                       POOL_ENTROPY_BITS() <= random_write_wakeup_bits,
+                       CRNG_RESEED_INTERVAL);
        mix_pool_bytes(buffer, count);
        credit_entropy_bits(entropy);
 }
diff --git a/drivers/clk/.kunitconfig b/drivers/clk/.kunitconfig
new file mode 100644 (file)
index 0000000..3754fdb
--- /dev/null
@@ -0,0 +1,3 @@
+CONFIG_KUNIT=y
+CONFIG_COMMON_CLK=y
+CONFIG_CLK_GATE_KUNIT_TEST=y
index ad4256d..2f0d40b 100644 (file)
@@ -197,6 +197,7 @@ config COMMON_CLK_CDCE925
 config COMMON_CLK_CS2000_CP
        tristate "Clock driver for CS2000 Fractional-N Clock Synthesizer & Clock Multiplier"
        depends on I2C
+       select REGMAP_I2C
        help
          If you say yes here you get support for the CS2000 clock multiplier.
 
@@ -330,9 +331,6 @@ config COMMON_CLK_PXA
        help
          Support for the Marvell PXA SoC.
 
-config COMMON_CLK_PIC32
-       def_bool COMMON_CLK && MACH_PIC32
-
 config COMMON_CLK_OXNAS
        bool "Clock driver for the OXNAS SoC Family"
        depends on ARCH_OXNAS || COMPILE_TEST
@@ -340,6 +338,15 @@ config COMMON_CLK_OXNAS
        help
          Support for the OXNAS SoC Family clocks.
 
+config COMMON_CLK_RS9_PCIE
+       tristate "Clock driver for Renesas 9-series PCIe clock generators"
+       depends on I2C
+       depends on OF
+       select REGMAP_I2C
+       help
+         This driver supports the Renesas 9-series PCIe clock generator
+         models 9FGV/9DBV/9DMV/9FGL/9DML/9QXL/9SQ.
+
 config COMMON_CLK_VC5
        tristate "Clock driver for IDT VersaClock 5,6 devices"
        depends on I2C
@@ -407,6 +414,7 @@ source "drivers/clk/keystone/Kconfig"
 source "drivers/clk/mediatek/Kconfig"
 source "drivers/clk/meson/Kconfig"
 source "drivers/clk/mstar/Kconfig"
+source "drivers/clk/microchip/Kconfig"
 source "drivers/clk/mvebu/Kconfig"
 source "drivers/clk/pistachio/Kconfig"
 source "drivers/clk/qcom/Kconfig"
@@ -428,4 +436,12 @@ source "drivers/clk/x86/Kconfig"
 source "drivers/clk/xilinx/Kconfig"
 source "drivers/clk/zynqmp/Kconfig"
 
+# Kunit test cases
+config CLK_GATE_KUNIT_TEST
+       tristate "Basic gate type Kunit test" if !KUNIT_ALL_TESTS
+       depends on KUNIT
+       default KUNIT_ALL_TESTS
+       help
+         Kunit test for the basic clk gate type.
+
 endif
index 16e5886..5b2eaf5 100644 (file)
@@ -6,6 +6,7 @@ obj-$(CONFIG_COMMON_CLK)        += clk-divider.o
 obj-$(CONFIG_COMMON_CLK)       += clk-fixed-factor.o
 obj-$(CONFIG_COMMON_CLK)       += clk-fixed-rate.o
 obj-$(CONFIG_COMMON_CLK)       += clk-gate.o
+obj-$(CONFIG_CLK_GATE_KUNIT_TEST) += clk-gate_test.o
 obj-$(CONFIG_COMMON_CLK)       += clk-multiplier.o
 obj-$(CONFIG_COMMON_CLK)       += clk-mux.o
 obj-$(CONFIG_COMMON_CLK)       += clk-composite.o
@@ -67,6 +68,7 @@ obj-$(CONFIG_COMMON_CLK_STM32MP157)   += clk-stm32mp1.o
 obj-$(CONFIG_COMMON_CLK_TPS68470)      += clk-tps68470.o
 obj-$(CONFIG_CLK_TWL6040)              += clk-twl6040.o
 obj-$(CONFIG_ARCH_VT8500)              += clk-vt8500.o
+obj-$(CONFIG_COMMON_CLK_RS9_PCIE)      += clk-renesas-pcie.o
 obj-$(CONFIG_COMMON_CLK_VC5)           += clk-versaclock5.o
 obj-$(CONFIG_COMMON_CLK_WM831X)                += clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_XGENE)         += clk-xgene.o
@@ -91,7 +93,7 @@ obj-$(CONFIG_ARCH_KEYSTONE)           += keystone/
 obj-$(CONFIG_MACH_LOONGSON32)          += loongson1/
 obj-y                                  += mediatek/
 obj-$(CONFIG_ARCH_MESON)               += meson/
-obj-$(CONFIG_MACH_PIC32)               += microchip/
+obj-y                                  += microchip/
 ifeq ($(CONFIG_COMMON_CLK), y)
 obj-$(CONFIG_ARCH_MMP)                 += mmp/
 endif
index fff4fdd..b174f72 100644 (file)
@@ -143,8 +143,7 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
                                           parent_names,
                                           &at91rm9200_master_layout,
                                           &rm9200_mck_characteristics,
-                                          &rm9200_mck_lock, CLK_SET_RATE_GATE,
-                                          INT_MIN);
+                                          &rm9200_mck_lock);
        if (IS_ERR(hw))
                goto err_free;
 
index 79802f8..11550e5 100644 (file)
@@ -419,8 +419,7 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
                                           parent_names,
                                           &at91rm9200_master_layout,
                                           data->mck_characteristics,
-                                          &at91sam9260_mck_lock,
-                                          CLK_SET_RATE_GATE, INT_MIN);
+                                          &at91sam9260_mck_lock);
        if (IS_ERR(hw))
                goto err_free;
 
index 7ed984f..8c93444 100644 (file)
@@ -154,8 +154,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
                                           parent_names,
                                           &at91rm9200_master_layout,
                                           &mck_characteristics,
-                                          &at91sam9g45_mck_lock,
-                                          CLK_SET_RATE_GATE, INT_MIN);
+                                          &at91sam9g45_mck_lock);
        if (IS_ERR(hw))
                goto err_free;
 
index 63cc589..0bb1940 100644 (file)
@@ -181,8 +181,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
                                           parent_names,
                                           &at91sam9x5_master_layout,
                                           &mck_characteristics,
-                                          &at91sam9n12_mck_lock,
-                                          CLK_SET_RATE_GATE, INT_MIN);
+                                          &at91sam9n12_mck_lock);
        if (IS_ERR(hw))
                goto err_free;
 
index 4d4faf6..b992137 100644 (file)
@@ -123,8 +123,7 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
                                           parent_names,
                                           &at91rm9200_master_layout,
                                           &sam9rl_mck_characteristics,
-                                          &sam9rl_mck_lock, CLK_SET_RATE_GATE,
-                                          INT_MIN);
+                                          &sam9rl_mck_lock);
        if (IS_ERR(hw))
                goto err_free;
 
index bd8007b..3857db2 100644 (file)
@@ -201,8 +201,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
        hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
                                           parent_names,
                                           &at91sam9x5_master_layout,
-                                          &mck_characteristics, &mck_lock,
-                                          CLK_SET_RATE_GATE, INT_MIN);
+                                          &mck_characteristics, &mck_lock);
        if (IS_ERR(hw))
                goto err_free;
 
index b2d0a7f..164e295 100644 (file)
@@ -374,85 +374,6 @@ static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
        }
 }
 
-static int clk_master_pres_determine_rate(struct clk_hw *hw,
-                                         struct clk_rate_request *req)
-{
-       struct clk_master *master = to_clk_master(hw);
-       struct clk_rate_request req_parent = *req;
-       const struct clk_master_characteristics *characteristics =
-                                                       master->characteristics;
-       struct clk_hw *parent;
-       long best_rate = LONG_MIN, best_diff = LONG_MIN;
-       u32 pres;
-       int i;
-
-       if (master->chg_pid < 0)
-               return -EOPNOTSUPP;
-
-       parent = clk_hw_get_parent_by_index(hw, master->chg_pid);
-       if (!parent)
-               return -EOPNOTSUPP;
-
-       for (i = 0; i <= MASTER_PRES_MAX; i++) {
-               if (characteristics->have_div3_pres && i == MASTER_PRES_MAX)
-                       pres = 3;
-               else
-                       pres = 1 << i;
-
-               req_parent.rate = req->rate * pres;
-               if (__clk_determine_rate(parent, &req_parent))
-                       continue;
-
-               clk_sama7g5_master_best_diff(req, parent, req_parent.rate,
-                                            &best_diff, &best_rate, pres);
-               if (!best_diff)
-                       break;
-       }
-
-       return 0;
-}
-
-static int clk_master_pres_set_rate(struct clk_hw *hw, unsigned long rate,
-                                   unsigned long parent_rate)
-{
-       struct clk_master *master = to_clk_master(hw);
-       unsigned long flags;
-       unsigned int pres, mckr, tmp;
-       int ret;
-
-       pres = DIV_ROUND_CLOSEST(parent_rate, rate);
-       if (pres > MASTER_PRES_MAX)
-               return -EINVAL;
-
-       else if (pres == 3)
-               pres = MASTER_PRES_MAX;
-       else if (pres)
-               pres = ffs(pres) - 1;
-
-       spin_lock_irqsave(master->lock, flags);
-       ret = regmap_read(master->regmap, master->layout->offset, &mckr);
-       if (ret)
-               goto unlock;
-
-       mckr &= master->layout->mask;
-       tmp = (mckr >> master->layout->pres_shift) & MASTER_PRES_MASK;
-       if (pres == tmp)
-               goto unlock;
-
-       mckr &= ~(MASTER_PRES_MASK << master->layout->pres_shift);
-       mckr |= (pres << master->layout->pres_shift);
-       ret = regmap_write(master->regmap, master->layout->offset, mckr);
-       if (ret)
-               goto unlock;
-
-       while (!clk_master_ready(master))
-               cpu_relax();
-unlock:
-       spin_unlock_irqrestore(master->lock, flags);
-
-       return ret;
-}
-
 static unsigned long clk_master_pres_recalc_rate(struct clk_hw *hw,
                                                 unsigned long parent_rate)
 {
@@ -539,13 +460,6 @@ static void clk_master_pres_restore_context(struct clk_hw *hw)
                pr_warn("MCKR PRES was not configured properly by firmware!\n");
 }
 
-static void clk_master_pres_restore_context_chg(struct clk_hw *hw)
-{
-       struct clk_master *master = to_clk_master(hw);
-
-       clk_master_pres_set_rate(hw, master->pms.rate, master->pms.parent_rate);
-}
-
 static const struct clk_ops master_pres_ops = {
        .prepare = clk_master_prepare,
        .is_prepared = clk_master_is_prepared,
@@ -555,25 +469,13 @@ static const struct clk_ops master_pres_ops = {
        .restore_context = clk_master_pres_restore_context,
 };
 
-static const struct clk_ops master_pres_ops_chg = {
-       .prepare = clk_master_prepare,
-       .is_prepared = clk_master_is_prepared,
-       .determine_rate = clk_master_pres_determine_rate,
-       .recalc_rate = clk_master_pres_recalc_rate,
-       .get_parent = clk_master_pres_get_parent,
-       .set_rate = clk_master_pres_set_rate,
-       .save_context = clk_master_pres_save_context,
-       .restore_context = clk_master_pres_restore_context_chg,
-};
-
 static struct clk_hw * __init
 at91_clk_register_master_internal(struct regmap *regmap,
                const char *name, int num_parents,
                const char **parent_names,
                const struct clk_master_layout *layout,
                const struct clk_master_characteristics *characteristics,
-               const struct clk_ops *ops, spinlock_t *lock, u32 flags,
-               int chg_pid)
+               const struct clk_ops *ops, spinlock_t *lock, u32 flags)
 {
        struct clk_master *master;
        struct clk_init_data init;
@@ -599,7 +501,6 @@ at91_clk_register_master_internal(struct regmap *regmap,
        master->layout = layout;
        master->characteristics = characteristics;
        master->regmap = regmap;
-       master->chg_pid = chg_pid;
        master->lock = lock;
 
        if (ops == &master_div_ops_chg) {
@@ -628,19 +529,13 @@ at91_clk_register_master_pres(struct regmap *regmap,
                const char **parent_names,
                const struct clk_master_layout *layout,
                const struct clk_master_characteristics *characteristics,
-               spinlock_t *lock, u32 flags, int chg_pid)
+               spinlock_t *lock)
 {
-       const struct clk_ops *ops;
-
-       if (flags & CLK_SET_RATE_GATE)
-               ops = &master_pres_ops;
-       else
-               ops = &master_pres_ops_chg;
-
        return at91_clk_register_master_internal(regmap, name, num_parents,
                                                 parent_names, layout,
-                                                characteristics, ops,
-                                                lock, flags, chg_pid);
+                                                characteristics,
+                                                &master_pres_ops,
+                                                lock, CLK_SET_RATE_GATE);
 }
 
 struct clk_hw * __init
@@ -661,7 +556,7 @@ at91_clk_register_master_div(struct regmap *regmap,
        hw = at91_clk_register_master_internal(regmap, name, 1,
                                               &parent_name, layout,
                                               characteristics, ops,
-                                              lock, flags, -EINVAL);
+                                              lock, flags);
 
        if (!IS_ERR(hw) && safe_div) {
                master_div = to_clk_master(hw);
index ca2dbb6..8ca8bca 100644 (file)
@@ -392,8 +392,7 @@ of_at91_clk_master_setup(struct device_node *np,
 
        hw = at91_clk_register_master_pres(regmap, "masterck_pres", num_parents,
                                           parent_names, layout,
-                                          characteristics, &mck_lock,
-                                          CLK_SET_RATE_GATE, INT_MIN);
+                                          characteristics, &mck_lock);
        if (IS_ERR(hw))
                goto out_free_characteristics;
 
index 3a1bf61..efe4975 100644 (file)
@@ -175,7 +175,7 @@ at91_clk_register_master_pres(struct regmap *regmap, const char *name,
                              int num_parents, const char **parent_names,
                              const struct clk_master_layout *layout,
                              const struct clk_master_characteristics *characteristics,
-                             spinlock_t *lock, u32 flags, int chg_pid);
+                             spinlock_t *lock);
 
 struct clk_hw * __init
 at91_clk_register_master_div(struct regmap *regmap, const char *name,
index 5c26418..9ea4ce5 100644 (file)
@@ -271,8 +271,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
        parent_names[2] = "pllack_divck";
        hw = at91_clk_register_master_pres(regmap, "masterck_pres", 3,
                                           parent_names, &sam9x60_master_layout,
-                                          &mck_characteristics, &mck_lock,
-                                          CLK_SET_RATE_GATE, INT_MIN);
+                                          &mck_characteristics, &mck_lock);
        if (IS_ERR(hw))
                goto err_free;
 
index d027294..cfd0f5e 100644 (file)
@@ -168,7 +168,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
        if (IS_ERR(regmap))
                return;
 
-       sama5d2_pmc = pmc_data_allocate(PMC_AUDIOPLLCK + 1,
+       sama5d2_pmc = pmc_data_allocate(PMC_AUDIOPINCK + 1,
                                        nck(sama5d2_systemck),
                                        nck(sama5d2_periph32ck),
                                        nck(sama5d2_gck), 3);
@@ -216,6 +216,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
        if (IS_ERR(hw))
                goto err_free;
 
+       sama5d2_pmc->chws[PMC_AUDIOPINCK] = hw;
+
        hw = at91_clk_register_audio_pll_pmc(regmap, "audiopll_pmcck",
                                             "audiopll_fracck");
        if (IS_ERR(hw))
@@ -240,8 +242,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
        hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
                                           parent_names,
                                           &at91sam9x5_master_layout,
-                                          &mck_characteristics, &mck_lock,
-                                          CLK_SET_RATE_GATE, INT_MIN);
+                                          &mck_characteristics, &mck_lock);
        if (IS_ERR(hw))
                goto err_free;
 
index 339d0f3..7e93c6e 100644 (file)
@@ -175,8 +175,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
        hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
                                           parent_names,
                                           &at91sam9x5_master_layout,
-                                          &mck_characteristics, &mck_lock,
-                                          CLK_SET_RATE_GATE, INT_MIN);
+                                          &mck_characteristics, &mck_lock);
        if (IS_ERR(hw))
                goto err_free;
 
index 4af75b1..1a14a9b 100644 (file)
@@ -190,8 +190,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
        hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
                                           parent_names,
                                           &at91sam9x5_master_layout,
-                                          &mck_characteristics, &mck_lock,
-                                          CLK_SET_RATE_GATE, INT_MIN);
+                                          &mck_characteristics, &mck_lock);
        if (IS_ERR(hw))
                goto err_free;
 
index 369dfaf..9a213ba 100644 (file)
@@ -302,6 +302,7 @@ static const struct {
  * @ep_count:          extra parents count
  * @ep_mux_table:      mux table for extra parents
  * @id:                        clock id
+ * @eid:               export index in sama7g5->chws[] array
  * @c:                 true if clock is critical and cannot be disabled
  */
 static const struct {
@@ -311,6 +312,7 @@ static const struct {
        u8 ep_count;
        u8 ep_mux_table[4];
        u8 id;
+       u8 eid;
        u8 c;
 } sama7g5_mckx[] = {
        { .n = "mck1",
@@ -319,6 +321,7 @@ static const struct {
          .ep_mux_table = { 5, },
          .ep_count = 1,
          .ep_chg_id = INT_MIN,
+         .eid = PMC_MCK1,
          .c = 1, },
 
        { .n = "mck2",
@@ -696,16 +699,16 @@ static const struct {
        { .n  = "pdmc0_gclk",
          .id = 68,
          .r = { .max = 50000000  },
-         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
-         .pp_mux_table = { 5, 8, },
+         .pp = { "syspll_divpmcck", "audiopll_divpmcck", },
+         .pp_mux_table = { 5, 9, },
          .pp_count = 2,
          .pp_chg_id = INT_MIN, },
 
        { .n  = "pdmc1_gclk",
          .id = 69,
          .r = { .max = 50000000, },
-         .pp = { "syspll_divpmcck", "baudpll_divpmcck", },
-         .pp_mux_table = { 5, 8, },
+         .pp = { "syspll_divpmcck", "audiopll_divpmcck", },
+         .pp_mux_table = { 5, 9, },
          .pp_count = 2,
          .pp_chg_id = INT_MIN, },
 
@@ -913,7 +916,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
        if (IS_ERR(regmap))
                return;
 
-       sama7g5_pmc = pmc_data_allocate(PMC_CPU + 1,
+       sama7g5_pmc = pmc_data_allocate(PMC_MCK1 + 1,
                                        nck(sama7g5_systemck),
                                        nck(sama7g5_periphck),
                                        nck(sama7g5_gck), 8);
@@ -1027,6 +1030,9 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
                        goto err_free;
 
                alloc_mem[alloc_mem_size++] = mux_table;
+
+               if (sama7g5_mckx[i].eid)
+                       sama7g5_pmc->chws[sama7g5_mckx[i].eid] = hw;
        }
 
        hw = at91_clk_sama7g5_register_utmi(regmap, "utmick", "main_xtal");
index 92bc4ac..dc5040a 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/i2c.h>
 #include <linux/of_device.h>
 #include <linux/module.h>
+#include <linux/regmap.h>
 
 #define CH_MAX 4
 #define RATIO_REG_SIZE 4
@@ -39,6 +40,8 @@
 /* DEVICE_CFG1 */
 #define RSEL(x)                (((x) & 0x3) << 3)
 #define RSEL_MASK      RSEL(0x3)
+#define AUXOUTSRC(x)   (((x) & 0x3) << 1)
+#define AUXOUTSRC_MASK AUXOUTSRC(0x3)
 #define ENDEV1         (0x1)
 
 /* DEVICE_CFG2 */
 #define LOCKCLK_MASK   LOCKCLK(0x3)
 #define FRACNSRC_MASK  (1 << 0)
 #define FRACNSRC_STATIC                (0 << 0)
-#define FRACNSRC_DYNAMIC       (1 << 1)
+#define FRACNSRC_DYNAMIC       (1 << 0)
 
 /* GLOBAL_CFG */
+#define FREEZE         (1 << 7)
 #define ENDEV2         (0x1)
 
 /* FUNC_CFG1 */
 #define REF_CLK        1
 #define CLK_MAX 2
 
+static bool cs2000_readable_reg(struct device *dev, unsigned int reg)
+{
+       return reg > 0;
+}
+
+static bool cs2000_writeable_reg(struct device *dev, unsigned int reg)
+{
+       return reg != DEVICE_ID;
+}
+
+static bool cs2000_volatile_reg(struct device *dev, unsigned int reg)
+{
+       return reg == DEVICE_CTRL;
+}
+
+static const struct regmap_config cs2000_regmap_config = {
+       .reg_bits       = 8,
+       .val_bits       = 8,
+       .max_register   = FUNC_CFG2,
+       .readable_reg   = cs2000_readable_reg,
+       .writeable_reg  = cs2000_writeable_reg,
+       .volatile_reg   = cs2000_volatile_reg,
+};
+
 struct cs2000_priv {
        struct clk_hw hw;
        struct i2c_client *client;
        struct clk *clk_in;
        struct clk *ref_clk;
+       struct regmap *regmap;
+
+       bool dynamic_mode;
+       bool lf_ratio;
+       bool clk_skip;
 
        /* suspend/resume */
        unsigned long saved_rate;
@@ -94,55 +127,30 @@ static const struct i2c_device_id cs2000_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, cs2000_id);
 
-#define cs2000_read(priv, addr) \
-       i2c_smbus_read_byte_data(priv_to_client(priv), addr)
-#define cs2000_write(priv, addr, val) \
-       i2c_smbus_write_byte_data(priv_to_client(priv), addr, val)
-
-static int cs2000_bset(struct cs2000_priv *priv, u8 addr, u8 mask, u8 val)
-{
-       s32 data;
-
-       data = cs2000_read(priv, addr);
-       if (data < 0)
-               return data;
-
-       data &= ~mask;
-       data |= (val & mask);
-
-       return cs2000_write(priv, addr, data);
-}
-
 static int cs2000_enable_dev_config(struct cs2000_priv *priv, bool enable)
 {
        int ret;
 
-       ret = cs2000_bset(priv, DEVICE_CFG1, ENDEV1,
-                         enable ? ENDEV1 : 0);
-       if (ret < 0)
-               return ret;
-
-       ret = cs2000_bset(priv, GLOBAL_CFG,  ENDEV2,
-                         enable ? ENDEV2 : 0);
+       ret = regmap_update_bits(priv->regmap, DEVICE_CFG1, ENDEV1,
+                                enable ? ENDEV1 : 0);
        if (ret < 0)
                return ret;
 
-       ret = cs2000_bset(priv, FUNC_CFG1, CLKSKIPEN,
-                         enable ? CLKSKIPEN : 0);
+       ret = regmap_update_bits(priv->regmap, GLOBAL_CFG,  ENDEV2,
+                                enable ? ENDEV2 : 0);
        if (ret < 0)
                return ret;
 
-       /* FIXME: for Static ratio mode */
-       ret = cs2000_bset(priv, FUNC_CFG2, LFRATIO_MASK,
-                         LFRATIO_12_20);
+       ret = regmap_update_bits(priv->regmap, FUNC_CFG1, CLKSKIPEN,
+                                (enable && priv->clk_skip) ? CLKSKIPEN : 0);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-static int cs2000_clk_in_bound_rate(struct cs2000_priv *priv,
-                                   u32 rate_in)
+static int cs2000_ref_clk_bound_rate(struct cs2000_priv *priv,
+                                    u32 rate_in)
 {
        u32 val;
 
@@ -155,21 +163,21 @@ static int cs2000_clk_in_bound_rate(struct cs2000_priv *priv,
        else
                return -EINVAL;
 
-       return cs2000_bset(priv, FUNC_CFG1,
-                          REFCLKDIV_MASK,
-                          REFCLKDIV(val));
+       return regmap_update_bits(priv->regmap, FUNC_CFG1,
+                                 REFCLKDIV_MASK,
+                                 REFCLKDIV(val));
 }
 
 static int cs2000_wait_pll_lock(struct cs2000_priv *priv)
 {
        struct device *dev = priv_to_dev(priv);
-       s32 val;
-       unsigned int i;
+       unsigned int i, val;
+       int ret;
 
        for (i = 0; i < 256; i++) {
-               val = cs2000_read(priv, DEVICE_CTRL);
-               if (val < 0)
-                       return val;
+               ret = regmap_read(priv->regmap, DEVICE_CTRL, &val);
+               if (ret < 0)
+                       return ret;
                if (!(val & PLL_UNLOCK))
                        return 0;
                udelay(1);
@@ -183,41 +191,43 @@ static int cs2000_wait_pll_lock(struct cs2000_priv *priv)
 static int cs2000_clk_out_enable(struct cs2000_priv *priv, bool enable)
 {
        /* enable both AUX_OUT, CLK_OUT */
-       return cs2000_bset(priv, DEVICE_CTRL,
-                          (AUXOUTDIS | CLKOUTDIS),
-                          enable ? 0 :
-                          (AUXOUTDIS | CLKOUTDIS));
+       return regmap_update_bits(priv->regmap, DEVICE_CTRL,
+                                 (AUXOUTDIS | CLKOUTDIS),
+                                 enable ? 0 :
+                                 (AUXOUTDIS | CLKOUTDIS));
 }
 
-static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out)
+static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out, bool lf_ratio)
 {
        u64 ratio;
+       u32 multiplier = lf_ratio ? 12 : 20;
 
        /*
-        * ratio = rate_out / rate_in * 2^20
+        * ratio = rate_out / rate_in * 2^multiplier
         *
         * To avoid over flow, rate_out is u64.
         * The result should be u32.
         */
-       ratio = (u64)rate_out << 20;
+       ratio = (u64)rate_out << multiplier;
        do_div(ratio, rate_in);
 
        return ratio;
 }
 
-static unsigned long cs2000_ratio_to_rate(u32 ratio, u32 rate_in)
+static unsigned long cs2000_ratio_to_rate(u32 ratio, u32 rate_in, bool lf_ratio)
 {
        u64 rate_out;
+       u32 multiplier = lf_ratio ? 12 : 20;
 
        /*
-        * ratio = rate_out / rate_in * 2^20
+        * ratio = rate_out / rate_in * 2^multiplier
         *
         * To avoid over flow, rate_out is u64.
         * The result should be u32 or unsigned long.
         */
 
        rate_out = (u64)ratio * rate_in;
-       return rate_out >> 20;
+       return rate_out >> multiplier;
 }
 
 static int cs2000_ratio_set(struct cs2000_priv *priv,
@@ -230,9 +240,9 @@ static int cs2000_ratio_set(struct cs2000_priv *priv,
        if (CH_SIZE_ERR(ch))
                return -EINVAL;
 
-       val = cs2000_rate_to_ratio(rate_in, rate_out);
+       val = cs2000_rate_to_ratio(rate_in, rate_out, priv->lf_ratio);
        for (i = 0; i < RATIO_REG_SIZE; i++) {
-               ret = cs2000_write(priv,
+               ret = regmap_write(priv->regmap,
                                   Ratio_Add(ch, i),
                                   Ratio_Val(val, i));
                if (ret < 0)
@@ -244,14 +254,14 @@ static int cs2000_ratio_set(struct cs2000_priv *priv,
 
 static u32 cs2000_ratio_get(struct cs2000_priv *priv, int ch)
 {
-       s32 tmp;
+       unsigned int tmp, i;
        u32 val;
-       unsigned int i;
+       int ret;
 
        val = 0;
        for (i = 0; i < RATIO_REG_SIZE; i++) {
-               tmp = cs2000_read(priv, Ratio_Add(ch, i));
-               if (tmp < 0)
+               ret = regmap_read(priv->regmap, Ratio_Add(ch, i), &tmp);
+               if (ret < 0)
                        return 0;
 
                val |= Val_Ratio(tmp, i);
@@ -263,22 +273,20 @@ static u32 cs2000_ratio_get(struct cs2000_priv *priv, int ch)
 static int cs2000_ratio_select(struct cs2000_priv *priv, int ch)
 {
        int ret;
+       u8 fracnsrc;
 
        if (CH_SIZE_ERR(ch))
                return -EINVAL;
 
-       /*
-        * FIXME
-        *
-        * this driver supports static ratio mode only at this point.
-        */
-       ret = cs2000_bset(priv, DEVICE_CFG1, RSEL_MASK, RSEL(ch));
+       ret = regmap_update_bits(priv->regmap, DEVICE_CFG1, RSEL_MASK, RSEL(ch));
        if (ret < 0)
                return ret;
 
-       ret = cs2000_bset(priv, DEVICE_CFG2,
-                         (AUTORMOD | LOCKCLK_MASK | FRACNSRC_MASK),
-                         (LOCKCLK(ch) | FRACNSRC_STATIC));
+       fracnsrc = priv->dynamic_mode ? FRACNSRC_DYNAMIC : FRACNSRC_STATIC;
+
+       ret = regmap_update_bits(priv->regmap, DEVICE_CFG2,
+                                AUTORMOD | LOCKCLK_MASK | FRACNSRC_MASK,
+                                LOCKCLK(ch) | fracnsrc);
        if (ret < 0)
                return ret;
 
@@ -294,17 +302,39 @@ static unsigned long cs2000_recalc_rate(struct clk_hw *hw,
 
        ratio = cs2000_ratio_get(priv, ch);
 
-       return cs2000_ratio_to_rate(ratio, parent_rate);
+       return cs2000_ratio_to_rate(ratio, parent_rate, priv->lf_ratio);
 }
 
 static long cs2000_round_rate(struct clk_hw *hw, unsigned long rate,
                              unsigned long *parent_rate)
 {
+       struct cs2000_priv *priv = hw_to_priv(hw);
        u32 ratio;
 
-       ratio = cs2000_rate_to_ratio(*parent_rate, rate);
+       ratio = cs2000_rate_to_ratio(*parent_rate, rate, priv->lf_ratio);
 
-       return cs2000_ratio_to_rate(ratio, *parent_rate);
+       return cs2000_ratio_to_rate(ratio, *parent_rate, priv->lf_ratio);
+}
+
+static int cs2000_select_ratio_mode(struct cs2000_priv *priv,
+                                   unsigned long rate,
+                                   unsigned long parent_rate)
+{
+       /*
+        * From the datasheet:
+        *
+        * | It is recommended that the 12.20 High-Resolution format be
+        * | utilized whenever the desired ratio is less than 4096 since
+        * | the output frequency accuracy of the PLL is directly proportional
+        * | to the accuracy of the timing reference clock and the resolution
+        * | of the R_UD.
+        *
+        * This mode is only available in dynamic mode.
+        */
+       priv->lf_ratio = priv->dynamic_mode && ((rate / parent_rate) > 4096);
+
+       return regmap_update_bits(priv->regmap, FUNC_CFG2, LFRATIO_MASK,
+                                 priv->lf_ratio ? LFRATIO_20_12 : LFRATIO_12_20);
 }
 
 static int __cs2000_set_rate(struct cs2000_priv *priv, int ch,
@@ -313,7 +343,11 @@ static int __cs2000_set_rate(struct cs2000_priv *priv, int ch,
 {
        int ret;
 
-       ret = cs2000_clk_in_bound_rate(priv, parent_rate);
+       ret = regmap_update_bits(priv->regmap, GLOBAL_CFG, FREEZE, FREEZE);
+       if (ret < 0)
+               return ret;
+
+       ret = cs2000_select_ratio_mode(priv, rate, parent_rate);
        if (ret < 0)
                return ret;
 
@@ -325,6 +359,10 @@ static int __cs2000_set_rate(struct cs2000_priv *priv, int ch,
        if (ret < 0)
                return ret;
 
+       ret = regmap_update_bits(priv->regmap, GLOBAL_CFG, FREEZE, 0);
+       if (ret < 0)
+               return ret;
+
        priv->saved_rate        = rate;
        priv->saved_parent_rate = parent_rate;
 
@@ -380,8 +418,13 @@ static void cs2000_disable(struct clk_hw *hw)
 
 static u8 cs2000_get_parent(struct clk_hw *hw)
 {
-       /* always return REF_CLK */
-       return REF_CLK;
+       struct cs2000_priv *priv = hw_to_priv(hw);
+
+       /*
+        * In dynamic mode, output rates are derived from CLK_IN.
+        * In static mode, CLK_IN is ignored, so we return REF_CLK instead.
+        */
+       return priv->dynamic_mode ? CLK_IN : REF_CLK;
 }
 
 static const struct clk_ops cs2000_ops = {
@@ -421,22 +464,44 @@ static int cs2000_clk_register(struct cs2000_priv *priv)
        struct clk_init_data init;
        const char *name = np->name;
        static const char *parent_names[CLK_MAX];
+       u32 aux_out = 0;
+       int ref_clk_rate;
        int ch = 0; /* it uses ch0 only at this point */
-       int rate;
        int ret;
 
        of_property_read_string(np, "clock-output-names", &name);
 
-       /*
-        * set default rate as 1/1.
-        * otherwise .set_rate which setup ratio
-        * is never called if user requests 1/1 rate
-        */
-       rate = clk_get_rate(priv->ref_clk);
-       ret = __cs2000_set_rate(priv, ch, rate, rate);
+       priv->dynamic_mode = of_property_read_bool(np, "cirrus,dynamic-mode");
+       dev_info(dev, "operating in %s mode\n",
+                priv->dynamic_mode ? "dynamic" : "static");
+
+       of_property_read_u32(np, "cirrus,aux-output-source", &aux_out);
+       ret = regmap_update_bits(priv->regmap, DEVICE_CFG1,
+                                AUXOUTSRC_MASK, AUXOUTSRC(aux_out));
+       if (ret < 0)
+               return ret;
+
+       priv->clk_skip = of_property_read_bool(np, "cirrus,clock-skip");
+
+       ref_clk_rate = clk_get_rate(priv->ref_clk);
+       ret = cs2000_ref_clk_bound_rate(priv, ref_clk_rate);
        if (ret < 0)
                return ret;
 
+       if (priv->dynamic_mode) {
+               /* Default to low-frequency mode to allow for large ratios */
+               priv->lf_ratio = true;
+       } else {
+               /*
+                * set default rate as 1/1.
+                * otherwise .set_rate which setup ratio
+                * is never called if user requests 1/1 rate
+                */
+               ret = __cs2000_set_rate(priv, ch, ref_clk_rate, ref_clk_rate);
+               if (ret < 0)
+                       return ret;
+       }
+
        parent_names[CLK_IN]    = __clk_get_name(priv->clk_in);
        parent_names[REF_CLK]   = __clk_get_name(priv->ref_clk);
 
@@ -464,12 +529,13 @@ static int cs2000_clk_register(struct cs2000_priv *priv)
 static int cs2000_version_print(struct cs2000_priv *priv)
 {
        struct device *dev = priv_to_dev(priv);
-       s32 val;
        const char *revision;
+       unsigned int val;
+       int ret;
 
-       val = cs2000_read(priv, DEVICE_ID);
-       if (val < 0)
-               return val;
+       ret = regmap_read(priv->regmap, DEVICE_ID, &val);
+       if (ret < 0)
+               return ret;
 
        /* CS2000 should be 0x0 */
        if (val >> 3)
@@ -518,6 +584,10 @@ static int cs2000_probe(struct i2c_client *client,
        priv->client = client;
        i2c_set_clientdata(client, priv);
 
+       priv->regmap = devm_regmap_init_i2c(client, &cs2000_regmap_config);
+       if (IS_ERR(priv->regmap))
+               return PTR_ERR(priv->regmap);
+
        ret = cs2000_clk_get(priv);
        if (ret < 0)
                return ret;
index 4e4b6d3..54942d7 100644 (file)
@@ -131,6 +131,28 @@ __clk_hw_register_fixed_factor(struct device *dev, struct device_node *np,
        return hw;
 }
 
+/**
+ * devm_clk_hw_register_fixed_factor_index - Register a fixed factor clock with
+ * parent from DT index
+ * @dev: device that is registering this clock
+ * @name: name of this clock
+ * @index: index of phandle in @dev 'clocks' property
+ * @flags: fixed factor flags
+ * @mult: multiplier
+ * @div: divider
+ *
+ * Return: Pointer to fixed factor clk_hw structure that was registered or
+ * an error pointer.
+ */
+struct clk_hw *devm_clk_hw_register_fixed_factor_index(struct device *dev,
+               const char *name, unsigned int index, unsigned long flags,
+               unsigned int mult, unsigned int div)
+{
+       return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, index,
+                                             flags, mult, div, true);
+}
+EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_index);
+
 struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
                const char *name, const char *parent_name, unsigned long flags,
                unsigned int mult, unsigned int div)
diff --git a/drivers/clk/clk-gate_test.c b/drivers/clk/clk-gate_test.c
new file mode 100644 (file)
index 0000000..e136aaa
--- /dev/null
@@ -0,0 +1,464 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kunit test for clk gate basic type
+ */
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+
+#include <kunit/test.h>
+
+static void clk_gate_register_test_dev(struct kunit *test)
+{
+       struct clk_hw *ret;
+       struct platform_device *pdev;
+
+       pdev = platform_device_register_simple("test_gate_device", -1, NULL, 0);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+       ret = clk_hw_register_gate(&pdev->dev, "test_gate", NULL, 0, NULL,
+                                  0, 0, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
+       KUNIT_EXPECT_STREQ(test, "test_gate", clk_hw_get_name(ret));
+       KUNIT_EXPECT_EQ(test, 0UL, clk_hw_get_flags(ret));
+
+       clk_hw_unregister_gate(ret);
+       platform_device_put(pdev);
+}
+
+static void clk_gate_register_test_parent_names(struct kunit *test)
+{
+       struct clk_hw *parent;
+       struct clk_hw *ret;
+
+       parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
+                                           1000000);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
+
+       ret = clk_hw_register_gate(NULL, "test_gate", "test_parent", 0, NULL,
+                                  0, 0, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
+       KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret));
+
+       clk_hw_unregister_gate(ret);
+       clk_hw_unregister_fixed_rate(parent);
+}
+
+static void clk_gate_register_test_parent_data(struct kunit *test)
+{
+       struct clk_hw *parent;
+       struct clk_hw *ret;
+       struct clk_parent_data pdata = { };
+
+       parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
+                                           1000000);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
+       pdata.hw = parent;
+
+       ret = clk_hw_register_gate_parent_data(NULL, "test_gate", &pdata, 0,
+                                              NULL, 0, 0, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
+       KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret));
+
+       clk_hw_unregister_gate(ret);
+       clk_hw_unregister_fixed_rate(parent);
+}
+
+static void clk_gate_register_test_parent_data_legacy(struct kunit *test)
+{
+       struct clk_hw *parent;
+       struct clk_hw *ret;
+       struct clk_parent_data pdata = { };
+
+       parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
+                                           1000000);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
+       pdata.name = "test_parent";
+
+       ret = clk_hw_register_gate_parent_data(NULL, "test_gate", &pdata, 0,
+                                              NULL, 0, 0, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
+       KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret));
+
+       clk_hw_unregister_gate(ret);
+       clk_hw_unregister_fixed_rate(parent);
+}
+
+static void clk_gate_register_test_parent_hw(struct kunit *test)
+{
+       struct clk_hw *parent;
+       struct clk_hw *ret;
+
+       parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
+                                           1000000);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
+
+       ret = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0, NULL,
+                                            0, 0, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
+       KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret));
+
+       clk_hw_unregister_gate(ret);
+       clk_hw_unregister_fixed_rate(parent);
+}
+
+static void clk_gate_register_test_hiword_invalid(struct kunit *test)
+{
+       struct clk_hw *ret;
+
+       ret = clk_hw_register_gate(NULL, "test_gate", NULL, 0, NULL,
+                                  20, CLK_GATE_HIWORD_MASK, NULL);
+
+       KUNIT_EXPECT_TRUE(test, IS_ERR(ret));
+}
+
+static struct kunit_case clk_gate_register_test_cases[] = {
+       KUNIT_CASE(clk_gate_register_test_dev),
+       KUNIT_CASE(clk_gate_register_test_parent_names),
+       KUNIT_CASE(clk_gate_register_test_parent_data),
+       KUNIT_CASE(clk_gate_register_test_parent_data_legacy),
+       KUNIT_CASE(clk_gate_register_test_parent_hw),
+       KUNIT_CASE(clk_gate_register_test_hiword_invalid),
+       {}
+};
+
+static struct kunit_suite clk_gate_register_test_suite = {
+       .name = "clk-gate-register-test",
+       .test_cases = clk_gate_register_test_cases,
+};
+
+struct clk_gate_test_context {
+       void __iomem *fake_mem;
+       struct clk_hw *hw;
+       struct clk_hw *parent;
+       u32 fake_reg; /* Keep at end, KASAN can detect out of bounds */
+};
+
+static struct clk_gate_test_context *clk_gate_test_alloc_ctx(struct kunit *test)
+{
+       struct clk_gate_test_context *ctx;
+
+       test->priv = ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+       ctx->fake_mem = (void __force __iomem *)&ctx->fake_reg;
+
+       return ctx;
+}
+
+static void clk_gate_test_parent_rate(struct kunit *test)
+{
+       struct clk_gate_test_context *ctx = test->priv;
+       struct clk_hw *parent = ctx->parent;
+       struct clk_hw *hw = ctx->hw;
+       unsigned long prate = clk_hw_get_rate(parent);
+       unsigned long rate = clk_hw_get_rate(hw);
+
+       KUNIT_EXPECT_EQ(test, prate, rate);
+}
+
+static void clk_gate_test_enable(struct kunit *test)
+{
+       struct clk_gate_test_context *ctx = test->priv;
+       struct clk_hw *parent = ctx->parent;
+       struct clk_hw *hw = ctx->hw;
+       struct clk *clk = hw->clk;
+       u32 enable_val = BIT(5);
+
+       KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
+
+       KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg);
+       KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
+       KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
+       KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
+       KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent));
+}
+
+static void clk_gate_test_disable(struct kunit *test)
+{
+       struct clk_gate_test_context *ctx = test->priv;
+       struct clk_hw *parent = ctx->parent;
+       struct clk_hw *hw = ctx->hw;
+       struct clk *clk = hw->clk;
+       u32 enable_val = BIT(5);
+       u32 disable_val = 0;
+
+       KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
+       KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg);
+
+       clk_disable_unprepare(clk);
+       KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg);
+       KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
+       KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
+       KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
+       KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent));
+}
+
+static struct kunit_case clk_gate_test_cases[] = {
+       KUNIT_CASE(clk_gate_test_parent_rate),
+       KUNIT_CASE(clk_gate_test_enable),
+       KUNIT_CASE(clk_gate_test_disable),
+       {}
+};
+
+static int clk_gate_test_init(struct kunit *test)
+{
+       struct clk_hw *parent;
+       struct clk_hw *hw;
+       struct clk_gate_test_context *ctx;
+
+       ctx = clk_gate_test_alloc_ctx(test);
+       parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
+                                           2000000);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
+
+       hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0,
+                                           ctx->fake_mem, 5, 0, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
+
+       ctx->hw = hw;
+       ctx->parent = parent;
+
+       return 0;
+}
+
+static void clk_gate_test_exit(struct kunit *test)
+{
+       struct clk_gate_test_context *ctx = test->priv;
+
+       clk_hw_unregister_gate(ctx->hw);
+       clk_hw_unregister_fixed_rate(ctx->parent);
+}
+
+static struct kunit_suite clk_gate_test_suite = {
+       .name = "clk-gate-test",
+       .init = clk_gate_test_init,
+       .exit = clk_gate_test_exit,
+       .test_cases = clk_gate_test_cases,
+};
+
+static void clk_gate_test_invert_enable(struct kunit *test)
+{
+       struct clk_gate_test_context *ctx = test->priv;
+       struct clk_hw *parent = ctx->parent;
+       struct clk_hw *hw = ctx->hw;
+       struct clk *clk = hw->clk;
+       u32 enable_val = 0;
+
+       KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
+
+       KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg);
+       KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
+       KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
+       KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
+       KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent));
+}
+
+static void clk_gate_test_invert_disable(struct kunit *test)
+{
+       struct clk_gate_test_context *ctx = test->priv;
+       struct clk_hw *parent = ctx->parent;
+       struct clk_hw *hw = ctx->hw;
+       struct clk *clk = hw->clk;
+       u32 enable_val = 0;
+       u32 disable_val = BIT(15);
+
+       KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
+       KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg);
+
+       clk_disable_unprepare(clk);
+       KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg);
+       KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
+       KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
+       KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
+       KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent));
+}
+
+static struct kunit_case clk_gate_test_invert_cases[] = {
+       KUNIT_CASE(clk_gate_test_invert_enable),
+       KUNIT_CASE(clk_gate_test_invert_disable),
+       {}
+};
+
+static int clk_gate_test_invert_init(struct kunit *test)
+{
+       struct clk_hw *parent;
+       struct clk_hw *hw;
+       struct clk_gate_test_context *ctx;
+
+       ctx = clk_gate_test_alloc_ctx(test);
+       parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
+                                           2000000);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
+
+       ctx->fake_reg = BIT(15); /* Default to off */
+       hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0,
+                                           ctx->fake_mem, 15,
+                                           CLK_GATE_SET_TO_DISABLE, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
+
+       ctx->hw = hw;
+       ctx->parent = parent;
+
+       return 0;
+}
+
+static struct kunit_suite clk_gate_test_invert_suite = {
+       .name = "clk-gate-invert-test",
+       .init = clk_gate_test_invert_init,
+       .exit = clk_gate_test_exit,
+       .test_cases = clk_gate_test_invert_cases,
+};
+
+static void clk_gate_test_hiword_enable(struct kunit *test)
+{
+       struct clk_gate_test_context *ctx = test->priv;
+       struct clk_hw *parent = ctx->parent;
+       struct clk_hw *hw = ctx->hw;
+       struct clk *clk = hw->clk;
+       u32 enable_val = BIT(9) | BIT(9 + 16);
+
+       KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
+
+       KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg);
+       KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
+       KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
+       KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
+       KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent));
+}
+
+static void clk_gate_test_hiword_disable(struct kunit *test)
+{
+       struct clk_gate_test_context *ctx = test->priv;
+       struct clk_hw *parent = ctx->parent;
+       struct clk_hw *hw = ctx->hw;
+       struct clk *clk = hw->clk;
+       u32 enable_val = BIT(9) | BIT(9 + 16);
+       u32 disable_val = BIT(9 + 16);
+
+       KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
+       KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg);
+
+       clk_disable_unprepare(clk);
+       KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg);
+       KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
+       KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
+       KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
+       KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent));
+}
+
+static struct kunit_case clk_gate_test_hiword_cases[] = {
+       KUNIT_CASE(clk_gate_test_hiword_enable),
+       KUNIT_CASE(clk_gate_test_hiword_disable),
+       {}
+};
+
+static int clk_gate_test_hiword_init(struct kunit *test)
+{
+       struct clk_hw *parent;
+       struct clk_hw *hw;
+       struct clk_gate_test_context *ctx;
+
+       ctx = clk_gate_test_alloc_ctx(test);
+       parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0,
+                                           2000000);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
+
+       hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0,
+                                           ctx->fake_mem, 9,
+                                           CLK_GATE_HIWORD_MASK, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
+
+       ctx->hw = hw;
+       ctx->parent = parent;
+
+       return 0;
+}
+
+static struct kunit_suite clk_gate_test_hiword_suite = {
+       .name = "clk-gate-hiword-test",
+       .init = clk_gate_test_hiword_init,
+       .exit = clk_gate_test_exit,
+       .test_cases = clk_gate_test_hiword_cases,
+};
+
+static void clk_gate_test_is_enabled(struct kunit *test)
+{
+       struct clk_hw *hw;
+       struct clk_gate_test_context *ctx;
+
+       ctx = clk_gate_test_alloc_ctx(test);
+       ctx->fake_reg = BIT(7);
+       hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 7,
+                                 0, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
+       KUNIT_ASSERT_TRUE(test, clk_hw_is_enabled(hw));
+
+       clk_hw_unregister_gate(hw);
+}
+
+static void clk_gate_test_is_disabled(struct kunit *test)
+{
+       struct clk_hw *hw;
+       struct clk_gate_test_context *ctx;
+
+       ctx = clk_gate_test_alloc_ctx(test);
+       ctx->fake_reg = BIT(4);
+       hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 7,
+                                 0, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
+       KUNIT_ASSERT_FALSE(test, clk_hw_is_enabled(hw));
+
+       clk_hw_unregister_gate(hw);
+}
+
+static void clk_gate_test_is_enabled_inverted(struct kunit *test)
+{
+       struct clk_hw *hw;
+       struct clk_gate_test_context *ctx;
+
+       ctx = clk_gate_test_alloc_ctx(test);
+       ctx->fake_reg = BIT(31);
+       hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 2,
+                                 CLK_GATE_SET_TO_DISABLE, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
+       KUNIT_ASSERT_TRUE(test, clk_hw_is_enabled(hw));
+
+       clk_hw_unregister_gate(hw);
+}
+
+static void clk_gate_test_is_disabled_inverted(struct kunit *test)
+{
+       struct clk_hw *hw;
+       struct clk_gate_test_context *ctx;
+
+       ctx = clk_gate_test_alloc_ctx(test);
+       ctx->fake_reg = BIT(29);
+       hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 29,
+                                 CLK_GATE_SET_TO_DISABLE, NULL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
+       KUNIT_ASSERT_FALSE(test, clk_hw_is_enabled(hw));
+
+       clk_hw_unregister_gate(hw);
+}
+
+static struct kunit_case clk_gate_test_enabled_cases[] = {
+       KUNIT_CASE(clk_gate_test_is_enabled),
+       KUNIT_CASE(clk_gate_test_is_disabled),
+       KUNIT_CASE(clk_gate_test_is_enabled_inverted),
+       KUNIT_CASE(clk_gate_test_is_disabled_inverted),
+       {}
+};
+
+static struct kunit_suite clk_gate_test_enabled_suite = {
+       .name = "clk-gate-is_enabled-test",
+       .test_cases = clk_gate_test_enabled_cases,
+};
+
+kunit_test_suites(
+       &clk_gate_register_test_suite,
+       &clk_gate_test_suite,
+       &clk_gate_test_invert_suite,
+       &clk_gate_test_hiword_suite,
+       &clk_gate_test_enabled_suite
+);
+MODULE_LICENSE("GPL v2");
index 20582aa..214045f 100644 (file)
@@ -40,7 +40,7 @@ static inline void clk_mux_writel(struct clk_mux *mux, u32 val)
                writel(val, mux->reg);
 }
 
-int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags,
+int clk_mux_val_to_index(struct clk_hw *hw, const u32 *table, unsigned int flags,
                         unsigned int val)
 {
        int num_parents = clk_hw_get_num_parents(hw);
@@ -67,7 +67,7 @@ int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags,
 }
 EXPORT_SYMBOL_GPL(clk_mux_val_to_index);
 
-unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index)
+unsigned int clk_mux_index_to_val(const u32 *table, unsigned int flags, u8 index)
 {
        unsigned int val = index;
 
@@ -152,7 +152,7 @@ struct clk_hw *__clk_hw_register_mux(struct device *dev, struct device_node *np,
                const struct clk_hw **parent_hws,
                const struct clk_parent_data *parent_data,
                unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
-               u8 clk_mux_flags, u32 *table, spinlock_t *lock)
+               u8 clk_mux_flags, const u32 *table, spinlock_t *lock)
 {
        struct clk_mux *mux;
        struct clk_hw *hw;
@@ -218,7 +218,7 @@ struct clk_hw *__devm_clk_hw_register_mux(struct device *dev, struct device_node
                const struct clk_hw **parent_hws,
                const struct clk_parent_data *parent_data,
                unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
-               u8 clk_mux_flags, u32 *table, spinlock_t *lock)
+               u8 clk_mux_flags, const u32 *table, spinlock_t *lock)
 {
        struct clk_hw **ptr, *hw;
 
@@ -244,7 +244,7 @@ EXPORT_SYMBOL_GPL(__devm_clk_hw_register_mux);
 struct clk *clk_register_mux_table(struct device *dev, const char *name,
                const char * const *parent_names, u8 num_parents,
                unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
-               u8 clk_mux_flags, u32 *table, spinlock_t *lock)
+               u8 clk_mux_flags, const u32 *table, spinlock_t *lock)
 {
        struct clk_hw *hw;
 
diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c
new file mode 100644 (file)
index 0000000..59d9cf0
--- /dev/null
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Renesas 9-series PCIe clock generator driver
+ *
+ * The following series can be supported:
+ *   - 9FGV/9DBV/9DMV/9FGL/9DML/9QXL/9SQ
+ * Currently supported:
+ *   - 9FGV0241
+ *
+ * Copyright (C) 2022 Marek Vasut <marex@denx.de>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#define RS9_REG_OE                             0x0
+#define RS9_REG_OE_DIF_OE(n)                   BIT((n) + 1)
+#define RS9_REG_SS                             0x1
+#define RS9_REG_SS_AMP_0V6                     0x0
+#define RS9_REG_SS_AMP_0V7                     0x1
+#define RS9_REG_SS_AMP_0V8                     0x2
+#define RS9_REG_SS_AMP_0V9                     0x3
+#define RS9_REG_SS_AMP_MASK                    0x3
+#define RS9_REG_SS_SSC_100                     0
+#define RS9_REG_SS_SSC_M025                    (1 << 3)
+#define RS9_REG_SS_SSC_M050                    (3 << 3)
+#define RS9_REG_SS_SSC_MASK                    (3 << 3)
+#define RS9_REG_SS_SSC_LOCK                    BIT(5)
+#define RS9_REG_SR                             0x2
+#define RS9_REG_SR_2V0_DIF(n)                  0
+#define RS9_REG_SR_3V0_DIF(n)                  BIT((n) + 1)
+#define RS9_REG_SR_DIF_MASK(n)         BIT((n) + 1)
+#define RS9_REG_REF                            0x3
+#define RS9_REG_REF_OE                         BIT(4)
+#define RS9_REG_REF_OD                         BIT(5)
+#define RS9_REG_REF_SR_SLOWEST                 0
+#define RS9_REG_REF_SR_SLOW                    (1 << 6)
+#define RS9_REG_REF_SR_FAST                    (2 << 6)
+#define RS9_REG_REF_SR_FASTER                  (3 << 6)
+#define RS9_REG_VID                            0x5
+#define RS9_REG_DID                            0x6
+#define RS9_REG_BCP                            0x7
+
+/* Supported Renesas 9-series models. */
+enum rs9_model {
+       RENESAS_9FGV0241,
+};
+
+/* Structure to describe features of a particular 9-series model */
+struct rs9_chip_info {
+       const enum rs9_model    model;
+       unsigned int            num_clks;
+};
+
+struct rs9_driver_data {
+       struct i2c_client       *client;
+       struct regmap           *regmap;
+       const struct rs9_chip_info *chip_info;
+       struct clk              *pin_xin;
+       struct clk_hw           *clk_dif[2];
+       u8                      pll_amplitude;
+       u8                      pll_ssc;
+       u8                      clk_dif_sr;
+};
+
+/*
+ * Renesas 9-series i2c regmap
+ */
+static const struct regmap_range rs9_readable_ranges[] = {
+       regmap_reg_range(RS9_REG_OE, RS9_REG_REF),
+       regmap_reg_range(RS9_REG_VID, RS9_REG_BCP),
+};
+
+static const struct regmap_access_table rs9_readable_table = {
+       .yes_ranges = rs9_readable_ranges,
+       .n_yes_ranges = ARRAY_SIZE(rs9_readable_ranges),
+};
+
+static const struct regmap_range rs9_writeable_ranges[] = {
+       regmap_reg_range(RS9_REG_OE, RS9_REG_REF),
+       regmap_reg_range(RS9_REG_BCP, RS9_REG_BCP),
+};
+
+static const struct regmap_access_table rs9_writeable_table = {
+       .yes_ranges = rs9_writeable_ranges,
+       .n_yes_ranges = ARRAY_SIZE(rs9_writeable_ranges),
+};
+
+static const struct regmap_config rs9_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .cache_type = REGCACHE_FLAT,
+       .max_register = 0x8,
+       .rd_table = &rs9_readable_table,
+       .wr_table = &rs9_writeable_table,
+};
+
+static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx)
+{
+       struct i2c_client *client = rs9->client;
+       unsigned char name[5] = "DIF0";
+       struct device_node *np;
+       int ret;
+       u32 sr;
+
+       /* Set defaults */
+       rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
+       rs9->clk_dif_sr |= RS9_REG_SR_3V0_DIF(idx);
+
+       snprintf(name, 5, "DIF%d", idx);
+       np = of_get_child_by_name(client->dev.of_node, name);
+       if (!np)
+               return 0;
+
+       /* Output clock slew rate */
+       ret = of_property_read_u32(np, "renesas,slew-rate", &sr);
+       of_node_put(np);
+       if (!ret) {
+               if (sr == 2000000) {            /* 2V/ns */
+                       rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
+                       rs9->clk_dif_sr |= RS9_REG_SR_2V0_DIF(idx);
+               } else if (sr == 3000000) {     /* 3V/ns (default) */
+                       rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
+                       rs9->clk_dif_sr |= RS9_REG_SR_3V0_DIF(idx);
+               } else
+                       ret = dev_err_probe(&client->dev, -EINVAL,
+                                           "Invalid renesas,slew-rate value\n");
+       }
+
+       return ret;
+}
+
+static int rs9_get_common_config(struct rs9_driver_data *rs9)
+{
+       struct i2c_client *client = rs9->client;
+       struct device_node *np = client->dev.of_node;
+       unsigned int amp, ssc;
+       int ret;
+
+       /* Set defaults */
+       rs9->pll_amplitude = RS9_REG_SS_AMP_0V7;
+       rs9->pll_ssc = RS9_REG_SS_SSC_100;
+
+       /* Output clock amplitude */
+       ret = of_property_read_u32(np, "renesas,out-amplitude-microvolt",
+                                  &amp);
+       if (!ret) {
+               if (amp == 600000)      /* 0.6V */
+                       rs9->pll_amplitude = RS9_REG_SS_AMP_0V6;
+               else if (amp == 700000) /* 0.7V (default) */
+                       rs9->pll_amplitude = RS9_REG_SS_AMP_0V7;
+               else if (amp == 800000) /* 0.8V */
+                       rs9->pll_amplitude = RS9_REG_SS_AMP_0V8;
+               else if (amp == 900000) /* 0.9V */
+                       rs9->pll_amplitude = RS9_REG_SS_AMP_0V9;
+               else
+                       return dev_err_probe(&client->dev, -EINVAL,
+                                            "Invalid renesas,out-amplitude-microvolt value\n");
+       }
+
+       /* Output clock spread spectrum */
+       ret = of_property_read_u32(np, "renesas,out-spread-spectrum", &ssc);
+       if (!ret) {
+               if (ssc == 100000)      /* 100% ... no spread (default) */
+                       rs9->pll_ssc = RS9_REG_SS_SSC_100;
+               else if (ssc == 99750)  /* -0.25% ... down spread */
+                       rs9->pll_ssc = RS9_REG_SS_SSC_M025;
+               else if (ssc == 99500)  /* -0.50% ... down spread */
+                       rs9->pll_ssc = RS9_REG_SS_SSC_M050;
+               else
+                       return dev_err_probe(&client->dev, -EINVAL,
+                                            "Invalid renesas,out-spread-spectrum value\n");
+       }
+
+       return 0;
+}
+
+static void rs9_update_config(struct rs9_driver_data *rs9)
+{
+       int i;
+
+       /* If amplitude is non-default, update it. */
+       if (rs9->pll_amplitude != RS9_REG_SS_AMP_0V7) {
+               regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_AMP_MASK,
+                                  rs9->pll_amplitude);
+       }
+
+       /* If SSC is non-default, update it. */
+       if (rs9->pll_ssc != RS9_REG_SS_SSC_100) {
+               regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_SSC_MASK,
+                                  rs9->pll_ssc);
+       }
+
+       for (i = 0; i < rs9->chip_info->num_clks; i++) {
+               if (rs9->clk_dif_sr & RS9_REG_SR_3V0_DIF(i))
+                       continue;
+
+               regmap_update_bits(rs9->regmap, RS9_REG_SR, RS9_REG_SR_3V0_DIF(i),
+                                  rs9->clk_dif_sr & RS9_REG_SR_3V0_DIF(i));
+       }
+}
+
+static struct clk_hw *
+rs9_of_clk_get(struct of_phandle_args *clkspec, void *data)
+{
+       struct rs9_driver_data *rs9 = data;
+       unsigned int idx = clkspec->args[0];
+
+       return rs9->clk_dif[idx];
+}
+
+static int rs9_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       unsigned char name[5] = "DIF0";
+       struct rs9_driver_data *rs9;
+       struct clk_hw *hw;
+       int i, ret;
+
+       rs9 = devm_kzalloc(&client->dev, sizeof(*rs9), GFP_KERNEL);
+       if (!rs9)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, rs9);
+       rs9->client = client;
+       rs9->chip_info = device_get_match_data(&client->dev);
+       if (!rs9->chip_info)
+               return -EINVAL;
+
+       /* Fetch common configuration from DT (if specified) */
+       ret = rs9_get_common_config(rs9);
+       if (ret)
+               return ret;
+
+       /* Fetch DIFx output configuration from DT (if specified) */
+       for (i = 0; i < rs9->chip_info->num_clks; i++) {
+               ret = rs9_get_output_config(rs9, i);
+               if (ret)
+                       return ret;
+       }
+
+       rs9->regmap = devm_regmap_init_i2c(client, &rs9_regmap_config);
+       if (IS_ERR(rs9->regmap))
+               return dev_err_probe(&client->dev, PTR_ERR(rs9->regmap),
+                                    "Failed to allocate register map\n");
+
+       /* Register clock */
+       for (i = 0; i < rs9->chip_info->num_clks; i++) {
+               snprintf(name, 5, "DIF%d", i);
+               hw = devm_clk_hw_register_fixed_factor_index(&client->dev, name,
+                                                   0, 0, 4, 1);
+               if (IS_ERR(hw))
+                       return PTR_ERR(hw);
+
+               rs9->clk_dif[i] = hw;
+       }
+
+       ret = devm_of_clk_add_hw_provider(&client->dev, rs9_of_clk_get, rs9);
+       if (!ret)
+               rs9_update_config(rs9);
+
+       return ret;
+}
+
+static int __maybe_unused rs9_suspend(struct device *dev)
+{
+       struct rs9_driver_data *rs9 = dev_get_drvdata(dev);
+
+       regcache_cache_only(rs9->regmap, true);
+       regcache_mark_dirty(rs9->regmap);
+
+       return 0;
+}
+
+static int __maybe_unused rs9_resume(struct device *dev)
+{
+       struct rs9_driver_data *rs9 = dev_get_drvdata(dev);
+       int ret;
+
+       regcache_cache_only(rs9->regmap, false);
+       ret = regcache_sync(rs9->regmap);
+       if (ret)
+               dev_err(dev, "Failed to restore register map: %d\n", ret);
+       return ret;
+}
+
+static const struct rs9_chip_info renesas_9fgv0241_info = {
+       .model          = RENESAS_9FGV0241,
+       .num_clks       = 2,
+};
+
+static const struct i2c_device_id rs9_id[] = {
+       { "9fgv0241", .driver_data = RENESAS_9FGV0241 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, rs9_id);
+
+static const struct of_device_id clk_rs9_of_match[] = {
+       { .compatible = "renesas,9fgv0241", .data = &renesas_9fgv0241_info },
+       { }
+};
+MODULE_DEVICE_TABLE(of, clk_rs9_of_match);
+
+static SIMPLE_DEV_PM_OPS(rs9_pm_ops, rs9_suspend, rs9_resume);
+
+static struct i2c_driver rs9_driver = {
+       .driver = {
+               .name = "clk-renesas-pcie-9series",
+               .pm     = &rs9_pm_ops,
+               .of_match_table = clk_rs9_of_match,
+       },
+       .probe          = rs9_probe,
+       .id_table       = rs9_id,
+};
+module_i2c_driver(rs9_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("Renesas 9-series PCIe clock generator driver");
+MODULE_LICENSE("GPL");
index f7b4136..071f5a1 100644 (file)
@@ -798,6 +798,15 @@ static unsigned long si5341_output_clk_recalc_rate(struct clk_hw *hw,
        u32 r_divider;
        u8 r[3];
 
+       err = regmap_read(output->data->regmap,
+                       SI5341_OUT_CONFIG(output), &val);
+       if (err < 0)
+               return err;
+
+       /* If SI5341_OUT_CFG_RDIV_FORCE2 is set, r_divider is 2 */
+       if (val & SI5341_OUT_CFG_RDIV_FORCE2)
+               return parent_rate / 2;
+
        err = regmap_bulk_read(output->data->regmap,
                        SI5341_OUT_R_REG(output), r, 3);
        if (err < 0)
@@ -814,13 +823,6 @@ static unsigned long si5341_output_clk_recalc_rate(struct clk_hw *hw,
        r_divider += 1;
        r_divider <<= 1;
 
-       err = regmap_read(output->data->regmap,
-                       SI5341_OUT_CONFIG(output), &val);
-       if (err < 0)
-               return err;
-
-       if (val & SI5341_OUT_CFG_RDIV_FORCE2)
-               r_divider = 2;
 
        return parent_rate / r_divider;
 }
@@ -1468,7 +1470,7 @@ static ssize_t input_present_show(struct device *dev,
        if (res < 0)
                return res;
        res = !(status & SI5341_STATUS_LOSREF);
-       return snprintf(buf, PAGE_SIZE, "%d\n", res);
+       return sysfs_emit(buf, "%d\n", res);
 }
 static DEVICE_ATTR_RO(input_present);
 
@@ -1483,7 +1485,7 @@ static ssize_t input_present_sticky_show(struct device *dev,
        if (res < 0)
                return res;
        res = !(status & SI5341_STATUS_LOSREF);
-       return snprintf(buf, PAGE_SIZE, "%d\n", res);
+       return sysfs_emit(buf, "%d\n", res);
 }
 static DEVICE_ATTR_RO(input_present_sticky);
 
@@ -1498,7 +1500,7 @@ static ssize_t pll_locked_show(struct device *dev,
        if (res < 0)
                return res;
        res = !(status & SI5341_STATUS_LOL);
-       return snprintf(buf, PAGE_SIZE, "%d\n", res);
+       return sysfs_emit(buf, "%d\n", res);
 }
 static DEVICE_ATTR_RO(pll_locked);
 
@@ -1513,7 +1515,7 @@ static ssize_t pll_locked_sticky_show(struct device *dev,
        if (res < 0)
                return res;
        res = !(status & SI5341_STATUS_LOL);
-       return snprintf(buf, PAGE_SIZE, "%d\n", res);
+       return sysfs_emit(buf, "%d\n", res);
 }
 static DEVICE_ATTR_RO(pll_locked_sticky);
 
index 863274a..7ad2e62 100644 (file)
@@ -155,6 +155,10 @@ static const char * const eth_src[] = {
        "pll4_p", "pll3_q"
 };
 
+const struct clk_parent_data ethrx_src[] = {
+       { .name = "ethck_k", .fw_name = "ETH_RX_CLK/ETH_REF_CLK" },
+};
+
 static const char * const rng_src[] = {
        "ck_csi", "pll4_r", "ck_lse", "ck_lsi"
 };
@@ -317,6 +321,7 @@ struct clock_config {
        const char *name;
        const char *parent_name;
        const char * const *parent_names;
+       const struct clk_parent_data *parent_data;
        int num_parents;
        unsigned long flags;
        void *cfg;
@@ -576,6 +581,7 @@ static struct clk_hw *
 clk_stm32_register_gate_ops(struct device *dev,
                            const char *name,
                            const char *parent_name,
+                           const struct clk_parent_data *parent_data,
                            unsigned long flags,
                            void __iomem *base,
                            const struct stm32_gate_cfg *cfg,
@@ -586,7 +592,10 @@ clk_stm32_register_gate_ops(struct device *dev,
        int ret;
 
        init.name = name;
-       init.parent_names = &parent_name;
+       if (parent_name)
+               init.parent_names = &parent_name;
+       if (parent_data)
+               init.parent_data = parent_data;
        init.num_parents = 1;
        init.flags = flags;
 
@@ -611,6 +620,7 @@ clk_stm32_register_gate_ops(struct device *dev,
 static struct clk_hw *
 clk_stm32_register_composite(struct device *dev,
                             const char *name, const char * const *parent_names,
+                            const struct clk_parent_data *parent_data,
                             int num_parents, void __iomem *base,
                             const struct stm32_composite_cfg *cfg,
                             unsigned long flags, spinlock_t *lock)
@@ -1135,6 +1145,7 @@ _clk_stm32_register_gate(struct device *dev,
        return clk_stm32_register_gate_ops(dev,
                                    cfg->name,
                                    cfg->parent_name,
+                                   cfg->parent_data,
                                    cfg->flags,
                                    base,
                                    cfg->cfg,
@@ -1148,8 +1159,8 @@ _clk_stm32_register_composite(struct device *dev,
                              const struct clock_config *cfg)
 {
        return clk_stm32_register_composite(dev, cfg->name, cfg->parent_names,
-                                           cfg->num_parents, base, cfg->cfg,
-                                           cfg->flags, lock);
+                                           cfg->parent_data, cfg->num_parents,
+                                           base, cfg->cfg, cfg->flags, lock);
 }
 
 #define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\
@@ -1258,6 +1269,16 @@ _clk_stm32_register_composite(struct device *dev,
        .func           = _clk_stm32_register_gate,\
 }
 
+#define STM32_GATE_PDATA(_id, _name, _parent, _flags, _gate)\
+{\
+       .id             = _id,\
+       .name           = _name,\
+       .parent_data    = _parent,\
+       .flags          = _flags,\
+       .cfg            = (struct stm32_gate_cfg *) {_gate},\
+       .func           = _clk_stm32_register_gate,\
+}
+
 #define _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags, _mgate, _ops)\
        (&(struct stm32_gate_cfg) {\
                &(struct gate_cfg) {\
@@ -1291,6 +1312,10 @@ _clk_stm32_register_composite(struct device *dev,
        STM32_GATE(_id, _name, _parent, _flags,\
                   _STM32_MGATE(_mgate))
 
+#define MGATE_MP1_PDATA(_id, _name, _parent, _flags, _mgate)\
+       STM32_GATE_PDATA(_id, _name, _parent, _flags,\
+                  _STM32_MGATE(_mgate))
+
 #define _STM32_DIV(_div_offset, _div_shift, _div_width,\
                   _div_flags, _div_table, _ops)\
        .div = &(struct stm32_div_cfg) {\
@@ -1354,6 +1379,9 @@ _clk_stm32_register_composite(struct device *dev,
 #define PCLK(_id, _name, _parent, _flags, _mgate)\
        MGATE_MP1(_id, _name, _parent, _flags, _mgate)
 
+#define PCLK_PDATA(_id, _name, _parent, _flags, _mgate)\
+       MGATE_MP1_PDATA(_id, _name, _parent, _flags, _mgate)
+
 #define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\
             COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE |\
                       CLK_SET_RATE_NO_REPARENT | _flags,\
@@ -1951,7 +1979,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
        PCLK(MDMA, "mdma", "ck_axi", 0, G_MDMA),
        PCLK(GPU, "gpu", "ck_axi", 0, G_GPU),
        PCLK(ETHTX, "ethtx", "ck_axi", 0, G_ETHTX),
-       PCLK(ETHRX, "ethrx", "ck_axi", 0, G_ETHRX),
+       PCLK_PDATA(ETHRX, "ethrx", ethrx_src, 0, G_ETHRX),
        PCLK(ETHMAC, "ethmac", "ck_axi", 0, G_ETHMAC),
        PCLK(FMC, "fmc", "ck_axi", CLK_IGNORE_UNUSED, G_FMC),
        PCLK(QSPI, "qspi", "ck_axi", CLK_IGNORE_UNUSED, G_QSPI),
@@ -2008,7 +2036,6 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
        KCLK(DSI_K, "dsi_k", dsi_src, 0, G_DSI, M_DSI),
        KCLK(ADFSDM_K, "adfsdm_k", sai_src, 0, G_ADFSDM, M_SAI1),
        KCLK(USBO_K, "usbo_k", usbo_src, 0, G_USBO, M_USBO),
-       KCLK(ETHCK_K, "ethck_k", eth_src, 0, G_ETHCK, M_ETHCK),
 
        /* Particulary Kernel Clocks (no mux or no gate) */
        MGATE_MP1(DFSDM_K, "dfsdm_k", "ck_mcu", 0, G_DFSDM),
@@ -2017,11 +2044,16 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
        MGATE_MP1(GPU_K, "gpu_k", "pll2_q", 0, G_GPU),
        MGATE_MP1(DAC12_K, "dac12_k", "ck_lsi", 0, G_DAC12),
 
-       COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE |
+       COMPOSITE(NO_ID, "ck_ker_eth", eth_src, CLK_OPS_PARENT_ENABLE |
                  CLK_SET_RATE_NO_REPARENT,
                  _NO_GATE,
                  _MMUX(M_ETHCK),
-                 _DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)),
+                 _NO_DIV),
+
+       MGATE_MP1(ETHCK_K, "ethck_k", "ck_ker_eth", 0, G_ETHCK),
+
+       DIV(ETHPTP_K, "ethptp_k", "ck_ker_eth", CLK_OPS_PARENT_ENABLE |
+           CLK_SET_RATE_NO_REPARENT, RCC_ETHCKSELR, 4, 4, 0),
 
        /* RTC clock */
        COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE,
index 8de6a22..d15997e 100644 (file)
@@ -37,7 +37,7 @@ static HLIST_HEAD(clk_root_list);
 static HLIST_HEAD(clk_orphan_list);
 static LIST_HEAD(clk_notifier_list);
 
-static struct hlist_head *all_lists[] = {
+static const struct hlist_head *all_lists[] = {
        &clk_root_list,
        &clk_orphan_list,
        NULL,
@@ -4079,7 +4079,7 @@ static const struct clk_ops clk_nodrv_ops = {
 };
 
 static void clk_core_evict_parent_cache_subtree(struct clk_core *root,
-                                               struct clk_core *target)
+                                               const struct clk_core *target)
 {
        int i;
        struct clk_core *child;
@@ -4095,7 +4095,7 @@ static void clk_core_evict_parent_cache_subtree(struct clk_core *root,
 /* Remove this clk from all parent caches */
 static void clk_core_evict_parent_cache(struct clk_core *core)
 {
-       struct hlist_head **lists;
+       const struct hlist_head **lists;
        struct clk_core *root;
 
        lockdep_assert_held(&prepare_lock);
index 9361fba..54d9fdc 100644 (file)
@@ -162,7 +162,7 @@ int hisi_clk_register_mux(const struct hisi_mux_clock *clks,
                                        clks[i].num_parents, clks[i].flags,
                                        base + clks[i].offset, clks[i].shift,
                                        mask, clks[i].mux_flags,
-                                       (u32 *)clks[i].table, &hisi_clk_lock);
+                                       clks[i].table, &hisi_clk_lock);
                if (IS_ERR(clk)) {
                        pr_err("%s: failed to register clock %s\n",
                               __func__, clks[i].name);
index caa9119..a29339c 100644 (file)
@@ -92,7 +92,7 @@ struct clk * __init mtk_clk_register_ref2usb_tx(const char *name,
        clk = clk_register(NULL, &tx->hw);
 
        if (IS_ERR(clk)) {
-               pr_err("Failed to register clk %s: %ld\n", name, PTR_ERR(clk));
+               pr_err("Failed to register clk %s: %pe\n", name, clk);
                kfree(tx);
        }
 
index e188018..c11b3fa 100644 (file)
@@ -5,13 +5,24 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/container_of.h>
+#include <linux/err.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 
 #include "clk-mtk.h"
 #include "clk-cpumux.h"
 
+struct mtk_clk_cpumux {
+       struct clk_hw   hw;
+       struct regmap   *regmap;
+       u32             reg;
+       u32             mask;
+       u8              shift;
+};
+
 static inline struct mtk_clk_cpumux *to_mtk_clk_cpumux(struct clk_hw *_hw)
 {
        return container_of(_hw, struct mtk_clk_cpumux, hw);
@@ -77,6 +88,21 @@ mtk_clk_register_cpumux(const struct mtk_composite *mux,
        return clk;
 }
 
+static void mtk_clk_unregister_cpumux(struct clk *clk)
+{
+       struct mtk_clk_cpumux *cpumux;
+       struct clk_hw *hw;
+
+       hw = __clk_get_hw(clk);
+       if (!hw)
+               return;
+
+       cpumux = to_mtk_clk_cpumux(hw);
+
+       clk_unregister(clk);
+       kfree(cpumux);
+}
+
 int mtk_clk_register_cpumuxes(struct device_node *node,
                              const struct mtk_composite *clks, int num,
                              struct clk_onecell_data *clk_data)
@@ -87,25 +113,58 @@ int mtk_clk_register_cpumuxes(struct device_node *node,
 
        regmap = device_node_to_regmap(node);
        if (IS_ERR(regmap)) {
-               pr_err("Cannot find regmap for %pOF: %ld\n", node,
-                      PTR_ERR(regmap));
+               pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap);
                return PTR_ERR(regmap);
        }
 
        for (i = 0; i < num; i++) {
                const struct mtk_composite *mux = &clks[i];
 
+               if (!IS_ERR_OR_NULL(clk_data->clks[mux->id])) {
+                       pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
+                               node, mux->id);
+                       continue;
+               }
+
                clk = mtk_clk_register_cpumux(mux, regmap);
                if (IS_ERR(clk)) {
-                       pr_err("Failed to register clk %s: %ld\n",
-                              mux->name, PTR_ERR(clk));
-                       continue;
+                       pr_err("Failed to register clk %s: %pe\n", mux->name, clk);
+                       goto err;
                }
 
                clk_data->clks[mux->id] = clk;
        }
 
        return 0;
+
+err:
+       while (--i >= 0) {
+               const struct mtk_composite *mux = &clks[i];
+
+               if (IS_ERR_OR_NULL(clk_data->clks[mux->id]))
+                       continue;
+
+               mtk_clk_unregister_cpumux(clk_data->clks[mux->id]);
+               clk_data->clks[mux->id] = ERR_PTR(-ENOENT);
+       }
+
+       return PTR_ERR(clk);
+}
+
+void mtk_clk_unregister_cpumuxes(const struct mtk_composite *clks, int num,
+                                struct clk_onecell_data *clk_data)
+{
+       int i;
+
+       for (i = num; i > 0; i--) {
+               const struct mtk_composite *mux = &clks[i - 1];
+
+               if (IS_ERR_OR_NULL(clk_data->clks[mux->id]))
+                       continue;
+
+               mtk_clk_unregister_cpumux(clk_data->clks[mux->id]);
+               clk_data->clks[mux->id] = ERR_PTR(-ENOENT);
+       }
 }
 
 MODULE_LICENSE("GPL");
index 2aaf1af..b07e89f 100644 (file)
@@ -7,16 +7,15 @@
 #ifndef __DRV_CLK_CPUMUX_H
 #define __DRV_CLK_CPUMUX_H
 
-struct mtk_clk_cpumux {
-       struct clk_hw   hw;
-       struct regmap   *regmap;
-       u32             reg;
-       u32             mask;
-       u8              shift;
-};
+struct clk_onecell_data;
+struct device_node;
+struct mtk_composite;
 
 int mtk_clk_register_cpumuxes(struct device_node *node,
                              const struct mtk_composite *clks, int num,
                              struct clk_onecell_data *clk_data);
 
+void mtk_clk_unregister_cpumuxes(const struct mtk_composite *clks, int num,
+                                struct clk_onecell_data *clk_data);
+
 #endif /* __DRV_CLK_CPUMUX_H */
index 5d88b42..da52023 100644 (file)
@@ -4,18 +4,30 @@
  * Author: James Liao <jamesjj.liao@mediatek.com>
  */
 
-#include <linux/of.h>
-#include <linux/of_address.h>
-
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/types.h>
 
-#include "clk-mtk.h"
 #include "clk-gate.h"
 
+struct mtk_clk_gate {
+       struct clk_hw   hw;
+       struct regmap   *regmap;
+       int             set_ofs;
+       int             clr_ofs;
+       int             sta_ofs;
+       u8              bit;
+};
+
+static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw)
+{
+       return container_of(hw, struct mtk_clk_gate, hw);
+}
+
 static u32 mtk_get_clockgating(struct clk_hw *hw)
 {
        struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
@@ -140,17 +152,12 @@ const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = {
 };
 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv);
 
-struct clk *mtk_clk_register_gate(
-               const char *name,
-               const char *parent_name,
-               struct regmap *regmap,
-               int set_ofs,
-               int clr_ofs,
-               int sta_ofs,
-               u8 bit,
-               const struct clk_ops *ops,
-               unsigned long flags,
-               struct device *dev)
+static struct clk *mtk_clk_register_gate(const char *name,
+                                        const char *parent_name,
+                                        struct regmap *regmap, int set_ofs,
+                                        int clr_ofs, int sta_ofs, u8 bit,
+                                        const struct clk_ops *ops,
+                                        unsigned long flags, struct device *dev)
 {
        struct mtk_clk_gate *cg;
        struct clk *clk;
@@ -180,6 +187,107 @@ struct clk *mtk_clk_register_gate(
 
        return clk;
 }
-EXPORT_SYMBOL_GPL(mtk_clk_register_gate);
+
+static void mtk_clk_unregister_gate(struct clk *clk)
+{
+       struct mtk_clk_gate *cg;
+       struct clk_hw *hw;
+
+       hw = __clk_get_hw(clk);
+       if (!hw)
+               return;
+
+       cg = to_mtk_clk_gate(hw);
+
+       clk_unregister(clk);
+       kfree(cg);
+}
+
+int mtk_clk_register_gates_with_dev(struct device_node *node,
+                                   const struct mtk_gate *clks, int num,
+                                   struct clk_onecell_data *clk_data,
+                                   struct device *dev)
+{
+       int i;
+       struct clk *clk;
+       struct regmap *regmap;
+
+       if (!clk_data)
+               return -ENOMEM;
+
+       regmap = device_node_to_regmap(node);
+       if (IS_ERR(regmap)) {
+               pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap);
+               return PTR_ERR(regmap);
+       }
+
+       for (i = 0; i < num; i++) {
+               const struct mtk_gate *gate = &clks[i];
+
+               if (!IS_ERR_OR_NULL(clk_data->clks[gate->id])) {
+                       pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
+                               node, gate->id);
+                       continue;
+               }
+
+               clk = mtk_clk_register_gate(gate->name, gate->parent_name,
+                                           regmap,
+                                           gate->regs->set_ofs,
+                                           gate->regs->clr_ofs,
+                                           gate->regs->sta_ofs,
+                                           gate->shift, gate->ops,
+                                           gate->flags, dev);
+
+               if (IS_ERR(clk)) {
+                       pr_err("Failed to register clk %s: %pe\n", gate->name, clk);
+                       goto err;
+               }
+
+               clk_data->clks[gate->id] = clk;
+       }
+
+       return 0;
+
+err:
+       while (--i >= 0) {
+               const struct mtk_gate *gate = &clks[i];
+
+               if (IS_ERR_OR_NULL(clk_data->clks[gate->id]))
+                       continue;
+
+               mtk_clk_unregister_gate(clk_data->clks[gate->id]);
+               clk_data->clks[gate->id] = ERR_PTR(-ENOENT);
+       }
+
+       return PTR_ERR(clk);
+}
+
+int mtk_clk_register_gates(struct device_node *node,
+                          const struct mtk_gate *clks, int num,
+                          struct clk_onecell_data *clk_data)
+{
+       return mtk_clk_register_gates_with_dev(node, clks, num, clk_data, NULL);
+}
+EXPORT_SYMBOL_GPL(mtk_clk_register_gates);
+
+void mtk_clk_unregister_gates(const struct mtk_gate *clks, int num,
+                             struct clk_onecell_data *clk_data)
+{
+       int i;
+
+       if (!clk_data)
+               return;
+
+       for (i = num; i > 0; i--) {
+               const struct mtk_gate *gate = &clks[i - 1];
+
+               if (IS_ERR_OR_NULL(clk_data->clks[gate->id]))
+                       continue;
+
+               mtk_clk_unregister_gate(clk_data->clks[gate->id]);
+               clk_data->clks[gate->id] = ERR_PTR(-ENOENT);
+       }
+}
+EXPORT_SYMBOL_GPL(mtk_clk_unregister_gates);
 
 MODULE_LICENSE("GPL");
index 3c3329e..6b57388 100644 (file)
@@ -7,41 +7,34 @@
 #ifndef __DRV_CLK_GATE_H
 #define __DRV_CLK_GATE_H
 
-#include <linux/regmap.h>
-#include <linux/clk-provider.h>
+#include <linux/types.h>
 
 struct clk;
-
-struct mtk_clk_gate {
-       struct clk_hw   hw;
-       struct regmap   *regmap;
-       int             set_ofs;
-       int             clr_ofs;
-       int             sta_ofs;
-       u8              bit;
-};
-
-static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw)
-{
-       return container_of(hw, struct mtk_clk_gate, hw);
-}
+struct clk_onecell_data;
+struct clk_ops;
+struct device;
+struct device_node;
 
 extern const struct clk_ops mtk_clk_gate_ops_setclr;
 extern const struct clk_ops mtk_clk_gate_ops_setclr_inv;
 extern const struct clk_ops mtk_clk_gate_ops_no_setclr;
 extern const struct clk_ops mtk_clk_gate_ops_no_setclr_inv;
 
-struct clk *mtk_clk_register_gate(
-               const char *name,
-               const char *parent_name,
-               struct regmap *regmap,
-               int set_ofs,
-               int clr_ofs,
-               int sta_ofs,
-               u8 bit,
-               const struct clk_ops *ops,
-               unsigned long flags,
-               struct device *dev);
+struct mtk_gate_regs {
+       u32 sta_ofs;
+       u32 clr_ofs;
+       u32 set_ofs;
+};
+
+struct mtk_gate {
+       int id;
+       const char *name;
+       const char *parent_name;
+       const struct mtk_gate_regs *regs;
+       int shift;
+       const struct clk_ops *ops;
+       unsigned long flags;
+};
 
 #define GATE_MTK_FLAGS(_id, _name, _parent, _regs, _shift,     \
                        _ops, _flags) {                         \
@@ -57,4 +50,16 @@ struct clk *mtk_clk_register_gate(
 #define GATE_MTK(_id, _name, _parent, _regs, _shift, _ops)             \
        GATE_MTK_FLAGS(_id, _name, _parent, _regs, _shift, _ops, 0)
 
+int mtk_clk_register_gates(struct device_node *node,
+                          const struct mtk_gate *clks, int num,
+                          struct clk_onecell_data *clk_data);
+
+int mtk_clk_register_gates_with_dev(struct device_node *node,
+                                   const struct mtk_gate *clks, int num,
+                                   struct clk_onecell_data *clk_data,
+                                   struct device *dev);
+
+void mtk_clk_unregister_gates(const struct mtk_gate *clks, int num,
+                             struct clk_onecell_data *clk_data);
+
 #endif /* __DRV_CLK_GATE_H */
index 695be0f..1eb3e45 100644 (file)
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 
-#include "clk-mtk.h"
-#include "clk-gate.h"
 #include "clk-cpumux.h"
+#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
 
 #include <dt-bindings/clock/mt2701-clk.h>
 
index a3bd9a1..ff72b9a 100644 (file)
@@ -13,8 +13,9 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
-#include "clk-mtk.h"
 #include "clk-gate.h"
+#include "clk-pll.h"
+#include "clk-mtk.h"
 
 #include <dt-bindings/clock/mt2712-clk.h>
 
index d77ea5a..24829ca 100644 (file)
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 
-#include "clk-mtk.h"
 #include "clk-gate.h"
+#include "clk-mtk.h"
 #include "clk-mux.h"
+#include "clk-pll.h"
 
 #include <dt-bindings/clock/mt6765-clk.h>
 
index 9825385..7b61664 100644 (file)
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 
+#include "clk-gate.h"
 #include "clk-mtk.h"
 #include "clk-mux.h"
-#include "clk-gate.h"
+#include "clk-pll.h"
 
 #include <dt-bindings/clock/mt6779-clk.h>
 
index 428eb24..02259e8 100644 (file)
@@ -9,8 +9,9 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 
-#include "clk-mtk.h"
 #include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
 
 #include <dt-bindings/clock/mt6797-clk.h>
 
index ef5947e..0e1fb30 100644 (file)
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 
-#include "clk-mtk.h"
-#include "clk-gate.h"
 #include "clk-cpumux.h"
+#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
 
 #include <dt-bindings/clock/mt7622-clk.h>
 #include <linux/clk.h> /* for consumer */
index a0ee079..c0e023b 100644 (file)
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 
-#include "clk-mtk.h"
-#include "clk-gate.h"
 #include "clk-cpumux.h"
+#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
 
 #include <dt-bindings/clock/mt7629-clk.h>
 
index 98ec388..21d4c82 100644 (file)
 #include <linux/of_address.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
-#include "clk-mtk.h"
+
 #include "clk-gate.h"
+#include "clk-mtk.h"
 #include "clk-mux.h"
+#include "clk-pll.h"
 
 #include <dt-bindings/clock/mt7986-clk.h>
 #include <linux/clk.h>
index 9b4b645..09ad272 100644 (file)
@@ -11,8 +11,9 @@
 #include <linux/mfd/syscon.h>
 #include <dt-bindings/clock/mt8135-clk.h>
 
-#include "clk-mtk.h"
 #include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
 
 static DEFINE_SPINLOCK(mt8135_clk_lock);
 
index e5ea10e..812b33a 100644 (file)
@@ -12,8 +12,9 @@
 #include <linux/slab.h>
 #include <linux/mfd/syscon.h>
 
-#include "clk-mtk.h"
 #include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
 
 #include <dt-bindings/clock/mt8167-clk.h>
 
index 8f898ac..46b7655 100644 (file)
@@ -8,9 +8,10 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 
-#include "clk-mtk.h"
-#include "clk-gate.h"
 #include "clk-cpumux.h"
+#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
 
 #include <dt-bindings/clock/mt8173-clk.h>
 
index 5046852..6849655 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
+#include "clk-gate.h"
 #include "clk-mtk.h"
 #include "clk-mux.h"
-#include "clk-gate.h"
+#include "clk-pll.h"
 
 #include <dt-bindings/clock/mt8183-clk.h>
 
index cbc7c6d..ab27cd6 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
+#include "clk-gate.h"
 #include "clk-mtk.h"
 #include "clk-mux.h"
-#include "clk-gate.h"
+#include "clk-pll.h"
 
 #include <dt-bindings/clock/mt8192-clk.h>
 
@@ -1236,9 +1237,17 @@ static int clk_mt8192_infra_probe(struct platform_device *pdev)
 
        r = mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), clk_data);
        if (r)
-               return r;
+               goto free_clk_data;
+
+       r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+       if (r)
+               goto free_clk_data;
 
-       return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+       return r;
+
+free_clk_data:
+       mtk_free_clk_data(clk_data);
+       return r;
 }
 
 static int clk_mt8192_peri_probe(struct platform_device *pdev)
@@ -1253,9 +1262,17 @@ static int clk_mt8192_peri_probe(struct platform_device *pdev)
 
        r = mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks), clk_data);
        if (r)
-               return r;
+               goto free_clk_data;
+
+       r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+       if (r)
+               goto free_clk_data;
+
+       return r;
 
-       return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+free_clk_data:
+       mtk_free_clk_data(clk_data);
+       return r;
 }
 
 static int clk_mt8192_apmixed_probe(struct platform_device *pdev)
@@ -1271,9 +1288,17 @@ static int clk_mt8192_apmixed_probe(struct platform_device *pdev)
        mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
        r = mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
        if (r)
-               return r;
+               goto free_clk_data;
 
-       return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+       r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+       if (r)
+               goto free_clk_data;
+
+       return r;
+
+free_clk_data:
+       mtk_free_clk_data(clk_data);
+       return r;
 }
 
 static const struct of_device_id of_match_clk_mt8192[] = {
index 6156cee..eecc703 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "clk-gate.h"
 #include "clk-mtk.h"
+#include "clk-pll.h"
 
 #include <dt-bindings/clock/mt8195-clk.h>
 #include <linux/of_device.h>
@@ -119,24 +120,47 @@ static int clk_mt8195_apmixed_probe(struct platform_device *pdev)
        if (!clk_data)
                return -ENOMEM;
 
-       mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
-       r = mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
+       r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
        if (r)
                goto free_apmixed_data;
 
+       r = mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
+       if (r)
+               goto unregister_plls;
+
        r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
        if (r)
-               goto free_apmixed_data;
+               goto unregister_gates;
+
+       platform_set_drvdata(pdev, clk_data);
 
        return r;
 
+unregister_gates:
+       mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
+unregister_plls:
+       mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data);
 free_apmixed_data:
        mtk_free_clk_data(clk_data);
        return r;
 }
 
+static int clk_mt8195_apmixed_remove(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
+
+       of_clk_del_provider(node);
+       mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
+       mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data);
+       mtk_free_clk_data(clk_data);
+
+       return 0;
+}
+
 static struct platform_driver clk_mt8195_apmixed_drv = {
        .probe = clk_mt8195_apmixed_probe,
+       .remove = clk_mt8195_apmixed_remove,
        .driver = {
                .name = "clk-mt8195-apmixed",
                .of_match_table = of_match_clk_mt8195_apmixed,
index f1c8418..8cd88df 100644 (file)
@@ -4,6 +4,7 @@
 // Author: Chun-Jie Chen <chun-jie.chen@mediatek.com>
 
 #include "clk-mtk.h"
+#include "clk-pll.h"
 
 #include <dt-bindings/clock/mt8195-clk.h>
 #include <linux/clk-provider.h>
@@ -65,18 +66,37 @@ static int clk_mt8195_apusys_pll_probe(struct platform_device *pdev)
        if (!clk_data)
                return -ENOMEM;
 
-       mtk_clk_register_plls(node, apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
-       r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+       r = mtk_clk_register_plls(node, apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
        if (r)
                goto free_apusys_pll_data;
 
+       r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+       if (r)
+               goto unregister_plls;
+
+       platform_set_drvdata(pdev, clk_data);
+
        return r;
 
+unregister_plls:
+       mtk_clk_unregister_plls(apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
 free_apusys_pll_data:
        mtk_free_clk_data(clk_data);
        return r;
 }
 
+static int clk_mt8195_apusys_pll_remove(struct platform_device *pdev)
+{
+       struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
+       struct device_node *node = pdev->dev.of_node;
+
+       of_clk_del_provider(node);
+       mtk_clk_unregister_plls(apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
+       mtk_free_clk_data(clk_data);
+
+       return 0;
+}
+
 static const struct of_device_id of_match_clk_mt8195_apusys_pll[] = {
        { .compatible = "mediatek,mt8195-apusys_pll", },
        {}
@@ -84,6 +104,7 @@ static const struct of_device_id of_match_clk_mt8195_apusys_pll[] = {
 
 static struct platform_driver clk_mt8195_apusys_pll_drv = {
        .probe = clk_mt8195_apusys_pll_probe,
+       .remove = clk_mt8195_apusys_pll_remove,
        .driver = {
                .name = "clk-mt8195-apusys_pll",
                .of_match_table = of_match_clk_mt8195_apusys_pll,
index 3d261fc..e4d00fe 100644 (file)
@@ -134,6 +134,7 @@ static const struct of_device_id of_match_clk_mt8195_cam[] = {
 
 static struct platform_driver clk_mt8195_cam_drv = {
        .probe = mtk_clk_simple_probe,
+       .remove = mtk_clk_simple_remove,
        .driver = {
                .name = "clk-mt8195-cam",
                .of_match_table = of_match_clk_mt8195_cam,
index f846f1d..4e326b6 100644 (file)
@@ -42,6 +42,7 @@ static const struct of_device_id of_match_clk_mt8195_ccu[] = {
 
 static struct platform_driver clk_mt8195_ccu_drv = {
        .probe = mtk_clk_simple_probe,
+       .remove = mtk_clk_simple_remove,
        .driver = {
                .name = "clk-mt8195-ccu",
                .of_match_table = of_match_clk_mt8195_ccu,
index 22b52a8..12f5c43 100644 (file)
@@ -88,6 +88,7 @@ static const struct of_device_id of_match_clk_mt8195_img[] = {
 
 static struct platform_driver clk_mt8195_img_drv = {
        .probe = mtk_clk_simple_probe,
+       .remove = mtk_clk_simple_remove,
        .driver = {
                .name = "clk-mt8195-img",
                .of_match_table = of_match_clk_mt8195_img,
index 4ab312e..fbc809d 100644 (file)
@@ -58,6 +58,7 @@ static const struct of_device_id of_match_clk_mt8195_imp_iic_wrap[] = {
 
 static struct platform_driver clk_mt8195_imp_iic_wrap_drv = {
        .probe = mtk_clk_simple_probe,
+       .remove = mtk_clk_simple_remove,
        .driver = {
                .name = "clk-mt8195-imp_iic_wrap",
                .of_match_table = of_match_clk_mt8195_imp_iic_wrap,
index 5f9b699..8ebe3b9 100644 (file)
@@ -198,6 +198,7 @@ static const struct of_device_id of_match_clk_mt8195_infra_ao[] = {
 
 static struct platform_driver clk_mt8195_infra_ao_drv = {
        .probe = mtk_clk_simple_probe,
+       .remove = mtk_clk_simple_remove,
        .driver = {
                .name = "clk-mt8195-infra_ao",
                .of_match_table = of_match_clk_mt8195_infra_ao,
index fc1d42b..b0d745c 100644 (file)
@@ -43,6 +43,7 @@ static const struct of_device_id of_match_clk_mt8195_ipe[] = {
 
 static struct platform_driver clk_mt8195_ipe_drv = {
        .probe = mtk_clk_simple_probe,
+       .remove = mtk_clk_simple_remove,
        .driver = {
                .name = "clk-mt8195-ipe",
                .of_match_table = of_match_clk_mt8195_ipe,
index aca6d9c..9411c55 100644 (file)
@@ -39,6 +39,7 @@ static const struct of_device_id of_match_clk_mt8195_mfg[] = {
 
 static struct platform_driver clk_mt8195_mfg_drv = {
        .probe = mtk_clk_simple_probe,
+       .remove = mtk_clk_simple_remove,
        .driver = {
                .name = "clk-mt8195-mfg",
                .of_match_table = of_match_clk_mt8195_mfg,
index 907a92b..2f6b3bb 100644 (file)
@@ -54,6 +54,7 @@ static const struct of_device_id of_match_clk_mt8195_peri_ao[] = {
 
 static struct platform_driver clk_mt8195_peri_ao_drv = {
        .probe = mtk_clk_simple_probe,
+       .remove = mtk_clk_simple_remove,
        .driver = {
                .name = "clk-mt8195-peri_ao",
                .of_match_table = of_match_clk_mt8195_peri_ao,
index 26b4846..e16c383 100644 (file)
@@ -39,6 +39,7 @@ static const struct of_device_id of_match_clk_mt8195_scp_adsp[] = {
 
 static struct platform_driver clk_mt8195_scp_adsp_drv = {
        .probe = mtk_clk_simple_probe,
+       .remove = mtk_clk_simple_remove,
        .driver = {
                .name = "clk-mt8195-scp_adsp",
                .of_match_table = of_match_clk_mt8195_scp_adsp,
index 3e2aba9..b602fcd 100644 (file)
@@ -1239,32 +1239,79 @@ static int clk_mt8195_topck_probe(struct platform_device *pdev)
                goto free_top_data;
        }
 
-       mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
-                                   top_clk_data);
-       mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
-       mtk_clk_register_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), node,
-                              &mt8195_clk_lock, top_clk_data);
-       mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
-                                   &mt8195_clk_lock, top_clk_data);
-       mtk_clk_register_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), base,
-                                   &mt8195_clk_lock, top_clk_data);
-       r = mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), top_clk_data);
+       r = mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
+                                       top_clk_data);
        if (r)
                goto free_top_data;
 
+       r = mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
+       if (r)
+               goto unregister_fixed_clks;
+
+       r = mtk_clk_register_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), node,
+                                  &mt8195_clk_lock, top_clk_data);
+       if (r)
+               goto unregister_factors;
+
+       r = mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
+                                       &mt8195_clk_lock, top_clk_data);
+       if (r)
+               goto unregister_muxes;
+
+       r = mtk_clk_register_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), base,
+                                       &mt8195_clk_lock, top_clk_data);
+       if (r)
+               goto unregister_composite_muxes;
+
+       r = mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), top_clk_data);
+       if (r)
+               goto unregister_composite_divs;
+
        r = of_clk_add_provider(node, of_clk_src_onecell_get, top_clk_data);
        if (r)
-               goto free_top_data;
+               goto unregister_gates;
+
+       platform_set_drvdata(pdev, top_clk_data);
 
        return r;
 
+unregister_gates:
+       mtk_clk_unregister_gates(top_clks, ARRAY_SIZE(top_clks), top_clk_data);
+unregister_composite_divs:
+       mtk_clk_unregister_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), top_clk_data);
+unregister_composite_muxes:
+       mtk_clk_unregister_composites(top_muxes, ARRAY_SIZE(top_muxes), top_clk_data);
+unregister_muxes:
+       mtk_clk_unregister_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), top_clk_data);
+unregister_factors:
+       mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
+unregister_fixed_clks:
+       mtk_clk_unregister_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), top_clk_data);
 free_top_data:
        mtk_free_clk_data(top_clk_data);
        return r;
 }
 
+static int clk_mt8195_topck_remove(struct platform_device *pdev)
+{
+       struct clk_onecell_data *top_clk_data = platform_get_drvdata(pdev);
+       struct device_node *node = pdev->dev.of_node;
+
+       of_clk_del_provider(node);
+       mtk_clk_unregister_gates(top_clks, ARRAY_SIZE(top_clks), top_clk_data);
+       mtk_clk_unregister_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), top_clk_data);
+       mtk_clk_unregister_composites(top_muxes, ARRAY_SIZE(top_muxes), top_clk_data);
+       mtk_clk_unregister_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), top_clk_data);
+       mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
+       mtk_clk_unregister_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), top_clk_data);
+       mtk_free_clk_data(top_clk_data);
+
+       return 0;
+}
+
 static struct platform_driver clk_mt8195_topck_drv = {
        .probe = clk_mt8195_topck_probe,
+       .remove = clk_mt8195_topck_remove,
        .driver = {
                .name = "clk-mt8195-topck",
                .of_match_table = of_match_clk_mt8195_topck,
index a1df04f..a1446b6 100644 (file)
@@ -96,6 +96,7 @@ static const struct of_device_id of_match_clk_mt8195_vdec[] = {
 
 static struct platform_driver clk_mt8195_vdec_drv = {
        .probe = mtk_clk_simple_probe,
+       .remove = mtk_clk_simple_remove,
        .driver = {
                .name = "clk-mt8195-vdec",
                .of_match_table = of_match_clk_mt8195_vdec,
index f7ff761..3bc7ed1 100644 (file)
@@ -105,17 +105,35 @@ static int clk_mt8195_vdo0_probe(struct platform_device *pdev)
 
        r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
        if (r)
-               goto free_vdo0_data;
+               goto unregister_gates;
+
+       platform_set_drvdata(pdev, clk_data);
 
        return r;
 
+unregister_gates:
+       mtk_clk_unregister_gates(vdo0_clks, ARRAY_SIZE(vdo0_clks), clk_data);
 free_vdo0_data:
        mtk_free_clk_data(clk_data);
        return r;
 }
 
+static int clk_mt8195_vdo0_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->parent->of_node;
+       struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
+
+       of_clk_del_provider(node);
+       mtk_clk_unregister_gates(vdo0_clks, ARRAY_SIZE(vdo0_clks), clk_data);
+       mtk_free_clk_data(clk_data);
+
+       return 0;
+}
+
 static struct platform_driver clk_mt8195_vdo0_drv = {
        .probe = clk_mt8195_vdo0_probe,
+       .remove = clk_mt8195_vdo0_remove,
        .driver = {
                .name = "clk-mt8195-vdo0",
        },
index 03df8ea..90c738a 100644 (file)
@@ -122,17 +122,35 @@ static int clk_mt8195_vdo1_probe(struct platform_device *pdev)
 
        r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
        if (r)
-               goto free_vdo1_data;
+               goto unregister_gates;
+
+       platform_set_drvdata(pdev, clk_data);
 
        return r;
 
+unregister_gates:
+       mtk_clk_unregister_gates(vdo1_clks, ARRAY_SIZE(vdo1_clks), clk_data);
 free_vdo1_data:
        mtk_free_clk_data(clk_data);
        return r;
 }
 
+static int clk_mt8195_vdo1_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->parent->of_node;
+       struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
+
+       of_clk_del_provider(node);
+       mtk_clk_unregister_gates(vdo1_clks, ARRAY_SIZE(vdo1_clks), clk_data);
+       mtk_free_clk_data(clk_data);
+
+       return 0;
+}
+
 static struct platform_driver clk_mt8195_vdo1_drv = {
        .probe = clk_mt8195_vdo1_probe,
+       .remove = clk_mt8195_vdo1_remove,
        .driver = {
                .name = "clk-mt8195-vdo1",
        },
index 7339851..622f578 100644 (file)
@@ -61,6 +61,7 @@ static const struct of_device_id of_match_clk_mt8195_venc[] = {
 
 static struct platform_driver clk_mt8195_venc_drv = {
        .probe = mtk_clk_simple_probe,
+       .remove = mtk_clk_simple_remove,
        .driver = {
                .name = "clk-mt8195-venc",
                .of_match_table = of_match_clk_mt8195_venc,
index c324146..bf2939c 100644 (file)
@@ -102,6 +102,7 @@ static const struct of_device_id of_match_clk_mt8195_vpp0[] = {
 
 static struct platform_driver clk_mt8195_vpp0_drv = {
        .probe = mtk_clk_simple_probe,
+       .remove = mtk_clk_simple_remove,
        .driver = {
                .name = "clk-mt8195-vpp0",
                .of_match_table = of_match_clk_mt8195_vpp0,
index ce0b9a4..ffd52c7 100644 (file)
@@ -100,6 +100,7 @@ static const struct of_device_id of_match_clk_mt8195_vpp1[] = {
 
 static struct platform_driver clk_mt8195_vpp1_drv = {
        .probe = mtk_clk_simple_probe,
+       .remove = mtk_clk_simple_remove,
        .driver = {
                .name = "clk-mt8195-vpp1",
                .of_match_table = of_match_clk_mt8195_vpp1,
index 274d608..b483fab 100644 (file)
@@ -135,6 +135,7 @@ static const struct of_device_id of_match_clk_mt8195_wpe[] = {
 
 static struct platform_driver clk_mt8195_wpe_drv = {
        .probe = mtk_clk_simple_probe,
+       .remove = mtk_clk_simple_remove,
        .driver = {
                .name = "clk-mt8195-wpe",
                .of_match_table = of_match_clk_mt8195_wpe,
index 9d4261e..a37143f 100644 (file)
@@ -11,8 +11,9 @@
 #include <linux/slab.h>
 #include <linux/mfd/syscon.h>
 
-#include "clk-mtk.h"
 #include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
 
 #include <dt-bindings/clock/mt8516-clk.h>
 
index 8d5791b..b406326 100644 (file)
@@ -4,17 +4,16 @@
  * Author: James Liao <jamesjj.liao@mediatek.com>
  */
 
-#include <linux/of.h>
-#include <linux/of_address.h>
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/clkdev.h>
-#include <linux/module.h>
 #include <linux/mfd/syscon.h>
-#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
 
 #include "clk-mtk.h"
 #include "clk-gate.h"
@@ -54,112 +53,135 @@ void mtk_free_clk_data(struct clk_onecell_data *clk_data)
        kfree(clk_data);
 }
 
-void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks,
-               int num, struct clk_onecell_data *clk_data)
+int mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num,
+                               struct clk_onecell_data *clk_data)
 {
        int i;
        struct clk *clk;
 
+       if (!clk_data)
+               return -ENOMEM;
+
        for (i = 0; i < num; i++) {
                const struct mtk_fixed_clk *rc = &clks[i];
 
-               if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[rc->id]))
+               if (!IS_ERR_OR_NULL(clk_data->clks[rc->id])) {
+                       pr_warn("Trying to register duplicate clock ID: %d\n", rc->id);
                        continue;
+               }
 
                clk = clk_register_fixed_rate(NULL, rc->name, rc->parent, 0,
                                              rc->rate);
 
                if (IS_ERR(clk)) {
-                       pr_err("Failed to register clk %s: %ld\n",
-                                       rc->name, PTR_ERR(clk));
-                       continue;
+                       pr_err("Failed to register clk %s: %pe\n", rc->name, clk);
+                       goto err;
                }
 
-               if (clk_data)
-                       clk_data->clks[rc->id] = clk;
+               clk_data->clks[rc->id] = clk;
+       }
+
+       return 0;
+
+err:
+       while (--i >= 0) {
+               const struct mtk_fixed_clk *rc = &clks[i];
+
+               if (IS_ERR_OR_NULL(clk_data->clks[rc->id]))
+                       continue;
+
+               clk_unregister_fixed_rate(clk_data->clks[rc->id]);
+               clk_data->clks[rc->id] = ERR_PTR(-ENOENT);
        }
+
+       return PTR_ERR(clk);
 }
 EXPORT_SYMBOL_GPL(mtk_clk_register_fixed_clks);
 
-void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
-               int num, struct clk_onecell_data *clk_data)
+void mtk_clk_unregister_fixed_clks(const struct mtk_fixed_clk *clks, int num,
+                                  struct clk_onecell_data *clk_data)
 {
        int i;
-       struct clk *clk;
 
-       for (i = 0; i < num; i++) {
-               const struct mtk_fixed_factor *ff = &clks[i];
-
-               if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[ff->id]))
-                       continue;
+       if (!clk_data)
+               return;
 
-               clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
-                               CLK_SET_RATE_PARENT, ff->mult, ff->div);
+       for (i = num; i > 0; i--) {
+               const struct mtk_fixed_clk *rc = &clks[i - 1];
 
-               if (IS_ERR(clk)) {
-                       pr_err("Failed to register clk %s: %ld\n",
-                                       ff->name, PTR_ERR(clk));
+               if (IS_ERR_OR_NULL(clk_data->clks[rc->id]))
                        continue;
-               }
 
-               if (clk_data)
-                       clk_data->clks[ff->id] = clk;
+               clk_unregister_fixed_rate(clk_data->clks[rc->id]);
+               clk_data->clks[rc->id] = ERR_PTR(-ENOENT);
        }
 }
-EXPORT_SYMBOL_GPL(mtk_clk_register_factors);
+EXPORT_SYMBOL_GPL(mtk_clk_unregister_fixed_clks);
 
-int mtk_clk_register_gates_with_dev(struct device_node *node,
-               const struct mtk_gate *clks,
-               int num, struct clk_onecell_data *clk_data,
-               struct device *dev)
+int mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num,
+                            struct clk_onecell_data *clk_data)
 {
        int i;
        struct clk *clk;
-       struct regmap *regmap;
 
        if (!clk_data)
                return -ENOMEM;
 
-       regmap = device_node_to_regmap(node);
-       if (IS_ERR(regmap)) {
-               pr_err("Cannot find regmap for %pOF: %ld\n", node,
-                               PTR_ERR(regmap));
-               return PTR_ERR(regmap);
-       }
-
        for (i = 0; i < num; i++) {
-               const struct mtk_gate *gate = &clks[i];
+               const struct mtk_fixed_factor *ff = &clks[i];
 
-               if (!IS_ERR_OR_NULL(clk_data->clks[gate->id]))
+               if (!IS_ERR_OR_NULL(clk_data->clks[ff->id])) {
+                       pr_warn("Trying to register duplicate clock ID: %d\n", ff->id);
                        continue;
+               }
 
-               clk = mtk_clk_register_gate(gate->name, gate->parent_name,
-                               regmap,
-                               gate->regs->set_ofs,
-                               gate->regs->clr_ofs,
-                               gate->regs->sta_ofs,
-                               gate->shift, gate->ops, gate->flags, dev);
+               clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
+                               CLK_SET_RATE_PARENT, ff->mult, ff->div);
 
                if (IS_ERR(clk)) {
-                       pr_err("Failed to register clk %s: %ld\n",
-                                       gate->name, PTR_ERR(clk));
-                       continue;
+                       pr_err("Failed to register clk %s: %pe\n", ff->name, clk);
+                       goto err;
                }
 
-               clk_data->clks[gate->id] = clk;
+               clk_data->clks[ff->id] = clk;
        }
 
        return 0;
+
+err:
+       while (--i >= 0) {
+               const struct mtk_fixed_factor *ff = &clks[i];
+
+               if (IS_ERR_OR_NULL(clk_data->clks[ff->id]))
+                       continue;
+
+               clk_unregister_fixed_factor(clk_data->clks[ff->id]);
+               clk_data->clks[ff->id] = ERR_PTR(-ENOENT);
+       }
+
+       return PTR_ERR(clk);
 }
+EXPORT_SYMBOL_GPL(mtk_clk_register_factors);
 
-int mtk_clk_register_gates(struct device_node *node,
-               const struct mtk_gate *clks,
-               int num, struct clk_onecell_data *clk_data)
+void mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num,
+                               struct clk_onecell_data *clk_data)
 {
-       return mtk_clk_register_gates_with_dev(node,
-               clks, num, clk_data, NULL);
+       int i;
+
+       if (!clk_data)
+               return;
+
+       for (i = num; i > 0; i--) {
+               const struct mtk_fixed_factor *ff = &clks[i - 1];
+
+               if (IS_ERR_OR_NULL(clk_data->clks[ff->id]))
+                       continue;
+
+               clk_unregister_fixed_factor(clk_data->clks[ff->id]);
+               clk_data->clks[ff->id] = ERR_PTR(-ENOENT);
+       }
 }
-EXPORT_SYMBOL_GPL(mtk_clk_register_gates);
+EXPORT_SYMBOL_GPL(mtk_clk_unregister_factors);
 
 struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
                void __iomem *base, spinlock_t *lock)
@@ -248,58 +270,161 @@ err_out:
        return ERR_PTR(ret);
 }
 
-void mtk_clk_register_composites(const struct mtk_composite *mcs,
-               int num, void __iomem *base, spinlock_t *lock,
-               struct clk_onecell_data *clk_data)
+static void mtk_clk_unregister_composite(struct clk *clk)
+{
+       struct clk_hw *hw;
+       struct clk_composite *composite;
+       struct clk_mux *mux = NULL;
+       struct clk_gate *gate = NULL;
+       struct clk_divider *div = NULL;
+
+       hw = __clk_get_hw(clk);
+       if (!hw)
+               return;
+
+       composite = to_clk_composite(hw);
+       if (composite->mux_hw)
+               mux = to_clk_mux(composite->mux_hw);
+       if (composite->gate_hw)
+               gate = to_clk_gate(composite->gate_hw);
+       if (composite->rate_hw)
+               div = to_clk_divider(composite->rate_hw);
+
+       clk_unregister_composite(clk);
+       kfree(div);
+       kfree(gate);
+       kfree(mux);
+}
+
+int mtk_clk_register_composites(const struct mtk_composite *mcs, int num,
+                               void __iomem *base, spinlock_t *lock,
+                               struct clk_onecell_data *clk_data)
 {
        struct clk *clk;
        int i;
 
+       if (!clk_data)
+               return -ENOMEM;
+
        for (i = 0; i < num; i++) {
                const struct mtk_composite *mc = &mcs[i];
 
-               if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mc->id]))
+               if (!IS_ERR_OR_NULL(clk_data->clks[mc->id])) {
+                       pr_warn("Trying to register duplicate clock ID: %d\n",
+                               mc->id);
                        continue;
+               }
 
                clk = mtk_clk_register_composite(mc, base, lock);
 
                if (IS_ERR(clk)) {
-                       pr_err("Failed to register clk %s: %ld\n",
-                                       mc->name, PTR_ERR(clk));
-                       continue;
+                       pr_err("Failed to register clk %s: %pe\n", mc->name, clk);
+                       goto err;
                }
 
-               if (clk_data)
-                       clk_data->clks[mc->id] = clk;
+               clk_data->clks[mc->id] = clk;
+       }
+
+       return 0;
+
+err:
+       while (--i >= 0) {
+               const struct mtk_composite *mc = &mcs[i];
+
+               if (IS_ERR_OR_NULL(clk_data->clks[mcs->id]))
+                       continue;
+
+               mtk_clk_unregister_composite(clk_data->clks[mc->id]);
+               clk_data->clks[mc->id] = ERR_PTR(-ENOENT);
        }
+
+       return PTR_ERR(clk);
 }
 EXPORT_SYMBOL_GPL(mtk_clk_register_composites);
 
-void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
-                       int num, void __iomem *base, spinlock_t *lock,
-                               struct clk_onecell_data *clk_data)
+void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num,
+                                  struct clk_onecell_data *clk_data)
+{
+       int i;
+
+       if (!clk_data)
+               return;
+
+       for (i = num; i > 0; i--) {
+               const struct mtk_composite *mc = &mcs[i - 1];
+
+               if (IS_ERR_OR_NULL(clk_data->clks[mc->id]))
+                       continue;
+
+               mtk_clk_unregister_composite(clk_data->clks[mc->id]);
+               clk_data->clks[mc->id] = ERR_PTR(-ENOENT);
+       }
+}
+EXPORT_SYMBOL_GPL(mtk_clk_unregister_composites);
+
+int mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, int num,
+                             void __iomem *base, spinlock_t *lock,
+                             struct clk_onecell_data *clk_data)
 {
        struct clk *clk;
        int i;
 
+       if (!clk_data)
+               return -ENOMEM;
+
        for (i = 0; i <  num; i++) {
                const struct mtk_clk_divider *mcd = &mcds[i];
 
-               if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
+               if (!IS_ERR_OR_NULL(clk_data->clks[mcd->id])) {
+                       pr_warn("Trying to register duplicate clock ID: %d\n",
+                               mcd->id);
                        continue;
+               }
 
                clk = clk_register_divider(NULL, mcd->name, mcd->parent_name,
                        mcd->flags, base +  mcd->div_reg, mcd->div_shift,
                        mcd->div_width, mcd->clk_divider_flags, lock);
 
                if (IS_ERR(clk)) {
-                       pr_err("Failed to register clk %s: %ld\n",
-                               mcd->name, PTR_ERR(clk));
-                       continue;
+                       pr_err("Failed to register clk %s: %pe\n", mcd->name, clk);
+                       goto err;
                }
 
-               if (clk_data)
-                       clk_data->clks[mcd->id] = clk;
+               clk_data->clks[mcd->id] = clk;
+       }
+
+       return 0;
+
+err:
+       while (--i >= 0) {
+               const struct mtk_clk_divider *mcd = &mcds[i];
+
+               if (IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
+                       continue;
+
+               mtk_clk_unregister_composite(clk_data->clks[mcd->id]);
+               clk_data->clks[mcd->id] = ERR_PTR(-ENOENT);
+       }
+
+       return PTR_ERR(clk);
+}
+
+void mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num,
+                                struct clk_onecell_data *clk_data)
+{
+       int i;
+
+       if (!clk_data)
+               return;
+
+       for (i = num; i > 0; i--) {
+               const struct mtk_clk_divider *mcd = &mcds[i - 1];
+
+               if (IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
+                       continue;
+
+               clk_unregister_divider(clk_data->clks[mcd->id]);
+               clk_data->clks[mcd->id] = ERR_PTR(-ENOENT);
        }
 }
 
@@ -324,13 +449,30 @@ int mtk_clk_simple_probe(struct platform_device *pdev)
 
        r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
        if (r)
-               goto free_data;
+               goto unregister_clks;
+
+       platform_set_drvdata(pdev, clk_data);
 
        return r;
 
+unregister_clks:
+       mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
 free_data:
        mtk_free_clk_data(clk_data);
        return r;
 }
 
+int mtk_clk_simple_remove(struct platform_device *pdev)
+{
+       const struct mtk_clk_desc *mcd = of_device_get_match_data(&pdev->dev);
+       struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
+       struct device_node *node = pdev->dev.of_node;
+
+       of_clk_del_provider(node);
+       mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
+       mtk_free_clk_data(clk_data);
+
+       return 0;
+}
+
 MODULE_LICENSE("GPL");
index 0ff289d..bf6565a 100644 (file)
@@ -7,19 +7,19 @@
 #ifndef __DRV_CLK_MTK_H
 #define __DRV_CLK_MTK_H
 
-#include <linux/regmap.h>
-#include <linux/bitops.h>
 #include <linux/clk-provider.h>
-#include <linux/platform_device.h>
-
-struct clk;
-struct clk_onecell_data;
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
 
 #define MAX_MUX_GATE_BIT       31
 #define INVALID_MUX_GATE_BIT   (MAX_MUX_GATE_BIT + 1)
 
 #define MHZ (1000 * 1000)
 
+struct platform_device;
+
 struct mtk_fixed_clk {
        int id;
        const char *name;
@@ -34,8 +34,10 @@ struct mtk_fixed_clk {
                .rate = _rate,                          \
        }
 
-void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks,
-               int num, struct clk_onecell_data *clk_data);
+int mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num,
+                               struct clk_onecell_data *clk_data);
+void mtk_clk_unregister_fixed_clks(const struct mtk_fixed_clk *clks, int num,
+                                  struct clk_onecell_data *clk_data);
 
 struct mtk_fixed_factor {
        int id;
@@ -53,8 +55,10 @@ struct mtk_fixed_factor {
                .div = _div,                            \
        }
 
-void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
-               int num, struct clk_onecell_data *clk_data);
+int mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num,
+                            struct clk_onecell_data *clk_data);
+void mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num,
+                               struct clk_onecell_data *clk_data);
 
 struct mtk_composite {
        int id;
@@ -146,34 +150,11 @@ struct mtk_composite {
 struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
                void __iomem *base, spinlock_t *lock);
 
-void mtk_clk_register_composites(const struct mtk_composite *mcs,
-               int num, void __iomem *base, spinlock_t *lock,
-               struct clk_onecell_data *clk_data);
-
-struct mtk_gate_regs {
-       u32 sta_ofs;
-       u32 clr_ofs;
-       u32 set_ofs;
-};
-
-struct mtk_gate {
-       int id;
-       const char *name;
-       const char *parent_name;
-       const struct mtk_gate_regs *regs;
-       int shift;
-       const struct clk_ops *ops;
-       unsigned long flags;
-};
-
-int mtk_clk_register_gates(struct device_node *node,
-                       const struct mtk_gate *clks, int num,
-                       struct clk_onecell_data *clk_data);
-
-int mtk_clk_register_gates_with_dev(struct device_node *node,
-               const struct mtk_gate *clks,
-               int num, struct clk_onecell_data *clk_data,
-               struct device *dev);
+int mtk_clk_register_composites(const struct mtk_composite *mcs, int num,
+                               void __iomem *base, spinlock_t *lock,
+                               struct clk_onecell_data *clk_data);
+void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num,
+                                  struct clk_onecell_data *clk_data);
 
 struct mtk_clk_divider {
        int id;
@@ -197,52 +178,15 @@ struct mtk_clk_divider {
                .div_width = _width,                            \
 }
 
-void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
-                       int num, void __iomem *base, spinlock_t *lock,
-                               struct clk_onecell_data *clk_data);
+int mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, int num,
+                             void __iomem *base, spinlock_t *lock,
+                             struct clk_onecell_data *clk_data);
+void mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num,
+                                struct clk_onecell_data *clk_data);
 
 struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
 void mtk_free_clk_data(struct clk_onecell_data *clk_data);
 
-#define HAVE_RST_BAR   BIT(0)
-#define PLL_AO         BIT(1)
-
-struct mtk_pll_div_table {
-       u32 div;
-       unsigned long freq;
-};
-
-struct mtk_pll_data {
-       int id;
-       const char *name;
-       u32 reg;
-       u32 pwr_reg;
-       u32 en_mask;
-       u32 pd_reg;
-       u32 tuner_reg;
-       u32 tuner_en_reg;
-       u8 tuner_en_bit;
-       int pd_shift;
-       unsigned int flags;
-       const struct clk_ops *ops;
-       u32 rst_bar_mask;
-       unsigned long fmin;
-       unsigned long fmax;
-       int pcwbits;
-       int pcwibits;
-       u32 pcw_reg;
-       int pcw_shift;
-       u32 pcw_chg_reg;
-       const struct mtk_pll_div_table *div_table;
-       const char *parent_name;
-       u32 en_reg;
-       u8 pll_en_bit; /* Assume 0, indicates BIT(0) by default */
-};
-
-void mtk_clk_register_plls(struct device_node *node,
-               const struct mtk_pll_data *plls, int num_plls,
-               struct clk_onecell_data *clk_data);
-
 struct clk *mtk_clk_register_ref2usb_tx(const char *name,
                        const char *parent_name, void __iomem *reg);
 
@@ -258,5 +202,6 @@ struct mtk_clk_desc {
 };
 
 int mtk_clk_simple_probe(struct platform_device *pdev);
+int mtk_clk_simple_remove(struct platform_device *pdev);
 
 #endif /* __DRV_CLK_MTK_H */
index 6d3a50e..21ad5a4 100644 (file)
@@ -4,15 +4,26 @@
  * Author: Owen Chen <owen.chen@mediatek.com>
  */
 
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/slab.h>
+#include <linux/clk-provider.h>
+#include <linux/compiler_types.h>
+#include <linux/container_of.h>
+#include <linux/err.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
 
-#include "clk-mtk.h"
 #include "clk-mux.h"
 
+struct mtk_clk_mux {
+       struct clk_hw hw;
+       struct regmap *regmap;
+       const struct mtk_mux *data;
+       spinlock_t *lock;
+       bool reparent;
+};
+
 static inline struct mtk_clk_mux *to_mtk_clk_mux(struct clk_hw *hw)
 {
        return container_of(hw, struct mtk_clk_mux, hw);
@@ -164,6 +175,21 @@ static struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
        return clk;
 }
 
+static void mtk_clk_unregister_mux(struct clk *clk)
+{
+       struct mtk_clk_mux *mux;
+       struct clk_hw *hw;
+
+       hw = __clk_get_hw(clk);
+       if (!hw)
+               return;
+
+       mux = to_mtk_clk_mux(hw);
+
+       clk_unregister(clk);
+       kfree(mux);
+}
+
 int mtk_clk_register_muxes(const struct mtk_mux *muxes,
                           int num, struct device_node *node,
                           spinlock_t *lock,
@@ -175,29 +201,64 @@ int mtk_clk_register_muxes(const struct mtk_mux *muxes,
 
        regmap = device_node_to_regmap(node);
        if (IS_ERR(regmap)) {
-               pr_err("Cannot find regmap for %pOF: %ld\n", node,
-                      PTR_ERR(regmap));
+               pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap);
                return PTR_ERR(regmap);
        }
 
        for (i = 0; i < num; i++) {
                const struct mtk_mux *mux = &muxes[i];
 
-               if (IS_ERR_OR_NULL(clk_data->clks[mux->id])) {
-                       clk = mtk_clk_register_mux(mux, regmap, lock);
+               if (!IS_ERR_OR_NULL(clk_data->clks[mux->id])) {
+                       pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
+                               node, mux->id);
+                       continue;
+               }
 
-                       if (IS_ERR(clk)) {
-                               pr_err("Failed to register clk %s: %ld\n",
-                                      mux->name, PTR_ERR(clk));
-                               continue;
-                       }
+               clk = mtk_clk_register_mux(mux, regmap, lock);
 
-                       clk_data->clks[mux->id] = clk;
+               if (IS_ERR(clk)) {
+                       pr_err("Failed to register clk %s: %pe\n", mux->name, clk);
+                       goto err;
                }
+
+               clk_data->clks[mux->id] = clk;
        }
 
        return 0;
+
+err:
+       while (--i >= 0) {
+               const struct mtk_mux *mux = &muxes[i];
+
+               if (IS_ERR_OR_NULL(clk_data->clks[mux->id]))
+                       continue;
+
+               mtk_clk_unregister_mux(clk_data->clks[mux->id]);
+               clk_data->clks[mux->id] = ERR_PTR(-ENOENT);
+       }
+
+       return PTR_ERR(clk);
 }
 EXPORT_SYMBOL_GPL(mtk_clk_register_muxes);
 
+void mtk_clk_unregister_muxes(const struct mtk_mux *muxes, int num,
+                             struct clk_onecell_data *clk_data)
+{
+       int i;
+
+       if (!clk_data)
+               return;
+
+       for (i = num; i > 0; i--) {
+               const struct mtk_mux *mux = &muxes[i - 1];
+
+               if (IS_ERR_OR_NULL(clk_data->clks[mux->id]))
+                       continue;
+
+               mtk_clk_unregister_mux(clk_data->clks[mux->id]);
+               clk_data->clks[mux->id] = ERR_PTR(-ENOENT);
+       }
+}
+EXPORT_SYMBOL_GPL(mtk_clk_unregister_muxes);
+
 MODULE_LICENSE("GPL");
index 27841d6..903a3c9 100644 (file)
@@ -7,15 +7,13 @@
 #ifndef __DRV_CLK_MTK_MUX_H
 #define __DRV_CLK_MTK_MUX_H
 
-#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
 
-struct mtk_clk_mux {
-       struct clk_hw hw;
-       struct regmap *regmap;
-       const struct mtk_mux *data;
-       spinlock_t *lock;
-       bool reparent;
-};
+struct clk;
+struct clk_onecell_data;
+struct clk_ops;
+struct device_node;
 
 struct mtk_mux {
        int id;
@@ -88,4 +86,7 @@ int mtk_clk_register_muxes(const struct mtk_mux *muxes,
                           spinlock_t *lock,
                           struct clk_onecell_data *clk_data);
 
+void mtk_clk_unregister_muxes(const struct mtk_mux *muxes, int num,
+                             struct clk_onecell_data *clk_data);
+
 #endif /* __DRV_CLK_MTK_MUX_H */
index 60d7ffa..ccaa208 100644 (file)
@@ -4,15 +4,18 @@
  * Author: James Liao <jamesjj.liao@mediatek.com>
  */
 
-#include <linux/of.h>
-#include <linux/of_address.h>
+#include <linux/clk-provider.h>
+#include <linux/container_of.h>
+#include <linux/delay.h>
+#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/of_address.h>
 #include <linux/slab.h>
-#include <linux/clkdev.h>
-#include <linux/delay.h>
 
-#include "clk-mtk.h"
+#include "clk-pll.h"
+
+#define MHZ                    (1000 * 1000)
 
 #define REG_CON0               0
 #define REG_CON1               4
@@ -359,8 +362,24 @@ static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data,
        return clk;
 }
 
-void mtk_clk_register_plls(struct device_node *node,
-               const struct mtk_pll_data *plls, int num_plls, struct clk_onecell_data *clk_data)
+static void mtk_clk_unregister_pll(struct clk *clk)
+{
+       struct clk_hw *hw;
+       struct mtk_clk_pll *pll;
+
+       hw = __clk_get_hw(clk);
+       if (!hw)
+               return;
+
+       pll = to_mtk_clk_pll(hw);
+
+       clk_unregister(clk);
+       kfree(pll);
+}
+
+int mtk_clk_register_plls(struct device_node *node,
+                         const struct mtk_pll_data *plls, int num_plls,
+                         struct clk_onecell_data *clk_data)
 {
        void __iomem *base;
        int i;
@@ -369,23 +388,82 @@ void mtk_clk_register_plls(struct device_node *node,
        base = of_iomap(node, 0);
        if (!base) {
                pr_err("%s(): ioremap failed\n", __func__);
-               return;
+               return -EINVAL;
        }
 
        for (i = 0; i < num_plls; i++) {
                const struct mtk_pll_data *pll = &plls[i];
 
+               if (!IS_ERR_OR_NULL(clk_data->clks[pll->id])) {
+                       pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
+                               node, pll->id);
+                       continue;
+               }
+
                clk = mtk_clk_register_pll(pll, base);
 
                if (IS_ERR(clk)) {
-                       pr_err("Failed to register clk %s: %ld\n",
-                                       pll->name, PTR_ERR(clk));
-                       continue;
+                       pr_err("Failed to register clk %s: %pe\n", pll->name, clk);
+                       goto err;
                }
 
                clk_data->clks[pll->id] = clk;
        }
+
+       return 0;
+
+err:
+       while (--i >= 0) {
+               const struct mtk_pll_data *pll = &plls[i];
+
+               mtk_clk_unregister_pll(clk_data->clks[pll->id]);
+               clk_data->clks[pll->id] = ERR_PTR(-ENOENT);
+       }
+
+       iounmap(base);
+
+       return PTR_ERR(clk);
 }
 EXPORT_SYMBOL_GPL(mtk_clk_register_plls);
 
+static __iomem void *mtk_clk_pll_get_base(struct clk *clk,
+                                         const struct mtk_pll_data *data)
+{
+       struct clk_hw *hw = __clk_get_hw(clk);
+       struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
+
+       return pll->base_addr - data->reg;
+}
+
+void mtk_clk_unregister_plls(const struct mtk_pll_data *plls, int num_plls,
+                            struct clk_onecell_data *clk_data)
+{
+       __iomem void *base = NULL;
+       int i;
+
+       if (!clk_data)
+               return;
+
+       for (i = num_plls; i > 0; i--) {
+               const struct mtk_pll_data *pll = &plls[i - 1];
+
+               if (IS_ERR_OR_NULL(clk_data->clks[pll->id]))
+                       continue;
+
+               /*
+                * This is quite ugly but unfortunately the clks don't have
+                * any device tied to them, so there's no place to store the
+                * pointer to the I/O region base address. We have to fetch
+                * it from one of the registered clks.
+                */
+               base = mtk_clk_pll_get_base(clk_data->clks[pll->id], pll);
+
+               mtk_clk_unregister_pll(clk_data->clks[pll->id]);
+               clk_data->clks[pll->id] = ERR_PTR(-ENOENT);
+       }
+
+       iounmap(base);
+}
+EXPORT_SYMBOL_GPL(mtk_clk_unregister_plls);
+
 MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h
new file mode 100644 (file)
index 0000000..bf06e44
--- /dev/null
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ */
+
+#ifndef __DRV_CLK_MTK_PLL_H
+#define __DRV_CLK_MTK_PLL_H
+
+#include <linux/types.h>
+
+struct clk_ops;
+struct clk_onecell_data;
+struct device_node;
+
+struct mtk_pll_div_table {
+       u32 div;
+       unsigned long freq;
+};
+
+#define HAVE_RST_BAR   BIT(0)
+#define PLL_AO         BIT(1)
+
+struct mtk_pll_data {
+       int id;
+       const char *name;
+       u32 reg;
+       u32 pwr_reg;
+       u32 en_mask;
+       u32 pd_reg;
+       u32 tuner_reg;
+       u32 tuner_en_reg;
+       u8 tuner_en_bit;
+       int pd_shift;
+       unsigned int flags;
+       const struct clk_ops *ops;
+       u32 rst_bar_mask;
+       unsigned long fmin;
+       unsigned long fmax;
+       int pcwbits;
+       int pcwibits;
+       u32 pcw_reg;
+       int pcw_shift;
+       u32 pcw_chg_reg;
+       const struct mtk_pll_div_table *div_table;
+       const char *parent_name;
+       u32 en_reg;
+       u8 pll_en_bit; /* Assume 0, indicates BIT(0) by default */
+};
+
+int mtk_clk_register_plls(struct device_node *node,
+                         const struct mtk_pll_data *plls, int num_plls,
+                         struct clk_onecell_data *clk_data);
+void mtk_clk_unregister_plls(const struct mtk_pll_data *plls, int num_plls,
+                            struct clk_onecell_data *clk_data);
+
+#endif /* __DRV_CLK_MTK_PLL_H */
index ffe464c..bcec4b8 100644 (file)
@@ -100,8 +100,7 @@ static void mtk_register_reset_controller_common(struct device_node *np,
 
        regmap = device_node_to_regmap(np);
        if (IS_ERR(regmap)) {
-               pr_err("Cannot find regmap for %pOF: %ld\n", np,
-                               PTR_ERR(regmap));
+               pr_err("Cannot find regmap for %pOF: %pe\n", np, regmap);
                return;
        }
 
diff --git a/drivers/clk/microchip/Kconfig b/drivers/clk/microchip/Kconfig
new file mode 100644 (file)
index 0000000..a5a9987
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config COMMON_CLK_PIC32
+       def_bool COMMON_CLK && MACH_PIC32
+
+config MCHP_CLK_MPFS
+       bool "Clk driver for PolarFire SoC"
+       depends on (RISCV && SOC_MICROCHIP_POLARFIRE) || COMPILE_TEST
+       help
+         Supports Clock Configuration for PolarFire SoC
index f34b247..5fa6dcf 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_COMMON_CLK_PIC32) += clk-core.o
 obj-$(CONFIG_PIC32MZDA) += clk-pic32mzda.o
+obj-$(CONFIG_MCHP_CLK_MPFS) += clk-mpfs.o
diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c
new file mode 100644 (file)
index 0000000..aa1561b
--- /dev/null
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Daire McNamara,<daire.mcnamara@microchip.com>
+ * Copyright (C) 2020 Microchip Technology Inc.  All rights reserved.
+ */
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <dt-bindings/clock/microchip,mpfs-clock.h>
+
+/* address offset of control registers */
+#define REG_CLOCK_CONFIG_CR    0x08u
+#define REG_SUBBLK_CLOCK_CR    0x84u
+#define REG_SUBBLK_RESET_CR    0x88u
+
+struct mpfs_clock_data {
+       void __iomem *base;
+       struct clk_hw_onecell_data hw_data;
+};
+
+struct mpfs_cfg_clock {
+       const struct clk_div_table *table;
+       unsigned int id;
+       u8 shift;
+       u8 width;
+};
+
+struct mpfs_cfg_hw_clock {
+       struct mpfs_cfg_clock cfg;
+       void __iomem *sys_base;
+       struct clk_hw hw;
+       struct clk_init_data init;
+};
+
+#define to_mpfs_cfg_clk(_hw) container_of(_hw, struct mpfs_cfg_hw_clock, hw)
+
+struct mpfs_periph_clock {
+       unsigned int id;
+       u8 shift;
+};
+
+struct mpfs_periph_hw_clock {
+       struct mpfs_periph_clock periph;
+       void __iomem *sys_base;
+       struct clk_hw hw;
+};
+
+#define to_mpfs_periph_clk(_hw) container_of(_hw, struct mpfs_periph_hw_clock, hw)
+
+/*
+ * mpfs_clk_lock prevents anything else from writing to the
+ * mpfs clk block while a software locked register is being written.
+ */
+static DEFINE_SPINLOCK(mpfs_clk_lock);
+
+static const struct clk_parent_data mpfs_cfg_parent[] = {
+       { .index = 0 },
+};
+
+static const struct clk_div_table mpfs_div_cpu_axi_table[] = {
+       { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 },
+       { 0, 0 }
+};
+
+static const struct clk_div_table mpfs_div_ahb_table[] = {
+       { 1, 2 }, { 2, 4}, { 3, 8 },
+       { 0, 0 }
+};
+
+static unsigned long mpfs_cfg_clk_recalc_rate(struct clk_hw *hw, unsigned long prate)
+{
+       struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
+       struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
+       void __iomem *base_addr = cfg_hw->sys_base;
+       u32 val;
+
+       val = readl_relaxed(base_addr + REG_CLOCK_CONFIG_CR) >> cfg->shift;
+       val &= clk_div_mask(cfg->width);
+
+       return prate / (1u << val);
+}
+
+static long mpfs_cfg_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate)
+{
+       struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
+       struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
+
+       return divider_round_rate(hw, rate, prate, cfg->table, cfg->width, 0);
+}
+
+static int mpfs_cfg_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
+{
+       struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
+       struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
+       void __iomem *base_addr = cfg_hw->sys_base;
+       unsigned long flags;
+       u32 val;
+       int divider_setting;
+
+       divider_setting = divider_get_val(rate, prate, cfg->table, cfg->width, 0);
+
+       if (divider_setting < 0)
+               return divider_setting;
+
+       spin_lock_irqsave(&mpfs_clk_lock, flags);
+
+       val = readl_relaxed(base_addr + REG_CLOCK_CONFIG_CR);
+       val &= ~(clk_div_mask(cfg->width) << cfg_hw->cfg.shift);
+       val |= divider_setting << cfg->shift;
+       writel_relaxed(val, base_addr + REG_CLOCK_CONFIG_CR);
+
+       spin_unlock_irqrestore(&mpfs_clk_lock, flags);
+
+       return 0;
+}
+
+static const struct clk_ops mpfs_clk_cfg_ops = {
+       .recalc_rate = mpfs_cfg_clk_recalc_rate,
+       .round_rate = mpfs_cfg_clk_round_rate,
+       .set_rate = mpfs_cfg_clk_set_rate,
+};
+
+#define CLK_CFG(_id, _name, _parent, _shift, _width, _table, _flags) {         \
+       .cfg.id = _id,                                                          \
+       .cfg.shift = _shift,                                                    \
+       .cfg.width = _width,                                                    \
+       .cfg.table = _table,                                                    \
+       .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent, &mpfs_clk_cfg_ops,  \
+                                           _flags),                            \
+}
+
+static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = {
+       CLK_CFG(CLK_CPU, "clk_cpu", mpfs_cfg_parent, 0, 2, mpfs_div_cpu_axi_table, 0),
+       CLK_CFG(CLK_AXI, "clk_axi", mpfs_cfg_parent, 2, 2, mpfs_div_cpu_axi_table, 0),
+       CLK_CFG(CLK_AHB, "clk_ahb", mpfs_cfg_parent, 4, 2, mpfs_div_ahb_table, 0),
+};
+
+static int mpfs_clk_register_cfg(struct device *dev, struct mpfs_cfg_hw_clock *cfg_hw,
+                                void __iomem *sys_base)
+{
+       cfg_hw->sys_base = sys_base;
+
+       return devm_clk_hw_register(dev, &cfg_hw->hw);
+}
+
+static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *cfg_hws,
+                                 unsigned int num_clks, struct mpfs_clock_data *data)
+{
+       void __iomem *sys_base = data->base;
+       unsigned int i, id;
+       int ret;
+
+       for (i = 0; i < num_clks; i++) {
+               struct mpfs_cfg_hw_clock *cfg_hw = &cfg_hws[i];
+
+               ret = mpfs_clk_register_cfg(dev, cfg_hw, sys_base);
+               if (ret)
+                       return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
+                                            cfg_hw->cfg.id);
+
+               id = cfg_hws[i].cfg.id;
+               data->hw_data.hws[id] = &cfg_hw->hw;
+       }
+
+       return 0;
+}
+
+static int mpfs_periph_clk_enable(struct clk_hw *hw)
+{
+       struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
+       struct mpfs_periph_clock *periph = &periph_hw->periph;
+       void __iomem *base_addr = periph_hw->sys_base;
+       u32 reg, val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mpfs_clk_lock, flags);
+
+       reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR);
+       val = reg & ~(1u << periph->shift);
+       writel_relaxed(val, base_addr + REG_SUBBLK_RESET_CR);
+
+       reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR);
+       val = reg | (1u << periph->shift);
+       writel_relaxed(val, base_addr + REG_SUBBLK_CLOCK_CR);
+
+       spin_unlock_irqrestore(&mpfs_clk_lock, flags);
+
+       return 0;
+}
+
+static void mpfs_periph_clk_disable(struct clk_hw *hw)
+{
+       struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
+       struct mpfs_periph_clock *periph = &periph_hw->periph;
+       void __iomem *base_addr = periph_hw->sys_base;
+       u32 reg, val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mpfs_clk_lock, flags);
+
+       reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR);
+       val = reg | (1u << periph->shift);
+       writel_relaxed(val, base_addr + REG_SUBBLK_RESET_CR);
+
+       reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR);
+       val = reg & ~(1u << periph->shift);
+       writel_relaxed(val, base_addr + REG_SUBBLK_CLOCK_CR);
+
+       spin_unlock_irqrestore(&mpfs_clk_lock, flags);
+}
+
+static int mpfs_periph_clk_is_enabled(struct clk_hw *hw)
+{
+       struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
+       struct mpfs_periph_clock *periph = &periph_hw->periph;
+       void __iomem *base_addr = periph_hw->sys_base;
+       u32 reg;
+
+       reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR);
+       if ((reg & (1u << periph->shift)) == 0u) {
+               reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR);
+               if (reg & (1u << periph->shift))
+                       return 1;
+       }
+
+       return 0;
+}
+
+static const struct clk_ops mpfs_periph_clk_ops = {
+       .enable = mpfs_periph_clk_enable,
+       .disable = mpfs_periph_clk_disable,
+       .is_enabled = mpfs_periph_clk_is_enabled,
+};
+
+#define CLK_PERIPH(_id, _name, _parent, _shift, _flags) {                      \
+       .periph.id = _id,                                                       \
+       .periph.shift = _shift,                                                 \
+       .hw.init = CLK_HW_INIT_HW(_name, _parent, &mpfs_periph_clk_ops,         \
+                                 _flags),                                      \
+}
+
+#define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT].hw)
+
+/*
+ * Critical clocks:
+ * - CLK_ENVM: reserved by hart software services (hss) superloop monitor/m mode interrupt
+ *   trap handler
+ * - CLK_MMUART0: reserved by the hss
+ * - CLK_DDRC: provides clock to the ddr subsystem
+ * - CLK_FICx: these provide clocks for sections of the fpga fabric, disabling them would
+ *   cause the fabric to go into reset
+ */
+
+static struct mpfs_periph_hw_clock mpfs_periph_clks[] = {
+       CLK_PERIPH(CLK_ENVM, "clk_periph_envm", PARENT_CLK(AHB), 0, CLK_IS_CRITICAL),
+       CLK_PERIPH(CLK_MAC0, "clk_periph_mac0", PARENT_CLK(AHB), 1, 0),
+       CLK_PERIPH(CLK_MAC1, "clk_periph_mac1", PARENT_CLK(AHB), 2, 0),
+       CLK_PERIPH(CLK_MMC, "clk_periph_mmc", PARENT_CLK(AHB), 3, 0),
+       CLK_PERIPH(CLK_TIMER, "clk_periph_timer", PARENT_CLK(AHB), 4, 0),
+       CLK_PERIPH(CLK_MMUART0, "clk_periph_mmuart0", PARENT_CLK(AHB), 5, CLK_IS_CRITICAL),
+       CLK_PERIPH(CLK_MMUART1, "clk_periph_mmuart1", PARENT_CLK(AHB), 6, 0),
+       CLK_PERIPH(CLK_MMUART2, "clk_periph_mmuart2", PARENT_CLK(AHB), 7, 0),
+       CLK_PERIPH(CLK_MMUART3, "clk_periph_mmuart3", PARENT_CLK(AHB), 8, 0),
+       CLK_PERIPH(CLK_MMUART4, "clk_periph_mmuart4", PARENT_CLK(AHB), 9, 0),
+       CLK_PERIPH(CLK_SPI0, "clk_periph_spi0", PARENT_CLK(AHB), 10, 0),
+       CLK_PERIPH(CLK_SPI1, "clk_periph_spi1", PARENT_CLK(AHB), 11, 0),
+       CLK_PERIPH(CLK_I2C0, "clk_periph_i2c0", PARENT_CLK(AHB), 12, 0),
+       CLK_PERIPH(CLK_I2C1, "clk_periph_i2c1", PARENT_CLK(AHB), 13, 0),
+       CLK_PERIPH(CLK_CAN0, "clk_periph_can0", PARENT_CLK(AHB), 14, 0),
+       CLK_PERIPH(CLK_CAN1, "clk_periph_can1", PARENT_CLK(AHB), 15, 0),
+       CLK_PERIPH(CLK_USB, "clk_periph_usb", PARENT_CLK(AHB), 16, 0),
+       CLK_PERIPH(CLK_RTC, "clk_periph_rtc", PARENT_CLK(AHB), 18, 0),
+       CLK_PERIPH(CLK_QSPI, "clk_periph_qspi", PARENT_CLK(AHB), 19, 0),
+       CLK_PERIPH(CLK_GPIO0, "clk_periph_gpio0", PARENT_CLK(AHB), 20, 0),
+       CLK_PERIPH(CLK_GPIO1, "clk_periph_gpio1", PARENT_CLK(AHB), 21, 0),
+       CLK_PERIPH(CLK_GPIO2, "clk_periph_gpio2", PARENT_CLK(AHB), 22, 0),
+       CLK_PERIPH(CLK_DDRC, "clk_periph_ddrc", PARENT_CLK(AHB), 23, CLK_IS_CRITICAL),
+       CLK_PERIPH(CLK_FIC0, "clk_periph_fic0", PARENT_CLK(AHB), 24, CLK_IS_CRITICAL),
+       CLK_PERIPH(CLK_FIC1, "clk_periph_fic1", PARENT_CLK(AHB), 25, CLK_IS_CRITICAL),
+       CLK_PERIPH(CLK_FIC2, "clk_periph_fic2", PARENT_CLK(AHB), 26, CLK_IS_CRITICAL),
+       CLK_PERIPH(CLK_FIC3, "clk_periph_fic3", PARENT_CLK(AHB), 27, CLK_IS_CRITICAL),
+       CLK_PERIPH(CLK_ATHENA, "clk_periph_athena", PARENT_CLK(AHB), 28, 0),
+       CLK_PERIPH(CLK_CFM, "clk_periph_cfm", PARENT_CLK(AHB), 29, 0),
+};
+
+static int mpfs_clk_register_periph(struct device *dev, struct mpfs_periph_hw_clock *periph_hw,
+                                   void __iomem *sys_base)
+{
+       periph_hw->sys_base = sys_base;
+
+       return devm_clk_hw_register(dev, &periph_hw->hw);
+}
+
+static int mpfs_clk_register_periphs(struct device *dev, struct mpfs_periph_hw_clock *periph_hws,
+                                    int num_clks, struct mpfs_clock_data *data)
+{
+       void __iomem *sys_base = data->base;
+       unsigned int i, id;
+       int ret;
+
+       for (i = 0; i < num_clks; i++) {
+               struct mpfs_periph_hw_clock *periph_hw = &periph_hws[i];
+
+               ret = mpfs_clk_register_periph(dev, periph_hw, sys_base);
+               if (ret)
+                       return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
+                                            periph_hw->periph.id);
+
+               id = periph_hws[i].periph.id;
+               data->hw_data.hws[id] = &periph_hw->hw;
+       }
+
+       return 0;
+}
+
+static int mpfs_clk_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mpfs_clock_data *clk_data;
+       unsigned int num_clks;
+       int ret;
+
+       /* CLK_RESERVED is not part of cfg_clks nor periph_clks, so add 1 */
+       num_clks = ARRAY_SIZE(mpfs_cfg_clks) + ARRAY_SIZE(mpfs_periph_clks) + 1;
+
+       clk_data = devm_kzalloc(dev, struct_size(clk_data, hw_data.hws, num_clks), GFP_KERNEL);
+       if (!clk_data)
+               return -ENOMEM;
+
+       clk_data->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(clk_data->base))
+               return PTR_ERR(clk_data->base);
+
+       clk_data->hw_data.num = num_clks;
+
+       ret = mpfs_clk_register_cfgs(dev, mpfs_cfg_clks, ARRAY_SIZE(mpfs_cfg_clks), clk_data);
+       if (ret)
+               return ret;
+
+       ret = mpfs_clk_register_periphs(dev, mpfs_periph_clks, ARRAY_SIZE(mpfs_periph_clks),
+                                       clk_data);
+       if (ret)
+               return ret;
+
+       ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, &clk_data->hw_data);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+static const struct of_device_id mpfs_clk_of_match_table[] = {
+       { .compatible = "microchip,mpfs-clkcfg", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, mpfs_clk_match_table);
+
+static struct platform_driver mpfs_clk_driver = {
+       .probe = mpfs_clk_probe,
+       .driver = {
+               .name = "microchip-mpfs-clkcfg",
+               .of_match_table = mpfs_clk_of_match_table,
+       },
+};
+
+static int __init clk_mpfs_init(void)
+{
+       return platform_driver_register(&mpfs_clk_driver);
+}
+core_initcall(clk_mpfs_init);
+
+static void __exit clk_mpfs_exit(void)
+{
+       platform_driver_unregister(&mpfs_clk_driver);
+}
+module_exit(clk_mpfs_exit);
+
+MODULE_DESCRIPTION("Microchip PolarFire SoC Clock Driver");
+MODULE_LICENSE("GPL v2");
index 0839fb2..50a7802 100644 (file)
@@ -317,9 +317,9 @@ static const char * const ccic_parent_names[] = {"pll1_2", "pll1_16", "vctcxo"};
 
 static DEFINE_SPINLOCK(gpu_lock);
 static const char * const mmp2_gpu_gc_parent_names[] =  {"pll1_2", "pll1_3", "pll2_2", "pll2_3", "pll2", "usb_pll"};
-static u32 mmp2_gpu_gc_parent_table[] =          { 0x0000,   0x0040,   0x0080,   0x00c0,   0x1000, 0x1040   };
+static const u32 mmp2_gpu_gc_parent_table[] = { 0x0000,   0x0040,   0x0080,   0x00c0,   0x1000, 0x1040   };
 static const char * const mmp2_gpu_bus_parent_names[] = {"pll1_4", "pll2",   "pll2_2", "usb_pll"};
-static u32 mmp2_gpu_bus_parent_table[] =         { 0x0000,   0x0020,   0x0030,   0x4020   };
+static const u32 mmp2_gpu_bus_parent_table[] = { 0x0000,   0x0020,   0x0030,   0x4020   };
 static const char * const mmp3_gpu_bus_parent_names[] = {"pll1_4", "pll1_6", "pll1_2", "pll2_2"};
 static const char * const mmp3_gpu_gc_parent_names[] =  {"pll1",   "pll2",   "pll1_p", "pll2_p"};
 
index 32ac6b6..e3777ca 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 
 #define TBG_SEL                0x0
 #define DIV_SEL0       0x4
@@ -541,7 +542,7 @@ static void clk_pm_cpu_set_rate_wa(struct clk_pm_cpu *pm_cpu,
         * We are going to L0 with rate >= 1GHz. Check whether we have been at
         * L1 for long enough time. If not, go to L1 for 20ms.
         */
-       if (pm_cpu->l1_expiration && jiffies >= pm_cpu->l1_expiration)
+       if (pm_cpu->l1_expiration && time_is_before_eq_jiffies(pm_cpu->l1_expiration))
                goto invalidate_l1_exp;
 
        regmap_update_bits(base, ARMADA_37XX_NB_CPU_LOAD,
index 8b686da..c23ac46 100644 (file)
@@ -457,9 +457,8 @@ static unsigned long lpc18xx_pll1_recalc_rate(struct clk_hw *hw,
        struct lpc18xx_pll *pll = to_lpc_pll(hw);
        u16 msel, nsel, psel;
        bool direct, fbsel;
-       u32 stat, ctrl;
+       u32 ctrl;
 
-       stat = readl(pll->reg + LPC18XX_CGU_PLL1_STAT);
        ctrl = readl(pll->reg + LPC18XX_CGU_PLL1_CTRL);
 
        direct = (ctrl & LPC18XX_PLL1_CTRL_DIRECT) ? true : false;
@@ -523,7 +522,7 @@ static struct lpc18xx_cgu_pll_clk lpc18xx_cgu_src_clk_plls[] = {
        LPC1XX_CGU_CLK_PLL(PLL1,        pll1_src_ids, pll1_ops),
 };
 
-static void lpc18xx_fill_parent_names(const char **parent, u32 *id, int size)
+static void lpc18xx_fill_parent_names(const char **parent, const u32 *id, int size)
 {
        int i;
 
index 76f492c..2a6d583 100644 (file)
@@ -154,7 +154,7 @@ static struct pistachio_pll pistachio_plls[] __initdata = {
 PNAME(mux_debug) = { "mips_pll_mux", "rpu_v_pll_mux",
                     "rpu_l_pll_mux", "sys_pll_mux",
                     "wifi_pll_mux", "bt_pll_mux" };
-static u32 mux_debug_idx[] = { 0x0, 0x1, 0x2, 0x4, 0x8, 0x10 };
+static const u32 mux_debug_idx[] = { 0x0, 0x1, 0x2, 0x4, 0x8, 0x10 };
 
 static unsigned int pistachio_critical_clks_core[] __initdata = {
        CLK_MIPS
index 4fec1f9..88d4b33 100644 (file)
@@ -17,7 +17,7 @@ static const char *aux_parents[] = {
        "pxo",
 };
 
-static unsigned int aux_parent_map[] = {
+static const u32 aux_parent_map[] = {
        3,
        0,
 };
index be6e6ae..c281f3a 100644 (file)
@@ -34,6 +34,7 @@ config CLK_RENESAS
        select CLK_R8A779F0 if ARCH_R8A779F0
        select CLK_R9A06G032 if ARCH_R9A06G032
        select CLK_R9A07G044 if ARCH_R9A07G044
+       select CLK_R9A07G054 if ARCH_R9A07G054
        select CLK_SH73A0 if ARCH_SH73A0
 
 if CLK_RENESAS
@@ -163,6 +164,10 @@ config CLK_R9A07G044
        bool "RZ/G2L clock support" if COMPILE_TEST
        select CLK_RZG2L
 
+config CLK_R9A07G054
+       bool "RZ/V2L clock support" if COMPILE_TEST
+       select CLK_RZG2L
+
 config CLK_SH73A0
        bool "SH-Mobile AG5 clock support" if COMPILE_TEST
        select CLK_RENESAS_CPG_MSTP
@@ -195,7 +200,7 @@ config CLK_RCAR_USB2_CLOCK_SEL
          This is a driver for R-Car USB2 clock selector
 
 config CLK_RZG2L
-       bool "Renesas RZ/G2L family clock support" if COMPILE_TEST
+       bool "Renesas RZ/{G2L,V2L} family clock support" if COMPILE_TEST
        select RESET_CONTROLLER
 
 # Generic
index 8b34db1..d5e5716 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_CLK_R8A779A0)            += r8a779a0-cpg-mssr.o
 obj-$(CONFIG_CLK_R8A779F0)             += r8a779f0-cpg-mssr.o
 obj-$(CONFIG_CLK_R9A06G032)            += r9a06g032-clocks.o
 obj-$(CONFIG_CLK_R9A07G044)            += r9a07g044-cpg.o
+obj-$(CONFIG_CLK_R9A07G054)            += r9a07g044-cpg.o
 obj-$(CONFIG_CLK_SH73A0)               += clk-sh73a0.o
 
 # Family
index faf60f7..d34d97b 100644 (file)
@@ -200,6 +200,7 @@ static const struct mssr_mod_clk r8a77990_mod_clks[] __initconst = {
        DEF_MOD("du0",                   724,   R8A77990_CLK_S1D1),
        DEF_MOD("lvds",                  727,   R8A77990_CLK_S2D1),
 
+       DEF_MOD("mlp",                   802,   R8A77990_CLK_S2D1),
        DEF_MOD("vin5",                  806,   R8A77990_CLK_S1D2),
        DEF_MOD("vin4",                  807,   R8A77990_CLK_S1D2),
        DEF_MOD("etheravb",              812,   R8A77990_CLK_S3D2),
index 7713cfd..525eef1 100644 (file)
@@ -160,6 +160,7 @@ static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = {
        DEF_MOD("du1",                   723,   R8A77995_CLK_S1D1),
        DEF_MOD("du0",                   724,   R8A77995_CLK_S1D1),
        DEF_MOD("lvds",                  727,   R8A77995_CLK_S2D1),
+       DEF_MOD("mlp",                   802,   R8A77995_CLK_S2D1),
        DEF_MOD("vin4",                  807,   R8A77995_CLK_S1D2),
        DEF_MOD("etheravb",              812,   R8A77995_CLK_S3D2),
        DEF_MOD("imr0",                  823,   R8A77995_CLK_S1D2),
index 1c09d4e..fadd8a1 100644 (file)
@@ -136,6 +136,7 @@ static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = {
        DEF_MOD("avb3",         214,    R8A779A0_CLK_S3D2),
        DEF_MOD("avb4",         215,    R8A779A0_CLK_S3D2),
        DEF_MOD("avb5",         216,    R8A779A0_CLK_S3D2),
+       DEF_MOD("canfd0",       328,    R8A779A0_CLK_CANFD),
        DEF_MOD("csi40",        331,    R8A779A0_CLK_CSI0),
        DEF_MOD("csi41",        400,    R8A779A0_CLK_CSI0),
        DEF_MOD("csi42",        401,    R8A779A0_CLK_CSI0),
index e6ec02c..76b4419 100644 (file)
@@ -103,7 +103,7 @@ static const struct cpg_core_clk r8a779f0_core_clks[] __initconst = {
        DEF_FIXED("s0d12_hsc",  R8A779F0_CLK_S0D12_HSC, CLK_S0,         12, 1),
        DEF_FIXED("cl16m_hsc",  R8A779F0_CLK_CL16M_HSC, CLK_S0,         48, 1),
        DEF_FIXED("s0d2_cc",    R8A779F0_CLK_S0D2_CC,   CLK_S0,         2, 1),
-       DEF_FIXED("rsw2",       R8A779F0_CLK_RSW2,      CLK_PLL5,       2, 1),
+       DEF_FIXED("rsw2",       R8A779F0_CLK_RSW2,      CLK_PLL5_DIV2,  5, 1),
        DEF_FIXED("cbfusa",     R8A779F0_CLK_CBFUSA,    CLK_EXTAL,      2, 1),
        DEF_FIXED("cpex",       R8A779F0_CLK_CPEX,      CLK_EXTAL,      2, 1),
 
@@ -115,10 +115,24 @@ static const struct cpg_core_clk r8a779f0_core_clks[] __initconst = {
 };
 
 static const struct mssr_mod_clk r8a779f0_mod_clks[] __initconst = {
+       DEF_MOD("i2c0",         518,    R8A779F0_CLK_S0D6_PER),
+       DEF_MOD("i2c1",         519,    R8A779F0_CLK_S0D6_PER),
+       DEF_MOD("i2c2",         520,    R8A779F0_CLK_S0D6_PER),
+       DEF_MOD("i2c3",         521,    R8A779F0_CLK_S0D6_PER),
+       DEF_MOD("i2c4",         522,    R8A779F0_CLK_S0D6_PER),
+       DEF_MOD("i2c5",         523,    R8A779F0_CLK_S0D6_PER),
        DEF_MOD("scif0",        702,    R8A779F0_CLK_S0D12_PER),
        DEF_MOD("scif1",        703,    R8A779F0_CLK_S0D12_PER),
        DEF_MOD("scif3",        704,    R8A779F0_CLK_S0D12_PER),
        DEF_MOD("scif4",        705,    R8A779F0_CLK_S0D12_PER),
+       DEF_MOD("sys-dmac0",    709,    R8A779F0_CLK_S0D3_PER),
+       DEF_MOD("sys-dmac1",    710,    R8A779F0_CLK_S0D3_PER),
+       DEF_MOD("wdt",          907,    R8A779F0_CLK_R),
+       DEF_MOD("pfc0",         915,    R8A779F0_CLK_CL16M),
+};
+
+static const unsigned int r8a779f0_crit_mod_clks[] __initconst = {
+       MOD_CLK_ID(907),        /* WDT */
 };
 
 /*
@@ -175,6 +189,10 @@ const struct cpg_mssr_info r8a779f0_cpg_mssr_info __initconst = {
        .num_mod_clks = ARRAY_SIZE(r8a779f0_mod_clks),
        .num_hw_mod_clks = 28 * 32,
 
+       /* Critical Module Clocks */
+       .crit_mod_clks = r8a779f0_crit_mod_clks,
+       .num_crit_mod_clks = ARRAY_SIZE(r8a779f0_crit_mod_clks),
+
        /* Callbacks */
        .init = r8a779f0_cpg_mssr_init,
        .cpg_clk_register = rcar_gen4_cpg_clk_register,
index 79042bf..bdfabb9 100644 (file)
 #include <linux/kernel.h>
 
 #include <dt-bindings/clock/r9a07g044-cpg.h>
+#include <dt-bindings/clock/r9a07g054-cpg.h>
 
 #include "rzg2l-cpg.h"
 
 enum clk_ids {
        /* Core Clock Outputs exported to DT */
-       LAST_DT_CORE_CLK = R9A07G044_CLK_P0_DIV2,
+       LAST_DT_CORE_CLK = R9A07G054_CLK_DRP_A,
 
        /* External Input Clocks */
        CLK_EXTAL,
@@ -80,200 +81,222 @@ static const char * const sel_pll6_2[]    = { ".pll6_250", ".pll5_250" };
 static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" };
 static const char * const sel_gpu2[] = { ".pll6", ".pll3_div2_2" };
 
-static const struct cpg_core_clk r9a07g044_core_clks[] __initconst = {
-       /* External Clock Inputs */
-       DEF_INPUT("extal", CLK_EXTAL),
+static const struct {
+       struct cpg_core_clk common[44];
+#ifdef CONFIG_CLK_R9A07G054
+       struct cpg_core_clk drp[0];
+#endif
+} core_clks __initconst = {
+       .common = {
+               /* External Clock Inputs */
+               DEF_INPUT("extal", CLK_EXTAL),
 
-       /* Internal Core Clocks */
-       DEF_FIXED(".osc", R9A07G044_OSCCLK, CLK_EXTAL, 1, 1),
-       DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000),
-       DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, PLL146_CONF(0)),
-       DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 133, 2),
-       DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 133, 2),
-       DEF_FIXED(".pll3_400", CLK_PLL3_400, CLK_PLL3, 1, 4),
-       DEF_FIXED(".pll3_533", CLK_PLL3_533, CLK_PLL3, 1, 3),
+               /* Internal Core Clocks */
+               DEF_FIXED(".osc", R9A07G044_OSCCLK, CLK_EXTAL, 1, 1),
+               DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000),
+               DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, PLL146_CONF(0)),
+               DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3),
+               DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3),
+               DEF_FIXED(".pll3_400", CLK_PLL3_400, CLK_PLL3, 1, 4),
+               DEF_FIXED(".pll3_533", CLK_PLL3_533, CLK_PLL3, 1, 3),
 
-       DEF_FIXED(".pll5", CLK_PLL5, CLK_EXTAL, 125, 1),
-       DEF_FIXED(".pll5_fout3", CLK_PLL5_FOUT3, CLK_PLL5, 1, 6),
+               DEF_FIXED(".pll5", CLK_PLL5, CLK_EXTAL, 125, 1),
+               DEF_FIXED(".pll5_fout3", CLK_PLL5_FOUT3, CLK_PLL5, 1, 6),
 
-       DEF_FIXED(".pll6", CLK_PLL6, CLK_EXTAL, 125, 6),
+               DEF_FIXED(".pll6", CLK_PLL6, CLK_EXTAL, 125, 6),
 
-       DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2),
-       DEF_FIXED(".clk_800", CLK_PLL2_800, CLK_PLL2, 1, 2),
-       DEF_FIXED(".clk_533", CLK_PLL2_SDHI_533, CLK_PLL2, 1, 3),
-       DEF_FIXED(".clk_400", CLK_PLL2_SDHI_400, CLK_PLL2_800, 1, 2),
-       DEF_FIXED(".clk_266", CLK_PLL2_SDHI_266, CLK_PLL2_SDHI_533, 1, 2),
+               DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2),
+               DEF_FIXED(".clk_800", CLK_PLL2_800, CLK_PLL2, 1, 2),
+               DEF_FIXED(".clk_533", CLK_PLL2_SDHI_533, CLK_PLL2, 1, 3),
+               DEF_FIXED(".clk_400", CLK_PLL2_SDHI_400, CLK_PLL2_800, 1, 2),
+               DEF_FIXED(".clk_266", CLK_PLL2_SDHI_266, CLK_PLL2_SDHI_533, 1, 2),
 
-       DEF_FIXED(".pll2_div2_8", CLK_PLL2_DIV2_8, CLK_PLL2_DIV2, 1, 8),
-       DEF_FIXED(".pll2_div2_10", CLK_PLL2_DIV2_10, CLK_PLL2_DIV2, 1, 10),
+               DEF_FIXED(".pll2_div2_8", CLK_PLL2_DIV2_8, CLK_PLL2_DIV2, 1, 8),
+               DEF_FIXED(".pll2_div2_10", CLK_PLL2_DIV2_10, CLK_PLL2_DIV2, 1, 10),
 
-       DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 1, 2),
-       DEF_FIXED(".pll3_div2_2", CLK_PLL3_DIV2_2, CLK_PLL3_DIV2, 1, 2),
-       DEF_FIXED(".pll3_div2_4", CLK_PLL3_DIV2_4, CLK_PLL3_DIV2, 1, 4),
-       DEF_FIXED(".pll3_div2_4_2", CLK_PLL3_DIV2_4_2, CLK_PLL3_DIV2_4, 1, 2),
-       DEF_MUX(".sel_pll3_3", CLK_SEL_PLL3_3, SEL_PLL3_3,
-               sel_pll3_3, ARRAY_SIZE(sel_pll3_3), 0, CLK_MUX_READ_ONLY),
-       DEF_DIV("divpl3c", CLK_DIV_PLL3_C, CLK_SEL_PLL3_3,
-               DIVPL3C, dtable_1_32, CLK_DIVIDER_HIWORD_MASK),
+               DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 1, 2),
+               DEF_FIXED(".pll3_div2_2", CLK_PLL3_DIV2_2, CLK_PLL3_DIV2, 1, 2),
+               DEF_FIXED(".pll3_div2_4", CLK_PLL3_DIV2_4, CLK_PLL3_DIV2, 1, 4),
+               DEF_FIXED(".pll3_div2_4_2", CLK_PLL3_DIV2_4_2, CLK_PLL3_DIV2_4, 1, 2),
+               DEF_MUX(".sel_pll3_3", CLK_SEL_PLL3_3, SEL_PLL3_3,
+                       sel_pll3_3, ARRAY_SIZE(sel_pll3_3), 0, CLK_MUX_READ_ONLY),
+               DEF_DIV("divpl3c", CLK_DIV_PLL3_C, CLK_SEL_PLL3_3,
+                       DIVPL3C, dtable_1_32, CLK_DIVIDER_HIWORD_MASK),
 
-       DEF_FIXED(".pll5_250", CLK_PLL5_250, CLK_PLL5_FOUT3, 1, 2),
-       DEF_FIXED(".pll6_250", CLK_PLL6_250, CLK_PLL6, 1, 2),
-       DEF_MUX(".sel_gpu2", CLK_SEL_GPU2, SEL_GPU2,
-               sel_gpu2, ARRAY_SIZE(sel_gpu2), 0, CLK_MUX_READ_ONLY),
+               DEF_FIXED(".pll5_250", CLK_PLL5_250, CLK_PLL5_FOUT3, 1, 2),
+               DEF_FIXED(".pll6_250", CLK_PLL6_250, CLK_PLL6, 1, 2),
+               DEF_MUX(".sel_gpu2", CLK_SEL_GPU2, SEL_GPU2,
+                       sel_gpu2, ARRAY_SIZE(sel_gpu2), 0, CLK_MUX_READ_ONLY),
 
-       /* Core output clk */
-       DEF_DIV("I", R9A07G044_CLK_I, CLK_PLL1, DIVPL1A, dtable_1_8,
-               CLK_DIVIDER_HIWORD_MASK),
-       DEF_DIV("P0", R9A07G044_CLK_P0, CLK_PLL2_DIV2_8, DIVPL2A,
-               dtable_1_32, CLK_DIVIDER_HIWORD_MASK),
-       DEF_FIXED("P0_DIV2", R9A07G044_CLK_P0_DIV2, R9A07G044_CLK_P0, 1, 2),
-       DEF_FIXED("TSU", R9A07G044_CLK_TSU, CLK_PLL2_DIV2_10, 1, 1),
-       DEF_DIV("P1", R9A07G044_CLK_P1, CLK_PLL3_DIV2_4,
-               DIVPL3B, dtable_1_32, CLK_DIVIDER_HIWORD_MASK),
-       DEF_FIXED("P1_DIV2", CLK_P1_DIV2, R9A07G044_CLK_P1, 1, 2),
-       DEF_DIV("P2", R9A07G044_CLK_P2, CLK_PLL3_DIV2_4_2,
-               DIVPL3A, dtable_1_32, CLK_DIVIDER_HIWORD_MASK),
-       DEF_FIXED("M0", R9A07G044_CLK_M0, CLK_PLL3_DIV2_4, 1, 1),
-       DEF_FIXED("ZT", R9A07G044_CLK_ZT, CLK_PLL3_DIV2_4_2, 1, 1),
-       DEF_MUX("HP", R9A07G044_CLK_HP, SEL_PLL6_2,
-               sel_pll6_2, ARRAY_SIZE(sel_pll6_2), 0, CLK_MUX_HIWORD_MASK),
-       DEF_FIXED("SPI0", R9A07G044_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2),
-       DEF_FIXED("SPI1", R9A07G044_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4),
-       DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0,
-                  sel_shdi, ARRAY_SIZE(sel_shdi)),
-       DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1,
-                  sel_shdi, ARRAY_SIZE(sel_shdi)),
-       DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4),
-       DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4),
-       DEF_DIV("G", R9A07G044_CLK_G, CLK_SEL_GPU2, DIVGPU, dtable_1_8,
-               CLK_DIVIDER_HIWORD_MASK),
+               /* Core output clk */
+               DEF_DIV("I", R9A07G044_CLK_I, CLK_PLL1, DIVPL1A, dtable_1_8,
+                       CLK_DIVIDER_HIWORD_MASK),
+               DEF_DIV("P0", R9A07G044_CLK_P0, CLK_PLL2_DIV2_8, DIVPL2A,
+                       dtable_1_32, CLK_DIVIDER_HIWORD_MASK),
+               DEF_FIXED("P0_DIV2", R9A07G044_CLK_P0_DIV2, R9A07G044_CLK_P0, 1, 2),
+               DEF_FIXED("TSU", R9A07G044_CLK_TSU, CLK_PLL2_DIV2_10, 1, 1),
+               DEF_DIV("P1", R9A07G044_CLK_P1, CLK_PLL3_DIV2_4,
+                       DIVPL3B, dtable_1_32, CLK_DIVIDER_HIWORD_MASK),
+               DEF_FIXED("P1_DIV2", CLK_P1_DIV2, R9A07G044_CLK_P1, 1, 2),
+               DEF_DIV("P2", R9A07G044_CLK_P2, CLK_PLL3_DIV2_4_2,
+                       DIVPL3A, dtable_1_32, CLK_DIVIDER_HIWORD_MASK),
+               DEF_FIXED("M0", R9A07G044_CLK_M0, CLK_PLL3_DIV2_4, 1, 1),
+               DEF_FIXED("ZT", R9A07G044_CLK_ZT, CLK_PLL3_DIV2_4_2, 1, 1),
+               DEF_MUX("HP", R9A07G044_CLK_HP, SEL_PLL6_2,
+                       sel_pll6_2, ARRAY_SIZE(sel_pll6_2), 0, CLK_MUX_HIWORD_MASK),
+               DEF_FIXED("SPI0", R9A07G044_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2),
+               DEF_FIXED("SPI1", R9A07G044_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4),
+               DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0,
+                          sel_shdi, ARRAY_SIZE(sel_shdi)),
+               DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1,
+                          sel_shdi, ARRAY_SIZE(sel_shdi)),
+               DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4),
+               DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4),
+               DEF_DIV("G", R9A07G044_CLK_G, CLK_SEL_GPU2, DIVGPU, dtable_1_8,
+                       CLK_DIVIDER_HIWORD_MASK),
+       },
+#ifdef CONFIG_CLK_R9A07G054
+       .drp = {
+       },
+#endif
 };
 
-static struct rzg2l_mod_clk r9a07g044_mod_clks[] = {
-       DEF_MOD("gic",          R9A07G044_GIC600_GICCLK, R9A07G044_CLK_P1,
-                               0x514, 0),
-       DEF_MOD("ia55_pclk",    R9A07G044_IA55_PCLK, R9A07G044_CLK_P2,
-                               0x518, 0),
-       DEF_MOD("ia55_clk",     R9A07G044_IA55_CLK, R9A07G044_CLK_P1,
-                               0x518, 1),
-       DEF_MOD("dmac_aclk",    R9A07G044_DMAC_ACLK, R9A07G044_CLK_P1,
-                               0x52c, 0),
-       DEF_MOD("dmac_pclk",    R9A07G044_DMAC_PCLK, CLK_P1_DIV2,
-                               0x52c, 1),
-       DEF_MOD("ostm0_pclk",   R9A07G044_OSTM0_PCLK, R9A07G044_CLK_P0,
-                               0x534, 0),
-       DEF_MOD("ostm1_clk",    R9A07G044_OSTM1_PCLK, R9A07G044_CLK_P0,
-                               0x534, 1),
-       DEF_MOD("ostm2_pclk",   R9A07G044_OSTM2_PCLK, R9A07G044_CLK_P0,
-                               0x534, 2),
-       DEF_MOD("wdt0_pclk",    R9A07G044_WDT0_PCLK, R9A07G044_CLK_P0,
-                               0x548, 0),
-       DEF_MOD("wdt0_clk",     R9A07G044_WDT0_CLK, R9A07G044_OSCCLK,
-                               0x548, 1),
-       DEF_MOD("wdt1_pclk",    R9A07G044_WDT1_PCLK, R9A07G044_CLK_P0,
-                               0x548, 2),
-       DEF_MOD("wdt1_clk",     R9A07G044_WDT1_CLK, R9A07G044_OSCCLK,
-                               0x548, 3),
-       DEF_MOD("wdt2_pclk",    R9A07G044_WDT2_PCLK, R9A07G044_CLK_P0,
-                               0x548, 4),
-       DEF_MOD("wdt2_clk",     R9A07G044_WDT2_CLK, R9A07G044_OSCCLK,
-                               0x548, 5),
-       DEF_MOD("spi_clk2",     R9A07G044_SPI_CLK2, R9A07G044_CLK_SPI1,
-                               0x550, 0),
-       DEF_MOD("spi_clk",      R9A07G044_SPI_CLK, R9A07G044_CLK_SPI0,
-                               0x550, 1),
-       DEF_MOD("sdhi0_imclk",  R9A07G044_SDHI0_IMCLK, CLK_SD0_DIV4,
-                               0x554, 0),
-       DEF_MOD("sdhi0_imclk2", R9A07G044_SDHI0_IMCLK2, CLK_SD0_DIV4,
-                               0x554, 1),
-       DEF_MOD("sdhi0_clk_hs", R9A07G044_SDHI0_CLK_HS, R9A07G044_CLK_SD0,
-                               0x554, 2),
-       DEF_MOD("sdhi0_aclk",   R9A07G044_SDHI0_ACLK, R9A07G044_CLK_P1,
-                               0x554, 3),
-       DEF_MOD("sdhi1_imclk",  R9A07G044_SDHI1_IMCLK, CLK_SD1_DIV4,
-                               0x554, 4),
-       DEF_MOD("sdhi1_imclk2", R9A07G044_SDHI1_IMCLK2, CLK_SD1_DIV4,
-                               0x554, 5),
-       DEF_MOD("sdhi1_clk_hs", R9A07G044_SDHI1_CLK_HS, R9A07G044_CLK_SD1,
-                               0x554, 6),
-       DEF_MOD("sdhi1_aclk",   R9A07G044_SDHI1_ACLK, R9A07G044_CLK_P1,
-                               0x554, 7),
-       DEF_MOD("gpu_clk",      R9A07G044_GPU_CLK, R9A07G044_CLK_G,
-                               0x558, 0),
-       DEF_MOD("gpu_axi_clk",  R9A07G044_GPU_AXI_CLK, R9A07G044_CLK_P1,
-                               0x558, 1),
-       DEF_MOD("gpu_ace_clk",  R9A07G044_GPU_ACE_CLK, R9A07G044_CLK_P1,
-                               0x558, 2),
-       DEF_MOD("ssi0_pclk",    R9A07G044_SSI0_PCLK2, R9A07G044_CLK_P0,
-                               0x570, 0),
-       DEF_MOD("ssi0_sfr",     R9A07G044_SSI0_PCLK_SFR, R9A07G044_CLK_P0,
-                               0x570, 1),
-       DEF_MOD("ssi1_pclk",    R9A07G044_SSI1_PCLK2, R9A07G044_CLK_P0,
-                               0x570, 2),
-       DEF_MOD("ssi1_sfr",     R9A07G044_SSI1_PCLK_SFR, R9A07G044_CLK_P0,
-                               0x570, 3),
-       DEF_MOD("ssi2_pclk",    R9A07G044_SSI2_PCLK2, R9A07G044_CLK_P0,
-                               0x570, 4),
-       DEF_MOD("ssi2_sfr",     R9A07G044_SSI2_PCLK_SFR, R9A07G044_CLK_P0,
-                               0x570, 5),
-       DEF_MOD("ssi3_pclk",    R9A07G044_SSI3_PCLK2, R9A07G044_CLK_P0,
-                               0x570, 6),
-       DEF_MOD("ssi3_sfr",     R9A07G044_SSI3_PCLK_SFR, R9A07G044_CLK_P0,
-                               0x570, 7),
-       DEF_MOD("usb0_host",    R9A07G044_USB_U2H0_HCLK, R9A07G044_CLK_P1,
-                               0x578, 0),
-       DEF_MOD("usb1_host",    R9A07G044_USB_U2H1_HCLK, R9A07G044_CLK_P1,
-                               0x578, 1),
-       DEF_MOD("usb0_func",    R9A07G044_USB_U2P_EXR_CPUCLK, R9A07G044_CLK_P1,
-                               0x578, 2),
-       DEF_MOD("usb_pclk",     R9A07G044_USB_PCLK, R9A07G044_CLK_P1,
-                               0x578, 3),
-       DEF_COUPLED("eth0_axi", R9A07G044_ETH0_CLK_AXI, R9A07G044_CLK_M0,
-                               0x57c, 0),
-       DEF_COUPLED("eth0_chi", R9A07G044_ETH0_CLK_CHI, R9A07G044_CLK_ZT,
-                               0x57c, 0),
-       DEF_COUPLED("eth1_axi", R9A07G044_ETH1_CLK_AXI, R9A07G044_CLK_M0,
-                               0x57c, 1),
-       DEF_COUPLED("eth1_chi", R9A07G044_ETH1_CLK_CHI, R9A07G044_CLK_ZT,
-                               0x57c, 1),
-       DEF_MOD("i2c0",         R9A07G044_I2C0_PCLK, R9A07G044_CLK_P0,
-                               0x580, 0),
-       DEF_MOD("i2c1",         R9A07G044_I2C1_PCLK, R9A07G044_CLK_P0,
-                               0x580, 1),
-       DEF_MOD("i2c2",         R9A07G044_I2C2_PCLK, R9A07G044_CLK_P0,
-                               0x580, 2),
-       DEF_MOD("i2c3",         R9A07G044_I2C3_PCLK, R9A07G044_CLK_P0,
-                               0x580, 3),
-       DEF_MOD("scif0",        R9A07G044_SCIF0_CLK_PCK, R9A07G044_CLK_P0,
-                               0x584, 0),
-       DEF_MOD("scif1",        R9A07G044_SCIF1_CLK_PCK, R9A07G044_CLK_P0,
-                               0x584, 1),
-       DEF_MOD("scif2",        R9A07G044_SCIF2_CLK_PCK, R9A07G044_CLK_P0,
-                               0x584, 2),
-       DEF_MOD("scif3",        R9A07G044_SCIF3_CLK_PCK, R9A07G044_CLK_P0,
-                               0x584, 3),
-       DEF_MOD("scif4",        R9A07G044_SCIF4_CLK_PCK, R9A07G044_CLK_P0,
-                               0x584, 4),
-       DEF_MOD("sci0",         R9A07G044_SCI0_CLKP, R9A07G044_CLK_P0,
-                               0x588, 0),
-       DEF_MOD("sci1",         R9A07G044_SCI1_CLKP, R9A07G044_CLK_P0,
-                               0x588, 1),
-       DEF_MOD("rspi0",        R9A07G044_RSPI0_CLKB, R9A07G044_CLK_P0,
-                               0x590, 0),
-       DEF_MOD("rspi1",        R9A07G044_RSPI1_CLKB, R9A07G044_CLK_P0,
-                               0x590, 1),
-       DEF_MOD("rspi2",        R9A07G044_RSPI2_CLKB, R9A07G044_CLK_P0,
-                               0x590, 2),
-       DEF_MOD("canfd",        R9A07G044_CANFD_PCLK, R9A07G044_CLK_P0,
-                               0x594, 0),
-       DEF_MOD("gpio",         R9A07G044_GPIO_HCLK, R9A07G044_OSCCLK,
-                               0x598, 0),
-       DEF_MOD("adc_adclk",    R9A07G044_ADC_ADCLK, R9A07G044_CLK_TSU,
-                               0x5a8, 0),
-       DEF_MOD("adc_pclk",     R9A07G044_ADC_PCLK, R9A07G044_CLK_P0,
-                               0x5a8, 1),
-       DEF_MOD("tsu_pclk",     R9A07G044_TSU_PCLK, R9A07G044_CLK_TSU,
-                               0x5ac, 0),
+static const struct {
+       struct rzg2l_mod_clk common[62];
+#ifdef CONFIG_CLK_R9A07G054
+       struct rzg2l_mod_clk drp[0];
+#endif
+} mod_clks = {
+       .common = {
+               DEF_MOD("gic",          R9A07G044_GIC600_GICCLK, R9A07G044_CLK_P1,
+                                       0x514, 0),
+               DEF_MOD("ia55_pclk",    R9A07G044_IA55_PCLK, R9A07G044_CLK_P2,
+                                       0x518, 0),
+               DEF_MOD("ia55_clk",     R9A07G044_IA55_CLK, R9A07G044_CLK_P1,
+                                       0x518, 1),
+               DEF_MOD("dmac_aclk",    R9A07G044_DMAC_ACLK, R9A07G044_CLK_P1,
+                                       0x52c, 0),
+               DEF_MOD("dmac_pclk",    R9A07G044_DMAC_PCLK, CLK_P1_DIV2,
+                                       0x52c, 1),
+               DEF_MOD("ostm0_pclk",   R9A07G044_OSTM0_PCLK, R9A07G044_CLK_P0,
+                                       0x534, 0),
+               DEF_MOD("ostm1_clk",    R9A07G044_OSTM1_PCLK, R9A07G044_CLK_P0,
+                                       0x534, 1),
+               DEF_MOD("ostm2_pclk",   R9A07G044_OSTM2_PCLK, R9A07G044_CLK_P0,
+                                       0x534, 2),
+               DEF_MOD("wdt0_pclk",    R9A07G044_WDT0_PCLK, R9A07G044_CLK_P0,
+                                       0x548, 0),
+               DEF_MOD("wdt0_clk",     R9A07G044_WDT0_CLK, R9A07G044_OSCCLK,
+                                       0x548, 1),
+               DEF_MOD("wdt1_pclk",    R9A07G044_WDT1_PCLK, R9A07G044_CLK_P0,
+                                       0x548, 2),
+               DEF_MOD("wdt1_clk",     R9A07G044_WDT1_CLK, R9A07G044_OSCCLK,
+                                       0x548, 3),
+               DEF_MOD("wdt2_pclk",    R9A07G044_WDT2_PCLK, R9A07G044_CLK_P0,
+                                       0x548, 4),
+               DEF_MOD("wdt2_clk",     R9A07G044_WDT2_CLK, R9A07G044_OSCCLK,
+                                       0x548, 5),
+               DEF_MOD("spi_clk2",     R9A07G044_SPI_CLK2, R9A07G044_CLK_SPI1,
+                                       0x550, 0),
+               DEF_MOD("spi_clk",      R9A07G044_SPI_CLK, R9A07G044_CLK_SPI0,
+                                       0x550, 1),
+               DEF_MOD("sdhi0_imclk",  R9A07G044_SDHI0_IMCLK, CLK_SD0_DIV4,
+                                       0x554, 0),
+               DEF_MOD("sdhi0_imclk2", R9A07G044_SDHI0_IMCLK2, CLK_SD0_DIV4,
+                                       0x554, 1),
+               DEF_MOD("sdhi0_clk_hs", R9A07G044_SDHI0_CLK_HS, R9A07G044_CLK_SD0,
+                                       0x554, 2),
+               DEF_MOD("sdhi0_aclk",   R9A07G044_SDHI0_ACLK, R9A07G044_CLK_P1,
+                                       0x554, 3),
+               DEF_MOD("sdhi1_imclk",  R9A07G044_SDHI1_IMCLK, CLK_SD1_DIV4,
+                                       0x554, 4),
+               DEF_MOD("sdhi1_imclk2", R9A07G044_SDHI1_IMCLK2, CLK_SD1_DIV4,
+                                       0x554, 5),
+               DEF_MOD("sdhi1_clk_hs", R9A07G044_SDHI1_CLK_HS, R9A07G044_CLK_SD1,
+                                       0x554, 6),
+               DEF_MOD("sdhi1_aclk",   R9A07G044_SDHI1_ACLK, R9A07G044_CLK_P1,
+                                       0x554, 7),
+               DEF_MOD("gpu_clk",      R9A07G044_GPU_CLK, R9A07G044_CLK_G,
+                                       0x558, 0),
+               DEF_MOD("gpu_axi_clk",  R9A07G044_GPU_AXI_CLK, R9A07G044_CLK_P1,
+                                       0x558, 1),
+               DEF_MOD("gpu_ace_clk",  R9A07G044_GPU_ACE_CLK, R9A07G044_CLK_P1,
+                                       0x558, 2),
+               DEF_MOD("ssi0_pclk",    R9A07G044_SSI0_PCLK2, R9A07G044_CLK_P0,
+                                       0x570, 0),
+               DEF_MOD("ssi0_sfr",     R9A07G044_SSI0_PCLK_SFR, R9A07G044_CLK_P0,
+                                       0x570, 1),
+               DEF_MOD("ssi1_pclk",    R9A07G044_SSI1_PCLK2, R9A07G044_CLK_P0,
+                                       0x570, 2),
+               DEF_MOD("ssi1_sfr",     R9A07G044_SSI1_PCLK_SFR, R9A07G044_CLK_P0,
+                                       0x570, 3),
+               DEF_MOD("ssi2_pclk",    R9A07G044_SSI2_PCLK2, R9A07G044_CLK_P0,
+                                       0x570, 4),
+               DEF_MOD("ssi2_sfr",     R9A07G044_SSI2_PCLK_SFR, R9A07G044_CLK_P0,
+                                       0x570, 5),
+               DEF_MOD("ssi3_pclk",    R9A07G044_SSI3_PCLK2, R9A07G044_CLK_P0,
+                                       0x570, 6),
+               DEF_MOD("ssi3_sfr",     R9A07G044_SSI3_PCLK_SFR, R9A07G044_CLK_P0,
+                                       0x570, 7),
+               DEF_MOD("usb0_host",    R9A07G044_USB_U2H0_HCLK, R9A07G044_CLK_P1,
+                                       0x578, 0),
+               DEF_MOD("usb1_host",    R9A07G044_USB_U2H1_HCLK, R9A07G044_CLK_P1,
+                                       0x578, 1),
+               DEF_MOD("usb0_func",    R9A07G044_USB_U2P_EXR_CPUCLK, R9A07G044_CLK_P1,
+                                       0x578, 2),
+               DEF_MOD("usb_pclk",     R9A07G044_USB_PCLK, R9A07G044_CLK_P1,
+                                       0x578, 3),
+               DEF_COUPLED("eth0_axi", R9A07G044_ETH0_CLK_AXI, R9A07G044_CLK_M0,
+                                       0x57c, 0),
+               DEF_COUPLED("eth0_chi", R9A07G044_ETH0_CLK_CHI, R9A07G044_CLK_ZT,
+                                       0x57c, 0),
+               DEF_COUPLED("eth1_axi", R9A07G044_ETH1_CLK_AXI, R9A07G044_CLK_M0,
+                                       0x57c, 1),
+               DEF_COUPLED("eth1_chi", R9A07G044_ETH1_CLK_CHI, R9A07G044_CLK_ZT,
+                                       0x57c, 1),
+               DEF_MOD("i2c0",         R9A07G044_I2C0_PCLK, R9A07G044_CLK_P0,
+                                       0x580, 0),
+               DEF_MOD("i2c1",         R9A07G044_I2C1_PCLK, R9A07G044_CLK_P0,
+                                       0x580, 1),
+               DEF_MOD("i2c2",         R9A07G044_I2C2_PCLK, R9A07G044_CLK_P0,
+                                       0x580, 2),
+               DEF_MOD("i2c3",         R9A07G044_I2C3_PCLK, R9A07G044_CLK_P0,
+                                       0x580, 3),
+               DEF_MOD("scif0",        R9A07G044_SCIF0_CLK_PCK, R9A07G044_CLK_P0,
+                                       0x584, 0),
+               DEF_MOD("scif1",        R9A07G044_SCIF1_CLK_PCK, R9A07G044_CLK_P0,
+                                       0x584, 1),
+               DEF_MOD("scif2",        R9A07G044_SCIF2_CLK_PCK, R9A07G044_CLK_P0,
+                                       0x584, 2),
+               DEF_MOD("scif3",        R9A07G044_SCIF3_CLK_PCK, R9A07G044_CLK_P0,
+                                       0x584, 3),
+               DEF_MOD("scif4",        R9A07G044_SCIF4_CLK_PCK, R9A07G044_CLK_P0,
+                                       0x584, 4),
+               DEF_MOD("sci0",         R9A07G044_SCI0_CLKP, R9A07G044_CLK_P0,
+                                       0x588, 0),
+               DEF_MOD("sci1",         R9A07G044_SCI1_CLKP, R9A07G044_CLK_P0,
+                                       0x588, 1),
+               DEF_MOD("rspi0",        R9A07G044_RSPI0_CLKB, R9A07G044_CLK_P0,
+                                       0x590, 0),
+               DEF_MOD("rspi1",        R9A07G044_RSPI1_CLKB, R9A07G044_CLK_P0,
+                                       0x590, 1),
+               DEF_MOD("rspi2",        R9A07G044_RSPI2_CLKB, R9A07G044_CLK_P0,
+                                       0x590, 2),
+               DEF_MOD("canfd",        R9A07G044_CANFD_PCLK, R9A07G044_CLK_P0,
+                                       0x594, 0),
+               DEF_MOD("gpio",         R9A07G044_GPIO_HCLK, R9A07G044_OSCCLK,
+                                       0x598, 0),
+               DEF_MOD("adc_adclk",    R9A07G044_ADC_ADCLK, R9A07G044_CLK_TSU,
+                                       0x5a8, 0),
+               DEF_MOD("adc_pclk",     R9A07G044_ADC_PCLK, R9A07G044_CLK_P0,
+                                       0x5a8, 1),
+               DEF_MOD("tsu_pclk",     R9A07G044_TSU_PCLK, R9A07G044_CLK_TSU,
+                                       0x5ac, 0),
+       },
+#ifdef CONFIG_CLK_R9A07G054
+       .drp = {
+       },
+#endif
 };
 
 static struct rzg2l_reset r9a07g044_resets[] = {
@@ -336,8 +359,8 @@ static const unsigned int r9a07g044_crit_mod_clks[] __initconst = {
 
 const struct rzg2l_cpg_info r9a07g044_cpg_info = {
        /* Core Clocks */
-       .core_clks = r9a07g044_core_clks,
-       .num_core_clks = ARRAY_SIZE(r9a07g044_core_clks),
+       .core_clks = core_clks.common,
+       .num_core_clks = ARRAY_SIZE(core_clks.common),
        .last_dt_core_clk = LAST_DT_CORE_CLK,
        .num_total_core_clks = MOD_CLK_BASE,
 
@@ -346,11 +369,34 @@ const struct rzg2l_cpg_info r9a07g044_cpg_info = {
        .num_crit_mod_clks = ARRAY_SIZE(r9a07g044_crit_mod_clks),
 
        /* Module Clocks */
-       .mod_clks = r9a07g044_mod_clks,
-       .num_mod_clks = ARRAY_SIZE(r9a07g044_mod_clks),
+       .mod_clks = mod_clks.common,
+       .num_mod_clks = ARRAY_SIZE(mod_clks.common),
        .num_hw_mod_clks = R9A07G044_TSU_PCLK + 1,
 
        /* Resets */
        .resets = r9a07g044_resets,
-       .num_resets = ARRAY_SIZE(r9a07g044_resets),
+       .num_resets = R9A07G044_TSU_PRESETN + 1, /* Last reset ID + 1 */
+};
+
+#ifdef CONFIG_CLK_R9A07G054
+const struct rzg2l_cpg_info r9a07g054_cpg_info = {
+       /* Core Clocks */
+       .core_clks = core_clks.common,
+       .num_core_clks = ARRAY_SIZE(core_clks.common) + ARRAY_SIZE(core_clks.drp),
+       .last_dt_core_clk = LAST_DT_CORE_CLK,
+       .num_total_core_clks = MOD_CLK_BASE,
+
+       /* Critical Module Clocks */
+       .crit_mod_clks = r9a07g044_crit_mod_clks,
+       .num_crit_mod_clks = ARRAY_SIZE(r9a07g044_crit_mod_clks),
+
+       /* Module Clocks */
+       .mod_clks = mod_clks.common,
+       .num_mod_clks = ARRAY_SIZE(mod_clks.common) + ARRAY_SIZE(mod_clks.drp),
+       .num_hw_mod_clks = R9A07G054_STPAI_ACLK_DRP + 1,
+
+       /* Resets */
+       .resets = r9a07g044_resets,
+       .num_resets = R9A07G054_STPAI_ARESETN + 1, /* Last reset ID + 1 */
 };
+#endif
index edd0abe..486d065 100644 (file)
@@ -952,6 +952,12 @@ static const struct of_device_id rzg2l_cpg_match[] = {
                .compatible = "renesas,r9a07g044-cpg",
                .data = &r9a07g044_cpg_info,
        },
+#endif
+#ifdef CONFIG_CLK_R9A07G054
+       {
+               .compatible = "renesas,r9a07g054-cpg",
+               .data = &r9a07g054_cpg_info,
+       },
 #endif
        { /* sentinel */ }
 };
index 5729d10..ce657be 100644 (file)
@@ -203,5 +203,6 @@ struct rzg2l_cpg_info {
 };
 
 extern const struct rzg2l_cpg_info r9a07g044_cpg_info;
+extern const struct rzg2l_cpg_info r9a07g054_cpg_info;
 
 #endif
index 69a9e80..606ae6c 100644 (file)
@@ -71,11 +71,17 @@ static struct rockchip_pll_rate_table rk3568_pll_rates[] = {
        RK3036_PLL_RATE(500000000, 1, 125, 6, 1, 1, 0),
        RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0),
        RK3036_PLL_RATE(312000000, 1, 78, 6, 1, 1, 0),
+       RK3036_PLL_RATE(297000000, 2, 99, 4, 1, 1, 0),
+       RK3036_PLL_RATE(241500000, 2, 161, 4, 2, 1, 0),
        RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0),
        RK3036_PLL_RATE(200000000, 1, 100, 3, 4, 1, 0),
        RK3036_PLL_RATE(148500000, 1, 99, 4, 4, 1, 0),
+       RK3036_PLL_RATE(135000000, 2, 45, 4, 1, 1, 0),
+       RK3036_PLL_RATE(119000000, 3, 119, 4, 2, 1, 0),
+       RK3036_PLL_RATE(108000000, 2, 45, 5, 1, 1, 0),
        RK3036_PLL_RATE(100000000, 1, 150, 6, 6, 1, 0),
        RK3036_PLL_RATE(96000000, 1, 96, 6, 4, 1, 0),
+       RK3036_PLL_RATE(78750000, 1, 96, 6, 4, 1, 0),
        RK3036_PLL_RATE(74250000, 2, 99, 4, 4, 1, 0),
        { /* sentinel */ },
 };
@@ -1038,13 +1044,13 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = {
                        RK3568_CLKGATE_CON(20), 8, GFLAGS),
        GATE(HCLK_VOP, "hclk_vop", "hclk_vo", 0,
                        RK3568_CLKGATE_CON(20), 9, GFLAGS),
-       COMPOSITE(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+       COMPOSITE(DCLK_VOP0, "dclk_vop0", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_NO_REPARENT,
                        RK3568_CLKSEL_CON(39), 10, 2, MFLAGS, 0, 8, DFLAGS,
                        RK3568_CLKGATE_CON(20), 10, GFLAGS),
-       COMPOSITE(DCLK_VOP1, "dclk_vop1", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+       COMPOSITE(DCLK_VOP1, "dclk_vop1", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_NO_REPARENT,
                        RK3568_CLKSEL_CON(40), 10, 2, MFLAGS, 0, 8, DFLAGS,
                        RK3568_CLKGATE_CON(20), 11, GFLAGS),
-       COMPOSITE(DCLK_VOP2, "dclk_vop2", hpll_vpll_gpll_cpll_p, 0,
+       COMPOSITE(DCLK_VOP2, "dclk_vop2", hpll_vpll_gpll_cpll_p, CLK_SET_RATE_NO_REPARENT,
                        RK3568_CLKSEL_CON(41), 10, 2, MFLAGS, 0, 8, DFLAGS,
                        RK3568_CLKGATE_CON(20), 12, GFLAGS),
        GATE(CLK_VOP_PWM, "clk_vop_pwm", "xin24m", 0,
@@ -1562,7 +1568,7 @@ static struct rockchip_clk_branch rk3568_clk_pmu_branches[] __initdata = {
                        RK3568_PMU_CLKGATE_CON(2), 14, GFLAGS),
        GATE(XIN_OSC0_EDPPHY_G, "xin_osc0_edpphy_g", "xin24m", 0,
                        RK3568_PMU_CLKGATE_CON(2), 15, GFLAGS),
-       MUX(CLK_HDMI_REF, "clk_hdmi_ref", clk_hdmi_ref_p, 0,
+       MUX(CLK_HDMI_REF, "clk_hdmi_ref", clk_hdmi_ref_p, CLK_SET_RATE_PARENT,
                        RK3568_PMU_CLKSEL_CON(8), 7, 1, MFLAGS),
 };
 
@@ -1697,14 +1703,12 @@ static const struct of_device_id clk_rk3568_match_table[] = {
 static int __init clk_rk3568_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       const struct of_device_id *match;
        const struct clk_rk3568_inits *init_data;
 
-       match = of_match_device(clk_rk3568_match_table, &pdev->dev);
-       if (!match || !match->data)
+       init_data = (struct clk_rk3568_inits *)of_device_get_match_data(&pdev->dev);
+       if (!init_data)
                return -EINVAL;
 
-       init_data = match->data;
        if (init_data->inits)
                init_data->inits(np);
 
index b7be7e1..bb8a844 100644 (file)
@@ -180,6 +180,7 @@ static void rockchip_fractional_approximation(struct clk_hw *hw,
                unsigned long rate, unsigned long *parent_rate,
                unsigned long *m, unsigned long *n)
 {
+       struct clk_fractional_divider *fd = to_clk_fd(hw);
        unsigned long p_rate, p_parent_rate;
        struct clk_hw *p_parent;
 
@@ -190,6 +191,8 @@ static void rockchip_fractional_approximation(struct clk_hw *hw,
                *parent_rate = p_parent_rate;
        }
 
+       fd->flags |= CLK_FRAC_DIVIDER_POWER_OF_TWO_PS;
+
        clk_fractional_divider_general_approximation(hw, rate, parent_rate, m, n);
 }
 
index 565ed67..b89e557 100644 (file)
@@ -41,8 +41,8 @@ static int zynqmp_clk_gate_enable(struct clk_hw *hw)
        ret = zynqmp_pm_clock_enable(clk_id);
 
        if (ret)
-               pr_warn_once("%s() clock enabled failed for %s, ret = %d\n",
-                            __func__, clk_name, ret);
+               pr_debug("%s() clock enable failed for %s (id %d), ret = %d\n",
+                        __func__, clk_name, clk_id, ret);
 
        return ret;
 }
@@ -61,8 +61,8 @@ static void zynqmp_clk_gate_disable(struct clk_hw *hw)
        ret = zynqmp_pm_clock_disable(clk_id);
 
        if (ret)
-               pr_warn_once("%s() clock disable failed for %s, ret = %d\n",
-                            __func__, clk_name, ret);
+               pr_debug("%s() clock disable failed for %s (id %d), ret = %d\n",
+                        __func__, clk_name, clk_id, ret);
 }
 
 /**
@@ -80,8 +80,8 @@ static int zynqmp_clk_gate_is_enabled(struct clk_hw *hw)
 
        ret = zynqmp_pm_clock_getstate(clk_id, &state);
        if (ret) {
-               pr_warn_once("%s() clock get state failed for %s, ret = %d\n",
-                            __func__, clk_name, ret);
+               pr_debug("%s() clock get state failed for %s, ret = %d\n",
+                        __func__, clk_name, ret);
                return -EIO;
        }
 
index 17afce5..6035933 100644 (file)
@@ -51,8 +51,8 @@ static u8 zynqmp_clk_mux_get_parent(struct clk_hw *hw)
        ret = zynqmp_pm_clock_getparent(clk_id, &val);
 
        if (ret) {
-               pr_warn_once("%s() getparent failed for clock: %s, ret = %d\n",
-                            __func__, clk_name, ret);
+               pr_debug("%s() getparent failed for clock: %s, ret = %d\n",
+                        __func__, clk_name, ret);
                /*
                 * clk_core_get_parent_by_index() takes num_parents as incorrect
                 * index which is exactly what I want to return here
@@ -80,8 +80,8 @@ static int zynqmp_clk_mux_set_parent(struct clk_hw *hw, u8 index)
        ret = zynqmp_pm_clock_setparent(clk_id, index);
 
        if (ret)
-               pr_warn_once("%s() set parent failed for clock: %s, ret = %d\n",
-                            __func__, clk_name, ret);
+               pr_debug("%s() set parent failed for clock: %s, ret = %d\n",
+                        __func__, clk_name, ret);
 
        return ret;
 }
index cb49281..422ea79 100644 (file)
@@ -89,8 +89,8 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw,
        ret = zynqmp_pm_clock_getdivider(clk_id, &div);
 
        if (ret)
-               pr_warn_once("%s() get divider failed for %s, ret = %d\n",
-                            __func__, clk_name, ret);
+               pr_debug("%s() get divider failed for %s, ret = %d\n",
+                        __func__, clk_name, ret);
 
        if (div_type == TYPE_DIV1)
                value = div & 0xFFFF;
@@ -177,8 +177,8 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw,
                ret = zynqmp_pm_clock_getdivider(clk_id, &bestdiv);
 
                if (ret)
-                       pr_warn_once("%s() get divider failed for %s, ret = %d\n",
-                                    __func__, clk_name, ret);
+                       pr_debug("%s() get divider failed for %s, ret = %d\n",
+                                __func__, clk_name, ret);
                if (div_type == TYPE_DIV1)
                        bestdiv = bestdiv & 0xFFFF;
                else
@@ -244,8 +244,8 @@ static int zynqmp_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
        ret = zynqmp_pm_clock_setdivider(clk_id, div);
 
        if (ret)
-               pr_warn_once("%s() set divider failed for %s, ret = %d\n",
-                            __func__, clk_name, ret);
+               pr_debug("%s() set divider failed for %s, ret = %d\n",
+                        __func__, clk_name, ret);
 
        return ret;
 }
index 036e4ff..91a6b4c 100644 (file)
@@ -56,8 +56,8 @@ static inline enum pll_mode zynqmp_pll_get_mode(struct clk_hw *hw)
 
        ret = zynqmp_pm_get_pll_frac_mode(clk_id, ret_payload);
        if (ret) {
-               pr_warn_once("%s() PLL get frac mode failed for %s, ret = %d\n",
-                            __func__, clk_name, ret);
+               pr_debug("%s() PLL get frac mode failed for %s, ret = %d\n",
+                        __func__, clk_name, ret);
                return PLL_MODE_ERROR;
        }
 
@@ -84,8 +84,8 @@ static inline void zynqmp_pll_set_mode(struct clk_hw *hw, bool on)
 
        ret = zynqmp_pm_set_pll_frac_mode(clk_id, mode);
        if (ret)
-               pr_warn_once("%s() PLL set frac mode failed for %s, ret = %d\n",
-                            __func__, clk_name, ret);
+               pr_debug("%s() PLL set frac mode failed for %s, ret = %d\n",
+                        __func__, clk_name, ret);
        else
                clk->set_pll_mode = true;
 }
@@ -145,8 +145,8 @@ static unsigned long zynqmp_pll_recalc_rate(struct clk_hw *hw,
 
        ret = zynqmp_pm_clock_getdivider(clk_id, &fbdiv);
        if (ret) {
-               pr_warn_once("%s() get divider failed for %s, ret = %d\n",
-                            __func__, clk_name, ret);
+               pr_debug("%s() get divider failed for %s, ret = %d\n",
+                        __func__, clk_name, ret);
                return 0ul;
        }
 
@@ -200,8 +200,8 @@ static int zynqmp_pll_set_rate(struct clk_hw *hw, unsigned long rate,
                        WARN(1, "More than allowed devices are using the %s, which is forbidden\n",
                             clk_name);
                else if (ret)
-                       pr_warn_once("%s() set divider failed for %s, ret = %d\n",
-                                    __func__, clk_name, ret);
+                       pr_debug("%s() set divider failed for %s, ret = %d\n",
+                                __func__, clk_name, ret);
                zynqmp_pm_set_pll_frac_data(clk_id, f);
 
                return rate + frac;
@@ -211,8 +211,8 @@ static int zynqmp_pll_set_rate(struct clk_hw *hw, unsigned long rate,
        fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
        ret = zynqmp_pm_clock_setdivider(clk_id, fbdiv);
        if (ret)
-               pr_warn_once("%s() set divider failed for %s, ret = %d\n",
-                            __func__, clk_name, ret);
+               pr_debug("%s() set divider failed for %s, ret = %d\n",
+                        __func__, clk_name, ret);
 
        return parent_rate * fbdiv;
 }
@@ -233,8 +233,8 @@ static int zynqmp_pll_is_enabled(struct clk_hw *hw)
 
        ret = zynqmp_pm_clock_getstate(clk_id, &state);
        if (ret) {
-               pr_warn_once("%s() clock get state failed for %s, ret = %d\n",
-                            __func__, clk_name, ret);
+               pr_debug("%s() clock get state failed for %s, ret = %d\n",
+                        __func__, clk_name, ret);
                return -EIO;
        }
 
@@ -265,8 +265,8 @@ static int zynqmp_pll_enable(struct clk_hw *hw)
 
        ret = zynqmp_pm_clock_enable(clk_id);
        if (ret)
-               pr_warn_once("%s() clock enable failed for %s, ret = %d\n",
-                            __func__, clk_name, ret);
+               pr_debug("%s() clock enable failed for %s, ret = %d\n",
+                        __func__, clk_name, ret);
 
        return ret;
 }
@@ -287,8 +287,8 @@ static void zynqmp_pll_disable(struct clk_hw *hw)
 
        ret = zynqmp_pm_clock_disable(clk_id);
        if (ret)
-               pr_warn_once("%s() clock disable failed for %s, ret = %d\n",
-                            __func__, clk_name, ret);
+               pr_debug("%s() clock disable failed for %s, ret = %d\n",
+                        __func__, clk_name, ret);
 }
 
 static const struct clk_ops zynqmp_pll_ops = {
index b6f9796..5c40ca1 100644 (file)
@@ -241,7 +241,7 @@ static void __init dmtimer_systimer_assign_alwon(void)
        bool quirk_unreliable_oscillator = false;
 
        /* Quirk unreliable 32 KiHz oscillator with incomplete dts */
-       if (of_machine_is_compatible("ti,omap3-beagle") ||
+       if (of_machine_is_compatible("ti,omap3-beagle-ab4") ||
            of_machine_is_compatible("timll,omap3-devkit8000")) {
                quirk_unreliable_oscillator = true;
                counter_32k = -ENODEV;
index 646ad38..ccac1c4 100644 (file)
@@ -358,7 +358,7 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg,
         * other namespaces.
         */
        if ((current_user_ns() != &init_user_ns) ||
-           (task_active_pid_ns(current) != &init_pid_ns))
+           !task_is_in_init_pid_ns(current))
                return;
 
        /* Can only change if privileged. */
index 7e0957e..869894b 100644 (file)
@@ -90,10 +90,8 @@ struct counter_device *counter_alloc(size_t sizeof_priv)
        int err;
 
        ch = kzalloc(sizeof(*ch) + sizeof_priv, GFP_KERNEL);
-       if (!ch) {
-               err = -ENOMEM;
-               goto err_alloc_ch;
-       }
+       if (!ch)
+               return NULL;
 
        counter = &ch->counter;
        dev = &counter->dev;
@@ -123,9 +121,8 @@ err_chrdev_add:
 err_ida_alloc:
 
        kfree(ch);
-err_alloc_ch:
 
-       return ERR_PTR(err);
+       return NULL;
 }
 EXPORT_SYMBOL_GPL(counter_alloc);
 
@@ -208,12 +205,12 @@ struct counter_device *devm_counter_alloc(struct device *dev, size_t sizeof_priv
        int err;
 
        counter = counter_alloc(sizeof_priv);
-       if (IS_ERR(counter))
-               return counter;
+       if (!counter)
+               return NULL;
 
        err = devm_add_action_or_reset(dev, devm_counter_put, counter);
        if (err < 0)
-               return ERR_PTR(err);
+               return NULL;
 
        return counter;
 }
index 4c8ebdf..1b4d425 100644 (file)
@@ -1753,7 +1753,6 @@ void otx2_cpt_print_uc_dbg_info(struct otx2_cptpf_dev *cptpf)
        char engs_info[2 * OTX2_CPT_NAME_LENGTH];
        struct otx2_cpt_eng_grp_info *grp;
        struct otx2_cpt_engs_rsvd *engs;
-       u32 mask[4];
        int i, j;
 
        pr_debug("Engine groups global info");
@@ -1785,6 +1784,8 @@ void otx2_cpt_print_uc_dbg_info(struct otx2_cptpf_dev *cptpf)
                for (j = 0; j < OTX2_CPT_MAX_ETYPES_PER_GRP; j++) {
                        engs = &grp->engs[j];
                        if (engs->type) {
+                               u32 mask[5] = { };
+
                                get_engs_info(grp, engs_info,
                                              2 * OTX2_CPT_NAME_LENGTH, j);
                                pr_debug("Slot%d: %s", j, engs_info);
index 56bf5ad..8f5848a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/xarray.h>
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <linux/nospec.h>
 #include <linux/uaccess.h>
 #include <linux/syscalls.h>
 #include <linux/dma-heap.h>
@@ -135,6 +136,7 @@ static long dma_heap_ioctl(struct file *file, unsigned int ucmd,
        if (nr >= ARRAY_SIZE(dma_heap_ioctl_cmds))
                return -EINVAL;
 
+       nr = array_index_nospec(nr, ARRAY_SIZE(dma_heap_ioctl_cmds));
        /* Get the kernel ioctl cmd that matches */
        kcmd = dma_heap_ioctl_cmds[nr];
 
index 3a6d241..5dd2978 100644 (file)
@@ -350,7 +350,7 @@ static int altr_sdram_probe(struct platform_device *pdev)
        if (irq < 0) {
                edac_printk(KERN_ERR, EDAC_MC,
                            "No irq %d in DT\n", irq);
-               return -ENODEV;
+               return irq;
        }
 
        /* Arria10 has a 2nd IRQ */
index 2ccd1db..7197f9f 100644 (file)
@@ -1919,7 +1919,7 @@ static int xgene_edac_probe(struct platform_device *pdev)
                        irq = platform_get_irq_optional(pdev, i);
                        if (irq < 0) {
                                dev_err(&pdev->dev, "No IRQ resource\n");
-                               rc = -EINVAL;
+                               rc = irq;
                                goto out_err;
                        }
                        rc = devm_request_irq(&pdev->dev, irq,
index ae79c33..7de3f5b 100644 (file)
@@ -722,6 +722,13 @@ void __init efi_systab_report_header(const efi_table_hdr_t *systab_hdr,
                systab_hdr->revision >> 16,
                systab_hdr->revision & 0xffff,
                vendor);
+
+       if (IS_ENABLED(CONFIG_X86_64) &&
+           systab_hdr->revision > EFI_1_10_SYSTEM_TABLE_REVISION &&
+           !strcmp(vendor, "Apple")) {
+               pr_info("Apple Mac detected, using EFI v1.10 runtime services only\n");
+               efi.runtime_version = EFI_1_10_SYSTEM_TABLE_REVISION;
+       }
 }
 
 static __initdata char memory_type_name[][13] = {
index 2363fee..9cc5560 100644 (file)
@@ -119,9 +119,9 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
        if (image->image_base != _text)
                efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n");
 
-       if (!IS_ALIGNED((u64)_text, EFI_KIMG_ALIGN))
-               efi_err("FIRMWARE BUG: kernel image not aligned on %ldk boundary\n",
-                       EFI_KIMG_ALIGN >> 10);
+       if (!IS_ALIGNED((u64)_text, SEGMENT_ALIGN))
+               efi_err("FIRMWARE BUG: kernel image not aligned on %dk boundary\n",
+                       SEGMENT_ALIGN >> 10);
 
        kernel_size = _edata - _text;
        kernel_memsize = kernel_size + (_end - _edata);
index 869dc95..0cb2664 100644 (file)
@@ -278,7 +278,8 @@ static int gpio_fwd_get(struct gpio_chip *chip, unsigned int offset)
 {
        struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
 
-       return gpiod_get_value(fwd->descs[offset]);
+       return chip->can_sleep ? gpiod_get_value_cansleep(fwd->descs[offset])
+                              : gpiod_get_value(fwd->descs[offset]);
 }
 
 static int gpio_fwd_get_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
@@ -293,7 +294,10 @@ static int gpio_fwd_get_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
        for_each_set_bit(i, mask, fwd->chip.ngpio)
                descs[j++] = fwd->descs[i];
 
-       error = gpiod_get_array_value(j, descs, NULL, values);
+       if (fwd->chip.can_sleep)
+               error = gpiod_get_array_value_cansleep(j, descs, NULL, values);
+       else
+               error = gpiod_get_array_value(j, descs, NULL, values);
        if (error)
                return error;
 
@@ -328,7 +332,10 @@ static void gpio_fwd_set(struct gpio_chip *chip, unsigned int offset, int value)
 {
        struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
 
-       gpiod_set_value(fwd->descs[offset], value);
+       if (chip->can_sleep)
+               gpiod_set_value_cansleep(fwd->descs[offset], value);
+       else
+               gpiod_set_value(fwd->descs[offset], value);
 }
 
 static void gpio_fwd_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
@@ -343,7 +350,10 @@ static void gpio_fwd_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
                descs[j++] = fwd->descs[i];
        }
 
-       gpiod_set_array_value(j, descs, NULL, values);
+       if (fwd->chip.can_sleep)
+               gpiod_set_array_value_cansleep(j, descs, NULL, values);
+       else
+               gpiod_set_array_value(j, descs, NULL, values);
 }
 
 static void gpio_fwd_set_multiple_locked(struct gpio_chip *chip,
index 403f9e8..7d82388 100644 (file)
@@ -223,7 +223,7 @@ static int sifive_gpio_probe(struct platform_device *pdev)
                         NULL,
                         chip->base + SIFIVE_GPIO_OUTPUT_EN,
                         chip->base + SIFIVE_GPIO_INPUT_EN,
-                        0);
+                        BGPIOF_READ_OUTPUT_REG_SET);
        if (ret) {
                dev_err(dev, "unable to init generic GPIO\n");
                return ret;
index 838bbfe..153fe79 100644 (file)
@@ -570,6 +570,11 @@ static struct gpio_sim_bank *to_gpio_sim_bank(struct config_item *item)
        return container_of(group, struct gpio_sim_bank, group);
 }
 
+static bool gpio_sim_bank_has_label(struct gpio_sim_bank *bank)
+{
+       return bank->label && *bank->label;
+}
+
 static struct gpio_sim_device *
 gpio_sim_bank_get_device(struct gpio_sim_bank *bank)
 {
@@ -770,9 +775,15 @@ static int gpio_sim_add_hogs(struct gpio_sim_device *dev)
                         * point the device doesn't exist yet and so dev_name()
                         * is not available.
                         */
-                       hog->chip_label = kasprintf(GFP_KERNEL,
-                                                   "gpio-sim.%u-%s", dev->id,
-                                                   fwnode_get_name(bank->swnode));
+                       if (gpio_sim_bank_has_label(bank))
+                               hog->chip_label = kstrdup(bank->label,
+                                                         GFP_KERNEL);
+                       else
+                               hog->chip_label = kasprintf(GFP_KERNEL,
+                                                       "gpio-sim.%u-%s",
+                                                       dev->id,
+                                                       fwnode_get_name(
+                                                               bank->swnode));
                        if (!hog->chip_label) {
                                gpio_sim_remove_hogs(dev);
                                return -ENOMEM;
@@ -816,7 +827,7 @@ gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank,
 
        properties[prop_idx++] = PROPERTY_ENTRY_U32("ngpios", bank->num_lines);
 
-       if (bank->label)
+       if (gpio_sim_bank_has_label(bank))
                properties[prop_idx++] = PROPERTY_ENTRY_STRING("gpio-sim,label",
                                                               bank->label);
 
index c7b5446..ffa0256 100644 (file)
@@ -330,7 +330,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
                        goto out_free_lh;
                }
 
-               ret = gpiod_request(desc, lh->label);
+               ret = gpiod_request_user(desc, lh->label);
                if (ret)
                        goto out_free_lh;
                lh->descs[i] = desc;
@@ -1378,7 +1378,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
                        goto out_free_linereq;
                }
 
-               ret = gpiod_request(desc, lr->label);
+               ret = gpiod_request_user(desc, lr->label);
                if (ret)
                        goto out_free_linereq;
 
@@ -1764,7 +1764,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
                }
        }
 
-       ret = gpiod_request(desc, le->label);
+       ret = gpiod_request_user(desc, le->label);
        if (ret)
                goto out_free_le;
        le->desc = desc;
index 4098bc7..44c1ad5 100644 (file)
@@ -475,12 +475,9 @@ static ssize_t export_store(struct class *class,
         * they may be undone on its behalf too.
         */
 
-       status = gpiod_request(desc, "sysfs");
-       if (status) {
-               if (status == -EPROBE_DEFER)
-                       status = -ENODEV;
+       status = gpiod_request_user(desc, "sysfs");
+       if (status)
                goto done;
-       }
 
        status = gpiod_set_transitory(desc, false);
        if (!status) {
index 30bc3f8..c31f462 100644 (file)
@@ -135,6 +135,18 @@ struct gpio_desc {
 
 int gpiod_request(struct gpio_desc *desc, const char *label);
 void gpiod_free(struct gpio_desc *desc);
+
+static inline int gpiod_request_user(struct gpio_desc *desc, const char *label)
+{
+       int ret;
+
+       ret = gpiod_request(desc, label);
+       if (ret == -EPROBE_DEFER)
+               ret = -ENODEV;
+
+       return ret;
+}
+
 int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
                unsigned long lflags, enum gpiod_flags dflags);
 int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce);
index d8b854f..9a53a4d 100644 (file)
@@ -1408,12 +1408,10 @@ int amdgpu_acpi_smart_shift_update(struct drm_device *dev, enum amdgpu_ss ss_sta
 int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev);
 
 void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps);
-bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev);
 void amdgpu_acpi_detect(void);
 #else
 static inline int amdgpu_acpi_init(struct amdgpu_device *adev) { return 0; }
 static inline void amdgpu_acpi_fini(struct amdgpu_device *adev) { }
-static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; }
 static inline void amdgpu_acpi_detect(void) { }
 static inline bool amdgpu_acpi_is_power_shift_control_supported(void) { return false; }
 static inline int amdgpu_acpi_power_shift_control(struct amdgpu_device *adev,
@@ -1422,6 +1420,14 @@ static inline int amdgpu_acpi_smart_shift_update(struct drm_device *dev,
                                                 enum amdgpu_ss ss_state) { return 0; }
 #endif
 
+#if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND)
+bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev);
+bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev);
+#else
+static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; }
+static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) { return false; }
+#endif
+
 int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
                           uint64_t addr, struct amdgpu_bo **bo,
                           struct amdgpu_bo_va_mapping **mapping);
index 4811b0f..0e12315 100644 (file)
@@ -1031,6 +1031,20 @@ void amdgpu_acpi_detect(void)
        }
 }
 
+#if IS_ENABLED(CONFIG_SUSPEND)
+/**
+ * amdgpu_acpi_is_s3_active
+ *
+ * @adev: amdgpu_device_pointer
+ *
+ * returns true if supported, false if not.
+ */
+bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev)
+{
+       return !(adev->flags & AMD_IS_APU) ||
+               (pm_suspend_target_state == PM_SUSPEND_MEM);
+}
+
 /**
  * amdgpu_acpi_is_s0ix_active
  *
@@ -1040,11 +1054,24 @@ void amdgpu_acpi_detect(void)
  */
 bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev)
 {
-#if IS_ENABLED(CONFIG_AMD_PMC) && IS_ENABLED(CONFIG_SUSPEND)
-       if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) {
-               if (adev->flags & AMD_IS_APU)
-                       return pm_suspend_target_state == PM_SUSPEND_TO_IDLE;
+       if (!(adev->flags & AMD_IS_APU) ||
+           (pm_suspend_target_state != PM_SUSPEND_TO_IDLE))
+               return false;
+
+       if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) {
+               dev_warn_once(adev->dev,
+                             "Power consumption will be higher as BIOS has not been configured for suspend-to-idle.\n"
+                             "To use suspend-to-idle change the sleep mode in BIOS setup.\n");
+               return false;
        }
-#endif
+
+#if !IS_ENABLED(CONFIG_AMD_PMC)
+       dev_warn_once(adev->dev,
+                     "Power consumption will be higher as the kernel has not been compiled with CONFIG_AMD_PMC.\n");
        return false;
+#else
+       return true;
+#endif /* CONFIG_AMD_PMC */
 }
+
+#endif /* CONFIG_SUSPEND */
index b21bcdc..63a0899 100644 (file)
@@ -1525,6 +1525,87 @@ static const u16 amdgpu_unsupported_pciidlist[] = {
        0x99A0,
        0x99A2,
        0x99A4,
+       /* radeon secondary ids */
+       0x3171,
+       0x3e70,
+       0x4164,
+       0x4165,
+       0x4166,
+       0x4168,
+       0x4170,
+       0x4171,
+       0x4172,
+       0x4173,
+       0x496e,
+       0x4a69,
+       0x4a6a,
+       0x4a6b,
+       0x4a70,
+       0x4a74,
+       0x4b69,
+       0x4b6b,
+       0x4b6c,
+       0x4c6e,
+       0x4e64,
+       0x4e65,
+       0x4e66,
+       0x4e67,
+       0x4e68,
+       0x4e69,
+       0x4e6a,
+       0x4e71,
+       0x4f73,
+       0x5569,
+       0x556b,
+       0x556d,
+       0x556f,
+       0x5571,
+       0x5854,
+       0x5874,
+       0x5940,
+       0x5941,
+       0x5b72,
+       0x5b73,
+       0x5b74,
+       0x5b75,
+       0x5d44,
+       0x5d45,
+       0x5d6d,
+       0x5d6f,
+       0x5d72,
+       0x5d77,
+       0x5e6b,
+       0x5e6d,
+       0x7120,
+       0x7124,
+       0x7129,
+       0x712e,
+       0x712f,
+       0x7162,
+       0x7163,
+       0x7166,
+       0x7167,
+       0x7172,
+       0x7173,
+       0x71a0,
+       0x71a1,
+       0x71a3,
+       0x71a7,
+       0x71bb,
+       0x71e0,
+       0x71e1,
+       0x71e2,
+       0x71e6,
+       0x71e7,
+       0x71f2,
+       0x7269,
+       0x726b,
+       0x726e,
+       0x72a0,
+       0x72a8,
+       0x72b1,
+       0x72b3,
+       0x793f,
 };
 
 static const struct pci_device_id pciidlist[] = {
@@ -2165,13 +2246,20 @@ static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work)
 static int amdgpu_pmops_prepare(struct device *dev)
 {
        struct drm_device *drm_dev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = drm_to_adev(drm_dev);
 
        /* Return a positive number here so
         * DPM_FLAG_SMART_SUSPEND works properly
         */
        if (amdgpu_device_supports_boco(drm_dev))
-               return pm_runtime_suspended(dev) &&
-                       pm_suspend_via_firmware();
+               return pm_runtime_suspended(dev);
+
+       /* if we will not support s3 or s2i for the device
+        *  then skip suspend
+        */
+       if (!amdgpu_acpi_is_s0ix_active(adev) &&
+           !amdgpu_acpi_is_s3_active(adev))
+               return 1;
 
        return 0;
 }
index 5c3f240..4655702 100644 (file)
@@ -1904,7 +1904,7 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
        unsigned i;
        int r;
 
-       if (direct_submit && !ring->sched.ready) {
+       if (!direct_submit && !ring->sched.ready) {
                DRM_ERROR("Trying to move memory with ring turned off.\n");
                return -EINVAL;
        }
index b4eddf6..ff738e9 100644 (file)
@@ -543,7 +543,9 @@ static void gfxhub_v2_1_utcl2_harvest(struct amdgpu_device *adev)
                adev->gfx.config.max_sh_per_se *
                adev->gfx.config.max_shader_engines);
 
-       if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 3, 3)) {
+       switch (adev->ip_versions[GC_HWIP][0]) {
+       case IP_VERSION(10, 3, 1):
+       case IP_VERSION(10, 3, 3):
                /* Get SA disabled bitmap from eFuse setting */
                efuse_setting = RREG32_SOC15(GC, 0, mmCC_GC_SA_UNIT_DISABLE);
                efuse_setting &= CC_GC_SA_UNIT_DISABLE__SA_DISABLE_MASK;
@@ -566,6 +568,9 @@ static void gfxhub_v2_1_utcl2_harvest(struct amdgpu_device *adev)
                disabled_sa = tmp;
 
                WREG32_SOC15(GC, 0, mmGCUTCL2_HARVEST_BYPASS_GROUPS_YELLOW_CARP, disabled_sa);
+               break;
+       default:
+               break;
        }
 }
 
index 38bb427..a2f8ed0 100644 (file)
@@ -1140,6 +1140,9 @@ static void gmc_v10_0_get_clockgating_state(void *handle, u32 *flags)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 1, 3))
+               return;
+
        adev->mmhub.funcs->get_clockgating(adev, flags);
 
        if (adev->ip_versions[ATHUB_HWIP][0] >= IP_VERSION(2, 1, 0))
index 7f9773f..7c1c623 100644 (file)
@@ -3653,7 +3653,7 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
 
        /* Use GRPH_PFLIP interrupt */
        for (i = DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT;
-                       i <= DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + adev->mode_info.num_crtc - 1;
+                       i <= DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + dc->caps.max_otg_num - 1;
                        i++) {
                r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->pageflip_irq);
                if (r) {
index ff5bb15..e6ef36d 100644 (file)
@@ -2033,10 +2033,10 @@ static void calculate_bandwidth(
        kfree(surface_type);
 free_tiling_mode:
        kfree(tiling_mode);
-free_yclk:
-       kfree(yclk);
 free_sclk:
        kfree(sclk);
+free_yclk:
+       kfree(yclk);
 }
 
 /*******************************************************************************
index ec19678..e447c74 100644 (file)
@@ -503,7 +503,6 @@ static void dcn_bw_calc_rq_dlg_ttu(
        //input[in_idx].dout.output_standard;
 
        /*todo: soc->sr_enter_plus_exit_time??*/
-       dlg_sys_param->t_srx_delay_us = dc->dcn_ip->dcfclk_cstate_latency / v->dcf_clk_deep_sleep;
 
        dml1_rq_dlg_get_rq_params(dml, rq_param, &input->pipe.src);
        dml1_extract_rq_regs(dml, rq_regs, rq_param);
index 48005de..bc4ddc3 100644 (file)
@@ -570,32 +570,32 @@ static struct wm_table lpddr5_wm_table = {
                        .wm_inst = WM_A,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 7.95,
-                       .sr_enter_plus_exit_time_us = 9,
+                       .sr_exit_time_us = 13.5,
+                       .sr_enter_plus_exit_time_us = 16.5,
                        .valid = true,
                },
                {
                        .wm_inst = WM_B,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 9.82,
-                       .sr_enter_plus_exit_time_us = 11.196,
+                       .sr_exit_time_us = 13.5,
+                       .sr_enter_plus_exit_time_us = 16.5,
                        .valid = true,
                },
                {
                        .wm_inst = WM_C,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 9.89,
-                       .sr_enter_plus_exit_time_us = 11.24,
+                       .sr_exit_time_us = 13.5,
+                       .sr_enter_plus_exit_time_us = 16.5,
                        .valid = true,
                },
                {
                        .wm_inst = WM_D,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 9.748,
-                       .sr_enter_plus_exit_time_us = 11.102,
+                       .sr_exit_time_us = 13.5,
+                       .sr_enter_plus_exit_time_us = 16.5,
                        .valid = true,
                },
        }
index 4162ce4..9d17c5a 100644 (file)
@@ -329,38 +329,38 @@ static struct clk_bw_params dcn31_bw_params = {
 
 };
 
-static struct wm_table ddr4_wm_table = {
+static struct wm_table ddr5_wm_table = {
        .entries = {
                {
                        .wm_inst = WM_A,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 6.09,
-                       .sr_enter_plus_exit_time_us = 7.14,
+                       .sr_exit_time_us = 9,
+                       .sr_enter_plus_exit_time_us = 11,
                        .valid = true,
                },
                {
                        .wm_inst = WM_B,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 10.12,
-                       .sr_enter_plus_exit_time_us = 11.48,
+                       .sr_exit_time_us = 9,
+                       .sr_enter_plus_exit_time_us = 11,
                        .valid = true,
                },
                {
                        .wm_inst = WM_C,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 10.12,
-                       .sr_enter_plus_exit_time_us = 11.48,
+                       .sr_exit_time_us = 9,
+                       .sr_enter_plus_exit_time_us = 11,
                        .valid = true,
                },
                {
                        .wm_inst = WM_D,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 10.12,
-                       .sr_enter_plus_exit_time_us = 11.48,
+                       .sr_exit_time_us = 9,
+                       .sr_enter_plus_exit_time_us = 11,
                        .valid = true,
                },
        }
@@ -687,7 +687,7 @@ void dcn31_clk_mgr_construct(
                if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) {
                        dcn31_bw_params.wm_table = lpddr5_wm_table;
                } else {
-                       dcn31_bw_params.wm_table = ddr4_wm_table;
+                       dcn31_bw_params.wm_table = ddr5_wm_table;
                }
                /* Saved clocks configured at boot for debug purposes */
                 dcn31_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, &clk_mgr->base.base, &log_info);
index a1011f3..de3f464 100644 (file)
@@ -120,7 +120,11 @@ static int dcn31_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
        result = dcn31_smu_wait_for_response(clk_mgr, 10, 200000);
 
        if (result == VBIOSSMC_Result_Failed) {
-               ASSERT(0);
+               if (msg_id == VBIOSSMC_MSG_TransferTableDram2Smu &&
+                   param == TABLE_WATERMARKS)
+                       DC_LOG_WARNING("Watermarks table not configured properly by SMU");
+               else
+                       ASSERT(0);
                REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Result_OK);
                return -1;
        }
index 01c8849..d18e9f3 100644 (file)
@@ -1220,6 +1220,8 @@ struct dc *dc_create(const struct dc_init_data *init_params)
 
                dc->caps.max_dp_protocol_version = DP_VERSION_1_4;
 
+               dc->caps.max_otg_num = dc->res_pool->res_cap->num_timing_generator;
+
                if (dc->res_pool->dmcu != NULL)
                        dc->versions.dmcu_version = dc->res_pool->dmcu->dmcu_version;
        }
@@ -1404,20 +1406,34 @@ static void program_timing_sync(
                                status->timing_sync_info.master = false;
 
                }
-               /* remove any other unblanked pipes as they have already been synced */
-               for (j = j + 1; j < group_size; j++) {
-                       bool is_blanked;
 
-                       if (pipe_set[j]->stream_res.opp->funcs->dpg_is_blanked)
-                               is_blanked =
-                                       pipe_set[j]->stream_res.opp->funcs->dpg_is_blanked(pipe_set[j]->stream_res.opp);
-                       else
-                               is_blanked =
-                                       pipe_set[j]->stream_res.tg->funcs->is_blanked(pipe_set[j]->stream_res.tg);
-                       if (!is_blanked) {
-                               group_size--;
-                               pipe_set[j] = pipe_set[group_size];
-                               j--;
+               /* remove any other pipes that are already been synced */
+               if (dc->config.use_pipe_ctx_sync_logic) {
+                       /* check pipe's syncd to decide which pipe to be removed */
+                       for (j = 1; j < group_size; j++) {
+                               if (pipe_set[j]->pipe_idx_syncd == pipe_set[0]->pipe_idx_syncd) {
+                                       group_size--;
+                                       pipe_set[j] = pipe_set[group_size];
+                                       j--;
+                               } else
+                                       /* link slave pipe's syncd with master pipe */
+                                       pipe_set[j]->pipe_idx_syncd = pipe_set[0]->pipe_idx_syncd;
+                       }
+               } else {
+                       for (j = j + 1; j < group_size; j++) {
+                               bool is_blanked;
+
+                               if (pipe_set[j]->stream_res.opp->funcs->dpg_is_blanked)
+                                       is_blanked =
+                                               pipe_set[j]->stream_res.opp->funcs->dpg_is_blanked(pipe_set[j]->stream_res.opp);
+                               else
+                                       is_blanked =
+                                               pipe_set[j]->stream_res.tg->funcs->is_blanked(pipe_set[j]->stream_res.tg);
+                               if (!is_blanked) {
+                                       group_size--;
+                                       pipe_set[j] = pipe_set[group_size];
+                                       j--;
+                               }
                        }
                }
 
index 05e2165..61b8f29 100644 (file)
@@ -202,7 +202,7 @@ void dp_wait_for_training_aux_rd_interval(
        uint32_t wait_in_micro_secs)
 {
 #if defined(CONFIG_DRM_AMD_DC_DCN)
-       if (wait_in_micro_secs > 16000)
+       if (wait_in_micro_secs > 1000)
                msleep(wait_in_micro_secs/1000);
        else
                udelay(wait_in_micro_secs);
@@ -5597,6 +5597,26 @@ static bool retrieve_link_cap(struct dc_link *link)
                dp_hw_fw_revision.ieee_fw_rev,
                sizeof(dp_hw_fw_revision.ieee_fw_rev));
 
+       /* Quirk for Apple MBP 2018 15" Retina panels: wrong DP_MAX_LINK_RATE */
+       {
+               uint8_t str_mbp_2018[] = { 101, 68, 21, 103, 98, 97 };
+               uint8_t fwrev_mbp_2018[] = { 7, 4 };
+               uint8_t fwrev_mbp_2018_vega[] = { 8, 4 };
+
+               /* We also check for the firmware revision as 16,1 models have an
+                * identical device id and are incorrectly quirked otherwise.
+                */
+               if ((link->dpcd_caps.sink_dev_id == 0x0010fa) &&
+                   !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2018,
+                            sizeof(str_mbp_2018)) &&
+                   (!memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018,
+                            sizeof(fwrev_mbp_2018)) ||
+                   !memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018_vega,
+                            sizeof(fwrev_mbp_2018_vega)))) {
+                       link->reported_link_cap.link_rate = LINK_RATE_RBR2;
+               }
+       }
+
        memset(&link->dpcd_caps.dsc_caps, '\0',
                        sizeof(link->dpcd_caps.dsc_caps));
        memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
@@ -6935,7 +6955,7 @@ bool dpcd_write_128b_132b_sst_payload_allocation_table(
                        }
                }
                retries++;
-               udelay(5000);
+               msleep(5);
        }
 
        if (!result && retries == max_retries) {
@@ -6987,7 +7007,7 @@ bool dpcd_poll_for_allocation_change_trigger(struct dc_link *link)
                        break;
                }
 
-               udelay(5000);
+               msleep(5);
        }
 
        if (result == ACT_FAILED) {
index d4ff6cc..b3912ff 100644 (file)
@@ -3217,6 +3217,60 @@ struct hpo_dp_link_encoder *resource_get_hpo_dp_link_enc_for_det_lt(
 }
 #endif
 
+void reset_syncd_pipes_from_disabled_pipes(struct dc *dc,
+               struct dc_state *context)
+{
+       int i, j;
+       struct pipe_ctx *pipe_ctx_old, *pipe_ctx, *pipe_ctx_syncd;
+
+       /* If pipe backend is reset, need to reset pipe syncd status */
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               pipe_ctx_old =  &dc->current_state->res_ctx.pipe_ctx[i];
+               pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+               if (!pipe_ctx_old->stream)
+                       continue;
+
+               if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
+                       continue;
+
+               if (!pipe_ctx->stream ||
+                               pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
+
+                       /* Reset all the syncd pipes from the disabled pipe */
+                       for (j = 0; j < dc->res_pool->pipe_count; j++) {
+                               pipe_ctx_syncd = &context->res_ctx.pipe_ctx[j];
+                               if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_syncd) == pipe_ctx_old->pipe_idx) ||
+                                       !IS_PIPE_SYNCD_VALID(pipe_ctx_syncd))
+                                       SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_syncd, j);
+                       }
+               }
+       }
+}
+
+void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc,
+       struct dc_state *context,
+       uint8_t disabled_master_pipe_idx)
+{
+       int i;
+       struct pipe_ctx *pipe_ctx, *pipe_ctx_check;
+
+       pipe_ctx = &context->res_ctx.pipe_ctx[disabled_master_pipe_idx];
+       if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx) != disabled_master_pipe_idx) ||
+               !IS_PIPE_SYNCD_VALID(pipe_ctx))
+               SET_PIPE_SYNCD_TO_PIPE(pipe_ctx, disabled_master_pipe_idx);
+
+       /* for the pipe disabled, check if any slave pipe exists and assert */
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               pipe_ctx_check = &context->res_ctx.pipe_ctx[i];
+
+               if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_check) == disabled_master_pipe_idx) &&
+                       IS_PIPE_SYNCD_VALID(pipe_ctx_check) && (i != disabled_master_pipe_idx))
+                       DC_ERR("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n",
+                               i, disabled_master_pipe_idx);
+       }
+}
+
 uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter)
 {
        /* TODO - get transmitter to phy idx mapping from DMUB */
index da2c78c..b518648 100644 (file)
@@ -202,6 +202,7 @@ struct dc_caps {
        bool edp_dsc_support;
        bool vbios_lttpr_aware;
        bool vbios_lttpr_enable;
+       uint32_t max_otg_num;
 };
 
 struct dc_bug_wa {
@@ -344,6 +345,7 @@ struct dc_config {
        uint8_t  vblank_alignment_max_frame_time_diff;
        bool is_asymmetric_memory;
        bool is_single_rank_dimm;
+       bool use_pipe_ctx_sync_logic;
 };
 
 enum visual_confirm {
index 78192ec..eb2755b 100644 (file)
@@ -1566,6 +1566,10 @@ static enum dc_status apply_single_controller_ctx_to_hw(
                                &pipe_ctx->stream->audio_info);
        }
 
+       /* make sure no pipes syncd to the pipe being enabled */
+       if (!pipe_ctx->stream->apply_seamless_boot_optimization && dc->config.use_pipe_ctx_sync_logic)
+               check_syncd_pipes_for_disabled_master_pipe(dc, context, pipe_ctx->pipe_idx);
+
 #if defined(CONFIG_DRM_AMD_DC_DCN)
        /* DCN3.1 FPGA Workaround
         * Need to enable HPO DP Stream Encoder before setting OTG master enable.
@@ -1604,11 +1608,6 @@ static enum dc_status apply_single_controller_ctx_to_hw(
                        pipe_ctx->stream_res.stream_enc,
                        pipe_ctx->stream_res.tg->inst);
 
-       if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
-               pipe_ctx->stream_res.stream_enc->funcs->reset_fifo)
-               pipe_ctx->stream_res.stream_enc->funcs->reset_fifo(
-                       pipe_ctx->stream_res.stream_enc);
-
        if (dc_is_dp_signal(pipe_ctx->stream->signal))
                dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
 
@@ -1835,9 +1834,29 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
                                break;
                        }
                }
-               // We are trying to enable eDP, don't power down VDD
-               if (can_apply_edp_fast_boot)
+
+               /*
+                * TO-DO: So far the code logic below only addresses single eDP case.
+                * For dual eDP case, there are a few things that need to be
+                * implemented first:
+                *
+                * 1. Change the fastboot logic above, so eDP link[0 or 1]'s
+                * stream[0 or 1] will all be checked.
+                *
+                * 2. Change keep_edp_vdd_on to an array, and maintain keep_edp_vdd_on
+                * for each eDP.
+                *
+                * Once above 2 things are completed, we can then change the logic below
+                * correspondingly, so dual eDP case will be fully covered.
+                */
+
+               // We are trying to enable eDP, don't power down VDD if eDP stream is existing
+               if ((edp_stream_num == 1 && edp_streams[0] != NULL) || can_apply_edp_fast_boot) {
                        keep_edp_vdd_on = true;
+                       DC_LOG_EVENT_LINK_TRAINING("Keep eDP Vdd on\n");
+               } else {
+                       DC_LOG_EVENT_LINK_TRAINING("No eDP stream enabled, turn eDP Vdd off\n");
+               }
        }
 
        // Check seamless boot support
@@ -2297,6 +2316,10 @@ enum dc_status dce110_apply_ctx_to_hw(
        enum dc_status status;
        int i;
 
+       /* reset syncd pipes from disabled pipes */
+       if (dc->config.use_pipe_ctx_sync_logic)
+               reset_syncd_pipes_from_disabled_pipes(dc, context);
+
        /* Reset old context */
        /* look up the targets that have been removed since last commit */
        hws->funcs.reset_hw_ctx_wrap(dc, context);
index bf4436d..b0c08ee 100644 (file)
@@ -902,19 +902,6 @@ void enc1_stream_encoder_stop_dp_info_packets(
 
 }
 
-void enc1_stream_encoder_reset_fifo(
-       struct stream_encoder *enc)
-{
-       struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
-
-       /* set DIG_START to 0x1 to reset FIFO */
-       REG_UPDATE(DIG_FE_CNTL, DIG_START, 1);
-       udelay(100);
-
-       /* write 0 to take the FIFO out of reset */
-       REG_UPDATE(DIG_FE_CNTL, DIG_START, 0);
-}
-
 void enc1_stream_encoder_dp_blank(
        struct dc_link *link,
        struct stream_encoder *enc)
@@ -1600,8 +1587,6 @@ static const struct stream_encoder_funcs dcn10_str_enc_funcs = {
                enc1_stream_encoder_send_immediate_sdp_message,
        .stop_dp_info_packets =
                enc1_stream_encoder_stop_dp_info_packets,
-       .reset_fifo =
-               enc1_stream_encoder_reset_fifo,
        .dp_blank =
                enc1_stream_encoder_dp_blank,
        .dp_unblank =
index a146a41..687d7e4 100644 (file)
@@ -626,9 +626,6 @@ void enc1_stream_encoder_send_immediate_sdp_message(
 void enc1_stream_encoder_stop_dp_info_packets(
        struct stream_encoder *enc);
 
-void enc1_stream_encoder_reset_fifo(
-       struct stream_encoder *enc);
-
 void enc1_stream_encoder_dp_blank(
        struct dc_link *link,
        struct stream_encoder *enc);
index 2bc93df..2a72517 100644 (file)
@@ -1069,7 +1069,7 @@ static const struct dc_debug_options debug_defaults_drv = {
                .timing_trace = false,
                .clock_trace = true,
                .disable_pplib_clock_request = true,
-               .pipe_split_policy = MPC_SPLIT_DYNAMIC,
+               .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP,
                .force_single_disp_pipe_split = false,
                .disable_dcc = DCC_ENABLE,
                .vsr_support = true,
index 8a70f92..aab25ca 100644 (file)
@@ -593,8 +593,6 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = {
                enc1_stream_encoder_send_immediate_sdp_message,
        .stop_dp_info_packets =
                enc1_stream_encoder_stop_dp_info_packets,
-       .reset_fifo =
-               enc1_stream_encoder_reset_fifo,
        .dp_blank =
                enc1_stream_encoder_dp_blank,
        .dp_unblank =
index 8daa127..a04ca4a 100644 (file)
@@ -789,8 +789,6 @@ static const struct stream_encoder_funcs dcn30_str_enc_funcs = {
                enc3_stream_encoder_update_dp_info_packets,
        .stop_dp_info_packets =
                enc1_stream_encoder_stop_dp_info_packets,
-       .reset_fifo =
-               enc1_stream_encoder_reset_fifo,
        .dp_blank =
                enc1_stream_encoder_dp_blank,
        .dp_unblank =
index 602ec9a..8ca2638 100644 (file)
@@ -1878,7 +1878,6 @@ noinline bool dcn30_internal_validate_bw(
        dc->res_pool->funcs->update_soc_for_wm_a(dc, context);
        pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate);
 
-       DC_FP_START();
        if (!pipe_cnt) {
                out = true;
                goto validate_out;
@@ -2104,7 +2103,6 @@ validate_fail:
        out = false;
 
 validate_out:
-       DC_FP_END();
        return out;
 }
 
@@ -2306,7 +2304,9 @@ bool dcn30_validate_bandwidth(struct dc *dc,
 
        BW_VAL_TRACE_COUNT();
 
+       DC_FP_START();
        out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate);
+       DC_FP_END();
 
        if (pipe_cnt == 0)
                goto validate_out;
index c1c6e60..5d9637b 100644 (file)
@@ -686,7 +686,7 @@ static const struct dc_debug_options debug_defaults_drv = {
        .disable_clock_gate = true,
        .disable_pplib_clock_request = true,
        .disable_pplib_wm_range = true,
-       .pipe_split_policy = MPC_SPLIT_DYNAMIC,
+       .pipe_split_policy = MPC_SPLIT_AVOID,
        .force_single_disp_pipe_split = false,
        .disable_dcc = DCC_ENABLE,
        .vsr_support = true,
@@ -1380,6 +1380,17 @@ static void set_wm_ranges(
        pp_smu->nv_funcs.set_wm_ranges(&pp_smu->nv_funcs.pp_smu, &ranges);
 }
 
+static void dcn301_calculate_wm_and_dlg(
+               struct dc *dc, struct dc_state *context,
+               display_e2e_pipe_params_st *pipes,
+               int pipe_cnt,
+               int vlevel)
+{
+       DC_FP_START();
+       dcn301_calculate_wm_and_dlg_fp(dc, context, pipes, pipe_cnt, vlevel);
+       DC_FP_END();
+}
+
 static struct resource_funcs dcn301_res_pool_funcs = {
        .destroy = dcn301_destroy_resource_pool,
        .link_enc_create = dcn301_link_encoder_create,
index 90c73a1..5e3bcaf 100644 (file)
@@ -138,8 +138,11 @@ static uint32_t convert_and_clamp(
        ret_val = wm_ns * refclk_mhz;
        ret_val /= 1000;
 
-       if (ret_val > clamp_value)
+       if (ret_val > clamp_value) {
+               /* clamping WMs is abnormal, unexpected and may lead to underflow*/
+               ASSERT(0);
                ret_val = clamp_value;
+       }
 
        return ret_val;
 }
@@ -159,7 +162,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->a.urgent_ns > hubbub2->watermarks.a.urgent_ns) {
                hubbub2->watermarks.a.urgent_ns = watermarks->a.urgent_ns;
                prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0,
                                DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
 
@@ -193,7 +196,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->a.urgent_latency_ns > hubbub2->watermarks.a.urgent_latency_ns) {
                hubbub2->watermarks.a.urgent_latency_ns = watermarks->a.urgent_latency_ns;
                prog_wm_value = convert_and_clamp(watermarks->a.urgent_latency_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, 0,
                                DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, prog_wm_value);
        } else if (watermarks->a.urgent_latency_ns < hubbub2->watermarks.a.urgent_latency_ns)
@@ -203,7 +206,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->b.urgent_ns > hubbub2->watermarks.b.urgent_ns) {
                hubbub2->watermarks.b.urgent_ns = watermarks->b.urgent_ns;
                prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0,
                                DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value);
 
@@ -237,7 +240,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->b.urgent_latency_ns > hubbub2->watermarks.b.urgent_latency_ns) {
                hubbub2->watermarks.b.urgent_latency_ns = watermarks->b.urgent_latency_ns;
                prog_wm_value = convert_and_clamp(watermarks->b.urgent_latency_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, 0,
                                DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, prog_wm_value);
        } else if (watermarks->b.urgent_latency_ns < hubbub2->watermarks.b.urgent_latency_ns)
@@ -247,7 +250,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->c.urgent_ns > hubbub2->watermarks.c.urgent_ns) {
                hubbub2->watermarks.c.urgent_ns = watermarks->c.urgent_ns;
                prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0,
                                DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value);
 
@@ -281,7 +284,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->c.urgent_latency_ns > hubbub2->watermarks.c.urgent_latency_ns) {
                hubbub2->watermarks.c.urgent_latency_ns = watermarks->c.urgent_latency_ns;
                prog_wm_value = convert_and_clamp(watermarks->c.urgent_latency_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, 0,
                                DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, prog_wm_value);
        } else if (watermarks->c.urgent_latency_ns < hubbub2->watermarks.c.urgent_latency_ns)
@@ -291,7 +294,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->d.urgent_ns > hubbub2->watermarks.d.urgent_ns) {
                hubbub2->watermarks.d.urgent_ns = watermarks->d.urgent_ns;
                prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0,
                                DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value);
 
@@ -325,7 +328,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->d.urgent_latency_ns > hubbub2->watermarks.d.urgent_latency_ns) {
                hubbub2->watermarks.d.urgent_latency_ns = watermarks->d.urgent_latency_ns;
                prog_wm_value = convert_and_clamp(watermarks->d.urgent_latency_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, 0,
                                DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, prog_wm_value);
        } else if (watermarks->d.urgent_latency_ns < hubbub2->watermarks.d.urgent_latency_ns)
@@ -351,7 +354,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n"
@@ -367,7 +370,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->a.cstate_pstate.cstate_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->a.cstate_pstate.cstate_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n"
@@ -383,7 +386,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_A calculated =%d\n"
@@ -399,7 +402,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->a.cstate_pstate.cstate_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->a.cstate_pstate.cstate_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_A calculated =%d\n"
@@ -416,7 +419,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n"
@@ -432,7 +435,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->b.cstate_pstate.cstate_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->b.cstate_pstate.cstate_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n"
@@ -448,7 +451,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_B calculated =%d\n"
@@ -464,7 +467,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->b.cstate_pstate.cstate_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->b.cstate_pstate.cstate_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_B calculated =%d\n"
@@ -481,7 +484,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n"
@@ -497,7 +500,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->c.cstate_pstate.cstate_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->c.cstate_pstate.cstate_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n"
@@ -513,7 +516,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_C calculated =%d\n"
@@ -529,7 +532,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->c.cstate_pstate.cstate_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->c.cstate_pstate.cstate_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_C calculated =%d\n"
@@ -546,7 +549,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n"
@@ -562,7 +565,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->d.cstate_pstate.cstate_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->d.cstate_pstate.cstate_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n"
@@ -578,7 +581,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_D calculated =%d\n"
@@ -594,7 +597,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->d.cstate_pstate.cstate_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->d.cstate_pstate.cstate_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_D calculated =%d\n"
@@ -625,7 +628,7 @@ static bool hubbub31_program_pstate_watermarks(
                                watermarks->a.cstate_pstate.pstate_change_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->a.cstate_pstate.pstate_change_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0,
                                DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n"
@@ -642,7 +645,7 @@ static bool hubbub31_program_pstate_watermarks(
                                watermarks->b.cstate_pstate.pstate_change_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->b.cstate_pstate.pstate_change_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0,
                                DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n"
@@ -659,7 +662,7 @@ static bool hubbub31_program_pstate_watermarks(
                                watermarks->c.cstate_pstate.pstate_change_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->c.cstate_pstate.pstate_change_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0,
                                DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n"
@@ -676,7 +679,7 @@ static bool hubbub31_program_pstate_watermarks(
                                watermarks->d.cstate_pstate.pstate_change_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->d.cstate_pstate.pstate_change_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, 0,
                                DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n"
index 42ed47e..8d64187 100644 (file)
@@ -2260,6 +2260,9 @@ static bool dcn31_resource_construct(
        dc->caps.color.mpc.ogam_rom_caps.hlg = 0;
        dc->caps.color.mpc.ocsc = 1;
 
+       /* Use pipe context based otg sync logic */
+       dc->config.use_pipe_ctx_sync_logic = true;
+
        /* read VBIOS LTTPR caps */
        {
                if (ctx->dc_bios->funcs->get_lttpr_caps) {
index 246071c..548cdef 100644 (file)
@@ -1576,8 +1576,6 @@ void dml20_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib,
        dlg_sys_param.total_flip_bytes = get_total_immediate_flip_bytes(mode_lib,
                        e2e_pipe_param,
                        num_pipes);
-       dlg_sys_param.t_srx_delay_us = mode_lib->ip.dcfclk_cstate_latency
-                       / dlg_sys_param.deepsleep_dcfclk_mhz; // TODO: Deprecated
 
        print__dlg_sys_params_st(mode_lib, &dlg_sys_param);
 
index 015e7f2..0fc9f3e 100644 (file)
@@ -1577,8 +1577,6 @@ void dml20v2_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib,
        dlg_sys_param.total_flip_bytes = get_total_immediate_flip_bytes(mode_lib,
                        e2e_pipe_param,
                        num_pipes);
-       dlg_sys_param.t_srx_delay_us = mode_lib->ip.dcfclk_cstate_latency
-                       / dlg_sys_param.deepsleep_dcfclk_mhz; // TODO: Deprecated
 
        print__dlg_sys_params_st(mode_lib, &dlg_sys_param);
 
index 8bc27de..618f4b6 100644 (file)
@@ -1688,8 +1688,6 @@ void dml21_rq_dlg_get_dlg_reg(
                        mode_lib,
                        e2e_pipe_param,
                        num_pipes);
-       dlg_sys_param.t_srx_delay_us = mode_lib->ip.dcfclk_cstate_latency
-                       / dlg_sys_param.deepsleep_dcfclk_mhz; // TODO: Deprecated
 
        print__dlg_sys_params_st(mode_lib, &dlg_sys_param);
 
index aef8542..7471670 100644 (file)
@@ -1858,8 +1858,6 @@ void dml30_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib,
        dlg_sys_param.total_flip_bytes = get_total_immediate_flip_bytes(mode_lib,
                e2e_pipe_param,
                num_pipes);
-       dlg_sys_param.t_srx_delay_us = mode_lib->ip.dcfclk_cstate_latency
-               / dlg_sys_param.deepsleep_dcfclk_mhz; // TODO: Deprecated
 
        print__dlg_sys_params_st(mode_lib, &dlg_sys_param);
 
index 94c3283..0a7a338 100644 (file)
@@ -327,7 +327,7 @@ void dcn301_fpu_init_soc_bounding_box(struct bp_soc_bb_info bb_info)
                dcn3_01_soc.sr_exit_time_us = bb_info.dram_sr_exit_latency_100ns * 10;
 }
 
-void dcn301_calculate_wm_and_dlg(struct dc *dc,
+void dcn301_calculate_wm_and_dlg_fp(struct dc *dc,
                struct dc_state *context,
                display_e2e_pipe_params_st *pipes,
                int pipe_cnt,
index fc7065d..774b0fd 100644 (file)
@@ -34,7 +34,7 @@ void dcn301_fpu_set_wm_ranges(int i,
 
 void dcn301_fpu_init_soc_bounding_box(struct bp_soc_bb_info bb_info);
 
-void dcn301_calculate_wm_and_dlg(struct dc *dc,
+void dcn301_calculate_wm_and_dlg_fp(struct dc *dc,
                struct dc_state *context,
                display_e2e_pipe_params_st *pipes,
                int pipe_cnt,
index d46a273..8f9f1d6 100644 (file)
@@ -546,7 +546,6 @@ struct _vcs_dpi_display_dlg_sys_params_st {
        double t_sr_wm_us;
        double t_extra_us;
        double mem_trip_us;
-       double t_srx_delay_us;
        double deepsleep_dcfclk_mhz;
        double total_flip_bw;
        unsigned int total_flip_bytes;
index 71ea503..412e75e 100644 (file)
@@ -141,9 +141,6 @@ void print__dlg_sys_params_st(struct display_mode_lib *mode_lib, const struct _v
        dml_print("DML_RQ_DLG_CALC:    t_urg_wm_us          = %3.2f\n", dlg_sys_param->t_urg_wm_us);
        dml_print("DML_RQ_DLG_CALC:    t_sr_wm_us           = %3.2f\n", dlg_sys_param->t_sr_wm_us);
        dml_print("DML_RQ_DLG_CALC:    t_extra_us           = %3.2f\n", dlg_sys_param->t_extra_us);
-       dml_print(
-                       "DML_RQ_DLG_CALC:    t_srx_delay_us       = %3.2f\n",
-                       dlg_sys_param->t_srx_delay_us);
        dml_print(
                        "DML_RQ_DLG_CALC:    deepsleep_dcfclk_mhz = %3.2f\n",
                        dlg_sys_param->deepsleep_dcfclk_mhz);
index 59dc2c5..3df559c 100644 (file)
@@ -1331,10 +1331,6 @@ void dml1_rq_dlg_get_dlg_params(
        if (dual_plane)
                DTRACE("DLG: %s: swath_height_c     = %d", __func__, swath_height_c);
 
-       DTRACE(
-                       "DLG: %s: t_srx_delay_us     = %3.2f",
-                       __func__,
-                       (double) dlg_sys_param->t_srx_delay_us);
        DTRACE("DLG: %s: line_time_in_us    = %3.2f", __func__, (double) line_time_in_us);
        DTRACE("DLG: %s: vupdate_offset     = %d", __func__, vupdate_offset);
        DTRACE("DLG: %s: vupdate_width      = %d", __func__, vupdate_width);
index 8902800..943240e 100644 (file)
@@ -382,6 +382,7 @@ struct pipe_ctx {
        struct pll_settings pll_settings;
 
        uint8_t pipe_idx;
+       uint8_t pipe_idx_syncd;
 
        struct pipe_ctx *top_pipe;
        struct pipe_ctx *bottom_pipe;
index 073f8b6..c88e113 100644 (file)
@@ -164,10 +164,6 @@ struct stream_encoder_funcs {
        void (*stop_dp_info_packets)(
                struct stream_encoder *enc);
 
-       void (*reset_fifo)(
-               struct stream_encoder *enc
-       );
-
        void (*dp_blank)(
                struct dc_link *link,
                struct stream_encoder *enc);
index 4249bf3..dbfe669 100644 (file)
 #define MEMORY_TYPE_HBM 2
 
 
+#define IS_PIPE_SYNCD_VALID(pipe) ((((pipe)->pipe_idx_syncd) & 0x80)?1:0)
+#define GET_PIPE_SYNCD_FROM_PIPE(pipe) ((pipe)->pipe_idx_syncd & 0x7F)
+#define SET_PIPE_SYNCD_TO_PIPE(pipe, pipe_syncd) ((pipe)->pipe_idx_syncd = (0x80 | pipe_syncd))
+
 enum dce_version resource_parse_asic_id(
                struct hw_asic_id asic_id);
 
@@ -208,6 +212,13 @@ struct hpo_dp_link_encoder *resource_get_hpo_dp_link_enc_for_det_lt(
                const struct dc_link *link);
 #endif
 
+void reset_syncd_pipes_from_disabled_pipes(struct dc *dc,
+       struct dc_state *context);
+
+void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc,
+       struct dc_state *context,
+       uint8_t disabled_master_pipe_idx);
+
 uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter);
 
 #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */
index e2cae97..48cc009 100644 (file)
@@ -3462,8 +3462,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
             attr == &sensor_dev_attr_power2_cap_min.dev_attr.attr ||
                 attr == &sensor_dev_attr_power2_cap.dev_attr.attr ||
                 attr == &sensor_dev_attr_power2_cap_default.dev_attr.attr ||
-                attr == &sensor_dev_attr_power2_label.dev_attr.attr ||
-                attr == &sensor_dev_attr_power1_label.dev_attr.attr))
+                attr == &sensor_dev_attr_power2_label.dev_attr.attr))
                return 0;
 
        return effective_mode;
index 777f717..a420729 100644 (file)
@@ -3696,14 +3696,14 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu,
 
 static int sienna_cichlid_enable_mgpu_fan_boost(struct smu_context *smu)
 {
-       struct smu_table_context *table_context = &smu->smu_table;
-       PPTable_t *smc_pptable = table_context->driver_pptable;
+       uint16_t *mgpu_fan_boost_limit_rpm;
 
+       GET_PPTABLE_MEMBER(MGpuFanBoostLimitRpm, &mgpu_fan_boost_limit_rpm);
        /*
         * Skip the MGpuFanBoost setting for those ASICs
         * which do not support it
         */
-       if (!smc_pptable->MGpuFanBoostLimitRpm)
+       if (*mgpu_fan_boost_limit_rpm == 0)
                return 0;
 
        return smu_cmn_send_smc_msg_with_param(smu,
index d9eb353..dbe1cc6 100644 (file)
@@ -282,8 +282,6 @@ static const struct ast_vbios_enhtable res_1360x768[] = {
 };
 
 static const struct ast_vbios_enhtable res_1600x900[] = {
-       {1800, 1600, 24, 80, 1000,  900, 1, 3, VCLK108,         /* 60Hz */
-        (SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 3, 0x3A },
        {1760, 1600, 48, 32, 926, 900, 3, 5, VCLK97_75,         /* 60Hz CVT RB */
         (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo |
          AST2500PreCatchCRT), 60, 1, 0x3A },
index a7389a0..af07eeb 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/bitfield.h>
+#include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/irq.h>
 #include <linux/math64.h>
@@ -196,12 +197,9 @@ static u32 ps2bc(struct nwl_dsi *dsi, unsigned long long ps)
 /*
  * ui2bc - UI time periods to byte clock cycles
  */
-static u32 ui2bc(struct nwl_dsi *dsi, unsigned long long ui)
+static u32 ui2bc(unsigned int ui)
 {
-       u32 bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
-
-       return DIV64_U64_ROUND_UP(ui * dsi->lanes,
-                                 dsi->mode.clock * 1000 * bpp);
+       return DIV_ROUND_UP(ui, BITS_PER_BYTE);
 }
 
 /*
@@ -232,12 +230,12 @@ static int nwl_dsi_config_host(struct nwl_dsi *dsi)
        }
 
        /* values in byte clock cycles */
-       cycles = ui2bc(dsi, cfg->clk_pre);
+       cycles = ui2bc(cfg->clk_pre);
        DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_t_pre: 0x%x\n", cycles);
        nwl_dsi_write(dsi, NWL_DSI_CFG_T_PRE, cycles);
        cycles = ps2bc(dsi, cfg->lpx + cfg->clk_prepare + cfg->clk_zero);
        DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_tx_gap (pre): 0x%x\n", cycles);
-       cycles += ui2bc(dsi, cfg->clk_pre);
+       cycles += ui2bc(cfg->clk_pre);
        DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_t_post: 0x%x\n", cycles);
        nwl_dsi_write(dsi, NWL_DSI_CFG_T_POST, cycles);
        cycles = ps2bc(dsi, cfg->hs_exit);
index 21174ef..88cd992 100644 (file)
@@ -1327,8 +1327,10 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
 
        drm_dbg_atomic(dev, "checking %p\n", state);
 
-       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i)
-               requested_crtc |= drm_crtc_mask(crtc);
+       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+               if (new_crtc_state->enable)
+                       requested_crtc |= drm_crtc_mask(crtc);
+       }
 
        for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
                ret = drm_atomic_plane_check(old_plane_state, new_plane_state);
@@ -1377,8 +1379,10 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
                }
        }
 
-       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i)
-               affected_crtc |= drm_crtc_mask(crtc);
+       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+               if (new_crtc_state->enable)
+                       affected_crtc |= drm_crtc_mask(crtc);
+       }
 
        /*
         * For commits that allow modesets drivers can add other CRTCs to the
index 042bb80..b910978 100644 (file)
@@ -115,6 +115,12 @@ static const struct drm_dmi_panel_orientation_data lcd1280x1920_rightside_up = {
        .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
 };
 
+static const struct drm_dmi_panel_orientation_data lcd1600x2560_leftside_up = {
+       .width = 1600,
+       .height = 2560,
+       .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP,
+};
+
 static const struct dmi_system_id orientation_data[] = {
        {       /* Acer One 10 (S1003) */
                .matches = {
@@ -275,6 +281,12 @@ static const struct dmi_system_id orientation_data[] = {
                  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Default string"),
                },
                .driver_data = (void *)&onegx1_pro,
+       }, {    /* OneXPlayer */
+               .matches = {
+                 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ONE-NETBOOK TECHNOLOGY CO., LTD."),
+                 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ONE XPLAYER"),
+               },
+               .driver_data = (void *)&lcd1600x2560_leftside_up,
        }, {    /* Samsung GalaxyBook 10.6 */
                .matches = {
                  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
index beaf99e..b688841 100644 (file)
@@ -269,7 +269,7 @@ EXPORT_SYMBOL(drm_privacy_screen_get_state);
  *
  * The notifier is called with no locks held. The new hw_state and sw_state
  * can be retrieved using the drm_privacy_screen_get_state() function.
- * A pointer to the drm_privacy_screen's struct is passed as the void *data
+ * A pointer to the drm_privacy_screen's struct is passed as the ``void *data``
  * argument of the notifier_block's notifier_call.
  *
  * The notifier will NOT be called when changes are made through
index a2cafb2..e7aa74a 100644 (file)
@@ -33,6 +33,9 @@ static bool __init detect_thinkpad_privacy_screen(void)
        unsigned long long output;
        acpi_status status;
 
+       if (acpi_disabled)
+               return false;
+
        /* Get embedded-controller handle */
        status = acpi_get_devices("PNP0C09", acpi_set_handle, NULL, &ec_handle);
        if (ACPI_FAILURE(status) || !ec_handle)
index b03c20c..a173132 100644 (file)
@@ -469,8 +469,8 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
-       if (args->stream_size > SZ_64K || args->nr_relocs > SZ_64K ||
-           args->nr_bos > SZ_64K || args->nr_pmrs > 128) {
+       if (args->stream_size > SZ_128K || args->nr_relocs > SZ_128K ||
+           args->nr_bos > SZ_128K || args->nr_pmrs > 128) {
                DRM_ERROR("submit arguments out of size limits\n");
                return -EINVAL;
        }
index bf7ce68..bb4a854 100644 (file)
@@ -10673,6 +10673,7 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
                vlv_wm_sanitize(dev_priv);
        } else if (DISPLAY_VER(dev_priv) >= 9) {
                skl_wm_get_hw_state(dev_priv);
+               skl_wm_sanitize(dev_priv);
        } else if (HAS_PCH_SPLIT(dev_priv)) {
                ilk_wm_get_hw_state(dev_priv);
        }
index c1439fc..3ff149d 100644 (file)
@@ -405,6 +405,7 @@ intel_drrs_init(struct intel_connector *connector,
                struct drm_display_mode *fixed_mode)
 {
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_encoder *encoder = connector->encoder;
        struct drm_display_mode *downclock_mode = NULL;
 
        INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_drrs_downclock_work);
@@ -416,6 +417,13 @@ intel_drrs_init(struct intel_connector *connector,
                return NULL;
        }
 
+       if ((DISPLAY_VER(dev_priv) < 8 && !HAS_GMCH(dev_priv)) &&
+           encoder->port != PORT_A) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "DRRS only supported on eDP port A\n");
+               return NULL;
+       }
+
        if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) {
                drm_dbg_kms(&dev_priv->drm, "VBT doesn't support DRRS\n");
                return NULL;
index 1a376e9..d610e48 100644 (file)
@@ -959,6 +959,9 @@ static int check_overlay_dst(struct intel_overlay *overlay,
        const struct intel_crtc_state *pipe_config =
                overlay->crtc->config;
 
+       if (rec->dst_height == 0 || rec->dst_width == 0)
+               return -EINVAL;
+
        if (rec->dst_x < pipe_config->pipe_src_w &&
            rec->dst_x + rec->dst_width <= pipe_config->pipe_src_w &&
            rec->dst_y < pipe_config->pipe_src_h &&
index 40faa18..dbd7d0d 100644 (file)
@@ -345,10 +345,11 @@ static bool icl_tc_phy_status_complete(struct intel_digital_port *dig_port)
 static bool adl_tc_phy_status_complete(struct intel_digital_port *dig_port)
 {
        struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+       enum tc_port tc_port = intel_port_to_tc(i915, dig_port->base.port);
        struct intel_uncore *uncore = &i915->uncore;
        u32 val;
 
-       val = intel_uncore_read(uncore, TCSS_DDI_STATUS(dig_port->tc_phy_fia_idx));
+       val = intel_uncore_read(uncore, TCSS_DDI_STATUS(tc_port));
        if (val == 0xffffffff) {
                drm_dbg_kms(&i915->drm,
                            "Port %s: PHY in TCCOLD, assuming not complete\n",
index 3a5b247..1736efa 100644 (file)
@@ -2505,9 +2505,14 @@ static int eb_pin_timeline(struct i915_execbuffer *eb, struct intel_context *ce,
                                      timeout) < 0) {
                        i915_request_put(rq);
 
-                       tl = intel_context_timeline_lock(ce);
+                       /*
+                        * Error path, cannot use intel_context_timeline_lock as
+                        * that is user interruptable and this clean up step
+                        * must be done.
+                        */
+                       mutex_lock(&ce->timeline->mutex);
                        intel_context_exit(ce);
-                       intel_context_timeline_unlock(tl);
+                       mutex_unlock(&ce->timeline->mutex);
 
                        if (nonblock)
                                return -EWOULDBLOCK;
index 4b4829e..0dd107d 100644 (file)
@@ -311,6 +311,7 @@ struct drm_i915_gem_object {
 #define I915_BO_READONLY          BIT(6)
 #define I915_TILING_QUIRK_BIT     7 /* unknown swizzling; do not release! */
 #define I915_BO_PROTECTED         BIT(8)
+#define I915_BO_WAS_BOUND_BIT     9
        /**
         * @mem_flags - Mutable placement-related flags
         *
index 9f429ed..a50f884 100644 (file)
@@ -10,6 +10,8 @@
 #include "i915_gem_lmem.h"
 #include "i915_gem_mman.h"
 
+#include "gt/intel_gt.h"
+
 void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
                                 struct sg_table *pages,
                                 unsigned int sg_page_sizes)
@@ -221,6 +223,14 @@ __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj)
        __i915_gem_object_reset_page_iter(obj);
        obj->mm.page_sizes.phys = obj->mm.page_sizes.sg = 0;
 
+       if (test_and_clear_bit(I915_BO_WAS_BOUND_BIT, &obj->flags)) {
+               struct drm_i915_private *i915 = to_i915(obj->base.dev);
+               intel_wakeref_t wakeref;
+
+               with_intel_runtime_pm_if_active(&i915->runtime_pm, wakeref)
+                       intel_gt_invalidate_tlbs(to_gt(i915));
+       }
+
        return pages;
 }
 
index ee9612a..e130c82 100644 (file)
@@ -427,11 +427,17 @@ __i915_ttm_move(struct ttm_buffer_object *bo,
 
                if (!IS_ERR(fence))
                        goto out;
-       } else if (move_deps) {
-               int err = i915_deps_sync(move_deps, ctx);
+       } else {
+               int err = PTR_ERR(fence);
+
+               if (err == -EINTR || err == -ERESTARTSYS || err == -EAGAIN)
+                       return fence;
 
-               if (err)
-                       return ERR_PTR(err);
+               if (move_deps) {
+                       err = i915_deps_sync(move_deps, ctx);
+                       if (err)
+                               return ERR_PTR(err);
+               }
        }
 
        /* Error intercept failed or no accelerated migration to start with */
index f98f0fb..35d0fcd 100644 (file)
@@ -29,6 +29,8 @@ void __intel_gt_init_early(struct intel_gt *gt, struct drm_i915_private *i915)
 {
        spin_lock_init(&gt->irq_lock);
 
+       mutex_init(&gt->tlb_invalidate_lock);
+
        INIT_LIST_HEAD(&gt->closed_vma);
        spin_lock_init(&gt->closed_lock);
 
@@ -912,3 +914,109 @@ void intel_gt_info_print(const struct intel_gt_info *info,
 
        intel_sseu_dump(&info->sseu, p);
 }
+
+struct reg_and_bit {
+       i915_reg_t reg;
+       u32 bit;
+};
+
+static struct reg_and_bit
+get_reg_and_bit(const struct intel_engine_cs *engine, const bool gen8,
+               const i915_reg_t *regs, const unsigned int num)
+{
+       const unsigned int class = engine->class;
+       struct reg_and_bit rb = { };
+
+       if (drm_WARN_ON_ONCE(&engine->i915->drm,
+                            class >= num || !regs[class].reg))
+               return rb;
+
+       rb.reg = regs[class];
+       if (gen8 && class == VIDEO_DECODE_CLASS)
+               rb.reg.reg += 4 * engine->instance; /* GEN8_M2TCR */
+       else
+               rb.bit = engine->instance;
+
+       rb.bit = BIT(rb.bit);
+
+       return rb;
+}
+
+void intel_gt_invalidate_tlbs(struct intel_gt *gt)
+{
+       static const i915_reg_t gen8_regs[] = {
+               [RENDER_CLASS]                  = GEN8_RTCR,
+               [VIDEO_DECODE_CLASS]            = GEN8_M1TCR, /* , GEN8_M2TCR */
+               [VIDEO_ENHANCEMENT_CLASS]       = GEN8_VTCR,
+               [COPY_ENGINE_CLASS]             = GEN8_BTCR,
+       };
+       static const i915_reg_t gen12_regs[] = {
+               [RENDER_CLASS]                  = GEN12_GFX_TLB_INV_CR,
+               [VIDEO_DECODE_CLASS]            = GEN12_VD_TLB_INV_CR,
+               [VIDEO_ENHANCEMENT_CLASS]       = GEN12_VE_TLB_INV_CR,
+               [COPY_ENGINE_CLASS]             = GEN12_BLT_TLB_INV_CR,
+       };
+       struct drm_i915_private *i915 = gt->i915;
+       struct intel_uncore *uncore = gt->uncore;
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
+       const i915_reg_t *regs;
+       unsigned int num = 0;
+
+       if (I915_SELFTEST_ONLY(gt->awake == -ENODEV))
+               return;
+
+       if (GRAPHICS_VER(i915) == 12) {
+               regs = gen12_regs;
+               num = ARRAY_SIZE(gen12_regs);
+       } else if (GRAPHICS_VER(i915) >= 8 && GRAPHICS_VER(i915) <= 11) {
+               regs = gen8_regs;
+               num = ARRAY_SIZE(gen8_regs);
+       } else if (GRAPHICS_VER(i915) < 8) {
+               return;
+       }
+
+       if (drm_WARN_ONCE(&i915->drm, !num,
+                         "Platform does not implement TLB invalidation!"))
+               return;
+
+       GEM_TRACE("\n");
+
+       assert_rpm_wakelock_held(&i915->runtime_pm);
+
+       mutex_lock(&gt->tlb_invalidate_lock);
+       intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
+
+       for_each_engine(engine, gt, id) {
+               /*
+                * HW architecture suggest typical invalidation time at 40us,
+                * with pessimistic cases up to 100us and a recommendation to
+                * cap at 1ms. We go a bit higher just in case.
+                */
+               const unsigned int timeout_us = 100;
+               const unsigned int timeout_ms = 4;
+               struct reg_and_bit rb;
+
+               rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num);
+               if (!i915_mmio_reg_offset(rb.reg))
+                       continue;
+
+               intel_uncore_write_fw(uncore, rb.reg, rb.bit);
+               if (__intel_wait_for_register_fw(uncore,
+                                                rb.reg, rb.bit, 0,
+                                                timeout_us, timeout_ms,
+                                                NULL))
+                       drm_err_ratelimited(&gt->i915->drm,
+                                           "%s TLB invalidation did not complete in %ums!\n",
+                                           engine->name, timeout_ms);
+       }
+
+       /*
+        * Use delayed put since a) we mostly expect a flurry of TLB
+        * invalidations so it is good to avoid paying the forcewake cost and
+        * b) it works around a bug in Icelake which cannot cope with too rapid
+        * transitions.
+        */
+       intel_uncore_forcewake_put_delayed(uncore, FORCEWAKE_ALL);
+       mutex_unlock(&gt->tlb_invalidate_lock);
+}
index 3ace129..a913fb6 100644 (file)
@@ -91,4 +91,6 @@ void intel_gt_info_print(const struct intel_gt_info *info,
 
 void intel_gt_watchdog_work(struct work_struct *work);
 
+void intel_gt_invalidate_tlbs(struct intel_gt *gt);
+
 #endif /* __INTEL_GT_H__ */
index 14216cc..f206877 100644 (file)
@@ -73,6 +73,8 @@ struct intel_gt {
 
        struct intel_uc uc;
 
+       struct mutex tlb_invalidate_lock;
+
        struct i915_wa_list wa_list;
 
        struct intel_gt_timelines {
index f9240d4..3aabe16 100644 (file)
@@ -206,6 +206,11 @@ struct intel_guc {
                 * context usage for overflows.
                 */
                struct delayed_work work;
+
+               /**
+                * @shift: Right shift value for the gpm timestamp
+                */
+               u32 shift;
        } timestamp;
 
 #ifdef CONFIG_DRM_I915_SELFTEST
index e751720..154ad72 100644 (file)
@@ -1113,6 +1113,19 @@ __extend_last_switch(struct intel_guc *guc, u64 *prev_start, u32 new_start)
        if (new_start == lower_32_bits(*prev_start))
                return;
 
+       /*
+        * When gt is unparked, we update the gt timestamp and start the ping
+        * worker that updates the gt_stamp every POLL_TIME_CLKS. As long as gt
+        * is unparked, all switched in contexts will have a start time that is
+        * within +/- POLL_TIME_CLKS of the most recent gt_stamp.
+        *
+        * If neither gt_stamp nor new_start has rolled over, then the
+        * gt_stamp_hi does not need to be adjusted, however if one of them has
+        * rolled over, we need to adjust gt_stamp_hi accordingly.
+        *
+        * The below conditions address the cases of new_start rollover and
+        * gt_stamp_last rollover respectively.
+        */
        if (new_start < gt_stamp_last &&
            (new_start - gt_stamp_last) <= POLL_TIME_CLKS)
                gt_stamp_hi++;
@@ -1124,17 +1137,45 @@ __extend_last_switch(struct intel_guc *guc, u64 *prev_start, u32 new_start)
        *prev_start = ((u64)gt_stamp_hi << 32) | new_start;
 }
 
-static void guc_update_engine_gt_clks(struct intel_engine_cs *engine)
+/*
+ * GuC updates shared memory and KMD reads it. Since this is not synchronized,
+ * we run into a race where the value read is inconsistent. Sometimes the
+ * inconsistency is in reading the upper MSB bytes of the last_in value when
+ * this race occurs. 2 types of cases are seen - upper 8 bits are zero and upper
+ * 24 bits are zero. Since these are non-zero values, it is non-trivial to
+ * determine validity of these values. Instead we read the values multiple times
+ * until they are consistent. In test runs, 3 attempts results in consistent
+ * values. The upper bound is set to 6 attempts and may need to be tuned as per
+ * any new occurences.
+ */
+static void __get_engine_usage_record(struct intel_engine_cs *engine,
+                                     u32 *last_in, u32 *id, u32 *total)
 {
        struct guc_engine_usage_record *rec = intel_guc_engine_usage(engine);
+       int i = 0;
+
+       do {
+               *last_in = READ_ONCE(rec->last_switch_in_stamp);
+               *id = READ_ONCE(rec->current_context_index);
+               *total = READ_ONCE(rec->total_runtime);
+
+               if (READ_ONCE(rec->last_switch_in_stamp) == *last_in &&
+                   READ_ONCE(rec->current_context_index) == *id &&
+                   READ_ONCE(rec->total_runtime) == *total)
+                       break;
+       } while (++i < 6);
+}
+
+static void guc_update_engine_gt_clks(struct intel_engine_cs *engine)
+{
        struct intel_engine_guc_stats *stats = &engine->stats.guc;
        struct intel_guc *guc = &engine->gt->uc.guc;
-       u32 last_switch = rec->last_switch_in_stamp;
-       u32 ctx_id = rec->current_context_index;
-       u32 total = rec->total_runtime;
+       u32 last_switch, ctx_id, total;
 
        lockdep_assert_held(&guc->timestamp.lock);
 
+       __get_engine_usage_record(engine, &last_switch, &ctx_id, &total);
+
        stats->running = ctx_id != ~0U && last_switch;
        if (stats->running)
                __extend_last_switch(guc, &stats->start_gt_clk, last_switch);
@@ -1149,23 +1190,51 @@ static void guc_update_engine_gt_clks(struct intel_engine_cs *engine)
        }
 }
 
-static void guc_update_pm_timestamp(struct intel_guc *guc,
-                                   struct intel_engine_cs *engine,
-                                   ktime_t *now)
+static u32 gpm_timestamp_shift(struct intel_gt *gt)
+{
+       intel_wakeref_t wakeref;
+       u32 reg, shift;
+
+       with_intel_runtime_pm(gt->uncore->rpm, wakeref)
+               reg = intel_uncore_read(gt->uncore, RPM_CONFIG0);
+
+       shift = (reg & GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK) >>
+               GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_SHIFT;
+
+       return 3 - shift;
+}
+
+static u64 gpm_timestamp(struct intel_gt *gt)
+{
+       u32 lo, hi, old_hi, loop = 0;
+
+       hi = intel_uncore_read(gt->uncore, MISC_STATUS1);
+       do {
+               lo = intel_uncore_read(gt->uncore, MISC_STATUS0);
+               old_hi = hi;
+               hi = intel_uncore_read(gt->uncore, MISC_STATUS1);
+       } while (old_hi != hi && loop++ < 2);
+
+       return ((u64)hi << 32) | lo;
+}
+
+static void guc_update_pm_timestamp(struct intel_guc *guc, ktime_t *now)
 {
-       u32 gt_stamp_now, gt_stamp_hi;
+       struct intel_gt *gt = guc_to_gt(guc);
+       u32 gt_stamp_lo, gt_stamp_hi;
+       u64 gpm_ts;
 
        lockdep_assert_held(&guc->timestamp.lock);
 
        gt_stamp_hi = upper_32_bits(guc->timestamp.gt_stamp);
-       gt_stamp_now = intel_uncore_read(engine->uncore,
-                                        RING_TIMESTAMP(engine->mmio_base));
+       gpm_ts = gpm_timestamp(gt) >> guc->timestamp.shift;
+       gt_stamp_lo = lower_32_bits(gpm_ts);
        *now = ktime_get();
 
-       if (gt_stamp_now < lower_32_bits(guc->timestamp.gt_stamp))
+       if (gt_stamp_lo < lower_32_bits(guc->timestamp.gt_stamp))
                gt_stamp_hi++;
 
-       guc->timestamp.gt_stamp = ((u64)gt_stamp_hi << 32) | gt_stamp_now;
+       guc->timestamp.gt_stamp = ((u64)gt_stamp_hi << 32) | gt_stamp_lo;
 }
 
 /*
@@ -1208,8 +1277,12 @@ static ktime_t guc_engine_busyness(struct intel_engine_cs *engine, ktime_t *now)
        if (!in_reset && intel_gt_pm_get_if_awake(gt)) {
                stats_saved = *stats;
                gt_stamp_saved = guc->timestamp.gt_stamp;
+               /*
+                * Update gt_clks, then gt timestamp to simplify the 'gt_stamp -
+                * start_gt_clk' calculation below for active engines.
+                */
                guc_update_engine_gt_clks(engine);
-               guc_update_pm_timestamp(guc, engine, now);
+               guc_update_pm_timestamp(guc, now);
                intel_gt_pm_put_async(gt);
                if (i915_reset_count(gpu_error) != reset_count) {
                        *stats = stats_saved;
@@ -1241,8 +1314,8 @@ static void __reset_guc_busyness_stats(struct intel_guc *guc)
 
        spin_lock_irqsave(&guc->timestamp.lock, flags);
 
+       guc_update_pm_timestamp(guc, &unused);
        for_each_engine(engine, gt, id) {
-               guc_update_pm_timestamp(guc, engine, &unused);
                guc_update_engine_gt_clks(engine);
                engine->stats.guc.prev_total = 0;
        }
@@ -1259,10 +1332,11 @@ static void __update_guc_busyness_stats(struct intel_guc *guc)
        ktime_t unused;
 
        spin_lock_irqsave(&guc->timestamp.lock, flags);
-       for_each_engine(engine, gt, id) {
-               guc_update_pm_timestamp(guc, engine, &unused);
+
+       guc_update_pm_timestamp(guc, &unused);
+       for_each_engine(engine, gt, id)
                guc_update_engine_gt_clks(engine);
-       }
+
        spin_unlock_irqrestore(&guc->timestamp.lock, flags);
 }
 
@@ -1335,10 +1409,15 @@ void intel_guc_busyness_park(struct intel_gt *gt)
 void intel_guc_busyness_unpark(struct intel_gt *gt)
 {
        struct intel_guc *guc = &gt->uc.guc;
+       unsigned long flags;
+       ktime_t unused;
 
        if (!guc_submission_initialized(guc))
                return;
 
+       spin_lock_irqsave(&guc->timestamp.lock, flags);
+       guc_update_pm_timestamp(guc, &unused);
+       spin_unlock_irqrestore(&guc->timestamp.lock, flags);
        mod_delayed_work(system_highpri_wq, &guc->timestamp.work,
                         guc->timestamp.ping_delay);
 }
@@ -1783,6 +1862,7 @@ int intel_guc_submission_init(struct intel_guc *guc)
        spin_lock_init(&guc->timestamp.lock);
        INIT_DELAYED_WORK(&guc->timestamp.work, guc_timestamp_ping);
        guc->timestamp.ping_delay = (POLL_TIME_CLKS / gt->clock_frequency + 1) * HZ;
+       guc->timestamp.shift = gpm_timestamp_shift(gt);
 
        return 0;
 }
index 5ae812d..0633888 100644 (file)
@@ -1522,7 +1522,7 @@ capture_engine(struct intel_engine_cs *engine,
        struct i915_request *rq = NULL;
        unsigned long flags;
 
-       ee = intel_engine_coredump_alloc(engine, GFP_KERNEL);
+       ee = intel_engine_coredump_alloc(engine, ALLOW_FAIL);
        if (!ee)
                return NULL;
 
index 76f1d53..3ad22bb 100644 (file)
@@ -6,6 +6,7 @@
 #ifndef __I915_MM_H__
 #define __I915_MM_H__
 
+#include <linux/bug.h>
 #include <linux/types.h>
 
 struct vm_area_struct;
index 971d601..c2bb33f 100644 (file)
@@ -2684,7 +2684,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 #define   RING_WAIT            (1 << 11) /* gen3+, PRBx_CTL */
 #define   RING_WAIT_SEMAPHORE  (1 << 10) /* gen6+ */
 
-#define GUCPMTIMESTAMP          _MMIO(0xC3E8)
+#define MISC_STATUS0           _MMIO(0xA500)
+#define MISC_STATUS1           _MMIO(0xA504)
 
 /* There are 16 64-bit CS General Purpose Registers per-engine on Gen8+ */
 #define GEN8_RING_CS_GPR(base, n)      _MMIO((base) + 0x600 + (n) * 8)
@@ -2721,6 +2722,12 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 #define   GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING     (1 << 28)
 #define   GAMT_CHKN_DISABLE_I2M_CYCLE_ON_WR_PORT       (1 << 24)
 
+#define GEN8_RTCR      _MMIO(0x4260)
+#define GEN8_M1TCR     _MMIO(0x4264)
+#define GEN8_M2TCR     _MMIO(0x4268)
+#define GEN8_BTCR      _MMIO(0x426c)
+#define GEN8_VTCR      _MMIO(0x4270)
+
 #if 0
 #define PRB0_TAIL      _MMIO(0x2030)
 #define PRB0_HEAD      _MMIO(0x2034)
@@ -2819,6 +2826,11 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 #define   FAULT_VA_HIGH_BITS           (0xf << 0)
 #define   FAULT_GTT_SEL                        (1 << 4)
 
+#define GEN12_GFX_TLB_INV_CR   _MMIO(0xced8)
+#define GEN12_VD_TLB_INV_CR    _MMIO(0xcedc)
+#define GEN12_VE_TLB_INV_CR    _MMIO(0xcee0)
+#define GEN12_BLT_TLB_INV_CR   _MMIO(0xcee4)
+
 #define GEN12_AUX_ERR_DBG              _MMIO(0x43f4)
 
 #define FPGA_DBG               _MMIO(0x42300)
index 29a858c..c0d6d55 100644 (file)
@@ -457,6 +457,9 @@ int i915_vma_bind(struct i915_vma *vma,
                vma->ops->bind_vma(vma->vm, NULL, vma, cache_level, bind_flags);
        }
 
+       if (vma->obj)
+               set_bit(I915_BO_WAS_BOUND_BIT, &vma->obj->flags);
+
        atomic_or(bind_flags, &vma->flags);
        return 0;
 }
index 434b1f8..3edba7f 100644 (file)
@@ -4717,6 +4717,10 @@ static const struct dbuf_slice_conf_entry dg2_allowed_dbufs[] = {
 };
 
 static const struct dbuf_slice_conf_entry adlp_allowed_dbufs[] = {
+       /*
+        * Keep the join_mbus cases first so check_mbus_joined()
+        * will prefer them over the !join_mbus cases.
+        */
        {
                .active_pipes = BIT(PIPE_A),
                .dbuf_mask = {
@@ -4731,6 +4735,20 @@ static const struct dbuf_slice_conf_entry adlp_allowed_dbufs[] = {
                },
                .join_mbus = true,
        },
+       {
+               .active_pipes = BIT(PIPE_A),
+               .dbuf_mask = {
+                       [PIPE_A] = BIT(DBUF_S1) | BIT(DBUF_S2),
+               },
+               .join_mbus = false,
+       },
+       {
+               .active_pipes = BIT(PIPE_B),
+               .dbuf_mask = {
+                       [PIPE_B] = BIT(DBUF_S3) | BIT(DBUF_S4),
+               },
+               .join_mbus = false,
+       },
        {
                .active_pipes = BIT(PIPE_A) | BIT(PIPE_B),
                .dbuf_mask = {
@@ -4847,13 +4865,14 @@ static bool adlp_check_mbus_joined(u8 active_pipes)
        return check_mbus_joined(active_pipes, adlp_allowed_dbufs);
 }
 
-static u8 compute_dbuf_slices(enum pipe pipe, u8 active_pipes,
+static u8 compute_dbuf_slices(enum pipe pipe, u8 active_pipes, bool join_mbus,
                              const struct dbuf_slice_conf_entry *dbuf_slices)
 {
        int i;
 
        for (i = 0; i < dbuf_slices[i].active_pipes; i++) {
-               if (dbuf_slices[i].active_pipes == active_pipes)
+               if (dbuf_slices[i].active_pipes == active_pipes &&
+                   dbuf_slices[i].join_mbus == join_mbus)
                        return dbuf_slices[i].dbuf_mask[pipe];
        }
        return 0;
@@ -4864,7 +4883,7 @@ static u8 compute_dbuf_slices(enum pipe pipe, u8 active_pipes,
  * returns correspondent DBuf slice mask as stated in BSpec for particular
  * platform.
  */
-static u8 icl_compute_dbuf_slices(enum pipe pipe, u8 active_pipes)
+static u8 icl_compute_dbuf_slices(enum pipe pipe, u8 active_pipes, bool join_mbus)
 {
        /*
         * FIXME: For ICL this is still a bit unclear as prev BSpec revision
@@ -4878,37 +4897,41 @@ static u8 icl_compute_dbuf_slices(enum pipe pipe, u8 active_pipes)
         * still here - we will need it once those additional constraints
         * pop up.
         */
-       return compute_dbuf_slices(pipe, active_pipes, icl_allowed_dbufs);
+       return compute_dbuf_slices(pipe, active_pipes, join_mbus,
+                                  icl_allowed_dbufs);
 }
 
-static u8 tgl_compute_dbuf_slices(enum pipe pipe, u8 active_pipes)
+static u8 tgl_compute_dbuf_slices(enum pipe pipe, u8 active_pipes, bool join_mbus)
 {
-       return compute_dbuf_slices(pipe, active_pipes, tgl_allowed_dbufs);
+       return compute_dbuf_slices(pipe, active_pipes, join_mbus,
+                                  tgl_allowed_dbufs);
 }
 
-static u32 adlp_compute_dbuf_slices(enum pipe pipe, u32 active_pipes)
+static u8 adlp_compute_dbuf_slices(enum pipe pipe, u8 active_pipes, bool join_mbus)
 {
-       return compute_dbuf_slices(pipe, active_pipes, adlp_allowed_dbufs);
+       return compute_dbuf_slices(pipe, active_pipes, join_mbus,
+                                  adlp_allowed_dbufs);
 }
 
-static u32 dg2_compute_dbuf_slices(enum pipe pipe, u32 active_pipes)
+static u8 dg2_compute_dbuf_slices(enum pipe pipe, u8 active_pipes, bool join_mbus)
 {
-       return compute_dbuf_slices(pipe, active_pipes, dg2_allowed_dbufs);
+       return compute_dbuf_slices(pipe, active_pipes, join_mbus,
+                                  dg2_allowed_dbufs);
 }
 
-static u8 skl_compute_dbuf_slices(struct intel_crtc *crtc, u8 active_pipes)
+static u8 skl_compute_dbuf_slices(struct intel_crtc *crtc, u8 active_pipes, bool join_mbus)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        enum pipe pipe = crtc->pipe;
 
        if (IS_DG2(dev_priv))
-               return dg2_compute_dbuf_slices(pipe, active_pipes);
+               return dg2_compute_dbuf_slices(pipe, active_pipes, join_mbus);
        else if (IS_ALDERLAKE_P(dev_priv))
-               return adlp_compute_dbuf_slices(pipe, active_pipes);
+               return adlp_compute_dbuf_slices(pipe, active_pipes, join_mbus);
        else if (DISPLAY_VER(dev_priv) == 12)
-               return tgl_compute_dbuf_slices(pipe, active_pipes);
+               return tgl_compute_dbuf_slices(pipe, active_pipes, join_mbus);
        else if (DISPLAY_VER(dev_priv) == 11)
-               return icl_compute_dbuf_slices(pipe, active_pipes);
+               return icl_compute_dbuf_slices(pipe, active_pipes, join_mbus);
        /*
         * For anything else just return one slice yet.
         * Should be extended for other platforms.
@@ -6127,11 +6150,16 @@ skl_compute_ddb(struct intel_atomic_state *state)
                        return ret;
        }
 
+       if (IS_ALDERLAKE_P(dev_priv))
+               new_dbuf_state->joined_mbus =
+                       adlp_check_mbus_joined(new_dbuf_state->active_pipes);
+
        for_each_intel_crtc(&dev_priv->drm, crtc) {
                enum pipe pipe = crtc->pipe;
 
                new_dbuf_state->slices[pipe] =
-                       skl_compute_dbuf_slices(crtc, new_dbuf_state->active_pipes);
+                       skl_compute_dbuf_slices(crtc, new_dbuf_state->active_pipes,
+                                               new_dbuf_state->joined_mbus);
 
                if (old_dbuf_state->slices[pipe] == new_dbuf_state->slices[pipe])
                        continue;
@@ -6143,9 +6171,6 @@ skl_compute_ddb(struct intel_atomic_state *state)
 
        new_dbuf_state->enabled_slices = intel_dbuf_enabled_slices(new_dbuf_state);
 
-       if (IS_ALDERLAKE_P(dev_priv))
-               new_dbuf_state->joined_mbus = adlp_check_mbus_joined(new_dbuf_state->active_pipes);
-
        if (old_dbuf_state->enabled_slices != new_dbuf_state->enabled_slices ||
            old_dbuf_state->joined_mbus != new_dbuf_state->joined_mbus) {
                ret = intel_atomic_serialize_global_state(&new_dbuf_state->base);
@@ -6626,6 +6651,7 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv)
                enum pipe pipe = crtc->pipe;
                unsigned int mbus_offset;
                enum plane_id plane_id;
+               u8 slices;
 
                skl_pipe_wm_get_hw_state(crtc, &crtc_state->wm.skl.optimal);
                crtc_state->wm.skl.raw = crtc_state->wm.skl.optimal;
@@ -6645,19 +6671,22 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv)
                        skl_ddb_entry_union(&dbuf_state->ddb[pipe], ddb_uv);
                }
 
-               dbuf_state->slices[pipe] =
-                       skl_compute_dbuf_slices(crtc, dbuf_state->active_pipes);
-
                dbuf_state->weight[pipe] = intel_crtc_ddb_weight(crtc_state);
 
                /*
                 * Used for checking overlaps, so we need absolute
                 * offsets instead of MBUS relative offsets.
                 */
-               mbus_offset = mbus_ddb_offset(dev_priv, dbuf_state->slices[pipe]);
+               slices = skl_compute_dbuf_slices(crtc, dbuf_state->active_pipes,
+                                                dbuf_state->joined_mbus);
+               mbus_offset = mbus_ddb_offset(dev_priv, slices);
                crtc_state->wm.skl.ddb.start = mbus_offset + dbuf_state->ddb[pipe].start;
                crtc_state->wm.skl.ddb.end = mbus_offset + dbuf_state->ddb[pipe].end;
 
+               /* The slices actually used by the planes on the pipe */
+               dbuf_state->slices[pipe] =
+                       skl_ddb_dbuf_slice_mask(dev_priv, &crtc_state->wm.skl.ddb);
+
                drm_dbg_kms(&dev_priv->drm,
                            "[CRTC:%d:%s] dbuf slices 0x%x, ddb (%d - %d), active pipes 0x%x, mbus joined: %s\n",
                            crtc->base.base.id, crtc->base.name,
@@ -6669,6 +6698,74 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv)
        dbuf_state->enabled_slices = dev_priv->dbuf.enabled_slices;
 }
 
+static bool skl_dbuf_is_misconfigured(struct drm_i915_private *i915)
+{
+       const struct intel_dbuf_state *dbuf_state =
+               to_intel_dbuf_state(i915->dbuf.obj.state);
+       struct skl_ddb_entry entries[I915_MAX_PIPES] = {};
+       struct intel_crtc *crtc;
+
+       for_each_intel_crtc(&i915->drm, crtc) {
+               const struct intel_crtc_state *crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+
+               entries[crtc->pipe] = crtc_state->wm.skl.ddb;
+       }
+
+       for_each_intel_crtc(&i915->drm, crtc) {
+               const struct intel_crtc_state *crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+               u8 slices;
+
+               slices = skl_compute_dbuf_slices(crtc, dbuf_state->active_pipes,
+                                                dbuf_state->joined_mbus);
+               if (dbuf_state->slices[crtc->pipe] & ~slices)
+                       return true;
+
+               if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.ddb, entries,
+                                               I915_MAX_PIPES, crtc->pipe))
+                       return true;
+       }
+
+       return false;
+}
+
+void skl_wm_sanitize(struct drm_i915_private *i915)
+{
+       struct intel_crtc *crtc;
+
+       /*
+        * On TGL/RKL (at least) the BIOS likes to assign the planes
+        * to the wrong DBUF slices. This will cause an infinite loop
+        * in skl_commit_modeset_enables() as it can't find a way to
+        * transition between the old bogus DBUF layout to the new
+        * proper DBUF layout without DBUF allocation overlaps between
+        * the planes (which cannot be allowed or else the hardware
+        * may hang). If we detect a bogus DBUF layout just turn off
+        * all the planes so that skl_commit_modeset_enables() can
+        * simply ignore them.
+        */
+       if (!skl_dbuf_is_misconfigured(i915))
+               return;
+
+       drm_dbg_kms(&i915->drm, "BIOS has misprogrammed the DBUF, disabling all planes\n");
+
+       for_each_intel_crtc(&i915->drm, crtc) {
+               struct intel_plane *plane = to_intel_plane(crtc->base.primary);
+               const struct intel_plane_state *plane_state =
+                       to_intel_plane_state(plane->base.state);
+               struct intel_crtc_state *crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+
+               if (plane_state->uapi.visible)
+                       intel_plane_disable_noatomic(crtc, plane);
+
+               drm_WARN_ON(&i915->drm, crtc_state->active_planes != 0);
+
+               memset(&crtc_state->wm.skl.ddb, 0, sizeof(crtc_state->wm.skl.ddb));
+       }
+}
+
 static void ilk_pipe_wm_get_hw_state(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
index 990cdca..d224365 100644 (file)
@@ -47,6 +47,7 @@ void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc,
                              struct skl_pipe_wm *out);
 void g4x_wm_sanitize(struct drm_i915_private *dev_priv);
 void vlv_wm_sanitize(struct drm_i915_private *dev_priv);
+void skl_wm_sanitize(struct drm_i915_private *dev_priv);
 bool intel_can_enable_sagv(struct drm_i915_private *dev_priv,
                           const struct intel_bw_state *bw_state);
 void intel_sagv_pre_plane_update(struct intel_atomic_state *state);
index 53f1ccb..64c2708 100644 (file)
@@ -68,9 +68,7 @@ static noinline depot_stack_handle_t __save_depot_stack(void)
 static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm)
 {
        spin_lock_init(&rpm->debug.lock);
-
-       if (rpm->available)
-               stack_depot_init();
+       stack_depot_init();
 }
 
 static noinline depot_stack_handle_t
index fc25ebf..778da31 100644 (file)
@@ -724,7 +724,8 @@ void intel_uncore_forcewake_get__locked(struct intel_uncore *uncore,
 }
 
 static void __intel_uncore_forcewake_put(struct intel_uncore *uncore,
-                                        enum forcewake_domains fw_domains)
+                                        enum forcewake_domains fw_domains,
+                                        bool delayed)
 {
        struct intel_uncore_forcewake_domain *domain;
        unsigned int tmp;
@@ -739,7 +740,11 @@ static void __intel_uncore_forcewake_put(struct intel_uncore *uncore,
                        continue;
                }
 
-               fw_domains_put(uncore, domain->mask);
+               if (delayed &&
+                   !(domain->uncore->fw_domains_timer & domain->mask))
+                       fw_domain_arm_timer(domain);
+               else
+                       fw_domains_put(uncore, domain->mask);
        }
 }
 
@@ -760,7 +765,20 @@ void intel_uncore_forcewake_put(struct intel_uncore *uncore,
                return;
 
        spin_lock_irqsave(&uncore->lock, irqflags);
-       __intel_uncore_forcewake_put(uncore, fw_domains);
+       __intel_uncore_forcewake_put(uncore, fw_domains, false);
+       spin_unlock_irqrestore(&uncore->lock, irqflags);
+}
+
+void intel_uncore_forcewake_put_delayed(struct intel_uncore *uncore,
+                                       enum forcewake_domains fw_domains)
+{
+       unsigned long irqflags;
+
+       if (!uncore->fw_get_funcs)
+               return;
+
+       spin_lock_irqsave(&uncore->lock, irqflags);
+       __intel_uncore_forcewake_put(uncore, fw_domains, true);
        spin_unlock_irqrestore(&uncore->lock, irqflags);
 }
 
@@ -802,7 +820,7 @@ void intel_uncore_forcewake_put__locked(struct intel_uncore *uncore,
        if (!uncore->fw_get_funcs)
                return;
 
-       __intel_uncore_forcewake_put(uncore, fw_domains);
+       __intel_uncore_forcewake_put(uncore, fw_domains, false);
 }
 
 void assert_forcewakes_inactive(struct intel_uncore *uncore)
index 210fe2a..2a15b2b 100644 (file)
@@ -246,6 +246,8 @@ void intel_uncore_forcewake_get(struct intel_uncore *uncore,
                                enum forcewake_domains domains);
 void intel_uncore_forcewake_put(struct intel_uncore *uncore,
                                enum forcewake_domains domains);
+void intel_uncore_forcewake_put_delayed(struct intel_uncore *uncore,
+                                       enum forcewake_domains domains);
 void intel_uncore_forcewake_flush(struct intel_uncore *uncore,
                                  enum forcewake_domains fw_domains);
 
index 00404ba..2735b8e 100644 (file)
@@ -158,12 +158,6 @@ static void kmb_plane_atomic_disable(struct drm_plane *plane,
        case LAYER_1:
                kmb->plane_status[plane_id].ctrl = LCD_CTRL_VL2_ENABLE;
                break;
-       case LAYER_2:
-               kmb->plane_status[plane_id].ctrl = LCD_CTRL_GL1_ENABLE;
-               break;
-       case LAYER_3:
-               kmb->plane_status[plane_id].ctrl = LCD_CTRL_GL2_ENABLE;
-               break;
        }
 
        kmb->plane_status[plane_id].disable = true;
index 51b8377..17cfad6 100644 (file)
@@ -1560,6 +1560,8 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu)
                for (i = 0; i < gpu->nr_rings; i++)
                        a6xx_gpu->shadow[i] = 0;
 
+       gpu->suspend_count++;
+
        return 0;
 }
 
index 9300583..fb26193 100644 (file)
@@ -608,9 +608,27 @@ static int adreno_resume(struct device *dev)
        return gpu->funcs->pm_resume(gpu);
 }
 
+static int active_submits(struct msm_gpu *gpu)
+{
+       int active_submits;
+       mutex_lock(&gpu->active_lock);
+       active_submits = gpu->active_submits;
+       mutex_unlock(&gpu->active_lock);
+       return active_submits;
+}
+
 static int adreno_suspend(struct device *dev)
 {
        struct msm_gpu *gpu = dev_to_gpu(dev);
+       int remaining;
+
+       remaining = wait_event_timeout(gpu->retire_event,
+                                      active_submits(gpu) == 0,
+                                      msecs_to_jiffies(1000));
+       if (remaining == 0) {
+               dev_err(dev, "Timeout waiting for GPU to suspend\n");
+               return -EBUSY;
+       }
 
        return gpu->funcs->pm_suspend(gpu);
 }
index a98e964..355894a 100644 (file)
@@ -26,9 +26,16 @@ static void dpu_setup_dspp_pcc(struct dpu_hw_dspp *ctx,
                struct dpu_hw_pcc_cfg *cfg)
 {
 
-       u32 base = ctx->cap->sblk->pcc.base;
+       u32 base;
 
-       if (!ctx || !base) {
+       if (!ctx) {
+               DRM_ERROR("invalid ctx %pK\n", ctx);
+               return;
+       }
+
+       base = ctx->cap->sblk->pcc.base;
+
+       if (!base) {
                DRM_ERROR("invalid ctx %pK pcc base 0x%x\n", ctx, base);
                return;
        }
index 0525488..0fe0252 100644 (file)
@@ -40,7 +40,12 @@ static int dsi_get_phy(struct msm_dsi *msm_dsi)
 
        of_node_put(phy_node);
 
-       if (!phy_pdev || !msm_dsi->phy) {
+       if (!phy_pdev) {
+               DRM_DEV_ERROR(&pdev->dev, "%s: phy driver is not ready\n", __func__);
+               return -EPROBE_DEFER;
+       }
+       if (!msm_dsi->phy) {
+               put_device(&phy_pdev->dev);
                DRM_DEV_ERROR(&pdev->dev, "%s: phy driver is not ready\n", __func__);
                return -EPROBE_DEFER;
        }
index c2ed177..2027b38 100644 (file)
@@ -808,12 +808,14 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy,
                        struct msm_dsi_phy_clk_request *clk_req,
                        struct msm_dsi_phy_shared_timings *shared_timings)
 {
-       struct device *dev = &phy->pdev->dev;
+       struct device *dev;
        int ret;
 
        if (!phy || !phy->cfg->ops.enable)
                return -EINVAL;
 
+       dev = &phy->pdev->dev;
+
        ret = dsi_phy_enable_resource(phy);
        if (ret) {
                DRM_DEV_ERROR(dev, "%s: resource enable failed, %d\n",
index 3acdeae..7197207 100644 (file)
@@ -97,10 +97,15 @@ static int msm_hdmi_get_phy(struct hdmi *hdmi)
 
        of_node_put(phy_node);
 
-       if (!phy_pdev || !hdmi->phy) {
+       if (!phy_pdev) {
                DRM_DEV_ERROR(&pdev->dev, "phy driver is not ready\n");
                return -EPROBE_DEFER;
        }
+       if (!hdmi->phy) {
+               DRM_DEV_ERROR(&pdev->dev, "phy driver is not ready\n");
+               put_device(&phy_pdev->dev);
+               return -EPROBE_DEFER;
+       }
 
        hdmi->phy_dev = get_device(&phy_pdev->dev);
 
index ad35a5d..555666e 100644 (file)
@@ -461,7 +461,7 @@ static int msm_init_vram(struct drm_device *dev)
                of_node_put(node);
                if (ret)
                        return ret;
-               size = r.end - r.start;
+               size = r.end - r.start + 1;
                DRM_INFO("using VRAM carveout: %lx@%pa\n", size, &r.start);
 
                /* if we have no IOMMU, then we need to use carveout allocator.
@@ -510,7 +510,6 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv)
        struct msm_drm_private *priv = dev_get_drvdata(dev);
        struct drm_device *ddev;
        struct msm_kms *kms;
-       struct msm_mdss *mdss;
        int ret, i;
 
        ddev = drm_dev_alloc(drv, dev);
@@ -521,8 +520,6 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv)
        ddev->dev_private = priv;
        priv->dev = ddev;
 
-       mdss = priv->mdss;
-
        priv->wq = alloc_ordered_workqueue("msm", 0);
        priv->hangcheck_period = DRM_MSM_HANGCHECK_DEFAULT_PERIOD;
 
index 0f78c26..2c1049c 100644 (file)
@@ -703,6 +703,8 @@ static void retire_submits(struct msm_gpu *gpu)
                        }
                }
        }
+
+       wake_up_all(&gpu->retire_event);
 }
 
 static void retire_worker(struct kthread_work *work)
@@ -848,6 +850,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
        INIT_LIST_HEAD(&gpu->active_list);
        mutex_init(&gpu->active_lock);
        mutex_init(&gpu->lock);
+       init_waitqueue_head(&gpu->retire_event);
        kthread_init_work(&gpu->retire_work, retire_worker);
        kthread_init_work(&gpu->recover_work, recover_worker);
        kthread_init_work(&gpu->fault_work, fault_worker);
index 445c6bf..92aa1e9 100644 (file)
@@ -230,6 +230,9 @@ struct msm_gpu {
        /* work for handling GPU recovery: */
        struct kthread_work recover_work;
 
+       /** retire_event: notified when submits are retired: */
+       wait_queue_head_t retire_event;
+
        /* work for handling active-list retiring: */
        struct kthread_work retire_work;
 
index 62405e9..9bf319b 100644 (file)
@@ -133,6 +133,18 @@ void msm_devfreq_init(struct msm_gpu *gpu)
                              CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 }
 
+static void cancel_idle_work(struct msm_gpu_devfreq *df)
+{
+       hrtimer_cancel(&df->idle_work.timer);
+       kthread_cancel_work_sync(&df->idle_work.work);
+}
+
+static void cancel_boost_work(struct msm_gpu_devfreq *df)
+{
+       hrtimer_cancel(&df->boost_work.timer);
+       kthread_cancel_work_sync(&df->boost_work.work);
+}
+
 void msm_devfreq_cleanup(struct msm_gpu *gpu)
 {
        struct msm_gpu_devfreq *df = &gpu->devfreq;
@@ -152,7 +164,12 @@ void msm_devfreq_resume(struct msm_gpu *gpu)
 
 void msm_devfreq_suspend(struct msm_gpu *gpu)
 {
-       devfreq_suspend_device(gpu->devfreq.devfreq);
+       struct msm_gpu_devfreq *df = &gpu->devfreq;
+
+       devfreq_suspend_device(df->devfreq);
+
+       cancel_idle_work(df);
+       cancel_boost_work(df);
 }
 
 static void msm_devfreq_boost_work(struct kthread_work *work)
@@ -196,7 +213,7 @@ void msm_devfreq_active(struct msm_gpu *gpu)
        /*
         * Cancel any pending transition to idle frequency:
         */
-       hrtimer_cancel(&df->idle_work.timer);
+       cancel_idle_work(df);
 
        idle_time = ktime_to_ms(ktime_sub(ktime_get(), df->idle_time));
 
index 0655582..4cfb6c0 100644 (file)
@@ -361,7 +361,11 @@ static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc,
                bridge_state =
                        drm_atomic_get_new_bridge_state(state,
                                                        mxsfb->bridge);
-               bus_format = bridge_state->input_bus_cfg.format;
+               if (!bridge_state)
+                       bus_format = MEDIA_BUS_FMT_FIXED;
+               else
+                       bus_format = bridge_state->input_bus_cfg.format;
+
                if (bus_format == MEDIA_BUS_FMT_FIXED) {
                        dev_warn_once(drm->dev,
                                      "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n"
index d0f52d5..64e423d 100644 (file)
@@ -38,7 +38,7 @@ nvbios_addr(struct nvkm_bios *bios, u32 *addr, u8 size)
                *addr += bios->imaged_addr;
        }
 
-       if (unlikely(*addr + size >= bios->size)) {
+       if (unlikely(*addr + size > bios->size)) {
                nvkm_error(&bios->subdev, "OOB %d %08x %08x\n", size, p, *addr);
                return false;
        }
index 9e46db5..3c08f98 100644 (file)
@@ -588,6 +588,7 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
                err = panel_dpi_probe(dev, panel);
                if (err)
                        goto free_ddc;
+               desc = panel->desc;
        } else {
                if (!of_get_display_timing(dev->of_node, "panel-timing", &dt))
                        panel_simple_parse_panel_timing_node(dev, panel, &dt);
index 830bdd5..8677c82 100644 (file)
@@ -529,13 +529,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
                return ret;
        }
 
-       ret = clk_prepare_enable(hdmi->vpll_clk);
-       if (ret) {
-               DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
-                             ret);
-               return ret;
-       }
-
        hdmi->phy = devm_phy_optional_get(dev, "hdmi");
        if (IS_ERR(hdmi->phy)) {
                ret = PTR_ERR(hdmi->phy);
@@ -544,6 +537,13 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
                return ret;
        }
 
+       ret = clk_prepare_enable(hdmi->vpll_clk);
+       if (ret) {
+               DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
+                             ret);
+               return ret;
+       }
+
        drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
        drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
 
index 1f7353f..798b542 100644 (file)
@@ -902,6 +902,7 @@ static const struct vop_win_phy rk3399_win01_data = {
        .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
        .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
        .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
+       .x_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 21),
        .y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22),
        .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
        .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
@@ -912,6 +913,7 @@ static const struct vop_win_phy rk3399_win01_data = {
        .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
        .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
        .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
+       .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0),
 };
 
 /*
@@ -922,11 +924,11 @@ static const struct vop_win_phy rk3399_win01_data = {
 static const struct vop_win_data rk3399_vop_win_data[] = {
        { .base = 0x00, .phy = &rk3399_win01_data,
          .type = DRM_PLANE_TYPE_PRIMARY },
-       { .base = 0x40, .phy = &rk3288_win01_data,
+       { .base = 0x40, .phy = &rk3368_win01_data,
          .type = DRM_PLANE_TYPE_OVERLAY },
-       { .base = 0x00, .phy = &rk3288_win23_data,
+       { .base = 0x00, .phy = &rk3368_win23_data,
          .type = DRM_PLANE_TYPE_OVERLAY },
-       { .base = 0x50, .phy = &rk3288_win23_data,
+       { .base = 0x50, .phy = &rk3368_win23_data,
          .type = DRM_PLANE_TYPE_CURSOR },
 };
 
index 287dbc8..e6cc474 100644 (file)
@@ -671,7 +671,6 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
                const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
                struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
 
-               mode = &crtc_state->adjusted_mode;
                if (vc4_encoder->type == VC4_ENCODER_TYPE_HDMI0) {
                        vc4_state->hvs_load = max(mode->clock * mode->hdisplay / mode->htotal + 1000,
                                                  mode->clock * 9 / 10) * 1000;
index a229da5..9300d33 100644 (file)
@@ -1262,7 +1262,6 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
                               struct mipi_dsi_device *device)
 {
        struct vc4_dsi *dsi = host_to_dsi(host);
-       int ret;
 
        dsi->lanes = device->lanes;
        dsi->channel = device->channel;
@@ -1297,18 +1296,15 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
                return 0;
        }
 
-       ret = component_add(&dsi->pdev->dev, &vc4_dsi_ops);
-       if (ret) {
-               mipi_dsi_host_unregister(&dsi->dsi_host);
-               return ret;
-       }
-
-       return 0;
+       return component_add(&dsi->pdev->dev, &vc4_dsi_ops);
 }
 
 static int vc4_dsi_host_detach(struct mipi_dsi_host *host,
                               struct mipi_dsi_device *device)
 {
+       struct vc4_dsi *dsi = host_to_dsi(host);
+
+       component_del(&dsi->pdev->dev, &vc4_dsi_ops);
        return 0;
 }
 
@@ -1686,9 +1682,7 @@ static int vc4_dsi_dev_remove(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct vc4_dsi *dsi = dev_get_drvdata(dev);
 
-       component_del(&pdev->dev, &vc4_dsi_ops);
        mipi_dsi_host_unregister(&dsi->dsi_host);
-
        return 0;
 }
 
index 053fbaf..b305004 100644 (file)
@@ -196,14 +196,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
                if (gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio))
                        connected = true;
        } else {
-               unsigned long flags;
-               u32 hotplug;
-
-               spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
-               hotplug = HDMI_READ(HDMI_HOTPLUG);
-               spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
-
-               if (hotplug & VC4_HDMI_HOTPLUG_CONNECTED)
+               if (vc4_hdmi->variant->hp_detect &&
+                   vc4_hdmi->variant->hp_detect(vc4_hdmi))
                        connected = true;
        }
 
@@ -1251,6 +1245,7 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
        unsigned long long tmds_rate;
 
        if (vc4_hdmi->variant->unsupported_odd_h_timings &&
+           !(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
            ((mode->hdisplay % 2) || (mode->hsync_start % 2) ||
             (mode->hsync_end % 2) || (mode->htotal % 2)))
                return -EINVAL;
@@ -1298,6 +1293,7 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder,
        struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
 
        if (vc4_hdmi->variant->unsupported_odd_h_timings &&
+           !(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
            ((mode->hdisplay % 2) || (mode->hsync_start % 2) ||
             (mode->hsync_end % 2) || (mode->htotal % 2)))
                return MODE_H_ILLEGAL;
@@ -1343,6 +1339,18 @@ static u32 vc5_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask)
        return channel_map;
 }
 
+static bool vc5_hdmi_hp_detect(struct vc4_hdmi *vc4_hdmi)
+{
+       unsigned long flags;
+       u32 hotplug;
+
+       spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
+       hotplug = HDMI_READ(HDMI_HOTPLUG);
+       spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
+
+       return !!(hotplug & VC4_HDMI_HOTPLUG_CONNECTED);
+}
+
 /* HDMI audio codec callbacks */
 static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi,
                                         unsigned int samplerate)
@@ -2504,7 +2512,8 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
         * vc4_hdmi_disable_scrambling() will thus run at boot, make
         * sure it's disabled, and avoid any inconsistency.
         */
-       vc4_hdmi->scdc_enabled = true;
+       if (variant->max_pixel_clock > HDMI_14_MAX_TMDS_CLK)
+               vc4_hdmi->scdc_enabled = true;
 
        ret = variant->init_resources(vc4_hdmi);
        if (ret)
@@ -2723,6 +2732,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
        .phy_rng_disable        = vc5_hdmi_phy_rng_disable,
        .channel_map            = vc5_hdmi_channel_map,
        .supports_hdr           = true,
+       .hp_detect              = vc5_hdmi_hp_detect,
 };
 
 static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
@@ -2751,6 +2761,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
        .phy_rng_disable        = vc5_hdmi_phy_rng_disable,
        .channel_map            = vc5_hdmi_channel_map,
        .supports_hdr           = true,
+       .hp_detect              = vc5_hdmi_hp_detect,
 };
 
 static const struct of_device_id vc4_hdmi_dt_match[] = {
index 36c0b08..31b77a9 100644 (file)
@@ -102,6 +102,9 @@ struct vc4_hdmi_variant {
 
        /* Enables HDR metadata */
        bool supports_hdr;
+
+       /* Callback for hardware specific hotplug detect */
+       bool (*hp_detect)(struct vc4_hdmi *vc4_hdmi);
 };
 
 /* HDMI audio information */
index d6b6663..ea3ecdd 100644 (file)
@@ -1140,15 +1140,14 @@ extern int vmw_execbuf_fence_commands(struct drm_file *file_priv,
                                      struct vmw_private *dev_priv,
                                      struct vmw_fence_obj **p_fence,
                                      uint32_t *p_handle);
-extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
+extern int vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
                                        struct vmw_fpriv *vmw_fp,
                                        int ret,
                                        struct drm_vmw_fence_rep __user
                                        *user_fence_rep,
                                        struct vmw_fence_obj *fence,
                                        uint32_t fence_handle,
-                                       int32_t out_fence_fd,
-                                       struct sync_file *sync_file);
+                                       int32_t out_fence_fd);
 bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd);
 
 /**
index 44ca23b..dd2ff44 100644 (file)
@@ -3879,17 +3879,17 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv,
  * Also if copying fails, user-space will be unable to signal the fence object
  * so we wait for it immediately, and then unreference the user-space reference.
  */
-void
+int
 vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
                            struct vmw_fpriv *vmw_fp, int ret,
                            struct drm_vmw_fence_rep __user *user_fence_rep,
                            struct vmw_fence_obj *fence, uint32_t fence_handle,
-                           int32_t out_fence_fd, struct sync_file *sync_file)
+                           int32_t out_fence_fd)
 {
        struct drm_vmw_fence_rep fence_rep;
 
        if (user_fence_rep == NULL)
-               return;
+               return 0;
 
        memset(&fence_rep, 0, sizeof(fence_rep));
 
@@ -3917,19 +3917,13 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
         * handle.
         */
        if (unlikely(ret != 0) && (fence_rep.error == 0)) {
-               if (sync_file)
-                       fput(sync_file->file);
-
-               if (fence_rep.fd != -1) {
-                       put_unused_fd(fence_rep.fd);
-                       fence_rep.fd = -1;
-               }
-
                ttm_ref_object_base_unref(vmw_fp->tfile, fence_handle);
                VMW_DEBUG_USER("Fence copy error. Syncing.\n");
                (void) vmw_fence_obj_wait(fence, false, false,
                                          VMW_FENCE_WAIT_TIMEOUT);
        }
+
+       return ret ? -EFAULT : 0;
 }
 
 /**
@@ -4266,16 +4260,23 @@ int vmw_execbuf_process(struct drm_file *file_priv,
 
                        (void) vmw_fence_obj_wait(fence, false, false,
                                                  VMW_FENCE_WAIT_TIMEOUT);
+               }
+       }
+
+       ret = vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
+                                   user_fence_rep, fence, handle, out_fence_fd);
+
+       if (sync_file) {
+               if (ret) {
+                       /* usercopy of fence failed, put the file object */
+                       fput(sync_file->file);
+                       put_unused_fd(out_fence_fd);
                } else {
                        /* Link the fence with the FD created earlier */
                        fd_install(out_fence_fd, sync_file->file);
                }
        }
 
-       vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
-                                   user_fence_rep, fence, handle, out_fence_fd,
-                                   sync_file);
-
        /* Don't unreference when handing fence out */
        if (unlikely(out_fence != NULL)) {
                *out_fence = fence;
@@ -4293,7 +4294,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
         */
        vmw_validation_unref_lists(&val_ctx);
 
-       return 0;
+       return ret;
 
 out_unlock_binding:
        mutex_unlock(&dev_priv->binding_mutex);
index c60d395..5001b87 100644 (file)
@@ -1128,7 +1128,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
        }
 
        vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
-                                   handle, -1, NULL);
+                                   handle, -1);
        vmw_fence_obj_unreference(&fence);
        return 0;
 out_no_create:
index 4e693e8..bbd2f4e 100644 (file)
@@ -2501,7 +2501,7 @@ void vmw_kms_helper_validation_finish(struct vmw_private *dev_priv,
        if (file_priv)
                vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv),
                                            ret, user_fence_rep, fence,
-                                           handle, -1, NULL);
+                                           handle, -1);
        if (out_fence)
                *out_fence = fence;
        else
index ca873a3..f2d05bf 100644 (file)
@@ -1660,6 +1660,13 @@ static int balloon_connect_vsp(struct hv_device *dev)
        unsigned long t;
        int ret;
 
+       /*
+        * max_pkt_size should be large enough for one vmbus packet header plus
+        * our receive buffer size. Hyper-V sends messages up to
+        * HV_HYP_PAGE_SIZE bytes long on balloon channel.
+        */
+       dev->channel->max_pkt_size = HV_HYP_PAGE_SIZE * 2;
+
        ret = vmbus_open(dev->channel, dm_ring_size, dm_ring_size, NULL, 0,
                         balloon_onchannelcallback, dev);
        if (ret)
index d519aca..fb6d14d 100644 (file)
@@ -662,6 +662,9 @@ static int adt7470_fan_write(struct device *dev, u32 attr, int channel, long val
        struct adt7470_data *data = dev_get_drvdata(dev);
        int err;
 
+       if (val <= 0)
+               return -EINVAL;
+
        val = FAN_RPM_TO_PERIOD(val);
        val = clamp_val(val, 1, 65534);
 
index 74019df..1c9493c 100644 (file)
@@ -373,7 +373,7 @@ static const struct lm90_params lm90_params[] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
                  | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT,
                .alert_alarms = 0x7c,
-               .max_convrate = 8,
+               .max_convrate = 7,
        },
        [lm86] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
@@ -394,12 +394,13 @@ static const struct lm90_params lm90_params[] = {
                .max_convrate = 9,
        },
        [max6646] = {
-               .flags = LM90_HAVE_CRIT,
+               .flags = LM90_HAVE_CRIT | LM90_HAVE_BROKEN_ALERT,
                .alert_alarms = 0x7c,
                .max_convrate = 6,
                .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [max6654] = {
+               .flags = LM90_HAVE_BROKEN_ALERT,
                .alert_alarms = 0x7c,
                .max_convrate = 7,
                .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
@@ -418,7 +419,7 @@ static const struct lm90_params lm90_params[] = {
        },
        [max6680] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_CRIT
-                 | LM90_HAVE_CRIT_ALRM_SWP,
+                 | LM90_HAVE_CRIT_ALRM_SWP | LM90_HAVE_BROKEN_ALERT,
                .alert_alarms = 0x7c,
                .max_convrate = 7,
        },
@@ -848,7 +849,7 @@ static int lm90_update_device(struct device *dev)
                 * Re-enable ALERT# output if it was originally enabled and
                 * relevant alarms are all clear
                 */
-               if (!(data->config_orig & 0x80) &&
+               if ((client->irq || !(data->config_orig & 0x80)) &&
                    !(data->alarms & data->alert_alarms)) {
                        if (data->config & 0x80) {
                                dev_dbg(&client->dev, "Re-enabling ALERT#\n");
@@ -1807,22 +1808,22 @@ static bool lm90_is_tripped(struct i2c_client *client, u16 *status)
 
        if (st & LM90_STATUS_LLOW)
                hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_min, 0);
+                                  hwmon_temp_min_alarm, 0);
        if (st & LM90_STATUS_RLOW)
                hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_min, 1);
+                                  hwmon_temp_min_alarm, 1);
        if (st2 & MAX6696_STATUS2_R2LOW)
                hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_min, 2);
+                                  hwmon_temp_min_alarm, 2);
        if (st & LM90_STATUS_LHIGH)
                hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_max, 0);
+                                  hwmon_temp_max_alarm, 0);
        if (st & LM90_STATUS_RHIGH)
                hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_max, 1);
+                                  hwmon_temp_max_alarm, 1);
        if (st2 & MAX6696_STATUS2_R2HIGH)
                hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_max, 2);
+                                  hwmon_temp_max_alarm, 2);
 
        return true;
 }
index fd3f91c..098d12b 100644 (file)
@@ -1175,7 +1175,7 @@ static inline u8 in_to_reg(u32 val, u8 nr)
 
 struct nct6775_data {
        int addr;       /* IO base of hw monitor block */
-       int sioreg;     /* SIO register address */
+       struct nct6775_sio_data *sio_data;
        enum kinds kind;
        const char *name;
 
@@ -3559,7 +3559,7 @@ clear_caseopen(struct device *dev, struct device_attribute *attr,
               const char *buf, size_t count)
 {
        struct nct6775_data *data = dev_get_drvdata(dev);
-       struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
+       struct nct6775_sio_data *sio_data = data->sio_data;
        int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
        unsigned long val;
        u8 reg;
@@ -3967,7 +3967,7 @@ static int nct6775_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        data->kind = sio_data->kind;
-       data->sioreg = sio_data->sioreg;
+       data->sio_data = sio_data;
 
        if (sio_data->access == access_direct) {
                data->addr = res->start;
index 0ea7e1c..09276e3 100644 (file)
@@ -62,7 +62,7 @@ static const struct i2c_device_id ir38064_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, ir38064_id);
 
-static const struct of_device_id ir38064_of_match[] = {
+static const struct of_device_id __maybe_unused ir38064_of_match[] = {
        { .compatible = "infineon,ir38060" },
        { .compatible = "infineon,ir38064" },
        { .compatible = "infineon,ir38164" },
index 94eb9f6..208b519 100644 (file)
@@ -1569,9 +1569,17 @@ static long iio_device_buffer_getfd(struct iio_dev *indio_dev, unsigned long arg
        }
 
        if (copy_to_user(ival, &fd, sizeof(fd))) {
-               put_unused_fd(fd);
-               ret = -EFAULT;
-               goto error_free_ib;
+               /*
+                * "Leak" the fd, as there's not much we can do about this
+                * anyway. 'fd' might have been closed already, as
+                * anon_inode_getfd() called fd_install() on it, which made
+                * it reachable by userland.
+                *
+                * Instead of allowing a malicious user to play tricks with
+                * us, rely on the process exit path to do any necessary
+                * cleanup, as in releasing the file, if still needed.
+                */
+               return -EFAULT;
        }
 
        return 0;
index c903b74..35f0d5e 100644 (file)
@@ -3322,7 +3322,7 @@ static int cm_lap_handler(struct cm_work *work)
        ret = cm_init_av_by_path(param->alternate_path, NULL, &alt_av);
        if (ret) {
                rdma_destroy_ah_attr(&ah_attr);
-               return -EINVAL;
+               goto deref;
        }
 
        spin_lock_irq(&cm_id_priv->lock);
index 27a00ce..c447526 100644 (file)
@@ -67,8 +67,8 @@ static const char * const cma_events[] = {
        [RDMA_CM_EVENT_TIMEWAIT_EXIT]    = "timewait exit",
 };
 
-static void cma_set_mgid(struct rdma_id_private *id_priv, struct sockaddr *addr,
-                        union ib_gid *mgid);
+static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid,
+                             enum ib_gid_type gid_type);
 
 const char *__attribute_const__ rdma_event_msg(enum rdma_cm_event_type event)
 {
@@ -1846,17 +1846,19 @@ static void destroy_mc(struct rdma_id_private *id_priv,
                if (dev_addr->bound_dev_if)
                        ndev = dev_get_by_index(dev_addr->net,
                                                dev_addr->bound_dev_if);
-               if (ndev) {
+               if (ndev && !send_only) {
+                       enum ib_gid_type gid_type;
                        union ib_gid mgid;
 
-                       cma_set_mgid(id_priv, (struct sockaddr *)&mc->addr,
-                                    &mgid);
-
-                       if (!send_only)
-                               cma_igmp_send(ndev, &mgid, false);
-
-                       dev_put(ndev);
+                       gid_type = id_priv->cma_dev->default_gid_type
+                                          [id_priv->id.port_num -
+                                           rdma_start_port(
+                                                   id_priv->cma_dev->device)];
+                       cma_iboe_set_mgid((struct sockaddr *)&mc->addr, &mgid,
+                                         gid_type);
+                       cma_igmp_send(ndev, &mgid, false);
                }
+               dev_put(ndev);
 
                cancel_work_sync(&mc->iboe_join.work);
        }
index 2b72c4f..9d6ac9d 100644 (file)
@@ -95,6 +95,7 @@ struct ucma_context {
        u64                     uid;
 
        struct list_head        list;
+       struct list_head        mc_list;
        struct work_struct      close_work;
 };
 
@@ -105,6 +106,7 @@ struct ucma_multicast {
 
        u64                     uid;
        u8                      join_state;
+       struct list_head        list;
        struct sockaddr_storage addr;
 };
 
@@ -198,6 +200,7 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file)
 
        INIT_WORK(&ctx->close_work, ucma_close_id);
        init_completion(&ctx->comp);
+       INIT_LIST_HEAD(&ctx->mc_list);
        /* So list_del() will work if we don't do ucma_finish_ctx() */
        INIT_LIST_HEAD(&ctx->list);
        ctx->file = file;
@@ -484,19 +487,19 @@ err1:
 
 static void ucma_cleanup_multicast(struct ucma_context *ctx)
 {
-       struct ucma_multicast *mc;
-       unsigned long index;
+       struct ucma_multicast *mc, *tmp;
 
-       xa_for_each(&multicast_table, index, mc) {
-               if (mc->ctx != ctx)
-                       continue;
+       xa_lock(&multicast_table);
+       list_for_each_entry_safe(mc, tmp, &ctx->mc_list, list) {
+               list_del(&mc->list);
                /*
                 * At this point mc->ctx->ref is 0 so the mc cannot leave the
                 * lock on the reader and this is enough serialization
                 */
-               xa_erase(&multicast_table, index);
+               __xa_erase(&multicast_table, mc->id);
                kfree(mc);
        }
+       xa_unlock(&multicast_table);
 }
 
 static void ucma_cleanup_mc_events(struct ucma_multicast *mc)
@@ -1469,12 +1472,16 @@ static ssize_t ucma_process_join(struct ucma_file *file,
        mc->uid = cmd->uid;
        memcpy(&mc->addr, addr, cmd->addr_size);
 
-       if (xa_alloc(&multicast_table, &mc->id, NULL, xa_limit_32b,
+       xa_lock(&multicast_table);
+       if (__xa_alloc(&multicast_table, &mc->id, NULL, xa_limit_32b,
                     GFP_KERNEL)) {
                ret = -ENOMEM;
                goto err_free_mc;
        }
 
+       list_add_tail(&mc->list, &ctx->mc_list);
+       xa_unlock(&multicast_table);
+
        mutex_lock(&ctx->mutex);
        ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *)&mc->addr,
                                  join_state, mc);
@@ -1500,8 +1507,11 @@ err_leave_multicast:
        mutex_unlock(&ctx->mutex);
        ucma_cleanup_mc_events(mc);
 err_xa_erase:
-       xa_erase(&multicast_table, mc->id);
+       xa_lock(&multicast_table);
+       list_del(&mc->list);
+       __xa_erase(&multicast_table, mc->id);
 err_free_mc:
+       xa_unlock(&multicast_table);
        kfree(mc);
 err_put_ctx:
        ucma_put_ctx(ctx);
@@ -1569,15 +1579,17 @@ static ssize_t ucma_leave_multicast(struct ucma_file *file,
                mc = ERR_PTR(-EINVAL);
        else if (!refcount_inc_not_zero(&mc->ctx->ref))
                mc = ERR_PTR(-ENXIO);
-       else
-               __xa_erase(&multicast_table, mc->id);
-       xa_unlock(&multicast_table);
 
        if (IS_ERR(mc)) {
+               xa_unlock(&multicast_table);
                ret = PTR_ERR(mc);
                goto out;
        }
 
+       list_del(&mc->list);
+       __xa_erase(&multicast_table, mc->id);
+       xa_unlock(&multicast_table);
+
        mutex_lock(&mc->ctx->mutex);
        rdma_leave_multicast(mc->ctx->cm_id, (struct sockaddr *) &mc->addr);
        mutex_unlock(&mc->ctx->mutex);
index 9091229..aec60d4 100644 (file)
@@ -55,7 +55,7 @@ union hfi1_ipoib_flow {
  */
 struct ipoib_txreq {
        struct sdma_txreq           txreq;
-       struct hfi1_sdma_header     sdma_hdr;
+       struct hfi1_sdma_header     *sdma_hdr;
        int                         sdma_status;
        int                         complete;
        struct hfi1_ipoib_dev_priv *priv;
index e1a2b02..5d814af 100644 (file)
@@ -22,26 +22,35 @@ static int hfi1_ipoib_dev_init(struct net_device *dev)
        int ret;
 
        dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+       if (!dev->tstats)
+               return -ENOMEM;
 
        ret = priv->netdev_ops->ndo_init(dev);
        if (ret)
-               return ret;
+               goto out_ret;
 
        ret = hfi1_netdev_add_data(priv->dd,
                                   qpn_from_mac(priv->netdev->dev_addr),
                                   dev);
        if (ret < 0) {
                priv->netdev_ops->ndo_uninit(dev);
-               return ret;
+               goto out_ret;
        }
 
        return 0;
+out_ret:
+       free_percpu(dev->tstats);
+       dev->tstats = NULL;
+       return ret;
 }
 
 static void hfi1_ipoib_dev_uninit(struct net_device *dev)
 {
        struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
 
+       free_percpu(dev->tstats);
+       dev->tstats = NULL;
+
        hfi1_netdev_remove_data(priv->dd, qpn_from_mac(priv->netdev->dev_addr));
 
        priv->netdev_ops->ndo_uninit(dev);
@@ -166,12 +175,7 @@ static void hfi1_ipoib_netdev_dtor(struct net_device *dev)
        hfi1_ipoib_rxq_deinit(priv->netdev);
 
        free_percpu(dev->tstats);
-}
-
-static void hfi1_ipoib_free_rdma_netdev(struct net_device *dev)
-{
-       hfi1_ipoib_netdev_dtor(dev);
-       free_netdev(dev);
+       dev->tstats = NULL;
 }
 
 static void hfi1_ipoib_set_id(struct net_device *dev, int id)
@@ -211,24 +215,23 @@ static int hfi1_ipoib_setup_rn(struct ib_device *device,
        priv->port_num = port_num;
        priv->netdev_ops = netdev->netdev_ops;
 
-       netdev->netdev_ops = &hfi1_ipoib_netdev_ops;
-
        ib_query_pkey(device, port_num, priv->pkey_index, &priv->pkey);
 
        rc = hfi1_ipoib_txreq_init(priv);
        if (rc) {
                dd_dev_err(dd, "IPoIB netdev TX init - failed(%d)\n", rc);
-               hfi1_ipoib_free_rdma_netdev(netdev);
                return rc;
        }
 
        rc = hfi1_ipoib_rxq_init(netdev);
        if (rc) {
                dd_dev_err(dd, "IPoIB netdev RX init - failed(%d)\n", rc);
-               hfi1_ipoib_free_rdma_netdev(netdev);
+               hfi1_ipoib_txreq_deinit(priv);
                return rc;
        }
 
+       netdev->netdev_ops = &hfi1_ipoib_netdev_ops;
+
        netdev->priv_destructor = hfi1_ipoib_netdev_dtor;
        netdev->needs_free_netdev = true;
 
index f401089..d6bbdb8 100644 (file)
@@ -122,7 +122,7 @@ static void hfi1_ipoib_free_tx(struct ipoib_txreq *tx, int budget)
                dd_dev_warn(priv->dd,
                            "%s: Status = 0x%x pbc 0x%llx txq = %d sde = %d\n",
                            __func__, tx->sdma_status,
-                           le64_to_cpu(tx->sdma_hdr.pbc), tx->txq->q_idx,
+                           le64_to_cpu(tx->sdma_hdr->pbc), tx->txq->q_idx,
                            tx->txq->sde->this_idx);
        }
 
@@ -231,7 +231,7 @@ static int hfi1_ipoib_build_tx_desc(struct ipoib_txreq *tx,
 {
        struct hfi1_devdata *dd = txp->dd;
        struct sdma_txreq *txreq = &tx->txreq;
-       struct hfi1_sdma_header *sdma_hdr = &tx->sdma_hdr;
+       struct hfi1_sdma_header *sdma_hdr = tx->sdma_hdr;
        u16 pkt_bytes =
                sizeof(sdma_hdr->pbc) + (txp->hdr_dwords << 2) + tx->skb->len;
        int ret;
@@ -256,7 +256,7 @@ static void hfi1_ipoib_build_ib_tx_headers(struct ipoib_txreq *tx,
                                           struct ipoib_txparms *txp)
 {
        struct hfi1_ipoib_dev_priv *priv = tx->txq->priv;
-       struct hfi1_sdma_header *sdma_hdr = &tx->sdma_hdr;
+       struct hfi1_sdma_header *sdma_hdr = tx->sdma_hdr;
        struct sk_buff *skb = tx->skb;
        struct hfi1_pportdata *ppd = ppd_from_ibp(txp->ibp);
        struct rdma_ah_attr *ah_attr = txp->ah_attr;
@@ -483,7 +483,7 @@ static int hfi1_ipoib_send_dma_single(struct net_device *dev,
        if (likely(!ret)) {
 tx_ok:
                trace_sdma_output_ibhdr(txq->priv->dd,
-                                       &tx->sdma_hdr.hdr,
+                                       &tx->sdma_hdr->hdr,
                                        ib_is_sc5(txp->flow.sc5));
                hfi1_ipoib_check_queue_depth(txq);
                return NETDEV_TX_OK;
@@ -547,7 +547,7 @@ static int hfi1_ipoib_send_dma_list(struct net_device *dev,
        hfi1_ipoib_check_queue_depth(txq);
 
        trace_sdma_output_ibhdr(txq->priv->dd,
-                               &tx->sdma_hdr.hdr,
+                               &tx->sdma_hdr->hdr,
                                ib_is_sc5(txp->flow.sc5));
 
        if (!netdev_xmit_more())
@@ -683,7 +683,8 @@ int hfi1_ipoib_txreq_init(struct hfi1_ipoib_dev_priv *priv)
 {
        struct net_device *dev = priv->netdev;
        u32 tx_ring_size, tx_item_size;
-       int i;
+       struct hfi1_ipoib_circ_buf *tx_ring;
+       int i, j;
 
        /*
         * Ring holds 1 less than tx_ring_size
@@ -701,7 +702,9 @@ int hfi1_ipoib_txreq_init(struct hfi1_ipoib_dev_priv *priv)
 
        for (i = 0; i < dev->num_tx_queues; i++) {
                struct hfi1_ipoib_txq *txq = &priv->txqs[i];
+               struct ipoib_txreq *tx;
 
+               tx_ring = &txq->tx_ring;
                iowait_init(&txq->wait,
                            0,
                            hfi1_ipoib_flush_txq,
@@ -725,14 +728,19 @@ int hfi1_ipoib_txreq_init(struct hfi1_ipoib_dev_priv *priv)
                                             priv->dd->node);
 
                txq->tx_ring.items =
-                       kcalloc_node(tx_ring_size, tx_item_size,
-                                    GFP_KERNEL, priv->dd->node);
+                       kvzalloc_node(array_size(tx_ring_size, tx_item_size),
+                                     GFP_KERNEL, priv->dd->node);
                if (!txq->tx_ring.items)
                        goto free_txqs;
 
                txq->tx_ring.max_items = tx_ring_size;
-               txq->tx_ring.shift = ilog2(tx_ring_size);
+               txq->tx_ring.shift = ilog2(tx_item_size);
                txq->tx_ring.avail = hfi1_ipoib_ring_hwat(txq);
+               tx_ring = &txq->tx_ring;
+               for (j = 0; j < tx_ring_size; j++)
+                       hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr =
+                               kzalloc_node(sizeof(*tx->sdma_hdr),
+                                            GFP_KERNEL, priv->dd->node);
 
                netif_tx_napi_add(dev, &txq->napi,
                                  hfi1_ipoib_poll_tx_ring,
@@ -746,7 +754,10 @@ free_txqs:
                struct hfi1_ipoib_txq *txq = &priv->txqs[i];
 
                netif_napi_del(&txq->napi);
-               kfree(txq->tx_ring.items);
+               tx_ring = &txq->tx_ring;
+               for (j = 0; j < tx_ring_size; j++)
+                       kfree(hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr);
+               kvfree(tx_ring->items);
        }
 
        kfree(priv->txqs);
@@ -780,17 +791,20 @@ static void hfi1_ipoib_drain_tx_list(struct hfi1_ipoib_txq *txq)
 
 void hfi1_ipoib_txreq_deinit(struct hfi1_ipoib_dev_priv *priv)
 {
-       int i;
+       int i, j;
 
        for (i = 0; i < priv->netdev->num_tx_queues; i++) {
                struct hfi1_ipoib_txq *txq = &priv->txqs[i];
+               struct hfi1_ipoib_circ_buf *tx_ring = &txq->tx_ring;
 
                iowait_cancel_work(&txq->wait);
                iowait_sdma_drain(&txq->wait);
                hfi1_ipoib_drain_tx_list(txq);
                netif_napi_del(&txq->napi);
                hfi1_ipoib_drain_tx_ring(txq);
-               kfree(txq->tx_ring.items);
+               for (j = 0; j < tx_ring->max_items; j++)
+                       kfree(hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr);
+               kvfree(tx_ring->items);
        }
 
        kfree(priv->txqs);
index 1c3d972..93b1650 100644 (file)
@@ -3237,7 +3237,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
        case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
                ew = kmalloc(sizeof *ew, GFP_ATOMIC);
                if (!ew)
-                       break;
+                       return;
 
                INIT_WORK(&ew->work, handle_port_mgmt_change_event);
                memcpy(&ew->ib_eqe, eqe, sizeof *eqe);
index 3305f27..ae50b56 100644 (file)
@@ -3073,6 +3073,8 @@ do_write:
        case IB_WR_ATOMIC_FETCH_AND_ADD:
                if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
                        goto inv_err;
+               if (unlikely(wqe->atomic_wr.remote_addr & (sizeof(u64) - 1)))
+                       goto inv_err;
                if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64),
                                          wqe->atomic_wr.remote_addr,
                                          wqe->atomic_wr.rkey,
index 368959a..df03d84 100644 (file)
@@ -644,14 +644,9 @@ static inline struct siw_sqe *orq_get_current(struct siw_qp *qp)
        return &qp->orq[qp->orq_get % qp->attrs.orq_size];
 }
 
-static inline struct siw_sqe *orq_get_tail(struct siw_qp *qp)
-{
-       return &qp->orq[qp->orq_put % qp->attrs.orq_size];
-}
-
 static inline struct siw_sqe *orq_get_free(struct siw_qp *qp)
 {
-       struct siw_sqe *orq_e = orq_get_tail(qp);
+       struct siw_sqe *orq_e = &qp->orq[qp->orq_put % qp->attrs.orq_size];
 
        if (READ_ONCE(orq_e->flags) == 0)
                return orq_e;
index 60116f2..875ea6f 100644 (file)
@@ -1153,11 +1153,12 @@ static int siw_check_tx_fence(struct siw_qp *qp)
 
        spin_lock_irqsave(&qp->orq_lock, flags);
 
-       rreq = orq_get_current(qp);
-
        /* free current orq entry */
+       rreq = orq_get_current(qp);
        WRITE_ONCE(rreq->flags, 0);
 
+       qp->orq_get++;
+
        if (qp->tx_ctx.orq_fence) {
                if (unlikely(tx_waiting->wr_status != SIW_WR_QUEUED)) {
                        pr_warn("siw: [QP %u]: fence resume: bad status %d\n",
@@ -1165,10 +1166,12 @@ static int siw_check_tx_fence(struct siw_qp *qp)
                        rv = -EPROTO;
                        goto out;
                }
-               /* resume SQ processing */
+               /* resume SQ processing, if possible */
                if (tx_waiting->sqe.opcode == SIW_OP_READ ||
                    tx_waiting->sqe.opcode == SIW_OP_READ_LOCAL_INV) {
-                       rreq = orq_get_tail(qp);
+
+                       /* SQ processing was stopped because of a full ORQ */
+                       rreq = orq_get_free(qp);
                        if (unlikely(!rreq)) {
                                pr_warn("siw: [QP %u]: no ORQE\n", qp_id(qp));
                                rv = -EPROTO;
@@ -1181,15 +1184,14 @@ static int siw_check_tx_fence(struct siw_qp *qp)
                        resume_tx = 1;
 
                } else if (siw_orq_empty(qp)) {
+                       /*
+                        * SQ processing was stopped by fenced work request.
+                        * Resume since all previous Read's are now completed.
+                        */
                        qp->tx_ctx.orq_fence = 0;
                        resume_tx = 1;
-               } else {
-                       pr_warn("siw: [QP %u]: fence resume: orq idx: %d:%d\n",
-                               qp_id(qp), qp->orq_get, qp->orq_put);
-                       rv = -EPROTO;
                }
        }
-       qp->orq_get++;
 out:
        spin_unlock_irqrestore(&qp->orq_lock, flags);
 
index a3dd2cb..54ef367 100644 (file)
@@ -313,7 +313,8 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
 
        if (atomic_inc_return(&sdev->num_qp) > SIW_MAX_QP) {
                siw_dbg(base_dev, "too many QP's\n");
-               return -ENOMEM;
+               rv = -ENOMEM;
+               goto err_atomic;
        }
        if (attrs->qp_type != IB_QPT_RC) {
                siw_dbg(base_dev, "only RC QP's supported\n");
index 78d2ee9..1b58611 100644 (file)
@@ -615,10 +615,9 @@ static int wm97xx_register_touch(struct wm97xx *wm)
         * extensions)
         */
        wm->touch_dev = platform_device_alloc("wm97xx-touch", -1);
-       if (!wm->touch_dev) {
-               ret = -ENOMEM;
-               goto touch_err;
-       }
+       if (!wm->touch_dev)
+               return -ENOMEM;
+
        platform_set_drvdata(wm->touch_dev, wm);
        wm->touch_dev->dev.parent = wm->dev;
        wm->touch_dev->dev.platform_data = pdata;
@@ -629,9 +628,6 @@ static int wm97xx_register_touch(struct wm97xx *wm)
        return 0;
 touch_reg_err:
        platform_device_put(wm->touch_dev);
-touch_err:
-       input_unregister_device(wm->input_dev);
-       wm->input_dev = NULL;
 
        return ret;
 }
@@ -639,8 +635,6 @@ touch_err:
 static void wm97xx_unregister_touch(struct wm97xx *wm)
 {
        platform_device_unregister(wm->touch_dev);
-       input_unregister_device(wm->input_dev);
-       wm->input_dev = NULL;
 }
 
 static int _wm97xx_probe(struct wm97xx *wm)
index dc338ac..b10fb52 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/export.h>
 #include <linux/kmemleak.h>
 #include <linux/cc_platform.h>
+#include <linux/iopoll.h>
 #include <asm/pci-direct.h>
 #include <asm/iommu.h>
 #include <asm/apic.h>
@@ -834,6 +835,7 @@ static int iommu_ga_log_enable(struct amd_iommu *iommu)
                status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
                if (status & (MMIO_STATUS_GALOG_RUN_MASK))
                        break;
+               udelay(10);
        }
 
        if (WARN_ON(i >= LOOP_TIMEOUT))
index f912fe4..a673195 100644 (file)
@@ -569,9 +569,8 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
                                            fn, &intel_ir_domain_ops,
                                            iommu);
        if (!iommu->ir_domain) {
-               irq_domain_free_fwnode(fn);
                pr_err("IR%d: failed to allocate irqdomain\n", iommu->seq_id);
-               goto out_free_bitmap;
+               goto out_free_fwnode;
        }
        iommu->ir_msi_domain =
                arch_create_remap_msi_irq_domain(iommu->ir_domain,
@@ -595,7 +594,7 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
 
                if (dmar_enable_qi(iommu)) {
                        pr_err("Failed to enable queued invalidation\n");
-                       goto out_free_bitmap;
+                       goto out_free_ir_domain;
                }
        }
 
@@ -619,6 +618,14 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
 
        return 0;
 
+out_free_ir_domain:
+       if (iommu->ir_msi_domain)
+               irq_domain_remove(iommu->ir_msi_domain);
+       iommu->ir_msi_domain = NULL;
+       irq_domain_remove(iommu->ir_domain);
+       iommu->ir_domain = NULL;
+out_free_fwnode:
+       irq_domain_free_fwnode(fn);
 out_free_bitmap:
        bitmap_free(bitmap);
 out_free_pages:
index 50ee27b..06fee74 100644 (file)
@@ -349,6 +349,7 @@ EXPORT_SYMBOL_GPL(ioasid_alloc);
 
 /**
  * ioasid_get - obtain a reference to the IOASID
+ * @ioasid: the ID to get
  */
 void ioasid_get(ioasid_t ioasid)
 {
index 8b86406..107dcf5 100644 (file)
@@ -207,9 +207,14 @@ static struct dev_iommu *dev_iommu_get(struct device *dev)
 
 static void dev_iommu_free(struct device *dev)
 {
-       iommu_fwspec_free(dev);
-       kfree(dev->iommu);
+       struct dev_iommu *param = dev->iommu;
+
        dev->iommu = NULL;
+       if (param->fwspec) {
+               fwnode_handle_put(param->fwspec->iommu_fwnode);
+               kfree(param->fwspec);
+       }
+       kfree(param);
 }
 
 static int __iommu_probe_device(struct device *dev, struct list_head *group_list)
@@ -980,17 +985,6 @@ static int iommu_group_device_count(struct iommu_group *group)
        return ret;
 }
 
-/**
- * iommu_group_for_each_dev - iterate over each device in the group
- * @group: the group
- * @data: caller opaque data to be passed to callback function
- * @fn: caller supplied callback function
- *
- * This function is called by group users to iterate over group devices.
- * Callers should hold a reference count to the group during callback.
- * The group->mutex is held across callbacks, which will block calls to
- * iommu_group_add/remove_device.
- */
 static int __iommu_group_for_each_dev(struct iommu_group *group, void *data,
                                      int (*fn)(struct device *, void *))
 {
@@ -1005,7 +999,17 @@ static int __iommu_group_for_each_dev(struct iommu_group *group, void *data,
        return ret;
 }
 
-
+/**
+ * iommu_group_for_each_dev - iterate over each device in the group
+ * @group: the group
+ * @data: caller opaque data to be passed to callback function
+ * @fn: caller supplied callback function
+ *
+ * This function is called by group users to iterate over group devices.
+ * Callers should hold a reference count to the group during callback.
+ * The group->mutex is held across callbacks, which will block calls to
+ * iommu_group_add/remove_device.
+ */
 int iommu_group_for_each_dev(struct iommu_group *group, void *data,
                             int (*fn)(struct device *, void *))
 {
@@ -3032,6 +3036,7 @@ EXPORT_SYMBOL_GPL(iommu_aux_get_pasid);
  * iommu_sva_bind_device() - Bind a process address space to a device
  * @dev: the device
  * @mm: the mm to bind, caller must hold a reference to it
+ * @drvdata: opaque data pointer to pass to bind callback
  *
  * Create a bond between device and address space, allowing the device to access
  * the mm using the returned PASID. If a bond already exists between @device and
index 9174965..980e4af 100644 (file)
@@ -1085,7 +1085,7 @@ static __maybe_unused int omap_iommu_runtime_resume(struct device *dev)
 }
 
 /**
- * omap_iommu_suspend_prepare - prepare() dev_pm_ops implementation
+ * omap_iommu_prepare - prepare() dev_pm_ops implementation
  * @dev:       iommu device
  *
  * This function performs the necessary checks to determine if the IOMMU
index 2543ef6..38091eb 100644 (file)
@@ -178,7 +178,6 @@ struct aic_irq_chip {
        struct irq_domain *hw_domain;
        struct irq_domain *ipi_domain;
        int nr_hw;
-       int ipi_hwirq;
 };
 
 static DEFINE_PER_CPU(uint32_t, aic_fiq_unmasked);
index d25b7a8..cd77297 100644 (file)
@@ -4856,6 +4856,38 @@ static struct syscore_ops its_syscore_ops = {
        .resume = its_restore_enable,
 };
 
+static void __init __iomem *its_map_one(struct resource *res, int *err)
+{
+       void __iomem *its_base;
+       u32 val;
+
+       its_base = ioremap(res->start, SZ_64K);
+       if (!its_base) {
+               pr_warn("ITS@%pa: Unable to map ITS registers\n", &res->start);
+               *err = -ENOMEM;
+               return NULL;
+       }
+
+       val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
+       if (val != 0x30 && val != 0x40) {
+               pr_warn("ITS@%pa: No ITS detected, giving up\n", &res->start);
+               *err = -ENODEV;
+               goto out_unmap;
+       }
+
+       *err = its_force_quiescent(its_base);
+       if (*err) {
+               pr_warn("ITS@%pa: Failed to quiesce, giving up\n", &res->start);
+               goto out_unmap;
+       }
+
+       return its_base;
+
+out_unmap:
+       iounmap(its_base);
+       return NULL;
+}
+
 static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
 {
        struct irq_domain *inner_domain;
@@ -4963,29 +4995,14 @@ static int __init its_probe_one(struct resource *res,
 {
        struct its_node *its;
        void __iomem *its_base;
-       u32 val, ctlr;
        u64 baser, tmp, typer;
        struct page *page;
+       u32 ctlr;
        int err;
 
-       its_base = ioremap(res->start, SZ_64K);
-       if (!its_base) {
-               pr_warn("ITS@%pa: Unable to map ITS registers\n", &res->start);
-               return -ENOMEM;
-       }
-
-       val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
-       if (val != 0x30 && val != 0x40) {
-               pr_warn("ITS@%pa: No ITS detected, giving up\n", &res->start);
-               err = -ENODEV;
-               goto out_unmap;
-       }
-
-       err = its_force_quiescent(its_base);
-       if (err) {
-               pr_warn("ITS@%pa: Failed to quiesce, giving up\n", &res->start);
-               goto out_unmap;
-       }
+       its_base = its_map_one(res, &err);
+       if (!its_base)
+               return err;
 
        pr_info("ITS %pR\n", res);
 
@@ -5241,13 +5258,31 @@ static int its_cpu_memreserve_lpi(unsigned int cpu)
 
 out:
        /* Last CPU being brought up gets to issue the cleanup */
-       if (cpumask_equal(&cpus_booted_once_mask, cpu_possible_mask))
+       if (!IS_ENABLED(CONFIG_SMP) ||
+           cpumask_equal(&cpus_booted_once_mask, cpu_possible_mask))
                schedule_work(&rdist_memreserve_cpuhp_cleanup_work);
 
        gic_data_rdist()->flags |= RD_LOCAL_MEMRESERVE_DONE;
        return ret;
 }
 
+/* Mark all the BASER registers as invalid before they get reprogrammed */
+static int __init its_reset_one(struct resource *res)
+{
+       void __iomem *its_base;
+       int err, i;
+
+       its_base = its_map_one(res, &err);
+       if (!its_base)
+               return err;
+
+       for (i = 0; i < GITS_BASER_NR_REGS; i++)
+               gits_write_baser(0, its_base + GITS_BASER + (i << 3));
+
+       iounmap(its_base);
+       return 0;
+}
+
 static const struct of_device_id its_device_id[] = {
        {       .compatible     = "arm,gic-v3-its",     },
        {},
@@ -5258,6 +5293,26 @@ static int __init its_of_probe(struct device_node *node)
        struct device_node *np;
        struct resource res;
 
+       /*
+        * Make sure *all* the ITS are reset before we probe any, as
+        * they may be sharing memory. If any of the ITS fails to
+        * reset, don't even try to go any further, as this could
+        * result in something even worse.
+        */
+       for (np = of_find_matching_node(node, its_device_id); np;
+            np = of_find_matching_node(np, its_device_id)) {
+               int err;
+
+               if (!of_device_is_available(np) ||
+                   !of_property_read_bool(np, "msi-controller") ||
+                   of_address_to_resource(np, 0, &res))
+                       continue;
+
+               err = its_reset_one(&res);
+               if (err)
+                       return err;
+       }
+
        for (np = of_find_matching_node(node, its_device_id); np;
             np = of_find_matching_node(np, its_device_id)) {
                if (!of_device_is_available(np))
@@ -5420,11 +5475,35 @@ dom_err:
        return err;
 }
 
+static int __init its_acpi_reset(union acpi_subtable_headers *header,
+                                const unsigned long end)
+{
+       struct acpi_madt_generic_translator *its_entry;
+       struct resource res;
+
+       its_entry = (struct acpi_madt_generic_translator *)header;
+       res = (struct resource) {
+               .start  = its_entry->base_address,
+               .end    = its_entry->base_address + ACPI_GICV3_ITS_MEM_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       };
+
+       return its_reset_one(&res);
+}
+
 static void __init its_acpi_probe(void)
 {
        acpi_table_parse_srat_its();
-       acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
-                             gic_acpi_parse_madt_its, 0);
+       /*
+        * Make sure *all* the ITS are reset before we probe any, as
+        * they may be sharing memory. If any of the ITS fails to
+        * reset, don't even try to go any further, as this could
+        * result in something even worse.
+        */
+       if (acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+                                 its_acpi_reset, 0) > 0)
+               acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+                                     gic_acpi_parse_madt_its, 0);
        acpi_its_srat_maps_free();
 }
 #else
@@ -5438,6 +5517,9 @@ int __init its_lpi_memreserve_init(void)
        if (!efi_enabled(EFI_CONFIG_TABLES))
                return 0;
 
+       if (list_empty(&its_nodes))
+               return 0;
+
        gic_rdists->cpuhp_memreserve_state = CPUHP_INVALID;
        state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
                                  "irqchip/arm/gicv3/memreserve:online",
index 32562b7..e3801c4 100644 (file)
@@ -241,7 +241,7 @@ static int pch_msi_init(struct device_node *node,
        return 0;
 
 err_map:
-       kfree(priv->msi_map);
+       bitmap_free(priv->msi_map);
 err_priv:
        kfree(priv);
        return ret;
index fd9f275..50a5682 100644 (file)
@@ -62,7 +62,7 @@ static struct irq_chip realtek_ictl_irq = {
 
 static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
 {
-       irq_set_chip_and_handler(hw, &realtek_ictl_irq, handle_level_irq);
+       irq_set_chip_and_handler(irq, &realtek_ictl_irq, handle_level_irq);
 
        return 0;
 }
@@ -76,16 +76,20 @@ static void realtek_irq_dispatch(struct irq_desc *desc)
 {
        struct irq_chip *chip = irq_desc_get_chip(desc);
        struct irq_domain *domain;
-       unsigned int pending;
+       unsigned long pending;
+       unsigned int soc_int;
 
        chained_irq_enter(chip, desc);
        pending = readl(REG(RTL_ICTL_GIMR)) & readl(REG(RTL_ICTL_GISR));
+
        if (unlikely(!pending)) {
                spurious_interrupt();
                goto out;
        }
+
        domain = irq_desc_get_handler_data(desc);
-       generic_handle_domain_irq(domain, __ffs(pending));
+       for_each_set_bit(soc_int, &pending, 32)
+               generic_handle_domain_irq(domain, soc_int);
 
 out:
        chained_irq_exit(chip, desc);
@@ -95,7 +99,8 @@ out:
  * SoC interrupts are cascaded to MIPS CPU interrupts according to the
  * interrupt-map in the device tree. Each SoC interrupt gets 4 bits for
  * the CPU interrupt in an Interrupt Routing Register. Max 32 SoC interrupts
- * thus go into 4 IRRs.
+ * thus go into 4 IRRs. A routing value of '0' means the interrupt is left
+ * disconnected. Routing values {1..15} connect to output lines {0..14}.
  */
 static int __init map_interrupts(struct device_node *node, struct irq_domain *domain)
 {
@@ -134,7 +139,7 @@ static int __init map_interrupts(struct device_node *node, struct irq_domain *do
                of_node_put(cpu_ictl);
 
                cpu_int = be32_to_cpup(imap + 2);
-               if (cpu_int > 7)
+               if (cpu_int > 7 || cpu_int < 2)
                        return -EINVAL;
 
                if (!(mips_irqs_set & BIT(cpu_int))) {
@@ -143,7 +148,8 @@ static int __init map_interrupts(struct device_node *node, struct irq_domain *do
                        mips_irqs_set |= BIT(cpu_int);
                }
 
-               regs[(soc_int * 4) / 32] |= cpu_int << (soc_int * 4) % 32;
+               /* Use routing values (1..6) for CPU interrupts (2..7) */
+               regs[(soc_int * 4) / 32] |= (cpu_int - 1) << (soc_int * 4) % 32;
                imap += 3;
        }
 
index 259065d..09cc982 100644 (file)
@@ -398,3 +398,4 @@ out_free_priv:
 
 IRQCHIP_DECLARE(sifive_plic, "sifive,plic-1.0.0", plic_init);
 IRQCHIP_DECLARE(riscv_plic0, "riscv,plic0", plic_init); /* for legacy systems */
+IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_init); /* for firmware driver */
index c0ae808..dcbd6d2 100644 (file)
@@ -489,7 +489,7 @@ static void start_io_acct(struct dm_io *io)
        struct mapped_device *md = io->md;
        struct bio *bio = io->orig_bio;
 
-       io->start_time = bio_start_io_acct(bio);
+       bio_start_io_acct_time(bio, io->start_time);
        if (unlikely(dm_stats_used(&md->stats)))
                dm_stats_account_io(&md->stats, bio_data_dir(bio),
                                    bio->bi_iter.bi_sector, bio_sectors(bio),
@@ -535,7 +535,7 @@ static struct dm_io *alloc_io(struct mapped_device *md, struct bio *bio)
        io->md = md;
        spin_lock_init(&io->endio_lock);
 
-       start_io_acct(io);
+       io->start_time = jiffies;
 
        return io;
 }
@@ -1442,9 +1442,6 @@ static void init_clone_info(struct clone_info *ci, struct mapped_device *md,
        ci->sector = bio->bi_iter.bi_sector;
 }
 
-#define __dm_part_stat_sub(part, field, subnd) \
-       (part_stat_get(part, field) -= (subnd))
-
 /*
  * Entry point to split a bio into clones and submit them to the targets.
  */
@@ -1480,23 +1477,12 @@ static void __split_and_process_bio(struct mapped_device *md,
                                                  GFP_NOIO, &md->queue->bio_split);
                        ci.io->orig_bio = b;
 
-                       /*
-                        * Adjust IO stats for each split, otherwise upon queue
-                        * reentry there will be redundant IO accounting.
-                        * NOTE: this is a stop-gap fix, a proper fix involves
-                        * significant refactoring of DM core's bio splitting
-                        * (by eliminating DM's splitting and just using bio_split)
-                        */
-                       part_stat_lock();
-                       __dm_part_stat_sub(dm_disk(md)->part0,
-                                          sectors[op_stat_group(bio_op(bio))], ci.sector_count);
-                       part_stat_unlock();
-
                        bio_chain(b, bio);
                        trace_block_split(b, bio->bi_iter.bi_sector);
                        submit_bio_noacct(bio);
                }
        }
+       start_io_acct(ci.io);
 
        /* drop the extra reference count */
        dm_io_dec_pending(ci.io, errno_to_blk_status(error));
index 5881d05..4d38bd7 100644 (file)
@@ -5869,10 +5869,6 @@ int md_run(struct mddev *mddev)
                nowait = nowait && blk_queue_nowait(bdev_get_queue(rdev->bdev));
        }
 
-       /* Set the NOWAIT flags if all underlying devices support it */
-       if (nowait)
-               blk_queue_flag_set(QUEUE_FLAG_NOWAIT, mddev->queue);
-
        if (!bioset_initialized(&mddev->bio_set)) {
                err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
                if (err)
@@ -6010,6 +6006,10 @@ int md_run(struct mddev *mddev)
                else
                        blk_queue_flag_clear(QUEUE_FLAG_NONROT, mddev->queue);
                blk_queue_flag_set(QUEUE_FLAG_IO_STAT, mddev->queue);
+
+               /* Set the NOWAIT flags if all underlying devices support it */
+               if (nowait)
+                       blk_queue_flag_set(QUEUE_FLAG_NOWAIT, mddev->queue);
        }
        if (pers->sync_request) {
                if (mddev->kobj.sd &&
index c3305bd..bee727e 100644 (file)
@@ -440,6 +440,10 @@ static int at25_probe(struct spi_device *spi)
                return -ENXIO;
        }
 
+       at25 = devm_kzalloc(&spi->dev, sizeof(*at25), GFP_KERNEL);
+       if (!at25)
+               return -ENOMEM;
+
        mutex_init(&at25->lock);
        at25->spi = spi;
        spi_set_drvdata(spi, at25);
index bb9c451..9fbfe78 100644 (file)
@@ -114,6 +114,9 @@ static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf,
        if (offset + count > EE1004_PAGE_SIZE)
                count = EE1004_PAGE_SIZE - offset;
 
+       if (count > I2C_SMBUS_BLOCK_MAX)
+               count = I2C_SMBUS_BLOCK_MAX;
+
        return i2c_smbus_read_i2c_block_data_or_emulated(client, offset, count, buf);
 }
 
index 4ccbf43..aa1682b 100644 (file)
@@ -1288,7 +1288,14 @@ static int fastrpc_dmabuf_alloc(struct fastrpc_user *fl, char __user *argp)
        }
 
        if (copy_to_user(argp, &bp, sizeof(bp))) {
-               dma_buf_put(buf->dmabuf);
+               /*
+                * The usercopy failed, but we can't do much about it, as
+                * dma_buf_fd() already called fd_install() and made the
+                * file descriptor accessible for the current process. It
+                * might already be closed and dmabuf no longer valid when
+                * we reach this point. Therefore "leak" the fd and rely on
+                * the process exit path to do any required cleanup.
+                */
                return -EFAULT;
        }
 
index 45f5787..bd87012 100644 (file)
@@ -67,7 +67,7 @@ static const unsigned int sd_au_size[] = {
                __res & __mask;                                         \
        })
 
-#define SD_POWEROFF_NOTIFY_TIMEOUT_MS 2000
+#define SD_POWEROFF_NOTIFY_TIMEOUT_MS 1000
 #define SD_WRITE_EXTR_SINGLE_TIMEOUT_MS 1000
 
 struct sd_busy_data {
@@ -1664,6 +1664,12 @@ static int sd_poweroff_notify(struct mmc_card *card)
                goto out;
        }
 
+       /* Find out when the command is completed. */
+       err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false,
+                               MMC_BUSY_EXTR_SINGLE);
+       if (err)
+               goto out;
+
        cb_data.card = card;
        cb_data.reg_buf = reg_buf;
        err = __mmc_poll_for_busy(card->host, SD_POWEROFF_NOTIFY_TIMEOUT_MS,
index 16d1c7a..b6eb75f 100644 (file)
@@ -705,12 +705,12 @@ static int moxart_remove(struct platform_device *pdev)
        if (!IS_ERR_OR_NULL(host->dma_chan_rx))
                dma_release_channel(host->dma_chan_rx);
        mmc_remove_host(mmc);
-       mmc_free_host(mmc);
 
        writel(0, host->base + REG_INTERRUPT_MASK);
        writel(0, host->base + REG_POWER_CONTROL);
        writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF,
               host->base + REG_CLOCK_CONTROL);
+       mmc_free_host(mmc);
 
        return 0;
 }
index a593b1f..0f3658b 100644 (file)
@@ -524,12 +524,16 @@ static void esdhc_of_adma_workaround(struct sdhci_host *host, u32 intmask)
 
 static int esdhc_of_enable_dma(struct sdhci_host *host)
 {
+       int ret;
        u32 value;
        struct device *dev = mmc_dev(host->mmc);
 
        if (of_device_is_compatible(dev->of_node, "fsl,ls1043a-esdhc") ||
-           of_device_is_compatible(dev->of_node, "fsl,ls1046a-esdhc"))
-               dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+           of_device_is_compatible(dev->of_node, "fsl,ls1046a-esdhc")) {
+               ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+               if (ret)
+                       return ret;
+       }
 
        value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
 
index bcc595c..104dcd7 100644 (file)
@@ -405,6 +405,9 @@ static int sh_mmcif_dma_slave_config(struct sh_mmcif_host *host,
        struct dma_slave_config cfg = { 0, };
 
        res = platform_get_resource(host->pd, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EINVAL;
+
        cfg.direction = direction;
 
        if (direction == DMA_DEV_TO_MEM) {
index 6006c2e..9fd1d6c 100644 (file)
@@ -1021,8 +1021,8 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
                                if (port->aggregator &&
                                    port->aggregator->is_active &&
                                    !__port_is_enabled(port)) {
-
                                        __enable_port(port);
+                                       *update_slave_arr = true;
                                }
                        }
                        break;
@@ -1779,6 +1779,7 @@ static void ad_agg_selection_logic(struct aggregator *agg,
                             port = port->next_port_in_aggregator) {
                                __enable_port(port);
                        }
+                       *update_slave_arr = true;
                }
        }
 
index ec498ce..238b56d 100644 (file)
@@ -4133,9 +4133,7 @@ static int bond_eth_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cm
 
                fallthrough;
        case SIOCGHWTSTAMP:
-               rcu_read_lock();
                real_dev = bond_option_active_slave_get_rcu(bond);
-               rcu_read_unlock();
                if (!real_dev)
                        return -EOPNOTSUPP;
 
@@ -5382,9 +5380,7 @@ static int bond_ethtool_get_ts_info(struct net_device *bond_dev,
        struct net_device *real_dev;
        struct phy_device *phydev;
 
-       rcu_read_lock();
        real_dev = bond_option_active_slave_get_rcu(bond);
-       rcu_read_unlock();
        if (real_dev) {
                ops = real_dev->ethtool_ops;
                phydev = real_dev->phydev;
index 0bff188..74d7fcb 100644 (file)
@@ -296,6 +296,7 @@ static_assert(sizeof(struct flexcan_regs) ==  0x4 * 18 + 0xfb8);
 static const struct flexcan_devtype_data fsl_mcf5441x_devtype_data = {
        .quirks = FLEXCAN_QUIRK_BROKEN_PERR_STATE |
                FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_NR_MB_16 |
+               FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
                FLEXCAN_QUIRK_SUPPPORT_RX_FIFO,
 };
 
index fccdff8..23fc09a 100644 (file)
@@ -21,7 +21,7 @@
  * Below is some version info we got:
  *    SOC   Version   IP-Version  Glitch- [TR]WRN_INT IRQ Err Memory err RTR rece-   FD Mode     MB
  *                                Filter? connected?  Passive detection  ption in MB Supported?
- * MCF5441X FlexCAN2  ?               no       yes        no       no       yes           no     16
+ * MCF5441X FlexCAN2  ?               no       yes        no       no        no           no     16
  *    MX25  FlexCAN2  03.00.00.00     no        no        no       no        no           no     64
  *    MX28  FlexCAN2  03.00.04.00    yes       yes        no       no        no           no     64
  *    MX35  FlexCAN2  03.00.00.00     no        no        no       no        no           no     64
index 5b47cd8..1a4b56f 100644 (file)
@@ -336,6 +336,9 @@ m_can_fifo_read(struct m_can_classdev *cdev,
        u32 addr_offset = cdev->mcfg[MRAM_RXF0].off + fgi * RXF0_ELEMENT_SIZE +
                offset;
 
+       if (val_count == 0)
+               return 0;
+
        return cdev->ops->read_fifo(cdev, addr_offset, val, val_count);
 }
 
@@ -346,6 +349,9 @@ m_can_fifo_write(struct m_can_classdev *cdev,
        u32 addr_offset = cdev->mcfg[MRAM_TXB].off + fpi * TXB_ELEMENT_SIZE +
                offset;
 
+       if (val_count == 0)
+               return 0;
+
        return cdev->ops->write_fifo(cdev, addr_offset, val, val_count);
 }
 
index ca80dba..26e212b 100644 (file)
@@ -12,7 +12,7 @@
 #define TCAN4X5X_SPI_INSTRUCTION_WRITE (0x61 << 24)
 #define TCAN4X5X_SPI_INSTRUCTION_READ (0x41 << 24)
 
-#define TCAN4X5X_MAX_REGISTER 0x8ffc
+#define TCAN4X5X_MAX_REGISTER 0x87fc
 
 static int tcan4x5x_regmap_gather_write(void *context,
                                        const void *reg, size_t reg_len,
index 7b1457a..c0c9144 100644 (file)
@@ -36,6 +36,7 @@ config NET_DSA_LANTIQ_GSWIP
 config NET_DSA_MT7530
        tristate "MediaTek MT753x and MT7621 Ethernet switch support"
        select NET_DSA_TAG_MTK
+       select MEDIATEK_GE_PHY
        help
          This enables support for the MediaTek MT7530, MT7531, and MT7621
          Ethernet switch chips.
index 33499fc..6afb5db 100644 (file)
@@ -621,7 +621,7 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
        get_device(&priv->master_mii_bus->dev);
        priv->master_mii_dn = dn;
 
-       priv->slave_mii_bus = devm_mdiobus_alloc(ds->dev);
+       priv->slave_mii_bus = mdiobus_alloc();
        if (!priv->slave_mii_bus) {
                of_node_put(dn);
                return -ENOMEM;
@@ -681,8 +681,10 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
        }
 
        err = mdiobus_register(priv->slave_mii_bus);
-       if (err && dn)
+       if (err && dn) {
+               mdiobus_free(priv->slave_mii_bus);
                of_node_put(dn);
+       }
 
        return err;
 }
@@ -690,6 +692,7 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
 static void bcm_sf2_mdio_unregister(struct bcm_sf2_priv *priv)
 {
        mdiobus_unregister(priv->slave_mii_bus);
+       mdiobus_free(priv->slave_mii_bus);
        of_node_put(priv->master_mii_dn);
 }
 
index 46ed953..320ee7f 100644 (file)
@@ -498,8 +498,9 @@ static int gswip_mdio_rd(struct mii_bus *bus, int addr, int reg)
 static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np)
 {
        struct dsa_switch *ds = priv->ds;
+       int err;
 
-       ds->slave_mii_bus = devm_mdiobus_alloc(priv->dev);
+       ds->slave_mii_bus = mdiobus_alloc();
        if (!ds->slave_mii_bus)
                return -ENOMEM;
 
@@ -512,7 +513,11 @@ static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np)
        ds->slave_mii_bus->parent = priv->dev;
        ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask;
 
-       return of_mdiobus_register(ds->slave_mii_bus, mdio_np);
+       err = of_mdiobus_register(ds->slave_mii_bus, mdio_np);
+       if (err)
+               mdiobus_free(ds->slave_mii_bus);
+
+       return err;
 }
 
 static int gswip_pce_table_entry_read(struct gswip_priv *priv,
@@ -2145,8 +2150,10 @@ disable_switch:
        gswip_mdio_mask(priv, GSWIP_MDIO_GLOB_ENABLE, 0, GSWIP_MDIO_GLOB);
        dsa_unregister_switch(priv->ds);
 mdio_bus:
-       if (mdio_np)
+       if (mdio_np) {
                mdiobus_unregister(priv->ds->slave_mii_bus);
+               mdiobus_free(priv->ds->slave_mii_bus);
+       }
 put_mdio_node:
        of_node_put(mdio_np);
        for (i = 0; i < priv->num_gphy_fw; i++)
@@ -2169,6 +2176,7 @@ static int gswip_remove(struct platform_device *pdev)
 
        if (priv->ds->slave_mii_bus) {
                mdiobus_unregister(priv->ds->slave_mii_bus);
+               mdiobus_free(priv->ds->slave_mii_bus);
                of_node_put(priv->ds->slave_mii_bus->dev.of_node);
        }
 
index b82512e..ff3c267 100644 (file)
@@ -2074,7 +2074,7 @@ mt7530_setup_mdio(struct mt7530_priv *priv)
        if (priv->irq)
                mt7530_setup_mdio_irq(priv);
 
-       ret = mdiobus_register(bus);
+       ret = devm_mdiobus_register(dev, bus);
        if (ret) {
                dev_err(dev, "failed to register MDIO bus: %d\n", ret);
                if (priv->irq)
index 58ca684..8530dbe 100644 (file)
@@ -3399,7 +3399,7 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
                        return err;
        }
 
-       bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus));
+       bus = mdiobus_alloc_size(sizeof(*mdio_bus));
        if (!bus)
                return -ENOMEM;
 
@@ -3424,14 +3424,14 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
        if (!external) {
                err = mv88e6xxx_g2_irq_mdio_setup(chip, bus);
                if (err)
-                       return err;
+                       goto out;
        }
 
        err = of_mdiobus_register(bus, np);
        if (err) {
                dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
                mv88e6xxx_g2_irq_mdio_free(chip, bus);
-               return err;
+               goto out;
        }
 
        if (external)
@@ -3440,21 +3440,26 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
                list_add(&mdio_bus->list, &chip->mdios);
 
        return 0;
+
+out:
+       mdiobus_free(bus);
+       return err;
 }
 
 static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)
 
 {
-       struct mv88e6xxx_mdio_bus *mdio_bus;
+       struct mv88e6xxx_mdio_bus *mdio_bus, *p;
        struct mii_bus *bus;
 
-       list_for_each_entry(mdio_bus, &chip->mdios, list) {
+       list_for_each_entry_safe(mdio_bus, p, &chip->mdios, list) {
                bus = mdio_bus->bus;
 
                if (!mdio_bus->external)
                        mv88e6xxx_g2_irq_mdio_free(chip, bus);
 
                mdiobus_unregister(bus);
+               mdiobus_free(bus);
        }
 }
 
index bf8d382..33f0cea 100644 (file)
@@ -1061,7 +1061,7 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
                return PTR_ERR(hw);
        }
 
-       bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+       bus = mdiobus_alloc_size(sizeof(*mdio_priv));
        if (!bus)
                return -ENOMEM;
 
@@ -1081,6 +1081,7 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
        rc = mdiobus_register(bus);
        if (rc < 0) {
                dev_err(dev, "failed to register MDIO bus\n");
+               mdiobus_free(bus);
                return rc;
        }
 
@@ -1132,6 +1133,7 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot)
                lynx_pcs_destroy(phylink_pcs);
        }
        mdiobus_unregister(felix->imdio);
+       mdiobus_free(felix->imdio);
 }
 
 static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
index 8c1c9da..f2f1608 100644 (file)
@@ -1029,7 +1029,7 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot)
        }
 
        /* Needed in order to initialize the bus mutex lock */
-       rc = of_mdiobus_register(bus, NULL);
+       rc = devm_of_mdiobus_register(dev, bus, NULL);
        if (rc < 0) {
                dev_err(dev, "failed to register MDIO bus\n");
                return rc;
@@ -1083,7 +1083,8 @@ static void vsc9953_mdio_bus_free(struct ocelot *ocelot)
                mdio_device_free(mdio_device);
                lynx_pcs_destroy(phylink_pcs);
        }
-       mdiobus_unregister(felix->imdio);
+
+       /* mdiobus_unregister and mdiobus_free handled by devres */
 }
 
 static const struct felix_info seville_info_vsc9953 = {
index da0d7e6..c39de2a 100644 (file)
@@ -378,7 +378,7 @@ static int ar9331_sw_mbus_init(struct ar9331_sw_priv *priv)
        if (!mnp)
                return -ENODEV;
 
-       ret = of_mdiobus_register(mbus, mnp);
+       ret = devm_of_mdiobus_register(dev, mbus, mnp);
        of_node_put(mnp);
        if (ret)
                return ret;
@@ -1091,7 +1091,6 @@ static void ar9331_sw_remove(struct mdio_device *mdiodev)
        }
 
        irq_domain_remove(priv->irqdomain);
-       mdiobus_unregister(priv->mbus);
        dsa_unregister_switch(&priv->ds);
 
        reset_control_assert(priv->sw_reset);
index 481f1df..8aec5d9 100644 (file)
@@ -2278,6 +2278,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct net_device *dev;
        struct typhoon *tp;
        int card_id = (int) ent->driver_data;
+       u8 addr[ETH_ALEN] __aligned(4);
        void __iomem *ioaddr;
        void *shared;
        dma_addr_t shared_dma;
@@ -2409,8 +2410,9 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto error_out_reset;
        }
 
-       *(__be16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1));
-       *(__be32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
+       *(__be16 *)&addr[0] = htons(le16_to_cpu(xp_resp[0].parm1));
+       *(__be32 *)&addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
+       eth_hw_addr_set(dev, addr);
 
        if (!is_valid_ether_addr(dev->dev_addr)) {
                err_msg = "Could not obtain valid ethernet address, aborting";
index bd22a53..e7b8791 100644 (file)
@@ -655,6 +655,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
        struct ei_device *ei_local;
        struct net_device *dev;
        struct etherh_priv *eh;
+       u8 addr[ETH_ALEN];
        int ret;
 
        ret = ecard_request_resources(ec);
@@ -724,12 +725,13 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
        spin_lock_init(&ei_local->page_lock);
 
        if (ec->cid.product == PROD_ANT_ETHERM) {
-               etherm_addr(dev->dev_addr);
+               etherm_addr(addr);
                ei_local->reg_offset = etherm_regoffsets;
        } else {
-               etherh_addr(dev->dev_addr, ec);
+               etherh_addr(addr, ec);
                ei_local->reg_offset = etherh_regoffsets;
        }
+       eth_hw_addr_set(dev, addr);
 
        ei_local->name          = dev->name;
        ei_local->word16        = 1;
index 493b0ce..ec8df05 100644 (file)
@@ -1032,6 +1032,7 @@ static int dec_lance_probe(struct device *bdev, const int type)
        int i, ret;
        unsigned long esar_base;
        unsigned char *esar;
+       u8 addr[ETH_ALEN];
        const char *desc;
 
        if (dec_lance_debug && version_printed++ == 0)
@@ -1228,7 +1229,8 @@ static int dec_lance_probe(struct device *bdev, const int type)
                break;
        }
        for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = esar[i * 4];
+               addr[i] = esar[i * 4];
+       eth_hw_addr_set(dev, addr);
 
        printk("%s: %s, addr = %pM, irq = %d\n",
               name, desc, dev->dev_addr, dev->irq);
index 492ac38..a359329 100644 (file)
@@ -721,7 +721,9 @@ static void xgbe_stop_timers(struct xgbe_prv_data *pdata)
                if (!channel->tx_ring)
                        break;
 
+               /* Deactivate the Tx timer */
                del_timer_sync(&channel->tx_timer);
+               channel->tx_timer_active = 0;
        }
 }
 
@@ -2550,6 +2552,14 @@ read_again:
                        buf2_len = xgbe_rx_buf2_len(rdata, packet, len);
                        len += buf2_len;
 
+                       if (buf2_len > rdata->rx.buf.dma_len) {
+                               /* Hardware inconsistency within the descriptors
+                                * that has resulted in a length underflow.
+                                */
+                               error = 1;
+                               goto skip_data;
+                       }
+
                        if (!skb) {
                                skb = xgbe_create_skb(pdata, napi, rdata,
                                                      buf1_len);
@@ -2579,8 +2589,10 @@ skip_data:
                if (!last || context_next)
                        goto read_again;
 
-               if (!skb)
+               if (!skb || error) {
+                       dev_kfree_skb(skb);
                        goto next_packet;
+               }
 
                /* Be sure we don't exceed the configured MTU */
                max_len = netdev->mtu + ETH_HLEN;
index efdcf48..2af3da4 100644 (file)
@@ -425,6 +425,9 @@ static void xgbe_pci_remove(struct pci_dev *pdev)
 
        pci_free_irq_vectors(pdata->pcidev);
 
+       /* Disable all interrupts in the hardware */
+       XP_IOWRITE(pdata, XP_INT_EN, 0x0);
+
        xgbe_free_pdata(pdata);
 }
 
index 1bc4d33..30a573d 100644 (file)
@@ -826,7 +826,6 @@ int aq_filters_vlans_update(struct aq_nic_s *aq_nic)
        struct aq_hw_s *aq_hw = aq_nic->aq_hw;
        int hweight = 0;
        int err = 0;
-       int i;
 
        if (unlikely(!aq_hw_ops->hw_filter_vlan_set))
                return -EOPNOTSUPP;
@@ -837,8 +836,7 @@ int aq_filters_vlans_update(struct aq_nic_s *aq_nic)
                         aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans);
 
        if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
-               for (i = 0; i < BITS_TO_LONGS(VLAN_N_VID); i++)
-                       hweight += hweight_long(aq_nic->active_vlans[i]);
+               hweight = bitmap_weight(aq_nic->active_vlans, VLAN_N_VID);
 
                err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, false);
                if (err)
@@ -871,7 +869,7 @@ int aq_filters_vlan_offload_off(struct aq_nic_s *aq_nic)
        struct aq_hw_s *aq_hw = aq_nic->aq_hw;
        int err = 0;
 
-       memset(aq_nic->active_vlans, 0, sizeof(aq_nic->active_vlans));
+       bitmap_zero(aq_nic->active_vlans, VLAN_N_VID);
        aq_fvlan_rebuild(aq_nic, aq_nic->active_vlans,
                         aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans);
 
index f38f40e..a1a3845 100644 (file)
@@ -2183,9 +2183,7 @@ static int sbmac_init(struct platform_device *pldev, long long base)
                ea_reg >>= 8;
        }
 
-       for (i = 0; i < 6; i++) {
-               dev->dev_addr[i] = eaddr[i];
-       }
+       eth_hw_addr_set(dev, eaddr);
 
        /*
         * Initialize context (get pointers to registers and stuff), then
index a363da9..98498a7 100644 (file)
@@ -4712,7 +4712,7 @@ static int macb_probe(struct platform_device *pdev)
 
 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
        if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) {
-               dma_set_mask(&pdev->dev, DMA_BIT_MASK(44));
+               dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44));
                bp->hw_dma_cap |= HW_DMA_CAP_64B;
        }
 #endif
index e985ae0..dd9385d 100644 (file)
@@ -4523,12 +4523,12 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev)
 #ifdef CONFIG_DEBUG_FS
        dpaa2_dbg_remove(priv);
 #endif
+
+       unregister_netdev(net_dev);
        rtnl_lock();
        dpaa2_eth_disconnect_mac(priv);
        rtnl_unlock();
 
-       unregister_netdev(net_dev);
-
        dpaa2_eth_dl_port_del(priv);
        dpaa2_eth_dl_traps_unregister(priv);
        dpaa2_eth_dl_free(priv);
index bbbde9f..be0bd4b 100644 (file)
@@ -99,13 +99,13 @@ static void mpc52xx_fec_tx_timeout(struct net_device *dev, unsigned int txqueue)
        netif_wake_queue(dev);
 }
 
-static void mpc52xx_fec_set_paddr(struct net_device *dev, u8 *mac)
+static void mpc52xx_fec_set_paddr(struct net_device *dev, const u8 *mac)
 {
        struct mpc52xx_fec_priv *priv = netdev_priv(dev);
        struct mpc52xx_fec __iomem *fec = priv->fec;
 
-       out_be32(&fec->paddr1, *(u32 *)(&mac[0]));
-       out_be32(&fec->paddr2, (*(u16 *)(&mac[4]) << 16) | FEC_PADDR2_TYPE);
+       out_be32(&fec->paddr1, *(const u32 *)(&mac[0]));
+       out_be32(&fec->paddr2, (*(const u16 *)(&mac[4]) << 16) | FEC_PADDR2_TYPE);
 }
 
 static int mpc52xx_fec_set_mac_address(struct net_device *dev, void *addr)
@@ -893,13 +893,15 @@ static int mpc52xx_fec_probe(struct platform_device *op)
        rv = of_get_ethdev_address(np, ndev);
        if (rv) {
                struct mpc52xx_fec __iomem *fec = priv->fec;
+               u8 addr[ETH_ALEN] __aligned(4);
 
                /*
                 * If the MAC addresse is not provided via DT then read
                 * it back from the controller regs
                 */
-               *(u32 *)(&ndev->dev_addr[0]) = in_be32(&fec->paddr1);
-               *(u16 *)(&ndev->dev_addr[4]) = in_be32(&fec->paddr2) >> 16;
+               *(u32 *)(&addr[0]) = in_be32(&fec->paddr1);
+               *(u16 *)(&addr[4]) = in_be32(&fec->paddr2) >> 16;
+               eth_hw_addr_set(ndev, addr);
        }
 
        /*
index 5f5d4f7..1607354 100644 (file)
@@ -843,7 +843,7 @@ static inline bool gve_is_gqi(struct gve_priv *priv)
 /* buffers */
 int gve_alloc_page(struct gve_priv *priv, struct device *dev,
                   struct page **page, dma_addr_t *dma,
-                  enum dma_data_direction);
+                  enum dma_data_direction, gfp_t gfp_flags);
 void gve_free_page(struct device *dev, struct page *page, dma_addr_t dma,
                   enum dma_data_direction);
 /* tx handling */
index 2ad7f57..f7621ab 100644 (file)
@@ -301,7 +301,7 @@ static int gve_adminq_parse_err(struct gve_priv *priv, u32 status)
  */
 static int gve_adminq_kick_and_wait(struct gve_priv *priv)
 {
-       u32 tail, head;
+       int tail, head;
        int i;
 
        tail = ioread32be(&priv->reg_bar0->adminq_event_counter);
index f7f65c4..54e51c8 100644 (file)
@@ -766,9 +766,9 @@ static void gve_free_rings(struct gve_priv *priv)
 
 int gve_alloc_page(struct gve_priv *priv, struct device *dev,
                   struct page **page, dma_addr_t *dma,
-                  enum dma_data_direction dir)
+                  enum dma_data_direction dir, gfp_t gfp_flags)
 {
-       *page = alloc_page(GFP_KERNEL);
+       *page = alloc_page(gfp_flags);
        if (!*page) {
                priv->page_alloc_fail++;
                return -ENOMEM;
@@ -811,7 +811,7 @@ static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id,
        for (i = 0; i < pages; i++) {
                err = gve_alloc_page(priv, &priv->pdev->dev, &qpl->pages[i],
                                     &qpl->page_buses[i],
-                                    gve_qpl_dma_dir(priv, id));
+                                    gve_qpl_dma_dir(priv, id), GFP_KERNEL);
                /* caller handles clean up */
                if (err)
                        return -ENOMEM;
index 9ddcc49..e4e98aa 100644 (file)
@@ -86,7 +86,8 @@ static int gve_rx_alloc_buffer(struct gve_priv *priv, struct device *dev,
        dma_addr_t dma;
        int err;
 
-       err = gve_alloc_page(priv, dev, &page, &dma, DMA_FROM_DEVICE);
+       err = gve_alloc_page(priv, dev, &page, &dma, DMA_FROM_DEVICE,
+                            GFP_ATOMIC);
        if (err)
                return err;
 
@@ -608,6 +609,7 @@ static bool gve_rx(struct gve_rx_ring *rx, netdev_features_t feat,
 
        *packet_size_bytes = skb->len + (skb->protocol ? ETH_HLEN : 0);
        *work_done = work_cnt;
+       skb_record_rx_queue(skb, rx->q_num);
        if (skb_is_nonlinear(skb))
                napi_gro_frags(napi);
        else
index beb8bb0..8c93962 100644 (file)
@@ -157,7 +157,7 @@ static int gve_alloc_page_dqo(struct gve_priv *priv,
        int err;
 
        err = gve_alloc_page(priv, &priv->pdev->dev, &buf_state->page_info.page,
-                            &buf_state->addr, DMA_FROM_DEVICE);
+                            &buf_state->addr, DMA_FROM_DEVICE, GFP_KERNEL);
        if (err)
                return err;
 
index 7df8761..21442a9 100644 (file)
@@ -2043,8 +2043,7 @@ static irqreturn_t hclgevf_misc_irq_handle(int irq, void *data)
                break;
        }
 
-       if (event_cause != HCLGEVF_VECTOR0_EVENT_OTHER)
-               hclgevf_enable_vector(&hdev->misc_vector, true);
+       hclgevf_enable_vector(&hdev->misc_vector, true);
 
        return IRQ_HANDLED;
 }
index c612ef5..3e7d7c4 100644 (file)
@@ -986,6 +986,7 @@ static int
 ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
        struct net_device *dev;
+       u8 addr[ETH_ALEN];
        int i, ret = 0;
 
        ether1_banner();
@@ -1015,7 +1016,8 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
        }
 
        for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = readb(IDPROM_ADDRESS + (i << 2));
+               addr[i] = readb(IDPROM_ADDRESS + (i << 2));
+       eth_hw_addr_set(dev, addr);
 
        if (ether1_init_2(dev)) {
                ret = -ENODEV;
index 59536bd..29617a8 100644 (file)
@@ -110,6 +110,7 @@ static void ibmvnic_tx_scrq_clean_buffer(struct ibmvnic_adapter *adapter,
                                         struct ibmvnic_sub_crq_queue *tx_scrq);
 static void free_long_term_buff(struct ibmvnic_adapter *adapter,
                                struct ibmvnic_long_term_buff *ltb);
+static void ibmvnic_disable_irqs(struct ibmvnic_adapter *adapter);
 
 struct ibmvnic_stat {
        char name[ETH_GSTRING_LEN];
@@ -1424,7 +1425,7 @@ static int __ibmvnic_open(struct net_device *netdev)
        rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_UP);
        if (rc) {
                ibmvnic_napi_disable(adapter);
-               release_resources(adapter);
+               ibmvnic_disable_irqs(adapter);
                return rc;
        }
 
@@ -1474,9 +1475,6 @@ static int ibmvnic_open(struct net_device *netdev)
                rc = init_resources(adapter);
                if (rc) {
                        netdev_err(netdev, "failed to initialize resources\n");
-                       release_resources(adapter);
-                       release_rx_pools(adapter);
-                       release_tx_pools(adapter);
                        goto out;
                }
        }
@@ -1493,6 +1491,13 @@ out:
                adapter->state = VNIC_OPEN;
                rc = 0;
        }
+
+       if (rc) {
+               release_resources(adapter);
+               release_rx_pools(adapter);
+               release_tx_pools(adapter);
+       }
+
        return rc;
 }
 
@@ -2602,6 +2607,7 @@ static void __ibmvnic_reset(struct work_struct *work)
        struct ibmvnic_rwi *rwi;
        unsigned long flags;
        u32 reset_state;
+       int num_fails = 0;
        int rc = 0;
 
        adapter = container_of(work, struct ibmvnic_adapter, ibmvnic_reset);
@@ -2655,11 +2661,23 @@ static void __ibmvnic_reset(struct work_struct *work)
                                rc = do_hard_reset(adapter, rwi, reset_state);
                                rtnl_unlock();
                        }
-                       if (rc) {
-                               /* give backing device time to settle down */
+                       if (rc)
+                               num_fails++;
+                       else
+                               num_fails = 0;
+
+                       /* If auto-priority-failover is enabled we can get
+                        * back to back failovers during resets, resulting
+                        * in at least two failed resets (from high-priority
+                        * backing device to low-priority one and then back)
+                        * If resets continue to fail beyond that, give the
+                        * adapter some time to settle down before retrying.
+                        */
+                       if (num_fails >= 3) {
                                netdev_dbg(adapter->netdev,
-                                          "[S:%s] Hard reset failed, waiting 60 secs\n",
-                                          adapter_state_to_string(adapter->state));
+                                          "[S:%s] Hard reset failed %d times, waiting 60 secs\n",
+                                          adapter_state_to_string(adapter->state),
+                                          num_fails);
                                set_current_state(TASK_UNINTERRUPTIBLE);
                                schedule_timeout(60 * HZ);
                        }
@@ -3844,11 +3862,25 @@ static void send_request_cap(struct ibmvnic_adapter *adapter, int retry)
        struct device *dev = &adapter->vdev->dev;
        union ibmvnic_crq crq;
        int max_entries;
+       int cap_reqs;
+
+       /* We send out 6 or 7 REQUEST_CAPABILITY CRQs below (depending on
+        * the PROMISC flag). Initialize this count upfront. When the tasklet
+        * receives a response to all of these, it will send the next protocol
+        * message (QUERY_IP_OFFLOAD).
+        */
+       if (!(adapter->netdev->flags & IFF_PROMISC) ||
+           adapter->promisc_supported)
+               cap_reqs = 7;
+       else
+               cap_reqs = 6;
 
        if (!retry) {
                /* Sub-CRQ entries are 32 byte long */
                int entries_page = 4 * PAGE_SIZE / (sizeof(u64) * 4);
 
+               atomic_set(&adapter->running_cap_crqs, cap_reqs);
+
                if (adapter->min_tx_entries_per_subcrq > entries_page ||
                    adapter->min_rx_add_entries_per_subcrq > entries_page) {
                        dev_err(dev, "Fatal, invalid entries per sub-crq\n");
@@ -3909,44 +3941,45 @@ static void send_request_cap(struct ibmvnic_adapter *adapter, int retry)
                                        adapter->opt_rx_comp_queues;
 
                adapter->req_rx_add_queues = adapter->max_rx_add_queues;
+       } else {
+               atomic_add(cap_reqs, &adapter->running_cap_crqs);
        }
-
        memset(&crq, 0, sizeof(crq));
        crq.request_capability.first = IBMVNIC_CRQ_CMD;
        crq.request_capability.cmd = REQUEST_CAPABILITY;
 
        crq.request_capability.capability = cpu_to_be16(REQ_TX_QUEUES);
        crq.request_capability.number = cpu_to_be64(adapter->req_tx_queues);
-       atomic_inc(&adapter->running_cap_crqs);
+       cap_reqs--;
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability = cpu_to_be16(REQ_RX_QUEUES);
        crq.request_capability.number = cpu_to_be64(adapter->req_rx_queues);
-       atomic_inc(&adapter->running_cap_crqs);
+       cap_reqs--;
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability = cpu_to_be16(REQ_RX_ADD_QUEUES);
        crq.request_capability.number = cpu_to_be64(adapter->req_rx_add_queues);
-       atomic_inc(&adapter->running_cap_crqs);
+       cap_reqs--;
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability =
            cpu_to_be16(REQ_TX_ENTRIES_PER_SUBCRQ);
        crq.request_capability.number =
            cpu_to_be64(adapter->req_tx_entries_per_subcrq);
-       atomic_inc(&adapter->running_cap_crqs);
+       cap_reqs--;
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability =
            cpu_to_be16(REQ_RX_ADD_ENTRIES_PER_SUBCRQ);
        crq.request_capability.number =
            cpu_to_be64(adapter->req_rx_add_entries_per_subcrq);
-       atomic_inc(&adapter->running_cap_crqs);
+       cap_reqs--;
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability = cpu_to_be16(REQ_MTU);
        crq.request_capability.number = cpu_to_be64(adapter->req_mtu);
-       atomic_inc(&adapter->running_cap_crqs);
+       cap_reqs--;
        ibmvnic_send_crq(adapter, &crq);
 
        if (adapter->netdev->flags & IFF_PROMISC) {
@@ -3954,16 +3987,21 @@ static void send_request_cap(struct ibmvnic_adapter *adapter, int retry)
                        crq.request_capability.capability =
                            cpu_to_be16(PROMISC_REQUESTED);
                        crq.request_capability.number = cpu_to_be64(1);
-                       atomic_inc(&adapter->running_cap_crqs);
+                       cap_reqs--;
                        ibmvnic_send_crq(adapter, &crq);
                }
        } else {
                crq.request_capability.capability =
                    cpu_to_be16(PROMISC_REQUESTED);
                crq.request_capability.number = cpu_to_be64(0);
-               atomic_inc(&adapter->running_cap_crqs);
+               cap_reqs--;
                ibmvnic_send_crq(adapter, &crq);
        }
+
+       /* Keep at end to catch any discrepancy between expected and actual
+        * CRQs sent.
+        */
+       WARN_ON(cap_reqs != 0);
 }
 
 static int pending_scrq(struct ibmvnic_adapter *adapter,
@@ -4357,118 +4395,132 @@ static void send_query_map(struct ibmvnic_adapter *adapter)
 static void send_query_cap(struct ibmvnic_adapter *adapter)
 {
        union ibmvnic_crq crq;
+       int cap_reqs;
+
+       /* We send out 25 QUERY_CAPABILITY CRQs below.  Initialize this count
+        * upfront. When the tasklet receives a response to all of these, it
+        * can send out the next protocol messaage (REQUEST_CAPABILITY).
+        */
+       cap_reqs = 25;
+
+       atomic_set(&adapter->running_cap_crqs, cap_reqs);
 
-       atomic_set(&adapter->running_cap_crqs, 0);
        memset(&crq, 0, sizeof(crq));
        crq.query_capability.first = IBMVNIC_CRQ_CMD;
        crq.query_capability.cmd = QUERY_CAPABILITY;
 
        crq.query_capability.capability = cpu_to_be16(MIN_TX_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MIN_RX_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MIN_RX_ADD_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MAX_TX_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MAX_RX_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MAX_RX_ADD_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability =
            cpu_to_be16(MIN_TX_ENTRIES_PER_SUBCRQ);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability =
            cpu_to_be16(MIN_RX_ADD_ENTRIES_PER_SUBCRQ);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability =
            cpu_to_be16(MAX_TX_ENTRIES_PER_SUBCRQ);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability =
            cpu_to_be16(MAX_RX_ADD_ENTRIES_PER_SUBCRQ);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(TCP_IP_OFFLOAD);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(PROMISC_SUPPORTED);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MIN_MTU);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MAX_MTU);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MAX_MULTICAST_FILTERS);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(VLAN_HEADER_INSERTION);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(RX_VLAN_HEADER_INSERTION);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MAX_TX_SG_ENTRIES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(RX_SG_SUPPORTED);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(OPT_TX_COMP_SUB_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(OPT_RX_COMP_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability =
                        cpu_to_be16(OPT_RX_BUFADD_Q_PER_RX_COMP_Q);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability =
                        cpu_to_be16(OPT_TX_ENTRIES_PER_SUBCRQ);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability =
                        cpu_to_be16(OPT_RXBA_ENTRIES_PER_SUBCRQ);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(TX_RX_DESC_REQ);
-       atomic_inc(&adapter->running_cap_crqs);
+
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
+
+       /* Keep at end to catch any discrepancy between expected and actual
+        * CRQs sent.
+        */
+       WARN_ON(cap_reqs != 0);
 }
 
 static void send_query_ip_offload(struct ibmvnic_adapter *adapter)
@@ -4772,6 +4824,8 @@ static void handle_request_cap_rsp(union ibmvnic_crq *crq,
        char *name;
 
        atomic_dec(&adapter->running_cap_crqs);
+       netdev_dbg(adapter->netdev, "Outstanding request-caps: %d\n",
+                  atomic_read(&adapter->running_cap_crqs));
        switch (be16_to_cpu(crq->request_capability_rsp.capability)) {
        case REQ_TX_QUEUES:
                req_value = &adapter->req_tx_queues;
@@ -4835,10 +4889,8 @@ static void handle_request_cap_rsp(union ibmvnic_crq *crq,
        }
 
        /* Done receiving requested capabilities, query IP offload support */
-       if (atomic_read(&adapter->running_cap_crqs) == 0) {
-               adapter->wait_capability = false;
+       if (atomic_read(&adapter->running_cap_crqs) == 0)
                send_query_ip_offload(adapter);
-       }
 }
 
 static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
@@ -5136,10 +5188,8 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,
        }
 
 out:
-       if (atomic_read(&adapter->running_cap_crqs) == 0) {
-               adapter->wait_capability = false;
+       if (atomic_read(&adapter->running_cap_crqs) == 0)
                send_request_cap(adapter, 0);
-       }
 }
 
 static int send_query_phys_parms(struct ibmvnic_adapter *adapter)
@@ -5435,33 +5485,21 @@ static void ibmvnic_tasklet(struct tasklet_struct *t)
        struct ibmvnic_crq_queue *queue = &adapter->crq;
        union ibmvnic_crq *crq;
        unsigned long flags;
-       bool done = false;
 
        spin_lock_irqsave(&queue->lock, flags);
-       while (!done) {
-               /* Pull all the valid messages off the CRQ */
-               while ((crq = ibmvnic_next_crq(adapter)) != NULL) {
-                       /* This barrier makes sure ibmvnic_next_crq()'s
-                        * crq->generic.first & IBMVNIC_CRQ_CMD_RSP is loaded
-                        * before ibmvnic_handle_crq()'s
-                        * switch(gen_crq->first) and switch(gen_crq->cmd).
-                        */
-                       dma_rmb();
-                       ibmvnic_handle_crq(crq, adapter);
-                       crq->generic.first = 0;
-               }
 
-               /* remain in tasklet until all
-                * capabilities responses are received
+       /* Pull all the valid messages off the CRQ */
+       while ((crq = ibmvnic_next_crq(adapter)) != NULL) {
+               /* This barrier makes sure ibmvnic_next_crq()'s
+                * crq->generic.first & IBMVNIC_CRQ_CMD_RSP is loaded
+                * before ibmvnic_handle_crq()'s
+                * switch(gen_crq->first) and switch(gen_crq->cmd).
                 */
-               if (!adapter->wait_capability)
-                       done = true;
+               dma_rmb();
+               ibmvnic_handle_crq(crq, adapter);
+               crq->generic.first = 0;
        }
-       /* if capabilities CRQ's were sent in this tasklet, the following
-        * tasklet must wait until all responses are received
-        */
-       if (atomic_read(&adapter->running_cap_crqs) != 0)
-               adapter->wait_capability = true;
+
        spin_unlock_irqrestore(&queue->lock, flags);
 }
 
index 4a8f36e..4a7a56f 100644 (file)
@@ -919,7 +919,6 @@ struct ibmvnic_adapter {
        int login_rsp_buf_sz;
 
        atomic_t running_cap_crqs;
-       bool wait_capability;
 
        struct ibmvnic_sub_crq_queue **tx_scrq ____cacheline_aligned;
        struct ibmvnic_sub_crq_queue **rx_scrq ____cacheline_aligned;
index c3def0e..8d06c9d 100644 (file)
@@ -115,7 +115,8 @@ enum e1000_boards {
        board_pch_lpt,
        board_pch_spt,
        board_pch_cnp,
-       board_pch_tgp
+       board_pch_tgp,
+       board_pch_adp
 };
 
 struct e1000_ps_page {
@@ -502,6 +503,7 @@ extern const struct e1000_info e1000_pch_lpt_info;
 extern const struct e1000_info e1000_pch_spt_info;
 extern const struct e1000_info e1000_pch_cnp_info;
 extern const struct e1000_info e1000_pch_tgp_info;
+extern const struct e1000_info e1000_pch_adp_info;
 extern const struct e1000_info e1000_es2_info;
 
 void e1000e_ptp_init(struct e1000_adapter *adapter);
index 5e4fc9b..c908c84 100644 (file)
@@ -6021,3 +6021,23 @@ const struct e1000_info e1000_pch_tgp_info = {
        .phy_ops                = &ich8_phy_ops,
        .nvm_ops                = &spt_nvm_ops,
 };
+
+const struct e1000_info e1000_pch_adp_info = {
+       .mac                    = e1000_pch_adp,
+       .flags                  = FLAG_IS_ICH
+                                 | FLAG_HAS_WOL
+                                 | FLAG_HAS_HW_TIMESTAMP
+                                 | FLAG_HAS_CTRLEXT_ON_LOAD
+                                 | FLAG_HAS_AMT
+                                 | FLAG_HAS_FLASH
+                                 | FLAG_HAS_JUMBO_FRAMES
+                                 | FLAG_APME_IN_WUC,
+       .flags2                 = FLAG2_HAS_PHY_STATS
+                                 | FLAG2_HAS_EEE,
+       .pba                    = 26,
+       .max_hw_frame_size      = 9022,
+       .get_variants           = e1000_get_variants_ich8lan,
+       .mac_ops                = &ich8_mac_ops,
+       .phy_ops                = &ich8_phy_ops,
+       .nvm_ops                = &spt_nvm_ops,
+};
index 635a959..a42aeb5 100644 (file)
@@ -52,6 +52,7 @@ static const struct e1000_info *e1000_info_tbl[] = {
        [board_pch_spt]         = &e1000_pch_spt_info,
        [board_pch_cnp]         = &e1000_pch_cnp_info,
        [board_pch_tgp]         = &e1000_pch_tgp_info,
+       [board_pch_adp]         = &e1000_pch_adp_info,
 };
 
 struct e1000_reg_info {
@@ -6341,7 +6342,8 @@ static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter)
        u32 mac_data;
        u16 phy_data;
 
-       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
+       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID &&
+           hw->mac.type >= e1000_pch_adp) {
                /* Request ME configure the device for S0ix */
                mac_data = er32(H2ME);
                mac_data |= E1000_H2ME_START_DPG;
@@ -6490,7 +6492,8 @@ static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter)
        u16 phy_data;
        u32 i = 0;
 
-       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
+       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID &&
+           hw->mac.type >= e1000_pch_adp) {
                /* Request ME unconfigure the device from S0ix */
                mac_data = er32(H2ME);
                mac_data &= ~E1000_H2ME_START_DPG;
@@ -7898,22 +7901,22 @@ static const struct pci_device_id e1000_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V14), board_pch_tgp },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM15), board_pch_tgp },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V15), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM23), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V23), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM16), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V16), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM17), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V17), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM22), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V22), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_LM18), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_V18), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_LM19), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_V19), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM20), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V20), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM21), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V21), board_pch_tgp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM23), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V23), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM16), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V16), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM17), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V17), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM22), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V22), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_LM18), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_V18), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_LM19), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_V19), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM20), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V20), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM21), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V21), board_pch_adp },
 
        { 0, 0, 0, 0, 0, 0, 0 } /* terminate list */
 };
index 4d939af..80c5cec 100644 (file)
@@ -144,6 +144,7 @@ enum i40e_state_t {
        __I40E_VIRTCHNL_OP_PENDING,
        __I40E_RECOVERY_MODE,
        __I40E_VF_RESETS_DISABLED,      /* disable resets during i40e_remove */
+       __I40E_IN_REMOVE,
        __I40E_VFS_RELEASING,
        /* This must be last as it determines the size of the BITMAP */
        __I40E_STATE_SIZE__,
@@ -174,7 +175,6 @@ enum i40e_interrupt_policy {
 
 struct i40e_lump_tracking {
        u16 num_entries;
-       u16 search_hint;
        u16 list[0];
 #define I40E_PILE_VALID_BIT  0x8000
 #define I40E_IWARP_IRQ_PILE_ID  (I40E_PILE_VALID_BIT - 2)
@@ -848,12 +848,12 @@ struct i40e_vsi {
        struct rtnl_link_stats64 net_stats_offsets;
        struct i40e_eth_stats eth_stats;
        struct i40e_eth_stats eth_stats_offsets;
-       u32 tx_restart;
-       u32 tx_busy;
+       u64 tx_restart;
+       u64 tx_busy;
        u64 tx_linearize;
        u64 tx_force_wb;
-       u32 rx_buf_failed;
-       u32 rx_page_failed;
+       u64 rx_buf_failed;
+       u64 rx_page_failed;
 
        /* These are containers of ring pointers, allocated at run-time */
        struct i40e_ring **rx_rings;
index 2c1b1da..1e57cc8 100644 (file)
@@ -240,7 +240,7 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                 (unsigned long int)vsi->net_stats_offsets.rx_compressed,
                 (unsigned long int)vsi->net_stats_offsets.tx_compressed);
        dev_info(&pf->pdev->dev,
-                "    tx_restart = %d, tx_busy = %d, rx_buf_failed = %d, rx_page_failed = %d\n",
+                "    tx_restart = %llu, tx_busy = %llu, rx_buf_failed = %llu, rx_page_failed = %llu\n",
                 vsi->tx_restart, vsi->tx_busy,
                 vsi->rx_buf_failed, vsi->rx_page_failed);
        rcu_read_lock();
index 2a3d8ae..0c4b7df 100644 (file)
@@ -196,10 +196,6 @@ int i40e_free_virt_mem_d(struct i40e_hw *hw, struct i40e_virt_mem *mem)
  * @id: an owner id to stick on the items assigned
  *
  * Returns the base item index of the lump, or negative for error
- *
- * The search_hint trick and lack of advanced fit-finding only work
- * because we're highly likely to have all the same size lump requests.
- * Linear search time and any fragmentation should be minimal.
  **/
 static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
                         u16 needed, u16 id)
@@ -214,8 +210,21 @@ static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
                return -EINVAL;
        }
 
-       /* start the linear search with an imperfect hint */
-       i = pile->search_hint;
+       /* Allocate last queue in the pile for FDIR VSI queue
+        * so it doesn't fragment the qp_pile
+        */
+       if (pile == pf->qp_pile && pf->vsi[id]->type == I40E_VSI_FDIR) {
+               if (pile->list[pile->num_entries - 1] & I40E_PILE_VALID_BIT) {
+                       dev_err(&pf->pdev->dev,
+                               "Cannot allocate queue %d for I40E_VSI_FDIR\n",
+                               pile->num_entries - 1);
+                       return -ENOMEM;
+               }
+               pile->list[pile->num_entries - 1] = id | I40E_PILE_VALID_BIT;
+               return pile->num_entries - 1;
+       }
+
+       i = 0;
        while (i < pile->num_entries) {
                /* skip already allocated entries */
                if (pile->list[i] & I40E_PILE_VALID_BIT) {
@@ -234,7 +243,6 @@ static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
                        for (j = 0; j < needed; j++)
                                pile->list[i+j] = id | I40E_PILE_VALID_BIT;
                        ret = i;
-                       pile->search_hint = i + j;
                        break;
                }
 
@@ -257,7 +265,7 @@ static int i40e_put_lump(struct i40e_lump_tracking *pile, u16 index, u16 id)
 {
        int valid_id = (id | I40E_PILE_VALID_BIT);
        int count = 0;
-       int i;
+       u16 i;
 
        if (!pile || index >= pile->num_entries)
                return -EINVAL;
@@ -269,8 +277,6 @@ static int i40e_put_lump(struct i40e_lump_tracking *pile, u16 index, u16 id)
                count++;
        }
 
-       if (count && index < pile->search_hint)
-               pile->search_hint = index;
 
        return count;
 }
@@ -772,9 +778,9 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi)
        struct rtnl_link_stats64 *ns;   /* netdev stats */
        struct i40e_eth_stats *oes;
        struct i40e_eth_stats *es;     /* device's eth stats */
-       u32 tx_restart, tx_busy;
+       u64 tx_restart, tx_busy;
        struct i40e_ring *p;
-       u32 rx_page, rx_buf;
+       u64 rx_page, rx_buf;
        u64 bytes, packets;
        unsigned int start;
        u64 tx_linearize;
@@ -5366,7 +5372,15 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc,
        /* There is no need to reset BW when mqprio mode is on.  */
        if (pf->flags & I40E_FLAG_TC_MQPRIO)
                return 0;
-       if (!vsi->mqprio_qopt.qopt.hw && !(pf->flags & I40E_FLAG_DCB_ENABLED)) {
+
+       if (!vsi->mqprio_qopt.qopt.hw) {
+               if (pf->flags & I40E_FLAG_DCB_ENABLED)
+                       goto skip_reset;
+
+               if (IS_ENABLED(CONFIG_I40E_DCB) &&
+                   i40e_dcb_hw_get_num_tc(&pf->hw) == 1)
+                       goto skip_reset;
+
                ret = i40e_set_bw_limit(vsi, vsi->seid, 0);
                if (ret)
                        dev_info(&pf->pdev->dev,
@@ -5374,6 +5388,8 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc,
                                 vsi->seid);
                return ret;
        }
+
+skip_reset:
        memset(&bw_data, 0, sizeof(bw_data));
        bw_data.tc_valid_bits = enabled_tc;
        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
@@ -10574,15 +10590,9 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
        }
        i40e_get_oem_version(&pf->hw);
 
-       if (test_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state) &&
-           ((hw->aq.fw_maj_ver == 4 && hw->aq.fw_min_ver <= 33) ||
-            hw->aq.fw_maj_ver < 4) && hw->mac.type == I40E_MAC_XL710) {
-               /* The following delay is necessary for 4.33 firmware and older
-                * to recover after EMP reset. 200 ms should suffice but we
-                * put here 300 ms to be sure that FW is ready to operate
-                * after reset.
-                */
-               mdelay(300);
+       if (test_and_clear_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state)) {
+               /* The following delay is necessary for firmware update. */
+               mdelay(1000);
        }
 
        /* re-verify the eeprom if we just had an EMP reset */
@@ -10853,6 +10863,9 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit,
                                   bool lock_acquired)
 {
        int ret;
+
+       if (test_bit(__I40E_IN_REMOVE, pf->state))
+               return;
        /* Now we wait for GRST to settle out.
         * We don't have to delete the VEBs or VSIs from the hw switch
         * because the reset will make them disappear.
@@ -11792,7 +11805,6 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf)
                return -ENOMEM;
 
        pf->irq_pile->num_entries = vectors;
-       pf->irq_pile->search_hint = 0;
 
        /* track first vector for misc interrupts, ignore return */
        (void)i40e_get_lump(pf, pf->irq_pile, 1, I40E_PILE_VALID_BIT - 1);
@@ -12213,6 +12225,8 @@ int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count)
 
                vsi->req_queue_pairs = queue_count;
                i40e_prep_for_reset(pf);
+               if (test_bit(__I40E_IN_REMOVE, pf->state))
+                       return pf->alloc_rss_size;
 
                pf->alloc_rss_size = new_rss_size;
 
@@ -12595,7 +12609,6 @@ static int i40e_sw_init(struct i40e_pf *pf)
                goto sw_init_done;
        }
        pf->qp_pile->num_entries = pf->hw.func_caps.num_tx_qp;
-       pf->qp_pile->search_hint = 0;
 
        pf->tx_timeout_recovery_level = 1;
 
@@ -13040,6 +13053,10 @@ static int i40e_xdp_setup(struct i40e_vsi *vsi, struct bpf_prog *prog,
        if (need_reset)
                i40e_prep_for_reset(pf);
 
+       /* VSI shall be deleted in a moment, just return EINVAL */
+       if (test_bit(__I40E_IN_REMOVE, pf->state))
+               return -EINVAL;
+
        old_prog = xchg(&vsi->xdp_prog, prog);
 
        if (need_reset) {
@@ -15930,8 +15947,13 @@ static void i40e_remove(struct pci_dev *pdev)
        i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), 0);
        i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), 0);
 
-       while (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
+       /* Grab __I40E_RESET_RECOVERY_PENDING and set __I40E_IN_REMOVE
+        * flags, once they are set, i40e_rebuild should not be called as
+        * i40e_prep_for_reset always returns early.
+        */
+       while (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
                usleep_range(1000, 2000);
+       set_bit(__I40E_IN_REMOVE, pf->state);
 
        if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
                set_bit(__I40E_VF_RESETS_DISABLED, pf->state);
@@ -16130,6 +16152,9 @@ static void i40e_pci_error_reset_done(struct pci_dev *pdev)
 {
        struct i40e_pf *pf = pci_get_drvdata(pdev);
 
+       if (test_bit(__I40E_IN_REMOVE, pf->state))
+               return;
+
        i40e_reset_and_rebuild(pf, false, false);
 }
 
index 8d0588a..1908eed 100644 (file)
 #define I40E_VFINT_DYN_CTLN(_INTVF) (0x00024800 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: VFR */
 #define I40E_VFINT_DYN_CTLN_CLEARPBA_SHIFT 1
 #define I40E_VFINT_DYN_CTLN_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_CLEARPBA_SHIFT)
+#define I40E_VFINT_ICR0_ADMINQ_SHIFT 30
+#define I40E_VFINT_ICR0_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ADMINQ_SHIFT)
+#define I40E_VFINT_ICR0_ENA(_VF) (0x0002C000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */
 #define I40E_VPINT_AEQCTL(_VF) (0x0002B800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */
 #define I40E_VPINT_AEQCTL_MSIX_INDX_SHIFT 0
 #define I40E_VPINT_AEQCTL_ITR_INDX_SHIFT 11
index b785d09..dfdb6e7 100644 (file)
@@ -1376,6 +1376,32 @@ static i40e_status i40e_config_vf_promiscuous_mode(struct i40e_vf *vf,
        return aq_ret;
 }
 
+/**
+ * i40e_sync_vfr_reset
+ * @hw: pointer to hw struct
+ * @vf_id: VF identifier
+ *
+ * Before trigger hardware reset, we need to know if no other process has
+ * reserved the hardware for any reset operations. This check is done by
+ * examining the status of the RSTAT1 register used to signal the reset.
+ **/
+static int i40e_sync_vfr_reset(struct i40e_hw *hw, int vf_id)
+{
+       u32 reg;
+       int i;
+
+       for (i = 0; i < I40E_VFR_WAIT_COUNT; i++) {
+               reg = rd32(hw, I40E_VFINT_ICR0_ENA(vf_id)) &
+                          I40E_VFINT_ICR0_ADMINQ_MASK;
+               if (reg)
+                       return 0;
+
+               usleep_range(100, 200);
+       }
+
+       return -EAGAIN;
+}
+
 /**
  * i40e_trigger_vf_reset
  * @vf: pointer to the VF structure
@@ -1390,9 +1416,11 @@ static void i40e_trigger_vf_reset(struct i40e_vf *vf, bool flr)
        struct i40e_pf *pf = vf->pf;
        struct i40e_hw *hw = &pf->hw;
        u32 reg, reg_idx, bit_idx;
+       bool vf_active;
+       u32 radq;
 
        /* warn the VF */
-       clear_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states);
+       vf_active = test_and_clear_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states);
 
        /* Disable VF's configuration API during reset. The flag is re-enabled
         * in i40e_alloc_vf_res(), when it's safe again to access VF's VSI.
@@ -1406,7 +1434,19 @@ static void i40e_trigger_vf_reset(struct i40e_vf *vf, bool flr)
         * just need to clean up, so don't hit the VFRTRIG register.
         */
        if (!flr) {
-               /* reset VF using VPGEN_VFRTRIG reg */
+               /* Sync VFR reset before trigger next one */
+               radq = rd32(hw, I40E_VFINT_ICR0_ENA(vf->vf_id)) &
+                           I40E_VFINT_ICR0_ADMINQ_MASK;
+               if (vf_active && !radq)
+                       /* waiting for finish reset by virtual driver */
+                       if (i40e_sync_vfr_reset(hw, vf->vf_id))
+                               dev_info(&pf->pdev->dev,
+                                        "Reset VF %d never finished\n",
+                               vf->vf_id);
+
+               /* Reset VF using VPGEN_VFRTRIG reg. It is also setting
+                * in progress state in rstat1 register.
+                */
                reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id));
                reg |= I40E_VPGEN_VFRTRIG_VFSWR_MASK;
                wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg);
@@ -2617,6 +2657,59 @@ error_param:
                                       aq_ret);
 }
 
+/**
+ * i40e_check_enough_queue - find big enough queue number
+ * @vf: pointer to the VF info
+ * @needed: the number of items needed
+ *
+ * Returns the base item index of the queue, or negative for error
+ **/
+static int i40e_check_enough_queue(struct i40e_vf *vf, u16 needed)
+{
+       unsigned int  i, cur_queues, more, pool_size;
+       struct i40e_lump_tracking *pile;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi;
+
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       cur_queues = vsi->alloc_queue_pairs;
+
+       /* if current allocated queues are enough for need */
+       if (cur_queues >= needed)
+               return vsi->base_queue;
+
+       pile = pf->qp_pile;
+       if (cur_queues > 0) {
+               /* if the allocated queues are not zero
+                * just check if there are enough queues for more
+                * behind the allocated queues.
+                */
+               more = needed - cur_queues;
+               for (i = vsi->base_queue + cur_queues;
+                       i < pile->num_entries; i++) {
+                       if (pile->list[i] & I40E_PILE_VALID_BIT)
+                               break;
+
+                       if (more-- == 1)
+                               /* there is enough */
+                               return vsi->base_queue;
+               }
+       }
+
+       pool_size = 0;
+       for (i = 0; i < pile->num_entries; i++) {
+               if (pile->list[i] & I40E_PILE_VALID_BIT) {
+                       pool_size = 0;
+                       continue;
+               }
+               if (needed <= ++pool_size)
+                       /* there is enough */
+                       return i;
+       }
+
+       return -ENOMEM;
+}
+
 /**
  * i40e_vc_request_queues_msg
  * @vf: pointer to the VF info
@@ -2651,6 +2744,12 @@ static int i40e_vc_request_queues_msg(struct i40e_vf *vf, u8 *msg)
                         req_pairs - cur_pairs,
                         pf->queues_left);
                vfres->num_queue_pairs = pf->queues_left + cur_pairs;
+       } else if (i40e_check_enough_queue(vf, req_pairs) < 0) {
+               dev_warn(&pf->pdev->dev,
+                        "VF %d requested %d more queues, but there is not enough for it.\n",
+                        vf->vf_id,
+                        req_pairs - cur_pairs);
+               vfres->num_queue_pairs = cur_pairs;
        } else {
                /* successful request */
                vf->num_req_queues = req_pairs;
index 49575a6..03c42fd 100644 (file)
@@ -19,6 +19,7 @@
 #define I40E_MAX_VF_PROMISC_FLAGS      3
 
 #define I40E_VF_STATE_WAIT_COUNT       20
+#define I40E_VFR_WAIT_COUNT            100
 
 /* Various queue ctrls */
 enum i40e_queue_ctrl {
index 4e16d18..a9fa701 100644 (file)
@@ -483,6 +483,7 @@ enum ice_pf_flags {
        ICE_FLAG_VF_TRUE_PROMISC_ENA,
        ICE_FLAG_MDD_AUTO_RESET_VF,
        ICE_FLAG_LINK_LENIENT_MODE_ENA,
+       ICE_FLAG_PLUG_AUX_DEV,
        ICE_PF_FLAGS_NBITS              /* must be last */
 };
 
@@ -887,7 +888,7 @@ static inline void ice_set_rdma_cap(struct ice_pf *pf)
        if (pf->hw.func_caps.common_cap.rdma && pf->num_rdma_msix) {
                set_bit(ICE_FLAG_RDMA_ENA, pf->flags);
                set_bit(ICE_FLAG_AUX_ENA, pf->flags);
-               ice_plug_aux_dev(pf);
+               set_bit(ICE_FLAG_PLUG_AUX_DEV, pf->flags);
        }
 }
 
index 408d15a..a6d7d3e 100644 (file)
@@ -3342,7 +3342,8 @@ ice_cfg_phy_fec(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg,
            !ice_fw_supports_report_dflt_cfg(hw)) {
                struct ice_link_default_override_tlv tlv;
 
-               if (ice_get_link_default_override(&tlv, pi))
+               status = ice_get_link_default_override(&tlv, pi);
+               if (status)
                        goto out;
 
                if (!(tlv.options & ICE_LINK_OVERRIDE_STRICT_MODE) &&
index e375ac8..4f954db 100644 (file)
@@ -204,17 +204,39 @@ ice_lag_unlink(struct ice_lag *lag,
                lag->upper_netdev = NULL;
        }
 
-       if (lag->peer_netdev) {
-               dev_put(lag->peer_netdev);
-               lag->peer_netdev = NULL;
-       }
-
+       lag->peer_netdev = NULL;
        ice_set_sriov_cap(pf);
        ice_set_rdma_cap(pf);
        lag->bonded = false;
        lag->role = ICE_LAG_NONE;
 }
 
+/**
+ * ice_lag_unregister - handle netdev unregister events
+ * @lag: LAG info struct
+ * @netdev: netdev reporting the event
+ */
+static void ice_lag_unregister(struct ice_lag *lag, struct net_device *netdev)
+{
+       struct ice_pf *pf = lag->pf;
+
+       /* check to see if this event is for this netdev
+        * check that we are in an aggregate
+        */
+       if (netdev != lag->netdev || !lag->bonded)
+               return;
+
+       if (lag->upper_netdev) {
+               dev_put(lag->upper_netdev);
+               lag->upper_netdev = NULL;
+               ice_set_sriov_cap(pf);
+               ice_set_rdma_cap(pf);
+       }
+       /* perform some cleanup in case we come back */
+       lag->bonded = false;
+       lag->role = ICE_LAG_NONE;
+}
+
 /**
  * ice_lag_changeupper_event - handle LAG changeupper event
  * @lag: LAG info struct
@@ -307,7 +329,7 @@ ice_lag_event_handler(struct notifier_block *notif_blk, unsigned long event,
                ice_lag_info_event(lag, ptr);
                break;
        case NETDEV_UNREGISTER:
-               ice_lag_unlink(lag, ptr);
+               ice_lag_unregister(lag, netdev);
                break;
        default:
                break;
index d981dc6..85a6128 100644 (file)
@@ -568,6 +568,7 @@ struct ice_tx_ctx_desc {
                        (0x3FFFFULL << ICE_TXD_CTX_QW1_TSO_LEN_S)
 
 #define ICE_TXD_CTX_QW1_MSS_S  50
+#define ICE_TXD_CTX_MIN_MSS    64
 
 #define ICE_TXD_CTX_QW1_VSI_S  50
 #define ICE_TXD_CTX_QW1_VSI_M  (0x3FFULL << ICE_TXD_CTX_QW1_VSI_S)
index 3081443..17a9bb4 100644 (file)
@@ -2253,6 +2253,9 @@ static void ice_service_task(struct work_struct *work)
                return;
        }
 
+       if (test_and_clear_bit(ICE_FLAG_PLUG_AUX_DEV, pf->flags))
+               ice_plug_aux_dev(pf);
+
        ice_clean_adminq_subtask(pf);
        ice_check_media_subtask(pf);
        ice_check_for_hang_subtask(pf);
@@ -8525,6 +8528,7 @@ ice_features_check(struct sk_buff *skb,
                   struct net_device __always_unused *netdev,
                   netdev_features_t features)
 {
+       bool gso = skb_is_gso(skb);
        size_t len;
 
        /* No point in doing any of this if neither checksum nor GSO are
@@ -8537,24 +8541,32 @@ ice_features_check(struct sk_buff *skb,
        /* We cannot support GSO if the MSS is going to be less than
         * 64 bytes. If it is then we need to drop support for GSO.
         */
-       if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_size < 64))
+       if (gso && (skb_shinfo(skb)->gso_size < ICE_TXD_CTX_MIN_MSS))
                features &= ~NETIF_F_GSO_MASK;
 
-       len = skb_network_header(skb) - skb->data;
+       len = skb_network_offset(skb);
        if (len > ICE_TXD_MACLEN_MAX || len & 0x1)
                goto out_rm_features;
 
-       len = skb_transport_header(skb) - skb_network_header(skb);
+       len = skb_network_header_len(skb);
        if (len > ICE_TXD_IPLEN_MAX || len & 0x1)
                goto out_rm_features;
 
        if (skb->encapsulation) {
-               len = skb_inner_network_header(skb) - skb_transport_header(skb);
-               if (len > ICE_TXD_L4LEN_MAX || len & 0x1)
-                       goto out_rm_features;
+               /* this must work for VXLAN frames AND IPIP/SIT frames, and in
+                * the case of IPIP frames, the transport header pointer is
+                * after the inner header! So check to make sure that this
+                * is a GRE or UDP_TUNNEL frame before doing that math.
+                */
+               if (gso && (skb_shinfo(skb)->gso_type &
+                           (SKB_GSO_GRE | SKB_GSO_UDP_TUNNEL))) {
+                       len = skb_inner_network_header(skb) -
+                             skb_transport_header(skb);
+                       if (len > ICE_TXD_L4LEN_MAX || len & 0x1)
+                               goto out_rm_features;
+               }
 
-               len = skb_inner_transport_header(skb) -
-                     skb_inner_network_header(skb);
+               len = skb_inner_network_header_len(skb);
                if (len > ICE_TXD_IPLEN_MAX || len & 0x1)
                        goto out_rm_features;
        }
index 0015fcf..0f293ac 100644 (file)
@@ -1984,14 +1984,15 @@ static void ixgbevf_set_rx_buffer_len(struct ixgbevf_adapter *adapter,
        if (adapter->flags & IXGBEVF_FLAGS_LEGACY_RX)
                return;
 
-       set_ring_build_skb_enabled(rx_ring);
+       if (PAGE_SIZE < 8192)
+               if (max_frame > IXGBEVF_MAX_FRAME_BUILD_SKB)
+                       set_ring_uses_large_buffer(rx_ring);
 
-       if (PAGE_SIZE < 8192) {
-               if (max_frame <= IXGBEVF_MAX_FRAME_BUILD_SKB)
-                       return;
+       /* 82599 can't rely on RXDCTL.RLPML to restrict the size of the frame */
+       if (adapter->hw.mac.type == ixgbe_mac_82599_vf && !ring_uses_large_buffer(rx_ring))
+               return;
 
-               set_ring_uses_large_buffer(rx_ring);
-       }
+       set_ring_build_skb_enabled(rx_ring);
 }
 
 /**
index f99adbf..04345b9 100644 (file)
@@ -17,7 +17,7 @@ if NET_VENDOR_LITEX
 
 config LITEX_LITEETH
        tristate "LiteX Ethernet support"
-       depends on OF
+       depends on OF && HAS_IOMEM
        help
          If you wish to compile a kernel for hardware with a LiteX LiteEth
          device then you should answer Y to this.
index 186d00a..3631d61 100644 (file)
@@ -1570,6 +1570,8 @@ static struct mac_ops     cgx_mac_ops    = {
        .mac_enadis_pause_frm =         cgx_lmac_enadis_pause_frm,
        .mac_pause_frm_config =         cgx_lmac_pause_frm_config,
        .mac_enadis_ptp_config =        cgx_lmac_ptp_config,
+       .mac_rx_tx_enable =             cgx_lmac_rx_tx_enable,
+       .mac_tx_enable =                cgx_lmac_tx_enable,
 };
 
 static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id)
index fc6e742..b33e7d1 100644 (file)
@@ -107,6 +107,9 @@ struct mac_ops {
        void                    (*mac_enadis_ptp_config)(void  *cgxd,
                                                         int lmac_id,
                                                         bool enable);
+
+       int                     (*mac_rx_tx_enable)(void *cgxd, int lmac_id, bool enable);
+       int                     (*mac_tx_enable)(void *cgxd, int lmac_id, bool enable);
 };
 
 struct cgx {
index 4e79e91..58e2aee 100644 (file)
@@ -732,6 +732,7 @@ enum nix_af_status {
        NIX_AF_ERR_BANDPROF_INVAL_REQ  = -428,
        NIX_AF_ERR_CQ_CTX_WRITE_ERR  = -429,
        NIX_AF_ERR_AQ_CTX_RETRY_WRITE  = -430,
+       NIX_AF_ERR_LINK_CREDITS  = -431,
 };
 
 /* For NIX RX vtag action  */
index 0fe7ad3..4180376 100644 (file)
@@ -185,7 +185,6 @@ enum npc_kpu_parser_state {
        NPC_S_KPU2_QINQ,
        NPC_S_KPU2_ETAG,
        NPC_S_KPU2_EXDSA,
-       NPC_S_KPU2_NGIO,
        NPC_S_KPU2_CPT_CTAG,
        NPC_S_KPU2_CPT_QINQ,
        NPC_S_KPU3_CTAG,
@@ -212,6 +211,7 @@ enum npc_kpu_parser_state {
        NPC_S_KPU5_NSH,
        NPC_S_KPU5_CPT_IP,
        NPC_S_KPU5_CPT_IP6,
+       NPC_S_KPU5_NGIO,
        NPC_S_KPU6_IP6_EXT,
        NPC_S_KPU6_IP6_HOP_DEST,
        NPC_S_KPU6_IP6_ROUT,
@@ -1120,15 +1120,6 @@ static struct npc_kpu_profile_cam kpu1_cam_entries[] = {
                0x0000,
                0x0000,
        },
-       {
-               NPC_S_KPU1_ETHER, 0xff,
-               NPC_ETYPE_CTAG,
-               0xffff,
-               NPC_ETYPE_NGIO,
-               0xffff,
-               0x0000,
-               0x0000,
-       },
        {
                NPC_S_KPU1_ETHER, 0xff,
                NPC_ETYPE_CTAG,
@@ -1966,6 +1957,15 @@ static struct npc_kpu_profile_cam kpu2_cam_entries[] = {
                0x0000,
                0x0000,
        },
+       {
+               NPC_S_KPU2_CTAG, 0xff,
+               NPC_ETYPE_NGIO,
+               0xffff,
+               0x0000,
+               0x0000,
+               0x0000,
+               0x0000,
+       },
        {
                NPC_S_KPU2_CTAG, 0xff,
                NPC_ETYPE_PPPOE,
@@ -2749,15 +2749,6 @@ static struct npc_kpu_profile_cam kpu2_cam_entries[] = {
                0x0000,
                0x0000,
        },
-       {
-               NPC_S_KPU2_NGIO, 0xff,
-               0x0000,
-               0x0000,
-               0x0000,
-               0x0000,
-               0x0000,
-               0x0000,
-       },
        {
                NPC_S_KPU2_CPT_CTAG, 0xff,
                NPC_ETYPE_IP,
@@ -5089,6 +5080,15 @@ static struct npc_kpu_profile_cam kpu5_cam_entries[] = {
                0x0000,
                0x0000,
        },
+       {
+               NPC_S_KPU5_NGIO, 0xff,
+               0x0000,
+               0x0000,
+               0x0000,
+               0x0000,
+               0x0000,
+               0x0000,
+       },
        {
                NPC_S_NA, 0X00,
                0x0000,
@@ -8422,14 +8422,6 @@ static struct npc_kpu_profile_action kpu1_action_entries[] = {
                0,
                0, 0, 0, 0,
        },
-       {
-               NPC_ERRLEV_RE, NPC_EC_NOERR,
-               8, 12, 0, 0, 0,
-               NPC_S_KPU2_NGIO, 12, 1,
-               NPC_LID_LA, NPC_LT_LA_ETHER,
-               0,
-               0, 0, 0, 0,
-       },
        {
                NPC_ERRLEV_RE, NPC_EC_NOERR,
                8, 12, 0, 0, 0,
@@ -9194,6 +9186,14 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = {
                0,
                0, 0, 0, 0,
        },
+       {
+               NPC_ERRLEV_RE, NPC_EC_NOERR,
+               0, 0, 0, 2, 0,
+               NPC_S_KPU5_NGIO, 6, 1,
+               NPC_LID_LB, NPC_LT_LB_CTAG,
+               0,
+               0, 0, 0, 0,
+       },
        {
                NPC_ERRLEV_RE, NPC_EC_NOERR,
                8, 0, 6, 2, 0,
@@ -9890,14 +9890,6 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = {
                NPC_F_LB_U_UNK_ETYPE | NPC_F_LB_L_EXDSA,
                0, 0, 0, 0,
        },
-       {
-               NPC_ERRLEV_RE, NPC_EC_NOERR,
-               0, 0, 0, 0, 1,
-               NPC_S_NA, 0, 1,
-               NPC_LID_LC, NPC_LT_LC_NGIO,
-               0,
-               0, 0, 0, 0,
-       },
        {
                NPC_ERRLEV_RE, NPC_EC_NOERR,
                8, 0, 6, 2, 0,
@@ -11973,6 +11965,14 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = {
                0,
                0, 0, 0, 0,
        },
+       {
+               NPC_ERRLEV_RE, NPC_EC_NOERR,
+               0, 0, 0, 0, 1,
+               NPC_S_NA, 0, 1,
+               NPC_LID_LC, NPC_LT_LC_NGIO,
+               0,
+               0, 0, 0, 0,
+       },
        {
                NPC_ERRLEV_LC, NPC_EC_UNK,
                0, 0, 0, 0, 1,
index e695fa0..9ea2f6a 100644 (file)
@@ -30,6 +30,8 @@ static struct mac_ops rpm_mac_ops   = {
        .mac_enadis_pause_frm =         rpm_lmac_enadis_pause_frm,
        .mac_pause_frm_config =         rpm_lmac_pause_frm_config,
        .mac_enadis_ptp_config =        rpm_lmac_ptp_config,
+       .mac_rx_tx_enable =             rpm_lmac_rx_tx_enable,
+       .mac_tx_enable =                rpm_lmac_tx_enable,
 };
 
 struct mac_ops *rpm_get_mac_ops(void)
@@ -54,6 +56,43 @@ int rpm_get_nr_lmacs(void *rpmd)
        return hweight8(rpm_read(rpm, 0, CGXX_CMRX_RX_LMACS) & 0xFULL);
 }
 
+int rpm_lmac_tx_enable(void *rpmd, int lmac_id, bool enable)
+{
+       rpm_t *rpm = rpmd;
+       u64 cfg, last;
+
+       if (!is_lmac_valid(rpm, lmac_id))
+               return -ENODEV;
+
+       cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
+       last = cfg;
+       if (enable)
+               cfg |= RPM_TX_EN;
+       else
+               cfg &= ~(RPM_TX_EN);
+
+       if (cfg != last)
+               rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
+       return !!(last & RPM_TX_EN);
+}
+
+int rpm_lmac_rx_tx_enable(void *rpmd, int lmac_id, bool enable)
+{
+       rpm_t *rpm = rpmd;
+       u64 cfg;
+
+       if (!is_lmac_valid(rpm, lmac_id))
+               return -ENODEV;
+
+       cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
+       if (enable)
+               cfg |= RPM_RX_EN | RPM_TX_EN;
+       else
+               cfg &= ~(RPM_RX_EN | RPM_TX_EN);
+       rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
+       return 0;
+}
+
 void rpm_lmac_enadis_rx_pause_fwding(void *rpmd, int lmac_id, bool enable)
 {
        rpm_t *rpm = rpmd;
@@ -252,23 +291,20 @@ int rpm_lmac_internal_loopback(void *rpmd, int lmac_id, bool enable)
        if (!rpm || lmac_id >= rpm->lmac_count)
                return -ENODEV;
        lmac_type = rpm->mac_ops->get_lmac_type(rpm, lmac_id);
-       if (lmac_type == LMAC_MODE_100G_R) {
-               cfg = rpm_read(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1);
-
-               if (enable)
-                       cfg |= RPMX_MTI_PCS_LBK;
-               else
-                       cfg &= ~RPMX_MTI_PCS_LBK;
-               rpm_write(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1, cfg);
-       } else {
-               cfg = rpm_read(rpm, lmac_id, RPMX_MTI_LPCSX_CONTROL1);
-               if (enable)
-                       cfg |= RPMX_MTI_PCS_LBK;
-               else
-                       cfg &= ~RPMX_MTI_PCS_LBK;
-               rpm_write(rpm, lmac_id, RPMX_MTI_LPCSX_CONTROL1, cfg);
+
+       if (lmac_type == LMAC_MODE_QSGMII || lmac_type == LMAC_MODE_SGMII) {
+               dev_err(&rpm->pdev->dev, "loopback not supported for LPC mode\n");
+               return 0;
        }
 
+       cfg = rpm_read(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1);
+
+       if (enable)
+               cfg |= RPMX_MTI_PCS_LBK;
+       else
+               cfg &= ~RPMX_MTI_PCS_LBK;
+       rpm_write(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1, cfg);
+
        return 0;
 }
 
index 57c8a68..ff58031 100644 (file)
@@ -43,6 +43,8 @@
 #define RPMX_MTI_STAT_DATA_HI_CDC            0x10038
 
 #define RPM_LMAC_FWI                   0xa
+#define RPM_TX_EN                      BIT_ULL(0)
+#define RPM_RX_EN                      BIT_ULL(1)
 
 /* Function Declarations */
 int rpm_get_nr_lmacs(void *rpmd);
@@ -57,4 +59,6 @@ int rpm_lmac_enadis_pause_frm(void *rpmd, int lmac_id, u8 tx_pause,
 int rpm_get_tx_stats(void *rpmd, int lmac_id, int idx, u64 *tx_stat);
 int rpm_get_rx_stats(void *rpmd, int lmac_id, int idx, u64 *rx_stat);
 void rpm_lmac_ptp_config(void *rpmd, int lmac_id, bool enable);
+int rpm_lmac_rx_tx_enable(void *rpmd, int lmac_id, bool enable);
+int rpm_lmac_tx_enable(void *rpmd, int lmac_id, bool enable);
 #endif /* RPM_H */
index 3ca6b94..54e1b27 100644 (file)
@@ -520,8 +520,11 @@ static void rvu_block_reset(struct rvu *rvu, int blkaddr, u64 rst_reg)
 
        rvu_write64(rvu, blkaddr, rst_reg, BIT_ULL(0));
        err = rvu_poll_reg(rvu, blkaddr, rst_reg, BIT_ULL(63), true);
-       if (err)
-               dev_err(rvu->dev, "HW block:%d reset failed\n", blkaddr);
+       if (err) {
+               dev_err(rvu->dev, "HW block:%d reset timeout retrying again\n", blkaddr);
+               while (rvu_poll_reg(rvu, blkaddr, rst_reg, BIT_ULL(63), true) == -EBUSY)
+                       ;
+       }
 }
 
 static void rvu_reset_all_blocks(struct rvu *rvu)
index 66e45d7..5ed94cf 100644 (file)
@@ -806,6 +806,7 @@ bool is_mac_feature_supported(struct rvu *rvu, int pf, int feature);
 u32  rvu_cgx_get_fifolen(struct rvu *rvu);
 void *rvu_first_cgx_pdata(struct rvu *rvu);
 int cgxlmac_to_pf(struct rvu *rvu, int cgx_id, int lmac_id);
+int rvu_cgx_config_tx(void *cgxd, int lmac_id, bool enable);
 
 int npc_get_nixlf_mcam_index(struct npc_mcam *mcam, u16 pcifunc, int nixlf,
                             int type);
index 2ca182a..8a7ac5a 100644 (file)
@@ -441,16 +441,26 @@ void rvu_cgx_enadis_rx_bp(struct rvu *rvu, int pf, bool enable)
 int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start)
 {
        int pf = rvu_get_pf(pcifunc);
+       struct mac_ops *mac_ops;
        u8 cgx_id, lmac_id;
+       void *cgxd;
 
        if (!is_cgx_config_permitted(rvu, pcifunc))
                return LMAC_AF_ERR_PERM_DENIED;
 
        rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+       cgxd = rvu_cgx_pdata(cgx_id, rvu);
+       mac_ops = get_mac_ops(cgxd);
+
+       return mac_ops->mac_rx_tx_enable(cgxd, lmac_id, start);
+}
 
-       cgx_lmac_rx_tx_enable(rvu_cgx_pdata(cgx_id, rvu), lmac_id, start);
+int rvu_cgx_config_tx(void *cgxd, int lmac_id, bool enable)
+{
+       struct mac_ops *mac_ops;
 
-       return 0;
+       mac_ops = get_mac_ops(cgxd);
+       return mac_ops->mac_tx_enable(cgxd, lmac_id, enable);
 }
 
 void rvu_cgx_disable_dmac_entries(struct rvu *rvu, u16 pcifunc)
index a09a507..d1eddb7 100644 (file)
@@ -1224,6 +1224,8 @@ static void print_nix_cn10k_sq_ctx(struct seq_file *m,
        seq_printf(m, "W3: head_offset\t\t\t%d\nW3: smenq_next_sqb_vld\t\t%d\n\n",
                   sq_ctx->head_offset, sq_ctx->smenq_next_sqb_vld);
 
+       seq_printf(m, "W3: smq_next_sq_vld\t\t%d\nW3: smq_pend\t\t\t%d\n",
+                  sq_ctx->smq_next_sq_vld, sq_ctx->smq_pend);
        seq_printf(m, "W4: next_sqb \t\t\t%llx\n\n", sq_ctx->next_sqb);
        seq_printf(m, "W5: tail_sqb \t\t\t%llx\n\n", sq_ctx->tail_sqb);
        seq_printf(m, "W6: smenq_sqb \t\t\t%llx\n\n", sq_ctx->smenq_sqb);
index d8b1948..97fb619 100644 (file)
@@ -512,11 +512,11 @@ static int rvu_nix_get_bpid(struct rvu *rvu, struct nix_bp_cfg_req *req,
        cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST);
        lmac_chan_cnt = cfg & 0xFF;
 
-       cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST1);
-       sdp_chan_cnt = cfg & 0xFFF;
-
        cgx_bpid_cnt = hw->cgx_links * lmac_chan_cnt;
        lbk_bpid_cnt = hw->lbk_links * ((cfg >> 16) & 0xFF);
+
+       cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST1);
+       sdp_chan_cnt = cfg & 0xFFF;
        sdp_bpid_cnt = hw->sdp_links * sdp_chan_cnt;
 
        pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc);
@@ -2068,8 +2068,8 @@ static int nix_smq_flush(struct rvu *rvu, int blkaddr,
        /* enable cgx tx if disabled */
        if (is_pf_cgxmapped(rvu, pf)) {
                rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
-               restore_tx_en = !cgx_lmac_tx_enable(rvu_cgx_pdata(cgx_id, rvu),
-                                                   lmac_id, true);
+               restore_tx_en = !rvu_cgx_config_tx(rvu_cgx_pdata(cgx_id, rvu),
+                                                  lmac_id, true);
        }
 
        cfg = rvu_read64(rvu, blkaddr, NIX_AF_SMQX_CFG(smq));
@@ -2092,7 +2092,7 @@ static int nix_smq_flush(struct rvu *rvu, int blkaddr,
        rvu_cgx_enadis_rx_bp(rvu, pf, true);
        /* restore cgx tx state */
        if (restore_tx_en)
-               cgx_lmac_tx_enable(rvu_cgx_pdata(cgx_id, rvu), lmac_id, false);
+               rvu_cgx_config_tx(rvu_cgx_pdata(cgx_id, rvu), lmac_id, false);
        return err;
 }
 
@@ -3878,7 +3878,7 @@ nix_config_link_credits(struct rvu *rvu, int blkaddr, int link,
        /* Enable cgx tx if disabled for credits to be back */
        if (is_pf_cgxmapped(rvu, pf)) {
                rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
-               restore_tx_en = !cgx_lmac_tx_enable(rvu_cgx_pdata(cgx_id, rvu),
+               restore_tx_en = !rvu_cgx_config_tx(rvu_cgx_pdata(cgx_id, rvu),
                                                    lmac_id, true);
        }
 
@@ -3891,8 +3891,8 @@ nix_config_link_credits(struct rvu *rvu, int blkaddr, int link,
                            NIX_AF_TL1X_SW_XOFF(schq), BIT_ULL(0));
        }
 
-       rc = -EBUSY;
-       poll_tmo = jiffies + usecs_to_jiffies(10000);
+       rc = NIX_AF_ERR_LINK_CREDITS;
+       poll_tmo = jiffies + usecs_to_jiffies(200000);
        /* Wait for credits to return */
        do {
                if (time_after(jiffies, poll_tmo))
@@ -3918,7 +3918,7 @@ exit:
 
        /* Restore state of cgx tx */
        if (restore_tx_en)
-               cgx_lmac_tx_enable(rvu_cgx_pdata(cgx_id, rvu), lmac_id, false);
+               rvu_cgx_config_tx(rvu_cgx_pdata(cgx_id, rvu), lmac_id, false);
 
        mutex_unlock(&rvu->rsrc_lock);
        return rc;
index c0005a1..91f86d7 100644 (file)
@@ -402,6 +402,7 @@ static void npc_fixup_vf_rule(struct rvu *rvu, struct npc_mcam *mcam,
                              int blkaddr, int index, struct mcam_entry *entry,
                              bool *enable)
 {
+       struct rvu_npc_mcam_rule *rule;
        u16 owner, target_func;
        struct rvu_pfvf *pfvf;
        u64 rx_action;
@@ -423,6 +424,12 @@ static void npc_fixup_vf_rule(struct rvu *rvu, struct npc_mcam *mcam,
              test_bit(NIXLF_INITIALIZED, &pfvf->flags)))
                *enable = false;
 
+       /* fix up not needed for the rules added by user(ntuple filters) */
+       list_for_each_entry(rule, &mcam->mcam_rules, list) {
+               if (rule->entry == index)
+                       return;
+       }
+
        /* copy VF default entry action to the VF mcam entry */
        rx_action = npc_get_default_entry_action(rvu, mcam, blkaddr,
                                                 target_func);
@@ -489,8 +496,8 @@ static void npc_config_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
        }
 
        /* PF installing VF rule */
-       if (intf == NIX_INTF_RX && actindex < mcam->bmap_entries)
-               npc_fixup_vf_rule(rvu, mcam, blkaddr, index, entry, &enable);
+       if (is_npc_intf_rx(intf) && actindex < mcam->bmap_entries)
+               npc_fixup_vf_rule(rvu, mcam, blkaddr, actindex, entry, &enable);
 
        /* Set 'action' */
        rvu_write64(rvu, blkaddr,
@@ -916,7 +923,8 @@ static void npc_update_vf_flow_entry(struct rvu *rvu, struct npc_mcam *mcam,
                                     int blkaddr, u16 pcifunc, u64 rx_action)
 {
        int actindex, index, bank, entry;
-       bool enable;
+       struct rvu_npc_mcam_rule *rule;
+       bool enable, update;
 
        if (!(pcifunc & RVU_PFVF_FUNC_MASK))
                return;
@@ -924,6 +932,14 @@ static void npc_update_vf_flow_entry(struct rvu *rvu, struct npc_mcam *mcam,
        mutex_lock(&mcam->lock);
        for (index = 0; index < mcam->bmap_entries; index++) {
                if (mcam->entry2target_pffunc[index] == pcifunc) {
+                       update = true;
+                       /* update not needed for the rules added via ntuple filters */
+                       list_for_each_entry(rule, &mcam->mcam_rules, list) {
+                               if (rule->entry == index)
+                                       update = false;
+                       }
+                       if (!update)
+                               continue;
                        bank = npc_get_bank(mcam, index);
                        actindex = index;
                        entry = index & (mcam->banksize - 1);
index ff2b219..19c53e5 100644 (file)
@@ -1098,14 +1098,6 @@ find_rule:
                write_req.cntr = rule->cntr;
        }
 
-       err = rvu_mbox_handler_npc_mcam_write_entry(rvu, &write_req,
-                                                   &write_rsp);
-       if (err) {
-               rvu_mcam_remove_counter_from_rule(rvu, owner, rule);
-               if (new)
-                       kfree(rule);
-               return err;
-       }
        /* update rule */
        memcpy(&rule->packet, &dummy.packet, sizeof(rule->packet));
        memcpy(&rule->mask, &dummy.mask, sizeof(rule->mask));
@@ -1132,6 +1124,18 @@ find_rule:
        if (req->default_rule)
                pfvf->def_ucast_rule = rule;
 
+       /* write to mcam entry registers */
+       err = rvu_mbox_handler_npc_mcam_write_entry(rvu, &write_req,
+                                                   &write_rsp);
+       if (err) {
+               rvu_mcam_remove_counter_from_rule(rvu, owner, rule);
+               if (new) {
+                       list_del(&rule->list);
+                       kfree(rule);
+               }
+               return err;
+       }
+
        /* VF's MAC address is being changed via PF  */
        if (pf_set_vfs_mac) {
                ether_addr_copy(pfvf->default_mac, req->packet.dmac);
index 61e5281..14509fc 100644 (file)
@@ -603,6 +603,7 @@ static inline void __cn10k_aura_freeptr(struct otx2_nic *pfvf, u64 aura,
                        size++;
                tar_addr |=  ((size - 1) & 0x7) << 4;
        }
+       dma_wmb();
        memcpy((u64 *)lmt_info->lmt_addr, ptrs, sizeof(u64) * num_ptrs);
        /* Perform LMTST flush */
        cn10k_lmt_flush(val, tar_addr);
index 6080ebd..d39341e 100644 (file)
@@ -394,7 +394,12 @@ static int otx2_forward_vf_mbox_msgs(struct otx2_nic *pf,
                dst_mdev->msg_size = mbox_hdr->msg_size;
                dst_mdev->num_msgs = num_msgs;
                err = otx2_sync_mbox_msg(dst_mbox);
-               if (err) {
+               /* Error code -EIO indicate there is a communication failure
+                * to the AF. Rest of the error codes indicate that AF processed
+                * VF messages and set the error codes in response messages
+                * (if any) so simply forward responses to VF.
+                */
+               if (err == -EIO) {
                        dev_warn(pf->dev,
                                 "AF not responding to VF%d messages\n", vf);
                        /* restore PF mbase and exit */
index 812e681..c14e06c 100644 (file)
@@ -224,7 +224,7 @@ static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)
 struct mlx5e_tx_wqe {
        struct mlx5_wqe_ctrl_seg ctrl;
        struct mlx5_wqe_eth_seg  eth;
-       struct mlx5_wqe_data_seg data[0];
+       struct mlx5_wqe_data_seg data[];
 };
 
 struct mlx5e_rx_wqe_ll {
@@ -241,8 +241,8 @@ struct mlx5e_umr_wqe {
        struct mlx5_wqe_umr_ctrl_seg   uctrl;
        struct mlx5_mkey_seg           mkc;
        union {
-               struct mlx5_mtt inline_mtts[0];
-               struct mlx5_klm inline_klms[0];
+               DECLARE_FLEX_ARRAY(struct mlx5_mtt, inline_mtts);
+               DECLARE_FLEX_ARRAY(struct mlx5_klm, inline_klms);
        };
 };
 
index 00449df..c1e0749 100644 (file)
@@ -570,7 +570,8 @@ static int mlx5e_htb_convert_rate(struct mlx5e_priv *priv, u64 rate,
 
 static void mlx5e_htb_convert_ceil(struct mlx5e_priv *priv, u64 ceil, u32 *max_average_bw)
 {
-       *max_average_bw = div_u64(ceil, BYTES_IN_MBIT);
+       /* Hardware treats 0 as "unlimited", set at least 1. */
+       *max_average_bw = max_t(u32, div_u64(ceil, BYTES_IN_MBIT), 1);
 
        qos_dbg(priv->mdev, "Convert: ceil %llu -> max_average_bw %u\n",
                ceil, *max_average_bw);
index 9c076aa..b6f5c1b 100644 (file)
@@ -183,18 +183,7 @@ void mlx5e_rep_bond_unslave(struct mlx5_eswitch *esw,
 
 static bool mlx5e_rep_is_lag_netdev(struct net_device *netdev)
 {
-       struct mlx5e_rep_priv *rpriv;
-       struct mlx5e_priv *priv;
-
-       /* A given netdev is not a representor or not a slave of LAG configuration */
-       if (!mlx5e_eswitch_rep(netdev) || !netif_is_lag_port(netdev))
-               return false;
-
-       priv = netdev_priv(netdev);
-       rpriv = priv->ppriv;
-
-       /* Egress acl forward to vport is supported only non-uplink representor */
-       return rpriv->rep->vport != MLX5_VPORT_UPLINK;
+       return netif_is_lag_port(netdev) && mlx5e_eswitch_vf_rep(netdev);
 }
 
 static void mlx5e_rep_changelowerstate_event(struct net_device *netdev, void *ptr)
@@ -210,9 +199,6 @@ static void mlx5e_rep_changelowerstate_event(struct net_device *netdev, void *pt
        u16 fwd_vport_num;
        int err;
 
-       if (!mlx5e_rep_is_lag_netdev(netdev))
-               return;
-
        info = ptr;
        lag_info = info->lower_state_info;
        /* This is not an event of a representor becoming active slave */
@@ -266,9 +252,6 @@ static void mlx5e_rep_changeupper_event(struct net_device *netdev, void *ptr)
        struct net_device *lag_dev;
        struct mlx5e_priv *priv;
 
-       if (!mlx5e_rep_is_lag_netdev(netdev))
-               return;
-
        priv = netdev_priv(netdev);
        rpriv = priv->ppriv;
        lag_dev = info->upper_dev;
@@ -293,6 +276,19 @@ static int mlx5e_rep_esw_bond_netevent(struct notifier_block *nb,
                                       unsigned long event, void *ptr)
 {
        struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+       struct mlx5e_rep_priv *rpriv;
+       struct mlx5e_rep_bond *bond;
+       struct mlx5e_priv *priv;
+
+       if (!mlx5e_rep_is_lag_netdev(netdev))
+               return NOTIFY_DONE;
+
+       bond = container_of(nb, struct mlx5e_rep_bond, nb);
+       priv = netdev_priv(netdev);
+       rpriv = mlx5_eswitch_get_uplink_priv(priv->mdev->priv.eswitch, REP_ETH);
+       /* Verify VF representor is on the same device of the bond handling the netevent. */
+       if (rpriv->uplink_priv.bond != bond)
+               return NOTIFY_DONE;
 
        switch (event) {
        case NETDEV_CHANGELOWERSTATE:
index c6d2f8c..48dc121 100644 (file)
@@ -491,7 +491,7 @@ void mlx5e_rep_bridge_init(struct mlx5e_priv *priv)
        }
 
        br_offloads->netdev_nb.notifier_call = mlx5_esw_bridge_switchdev_port_event;
-       err = register_netdevice_notifier(&br_offloads->netdev_nb);
+       err = register_netdevice_notifier_net(&init_net, &br_offloads->netdev_nb);
        if (err) {
                esw_warn(mdev, "Failed to register bridge offloads netdevice notifier (err=%d)\n",
                         err);
@@ -509,7 +509,9 @@ err_register_swdev_blk:
 err_register_swdev:
        destroy_workqueue(br_offloads->wq);
 err_alloc_wq:
+       rtnl_lock();
        mlx5_esw_bridge_cleanup(esw);
+       rtnl_unlock();
 }
 
 void mlx5e_rep_bridge_cleanup(struct mlx5e_priv *priv)
@@ -524,7 +526,7 @@ void mlx5e_rep_bridge_cleanup(struct mlx5e_priv *priv)
                return;
 
        cancel_delayed_work_sync(&br_offloads->update_work);
-       unregister_netdevice_notifier(&br_offloads->netdev_nb);
+       unregister_netdevice_notifier_net(&init_net, &br_offloads->netdev_nb);
        unregister_switchdev_blocking_notifier(&br_offloads->nb_blk);
        unregister_switchdev_notifier(&br_offloads->nb);
        destroy_workqueue(br_offloads->wq);
index 4cdf8e5..b789af0 100644 (file)
@@ -167,6 +167,11 @@ static inline u16 mlx5e_txqsq_get_next_pi(struct mlx5e_txqsq *sq, u16 size)
        return pi;
 }
 
+static inline u16 mlx5e_shampo_get_cqe_header_index(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
+{
+       return be16_to_cpu(cqe->shampo.header_entry_index) & (rq->mpwqe.shampo->hd_per_wq - 1);
+}
+
 struct mlx5e_shampo_umr {
        u16 len;
 };
index 338d65e..56e10c8 100644 (file)
@@ -341,8 +341,10 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
 
        /* copy the inline part if required */
        if (sq->min_inline_mode != MLX5_INLINE_MODE_NONE) {
-               memcpy(eseg->inline_hdr.start, xdptxd->data, MLX5E_XDP_MIN_INLINE);
+               memcpy(eseg->inline_hdr.start, xdptxd->data, sizeof(eseg->inline_hdr.start));
                eseg->inline_hdr.sz = cpu_to_be16(MLX5E_XDP_MIN_INLINE);
+               memcpy(dseg, xdptxd->data + sizeof(eseg->inline_hdr.start),
+                      MLX5E_XDP_MIN_INLINE - sizeof(eseg->inline_hdr.start));
                dma_len  -= MLX5E_XDP_MIN_INLINE;
                dma_addr += MLX5E_XDP_MIN_INLINE;
                dseg++;
index 2db9573..b56fea1 100644 (file)
@@ -157,11 +157,20 @@ static void mlx5e_ipsec_set_swp(struct sk_buff *skb,
        /* Tunnel mode */
        if (mode == XFRM_MODE_TUNNEL) {
                eseg->swp_inner_l3_offset = skb_inner_network_offset(skb) / 2;
-               eseg->swp_inner_l4_offset = skb_inner_transport_offset(skb) / 2;
                if (xo->proto == IPPROTO_IPV6)
                        eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
-               if (inner_ip_hdr(skb)->protocol == IPPROTO_UDP)
+
+               switch (xo->inner_ipproto) {
+               case IPPROTO_UDP:
                        eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP;
+                       fallthrough;
+               case IPPROTO_TCP:
+                       /* IP | ESP | IP | [TCP | UDP] */
+                       eseg->swp_inner_l4_offset = skb_inner_transport_offset(skb) / 2;
+                       break;
+               default:
+                       break;
+               }
                return;
        }
 
index b98db50..428881e 100644 (file)
@@ -131,14 +131,17 @@ static inline bool
 mlx5e_ipsec_txwqe_build_eseg_csum(struct mlx5e_txqsq *sq, struct sk_buff *skb,
                                  struct mlx5_wqe_eth_seg *eseg)
 {
-       struct xfrm_offload *xo = xfrm_offload(skb);
+       u8 inner_ipproto;
 
        if (!mlx5e_ipsec_eseg_meta(eseg))
                return false;
 
        eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM;
-       if (xo->inner_ipproto) {
-               eseg->cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM | MLX5_ETH_WQE_L3_INNER_CSUM;
+       inner_ipproto = xfrm_offload(skb)->inner_ipproto;
+       if (inner_ipproto) {
+               eseg->cs_flags |= MLX5_ETH_WQE_L3_INNER_CSUM;
+               if (inner_ipproto == IPPROTO_TCP || inner_ipproto == IPPROTO_UDP)
+                       eseg->cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM;
        } else if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
                eseg->cs_flags |= MLX5_ETH_WQE_L4_CSUM;
                sq->stats->csum_partial_inner++;
index e86ccc2..ee0a8f5 100644 (file)
@@ -1117,7 +1117,7 @@ static void mlx5e_shampo_update_ipv6_udp_hdr(struct mlx5e_rq *rq, struct ipv6hdr
 static void mlx5e_shampo_update_fin_psh_flags(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
                                              struct tcphdr *skb_tcp_hd)
 {
-       u16 header_index = be16_to_cpu(cqe->shampo.header_entry_index);
+       u16 header_index = mlx5e_shampo_get_cqe_header_index(rq, cqe);
        struct tcphdr *last_tcp_hd;
        void *last_hd_addr;
 
@@ -1871,7 +1871,7 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
        return skb;
 }
 
-static void
+static struct sk_buff *
 mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
                          struct mlx5_cqe64 *cqe, u16 header_index)
 {
@@ -1895,7 +1895,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
                skb = mlx5e_build_linear_skb(rq, hdr, frag_size, rx_headroom, head_size);
 
                if (unlikely(!skb))
-                       return;
+                       return NULL;
 
                /* queue up for recycling/reuse */
                page_ref_inc(head->page);
@@ -1907,7 +1907,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
                                     ALIGN(head_size, sizeof(long)));
                if (unlikely(!skb)) {
                        rq->stats->buff_alloc_err++;
-                       return;
+                       return NULL;
                }
 
                prefetchw(skb->data);
@@ -1918,9 +1918,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
                skb->tail += head_size;
                skb->len  += head_size;
        }
-       rq->hw_gro_data->skb = skb;
-       NAPI_GRO_CB(skb)->count = 1;
-       skb_shinfo(skb)->gso_size = mpwrq_get_cqe_byte_cnt(cqe) - head_size;
+       return skb;
 }
 
 static void
@@ -1973,13 +1971,14 @@ mlx5e_free_rx_shampo_hd_entry(struct mlx5e_rq *rq, u16 header_index)
 static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
 {
        u16 data_bcnt           = mpwrq_get_cqe_byte_cnt(cqe) - cqe->shampo.header_size;
-       u16 header_index        = be16_to_cpu(cqe->shampo.header_entry_index);
+       u16 header_index        = mlx5e_shampo_get_cqe_header_index(rq, cqe);
        u32 wqe_offset          = be32_to_cpu(cqe->shampo.data_offset);
        u16 cstrides            = mpwrq_get_cqe_consumed_strides(cqe);
        u32 data_offset         = wqe_offset & (PAGE_SIZE - 1);
        u32 cqe_bcnt            = mpwrq_get_cqe_byte_cnt(cqe);
        u16 wqe_id              = be16_to_cpu(cqe->wqe_id);
        u32 page_idx            = wqe_offset >> PAGE_SHIFT;
+       u16 head_size           = cqe->shampo.header_size;
        struct sk_buff **skb    = &rq->hw_gro_data->skb;
        bool flush              = cqe->shampo.flush;
        bool match              = cqe->shampo.match;
@@ -2011,9 +2010,16 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq
        }
 
        if (!*skb) {
-               mlx5e_skb_from_cqe_shampo(rq, wi, cqe, header_index);
+               if (likely(head_size))
+                       *skb = mlx5e_skb_from_cqe_shampo(rq, wi, cqe, header_index);
+               else
+                       *skb = mlx5e_skb_from_cqe_mpwrq_nonlinear(rq, wi, cqe_bcnt, data_offset,
+                                                                 page_idx);
                if (unlikely(!*skb))
                        goto free_hd_entry;
+
+               NAPI_GRO_CB(*skb)->count = 1;
+               skb_shinfo(*skb)->gso_size = cqe_bcnt - head_size;
        } else {
                NAPI_GRO_CB(*skb)->count++;
                if (NAPI_GRO_CB(*skb)->count == 2 &&
@@ -2027,8 +2033,10 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq
                }
        }
 
-       di = &wi->umr.dma_info[page_idx];
-       mlx5e_fill_skb_data(*skb, rq, di, data_bcnt, data_offset);
+       if (likely(head_size)) {
+               di = &wi->umr.dma_info[page_idx];
+               mlx5e_fill_skb_data(*skb, rq, di, data_bcnt, data_offset);
+       }
 
        mlx5e_shampo_complete_rx_cqe(rq, cqe, cqe_bcnt, *skb);
        if (flush)
index 3d908a7..2022fa4 100644 (file)
@@ -1414,7 +1414,8 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
                if (err)
                        goto err_out;
 
-               if (!attr->chain && esw_attr->int_port) {
+               if (!attr->chain && esw_attr->int_port &&
+                   attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
                        /* If decap route device is internal port, change the
                         * source vport value in reg_c0 back to uplink just in
                         * case the rule performs goto chain > 0. If we have a miss
@@ -3191,6 +3192,18 @@ actions_match_supported(struct mlx5e_priv *priv,
                return false;
        }
 
+       if (!(~actions &
+             (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) {
+               NL_SET_ERR_MSG_MOD(extack, "Rule cannot support forward+drop action");
+               return false;
+       }
+
+       if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
+           actions & MLX5_FLOW_CONTEXT_ACTION_DROP) {
+               NL_SET_ERR_MSG_MOD(extack, "Drop with modify header action is not supported");
+               return false;
+       }
+
        if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
            !modify_header_match_supported(priv, &parse_attr->spec, flow_action,
                                           actions, ct_flow, ct_clear, extack))
index 7fd33b3..ee7ecb8 100644 (file)
@@ -208,7 +208,7 @@ static inline void mlx5e_insert_vlan(void *start, struct sk_buff *skb, u16 ihs)
        int cpy1_sz = 2 * ETH_ALEN;
        int cpy2_sz = ihs - cpy1_sz;
 
-       memcpy(vhdr, skb->data, cpy1_sz);
+       memcpy(&vhdr->addrs, skb->data, cpy1_sz);
        vhdr->h_vlan_proto = skb->vlan_proto;
        vhdr->h_vlan_TCI = cpu_to_be16(skb_vlan_tag_get(skb));
        memcpy(&vhdr->h_vlan_encapsulated_proto, skb->data + cpy1_sz, cpy2_sz);
index f690f43..05e08ce 100644 (file)
@@ -1574,6 +1574,8 @@ struct mlx5_esw_bridge_offloads *mlx5_esw_bridge_init(struct mlx5_eswitch *esw)
 {
        struct mlx5_esw_bridge_offloads *br_offloads;
 
+       ASSERT_RTNL();
+
        br_offloads = kvzalloc(sizeof(*br_offloads), GFP_KERNEL);
        if (!br_offloads)
                return ERR_PTR(-ENOMEM);
@@ -1590,6 +1592,8 @@ void mlx5_esw_bridge_cleanup(struct mlx5_eswitch *esw)
 {
        struct mlx5_esw_bridge_offloads *br_offloads = esw->br_offloads;
 
+       ASSERT_RTNL();
+
        if (!br_offloads)
                return;
 
index 3401188..51ac24e 100644 (file)
@@ -21,7 +21,7 @@ DECLARE_EVENT_CLASS(mlx5_esw_bridge_fdb_template,
                            __field(unsigned int, used)
                            ),
                    TP_fast_assign(
-                           strncpy(__entry->dev_name,
+                           strscpy(__entry->dev_name,
                                    netdev_name(fdb->dev),
                                    IFNAMSIZ);
                            memcpy(__entry->addr, fdb->key.addr, ETH_ALEN);
index 0b0234f..84dbe46 100644 (file)
@@ -132,7 +132,7 @@ static void mlx5_stop_sync_reset_poll(struct mlx5_core_dev *dev)
 {
        struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
 
-       del_timer(&fw_reset->timer);
+       del_timer_sync(&fw_reset->timer);
 }
 
 static void mlx5_sync_reset_clear_reset_requested(struct mlx5_core_dev *dev, bool poll_health)
index d5e4763..df58cba 100644 (file)
@@ -121,12 +121,13 @@ u32 mlx5_chains_get_nf_ft_chain(struct mlx5_fs_chains *chains)
 
 u32 mlx5_chains_get_prio_range(struct mlx5_fs_chains *chains)
 {
-       if (!mlx5_chains_prios_supported(chains))
-               return 1;
-
        if (mlx5_chains_ignore_flow_level_supported(chains))
                return UINT_MAX;
 
+       if (!chains->dev->priv.eswitch ||
+           chains->dev->priv.eswitch->mode != MLX5_ESWITCH_OFFLOADS)
+               return 1;
+
        /* We should get here only for eswitch case */
        return FDB_TC_MAX_PRIO;
 }
@@ -211,7 +212,7 @@ static int
 create_chain_restore(struct fs_chain *chain)
 {
        struct mlx5_eswitch *esw = chain->chains->dev->priv.eswitch;
-       char modact[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)];
+       u8 modact[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
        struct mlx5_fs_chains *chains = chain->chains;
        enum mlx5e_tc_attr_to_reg chain_to_reg;
        struct mlx5_modify_hdr *mod_hdr;
index 1ef2b6a..7b16a11 100644 (file)
@@ -406,23 +406,24 @@ int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
 
        switch (module_id) {
        case MLX5_MODULE_ID_SFP:
-               mlx5_sfp_eeprom_params_set(&query.i2c_address, &query.page, &query.offset);
+               mlx5_sfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
                break;
        case MLX5_MODULE_ID_QSFP:
        case MLX5_MODULE_ID_QSFP_PLUS:
        case MLX5_MODULE_ID_QSFP28:
-               mlx5_qsfp_eeprom_params_set(&query.i2c_address, &query.page, &query.offset);
+               mlx5_qsfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
                break;
        default:
                mlx5_core_err(dev, "Module ID not recognized: 0x%x\n", module_id);
                return -EINVAL;
        }
 
-       if (query.offset + size > MLX5_EEPROM_PAGE_LENGTH)
+       if (offset + size > MLX5_EEPROM_PAGE_LENGTH)
                /* Cross pages read, read until offset 256 in low page */
-               size -= offset + size - MLX5_EEPROM_PAGE_LENGTH;
+               size = MLX5_EEPROM_PAGE_LENGTH - offset;
 
        query.size = size;
+       query.offset = offset;
 
        return mlx5_query_mcia(dev, &query, data);
 }
index ca5f117..ce5970b 100644 (file)
@@ -40,11 +40,12 @@ static int lan966x_mac_wait_for_completion(struct lan966x *lan966x)
 {
        u32 val;
 
-       return readx_poll_timeout(lan966x_mac_get_status,
-               lan966x, val,
-               (ANA_MACACCESS_MAC_TABLE_CMD_GET(val)) ==
-               MACACCESS_CMD_IDLE,
-               TABLE_UPDATE_SLEEP_US, TABLE_UPDATE_TIMEOUT_US);
+       return readx_poll_timeout_atomic(lan966x_mac_get_status,
+                                        lan966x, val,
+                                        (ANA_MACACCESS_MAC_TABLE_CMD_GET(val)) ==
+                                        MACACCESS_CMD_IDLE,
+                                        TABLE_UPDATE_SLEEP_US,
+                                        TABLE_UPDATE_TIMEOUT_US);
 }
 
 static void lan966x_mac_select(struct lan966x *lan966x,
index 2cb70da..1f60fd1 100644 (file)
@@ -182,9 +182,9 @@ static int lan966x_port_inj_ready(struct lan966x *lan966x, u8 grp)
 {
        u32 val;
 
-       return readx_poll_timeout(lan966x_port_inj_status, lan966x, val,
-                                 QS_INJ_STATUS_FIFO_RDY_GET(val) & BIT(grp),
-                                 READL_SLEEP_US, READL_TIMEOUT_US);
+       return readx_poll_timeout_atomic(lan966x_port_inj_status, lan966x, val,
+                                        QS_INJ_STATUS_FIFO_RDY_GET(val) & BIT(grp),
+                                        READL_SLEEP_US, READL_TIMEOUT_US);
 }
 
 static int lan966x_port_ifh_xmit(struct sk_buff *skb,
index 59783fc..10b866e 100644 (file)
@@ -1103,7 +1103,7 @@ void sparx5_get_stats64(struct net_device *ndev,
        stats->tx_carrier_errors = portstats[spx5_stats_tx_csense_cnt];
        stats->tx_window_errors = portstats[spx5_stats_tx_late_coll_cnt];
        stats->rx_dropped = portstats[spx5_stats_ana_ac_port_stat_lsb_cnt];
-       for (idx = 0; idx < 2 * SPX5_PRIOS; ++idx, ++stats)
+       for (idx = 0; idx < 2 * SPX5_PRIOS; ++idx)
                stats->rx_dropped += portstats[spx5_stats_green_p0_rx_port_drop
                                               + idx];
        stats->tx_dropped = portstats[spx5_stats_tx_local_drop];
index dc7e5ea..148d431 100644 (file)
@@ -145,9 +145,9 @@ static void sparx5_xtr_grp(struct sparx5 *sparx5, u8 grp, bool byte_swap)
        skb_put(skb, byte_cnt - ETH_FCS_LEN);
        eth_skb_pad(skb);
        skb->protocol = eth_type_trans(skb, netdev);
-       netif_rx(skb);
        netdev->stats.rx_bytes += skb->len;
        netdev->stats.rx_packets++;
+       netif_rx(skb);
 }
 
 static int sparx5_inject(struct sparx5 *sparx5,
index 455293a..e6de865 100644 (file)
@@ -1432,6 +1432,8 @@ static void
 ocelot_populate_ipv4_ptp_event_trap_key(struct ocelot_vcap_filter *trap)
 {
        trap->key_type = OCELOT_VCAP_KEY_IPV4;
+       trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
+       trap->key.ipv4.proto.mask[0] = 0xff;
        trap->key.ipv4.dport.value = PTP_EV_PORT;
        trap->key.ipv4.dport.mask = 0xffff;
 }
@@ -1440,6 +1442,8 @@ static void
 ocelot_populate_ipv6_ptp_event_trap_key(struct ocelot_vcap_filter *trap)
 {
        trap->key_type = OCELOT_VCAP_KEY_IPV6;
+       trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
+       trap->key.ipv4.proto.mask[0] = 0xff;
        trap->key.ipv6.dport.value = PTP_EV_PORT;
        trap->key.ipv6.dport.mask = 0xffff;
 }
@@ -1448,6 +1452,8 @@ static void
 ocelot_populate_ipv4_ptp_general_trap_key(struct ocelot_vcap_filter *trap)
 {
        trap->key_type = OCELOT_VCAP_KEY_IPV4;
+       trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
+       trap->key.ipv4.proto.mask[0] = 0xff;
        trap->key.ipv4.dport.value = PTP_GEN_PORT;
        trap->key.ipv4.dport.mask = 0xffff;
 }
@@ -1456,6 +1462,8 @@ static void
 ocelot_populate_ipv6_ptp_general_trap_key(struct ocelot_vcap_filter *trap)
 {
        trap->key_type = OCELOT_VCAP_KEY_IPV6;
+       trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
+       trap->key.ipv4.proto.mask[0] = 0xff;
        trap->key.ipv6.dport.value = PTP_GEN_PORT;
        trap->key.ipv6.dport.mask = 0xffff;
 }
@@ -1737,12 +1745,11 @@ void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
 }
 EXPORT_SYMBOL(ocelot_get_strings);
 
+/* Caller must hold &ocelot->stats_lock */
 static void ocelot_update_stats(struct ocelot *ocelot)
 {
        int i, j;
 
-       mutex_lock(&ocelot->stats_lock);
-
        for (i = 0; i < ocelot->num_phys_ports; i++) {
                /* Configure the port to read the stats from */
                ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(i), SYS_STAT_CFG);
@@ -1761,8 +1768,6 @@ static void ocelot_update_stats(struct ocelot *ocelot)
                                              ~(u64)U32_MAX) + val;
                }
        }
-
-       mutex_unlock(&ocelot->stats_lock);
 }
 
 static void ocelot_check_stats_work(struct work_struct *work)
@@ -1771,7 +1776,9 @@ static void ocelot_check_stats_work(struct work_struct *work)
        struct ocelot *ocelot = container_of(del_work, struct ocelot,
                                             stats_work);
 
+       mutex_lock(&ocelot->stats_lock);
        ocelot_update_stats(ocelot);
+       mutex_unlock(&ocelot->stats_lock);
 
        queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
                           OCELOT_STATS_CHECK_DELAY);
@@ -1781,12 +1788,16 @@ void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
 {
        int i;
 
+       mutex_lock(&ocelot->stats_lock);
+
        /* check and update now */
        ocelot_update_stats(ocelot);
 
        /* Copy all counters */
        for (i = 0; i < ocelot->num_stats; i++)
                *data++ = ocelot->stats[port * ocelot->num_stats + i];
+
+       mutex_unlock(&ocelot->stats_lock);
 }
 EXPORT_SYMBOL(ocelot_get_ethtool_stats);
 
index dfb4468..0a326e0 100644 (file)
@@ -1011,6 +1011,7 @@ nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev,
        struct nfp_flower_repr_priv *repr_priv;
        struct nfp_tun_offloaded_mac *entry;
        struct nfp_repr *repr;
+       u16 nfp_mac_idx;
        int ida_idx;
 
        entry = nfp_tunnel_lookup_offloaded_macs(app, mac);
@@ -1029,8 +1030,6 @@ nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev,
                entry->bridge_count--;
 
                if (!entry->bridge_count && entry->ref_count) {
-                       u16 nfp_mac_idx;
-
                        nfp_mac_idx = entry->index & ~NFP_TUN_PRE_TUN_IDX_BIT;
                        if (__nfp_tunnel_offload_mac(app, mac, nfp_mac_idx,
                                                     false)) {
@@ -1046,7 +1045,6 @@ nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev,
 
        /* If MAC is now used by 1 repr set the offloaded MAC index to port. */
        if (entry->ref_count == 1 && list_is_singular(&entry->repr_list)) {
-               u16 nfp_mac_idx;
                int port, err;
 
                repr_priv = list_first_entry(&entry->repr_list,
@@ -1074,8 +1072,14 @@ nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev,
        WARN_ON_ONCE(rhashtable_remove_fast(&priv->tun.offloaded_macs,
                                            &entry->ht_node,
                                            offloaded_macs_params));
+
+       if (nfp_flower_is_supported_bridge(netdev))
+               nfp_mac_idx = entry->index & ~NFP_TUN_PRE_TUN_IDX_BIT;
+       else
+               nfp_mac_idx = entry->index;
+
        /* If MAC has global ID then extract and free the ida entry. */
-       if (nfp_tunnel_is_mac_idx_global(entry->index)) {
+       if (nfp_tunnel_is_mac_idx_global(nfp_mac_idx)) {
                ida_idx = nfp_tunnel_get_ida_from_global_mac_idx(entry->index);
                ida_simple_remove(&priv->tun.mac_off_ids, ida_idx);
        }
index 16a4cba..c672f92 100644 (file)
@@ -749,6 +749,7 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
        const struct ether3_data *data = id->data;
        struct net_device *dev;
        int bus_type, ret;
+       u8 addr[ETH_ALEN];
 
        ether3_banner();
 
@@ -776,7 +777,8 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
        priv(dev)->seeq = priv(dev)->base + data->base_offset;
        dev->irq = ec->irq;
 
-       ether3_addr(dev->dev_addr, ec);
+       ether3_addr(addr, ec);
+       eth_hw_addr_set(dev, addr);
 
        priv(dev)->dev = dev;
        timer_setup(&priv(dev)->timer, ether3_ledoff, 0);
index dd6f69c..fc9cef9 100644 (file)
@@ -1648,7 +1648,7 @@ static int smc911x_ethtool_geteeprom(struct net_device *dev,
                        return ret;
                if ((ret=smc911x_ethtool_read_eeprom_byte(dev, &eebuf[i]))!=0)
                        return ret;
-               }
+       }
        memcpy(data, eebuf+eeprom->offset, eeprom->len);
        return 0;
 }
@@ -1667,11 +1667,11 @@ static int smc911x_ethtool_seteeprom(struct net_device *dev,
                        return ret;
                /* write byte */
                if ((ret=smc911x_ethtool_write_eeprom_byte(dev, *data))!=0)
-                        return ret;
+                       return ret;
                if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE_, i ))!=0)
                        return ret;
-               }
-        return 0;
+       }
+       return 0;
 }
 
 static int smc911x_ethtool_geteeprom_len(struct net_device *dev)
index 617d0e4..09644ab 100644 (file)
@@ -756,7 +756,7 @@ static int sun8i_dwmac_reset(struct stmmac_priv *priv)
 
        if (err) {
                dev_err(priv->device, "EMAC reset timeout\n");
-               return -EFAULT;
+               return err;
        }
        return 0;
 }
index e2e0f97..c3f10a9 100644 (file)
 #define ETHER_CLK_SEL_RMII_CLK_EN BIT(2)
 #define ETHER_CLK_SEL_RMII_CLK_RST BIT(3)
 #define ETHER_CLK_SEL_DIV_SEL_2 BIT(4)
-#define ETHER_CLK_SEL_DIV_SEL_20 BIT(0)
+#define ETHER_CLK_SEL_DIV_SEL_20 0
 #define ETHER_CLK_SEL_FREQ_SEL_125M    (BIT(9) | BIT(8))
 #define ETHER_CLK_SEL_FREQ_SEL_50M     BIT(9)
 #define ETHER_CLK_SEL_FREQ_SEL_25M     BIT(8)
 #define ETHER_CLK_SEL_FREQ_SEL_2P5M    0
-#define ETHER_CLK_SEL_TX_CLK_EXT_SEL_IN BIT(0)
+#define ETHER_CLK_SEL_TX_CLK_EXT_SEL_IN 0
 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC BIT(10)
 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV BIT(11)
-#define ETHER_CLK_SEL_RX_CLK_EXT_SEL_IN  BIT(0)
+#define ETHER_CLK_SEL_RX_CLK_EXT_SEL_IN  0
 #define ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC BIT(12)
 #define ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV BIT(13)
-#define ETHER_CLK_SEL_TX_CLK_O_TX_I     BIT(0)
+#define ETHER_CLK_SEL_TX_CLK_O_TX_I     0
 #define ETHER_CLK_SEL_TX_CLK_O_RMII_I   BIT(14)
 #define ETHER_CLK_SEL_TX_O_E_N_IN       BIT(15)
-#define ETHER_CLK_SEL_RMII_CLK_SEL_IN   BIT(0)
+#define ETHER_CLK_SEL_RMII_CLK_SEL_IN   0
 #define ETHER_CLK_SEL_RMII_CLK_SEL_RX_C         BIT(16)
 
 #define ETHER_CLK_SEL_RX_TX_CLK_EN (ETHER_CLK_SEL_RX_CLK_EN | ETHER_CLK_SEL_TX_CLK_EN)
@@ -49,13 +49,15 @@ struct visconti_eth {
        void __iomem *reg;
        u32 phy_intf_sel;
        struct clk *phy_ref_clk;
+       struct device *dev;
        spinlock_t lock; /* lock to protect register update */
 };
 
 static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
 {
        struct visconti_eth *dwmac = priv;
-       unsigned int val, clk_sel_val;
+       struct net_device *netdev = dev_get_drvdata(dwmac->dev);
+       unsigned int val, clk_sel_val = 0;
        unsigned long flags;
 
        spin_lock_irqsave(&dwmac->lock, flags);
@@ -85,7 +87,9 @@ static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
                break;
        default:
                /* No bit control */
-               break;
+               netdev_err(netdev, "Unsupported speed request (%d)", speed);
+               spin_unlock_irqrestore(&dwmac->lock, flags);
+               return;
        }
 
        writel(val, dwmac->reg + MAC_CTRL_REG);
@@ -96,31 +100,41 @@ static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
        val |= ETHER_CLK_SEL_TX_O_E_N_IN;
        writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
 
+       /* Set Clock-Mux, Start clock, Set TX_O direction */
        switch (dwmac->phy_intf_sel) {
        case ETHER_CONFIG_INTF_RGMII:
                val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
+
+               val |= ETHER_CLK_SEL_RX_TX_CLK_EN;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
+
+               val &= ~ETHER_CLK_SEL_TX_O_E_N_IN;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
                break;
        case ETHER_CONFIG_INTF_RMII:
                val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV |
-                       ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC | ETHER_CLK_SEL_TX_O_E_N_IN |
+                       ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN |
                        ETHER_CLK_SEL_RMII_CLK_SEL_RX_C;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
+
+               val |= ETHER_CLK_SEL_RMII_CLK_RST;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
+
+               val |= ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
                break;
        case ETHER_CONFIG_INTF_MII:
        default:
                val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC |
-                       ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN |
-                       ETHER_CLK_SEL_RMII_CLK_EN;
+                       ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC | ETHER_CLK_SEL_TX_O_E_N_IN;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
+
+               val |= ETHER_CLK_SEL_RX_TX_CLK_EN;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
                break;
        }
 
-       /* Start clock */
-       writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
-       val |= ETHER_CLK_SEL_RX_TX_CLK_EN;
-       writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
-
-       val &= ~ETHER_CLK_SEL_TX_O_E_N_IN;
-       writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
-
        spin_unlock_irqrestore(&dwmac->lock, flags);
 }
 
@@ -219,6 +233,7 @@ static int visconti_eth_dwmac_probe(struct platform_device *pdev)
 
        spin_lock_init(&dwmac->lock);
        dwmac->reg = stmmac_res.addr;
+       dwmac->dev = &pdev->dev;
        plat_dat->bsp_priv = dwmac;
        plat_dat->fix_mac_speed = visconti_eth_fix_mac_speed;
 
index 1914ad6..acd70b9 100644 (file)
 
 #define NUM_DWMAC100_DMA_REGS  9
 #define NUM_DWMAC1000_DMA_REGS 23
+#define NUM_DWMAC4_DMA_REGS    27
 
 void dwmac_enable_dma_transmission(void __iomem *ioaddr);
 void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
index 40b5ed9..5b195d5 100644 (file)
@@ -194,7 +194,6 @@ struct stmmac_priv {
        u32 tx_coal_timer[MTL_MAX_TX_QUEUES];
        u32 rx_coal_frames[MTL_MAX_TX_QUEUES];
 
-       int tx_coalesce;
        int hwts_tx_en;
        bool tx_path_in_lpi_mode;
        bool tso;
@@ -229,7 +228,6 @@ struct stmmac_priv {
        unsigned int flow_ctrl;
        unsigned int pause;
        struct mii_bus *mii;
-       int mii_irq[PHY_MAX_ADDR];
 
        struct phylink_config phylink_config;
        struct phylink *phylink;
index 164dff5..abfb3cd 100644 (file)
 #include "dwxgmac2.h"
 
 #define REG_SPACE_SIZE 0x1060
+#define GMAC4_REG_SPACE_SIZE   0x116C
 #define MAC100_ETHTOOL_NAME    "st_mac100"
 #define GMAC_ETHTOOL_NAME      "st_gmac"
 #define XGMAC_ETHTOOL_NAME     "st_xgmac"
 
+/* Same as DMA_CHAN_BASE_ADDR defined in dwmac4_dma.h
+ *
+ * It is here because dwmac_dma.h and dwmac4_dam.h can not be included at the
+ * same time due to the conflicting macro names.
+ */
+#define GMAC4_DMA_CHAN_BASE_ADDR  0x00001100
+
 #define ETHTOOL_DMA_OFFSET     55
 
 struct stmmac_stats {
@@ -434,6 +442,8 @@ static int stmmac_ethtool_get_regs_len(struct net_device *dev)
 
        if (priv->plat->has_xgmac)
                return XGMAC_REGSIZE * 4;
+       else if (priv->plat->has_gmac4)
+               return GMAC4_REG_SPACE_SIZE;
        return REG_SPACE_SIZE;
 }
 
@@ -446,8 +456,13 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
        stmmac_dump_mac_regs(priv, priv->hw, reg_space);
        stmmac_dump_dma_regs(priv, priv->ioaddr, reg_space);
 
-       if (!priv->plat->has_xgmac) {
-               /* Copy DMA registers to where ethtool expects them */
+       /* Copy DMA registers to where ethtool expects them */
+       if (priv->plat->has_gmac4) {
+               /* GMAC4 dumps its DMA registers at its DMA_CHAN_BASE_ADDR */
+               memcpy(&reg_space[ETHTOOL_DMA_OFFSET],
+                      &reg_space[GMAC4_DMA_CHAN_BASE_ADDR / 4],
+                      NUM_DWMAC4_DMA_REGS * 4);
+       } else if (!priv->plat->has_xgmac) {
                memcpy(&reg_space[ETHTOOL_DMA_OFFSET],
                       &reg_space[DMA_BUS_MODE / 4],
                       NUM_DWMAC1000_DMA_REGS * 4);
index 074e2cd..a7ec9f4 100644 (file)
@@ -145,15 +145,20 @@ static int adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
 
 static void get_systime(void __iomem *ioaddr, u64 *systime)
 {
-       u64 ns;
-
-       /* Get the TSSS value */
-       ns = readl(ioaddr + PTP_STNSR);
-       /* Get the TSS and convert sec time value to nanosecond */
-       ns += readl(ioaddr + PTP_STSR) * 1000000000ULL;
+       u64 ns, sec0, sec1;
+
+       /* Get the TSS value */
+       sec1 = readl_relaxed(ioaddr + PTP_STSR);
+       do {
+               sec0 = sec1;
+               /* Get the TSSS value */
+               ns = readl_relaxed(ioaddr + PTP_STNSR);
+               /* Get the TSS value */
+               sec1 = readl_relaxed(ioaddr + PTP_STSR);
+       } while (sec0 != sec1);
 
        if (systime)
-               *systime = ns;
+               *systime = ns + (sec1 * 1000000000ULL);
 }
 
 static void get_ptptime(void __iomem *ptpaddr, u64 *ptp_time)
index 6708ca2..bde76ea 100644 (file)
@@ -402,7 +402,7 @@ static void stmmac_lpi_entry_timer_config(struct stmmac_priv *priv, bool en)
  * Description: this function is to verify and enter in LPI mode in case of
  * EEE.
  */
-static void stmmac_enable_eee_mode(struct stmmac_priv *priv)
+static int stmmac_enable_eee_mode(struct stmmac_priv *priv)
 {
        u32 tx_cnt = priv->plat->tx_queues_to_use;
        u32 queue;
@@ -412,13 +412,14 @@ static void stmmac_enable_eee_mode(struct stmmac_priv *priv)
                struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
 
                if (tx_q->dirty_tx != tx_q->cur_tx)
-                       return; /* still unfinished work */
+                       return -EBUSY; /* still unfinished work */
        }
 
        /* Check and enter in LPI mode */
        if (!priv->tx_path_in_lpi_mode)
                stmmac_set_eee_mode(priv, priv->hw,
                                priv->plat->en_tx_lpi_clockgating);
+       return 0;
 }
 
 /**
@@ -450,8 +451,8 @@ static void stmmac_eee_ctrl_timer(struct timer_list *t)
 {
        struct stmmac_priv *priv = from_timer(priv, t, eee_ctrl_timer);
 
-       stmmac_enable_eee_mode(priv);
-       mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
+       if (stmmac_enable_eee_mode(priv))
+               mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
 }
 
 /**
@@ -889,6 +890,9 @@ static int stmmac_init_ptp(struct stmmac_priv *priv)
        bool xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac;
        int ret;
 
+       if (priv->plat->ptp_clk_freq_config)
+               priv->plat->ptp_clk_freq_config(priv);
+
        ret = stmmac_init_tstamp_counter(priv, STMMAC_HWTS_ACTIVE);
        if (ret)
                return ret;
@@ -911,8 +915,6 @@ static int stmmac_init_ptp(struct stmmac_priv *priv)
        priv->hwts_tx_en = 0;
        priv->hwts_rx_en = 0;
 
-       stmmac_ptp_register(priv);
-
        return 0;
 }
 
@@ -2647,8 +2649,8 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
 
        if (priv->eee_enabled && !priv->tx_path_in_lpi_mode &&
            priv->eee_sw_timer_en) {
-               stmmac_enable_eee_mode(priv);
-               mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
+               if (stmmac_enable_eee_mode(priv))
+                       mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
        }
 
        /* We still have pending packets, let's call for a new scheduling */
@@ -3238,7 +3240,7 @@ static int stmmac_fpe_start_wq(struct stmmac_priv *priv)
 /**
  * stmmac_hw_setup - setup mac in a usable state.
  *  @dev : pointer to the device structure.
- *  @init_ptp: initialize PTP if set
+ *  @ptp_register: register PTP if set
  *  Description:
  *  this is the main function to setup the HW in a usable state because the
  *  dma engine is reset, the core registers are configured (e.g. AXI,
@@ -3248,7 +3250,7 @@ static int stmmac_fpe_start_wq(struct stmmac_priv *priv)
  *  0 on success and an appropriate (-)ve integer as defined in errno.h
  *  file on failure.
  */
-static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
+static int stmmac_hw_setup(struct net_device *dev, bool ptp_register)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
        u32 rx_cnt = priv->plat->rx_queues_to_use;
@@ -3305,13 +3307,13 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
 
        stmmac_mmc_setup(priv);
 
-       if (init_ptp) {
-               ret = stmmac_init_ptp(priv);
-               if (ret == -EOPNOTSUPP)
-                       netdev_warn(priv->dev, "PTP not supported by HW\n");
-               else if (ret)
-                       netdev_warn(priv->dev, "PTP init failed\n");
-       }
+       ret = stmmac_init_ptp(priv);
+       if (ret == -EOPNOTSUPP)
+               netdev_warn(priv->dev, "PTP not supported by HW\n");
+       else if (ret)
+               netdev_warn(priv->dev, "PTP init failed\n");
+       else if (ptp_register)
+               stmmac_ptp_register(priv);
 
        priv->eee_tw_timer = STMMAC_DEFAULT_TWT_LS;
 
@@ -7250,6 +7252,10 @@ int stmmac_dvr_remove(struct device *dev)
 
        netdev_info(priv->dev, "%s: removing driver", __func__);
 
+       pm_runtime_get_sync(dev);
+       pm_runtime_disable(dev);
+       pm_runtime_put_noidle(dev);
+
        stmmac_stop_all_dma(priv);
        stmmac_mac_set(priv, priv->ioaddr, false);
        netif_carrier_off(ndev);
@@ -7268,8 +7274,6 @@ int stmmac_dvr_remove(struct device *dev)
        if (priv->plat->stmmac_rst)
                reset_control_assert(priv->plat->stmmac_rst);
        reset_control_assert(priv->plat->stmmac_ahb_rst);
-       pm_runtime_put(dev);
-       pm_runtime_disable(dev);
        if (priv->hw->pcs != STMMAC_PCS_TBI &&
            priv->hw->pcs != STMMAC_PCS_RTBI)
                stmmac_mdio_unregister(ndev);
index 0d24ebd..1c9f02f 100644 (file)
@@ -297,9 +297,6 @@ void stmmac_ptp_register(struct stmmac_priv *priv)
 {
        int i;
 
-       if (priv->plat->ptp_clk_freq_config)
-               priv->plat->ptp_clk_freq_config(priv);
-
        for (i = 0; i < priv->dma_cap.pps_out_num; i++) {
                if (i >= STMMAC_PPS_MAX)
                        break;
index ba22059..8f6817f 100644 (file)
@@ -1146,7 +1146,7 @@ int cpsw_fill_rx_channels(struct cpsw_priv *priv)
 static struct page_pool *cpsw_create_page_pool(struct cpsw_common *cpsw,
                                               int size)
 {
-       struct page_pool_params pp_params;
+       struct page_pool_params pp_params = {};
        struct page_pool *pool;
 
        pp_params.order = 0;
index cf0917b..5251fc3 100644 (file)
@@ -1091,20 +1091,22 @@ static int tsi108_get_mac(struct net_device *dev)
        struct tsi108_prv_data *data = netdev_priv(dev);
        u32 word1 = TSI_READ(TSI108_MAC_ADDR1);
        u32 word2 = TSI_READ(TSI108_MAC_ADDR2);
+       u8 addr[ETH_ALEN];
 
        /* Note that the octets are reversed from what the manual says,
         * producing an even weirder ordering...
         */
        if (word2 == 0 && word1 == 0) {
-               dev->dev_addr[0] = 0x00;
-               dev->dev_addr[1] = 0x06;
-               dev->dev_addr[2] = 0xd2;
-               dev->dev_addr[3] = 0x00;
-               dev->dev_addr[4] = 0x00;
+               addr[0] = 0x00;
+               addr[1] = 0x06;
+               addr[2] = 0xd2;
+               addr[3] = 0x00;
+               addr[4] = 0x00;
                if (0x8 == data->phy)
-                       dev->dev_addr[5] = 0x01;
+                       addr[5] = 0x01;
                else
-                       dev->dev_addr[5] = 0x02;
+                       addr[5] = 0x02;
+               eth_hw_addr_set(dev, addr);
 
                word2 = (dev->dev_addr[0] << 16) | (dev->dev_addr[1] << 24);
 
@@ -1114,12 +1116,13 @@ static int tsi108_get_mac(struct net_device *dev)
                TSI_WRITE(TSI108_MAC_ADDR1, word1);
                TSI_WRITE(TSI108_MAC_ADDR2, word2);
        } else {
-               dev->dev_addr[0] = (word2 >> 16) & 0xff;
-               dev->dev_addr[1] = (word2 >> 24) & 0xff;
-               dev->dev_addr[2] = (word1 >> 0) & 0xff;
-               dev->dev_addr[3] = (word1 >> 8) & 0xff;
-               dev->dev_addr[4] = (word1 >> 16) & 0xff;
-               dev->dev_addr[5] = (word1 >> 24) & 0xff;
+               addr[0] = (word2 >> 16) & 0xff;
+               addr[1] = (word2 >> 24) & 0xff;
+               addr[2] = (word1 >> 0) & 0xff;
+               addr[3] = (word1 >> 8) & 0xff;
+               addr[4] = (word1 >> 16) & 0xff;
+               addr[5] = (word1 >> 24) & 0xff;
+               eth_hw_addr_set(dev, addr);
        }
 
        if (!is_valid_ether_addr(dev->dev_addr)) {
@@ -1136,14 +1139,12 @@ static int tsi108_set_mac(struct net_device *dev, void *addr)
 {
        struct tsi108_prv_data *data = netdev_priv(dev);
        u32 word1, word2;
-       int i;
 
        if (!is_valid_ether_addr(addr))
                return -EADDRNOTAVAIL;
 
-       for (i = 0; i < 6; i++)
-               /* +2 is for the offset of the HW addr type */
-               dev->dev_addr[i] = ((unsigned char *)addr)[i + 2];
+       /* +2 is for the offset of the HW addr type */
+       eth_hw_addr_set(dev, ((unsigned char *)addr) + 2);
 
        word2 = (dev->dev_addr[0] << 16) | (dev->dev_addr[1] << 24);
 
index 6376b84..980f2be 100644 (file)
@@ -950,9 +950,7 @@ static int yam_siocdevprivate(struct net_device *dev, struct ifreq *ifr, void __
                ym = memdup_user(data, sizeof(struct yamdrv_ioctl_mcs));
                if (IS_ERR(ym))
                        return PTR_ERR(ym);
-               if (ym->cmd != SIOCYAMSMCS)
-                       return -EINVAL;
-               if (ym->bitrate > YAM_MAXBITRATE) {
+               if (ym->cmd != SIOCYAMSMCS || ym->bitrate > YAM_MAXBITRATE) {
                        kfree(ym);
                        return -EINVAL;
                }
index 7d67f41..4f5ef8a 100644 (file)
@@ -100,6 +100,7 @@ struct at86rf230_local {
        unsigned long cal_timeout;
        bool is_tx;
        bool is_tx_from_off;
+       bool was_tx;
        u8 tx_retry;
        struct sk_buff *tx_skb;
        struct at86rf230_state_change tx;
@@ -343,7 +344,11 @@ at86rf230_async_error_recover_complete(void *context)
        if (ctx->free)
                kfree(ctx);
 
-       ieee802154_wake_queue(lp->hw);
+       if (lp->was_tx) {
+               lp->was_tx = 0;
+               dev_kfree_skb_any(lp->tx_skb);
+               ieee802154_wake_queue(lp->hw);
+       }
 }
 
 static void
@@ -352,7 +357,11 @@ at86rf230_async_error_recover(void *context)
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
 
-       lp->is_tx = 0;
+       if (lp->is_tx) {
+               lp->was_tx = 1;
+               lp->is_tx = 0;
+       }
+
        at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON,
                                     at86rf230_async_error_recover_complete);
 }
index ece6ff6..f3438d3 100644 (file)
@@ -1771,6 +1771,7 @@ static int ca8210_async_xmit_complete(
                        status
                );
                if (status != MAC_TRANSACTION_OVERFLOW) {
+                       dev_kfree_skb_any(priv->tx_skb);
                        ieee802154_wake_queue(priv->hw);
                        return 0;
                }
index 8caa61e..36f1c5a 100644 (file)
@@ -786,6 +786,7 @@ static int hwsim_add_one(struct genl_info *info, struct device *dev,
                goto err_pib;
        }
 
+       pib->channel = 13;
        rcu_assign_pointer(phy->pib, pib);
        phy->idx = idx;
        INIT_LIST_HEAD(&phy->edges);
index 8dc04e2..383231b 100644 (file)
@@ -976,8 +976,8 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
        dev_dbg(printdev(lp), "%s\n", __func__);
 
        phy->symbol_duration = 16;
-       phy->lifs_period = 40;
-       phy->sifs_period = 12;
+       phy->lifs_period = 40 * phy->symbol_duration;
+       phy->sifs_period = 12 * phy->symbol_duration;
 
        hw->flags = IEEE802154_HW_TX_OMIT_CKSUM |
                        IEEE802154_HW_AFILT |
index b1c6c0f..f2989aa 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/pm_runtime.h>
 #include <linux/bitops.h>
 
+#include "linux/soc/qcom/qcom_aoss.h"
+
 #include "ipa.h"
 #include "ipa_power.h"
 #include "ipa_endpoint.h"
@@ -64,6 +66,7 @@ enum ipa_power_flag {
  * struct ipa_power - IPA power management information
  * @dev:               IPA device pointer
  * @core:              IPA core clock
+ * @qmp:               QMP handle for AOSS communication
  * @spinlock:          Protects modem TX queue enable/disable
  * @flags:             Boolean state flags
  * @interconnect_count:        Number of elements in interconnect[]
@@ -72,6 +75,7 @@ enum ipa_power_flag {
 struct ipa_power {
        struct device *dev;
        struct clk *core;
+       struct qmp *qmp;
        spinlock_t spinlock;    /* used with STOPPED/STARTED power flags */
        DECLARE_BITMAP(flags, IPA_POWER_FLAG_COUNT);
        u32 interconnect_count;
@@ -382,6 +386,47 @@ void ipa_power_modem_queue_active(struct ipa *ipa)
        clear_bit(IPA_POWER_FLAG_STARTED, ipa->power->flags);
 }
 
+static int ipa_power_retention_init(struct ipa_power *power)
+{
+       struct qmp *qmp = qmp_get(power->dev);
+
+       if (IS_ERR(qmp)) {
+               if (PTR_ERR(qmp) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               /* We assume any other error means it's not defined/needed */
+               qmp = NULL;
+       }
+       power->qmp = qmp;
+
+       return 0;
+}
+
+static void ipa_power_retention_exit(struct ipa_power *power)
+{
+       qmp_put(power->qmp);
+       power->qmp = NULL;
+}
+
+/* Control register retention on power collapse */
+void ipa_power_retention(struct ipa *ipa, bool enable)
+{
+       static const char fmt[] = "{ class: bcm, res: ipa_pc, val: %c }";
+       struct ipa_power *power = ipa->power;
+       char buf[36];   /* Exactly enough for fmt[]; size a multiple of 4 */
+       int ret;
+
+       if (!power->qmp)
+               return;         /* Not needed on this platform */
+
+       (void)snprintf(buf, sizeof(buf), fmt, enable ? '1' : '0');
+
+       ret = qmp_send(power->qmp, buf, sizeof(buf));
+       if (ret)
+               dev_err(power->dev, "error %d sending QMP %sable request\n",
+                       ret, enable ? "en" : "dis");
+}
+
 int ipa_power_setup(struct ipa *ipa)
 {
        int ret;
@@ -438,12 +483,18 @@ ipa_power_init(struct device *dev, const struct ipa_power_data *data)
        if (ret)
                goto err_kfree;
 
+       ret = ipa_power_retention_init(power);
+       if (ret)
+               goto err_interconnect_exit;
+
        pm_runtime_set_autosuspend_delay(dev, IPA_AUTOSUSPEND_DELAY);
        pm_runtime_use_autosuspend(dev);
        pm_runtime_enable(dev);
 
        return power;
 
+err_interconnect_exit:
+       ipa_interconnect_exit(power);
 err_kfree:
        kfree(power);
 err_clk_put:
@@ -460,6 +511,7 @@ void ipa_power_exit(struct ipa_power *power)
 
        pm_runtime_disable(dev);
        pm_runtime_dont_use_autosuspend(dev);
+       ipa_power_retention_exit(power);
        ipa_interconnect_exit(power);
        kfree(power);
        clk_put(clk);
index 2151805..6f84f05 100644 (file)
@@ -40,6 +40,13 @@ void ipa_power_modem_queue_wake(struct ipa *ipa);
  */
 void ipa_power_modem_queue_active(struct ipa *ipa);
 
+/**
+ * ipa_power_retention() - Control register retention on power collapse
+ * @ipa:       IPA pointer
+ * @enable:    Whether retention should be enabled or disabled
+ */
+void ipa_power_retention(struct ipa *ipa, bool enable);
+
 /**
  * ipa_power_setup() - Set up IPA power management
  * @ipa:       IPA pointer
index 856e55a..fe11910 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "ipa.h"
 #include "ipa_uc.h"
+#include "ipa_power.h"
 
 /**
  * DOC:  The IPA embedded microcontroller
@@ -154,6 +155,7 @@ static void ipa_uc_response_hdlr(struct ipa *ipa, enum ipa_irq_id irq_id)
        case IPA_UC_RESPONSE_INIT_COMPLETED:
                if (ipa->uc_powered) {
                        ipa->uc_loaded = true;
+                       ipa_power_retention(ipa, true);
                        pm_runtime_mark_last_busy(dev);
                        (void)pm_runtime_put_autosuspend(dev);
                        ipa->uc_powered = false;
@@ -184,6 +186,9 @@ void ipa_uc_deconfig(struct ipa *ipa)
 
        ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_1);
        ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_0);
+       if (ipa->uc_loaded)
+               ipa_power_retention(ipa, false);
+
        if (!ipa->uc_powered)
                return;
 
index 16aa3a4..3d08743 100644 (file)
@@ -3870,6 +3870,18 @@ static void macsec_common_dellink(struct net_device *dev, struct list_head *head
        struct macsec_dev *macsec = macsec_priv(dev);
        struct net_device *real_dev = macsec->real_dev;
 
+       /* If h/w offloading is available, propagate to the device */
+       if (macsec_is_offloaded(macsec)) {
+               const struct macsec_ops *ops;
+               struct macsec_context ctx;
+
+               ops = macsec_get_ops(netdev_priv(dev), &ctx);
+               if (ops) {
+                       ctx.secy = &macsec->secy;
+                       macsec_offload(ops->mdo_del_secy, &ctx);
+               }
+       }
+
        unregister_netdevice_queue(dev, head);
        list_del_rcu(&macsec->secys);
        macsec_del_dev(macsec);
@@ -3884,18 +3896,6 @@ static void macsec_dellink(struct net_device *dev, struct list_head *head)
        struct net_device *real_dev = macsec->real_dev;
        struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev);
 
-       /* If h/w offloading is available, propagate to the device */
-       if (macsec_is_offloaded(macsec)) {
-               const struct macsec_ops *ops;
-               struct macsec_context ctx;
-
-               ops = macsec_get_ops(netdev_priv(dev), &ctx);
-               if (ops) {
-                       ctx.secy = &macsec->secy;
-                       macsec_offload(ops->mdo_del_secy, &ctx);
-               }
-       }
-
        macsec_common_dellink(dev, head);
 
        if (list_empty(&rxd->secys)) {
@@ -4018,6 +4018,15 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
            !macsec_check_offload(macsec->offload, macsec))
                return -EOPNOTSUPP;
 
+       /* send_sci must be set to true when transmit sci explicitly is set */
+       if ((data && data[IFLA_MACSEC_SCI]) &&
+           (data && data[IFLA_MACSEC_INC_SCI])) {
+               u8 send_sci = !!nla_get_u8(data[IFLA_MACSEC_INC_SCI]);
+
+               if (!send_sci)
+                       return -EINVAL;
+       }
+
        if (data && data[IFLA_MACSEC_ICV_LEN])
                icv_len = nla_get_u8(data[IFLA_MACSEC_ICV_LEN]);
        mtu = real_dev->mtu - icv_len - macsec_extra_len(true);
index 966c3b4..e227358 100644 (file)
@@ -148,6 +148,7 @@ static const struct of_device_id aspeed_mdio_of_match[] = {
        { .compatible = "aspeed,ast2600-mdio", },
        { },
 };
+MODULE_DEVICE_TABLE(of, aspeed_mdio_of_match);
 
 static struct platform_driver aspeed_mdio_driver = {
        .driver = {
index 5b6c0d1..29aa811 100644 (file)
@@ -1688,19 +1688,19 @@ static int qca808x_read_status(struct phy_device *phydev)
        if (ret < 0)
                return ret;
 
-       if (phydev->link && phydev->speed == SPEED_2500)
-               phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
-       else
-               phydev->interface = PHY_INTERFACE_MODE_SMII;
-
-       /* generate seed as a lower random value to make PHY linked as SLAVE easily,
-        * except for master/slave configuration fault detected.
-        * the reason for not putting this code into the function link_change_notify is
-        * the corner case where the link partner is also the qca8081 PHY and the seed
-        * value is configured as the same value, the link can't be up and no link change
-        * occurs.
-        */
-       if (!phydev->link) {
+       if (phydev->link) {
+               if (phydev->speed == SPEED_2500)
+                       phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
+               else
+                       phydev->interface = PHY_INTERFACE_MODE_SGMII;
+       } else {
+               /* generate seed as a lower random value to make PHY linked as SLAVE easily,
+                * except for master/slave configuration fault detected.
+                * the reason for not putting this code into the function link_change_notify is
+                * the corner case where the link partner is also the qca8081 PHY and the seed
+                * value is configured as the same value, the link can't be up and no link change
+                * occurs.
+                */
                if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR) {
                        qca808x_phy_ms_seed_enable(phydev, false);
                } else {
index bb5104a..3c683e0 100644 (file)
@@ -854,6 +854,7 @@ static struct phy_driver broadcom_drivers[] = {
        .phy_id_mask    = 0xfffffff0,
        .name           = "Broadcom BCM54616S",
        /* PHY_GBIT_FEATURES */
+       .soft_reset     = genphy_soft_reset,
        .config_init    = bcm54xx_config_init,
        .config_aneg    = bcm54616s_config_aneg,
        .config_intr    = bcm_phy_config_intr,
index fa71fb7..2429db6 100644 (file)
@@ -553,9 +553,9 @@ static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev)
        else
                mscr = 0;
 
-       return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
-                               MII_88E1121_PHY_MSCR_REG,
-                               MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
+       return phy_modify_paged_changed(phydev, MII_MARVELL_MSCR_PAGE,
+                                       MII_88E1121_PHY_MSCR_REG,
+                                       MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
 }
 
 static int m88e1121_config_aneg(struct phy_device *phydev)
@@ -569,11 +569,13 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
                        return err;
        }
 
+       changed = err;
+
        err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
        if (err < 0)
                return err;
 
-       changed = err;
+       changed |= err;
 
        err = genphy_config_aneg(phydev);
        if (err < 0)
@@ -1213,16 +1215,15 @@ static int m88e1118_config_aneg(struct phy_device *phydev)
 {
        int err;
 
-       err = genphy_soft_reset(phydev);
+       err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
        if (err < 0)
                return err;
 
-       err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
+       err = genphy_config_aneg(phydev);
        if (err < 0)
                return err;
 
-       err = genphy_config_aneg(phydev);
-       return 0;
+       return genphy_soft_reset(phydev);
 }
 
 static int m88e1118_config_init(struct phy_device *phydev)
index 74d8e1d..ce0bb59 100644 (file)
@@ -1746,6 +1746,9 @@ void phy_detach(struct phy_device *phydev)
            phy_driver_is_genphy_10g(phydev))
                device_release_driver(&phydev->mdio.dev);
 
+       /* Assert the reset signal */
+       phy_device_reset(phydev, 1);
+
        /*
         * The phydev might go away on the put_device() below, so avoid
         * a use-after-free bug by reading the underlying bus first.
@@ -1757,9 +1760,6 @@ void phy_detach(struct phy_device *phydev)
                ndev_owner = dev->dev.parent->driver->owner;
        if (ndev_owner != bus->owner)
                module_put(bus->owner);
-
-       /* Assert the reset signal */
-       phy_device_reset(phydev, 1);
 }
 EXPORT_SYMBOL(phy_detach);
 
index 0c6c0d1..c1512c9 100644 (file)
@@ -651,6 +651,11 @@ struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode)
        else if (ret < 0)
                return ERR_PTR(ret);
 
+       if (!fwnode_device_is_available(ref.fwnode)) {
+               fwnode_handle_put(ref.fwnode);
+               return NULL;
+       }
+
        bus = sfp_bus_get(ref.fwnode);
        fwnode_handle_put(ref.fwnode);
        if (!bus)
index 1a627ba..a310989 100644 (file)
@@ -1468,58 +1468,68 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
        u16 hdr_off;
        u32 *pkt_hdr;
 
-       /* This check is no longer done by usbnet */
-       if (skb->len < dev->net->hard_header_len)
+       /* At the end of the SKB, there's a header telling us how many packets
+        * are bundled into this buffer and where we can find an array of
+        * per-packet metadata (which contains elements encoded into u16).
+        */
+       if (skb->len < 4)
                return 0;
-
        skb_trim(skb, skb->len - 4);
        rx_hdr = get_unaligned_le32(skb_tail_pointer(skb));
-
        pkt_cnt = (u16)rx_hdr;
        hdr_off = (u16)(rx_hdr >> 16);
+
+       if (pkt_cnt == 0)
+               return 0;
+
+       /* Make sure that the bounds of the metadata array are inside the SKB
+        * (and in front of the counter at the end).
+        */
+       if (pkt_cnt * 2 + hdr_off > skb->len)
+               return 0;
        pkt_hdr = (u32 *)(skb->data + hdr_off);
 
-       while (pkt_cnt--) {
+       /* Packets must not overlap the metadata array */
+       skb_trim(skb, hdr_off);
+
+       for (; ; pkt_cnt--, pkt_hdr++) {
                u16 pkt_len;
 
                le32_to_cpus(pkt_hdr);
                pkt_len = (*pkt_hdr >> 16) & 0x1fff;
 
-               /* Check CRC or runt packet */
-               if ((*pkt_hdr & AX_RXHDR_CRC_ERR) ||
-                   (*pkt_hdr & AX_RXHDR_DROP_ERR)) {
-                       skb_pull(skb, (pkt_len + 7) & 0xFFF8);
-                       pkt_hdr++;
-                       continue;
-               }
-
-               if (pkt_cnt == 0) {
-                       skb->len = pkt_len;
-                       /* Skip IP alignment pseudo header */
-                       skb_pull(skb, 2);
-                       skb_set_tail_pointer(skb, skb->len);
-                       skb->truesize = pkt_len + sizeof(struct sk_buff);
-                       ax88179_rx_checksum(skb, pkt_hdr);
-                       return 1;
-               }
+               if (pkt_len > skb->len)
+                       return 0;
 
-               ax_skb = skb_clone(skb, GFP_ATOMIC);
-               if (ax_skb) {
+               /* Check CRC or runt packet */
+               if (((*pkt_hdr & (AX_RXHDR_CRC_ERR | AX_RXHDR_DROP_ERR)) == 0) &&
+                   pkt_len >= 2 + ETH_HLEN) {
+                       bool last = (pkt_cnt == 0);
+
+                       if (last) {
+                               ax_skb = skb;
+                       } else {
+                               ax_skb = skb_clone(skb, GFP_ATOMIC);
+                               if (!ax_skb)
+                                       return 0;
+                       }
                        ax_skb->len = pkt_len;
                        /* Skip IP alignment pseudo header */
                        skb_pull(ax_skb, 2);
                        skb_set_tail_pointer(ax_skb, ax_skb->len);
                        ax_skb->truesize = pkt_len + sizeof(struct sk_buff);
                        ax88179_rx_checksum(ax_skb, pkt_hdr);
+
+                       if (last)
+                               return 1;
+
                        usbnet_skb_return(dev, ax_skb);
-               } else {
-                       return 0;
                }
 
-               skb_pull(skb, (pkt_len + 7) & 0xFFF8);
-               pkt_hdr++;
+               /* Trim this packet away from the SKB */
+               if (!skb_pull(skb, (pkt_len + 7) & 0xFFF8))
+                       return 0;
        }
-       return 1;
 }
 
 static struct sk_buff *
index cd33955..6a769df 100644 (file)
@@ -121,7 +121,7 @@ static int ipheth_alloc_urbs(struct ipheth_device *iphone)
        if (tx_buf == NULL)
                goto free_rx_urb;
 
-       rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
+       rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
                                    GFP_KERNEL, &rx_urb->transfer_dma);
        if (rx_buf == NULL)
                goto free_tx_buf;
@@ -146,7 +146,7 @@ error_nomem:
 
 static void ipheth_free_urbs(struct ipheth_device *iphone)
 {
-       usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf,
+       usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, iphone->rx_buf,
                          iphone->rx_urb->transfer_dma);
        usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
                          iphone->tx_urb->transfer_dma);
@@ -317,7 +317,7 @@ static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags)
 
        usb_fill_bulk_urb(dev->rx_urb, udev,
                          usb_rcvbulkpipe(udev, dev->bulk_in),
-                         dev->rx_buf, IPHETH_BUF_SIZE,
+                         dev->rx_buf, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
                          ipheth_rcvbulk_callback,
                          dev);
        dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
index 37e5f34..3353e76 100644 (file)
@@ -1400,6 +1400,8 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x413c, 0x81d7, 0)},    /* Dell Wireless 5821e */
        {QMI_FIXED_INTF(0x413c, 0x81d7, 1)},    /* Dell Wireless 5821e preproduction config */
        {QMI_FIXED_INTF(0x413c, 0x81e0, 0)},    /* Dell Wireless 5821e with eSIM support*/
+       {QMI_FIXED_INTF(0x413c, 0x81e4, 0)},    /* Dell Wireless 5829e with eSIM support*/
+       {QMI_FIXED_INTF(0x413c, 0x81e6, 0)},    /* Dell Wireless 5829e */
        {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)},    /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
        {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)},    /* HP lt4120 Snapdragon X5 LTE */
        {QMI_QUIRK_SET_DTR(0x22de, 0x9051, 2)}, /* Hucom Wireless HM-211S/K */
index 354a963..d29fb97 100644 (file)
@@ -265,9 +265,10 @@ static void __veth_xdp_flush(struct veth_rq *rq)
 {
        /* Write ptr_ring before reading rx_notify_masked */
        smp_mb();
-       if (!rq->rx_notify_masked) {
-               rq->rx_notify_masked = true;
-               napi_schedule(&rq->xdp_napi);
+       if (!READ_ONCE(rq->rx_notify_masked) &&
+           napi_schedule_prep(&rq->xdp_napi)) {
+               WRITE_ONCE(rq->rx_notify_masked, true);
+               __napi_schedule(&rq->xdp_napi);
        }
 }
 
@@ -912,8 +913,10 @@ static int veth_poll(struct napi_struct *napi, int budget)
                /* Write rx_notify_masked before reading ptr_ring */
                smp_store_mb(rq->rx_notify_masked, false);
                if (unlikely(!__ptr_ring_empty(&rq->xdp_ring))) {
-                       rq->rx_notify_masked = true;
-                       napi_schedule(&rq->xdp_napi);
+                       if (napi_schedule_prep(&rq->xdp_napi)) {
+                               WRITE_ONCE(rq->rx_notify_masked, true);
+                               __napi_schedule(&rq->xdp_napi);
+                       }
                }
        }
 
index 5e0bfda..79005ea 100644 (file)
@@ -368,6 +368,7 @@ EXPORT_SYMBOL_GPL(nvme_complete_rq);
 
 void nvme_complete_batch_req(struct request *req)
 {
+       trace_nvme_complete_rq(req);
        nvme_cleanup_cmd(req);
        nvme_end_req_zoned(req);
 }
@@ -4253,7 +4254,14 @@ static void nvme_async_event_work(struct work_struct *work)
                container_of(work, struct nvme_ctrl, async_event_work);
 
        nvme_aen_uevent(ctrl);
-       ctrl->ops->submit_async_event(ctrl);
+
+       /*
+        * The transport drivers must guarantee AER submission here is safe by
+        * flushing ctrl async_event_work after changing the controller state
+        * from LIVE and before freeing the admin queue.
+       */
+       if (ctrl->state == NVME_CTRL_LIVE)
+               ctrl->ops->submit_async_event(ctrl);
 }
 
 static bool nvme_ctrl_pp_status(struct nvme_ctrl *ctrl)
index 7ae041e..f79a66d 100644 (file)
@@ -1092,7 +1092,6 @@ static void __nvmf_concat_opt_tokens(struct seq_file *seq_file)
 static int nvmf_dev_show(struct seq_file *seq_file, void *private)
 {
        struct nvme_ctrl *ctrl;
-       int ret = 0;
 
        mutex_lock(&nvmf_dev_mutex);
        ctrl = seq_file->private;
@@ -1106,7 +1105,7 @@ static int nvmf_dev_show(struct seq_file *seq_file, void *private)
 
 out_unlock:
        mutex_unlock(&nvmf_dev_mutex);
-       return ret;
+       return 0;
 }
 
 static int nvmf_dev_open(struct inode *inode, struct file *file)
index c3203ff..1e3a09c 100644 (file)
@@ -170,6 +170,7 @@ nvmf_ctlr_matches_baseopts(struct nvme_ctrl *ctrl,
                        struct nvmf_ctrl_options *opts)
 {
        if (ctrl->state == NVME_CTRL_DELETING ||
+           ctrl->state == NVME_CTRL_DELETING_NOIO ||
            ctrl->state == NVME_CTRL_DEAD ||
            strcmp(opts->subsysnqn, ctrl->opts->subsysnqn) ||
            strcmp(opts->host->nqn, ctrl->opts->host->nqn) ||
index d8585df..6a99ed6 100644 (file)
@@ -3391,7 +3391,8 @@ static const struct pci_device_id nvme_id_table[] = {
                                NVME_QUIRK_DEALLOCATE_ZEROES, },
        { PCI_VDEVICE(INTEL, 0x0a54),   /* Intel P4500/P4600 */
                .driver_data = NVME_QUIRK_STRIPE_SIZE |
-                               NVME_QUIRK_DEALLOCATE_ZEROES, },
+                               NVME_QUIRK_DEALLOCATE_ZEROES |
+                               NVME_QUIRK_IGNORE_DEV_SUBNQN, },
        { PCI_VDEVICE(INTEL, 0x0a55),   /* Dell Express Flash P4600 */
                .driver_data = NVME_QUIRK_STRIPE_SIZE |
                                NVME_QUIRK_DEALLOCATE_ZEROES, },
index 850f84d..9c55e4b 100644 (file)
@@ -1200,6 +1200,7 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work)
                        struct nvme_rdma_ctrl, err_work);
 
        nvme_stop_keep_alive(&ctrl->ctrl);
+       flush_work(&ctrl->ctrl.async_event_work);
        nvme_rdma_teardown_io_queues(ctrl, false);
        nvme_start_queues(&ctrl->ctrl);
        nvme_rdma_teardown_admin_queue(ctrl, false);
index 4ceb286..891a36d 100644 (file)
@@ -913,7 +913,15 @@ static inline void nvme_tcp_done_send_req(struct nvme_tcp_queue *queue)
 
 static void nvme_tcp_fail_request(struct nvme_tcp_request *req)
 {
-       nvme_tcp_end_request(blk_mq_rq_from_pdu(req), NVME_SC_HOST_PATH_ERROR);
+       if (nvme_tcp_async_req(req)) {
+               union nvme_result res = {};
+
+               nvme_complete_async_event(&req->queue->ctrl->ctrl,
+                               cpu_to_le16(NVME_SC_HOST_PATH_ERROR), &res);
+       } else {
+               nvme_tcp_end_request(blk_mq_rq_from_pdu(req),
+                               NVME_SC_HOST_PATH_ERROR);
+       }
 }
 
 static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
@@ -2096,6 +2104,7 @@ static void nvme_tcp_error_recovery_work(struct work_struct *work)
        struct nvme_ctrl *ctrl = &tcp_ctrl->ctrl;
 
        nvme_stop_keep_alive(ctrl);
+       flush_work(&ctrl->async_event_work);
        nvme_tcp_teardown_io_queues(ctrl, false);
        /* unquiesce to fail fast pending requests */
        nvme_start_queues(ctrl);
index 489586a..768d33f 100644 (file)
@@ -356,8 +356,8 @@ static int j721e_pcie_probe(struct platform_device *pdev)
        const struct j721e_pcie_data *data;
        struct cdns_pcie *cdns_pcie;
        struct j721e_pcie *pcie;
-       struct cdns_pcie_rc *rc;
-       struct cdns_pcie_ep *ep;
+       struct cdns_pcie_rc *rc = NULL;
+       struct cdns_pcie_ep *ep = NULL;
        struct gpio_desc *gpiod;
        void __iomem *base;
        struct clk *clk;
@@ -376,6 +376,46 @@ static int j721e_pcie_probe(struct platform_device *pdev)
        if (!pcie)
                return -ENOMEM;
 
+       switch (mode) {
+       case PCI_MODE_RC:
+               if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST))
+                       return -ENODEV;
+
+               bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
+               if (!bridge)
+                       return -ENOMEM;
+
+               if (!data->byte_access_allowed)
+                       bridge->ops = &cdns_ti_pcie_host_ops;
+               rc = pci_host_bridge_priv(bridge);
+               rc->quirk_retrain_flag = data->quirk_retrain_flag;
+               rc->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
+
+               cdns_pcie = &rc->pcie;
+               cdns_pcie->dev = dev;
+               cdns_pcie->ops = &j721e_pcie_ops;
+               pcie->cdns_pcie = cdns_pcie;
+               break;
+       case PCI_MODE_EP:
+               if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP))
+                       return -ENODEV;
+
+               ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+               if (!ep)
+                       return -ENOMEM;
+
+               ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
+
+               cdns_pcie = &ep->pcie;
+               cdns_pcie->dev = dev;
+               cdns_pcie->ops = &j721e_pcie_ops;
+               pcie->cdns_pcie = cdns_pcie;
+               break;
+       default:
+               dev_err(dev, "INVALID device type %d\n", mode);
+               return 0;
+       }
+
        pcie->mode = mode;
        pcie->linkdown_irq_regfield = data->linkdown_irq_regfield;
 
@@ -426,28 +466,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 
        switch (mode) {
        case PCI_MODE_RC:
-               if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) {
-                       ret = -ENODEV;
-                       goto err_get_sync;
-               }
-
-               bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
-               if (!bridge) {
-                       ret = -ENOMEM;
-                       goto err_get_sync;
-               }
-
-               if (!data->byte_access_allowed)
-                       bridge->ops = &cdns_ti_pcie_host_ops;
-               rc = pci_host_bridge_priv(bridge);
-               rc->quirk_retrain_flag = data->quirk_retrain_flag;
-               rc->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
-
-               cdns_pcie = &rc->pcie;
-               cdns_pcie->dev = dev;
-               cdns_pcie->ops = &j721e_pcie_ops;
-               pcie->cdns_pcie = cdns_pcie;
-
                gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
                if (IS_ERR(gpiod)) {
                        ret = PTR_ERR(gpiod);
@@ -497,23 +515,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 
                break;
        case PCI_MODE_EP:
-               if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) {
-                       ret = -ENODEV;
-                       goto err_get_sync;
-               }
-
-               ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
-               if (!ep) {
-                       ret = -ENOMEM;
-                       goto err_get_sync;
-               }
-               ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
-
-               cdns_pcie = &ep->pcie;
-               cdns_pcie->dev = dev;
-               cdns_pcie->ops = &j721e_pcie_ops;
-               pcie->cdns_pcie = cdns_pcie;
-
                ret = cdns_pcie_init_phy(dev, cdns_pcie);
                if (ret) {
                        dev_err(dev, "Failed to init phy\n");
@@ -525,8 +526,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
                        goto err_pcie_setup;
 
                break;
-       default:
-               dev_err(dev, "INVALID device type %d\n", mode);
        }
 
        return 0;
index fa6886d..c625fc6 100644 (file)
@@ -756,22 +756,28 @@ static int __exit kirin_pcie_remove(struct platform_device *pdev)
        return 0;
 }
 
+struct kirin_pcie_data {
+       enum pcie_kirin_phy_type        phy_type;
+};
+
+static const struct kirin_pcie_data kirin_960_data = {
+       .phy_type = PCIE_KIRIN_INTERNAL_PHY,
+};
+
+static const struct kirin_pcie_data kirin_970_data = {
+       .phy_type = PCIE_KIRIN_EXTERNAL_PHY,
+};
+
 static const struct of_device_id kirin_pcie_match[] = {
-       {
-               .compatible = "hisilicon,kirin960-pcie",
-               .data = (void *)PCIE_KIRIN_INTERNAL_PHY
-       },
-       {
-               .compatible = "hisilicon,kirin970-pcie",
-               .data = (void *)PCIE_KIRIN_EXTERNAL_PHY
-       },
+       { .compatible = "hisilicon,kirin960-pcie", .data = &kirin_960_data },
+       { .compatible = "hisilicon,kirin970-pcie", .data = &kirin_970_data },
        {},
 };
 
 static int kirin_pcie_probe(struct platform_device *pdev)
 {
-       enum pcie_kirin_phy_type phy_type;
        struct device *dev = &pdev->dev;
+       const struct kirin_pcie_data *data;
        struct kirin_pcie *kirin_pcie;
        struct dw_pcie *pci;
        int ret;
@@ -781,13 +787,12 @@ static int kirin_pcie_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       phy_type = (long)of_device_get_match_data(dev);
-       if (!phy_type) {
+       data = of_device_get_match_data(dev);
+       if (!data) {
                dev_err(dev, "OF data missing\n");
                return -EINVAL;
        }
 
-
        kirin_pcie = devm_kzalloc(dev, sizeof(struct kirin_pcie), GFP_KERNEL);
        if (!kirin_pcie)
                return -ENOMEM;
@@ -800,7 +805,7 @@ static int kirin_pcie_probe(struct platform_device *pdev)
        pci->ops = &kirin_dw_pcie_ops;
        pci->pp.ops = &kirin_pcie_host_ops;
        kirin_pcie->pci = pci;
-       kirin_pcie->type = phy_type;
+       kirin_pcie->type = data->phy_type;
 
        ret = kirin_pcie_get_resource(kirin_pcie, pdev);
        if (ret)
index 3824862..33eb37a 100644 (file)
@@ -109,15 +109,6 @@ static inline void pcie_write(struct mt7621_pcie *pcie, u32 val, u32 reg)
        writel_relaxed(val, pcie->base + reg);
 }
 
-static inline void pcie_rmw(struct mt7621_pcie *pcie, u32 reg, u32 clr, u32 set)
-{
-       u32 val = readl_relaxed(pcie->base + reg);
-
-       val &= ~clr;
-       val |= set;
-       writel_relaxed(val, pcie->base + reg);
-}
-
 static inline u32 pcie_port_read(struct mt7621_pcie_port *port, u32 reg)
 {
        return readl_relaxed(port->base + reg);
@@ -557,7 +548,7 @@ static struct platform_driver mt7621_pcie_driver = {
        .remove = mt7621_pcie_remove,
        .driver = {
                .name = "mt7621-pci",
-               .of_match_table = of_match_ptr(mt7621_pcie_ids),
+               .of_match_table = mt7621_pcie_ids,
        },
 };
 builtin_platform_driver(mt7621_pcie_driver);
index 0d63541..e9cf318 100644 (file)
@@ -28,6 +28,7 @@ void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
                msi_domain_free_irqs_descs_locked(domain, &dev->dev);
        else
                pci_msi_legacy_teardown_msi_irqs(dev);
+       msi_free_msi_descs(&dev->dev);
 }
 
 /**
@@ -171,8 +172,7 @@ struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
        if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
                pci_msi_domain_update_chip_ops(info);
 
-       info->flags |= MSI_FLAG_ACTIVATE_EARLY | MSI_FLAG_DEV_SYSFS |
-                      MSI_FLAG_FREE_MSI_DESCS;
+       info->flags |= MSI_FLAG_ACTIVATE_EARLY | MSI_FLAG_DEV_SYSFS;
        if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE))
                info->flags |= MSI_FLAG_MUST_REACTIVATE;
 
index cdbb468..db761ad 100644 (file)
@@ -77,5 +77,4 @@ void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev)
 {
        msi_device_destroy_sysfs(&dev->dev);
        arch_teardown_msi_irqs(dev);
-       msi_free_msi_descs(&dev->dev);
 }
index c19c7ca..9037a78 100644 (file)
@@ -1111,7 +1111,8 @@ const struct cpumask *pci_irq_get_affinity(struct pci_dev *dev, int nr)
        if (!desc)
                return cpu_possible_mask;
 
-       if (WARN_ON_ONCE(!desc->affinity))
+       /* MSI[X] interrupts can be allocated without affinity descriptor */
+       if (!desc->affinity)
                return NULL;
 
        /*
index bda6308..604feeb 100644 (file)
@@ -166,6 +166,9 @@ static int pcie_init_service_irqs(struct pci_dev *dev, int *irqs, int mask)
 {
        int ret, i;
 
+       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
+               irqs[i] = -1;
+
        /*
         * If we support PME but can't use MSI/MSI-X for it, we have to
         * fall back to INTx or other interrupts, e.g., a system shared
@@ -314,10 +317,8 @@ static int pcie_device_init(struct pci_dev *pdev, int service, int irq)
  */
 int pcie_port_device_register(struct pci_dev *dev)
 {
-       int status, capabilities, irq_services, i, nr_service;
-       int irqs[PCIE_PORT_DEVICE_MAXSERVICES] = {
-               [0 ... PCIE_PORT_DEVICE_MAXSERVICES-1] = -1
-       };
+       int status, capabilities, i, nr_service;
+       int irqs[PCIE_PORT_DEVICE_MAXSERVICES];
 
        /* Enable PCI Express port device */
        status = pci_enable_device(dev);
@@ -330,32 +331,18 @@ int pcie_port_device_register(struct pci_dev *dev)
                return 0;
 
        pci_set_master(dev);
-
-       irq_services = 0;
-       if (IS_ENABLED(CONFIG_PCIE_PME))
-               irq_services |= PCIE_PORT_SERVICE_PME;
-       if (IS_ENABLED(CONFIG_PCIEAER))
-               irq_services |= PCIE_PORT_SERVICE_AER;
-       if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
-               irq_services |= PCIE_PORT_SERVICE_HP;
-       if (IS_ENABLED(CONFIG_PCIE_DPC))
-               irq_services |= PCIE_PORT_SERVICE_DPC;
-       irq_services &= capabilities;
-
-       if (irq_services) {
-               /*
-                * Initialize service IRQs. Don't use service devices that
-                * require interrupts if there is no way to generate them.
-                * However, some drivers may have a polling mode (e.g.
-                * pciehp_poll_mode) that can be used in the absence of IRQs.
-                * Allow them to determine if that is to be used.
-                */
-               status = pcie_init_service_irqs(dev, irqs, irq_services);
-               if (status) {
-                       irq_services &= PCIE_PORT_SERVICE_HP;
-                       if (!irq_services)
-                               goto error_disable;
-               }
+       /*
+        * Initialize service irqs. Don't use service devices that
+        * require interrupts if there is no way to generate them.
+        * However, some drivers may have a polling mode (e.g. pciehp_poll_mode)
+        * that can be used in the absence of irqs.  Allow them to determine
+        * if that is to be used.
+        */
+       status = pcie_init_service_irqs(dev, irqs, capabilities);
+       if (status) {
+               capabilities &= PCIE_PORT_SERVICE_HP;
+               if (!capabilities)
+                       goto error_disable;
        }
 
        /* Allocate child services if any */
index cd2332b..fdbd64c 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/bitfield.h>
 #include <linux/bitops.h>
+#include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/io.h>
@@ -250,7 +251,7 @@ static int phy_meson_axg_mipi_dphy_power_on(struct phy *phy)
                     (DIV_ROUND_UP(priv->config.clk_zero, temp) << 16) |
                     (DIV_ROUND_UP(priv->config.clk_prepare, temp) << 24));
        regmap_write(priv->regmap, MIPI_DSI_CLK_TIM1,
-                    DIV_ROUND_UP(priv->config.clk_pre, temp));
+                    DIV_ROUND_UP(priv->config.clk_pre, BITS_PER_BYTE));
 
        regmap_write(priv->regmap, MIPI_DSI_HS_TIM,
                     DIV_ROUND_UP(priv->config.hs_exit, temp) |
index f81e237..849c420 100644 (file)
@@ -97,8 +97,7 @@ config PHY_BRCM_USB
        depends on OF
        select GENERIC_PHY
        select SOC_BRCMSTB if ARCH_BRCMSTB
-       default ARCH_BCM4908
-       default ARCH_BRCMSTB
+       default ARCH_BCM4908 || ARCH_BRCMSTB
        help
          Enable this to support the Broadcom STB USB PHY.
          This driver is required by the USB XHCI, EHCI and OHCI
index 116fb23..0f1deb6 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/soc/brcmstb/brcmstb.h>
 #include <dt-bindings/phy/phy.h>
 #include <linux/mfd/syscon.h>
+#include <linux/suspend.h>
 
 #include "phy-brcm-usb-init.h"
 
@@ -70,12 +71,35 @@ struct brcm_usb_phy_data {
        int                     init_count;
        int                     wake_irq;
        struct brcm_usb_phy     phys[BRCM_USB_PHY_ID_MAX];
+       struct notifier_block   pm_notifier;
+       bool                    pm_active;
 };
 
 static s8 *node_reg_names[BRCM_REGS_MAX] = {
        "crtl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec"
 };
 
+static int brcm_pm_notifier(struct notifier_block *notifier,
+                           unsigned long pm_event,
+                           void *unused)
+{
+       struct brcm_usb_phy_data *priv =
+               container_of(notifier, struct brcm_usb_phy_data, pm_notifier);
+
+       switch (pm_event) {
+       case PM_HIBERNATION_PREPARE:
+       case PM_SUSPEND_PREPARE:
+               priv->pm_active = true;
+               break;
+       case PM_POST_RESTORE:
+       case PM_POST_HIBERNATION:
+       case PM_POST_SUSPEND:
+               priv->pm_active = false;
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
 static irqreturn_t brcm_usb_phy_wake_isr(int irq, void *dev_id)
 {
        struct phy *gphy = dev_id;
@@ -91,6 +115,9 @@ static int brcm_usb_phy_init(struct phy *gphy)
        struct brcm_usb_phy_data *priv =
                container_of(phy, struct brcm_usb_phy_data, phys[phy->id]);
 
+       if (priv->pm_active)
+               return 0;
+
        /*
         * Use a lock to make sure a second caller waits until
         * the base phy is inited before using it.
@@ -120,6 +147,9 @@ static int brcm_usb_phy_exit(struct phy *gphy)
        struct brcm_usb_phy_data *priv =
                container_of(phy, struct brcm_usb_phy_data, phys[phy->id]);
 
+       if (priv->pm_active)
+               return 0;
+
        dev_dbg(&gphy->dev, "EXIT\n");
        if (phy->id == BRCM_USB_PHY_2_0)
                brcm_usb_uninit_eohci(&priv->ini);
@@ -488,6 +518,9 @@ static int brcm_usb_phy_probe(struct platform_device *pdev)
        if (err)
                return err;
 
+       priv->pm_notifier.notifier_call = brcm_pm_notifier;
+       register_pm_notifier(&priv->pm_notifier);
+
        mutex_init(&priv->mutex);
 
        /* make sure invert settings are correct */
@@ -528,7 +561,10 @@ static int brcm_usb_phy_probe(struct platform_device *pdev)
 
 static int brcm_usb_phy_remove(struct platform_device *pdev)
 {
+       struct brcm_usb_phy_data *priv = dev_get_drvdata(&pdev->dev);
+
        sysfs_remove_group(&pdev->dev.kobj, &brcm_usb_phy_group);
+       unregister_pm_notifier(&priv->pm_notifier);
 
        return 0;
 }
@@ -539,6 +575,7 @@ static int brcm_usb_phy_suspend(struct device *dev)
        struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
 
        if (priv->init_count) {
+               dev_dbg(dev, "SUSPEND\n");
                priv->ini.wake_enabled = device_may_wakeup(dev);
                if (priv->phys[BRCM_USB_PHY_3_0].inited)
                        brcm_usb_uninit_xhci(&priv->ini);
@@ -578,6 +615,7 @@ static int brcm_usb_phy_resume(struct device *dev)
         * Uninitialize anything that wasn't previously initialized.
         */
        if (priv->init_count) {
+               dev_dbg(dev, "RESUME\n");
                if (priv->wake_irq >= 0)
                        disable_irq_wake(priv->wake_irq);
                brcm_usb_init_common(&priv->ini);
index da24acd..e265647 100644 (file)
@@ -1338,7 +1338,7 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        const struct cdns_sierra_data *data;
        unsigned int id_value;
-       int i, ret, node = 0;
+       int ret, node = 0;
        void __iomem *base;
        struct device_node *dn = dev->of_node, *child;
 
@@ -1416,7 +1416,8 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
                        dev_err(dev, "failed to get reset %s\n",
                                child->full_name);
                        ret = PTR_ERR(sp->phys[node].lnk_rst);
-                       goto put_child2;
+                       of_node_put(child);
+                       goto put_control;
                }
 
                if (!sp->autoconf) {
@@ -1424,7 +1425,9 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
                        if (ret) {
                                dev_err(dev, "missing property in node %s\n",
                                        child->name);
-                               goto put_child;
+                               of_node_put(child);
+                               reset_control_put(sp->phys[node].lnk_rst);
+                               goto put_control;
                        }
                }
 
@@ -1434,7 +1437,9 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
 
                if (IS_ERR(gphy)) {
                        ret = PTR_ERR(gphy);
-                       goto put_child;
+                       of_node_put(child);
+                       reset_control_put(sp->phys[node].lnk_rst);
+                       goto put_control;
                }
                sp->phys[node].phy = gphy;
                phy_set_drvdata(gphy, &sp->phys[node]);
@@ -1446,26 +1451,28 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
        if (sp->num_lanes > SIERRA_MAX_LANES) {
                ret = -EINVAL;
                dev_err(dev, "Invalid lane configuration\n");
-               goto put_child2;
+               goto put_control;
        }
 
        /* If more than one subnode, configure the PHY as multilink */
        if (!sp->autoconf && sp->nsubnodes > 1) {
                ret = cdns_sierra_phy_configure_multilink(sp);
                if (ret)
-                       goto put_child2;
+                       goto put_control;
        }
 
        pm_runtime_enable(dev);
        phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
-       return PTR_ERR_OR_ZERO(phy_provider);
-
-put_child:
-       node++;
-put_child2:
-       for (i = 0; i < node; i++)
-               reset_control_put(sp->phys[i].lnk_rst);
-       of_node_put(child);
+       if (IS_ERR(phy_provider)) {
+               ret = PTR_ERR(phy_provider);
+               goto put_control;
+       }
+
+       return 0;
+
+put_control:
+       while (--node >= 0)
+               reset_control_put(sp->phys[node].lnk_rst);
 clk_disable:
        cdns_sierra_phy_disable_clocks(sp);
        reset_control_assert(sp->apb_rst);
index 6d30710..8ee7682 100644 (file)
@@ -992,7 +992,7 @@ static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instanc
                /* no efuse, ignore it */
                if (!instance->efuse_intr &&
                    !instance->efuse_rx_imp &&
-                   !instance->efuse_rx_imp) {
+                   !instance->efuse_tx_imp) {
                        dev_warn(dev, "no u3 intr efuse, but dts enable it\n");
                        instance->efuse_sw_en = 0;
                        break;
index 288c9c6..ccb4045 100644 (file)
@@ -36,7 +36,7 @@ int phy_mipi_dphy_get_default_config(unsigned long pixel_clock,
 
        cfg->clk_miss = 0;
        cfg->clk_post = 60000 + 52 * ui;
-       cfg->clk_pre = 8000;
+       cfg->clk_pre = 8;
        cfg->clk_prepare = 38000;
        cfg->clk_settle = 95000;
        cfg->clk_term_en = 0;
@@ -97,7 +97,7 @@ int phy_mipi_dphy_config_validate(struct phy_configure_opts_mipi_dphy *cfg)
        if (cfg->clk_post < (60000 + 52 * ui))
                return -EINVAL;
 
-       if (cfg->clk_pre < 8000)
+       if (cfg->clk_pre < 8)
                return -EINVAL;
 
        if (cfg->clk_prepare < 38000 || cfg->clk_prepare > 95000)
index 347dc79..630e01b 100644 (file)
@@ -5,6 +5,7 @@
  * Author: Wyon Bi <bivvy.bi@rock-chips.com>
  */
 
+#include <linux/bits.h>
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/iopoll.h>
@@ -364,7 +365,7 @@ static void inno_dsidphy_mipi_mode_enable(struct inno_dsidphy *inno)
         * The value of counter for HS Tclk-pre
         * Tclk-pre = Tpin_txbyteclkhs * value
         */
-       clk_pre = DIV_ROUND_UP(cfg->clk_pre, t_txbyteclkhs);
+       clk_pre = DIV_ROUND_UP(cfg->clk_pre, BITS_PER_BYTE);
 
        /*
         * The value of counter for HS Tlpx Time
index 2ce9bfd..007a23c 100644 (file)
@@ -304,7 +304,7 @@ static int stm32_usbphyc_pll_enable(struct stm32_usbphyc *usbphyc)
 
                ret = __stm32_usbphyc_pll_disable(usbphyc);
                if (ret)
-                       return ret;
+                       goto dec_n_pll_cons;
        }
 
        ret = stm32_usbphyc_regulators_enable(usbphyc);
index b3384c3..da546c3 100644 (file)
@@ -233,6 +233,7 @@ static const struct clk_div_table clk_div_table[] = {
        { .val = 1, .div = 2, },
        { .val = 2, .div = 4, },
        { .val = 3, .div = 8, },
+       { /* sentinel */ },
 };
 
 static const struct wiz_clk_div_sel clk_div_sel[] = {
index f478d8a..9be9535 100644 (file)
 #define PROT_BUS_WIDTH_10              0x0
 #define PROT_BUS_WIDTH_20              0x1
 #define PROT_BUS_WIDTH_40              0x2
-#define PROT_BUS_WIDTH_SHIFT           2
+#define PROT_BUS_WIDTH_SHIFT(n)                ((n) * 2)
+#define PROT_BUS_WIDTH_MASK(n)         GENMASK((n) * 2 + 1, (n) * 2)
 
 /* Number of GT lanes */
 #define NUM_LANES                      4
@@ -445,12 +446,12 @@ static void xpsgtr_phy_init_sata(struct xpsgtr_phy *gtr_phy)
 static void xpsgtr_phy_init_sgmii(struct xpsgtr_phy *gtr_phy)
 {
        struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
+       u32 mask = PROT_BUS_WIDTH_MASK(gtr_phy->lane);
+       u32 val = PROT_BUS_WIDTH_10 << PROT_BUS_WIDTH_SHIFT(gtr_phy->lane);
 
        /* Set SGMII protocol TX and RX bus width to 10 bits. */
-       xpsgtr_write(gtr_dev, TX_PROT_BUS_WIDTH,
-                    PROT_BUS_WIDTH_10 << (gtr_phy->lane * PROT_BUS_WIDTH_SHIFT));
-       xpsgtr_write(gtr_dev, RX_PROT_BUS_WIDTH,
-                    PROT_BUS_WIDTH_10 << (gtr_phy->lane * PROT_BUS_WIDTH_SHIFT));
+       xpsgtr_clr_set(gtr_dev, TX_PROT_BUS_WIDTH, mask, val);
+       xpsgtr_clr_set(gtr_dev, RX_PROT_BUS_WIDTH, mask, val);
 
        xpsgtr_bypass_scrambler_8b10b(gtr_phy);
 }
index 08c364d..f64d29f 100644 (file)
@@ -42,9 +42,9 @@ obj-$(CONFIG_PINCTRL_PISTACHIO)       += pinctrl-pistachio.o
 obj-$(CONFIG_PINCTRL_RK805)    += pinctrl-rk805.o
 obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
 obj-$(CONFIG_PINCTRL_SINGLE)   += pinctrl-single.o
+obj-$(CONFIG_PINCTRL_ST)       += pinctrl-st.o
 obj-$(CONFIG_PINCTRL_STARFIVE) += pinctrl-starfive.o
 obj-$(CONFIG_PINCTRL_STMFX)    += pinctrl-stmfx.o
-obj-$(CONFIG_PINCTRL_ST)       += pinctrl-st.o
 obj-$(CONFIG_PINCTRL_SX150X)   += pinctrl-sx150x.o
 obj-$(CONFIG_PINCTRL_TB10X)    += pinctrl-tb10x.o
 obj-$(CONFIG_PINCTRL_THUNDERBAY) += pinctrl-thunderbay.o
index 5123f4c..ac1e400 100644 (file)
@@ -35,6 +35,7 @@ config PINCTRL_BCM63XX
        select PINCONF
        select GENERIC_PINCONF
        select GPIOLIB
+       select REGMAP
        select GPIO_REGMAP
 
 config PINCTRL_BCM6318
index c4ebfa8..47e433e 100644 (file)
@@ -1269,16 +1269,18 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
                                     sizeof(*girq->parents),
                                     GFP_KERNEL);
        if (!girq->parents) {
-               pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto out_remove;
        }
 
        if (is_7211) {
                pc->wake_irq = devm_kcalloc(dev, BCM2835_NUM_IRQS,
                                            sizeof(*pc->wake_irq),
                                            GFP_KERNEL);
-               if (!pc->wake_irq)
-                       return -ENOMEM;
+               if (!pc->wake_irq) {
+                       err = -ENOMEM;
+                       goto out_remove;
+               }
        }
 
        /*
@@ -1306,8 +1308,10 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
 
                len = strlen(dev_name(pc->dev)) + 16;
                name = devm_kzalloc(pc->dev, len, GFP_KERNEL);
-               if (!name)
-                       return -ENOMEM;
+               if (!name) {
+                       err = -ENOMEM;
+                       goto out_remove;
+               }
 
                snprintf(name, len, "%s:bank%d", dev_name(pc->dev), i);
 
@@ -1326,11 +1330,14 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
        err = gpiochip_add_data(&pc->gpio_chip, pc);
        if (err) {
                dev_err(dev, "could not add GPIO chip\n");
-               pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
-               return err;
+               goto out_remove;
        }
 
        return 0;
+
+out_remove:
+       pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
+       return err;
 }
 
 static struct platform_driver bcm2835_pinctrl_driver = {
index abffda1..1d58182 100644 (file)
@@ -1471,8 +1471,9 @@ static void chv_gpio_irq_handler(struct irq_desc *desc)
 
                offset = cctx->intr_lines[intr_line];
                if (offset == CHV_INVALID_HWIRQ) {
-                       dev_err(dev, "interrupt on unused interrupt line %u\n", intr_line);
-                       continue;
+                       dev_warn_once(dev, "interrupt on unmapped interrupt line %u\n", intr_line);
+                       /* Some boards expect hwirq 0 to trigger in this case */
+                       offset = 0;
                }
 
                generic_handle_domain_irq(gc->irq.domain, offset);
index 8575097..826d494 100644 (file)
@@ -451,8 +451,8 @@ static void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
        value &= ~PADCFG0_PMODE_MASK;
        value |= PADCFG0_PMODE_GPIO;
 
-       /* Disable input and output buffers */
-       value |= PADCFG0_GPIORXDIS;
+       /* Disable TX buffer and enable RX (this will be input) */
+       value &= ~PADCFG0_GPIORXDIS;
        value |= PADCFG0_GPIOTXDIS;
 
        /* Disable SCI/SMI/NMI generation */
@@ -497,9 +497,6 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
 
        intel_gpio_set_gpio_mode(padcfg0);
 
-       /* Disable TX buffer and enable RX (this will be input) */
-       __intel_gpio_set_direction(padcfg0, true);
-
        raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
@@ -1115,9 +1112,6 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned int type)
 
        intel_gpio_set_gpio_mode(reg);
 
-       /* Disable TX buffer and enable RX (this will be input) */
-       __intel_gpio_set_direction(reg, true);
-
        value = readl(reg);
 
        value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV);
@@ -1216,6 +1210,39 @@ static irqreturn_t intel_gpio_irq(int irq, void *data)
        return IRQ_RETVAL(ret);
 }
 
+static void intel_gpio_irq_init(struct intel_pinctrl *pctrl)
+{
+       int i;
+
+       for (i = 0; i < pctrl->ncommunities; i++) {
+               const struct intel_community *community;
+               void __iomem *base;
+               unsigned int gpp;
+
+               community = &pctrl->communities[i];
+               base = community->regs;
+
+               for (gpp = 0; gpp < community->ngpps; gpp++) {
+                       /* Mask and clear all interrupts */
+                       writel(0, base + community->ie_offset + gpp * 4);
+                       writel(0xffff, base + community->is_offset + gpp * 4);
+               }
+       }
+}
+
+static int intel_gpio_irq_init_hw(struct gpio_chip *gc)
+{
+       struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
+
+       /*
+        * Make sure the interrupt lines are in a proper state before
+        * further configuration.
+        */
+       intel_gpio_irq_init(pctrl);
+
+       return 0;
+}
+
 static int intel_gpio_add_community_ranges(struct intel_pinctrl *pctrl,
                                const struct intel_community *community)
 {
@@ -1320,6 +1347,7 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq)
        girq->num_parents = 0;
        girq->default_type = IRQ_TYPE_NONE;
        girq->handler = handle_bad_irq;
+       girq->init_hw = intel_gpio_irq_init_hw;
 
        ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl);
        if (ret) {
@@ -1695,26 +1723,6 @@ int intel_pinctrl_suspend_noirq(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(intel_pinctrl_suspend_noirq);
 
-static void intel_gpio_irq_init(struct intel_pinctrl *pctrl)
-{
-       size_t i;
-
-       for (i = 0; i < pctrl->ncommunities; i++) {
-               const struct intel_community *community;
-               void __iomem *base;
-               unsigned int gpp;
-
-               community = &pctrl->communities[i];
-               base = community->regs;
-
-               for (gpp = 0; gpp < community->ngpps; gpp++) {
-                       /* Mask and clear all interrupts */
-                       writel(0, base + community->ie_offset + gpp * 4);
-                       writel(0xffff, base + community->is_offset + gpp * 4);
-               }
-       }
-}
-
 static bool intel_gpio_update_reg(void __iomem *reg, u32 mask, u32 value)
 {
        u32 curr, updated;
index 8e081c9..639f113 100644 (file)
@@ -137,7 +137,8 @@ static inline int sgpio_addr_to_pin(struct sgpio_priv *priv, int port, int bit)
 
 static inline u32 sgpio_get_addr(struct sgpio_priv *priv, u32 rno, u32 off)
 {
-       return priv->properties->regoff[rno] + off;
+       return (priv->properties->regoff[rno] + off) *
+               regmap_get_reg_stride(priv->regs);
 }
 
 static u32 sgpio_readl(struct sgpio_priv *priv, u32 rno, u32 off)
index b5b47f4..79d44bc 100644 (file)
@@ -773,63 +773,42 @@ static int thunderbay_build_groups(struct thunderbay_pinctrl *tpc)
 
 static int thunderbay_add_functions(struct thunderbay_pinctrl *tpc, struct function_desc *funcs)
 {
-       struct function_desc *function = funcs;
        int i;
 
        /* Assign the groups for each function */
-       for (i = 0; i < tpc->soc->npins; i++) {
-               const struct pinctrl_pin_desc *pin_info = thunderbay_pins + i;
-               struct thunderbay_mux_desc *pin_mux = pin_info->drv_data;
-
-               while (pin_mux->name) {
-                       const char **grp;
-                       int j, grp_num, match = 0;
-                       size_t grp_size;
-                       struct function_desc *func;
-
-                       for (j = 0; j < tpc->nfuncs; j++) {
-                               if (!strcmp(pin_mux->name, function[j].name)) {
-                                       match = 1;
-                                       break;
-                               }
-                       }
-
-                       if (!match)
-                               return -EINVAL;
-
-                       func = function + j;
-                       grp_num = func->num_group_names;
-                       grp_size = sizeof(*func->group_names);
-
-                       if (!func->group_names) {
-                               func->group_names = devm_kcalloc(tpc->dev,
-                                                                grp_num,
-                                                                grp_size,
-                                                                GFP_KERNEL);
-                               if (!func->group_names) {
-                                       kfree(func);
-                                       return -ENOMEM;
-                               }
+       for (i = 0; i < tpc->nfuncs; i++) {
+               struct function_desc *func = &funcs[i];
+               const char **group_names;
+               unsigned int grp_idx = 0;
+               int j;
+
+               group_names = devm_kcalloc(tpc->dev, func->num_group_names,
+                                          sizeof(*group_names), GFP_KERNEL);
+               if (!group_names)
+                       return -ENOMEM;
+
+               for (j = 0; j < tpc->soc->npins; j++) {
+                       const struct pinctrl_pin_desc *pin_info = &thunderbay_pins[j];
+                       struct thunderbay_mux_desc *pin_mux;
+
+                       for (pin_mux = pin_info->drv_data; pin_mux->name; pin_mux++) {
+                               if (!strcmp(pin_mux->name, func->name))
+                                       group_names[grp_idx++] = pin_info->name;
                        }
-
-                       grp = func->group_names;
-                       while (*grp)
-                               grp++;
-
-                       *grp = pin_info->name;
-                       pin_mux++;
                }
+
+               func->group_names = group_names;
        }
 
        /* Add all functions */
        for (i = 0; i < tpc->nfuncs; i++) {
                pinmux_generic_add_function(tpc->pctrl,
-                                           function[i].name,
-                                           function[i].group_names,
-                                           function[i].num_group_names,
-                                           function[i].data);
+                                           funcs[i].name,
+                                           funcs[i].group_names,
+                                           funcs[i].num_group_names,
+                                           funcs[i].data);
        }
-       kfree(function);
+       kfree(funcs);
        return 0;
 }
 
@@ -839,27 +818,30 @@ static int thunderbay_build_functions(struct thunderbay_pinctrl *tpc)
        void *ptr;
        int pin;
 
-       /* Total number of functions is unknown at this point. Allocate first. */
+       /*
+        * Allocate maximum possible number of functions. Assume every pin
+        * being part of 8 (hw maximum) globally unique muxes.
+        */
        tpc->nfuncs = 0;
        thunderbay_funcs = kcalloc(tpc->soc->npins * 8,
                                   sizeof(*thunderbay_funcs), GFP_KERNEL);
        if (!thunderbay_funcs)
                return -ENOMEM;
 
-       /* Find total number of functions and each's properties */
+       /* Setup 1 function for each unique mux */
        for (pin = 0; pin < tpc->soc->npins; pin++) {
                const struct pinctrl_pin_desc *pin_info = thunderbay_pins + pin;
-               struct thunderbay_mux_desc *pin_mux = pin_info->drv_data;
+               struct thunderbay_mux_desc *pin_mux;
 
-               while (pin_mux->name) {
-                       struct function_desc *func = thunderbay_funcs;
+               for (pin_mux = pin_info->drv_data; pin_mux->name; pin_mux++) {
+                       struct function_desc *func;
 
-                       while (func->name) {
+                       /* Check if we already have function for this mux */
+                       for (func = thunderbay_funcs; func->name; func++) {
                                if (!strcmp(pin_mux->name, func->name)) {
                                        func->num_group_names++;
                                        break;
                                }
-                               func++;
                        }
 
                        if (!func->name) {
@@ -868,8 +850,6 @@ static int thunderbay_build_functions(struct thunderbay_pinctrl *tpc)
                                func->data = (int *)&pin_mux->mode;
                                tpc->nfuncs++;
                        }
-
-                       pin_mux++;
                }
        }
 
index 42da6bd..e140122 100644 (file)
@@ -809,7 +809,6 @@ static int zynqmp_pinctrl_prepare_pin_desc(struct device *dev,
                                           unsigned int *npins)
 {
        struct pinctrl_pin_desc *pins, *pin;
-       char **pin_names;
        int ret;
        int i;
 
@@ -821,14 +820,13 @@ static int zynqmp_pinctrl_prepare_pin_desc(struct device *dev,
        if (!pins)
                return -ENOMEM;
 
-       pin_names = devm_kasprintf_strarray(dev, ZYNQMP_PIN_PREFIX, *npins);
-       if (IS_ERR(pin_names))
-               return PTR_ERR(pin_names);
-
        for (i = 0; i < *npins; i++) {
                pin = &pins[i];
                pin->number = i;
-               pin->name = pin_names[i];
+               pin->name = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
+                                          ZYNQMP_PIN_PREFIX, i);
+               if (!pin->name)
+                       return -ENOMEM;
        }
 
        *zynqmp_pins = pins;
index ce1917e..152b712 100644 (file)
@@ -363,16 +363,16 @@ static const struct sunxi_desc_pin h616_pins[] = {
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "uart2"),         /* CTS */
-                 SUNXI_FUNCTION(0x3, "i2s3"),  /* DO0 */
+                 SUNXI_FUNCTION(0x3, "i2s3_dout0"),    /* DO0 */
                  SUNXI_FUNCTION(0x4, "spi1"),          /* MISO */
-                 SUNXI_FUNCTION(0x5, "i2s3"),  /* DI1 */
+                 SUNXI_FUNCTION(0x5, "i2s3_din1"),     /* DI1 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 6, 8)),  /* PH_EINT8 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x3, "i2s3"),  /* DI0 */
+                 SUNXI_FUNCTION(0x3, "i2s3_din0"),     /* DI0 */
                  SUNXI_FUNCTION(0x4, "spi1"),          /* CS1 */
-                 SUNXI_FUNCTION(0x3, "i2s3"),  /* DO1 */
+                 SUNXI_FUNCTION(0x5, "i2s3_dout1"),    /* DO1 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 6, 9)),  /* PH_EINT9 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 10),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
index 5f0578e..463f1ec 100644 (file)
@@ -5,6 +5,7 @@
 
 menuconfig SURFACE_PLATFORMS
        bool "Microsoft Surface Platform-Specific Device Drivers"
+       depends on ARM64 || X86 || COMPILE_TEST
        default y
        help
          Say Y here to get to see options for platform-specific device drivers
index f794343..4c72ba6 100644 (file)
@@ -124,9 +124,10 @@ struct amd_pmc_dev {
        u32 cpu_id;
        u32 active_ips;
 /* SMU version information */
-       u16 major;
-       u16 minor;
-       u16 rev;
+       u8 smu_program;
+       u8 major;
+       u8 minor;
+       u8 rev;
        struct device *dev;
        struct pci_dev *rdev;
        struct mutex lock; /* generic mutex lock */
@@ -180,11 +181,13 @@ static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev)
        if (rc)
                return rc;
 
-       dev->major = (val >> 16) & GENMASK(15, 0);
+       dev->smu_program = (val >> 24) & GENMASK(7, 0);
+       dev->major = (val >> 16) & GENMASK(7, 0);
        dev->minor = (val >> 8) & GENMASK(7, 0);
        dev->rev = (val >> 0) & GENMASK(7, 0);
 
-       dev_dbg(dev->dev, "SMU version is %u.%u.%u\n", dev->major, dev->minor, dev->rev);
+       dev_dbg(dev->dev, "SMU program %u version is %u.%u.%u\n",
+               dev->smu_program, dev->major, dev->minor, dev->rev);
 
        return 0;
 }
@@ -226,7 +229,7 @@ static int amd_pmc_stb_debugfs_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
-const struct file_operations amd_pmc_stb_debugfs_fops = {
+static const struct file_operations amd_pmc_stb_debugfs_fops = {
        .owner = THIS_MODULE,
        .open = amd_pmc_stb_debugfs_open,
        .read = amd_pmc_stb_debugfs_read,
index d4ef8f3..6fd0c9f 100644 (file)
@@ -250,7 +250,7 @@ static int tf103c_dock_hid_raw_request(struct hid_device *hid, u8 reportnum,
        return 0;
 }
 
-struct hid_ll_driver tf103c_dock_hid_ll_driver = {
+static struct hid_ll_driver tf103c_dock_hid_ll_driver = {
        .parse = tf103c_dock_hid_parse,
        .start = tf103c_dock_hid_start,
        .stop = tf103c_dock_hid_stop,
@@ -921,7 +921,7 @@ static int __maybe_unused tf103c_dock_resume(struct device *dev)
        return 0;
 }
 
-SIMPLE_DEV_PM_OPS(tf103c_dock_pm_ops, tf103c_dock_suspend, tf103c_dock_resume);
+static SIMPLE_DEV_PM_OPS(tf103c_dock_pm_ops, tf103c_dock_suspend, tf103c_dock_resume);
 
 static const struct acpi_device_id tf103c_dock_acpi_match[] = {
        {"NPCE69A"},
index 0374bc7..e4299cf 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/regmap.h>
 
 #define CHGRIRQ_REG                                    0x0a
+#define MCHGRIRQ_REG                                   0x17
 
 struct crystal_cove_charger_data {
        struct mutex buslock; /* irq_bus_lock */
@@ -25,8 +26,8 @@ struct crystal_cove_charger_data {
        struct irq_domain *irq_domain;
        int irq;
        int charger_irq;
-       bool irq_enabled;
-       bool irq_is_enabled;
+       u8 mask;
+       u8 new_mask;
 };
 
 static irqreturn_t crystal_cove_charger_irq(int irq, void *data)
@@ -53,13 +54,9 @@ static void crystal_cove_charger_irq_bus_sync_unlock(struct irq_data *data)
 {
        struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
 
-       if (charger->irq_is_enabled != charger->irq_enabled) {
-               if (charger->irq_enabled)
-                       enable_irq(charger->irq);
-               else
-                       disable_irq(charger->irq);
-
-               charger->irq_is_enabled = charger->irq_enabled;
+       if (charger->mask != charger->new_mask) {
+               regmap_write(charger->regmap, MCHGRIRQ_REG, charger->new_mask);
+               charger->mask = charger->new_mask;
        }
 
        mutex_unlock(&charger->buslock);
@@ -69,14 +66,14 @@ static void crystal_cove_charger_irq_unmask(struct irq_data *data)
 {
        struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
 
-       charger->irq_enabled = true;
+       charger->new_mask &= ~BIT(data->hwirq);
 }
 
 static void crystal_cove_charger_irq_mask(struct irq_data *data)
 {
        struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
 
-       charger->irq_enabled = false;
+       charger->new_mask |= BIT(data->hwirq);
 }
 
 static void crystal_cove_charger_rm_irq_domain(void *data)
@@ -130,10 +127,13 @@ static int crystal_cove_charger_probe(struct platform_device *pdev)
        irq_set_nested_thread(charger->charger_irq, true);
        irq_set_noprobe(charger->charger_irq);
 
+       /* Mask the single 2nd level IRQ before enabling the 1st level IRQ */
+       charger->mask = charger->new_mask = BIT(0);
+       regmap_write(charger->regmap, MCHGRIRQ_REG, charger->mask);
+
        ret = devm_request_threaded_irq(&pdev->dev, charger->irq, NULL,
                                        crystal_cove_charger_irq,
-                                       IRQF_ONESHOT | IRQF_NO_AUTOEN,
-                                       KBUILD_MODNAME, charger);
+                                       IRQF_ONESHOT, KBUILD_MODNAME, charger);
        if (ret)
                return dev_err_probe(&pdev->dev, ret, "requesting irq\n");
 
index c9a85eb..e8424e7 100644 (file)
@@ -596,7 +596,10 @@ static long isst_if_def_ioctl(struct file *file, unsigned int cmd,
        return ret;
 }
 
-static DEFINE_MUTEX(punit_misc_dev_lock);
+/* Lock to prevent module registration when already opened by user space */
+static DEFINE_MUTEX(punit_misc_dev_open_lock);
+/* Lock to allow one share misc device for all ISST interace */
+static DEFINE_MUTEX(punit_misc_dev_reg_lock);
 static int misc_usage_count;
 static int misc_device_ret;
 static int misc_device_open;
@@ -606,7 +609,7 @@ static int isst_if_open(struct inode *inode, struct file *file)
        int i, ret = 0;
 
        /* Fail open, if a module is going away */
-       mutex_lock(&punit_misc_dev_lock);
+       mutex_lock(&punit_misc_dev_open_lock);
        for (i = 0; i < ISST_IF_DEV_MAX; ++i) {
                struct isst_if_cmd_cb *cb = &punit_callbacks[i];
 
@@ -628,7 +631,7 @@ static int isst_if_open(struct inode *inode, struct file *file)
        } else {
                misc_device_open++;
        }
-       mutex_unlock(&punit_misc_dev_lock);
+       mutex_unlock(&punit_misc_dev_open_lock);
 
        return ret;
 }
@@ -637,7 +640,7 @@ static int isst_if_relase(struct inode *inode, struct file *f)
 {
        int i;
 
-       mutex_lock(&punit_misc_dev_lock);
+       mutex_lock(&punit_misc_dev_open_lock);
        misc_device_open--;
        for (i = 0; i < ISST_IF_DEV_MAX; ++i) {
                struct isst_if_cmd_cb *cb = &punit_callbacks[i];
@@ -645,7 +648,7 @@ static int isst_if_relase(struct inode *inode, struct file *f)
                if (cb->registered)
                        module_put(cb->owner);
        }
-       mutex_unlock(&punit_misc_dev_lock);
+       mutex_unlock(&punit_misc_dev_open_lock);
 
        return 0;
 }
@@ -662,6 +665,43 @@ static struct miscdevice isst_if_char_driver = {
        .fops           = &isst_if_char_driver_ops,
 };
 
+static int isst_misc_reg(void)
+{
+       mutex_lock(&punit_misc_dev_reg_lock);
+       if (misc_device_ret)
+               goto unlock_exit;
+
+       if (!misc_usage_count) {
+               misc_device_ret = isst_if_cpu_info_init();
+               if (misc_device_ret)
+                       goto unlock_exit;
+
+               misc_device_ret = misc_register(&isst_if_char_driver);
+               if (misc_device_ret) {
+                       isst_if_cpu_info_exit();
+                       goto unlock_exit;
+               }
+       }
+       misc_usage_count++;
+
+unlock_exit:
+       mutex_unlock(&punit_misc_dev_reg_lock);
+
+       return misc_device_ret;
+}
+
+static void isst_misc_unreg(void)
+{
+       mutex_lock(&punit_misc_dev_reg_lock);
+       if (misc_usage_count)
+               misc_usage_count--;
+       if (!misc_usage_count && !misc_device_ret) {
+               misc_deregister(&isst_if_char_driver);
+               isst_if_cpu_info_exit();
+       }
+       mutex_unlock(&punit_misc_dev_reg_lock);
+}
+
 /**
  * isst_if_cdev_register() - Register callback for IOCTL
  * @device_type: The device type this callback handling.
@@ -679,38 +719,31 @@ static struct miscdevice isst_if_char_driver = {
  */
 int isst_if_cdev_register(int device_type, struct isst_if_cmd_cb *cb)
 {
-       if (misc_device_ret)
-               return misc_device_ret;
+       int ret;
 
        if (device_type >= ISST_IF_DEV_MAX)
                return -EINVAL;
 
-       mutex_lock(&punit_misc_dev_lock);
+       mutex_lock(&punit_misc_dev_open_lock);
+       /* Device is already open, we don't want to add new callbacks */
        if (misc_device_open) {
-               mutex_unlock(&punit_misc_dev_lock);
+               mutex_unlock(&punit_misc_dev_open_lock);
                return -EAGAIN;
        }
-       if (!misc_usage_count) {
-               int ret;
-
-               misc_device_ret = misc_register(&isst_if_char_driver);
-               if (misc_device_ret)
-                       goto unlock_exit;
-
-               ret = isst_if_cpu_info_init();
-               if (ret) {
-                       misc_deregister(&isst_if_char_driver);
-                       misc_device_ret = ret;
-                       goto unlock_exit;
-               }
-       }
        memcpy(&punit_callbacks[device_type], cb, sizeof(*cb));
        punit_callbacks[device_type].registered = 1;
-       misc_usage_count++;
-unlock_exit:
-       mutex_unlock(&punit_misc_dev_lock);
+       mutex_unlock(&punit_misc_dev_open_lock);
 
-       return misc_device_ret;
+       ret = isst_misc_reg();
+       if (ret) {
+               /*
+                * No need of mutex as the misc device register failed
+                * as no one can open device yet. Hence no contention.
+                */
+               punit_callbacks[device_type].registered = 0;
+               return ret;
+       }
+       return 0;
 }
 EXPORT_SYMBOL_GPL(isst_if_cdev_register);
 
@@ -725,16 +758,12 @@ EXPORT_SYMBOL_GPL(isst_if_cdev_register);
  */
 void isst_if_cdev_unregister(int device_type)
 {
-       mutex_lock(&punit_misc_dev_lock);
-       misc_usage_count--;
+       isst_misc_unreg();
+       mutex_lock(&punit_misc_dev_open_lock);
        punit_callbacks[device_type].registered = 0;
        if (device_type == ISST_IF_DEV_MBOX)
                isst_delete_hash();
-       if (!misc_usage_count && !misc_device_ret) {
-               misc_deregister(&isst_if_char_driver);
-               isst_if_cpu_info_exit();
-       }
-       mutex_unlock(&punit_misc_dev_lock);
+       mutex_unlock(&punit_misc_dev_open_lock);
 }
 EXPORT_SYMBOL_GPL(isst_if_cdev_unregister);
 
index 098180f..bd04548 100644 (file)
@@ -8679,9 +8679,10 @@ static const struct attribute_group fan_driver_attr_group = {
        .attrs = fan_driver_attributes,
 };
 
-#define TPACPI_FAN_Q1  0x0001          /* Unitialized HFSP */
-#define TPACPI_FAN_2FAN        0x0002          /* EC 0x31 bit 0 selects fan2 */
-#define TPACPI_FAN_2CTL        0x0004          /* selects fan2 control */
+#define TPACPI_FAN_Q1          0x0001          /* Uninitialized HFSP */
+#define TPACPI_FAN_2FAN                0x0002          /* EC 0x31 bit 0 selects fan2 */
+#define TPACPI_FAN_2CTL                0x0004          /* selects fan2 control */
+#define TPACPI_FAN_NOFAN       0x0008          /* no fan available */
 
 static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
        TPACPI_QEC_IBM('1', 'Y', TPACPI_FAN_Q1),
@@ -8702,6 +8703,7 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
        TPACPI_Q_LNV3('N', '4', '0', TPACPI_FAN_2CTL),  /* P1 / X1 Extreme (4nd gen) */
        TPACPI_Q_LNV3('N', '3', '0', TPACPI_FAN_2CTL),  /* P15 (1st gen) / P15v (1st gen) */
        TPACPI_Q_LNV3('N', '3', '2', TPACPI_FAN_2CTL),  /* X1 Carbon (9th gen) */
+       TPACPI_Q_LNV3('N', '1', 'O', TPACPI_FAN_NOFAN), /* X1 Tablet (2nd gen) */
 };
 
 static int __init fan_init(struct ibm_init_struct *iibm)
@@ -8730,6 +8732,11 @@ static int __init fan_init(struct ibm_init_struct *iibm)
        quirks = tpacpi_check_quirks(fan_quirk_table,
                                     ARRAY_SIZE(fan_quirk_table));
 
+       if (quirks & TPACPI_FAN_NOFAN) {
+               pr_info("No integrated ThinkPad fan available\n");
+               return -ENODEV;
+       }
+
        if (gfan_handle) {
                /* 570, 600e/x, 770e, 770x */
                fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
@@ -10112,6 +10119,9 @@ static struct ibm_struct proxsensor_driver_data = {
 #define DYTC_CMD_MMC_GET      8 /* To get current MMC function and mode */
 #define DYTC_CMD_RESET    0x1ff /* To reset back to default */
 
+#define DYTC_CMD_FUNC_CAP     3 /* To get DYTC capabilities */
+#define DYTC_FC_MMC           27 /* MMC Mode supported */
+
 #define DYTC_GET_FUNCTION_BIT 8  /* Bits  8-11 - function setting */
 #define DYTC_GET_MODE_BIT     12 /* Bits 12-15 - mode setting */
 
@@ -10324,6 +10334,15 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
        if (dytc_version < 5)
                return -ENODEV;
 
+       /* Check what capabilities are supported. Currently MMC is needed */
+       err = dytc_command(DYTC_CMD_FUNC_CAP, &output);
+       if (err)
+               return err;
+       if (!(output & BIT(DYTC_FC_MMC))) {
+               dbg_printk(TPACPI_DBG_INIT, " DYTC MMC mode not supported\n");
+               return -ENODEV;
+       }
+
        dbg_printk(TPACPI_DBG_INIT,
                        "DYTC version %d: thermal mode available\n", dytc_version);
        /*
index 494f230..bc97bfa 100644 (file)
@@ -770,6 +770,21 @@ static const struct ts_dmi_data predia_basic_data = {
        .properties     = predia_basic_props,
 };
 
+static const struct property_entry rwc_nanote_p8_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-min-y", 46),
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
+       PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+       PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-rwc-nanote-p8.fw"),
+       PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       { }
+};
+
+static const struct ts_dmi_data rwc_nanote_p8_data = {
+       .acpi_name = "MSSL1680:00",
+       .properties = rwc_nanote_p8_props,
+};
+
 static const struct property_entry schneider_sct101ctm_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-size-x", 1715),
        PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
@@ -1394,6 +1409,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
                        DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"),
                },
        },
+       {
+               /* RWC NANOTE P8 */
+               .driver_data = (void *)&rwc_nanote_p8_data,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Default string"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "AY07J"),
+                       DMI_MATCH(DMI_PRODUCT_SKU, "0001")
+               },
+       },
        {
                /* Schneider SCT101CTM */
                .driver_data = (void *)&schneider_sct101ctm_data,
index 3ba63ad..9360a8a 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/string.h>
 /* For gpio_get_desc() which is EXPORT_SYMBOL_GPL() */
 #include "../../gpio/gpiolib.h"
+#include "../../gpio/gpiolib-acpi.h"
 
 /*
  * Helper code to get Linux IRQ numbers given a description of the IRQ source
@@ -47,7 +48,7 @@ struct x86_acpi_irq_data {
        int polarity; /* ACPI_ACTIVE_HIGH / ACPI_ACTIVE_LOW / ACPI_ACTIVE_BOTH */
 };
 
-static int x86_acpi_irq_helper_gpiochip_find(struct gpio_chip *gc, void *data)
+static int gpiochip_find_match_label(struct gpio_chip *gc, void *data)
 {
        return gc->label && !strcmp(gc->label, data);
 }
@@ -73,7 +74,7 @@ static int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data)
                return irq;
        case X86_ACPI_IRQ_TYPE_GPIOINT:
                /* Like acpi_dev_gpio_irq_get(), but without parsing ACPI resources */
-               chip = gpiochip_find(data->chip, x86_acpi_irq_helper_gpiochip_find);
+               chip = gpiochip_find(data->chip, gpiochip_find_match_label);
                if (!chip) {
                        pr_err("error cannot find GPIO chip %s\n", data->chip);
                        return -ENODEV;
@@ -143,14 +144,17 @@ struct x86_serdev_info {
 };
 
 struct x86_dev_info {
+       char *invalid_aei_gpiochip;
        const char * const *modules;
-       struct gpiod_lookup_table **gpiod_lookup_tables;
+       struct gpiod_lookup_table * const *gpiod_lookup_tables;
        const struct x86_i2c_client_info *i2c_client_info;
        const struct platform_device_info *pdev_info;
        const struct x86_serdev_info *serdev_info;
        int i2c_client_count;
        int pdev_count;
        int serdev_count;
+       int (*init)(void);
+       void (*exit)(void);
 };
 
 /* Generic / shared bq24190 settings */
@@ -187,8 +191,8 @@ static struct bq24190_platform_data bq24190_pdata = {
 };
 
 static const char * const bq24190_modules[] __initconst = {
-       "crystal_cove_charger", /* For the bq24190 IRQ */
-       "bq24190_charger",      /* For the Vbus regulator for intel-int3496 */
+       "intel_crystal_cove_charger", /* For the bq24190 IRQ */
+       "bq24190_charger",            /* For the Vbus regulator for intel-int3496 */
        NULL
 };
 
@@ -302,7 +306,7 @@ static struct gpiod_lookup_table asus_me176c_goodix_gpios = {
        },
 };
 
-static struct gpiod_lookup_table *asus_me176c_gpios[] = {
+static struct gpiod_lookup_table * const asus_me176c_gpios[] = {
        &int3496_gpo2_pin22_gpios,
        &asus_me176c_goodix_gpios,
        NULL
@@ -317,6 +321,7 @@ static const struct x86_dev_info asus_me176c_info __initconst = {
        .serdev_count = ARRAY_SIZE(asus_me176c_serdevs),
        .gpiod_lookup_tables = asus_me176c_gpios,
        .modules = bq24190_modules,
+       .invalid_aei_gpiochip = "INT33FC:02",
 };
 
 /* Asus TF103C tablets have an Android factory img with everything hardcoded */
@@ -405,7 +410,7 @@ static const struct x86_i2c_client_info asus_tf103c_i2c_clients[] __initconst =
        },
 };
 
-static struct gpiod_lookup_table *asus_tf103c_gpios[] = {
+static struct gpiod_lookup_table * const asus_tf103c_gpios[] = {
        &int3496_gpo2_pin22_gpios,
        NULL
 };
@@ -417,6 +422,7 @@ static const struct x86_dev_info asus_tf103c_info __initconst = {
        .pdev_count = ARRAY_SIZE(int3496_pdevs),
        .gpiod_lookup_tables = asus_tf103c_gpios,
        .modules = bq24190_modules,
+       .invalid_aei_gpiochip = "INT33FC:02",
 };
 
 /*
@@ -490,6 +496,39 @@ static const struct x86_dev_info chuwi_hi8_info __initconst = {
        .i2c_client_count = ARRAY_SIZE(chuwi_hi8_i2c_clients),
 };
 
+#define CZC_EC_EXTRA_PORT      0x68
+#define CZC_EC_ANDROID_KEYS    0x63
+
+static int __init czc_p10t_init(void)
+{
+       /*
+        * The device boots up in "Windows 7" mode, when the home button sends a
+        * Windows specific key sequence (Left Meta + D) and the second button
+        * sends an unknown one while also toggling the Radio Kill Switch.
+        * This is a surprising behavior when the second button is labeled "Back".
+        *
+        * The vendor-supplied Android-x86 build switches the device to a "Android"
+        * mode by writing value 0x63 to the I/O port 0x68. This just seems to just
+        * set bit 6 on address 0x96 in the EC region; switching the bit directly
+        * seems to achieve the same result. It uses a "p10t_switcher" to do the
+        * job. It doesn't seem to be able to do anything else, and no other use
+        * of the port 0x68 is known.
+        *
+        * In the Android mode, the home button sends just a single scancode,
+        * which can be handled in Linux userspace more reasonably and the back
+        * button only sends a scancode without toggling the kill switch.
+        * The scancode can then be mapped either to Back or RF Kill functionality
+        * in userspace, depending on how the button is labeled on that particular
+        * model.
+        */
+       outb(CZC_EC_ANDROID_KEYS, CZC_EC_EXTRA_PORT);
+       return 0;
+}
+
+static const struct x86_dev_info czc_p10t __initconst = {
+       .init = czc_p10t_init,
+};
+
 /*
  * Whitelabel (sold as various brands) TM800A550L tablets.
  * These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices
@@ -559,7 +598,7 @@ static struct gpiod_lookup_table whitelabel_tm800a550l_goodix_gpios = {
        },
 };
 
-static struct gpiod_lookup_table *whitelabel_tm800a550l_gpios[] = {
+static struct gpiod_lookup_table * const whitelabel_tm800a550l_gpios[] = {
        &whitelabel_tm800a550l_goodix_gpios,
        NULL
 };
@@ -641,6 +680,24 @@ static const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
                },
                .driver_data = (void *)&chuwi_hi8_info,
        },
+       {
+               /* CZC P10T */
+               .ident = "CZC ODEON TPC-10 (\"P10T\")",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "CZC"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ODEON*TPC-10"),
+               },
+               .driver_data = (void *)&czc_p10t,
+       },
+       {
+               /* A variant of CZC P10T */
+               .ident = "ViewSonic ViewPad 10",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ViewSonic"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "VPAD10"),
+               },
+               .driver_data = (void *)&czc_p10t,
+       },
        {
                /* Whitelabel (sold as various brands) TM800A550L */
                .matches = {
@@ -669,7 +726,8 @@ static int serdev_count;
 static struct i2c_client **i2c_clients;
 static struct platform_device **pdevs;
 static struct serdev_device **serdevs;
-static struct gpiod_lookup_table **gpiod_lookup_tables;
+static struct gpiod_lookup_table * const *gpiod_lookup_tables;
+static void (*exit_handler)(void);
 
 static __init int x86_instantiate_i2c_client(const struct x86_dev_info *dev_info,
                                             int idx)
@@ -787,6 +845,9 @@ static void x86_android_tablet_cleanup(void)
 
        kfree(i2c_clients);
 
+       if (exit_handler)
+               exit_handler();
+
        for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
                gpiod_remove_lookup_table(gpiod_lookup_tables[i]);
 }
@@ -795,6 +856,7 @@ static __init int x86_android_tablet_init(void)
 {
        const struct x86_dev_info *dev_info;
        const struct dmi_system_id *id;
+       struct gpio_chip *chip;
        int i, ret = 0;
 
        id = dmi_first_match(x86_android_tablet_ids);
@@ -803,6 +865,20 @@ static __init int x86_android_tablet_init(void)
 
        dev_info = id->driver_data;
 
+       /*
+        * The broken DSDTs on these devices often also include broken
+        * _AEI (ACPI Event Interrupt) handlers, disable these.
+        */
+       if (dev_info->invalid_aei_gpiochip) {
+               chip = gpiochip_find(dev_info->invalid_aei_gpiochip,
+                                    gpiochip_find_match_label);
+               if (!chip) {
+                       pr_err("error cannot find GPIO chip %s\n", dev_info->invalid_aei_gpiochip);
+                       return -ENODEV;
+               }
+               acpi_gpiochip_free_interrupts(chip);
+       }
+
        /*
         * Since this runs from module_init() it cannot use -EPROBE_DEFER,
         * instead pre-load any modules which are listed as requirements.
@@ -814,6 +890,15 @@ static __init int x86_android_tablet_init(void)
        for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
                gpiod_add_lookup_table(gpiod_lookup_tables[i]);
 
+       if (dev_info->init) {
+               ret = dev_info->init();
+               if (ret < 0) {
+                       x86_android_tablet_cleanup();
+                       return ret;
+               }
+               exit_handler = dev_info->exit;
+       }
+
        i2c_clients = kcalloc(dev_info->i2c_client_count, sizeof(*i2c_clients), GFP_KERNEL);
        if (!i2c_clients) {
                x86_android_tablet_cleanup();
@@ -865,6 +950,6 @@ static __init int x86_android_tablet_init(void)
 module_init(x86_android_tablet_init);
 module_exit(x86_android_tablet_cleanup);
 
-MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 MODULE_DESCRIPTION("X86 Android tablets DSDT fixups driver");
 MODULE_LICENSE("GPL");
index fbc56b0..b8bf76c 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
@@ -140,7 +141,7 @@ static int max20086_parse_regulators_dt(struct max20086 *chip, bool *boot_on)
        node = of_get_child_by_name(chip->dev->of_node, "regulators");
        if (!node) {
                dev_err(chip->dev, "regulators node not found\n");
-               return PTR_ERR(node);
+               return -ENODEV;
        }
 
        for (i = 0; i < chip->info->num_outputs; ++i)
index 3ddd426..1660197 100644 (file)
@@ -180,6 +180,7 @@ config QCOM_Q6V5_ADSP
        depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
        depends on QCOM_SYSMON || QCOM_SYSMON=n
        depends on RPMSG_QCOM_GLINK || RPMSG_QCOM_GLINK=n
+       depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n
        select MFD_SYSCON
        select QCOM_PIL_INFO
        select QCOM_MDT_LOADER
@@ -199,6 +200,7 @@ config QCOM_Q6V5_MSS
        depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
        depends on QCOM_SYSMON || QCOM_SYSMON=n
        depends on RPMSG_QCOM_GLINK || RPMSG_QCOM_GLINK=n
+       depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n
        select MFD_SYSCON
        select QCOM_MDT_LOADER
        select QCOM_PIL_INFO
@@ -218,6 +220,7 @@ config QCOM_Q6V5_PAS
        depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
        depends on QCOM_SYSMON || QCOM_SYSMON=n
        depends on RPMSG_QCOM_GLINK || RPMSG_QCOM_GLINK=n
+       depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n
        select MFD_SYSCON
        select QCOM_PIL_INFO
        select QCOM_MDT_LOADER
@@ -239,6 +242,7 @@ config QCOM_Q6V5_WCSS
        depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
        depends on QCOM_SYSMON || QCOM_SYSMON=n
        depends on RPMSG_QCOM_GLINK || RPMSG_QCOM_GLINK=n
+       depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n
        select MFD_SYSCON
        select QCOM_MDT_LOADER
        select QCOM_PIL_INFO
index eada7e3..442a388 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/soc/qcom/qcom_aoss.h>
 #include <linux/soc/qcom/smem.h>
 #include <linux/soc/qcom/smem_state.h>
 #include <linux/remoteproc.h>
index d6214cb..5663cf7 100644 (file)
@@ -93,7 +93,7 @@ static int rpmsg_eptdev_destroy(struct device *dev, void *data)
        /* wake up any blocked readers */
        wake_up_interruptible(&eptdev->readq);
 
-       device_del(&eptdev->dev);
+       cdev_device_del(&eptdev->cdev, &eptdev->dev);
        put_device(&eptdev->dev);
 
        return 0;
@@ -336,7 +336,6 @@ static void rpmsg_eptdev_release_device(struct device *dev)
 
        ida_simple_remove(&rpmsg_ept_ida, dev->id);
        ida_simple_remove(&rpmsg_minor_ida, MINOR(eptdev->dev.devt));
-       cdev_del(&eptdev->cdev);
        kfree(eptdev);
 }
 
@@ -381,19 +380,13 @@ static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
        dev->id = ret;
        dev_set_name(dev, "rpmsg%d", ret);
 
-       ret = cdev_add(&eptdev->cdev, dev->devt, 1);
+       ret = cdev_device_add(&eptdev->cdev, &eptdev->dev);
        if (ret)
                goto free_ept_ida;
 
        /* We can now rely on the release function for cleanup */
        dev->release = rpmsg_eptdev_release_device;
 
-       ret = device_add(dev);
-       if (ret) {
-               dev_err(dev, "device_add failed: %d\n", ret);
-               put_device(dev);
-       }
-
        return ret;
 
 free_ept_ida:
@@ -462,7 +455,6 @@ static void rpmsg_ctrldev_release_device(struct device *dev)
 
        ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
        ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
-       cdev_del(&ctrldev->cdev);
        kfree(ctrldev);
 }
 
@@ -497,19 +489,13 @@ static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
        dev->id = ret;
        dev_set_name(&ctrldev->dev, "rpmsg_ctrl%d", ret);
 
-       ret = cdev_add(&ctrldev->cdev, dev->devt, 1);
+       ret = cdev_device_add(&ctrldev->cdev, &ctrldev->dev);
        if (ret)
                goto free_ctrl_ida;
 
        /* We can now rely on the release function for cleanup */
        dev->release = rpmsg_ctrldev_release_device;
 
-       ret = device_add(dev);
-       if (ret) {
-               dev_err(&rpdev->dev, "device_add failed: %d\n", ret);
-               put_device(dev);
-       }
-
        dev_set_drvdata(&rpdev->dev, ctrldev);
 
        return ret;
@@ -535,7 +521,7 @@ static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
        if (ret)
                dev_warn(&rpdev->dev, "failed to nuke endpoints: %d\n", ret);
 
-       device_del(&ctrldev->dev);
+       cdev_device_del(&ctrldev->cdev, &ctrldev->dev);
        put_device(&ctrldev->dev);
 }
 
index cd938a2..3b1cd0c 100644 (file)
@@ -1180,7 +1180,7 @@ static int io_subchannel_chp_event(struct subchannel *sch,
                        else
                                path_event[chpid] = PE_NONE;
                }
-               if (cdev)
+               if (cdev && cdev->drv && cdev->drv->path_event)
                        cdev->drv->path_event(cdev, path_event);
                break;
        }
index d24cafe..511bf8e 100644 (file)
@@ -521,6 +521,8 @@ static void zfcp_fc_adisc_handler(void *data)
                goto out;
        }
 
+       /* re-init to undo drop from zfcp_fc_adisc() */
+       port->d_id = ntoh24(adisc_resp->adisc_port_id);
        /* port is good, unblock rport without going through erp */
        zfcp_scsi_schedule_rport_register(port);
  out:
@@ -534,6 +536,7 @@ static int zfcp_fc_adisc(struct zfcp_port *port)
        struct zfcp_fc_req *fc_req;
        struct zfcp_adapter *adapter = port->adapter;
        struct Scsi_Host *shost = adapter->scsi_host;
+       u32 d_id;
        int ret;
 
        fc_req = kmem_cache_zalloc(zfcp_fc_req_cache, GFP_ATOMIC);
@@ -558,7 +561,15 @@ static int zfcp_fc_adisc(struct zfcp_port *port)
        fc_req->u.adisc.req.adisc_cmd = ELS_ADISC;
        hton24(fc_req->u.adisc.req.adisc_port_id, fc_host_port_id(shost));
 
-       ret = zfcp_fsf_send_els(adapter, port->d_id, &fc_req->ct_els,
+       d_id = port->d_id; /* remember as destination for send els below */
+       /*
+        * Force fresh GID_PN lookup on next port recovery.
+        * Must happen after request setup and before sending request,
+        * to prevent race with port->d_id re-init in zfcp_fc_adisc_handler().
+        */
+       port->d_id = 0;
+
+       ret = zfcp_fsf_send_els(adapter, d_id, &fc_req->ct_els,
                                ZFCP_FC_CTELS_TMO);
        if (ret)
                kmem_cache_free(zfcp_fc_req_cache, fc_req);
index b9482da..3ebe661 100644 (file)
@@ -1567,8 +1567,6 @@ static int twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
        pci_try_set_mwi(pdev);
 
        retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
-       if (retval)
-               retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
        if (retval) {
                TW_PRINTK(host, TW_DRIVER, 0x18, "Failed to set dma mask");
                retval = -ENODEV;
@@ -1786,8 +1784,6 @@ static int __maybe_unused twl_resume(struct device *dev)
        pci_try_set_mwi(pdev);
 
        retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
-       if (retval)
-               retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
        if (retval) {
                TW_PRINTK(host, TW_DRIVER, 0x25, "Failed to set dma mask during resume");
                retval = -ENODEV;
index 3ad3eba..ad4972c 100644 (file)
@@ -1507,7 +1507,6 @@ NCR_700_intr(int irq, void *dev_id)
                struct scsi_cmnd *SCp = hostdata->cmd;
 
                handled = 1;
-               SCp = hostdata->cmd;
 
                if(istat & SCSI_INT_PENDING) {
                        udelay(10);
index 440ef32..e5aa982 100644 (file)
@@ -732,9 +732,6 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)
        pci_set_master(pdev);
 
        rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
-       if (rc)
-               rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
-
        if (rc) {
                rc = -ENODEV;
                printk(KERN_ERR "dma_set_mask_and_coherent fail %p\n", pdev);
@@ -1559,9 +1556,6 @@ bfad_pci_slot_reset(struct pci_dev *pdev)
        pci_set_master(pdev);
 
        rc = dma_set_mask_and_coherent(&bfad->pcidev->dev, DMA_BIT_MASK(64));
-       if (rc)
-               rc = dma_set_mask_and_coherent(&bfad->pcidev->dev,
-                                              DMA_BIT_MASK(32));
        if (rc)
                goto out_disable_device;
 
index 71fa62b..a826456 100644 (file)
@@ -82,7 +82,7 @@ static int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba);
 static void bnx2fc_unbind_pcidev(struct bnx2fc_hba *hba);
 static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
                                  struct device *parent, int npiv);
-static void bnx2fc_destroy_work(struct work_struct *work);
+static void bnx2fc_port_destroy(struct fcoe_port *port);
 
 static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev);
 static struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device
@@ -508,7 +508,8 @@ static int bnx2fc_l2_rcv_thread(void *arg)
 
 static void bnx2fc_recv_frame(struct sk_buff *skb)
 {
-       u32 fr_len;
+       u64 crc_err;
+       u32 fr_len, fr_crc;
        struct fc_lport *lport;
        struct fcoe_rcv_info *fr;
        struct fc_stats *stats;
@@ -542,6 +543,11 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
        skb_pull(skb, sizeof(struct fcoe_hdr));
        fr_len = skb->len - sizeof(struct fcoe_crc_eof);
 
+       stats = per_cpu_ptr(lport->stats, get_cpu());
+       stats->RxFrames++;
+       stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
+       put_cpu();
+
        fp = (struct fc_frame *)skb;
        fc_frame_init(fp);
        fr_dev(fp) = lport;
@@ -624,16 +630,15 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
                return;
        }
 
-       stats = per_cpu_ptr(lport->stats, smp_processor_id());
-       stats->RxFrames++;
-       stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
+       fr_crc = le32_to_cpu(fr_crc(fp));
 
-       if (le32_to_cpu(fr_crc(fp)) !=
-                       ~crc32(~0, skb->data, fr_len)) {
-               if (stats->InvalidCRCCount < 5)
+       if (unlikely(fr_crc != ~crc32(~0, skb->data, fr_len))) {
+               stats = per_cpu_ptr(lport->stats, get_cpu());
+               crc_err = (stats->InvalidCRCCount++);
+               put_cpu();
+               if (crc_err < 5)
                        printk(KERN_WARNING PFX "dropping frame with "
                               "CRC error\n");
-               stats->InvalidCRCCount++;
                kfree_skb(skb);
                return;
        }
@@ -907,9 +912,6 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event,
                                __bnx2fc_destroy(interface);
                }
                mutex_unlock(&bnx2fc_dev_lock);
-
-               /* Ensure ALL destroy work has been completed before return */
-               flush_workqueue(bnx2fc_wq);
                return;
 
        default:
@@ -1215,8 +1217,8 @@ static int bnx2fc_vport_destroy(struct fc_vport *vport)
        mutex_unlock(&n_port->lp_mutex);
        bnx2fc_free_vport(interface->hba, port->lport);
        bnx2fc_port_shutdown(port->lport);
+       bnx2fc_port_destroy(port);
        bnx2fc_interface_put(interface);
-       queue_work(bnx2fc_wq, &port->destroy_work);
        return 0;
 }
 
@@ -1525,7 +1527,6 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
        port->lport = lport;
        port->priv = interface;
        port->get_netdev = bnx2fc_netdev;
-       INIT_WORK(&port->destroy_work, bnx2fc_destroy_work);
 
        /* Configure fcoe_port */
        rc = bnx2fc_lport_config(lport);
@@ -1653,8 +1654,8 @@ static void __bnx2fc_destroy(struct bnx2fc_interface *interface)
        bnx2fc_interface_cleanup(interface);
        bnx2fc_stop(interface);
        list_del(&interface->list);
+       bnx2fc_port_destroy(port);
        bnx2fc_interface_put(interface);
-       queue_work(bnx2fc_wq, &port->destroy_work);
 }
 
 /**
@@ -1694,15 +1695,12 @@ netdev_err:
        return rc;
 }
 
-static void bnx2fc_destroy_work(struct work_struct *work)
+static void bnx2fc_port_destroy(struct fcoe_port *port)
 {
-       struct fcoe_port *port;
        struct fc_lport *lport;
 
-       port = container_of(work, struct fcoe_port, destroy_work);
        lport = port->lport;
-
-       BNX2FC_HBA_DBG(lport, "Entered bnx2fc_destroy_work\n");
+       BNX2FC_HBA_DBG(lport, "Entered %s, destroying lport %p\n", __func__, lport);
 
        bnx2fc_if_destroy(lport);
 }
@@ -2556,9 +2554,6 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev)
                        __bnx2fc_destroy(interface);
        mutex_unlock(&bnx2fc_dev_lock);
 
-       /* Ensure ALL destroy work has been completed before return */
-       flush_workqueue(bnx2fc_wq);
-
        bnx2fc_ulp_stop(hba);
        /* unregister cnic device */
        if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic))
index 7bb4f9a..84bc81d 100644 (file)
@@ -46,18 +46,14 @@ efc_els_io_alloc_size(struct efc_node *node, u32 reqlen, u32 rsplen)
 
        efc = node->efc;
 
-       spin_lock_irqsave(&node->els_ios_lock, flags);
-
        if (!node->els_io_enabled) {
                efc_log_err(efc, "els io alloc disabled\n");
-               spin_unlock_irqrestore(&node->els_ios_lock, flags);
                return NULL;
        }
 
        els = mempool_alloc(efc->els_io_pool, GFP_ATOMIC);
        if (!els) {
                atomic_add_return(1, &efc->els_io_alloc_failed_count);
-               spin_unlock_irqrestore(&node->els_ios_lock, flags);
                return NULL;
        }
 
@@ -74,7 +70,6 @@ efc_els_io_alloc_size(struct efc_node *node, u32 reqlen, u32 rsplen)
                                              &els->io.req.phys, GFP_KERNEL);
        if (!els->io.req.virt) {
                mempool_free(els, efc->els_io_pool);
-               spin_unlock_irqrestore(&node->els_ios_lock, flags);
                return NULL;
        }
 
@@ -94,10 +89,11 @@ efc_els_io_alloc_size(struct efc_node *node, u32 reqlen, u32 rsplen)
 
                /* add els structure to ELS IO list */
                INIT_LIST_HEAD(&els->list_entry);
+               spin_lock_irqsave(&node->els_ios_lock, flags);
                list_add_tail(&els->list_entry, &node->els_ios_list);
+               spin_unlock_irqrestore(&node->els_ios_lock, flags);
        }
 
-       spin_unlock_irqrestore(&node->els_ios_lock, flags);
        return els;
 }
 
index a05ec7a..ebf5ec3 100644 (file)
@@ -400,8 +400,7 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba,
                           struct hisi_sas_slot *slot,
                           struct hisi_sas_dq *dq,
                           struct hisi_sas_device *sas_dev,
-                          struct hisi_sas_internal_abort *abort,
-                          struct hisi_sas_tmf_task *tmf)
+                          struct hisi_sas_internal_abort *abort)
 {
        struct hisi_sas_cmd_hdr *cmd_hdr_base;
        int dlvry_queue_slot, dlvry_queue;
@@ -427,8 +426,6 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba,
        cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
        slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot];
 
-       slot->tmf = tmf;
-       slot->is_internal = tmf;
        task->lldd_task = slot;
 
        memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
@@ -587,7 +584,7 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
        slot->is_internal = tmf;
 
        /* protect task_prep and start_delivery sequence */
-       hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL, tmf);
+       hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL);
 
        return 0;
 
@@ -1380,12 +1377,13 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device)
        struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
        struct device *dev = hisi_hba->dev;
        int s = sizeof(struct host_to_dev_fis);
+       struct hisi_sas_tmf_task tmf = {};
 
        ata_for_each_link(link, ap, EDGE) {
                int pmp = sata_srst_pmp(link);
 
                hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis);
-               rc = hisi_sas_exec_internal_tmf_task(device, fis, s, NULL);
+               rc = hisi_sas_exec_internal_tmf_task(device, fis, s, &tmf);
                if (rc != TMF_RESP_FUNC_COMPLETE)
                        break;
        }
@@ -1396,7 +1394,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device)
 
                        hisi_sas_fill_ata_reset_cmd(link->device, 0, pmp, fis);
                        rc = hisi_sas_exec_internal_tmf_task(device, fis,
-                                                            s, NULL);
+                                                            s, &tmf);
                        if (rc != TMF_RESP_FUNC_COMPLETE)
                                dev_err(dev, "ata disk %016llx de-reset failed\n",
                                        SAS_ADDR(device->sas_addr));
@@ -2067,7 +2065,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
        slot->port = port;
        slot->is_internal = true;
 
-       hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort, NULL);
+       hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort);
 
        return 0;
 
@@ -2666,9 +2664,6 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
                goto err_out;
 
        error = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
-       if (error)
-               error = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
-
        if (error) {
                dev_err(dev, "No usable DMA addressing method\n");
                goto err_out;
index a45ef9a..a01a3a7 100644 (file)
@@ -4695,8 +4695,6 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto err_out;
 
        rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
-       if (rc)
-               rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
        if (rc) {
                dev_err(dev, "No usable DMA addressing method\n");
                rc = -ENODEV;
index 4878c94..a1e0a10 100644 (file)
@@ -1161,6 +1161,16 @@ struct lpfc_hba {
        uint32_t cfg_hostmem_hgp;
        uint32_t cfg_log_verbose;
        uint32_t cfg_enable_fc4_type;
+#define LPFC_ENABLE_FCP  1
+#define LPFC_ENABLE_NVME 2
+#define LPFC_ENABLE_BOTH 3
+#if (IS_ENABLED(CONFIG_NVME_FC))
+#define LPFC_MAX_ENBL_FC4_TYPE LPFC_ENABLE_BOTH
+#define LPFC_DEF_ENBL_FC4_TYPE LPFC_ENABLE_BOTH
+#else
+#define LPFC_MAX_ENBL_FC4_TYPE LPFC_ENABLE_FCP
+#define LPFC_DEF_ENBL_FC4_TYPE LPFC_ENABLE_FCP
+#endif
        uint32_t cfg_aer_support;
        uint32_t cfg_sriov_nr_virtfn;
        uint32_t cfg_request_firmware_upgrade;
@@ -1182,9 +1192,6 @@ struct lpfc_hba {
        uint32_t cfg_ras_fwlog_func;
        uint32_t cfg_enable_bbcr;       /* Enable BB Credit Recovery */
        uint32_t cfg_enable_dpp;        /* Enable Direct Packet Push */
-#define LPFC_ENABLE_FCP  1
-#define LPFC_ENABLE_NVME 2
-#define LPFC_ENABLE_BOTH 3
        uint32_t cfg_enable_pbde;
        uint32_t cfg_enable_mi;
        struct nvmet_fc_target_port *targetport;
index 7a7f17d..bac78fb 100644 (file)
@@ -3978,8 +3978,8 @@ LPFC_ATTR_R(nvmet_mrq_post,
  *                    3 - register both FCP and NVME
  * Supported values are [1,3]. Default value is 3
  */
-LPFC_ATTR_R(enable_fc4_type, LPFC_ENABLE_BOTH,
-           LPFC_ENABLE_FCP, LPFC_ENABLE_BOTH,
+LPFC_ATTR_R(enable_fc4_type, LPFC_DEF_ENBL_FC4_TYPE,
+           LPFC_ENABLE_FCP, LPFC_MAX_ENBL_FC4_TYPE,
            "Enable FC4 Protocol support - FCP / NVME");
 
 /*
index a56f01f..558f7d2 100644 (file)
@@ -2104,7 +2104,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
                }
                if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 &&
                    reg_err2 == SLIPORT_ERR2_REG_FW_RESTART) {
-                       lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
+                       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                                        "3143 Port Down: Firmware Update "
                                        "Detected\n");
                        en_rn_msg = false;
index 1bc0db5..430abeb 100644 (file)
@@ -13363,6 +13363,7 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba)
        uint32_t uerr_sta_hi, uerr_sta_lo;
        uint32_t if_type, portsmphr;
        struct lpfc_register portstat_reg;
+       u32 logmask;
 
        /*
         * For now, use the SLI4 device internal unrecoverable error
@@ -13413,7 +13414,12 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba)
                                readl(phba->sli4_hba.u.if_type2.ERR1regaddr);
                        phba->work_status[1] =
                                readl(phba->sli4_hba.u.if_type2.ERR2regaddr);
-                       lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
+                       logmask = LOG_TRACE_EVENT;
+                       if (phba->work_status[0] ==
+                               SLIPORT_ERR1_REG_ERR_CODE_2 &&
+                           phba->work_status[1] == SLIPORT_ERR2_REG_FW_RESTART)
+                               logmask = LOG_SLI;
+                       lpfc_printf_log(phba, KERN_ERR, logmask,
                                        "2885 Port Status Event: "
                                        "port status reg 0x%x, "
                                        "port smphr reg 0x%x, "
index 253ceca..7eb8c39 100644 (file)
@@ -2267,7 +2267,8 @@ static void myrs_cleanup(struct myrs_hba *cs)
        myrs_unmap(cs);
 
        if (cs->mmio_base) {
-               cs->disable_intr(cs);
+               if (cs->disable_intr)
+                       cs->disable_intr(cs);
                iounmap(cs->mmio_base);
                cs->mmio_base = NULL;
        }
index c814e50..9ec310b 100644 (file)
@@ -2692,7 +2692,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
        u32 tag = le32_to_cpu(psataPayload->tag);
        u32 port_id = le32_to_cpu(psataPayload->port_id);
        u32 dev_id = le32_to_cpu(psataPayload->device_id);
-       unsigned long flags;
 
        if (event)
                pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n", event);
@@ -2724,8 +2723,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
                ts->resp = SAS_TASK_COMPLETE;
                ts->stat = SAS_DATA_OVERRUN;
                ts->residual = 0;
-               if (pm8001_dev)
-                       atomic_dec(&pm8001_dev->running_req);
                break;
        case IO_XFER_ERROR_BREAK:
                pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
@@ -2767,7 +2764,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
                                IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
                        ts->resp = SAS_TASK_COMPLETE;
                        ts->stat = SAS_QUEUE_FULL;
-                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
                        return;
                }
                break;
@@ -2853,20 +2849,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
                ts->stat = SAS_OPEN_TO;
                break;
        }
-       spin_lock_irqsave(&t->task_state_lock, flags);
-       t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
-       t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
-       t->task_state_flags |= SAS_TASK_STATE_DONE;
-       if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
-               pm8001_dbg(pm8001_ha, FAIL,
-                          "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
-                          t, event, ts->resp, ts->stat);
-               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-       } else {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
-               pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
-       }
 }
 
 /*See the comments for mpi_ssp_completion */
index 160ee8b..32edda3 100644 (file)
@@ -769,8 +769,13 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
                res = -TMF_RESP_FUNC_FAILED;
                /* Even TMF timed out, return direct. */
                if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+                       struct pm8001_ccb_info *ccb = task->lldd_task;
+
                        pm8001_dbg(pm8001_ha, FAIL, "TMF task[%x]timeout.\n",
                                   tmf->tmf);
+
+                       if (ccb)
+                               ccb->task = NULL;
                        goto ex_err;
                }
 
index bbf538f..9d20f80 100644 (file)
@@ -2185,9 +2185,9 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                pm8001_dbg(pm8001_ha, FAIL,
                           "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
                           t, status, ts->resp, ts->stat);
+               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                if (t->slow_task)
                        complete(&t->slow_task->completion);
-               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
        } else {
                spin_unlock_irqrestore(&t->task_state_lock, flags);
                pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
@@ -2794,9 +2794,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha,
                pm8001_dbg(pm8001_ha, FAIL,
                           "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
                           t, status, ts->resp, ts->stat);
+               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                if (t->slow_task)
                        complete(&t->slow_task->completion);
-               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
        } else {
                spin_unlock_irqrestore(&t->task_state_lock, flags);
                spin_unlock_irqrestore(&circularQ->oq_lock,
@@ -2821,7 +2821,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
        u32 tag = le32_to_cpu(psataPayload->tag);
        u32 port_id = le32_to_cpu(psataPayload->port_id);
        u32 dev_id = le32_to_cpu(psataPayload->device_id);
-       unsigned long flags;
 
        if (event)
                pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n", event);
@@ -2854,8 +2853,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
                ts->resp = SAS_TASK_COMPLETE;
                ts->stat = SAS_DATA_OVERRUN;
                ts->residual = 0;
-               if (pm8001_dev)
-                       atomic_dec(&pm8001_dev->running_req);
                break;
        case IO_XFER_ERROR_BREAK:
                pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
@@ -2904,11 +2901,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
                                IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
                        ts->resp = SAS_TASK_COMPLETE;
                        ts->stat = SAS_QUEUE_FULL;
-                       spin_unlock_irqrestore(&circularQ->oq_lock,
-                                       circularQ->lock_flags);
-                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
-                       spin_lock_irqsave(&circularQ->oq_lock,
-                                       circularQ->lock_flags);
                        return;
                }
                break;
@@ -3008,24 +3000,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
                ts->stat = SAS_OPEN_TO;
                break;
        }
-       spin_lock_irqsave(&t->task_state_lock, flags);
-       t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
-       t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
-       t->task_state_flags |= SAS_TASK_STATE_DONE;
-       if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
-               pm8001_dbg(pm8001_ha, FAIL,
-                          "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
-                          t, event, ts->resp, ts->stat);
-               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-       } else {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
-               spin_unlock_irqrestore(&circularQ->oq_lock,
-                               circularQ->lock_flags);
-               pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
-               spin_lock_irqsave(&circularQ->oq_lock,
-                               circularQ->lock_flags);
-       }
 }
 
 /*See the comments for mpi_ssp_completion */
@@ -3931,6 +3905,7 @@ static int ssp_coalesced_comp_resp(struct pm8001_hba_info *pm8001_ha,
 /**
  * process_one_iomb - process one outbound Queue memory block
  * @pm8001_ha: our hba card information
+ * @circularQ: outbound circular queue
  * @piomb: IO message buffer
  */
 static void process_one_iomb(struct pm8001_hba_info *pm8001_ha,
@@ -4151,10 +4126,22 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
        u32 ret = MPI_IO_STATUS_FAIL;
        u32 regval;
 
+       /*
+        * Fatal errors are programmed to be signalled in irq vector
+        * pm8001_ha->max_q_num - 1 through pm8001_ha->main_cfg_tbl.pm80xx_tbl.
+        * fatal_err_interrupt
+        */
        if (vec == (pm8001_ha->max_q_num - 1)) {
+               u32 mipsall_ready;
+
+               if (pm8001_ha->chip_id == chip_8008 ||
+                   pm8001_ha->chip_id == chip_8009)
+                       mipsall_ready = SCRATCH_PAD_MIPSALL_READY_8PORT;
+               else
+                       mipsall_ready = SCRATCH_PAD_MIPSALL_READY_16PORT;
+
                regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
-               if ((regval & SCRATCH_PAD_MIPSALL_READY) !=
-                                       SCRATCH_PAD_MIPSALL_READY) {
+               if ((regval & mipsall_ready) != mipsall_ready) {
                        pm8001_ha->controller_fatal_error = true;
                        pm8001_dbg(pm8001_ha, FAIL,
                                   "Firmware Fatal error! Regval:0x%x\n",
index c7e5d93..c41ed03 100644 (file)
@@ -1405,8 +1405,12 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t;
 #define SCRATCH_PAD_BOOT_LOAD_SUCCESS  0x0
 #define SCRATCH_PAD_IOP0_READY         0xC00
 #define SCRATCH_PAD_IOP1_READY         0x3000
-#define SCRATCH_PAD_MIPSALL_READY      (SCRATCH_PAD_IOP1_READY | \
+#define SCRATCH_PAD_MIPSALL_READY_16PORT       (SCRATCH_PAD_IOP1_READY | \
                                        SCRATCH_PAD_IOP0_READY | \
+                                       SCRATCH_PAD_ILA_READY | \
+                                       SCRATCH_PAD_RAAE_READY)
+#define SCRATCH_PAD_MIPSALL_READY_8PORT        (SCRATCH_PAD_IOP0_READY | \
+                                       SCRATCH_PAD_ILA_READY | \
                                        SCRATCH_PAD_RAAE_READY)
 
 /* boot loader state */
index 99a56ca..fab43da 100644 (file)
@@ -2250,6 +2250,7 @@ process_els:
            io_req->tm_flags == FCP_TMF_TGT_RESET) {
                clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags);
                io_req->sc_cmd = NULL;
+               kref_put(&io_req->refcount, qedf_release_cmd);
                complete(&io_req->tm_done);
        }
 
index cdc66e2..6ad28bc 100644 (file)
@@ -911,7 +911,7 @@ void qedf_ctx_soft_reset(struct fc_lport *lport)
        struct qed_link_output if_link;
 
        if (lport->vport) {
-               QEDF_ERR(NULL, "Cannot issue host reset on NPIV port.\n");
+               printk_ratelimited("Cannot issue host reset on NPIV port.\n");
                return;
        }
 
@@ -1864,6 +1864,7 @@ static int qedf_vport_create(struct fc_vport *vport, bool disabled)
        vport_qedf->cmd_mgr = base_qedf->cmd_mgr;
        init_completion(&vport_qedf->flogi_compl);
        INIT_LIST_HEAD(&vport_qedf->fcports);
+       INIT_DELAYED_WORK(&vport_qedf->stag_work, qedf_stag_change_work);
 
        rc = qedf_vport_libfc_config(vport, vn_port);
        if (rc) {
@@ -3980,7 +3981,9 @@ void qedf_stag_change_work(struct work_struct *work)
        struct qedf_ctx *qedf =
            container_of(work, struct qedf_ctx, stag_work.work);
 
-       QEDF_ERR(&qedf->dbg_ctx, "Performing software context reset.\n");
+       printk_ratelimited("[%s]:[%s:%d]:%d: Performing software context reset.",
+                       dev_name(&qedf->pdev->dev), __func__, __LINE__,
+                       qedf->dbg_ctx.host_no);
        qedf_ctx_soft_reset(qedf->lport);
 }
 
index 3520b93..f4e6c68 100644 (file)
@@ -214,6 +214,48 @@ static void scsi_unlock_floptical(struct scsi_device *sdev,
                         SCSI_TIMEOUT, 3, NULL);
 }
 
+static int scsi_realloc_sdev_budget_map(struct scsi_device *sdev,
+                                       unsigned int depth)
+{
+       int new_shift = sbitmap_calculate_shift(depth);
+       bool need_alloc = !sdev->budget_map.map;
+       bool need_free = false;
+       int ret;
+       struct sbitmap sb_backup;
+
+       /*
+        * realloc if new shift is calculated, which is caused by setting
+        * up one new default queue depth after calling ->slave_configure
+        */
+       if (!need_alloc && new_shift != sdev->budget_map.shift)
+               need_alloc = need_free = true;
+
+       if (!need_alloc)
+               return 0;
+
+       /*
+        * Request queue has to be frozen for reallocating budget map,
+        * and here disk isn't added yet, so freezing is pretty fast
+        */
+       if (need_free) {
+               blk_mq_freeze_queue(sdev->request_queue);
+               sb_backup = sdev->budget_map;
+       }
+       ret = sbitmap_init_node(&sdev->budget_map,
+                               scsi_device_max_queue_depth(sdev),
+                               new_shift, GFP_KERNEL,
+                               sdev->request_queue->node, false, true);
+       if (need_free) {
+               if (ret)
+                       sdev->budget_map = sb_backup;
+               else
+                       sbitmap_free(&sb_backup);
+               ret = 0;
+               blk_mq_unfreeze_queue(sdev->request_queue);
+       }
+       return ret;
+}
+
 /**
  * scsi_alloc_sdev - allocate and setup a scsi_Device
  * @starget: which target to allocate a &scsi_device for
@@ -306,11 +348,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
         * default device queue depth to figure out sbitmap shift
         * since we use this queue depth most of times.
         */
-       if (sbitmap_init_node(&sdev->budget_map,
-                               scsi_device_max_queue_depth(sdev),
-                               sbitmap_calculate_shift(depth),
-                               GFP_KERNEL, sdev->request_queue->node,
-                               false, true)) {
+       if (scsi_realloc_sdev_budget_map(sdev, depth)) {
                put_device(&starget->dev);
                kfree(sdev);
                goto out;
@@ -1017,6 +1055,13 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
                        }
                        return SCSI_SCAN_NO_RESPONSE;
                }
+
+               /*
+                * The queue_depth is often changed in ->slave_configure.
+                * Set up budget map again since memory consumption of
+                * the map depends on actual queue depth.
+                */
+               scsi_realloc_sdev_budget_map(sdev, sdev->queue_depth);
        }
 
        if (sdev->scsi_level >= SCSI_3)
index 8b16bbb..87975d1 100644 (file)
@@ -92,6 +92,11 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
                clki->min_freq = clkfreq[i];
                clki->max_freq = clkfreq[i+1];
                clki->name = devm_kstrdup(dev, name, GFP_KERNEL);
+               if (!clki->name) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
                if (!strcmp(name, "ref_clk"))
                        clki->keep_link_active = true;
                dev_dbg(dev, "%s: min %u max %u name %s\n", "freq-table-hz",
@@ -127,6 +132,8 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name,
                return -ENOMEM;
 
        vreg->name = devm_kstrdup(dev, name, GFP_KERNEL);
+       if (!vreg->name)
+               return -ENOMEM;
 
        snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name);
        if (of_property_read_u32(np, prop_name, &vreg->max_uA)) {
index 460d2b4..50b12d6 100644 (file)
@@ -8613,7 +8613,7 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
  * @pwr_mode: device power mode to set
  *
  * Returns 0 if requested power mode is set successfully
- * Returns non-zero if failed to set the requested power mode
+ * Returns < 0 if failed to set the requested power mode
  */
 static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
                                     enum ufs_dev_pwr_mode pwr_mode)
@@ -8667,8 +8667,11 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
                sdev_printk(KERN_WARNING, sdp,
                            "START_STOP failed for power mode: %d, result %x\n",
                            pwr_mode, ret);
-               if (ret > 0 && scsi_sense_valid(&sshdr))
-                       scsi_print_sense_hdr(sdp, NULL, &sshdr);
+               if (ret > 0) {
+                       if (scsi_sense_valid(&sshdr))
+                               scsi_print_sense_hdr(sdp, NULL, &sshdr);
+                       ret = -EIO;
+               }
        }
 
        if (!ret)
index 6a295c8..a7ff0e5 100644 (file)
@@ -142,7 +142,8 @@ static inline u32 ufshci_version(u32 major, u32 minor)
 #define INT_FATAL_ERRORS       (DEVICE_FATAL_ERROR |\
                                CONTROLLER_FATAL_ERROR |\
                                SYSTEM_BUS_FATAL_ERROR |\
-                               CRYPTO_ENGINE_FATAL_ERROR)
+                               CRYPTO_ENGINE_FATAL_ERROR |\
+                               UIC_LINK_LOST)
 
 /* HCS - Host Controller Status 30h */
 #define DEVICE_PRESENT                         0x1
index 72771e0..258894e 100644 (file)
@@ -306,10 +306,9 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
        }
 
        lpc_ctrl->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(lpc_ctrl->clk)) {
-               dev_err(dev, "couldn't get clock\n");
-               return PTR_ERR(lpc_ctrl->clk);
-       }
+       if (IS_ERR(lpc_ctrl->clk))
+               return dev_err_probe(dev, PTR_ERR(lpc_ctrl->clk),
+                                    "couldn't get clock\n");
        rc = clk_prepare_enable(lpc_ctrl->clk);
        if (rc) {
                dev_err(dev, "couldn't enable clock\n");
index a9f8b22..02e3195 100644 (file)
@@ -31,7 +31,7 @@ config EXYNOS_USI
        help
          Enable support for USI block. USI (Universal Serial Interface) is an
          IP-core found in modern Samsung Exynos SoCs, like Exynos850 and
-         ExynosAutoV0. USI block can be configured to provide one of the
+         ExynosAutoV9. USI block can be configured to provide one of the
          following serial protocols: UART, SPI or High Speed I2C.
 
          This driver allows one to configure USI for desired protocol, which
index c9a769b..86c7621 100644 (file)
@@ -585,7 +585,7 @@ static void bcm_qspi_chip_select(struct bcm_qspi *qspi, int cs)
        u32 rd = 0;
        u32 wr = 0;
 
-       if (qspi->base[CHIP_SELECT]) {
+       if (cs >= 0 && qspi->base[CHIP_SELECT]) {
                rd = bcm_qspi_read(qspi, CHIP_SELECT, 0);
                wr = (rd & ~0xff) | (1 << cs);
                if (rd == wr)
index c208efe..0bc7daa 100644 (file)
@@ -693,6 +693,11 @@ static int meson_spicc_probe(struct platform_device *pdev)
        writel_relaxed(0, spicc->base + SPICC_INTREG);
 
        irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = irq;
+               goto out_master;
+       }
+
        ret = devm_request_irq(&pdev->dev, irq, meson_spicc_irq,
                               0, NULL, spicc);
        if (ret) {
index a15de10..753bd31 100644 (file)
@@ -624,7 +624,7 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
        else
                mdata->state = MTK_SPI_IDLE;
 
-       if (!master->can_dma(master, master->cur_msg->spi, trans)) {
+       if (!master->can_dma(master, NULL, trans)) {
                if (trans->rx_buf) {
                        cnt = mdata->xfer_len / 4;
                        ioread32_rep(mdata->base + SPI_RX_DATA_REG,
index 514337c..ffdc55f 100644 (file)
@@ -688,7 +688,7 @@ static int stm32_qspi_probe(struct platform_device *pdev)
        struct resource *res;
        int ret, irq;
 
-       ctrl = spi_alloc_master(dev, sizeof(*qspi));
+       ctrl = devm_spi_alloc_master(dev, sizeof(*qspi));
        if (!ctrl)
                return -ENOMEM;
 
@@ -697,58 +697,46 @@ static int stm32_qspi_probe(struct platform_device *pdev)
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi");
        qspi->io_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(qspi->io_base)) {
-               ret = PTR_ERR(qspi->io_base);
-               goto err_master_put;
-       }
+       if (IS_ERR(qspi->io_base))
+               return PTR_ERR(qspi->io_base);
 
        qspi->phys_base = res->start;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm");
        qspi->mm_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(qspi->mm_base)) {
-               ret = PTR_ERR(qspi->mm_base);
-               goto err_master_put;
-       }
+       if (IS_ERR(qspi->mm_base))
+               return PTR_ERR(qspi->mm_base);
 
        qspi->mm_size = resource_size(res);
-       if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) {
-               ret = -EINVAL;
-               goto err_master_put;
-       }
+       if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ)
+               return -EINVAL;
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               ret = irq;
-               goto err_master_put;
-       }
+       if (irq < 0)
+               return irq;
 
        ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0,
                               dev_name(dev), qspi);
        if (ret) {
                dev_err(dev, "failed to request irq\n");
-               goto err_master_put;
+               return ret;
        }
 
        init_completion(&qspi->data_completion);
        init_completion(&qspi->match_completion);
 
        qspi->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(qspi->clk)) {
-               ret = PTR_ERR(qspi->clk);
-               goto err_master_put;
-       }
+       if (IS_ERR(qspi->clk))
+               return PTR_ERR(qspi->clk);
 
        qspi->clk_rate = clk_get_rate(qspi->clk);
-       if (!qspi->clk_rate) {
-               ret = -EINVAL;
-               goto err_master_put;
-       }
+       if (!qspi->clk_rate)
+               return -EINVAL;
 
        ret = clk_prepare_enable(qspi->clk);
        if (ret) {
                dev_err(dev, "can not enable the clock\n");
-               goto err_master_put;
+               return ret;
        }
 
        rstc = devm_reset_control_get_exclusive(dev, NULL);
@@ -784,7 +772,7 @@ static int stm32_qspi_probe(struct platform_device *pdev)
        pm_runtime_enable(dev);
        pm_runtime_get_noresume(dev);
 
-       ret = devm_spi_register_master(dev, ctrl);
+       ret = spi_register_master(ctrl);
        if (ret)
                goto err_pm_runtime_free;
 
@@ -806,8 +794,6 @@ err_dma_free:
        stm32_qspi_dma_free(qspi);
 err_clk_disable:
        clk_disable_unprepare(qspi->clk);
-err_master_put:
-       spi_master_put(qspi->ctrl);
 
        return ret;
 }
@@ -817,6 +803,7 @@ static int stm32_qspi_remove(struct platform_device *pdev)
        struct stm32_qspi *qspi = platform_get_drvdata(pdev);
 
        pm_runtime_get_sync(qspi->dev);
+       spi_unregister_master(qspi->ctrl);
        /* disable qspi */
        writel_relaxed(0, qspi->io_base + QSPI_CR);
        stm32_qspi_dma_free(qspi);
index 9bd3fd1..7fc2450 100644 (file)
@@ -221,7 +221,6 @@ struct stm32_spi;
  * time between frames (if driver has this functionality)
  * @set_number_of_data: optional routine to configure registers to desired
  * number of data (if driver has this functionality)
- * @can_dma: routine to determine if the transfer is eligible for DMA use
  * @transfer_one_dma_start: routine to start transfer a single spi_transfer
  * using DMA
  * @dma_rx_cb: routine to call after DMA RX channel operation is complete
@@ -232,7 +231,7 @@ struct stm32_spi;
  * @baud_rate_div_min: minimum baud rate divisor
  * @baud_rate_div_max: maximum baud rate divisor
  * @has_fifo: boolean to know if fifo is used for driver
- * @has_startbit: boolean to know if start bit is used to start transfer
+ * @flags: compatible specific SPI controller flags used at registration time
  */
 struct stm32_spi_cfg {
        const struct stm32_spi_regspec *regs;
@@ -253,6 +252,7 @@ struct stm32_spi_cfg {
        unsigned int baud_rate_div_min;
        unsigned int baud_rate_div_max;
        bool has_fifo;
+       u16 flags;
 };
 
 /**
@@ -1722,6 +1722,7 @@ static const struct stm32_spi_cfg stm32f4_spi_cfg = {
        .baud_rate_div_min = STM32F4_SPI_BR_DIV_MIN,
        .baud_rate_div_max = STM32F4_SPI_BR_DIV_MAX,
        .has_fifo = false,
+       .flags = SPI_MASTER_MUST_TX,
 };
 
 static const struct stm32_spi_cfg stm32h7_spi_cfg = {
@@ -1854,7 +1855,7 @@ static int stm32_spi_probe(struct platform_device *pdev)
        master->prepare_message = stm32_spi_prepare_msg;
        master->transfer_one = stm32_spi_transfer_one;
        master->unprepare_message = stm32_spi_unprepare_msg;
-       master->flags = SPI_MASTER_MUST_TX;
+       master->flags = spi->cfg->flags;
 
        spi->dma_tx = dma_request_chan(spi->dev, "tx");
        if (IS_ERR(spi->dma_tx)) {
index 342ee8d..cc0da48 100644 (file)
@@ -726,7 +726,7 @@ static int uniphier_spi_probe(struct platform_device *pdev)
                if (ret) {
                        dev_err(&pdev->dev, "failed to get TX DMA capacities: %d\n",
                                ret);
-                       goto out_disable_clk;
+                       goto out_release_dma;
                }
                dma_tx_burst = caps.max_burst;
        }
@@ -735,7 +735,7 @@ static int uniphier_spi_probe(struct platform_device *pdev)
        if (IS_ERR_OR_NULL(master->dma_rx)) {
                if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) {
                        ret = -EPROBE_DEFER;
-                       goto out_disable_clk;
+                       goto out_release_dma;
                }
                master->dma_rx = NULL;
                dma_rx_burst = INT_MAX;
@@ -744,7 +744,7 @@ static int uniphier_spi_probe(struct platform_device *pdev)
                if (ret) {
                        dev_err(&pdev->dev, "failed to get RX DMA capacities: %d\n",
                                ret);
-                       goto out_disable_clk;
+                       goto out_release_dma;
                }
                dma_rx_burst = caps.max_burst;
        }
@@ -753,10 +753,20 @@ static int uniphier_spi_probe(struct platform_device *pdev)
 
        ret = devm_spi_register_master(&pdev->dev, master);
        if (ret)
-               goto out_disable_clk;
+               goto out_release_dma;
 
        return 0;
 
+out_release_dma:
+       if (!IS_ERR_OR_NULL(master->dma_rx)) {
+               dma_release_channel(master->dma_rx);
+               master->dma_rx = NULL;
+       }
+       if (!IS_ERR_OR_NULL(master->dma_tx)) {
+               dma_release_channel(master->dma_tx);
+               master->dma_tx = NULL;
+       }
+
 out_disable_clk:
        clk_disable_unprepare(priv->clk);
 
index 4cdec34..55677ef 100644 (file)
@@ -334,7 +334,10 @@ static int __init fbtft_driver_module_init(void)                           \
        ret = spi_register_driver(&fbtft_driver_spi_driver);               \
        if (ret < 0)                                                       \
                return ret;                                                \
-       return platform_driver_register(&fbtft_driver_platform_driver);    \
+       ret = platform_driver_register(&fbtft_driver_platform_driver);     \
+       if (ret < 0)                                                       \
+               spi_unregister_driver(&fbtft_driver_spi_driver);           \
+       return ret;                                                        \
 }                                                                          \
                                                                           \
 static void __exit fbtft_driver_module_exit(void)                          \
index 6759a62..3a2e458 100644 (file)
@@ -1058,15 +1058,27 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header,
 
        DEBUG_TRACE(SERVICE_CALLBACK_LINE);
 
+       rcu_read_lock();
        service = handle_to_service(handle);
-       if (WARN_ON(!service))
+       if (WARN_ON(!service)) {
+               rcu_read_unlock();
                return VCHIQ_SUCCESS;
+       }
 
        user_service = (struct user_service *)service->base.userdata;
        instance = user_service->instance;
 
-       if (!instance || instance->closing)
+       if (!instance || instance->closing) {
+               rcu_read_unlock();
                return VCHIQ_SUCCESS;
+       }
+
+       /*
+        * As hopping around different synchronization mechanism,
+        * taking an extra reference results in simpler implementation.
+        */
+       vchiq_service_get(service);
+       rcu_read_unlock();
 
        vchiq_log_trace(vchiq_arm_log_level,
                        "%s - service %lx(%d,%p), reason %d, header %lx, instance %lx, bulk_userdata %lx",
@@ -1097,6 +1109,7 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header,
                                                        bulk_userdata);
                                if (status != VCHIQ_SUCCESS) {
                                        DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+                                       vchiq_service_put(service);
                                        return status;
                                }
                        }
@@ -1105,10 +1118,12 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header,
                        if (wait_for_completion_interruptible(&user_service->remove_event)) {
                                vchiq_log_info(vchiq_arm_log_level, "%s interrupted", __func__);
                                DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+                               vchiq_service_put(service);
                                return VCHIQ_RETRY;
                        } else if (instance->closing) {
                                vchiq_log_info(vchiq_arm_log_level, "%s closing", __func__);
                                DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+                               vchiq_service_put(service);
                                return VCHIQ_ERROR;
                        }
                        DEBUG_TRACE(SERVICE_CALLBACK_LINE);
@@ -1137,6 +1152,7 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header,
                header = NULL;
        }
        DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+       vchiq_service_put(service);
 
        if (skip_completion)
                return VCHIQ_SUCCESS;
index 8075f60..2d5cf17 100644 (file)
@@ -443,6 +443,9 @@ static bool iscsit_tpg_check_network_portal(
                                break;
                }
                spin_unlock(&tpg->tpg_np_lock);
+
+               if (match)
+                       break;
        }
        spin_unlock(&tiqn->tiqn_tpg_lock);
 
index 1ca3208..17a6f51 100644 (file)
@@ -158,6 +158,7 @@ void optee_remove_common(struct optee *optee)
        optee_unregister_devices();
 
        optee_notif_uninit(optee);
+       teedev_close_context(optee->ctx);
        /*
         * The two devices have to be unregistered before we can free the
         * other resources.
index 20a1b1a..f2bf6c6 100644 (file)
@@ -424,6 +424,7 @@ static struct tee_shm_pool_mgr *optee_ffa_shm_pool_alloc_pages(void)
  */
 
 static void handle_ffa_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
+                                             struct optee *optee,
                                              struct optee_msg_arg *arg)
 {
        struct tee_shm *shm;
@@ -439,7 +440,7 @@ static void handle_ffa_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
                shm = optee_rpc_cmd_alloc_suppl(ctx, arg->params[0].u.value.b);
                break;
        case OPTEE_RPC_SHM_TYPE_KERNEL:
-               shm = tee_shm_alloc(ctx, arg->params[0].u.value.b,
+               shm = tee_shm_alloc(optee->ctx, arg->params[0].u.value.b,
                                    TEE_SHM_MAPPED | TEE_SHM_PRIV);
                break;
        default:
@@ -493,14 +494,13 @@ err_bad_param:
 }
 
 static void handle_ffa_rpc_func_cmd(struct tee_context *ctx,
+                                   struct optee *optee,
                                    struct optee_msg_arg *arg)
 {
-       struct optee *optee = tee_get_drvdata(ctx->teedev);
-
        arg->ret_origin = TEEC_ORIGIN_COMMS;
        switch (arg->cmd) {
        case OPTEE_RPC_CMD_SHM_ALLOC:
-               handle_ffa_rpc_func_cmd_shm_alloc(ctx, arg);
+               handle_ffa_rpc_func_cmd_shm_alloc(ctx, optee, arg);
                break;
        case OPTEE_RPC_CMD_SHM_FREE:
                handle_ffa_rpc_func_cmd_shm_free(ctx, optee, arg);
@@ -510,12 +510,12 @@ static void handle_ffa_rpc_func_cmd(struct tee_context *ctx,
        }
 }
 
-static void optee_handle_ffa_rpc(struct tee_context *ctx, u32 cmd,
-                                struct optee_msg_arg *arg)
+static void optee_handle_ffa_rpc(struct tee_context *ctx, struct optee *optee,
+                                u32 cmd, struct optee_msg_arg *arg)
 {
        switch (cmd) {
        case OPTEE_FFA_YIELDING_CALL_RETURN_RPC_CMD:
-               handle_ffa_rpc_func_cmd(ctx, arg);
+               handle_ffa_rpc_func_cmd(ctx, optee, arg);
                break;
        case OPTEE_FFA_YIELDING_CALL_RETURN_INTERRUPT:
                /* Interrupt delivered by now */
@@ -582,7 +582,7 @@ static int optee_ffa_yielding_call(struct tee_context *ctx,
                 * above.
                 */
                cond_resched();
-               optee_handle_ffa_rpc(ctx, data->data1, rpc_arg);
+               optee_handle_ffa_rpc(ctx, optee, data->data1, rpc_arg);
                cmd = OPTEE_FFA_YIELDING_CALL_RESUME;
                data->data0 = cmd;
                data->data1 = 0;
@@ -619,9 +619,18 @@ static int optee_ffa_do_call_with_arg(struct tee_context *ctx,
                .data2 = (u32)(shm->sec_world_id >> 32),
                .data3 = shm->offset,
        };
-       struct optee_msg_arg *arg = tee_shm_get_va(shm, 0);
-       unsigned int rpc_arg_offs = OPTEE_MSG_GET_ARG_SIZE(arg->num_params);
-       struct optee_msg_arg *rpc_arg = tee_shm_get_va(shm, rpc_arg_offs);
+       struct optee_msg_arg *arg;
+       unsigned int rpc_arg_offs;
+       struct optee_msg_arg *rpc_arg;
+
+       arg = tee_shm_get_va(shm, 0);
+       if (IS_ERR(arg))
+               return PTR_ERR(arg);
+
+       rpc_arg_offs = OPTEE_MSG_GET_ARG_SIZE(arg->num_params);
+       rpc_arg = tee_shm_get_va(shm, rpc_arg_offs);
+       if (IS_ERR(rpc_arg))
+               return PTR_ERR(rpc_arg);
 
        return optee_ffa_yielding_call(ctx, &data, rpc_arg);
 }
@@ -793,7 +802,9 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 {
        const struct ffa_dev_ops *ffa_ops;
        unsigned int rpc_arg_count;
+       struct tee_shm_pool *pool;
        struct tee_device *teedev;
+       struct tee_context *ctx;
        struct optee *optee;
        int rc;
 
@@ -813,12 +824,12 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
        if (!optee)
                return -ENOMEM;
 
-       optee->pool = optee_ffa_config_dyn_shm();
-       if (IS_ERR(optee->pool)) {
-               rc = PTR_ERR(optee->pool);
-               optee->pool = NULL;
-               goto err;
+       pool = optee_ffa_config_dyn_shm();
+       if (IS_ERR(pool)) {
+               rc = PTR_ERR(pool);
+               goto err_free_optee;
        }
+       optee->pool = pool;
 
        optee->ops = &optee_ffa_ops;
        optee->ffa.ffa_dev = ffa_dev;
@@ -829,7 +840,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
                                  optee);
        if (IS_ERR(teedev)) {
                rc = PTR_ERR(teedev);
-               goto err;
+               goto err_free_pool;
        }
        optee->teedev = teedev;
 
@@ -837,50 +848,57 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
                                  optee);
        if (IS_ERR(teedev)) {
                rc = PTR_ERR(teedev);
-               goto err;
+               goto err_unreg_teedev;
        }
        optee->supp_teedev = teedev;
 
        rc = tee_device_register(optee->teedev);
        if (rc)
-               goto err;
+               goto err_unreg_supp_teedev;
 
        rc = tee_device_register(optee->supp_teedev);
        if (rc)
-               goto err;
+               goto err_unreg_supp_teedev;
 
        rc = rhashtable_init(&optee->ffa.global_ids, &shm_rhash_params);
        if (rc)
-               goto err;
+               goto err_unreg_supp_teedev;
        mutex_init(&optee->ffa.mutex);
        mutex_init(&optee->call_queue.mutex);
        INIT_LIST_HEAD(&optee->call_queue.waiters);
        optee_supp_init(&optee->supp);
        ffa_dev_set_drvdata(ffa_dev, optee);
+       ctx = teedev_open(optee->teedev);
+       if (IS_ERR(ctx))
+               goto err_rhashtable_free;
+       optee->ctx = ctx;
        rc = optee_notif_init(optee, OPTEE_DEFAULT_MAX_NOTIF_VALUE);
-       if (rc) {
-               optee_ffa_remove(ffa_dev);
-               return rc;
-       }
+       if (rc)
+               goto err_close_ctx;
 
        rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES);
-       if (rc) {
-               optee_ffa_remove(ffa_dev);
-               return rc;
-       }
+       if (rc)
+               goto err_unregister_devices;
 
        pr_info("initialized driver\n");
        return 0;
-err:
-       /*
-        * tee_device_unregister() is safe to call even if the
-        * devices hasn't been registered with
-        * tee_device_register() yet.
-        */
+
+err_unregister_devices:
+       optee_unregister_devices();
+       optee_notif_uninit(optee);
+err_close_ctx:
+       teedev_close_context(ctx);
+err_rhashtable_free:
+       rhashtable_free_and_destroy(&optee->ffa.global_ids, rh_free_fn, NULL);
+       optee_supp_uninit(&optee->supp);
+       mutex_destroy(&optee->call_queue.mutex);
+err_unreg_supp_teedev:
        tee_device_unregister(optee->supp_teedev);
+err_unreg_teedev:
        tee_device_unregister(optee->teedev);
-       if (optee->pool)
-               tee_shm_pool_free(optee->pool);
+err_free_pool:
+       tee_shm_pool_free(pool);
+err_free_optee:
        kfree(optee);
        return rc;
 }
index a28fa03..0521284 100644 (file)
@@ -121,5 +121,5 @@ int optee_notif_init(struct optee *optee, u_int max_key)
 
 void optee_notif_uninit(struct optee *optee)
 {
-       kfree(optee->notif.bitmap);
+       bitmap_free(optee->notif.bitmap);
 }
index 46f74ab..92bc47b 100644 (file)
@@ -53,7 +53,6 @@ struct optee_call_queue {
 
 struct optee_notif {
        u_int max_key;
-       struct tee_context *ctx;
        /* Serializes access to the elements below in this struct */
        spinlock_t lock;
        struct list_head db;
@@ -134,9 +133,10 @@ struct optee_ops {
 /**
  * struct optee - main service struct
  * @supp_teedev:       supplicant device
+ * @teedev:            client device
  * @ops:               internal callbacks for different ways to reach secure
  *                     world
- * @teedev:            client device
+ * @ctx:               driver internal TEE context
  * @smc:               specific to SMC ABI
  * @ffa:               specific to FF-A ABI
  * @call_queue:                queue of threads waiting to call @invoke_fn
@@ -152,6 +152,7 @@ struct optee {
        struct tee_device *supp_teedev;
        struct tee_device *teedev;
        const struct optee_ops *ops;
+       struct tee_context *ctx;
        union {
                struct optee_smc smc;
                struct optee_ffa ffa;
index 449d6a7..1a55339 100644 (file)
@@ -75,16 +75,6 @@ static int from_msg_param_tmp_mem(struct tee_param *p, u32 attr,
        p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa;
        p->u.memref.shm = shm;
 
-       /* Check that the memref is covered by the shm object */
-       if (p->u.memref.size) {
-               size_t o = p->u.memref.shm_offs +
-                          p->u.memref.size - 1;
-
-               rc = tee_shm_get_pa(shm, o, NULL);
-               if (rc)
-                       return rc;
-       }
-
        return 0;
 }
 
@@ -622,6 +612,7 @@ static void handle_rpc_func_cmd_shm_free(struct tee_context *ctx,
 }
 
 static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
+                                         struct optee *optee,
                                          struct optee_msg_arg *arg,
                                          struct optee_call_ctx *call_ctx)
 {
@@ -651,7 +642,8 @@ static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
                shm = optee_rpc_cmd_alloc_suppl(ctx, sz);
                break;
        case OPTEE_RPC_SHM_TYPE_KERNEL:
-               shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED | TEE_SHM_PRIV);
+               shm = tee_shm_alloc(optee->ctx, sz,
+                                   TEE_SHM_MAPPED | TEE_SHM_PRIV);
                break;
        default:
                arg->ret = TEEC_ERROR_BAD_PARAMETERS;
@@ -747,7 +739,7 @@ static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
        switch (arg->cmd) {
        case OPTEE_RPC_CMD_SHM_ALLOC:
                free_pages_list(call_ctx);
-               handle_rpc_func_cmd_shm_alloc(ctx, arg, call_ctx);
+               handle_rpc_func_cmd_shm_alloc(ctx, optee, arg, call_ctx);
                break;
        case OPTEE_RPC_CMD_SHM_FREE:
                handle_rpc_func_cmd_shm_free(ctx, arg);
@@ -776,7 +768,7 @@ static void optee_handle_rpc(struct tee_context *ctx,
 
        switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) {
        case OPTEE_SMC_RPC_FUNC_ALLOC:
-               shm = tee_shm_alloc(ctx, param->a1,
+               shm = tee_shm_alloc(optee->ctx, param->a1,
                                    TEE_SHM_MAPPED | TEE_SHM_PRIV);
                if (!IS_ERR(shm) && !tee_shm_get_pa(shm, 0, &pa)) {
                        reg_pair_from_64(&param->a1, &param->a2, pa);
@@ -954,57 +946,34 @@ static irqreturn_t notif_irq_thread_fn(int irq, void *dev_id)
 {
        struct optee *optee = dev_id;
 
-       optee_smc_do_bottom_half(optee->notif.ctx);
+       optee_smc_do_bottom_half(optee->ctx);
 
        return IRQ_HANDLED;
 }
 
 static int optee_smc_notif_init_irq(struct optee *optee, u_int irq)
 {
-       struct tee_context *ctx;
        int rc;
 
-       ctx = teedev_open(optee->teedev);
-       if (IS_ERR(ctx))
-               return PTR_ERR(ctx);
-
-       optee->notif.ctx = ctx;
        rc = request_threaded_irq(irq, notif_irq_handler,
                                  notif_irq_thread_fn,
                                  0, "optee_notification", optee);
        if (rc)
-               goto err_close_ctx;
+               return rc;
 
        optee->smc.notif_irq = irq;
 
        return 0;
-
-err_close_ctx:
-       teedev_close_context(optee->notif.ctx);
-       optee->notif.ctx = NULL;
-
-       return rc;
 }
 
 static void optee_smc_notif_uninit_irq(struct optee *optee)
 {
-       if (optee->notif.ctx) {
-               optee_smc_stop_async_notif(optee->notif.ctx);
+       if (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF) {
+               optee_smc_stop_async_notif(optee->ctx);
                if (optee->smc.notif_irq) {
                        free_irq(optee->smc.notif_irq, optee);
                        irq_dispose_mapping(optee->smc.notif_irq);
                }
-
-               /*
-                * The thread normally working with optee->notif.ctx was
-                * stopped with free_irq() above.
-                *
-                * Note we're not using teedev_close_context() or
-                * tee_client_close_context() since we have already called
-                * tee_device_put() while initializing to avoid a circular
-                * reference counting.
-                */
-               teedev_close_context(optee->notif.ctx);
        }
 }
 
@@ -1366,6 +1335,7 @@ static int optee_probe(struct platform_device *pdev)
        struct optee *optee = NULL;
        void *memremaped_shm = NULL;
        struct tee_device *teedev;
+       struct tee_context *ctx;
        u32 max_notif_value;
        u32 sec_caps;
        int rc;
@@ -1446,9 +1416,13 @@ static int optee_probe(struct platform_device *pdev)
        optee->pool = pool;
 
        platform_set_drvdata(pdev, optee);
+       ctx = teedev_open(optee->teedev);
+       if (IS_ERR(ctx))
+               goto err_supp_uninit;
+       optee->ctx = ctx;
        rc = optee_notif_init(optee, max_notif_value);
        if (rc)
-               goto err_supp_uninit;
+               goto err_close_ctx;
 
        if (sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF) {
                unsigned int irq;
@@ -1496,6 +1470,8 @@ err_disable_shm_cache:
        optee_unregister_devices();
 err_notif_uninit:
        optee_notif_uninit(optee);
+err_close_ctx:
+       teedev_close_context(ctx);
 err_supp_uninit:
        optee_supp_uninit(&optee->supp);
        mutex_destroy(&optee->call_queue.mutex);
index ba27b27..0b1808e 100644 (file)
@@ -322,6 +322,7 @@ static int addr_cnt;
 #define GSM1_ESCAPE_BITS       0x20
 #define XON                    0x11
 #define XOFF                   0x13
+#define ISO_IEC_646_MASK       0x7F
 
 static const struct tty_port_operations gsm_port_ops;
 
@@ -531,7 +532,8 @@ static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
        int olen = 0;
        while (len--) {
                if (*input == GSM1_SOF || *input == GSM1_ESCAPE
-                   || *input == XON || *input == XOFF) {
+                   || (*input & ISO_IEC_646_MASK) == XON
+                   || (*input & ISO_IEC_646_MASK) == XOFF) {
                        *output++ = GSM1_ESCAPE;
                        *output++ = *input++ ^ GSM1_ESCAPE_BITS;
                        olen++;
index 8933ef1..5e988e5 100644 (file)
@@ -1329,7 +1329,7 @@ handle_newline:
                        put_tty_queue(c, ldata);
                        smp_store_release(&ldata->canon_head, ldata->read_head);
                        kill_fasync(&tty->fasync, SIGIO, POLL_IN);
-                       wake_up_interruptible_poll(&tty->read_wait, EPOLLIN);
+                       wake_up_interruptible_poll(&tty->read_wait, EPOLLIN | EPOLLRDNORM);
                        return;
                }
        }
@@ -1561,7 +1561,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
 
        if (read_cnt(ldata)) {
                kill_fasync(&tty->fasync, SIGIO, POLL_IN);
-               wake_up_interruptible_poll(&tty->read_wait, EPOLLIN);
+               wake_up_interruptible_poll(&tty->read_wait, EPOLLIN | EPOLLRDNORM);
        }
 }
 
index dae2a4e..29db413 100644 (file)
@@ -50,10 +50,17 @@ static int rpmsg_tty_cb(struct rpmsg_device *rpdev, void *data, int len, void *p
 static int rpmsg_tty_install(struct tty_driver *driver, struct tty_struct *tty)
 {
        struct rpmsg_tty_port *cport = idr_find(&tty_idr, tty->index);
+       struct tty_port *port;
 
        tty->driver_data = cport;
 
-       return tty_port_install(&cport->port, driver, tty);
+       port = tty_port_get(&cport->port);
+       return tty_port_install(port, driver, tty);
+}
+
+static void rpmsg_tty_cleanup(struct tty_struct *tty)
+{
+       tty_port_put(tty->port);
 }
 
 static int rpmsg_tty_open(struct tty_struct *tty, struct file *filp)
@@ -106,12 +113,19 @@ static unsigned int rpmsg_tty_write_room(struct tty_struct *tty)
        return size;
 }
 
+static void rpmsg_tty_hangup(struct tty_struct *tty)
+{
+       tty_port_hangup(tty->port);
+}
+
 static const struct tty_operations rpmsg_tty_ops = {
        .install        = rpmsg_tty_install,
        .open           = rpmsg_tty_open,
        .close          = rpmsg_tty_close,
        .write          = rpmsg_tty_write,
        .write_room     = rpmsg_tty_write_room,
+       .hangup         = rpmsg_tty_hangup,
+       .cleanup        = rpmsg_tty_cleanup,
 };
 
 static struct rpmsg_tty_port *rpmsg_tty_alloc_cport(void)
@@ -137,8 +151,10 @@ static struct rpmsg_tty_port *rpmsg_tty_alloc_cport(void)
        return cport;
 }
 
-static void rpmsg_tty_release_cport(struct rpmsg_tty_port *cport)
+static void rpmsg_tty_destruct_port(struct tty_port *port)
 {
+       struct rpmsg_tty_port *cport = container_of(port, struct rpmsg_tty_port, port);
+
        mutex_lock(&idr_lock);
        idr_remove(&tty_idr, cport->id);
        mutex_unlock(&idr_lock);
@@ -146,7 +162,10 @@ static void rpmsg_tty_release_cport(struct rpmsg_tty_port *cport)
        kfree(cport);
 }
 
-static const struct tty_port_operations rpmsg_tty_port_ops = { };
+static const struct tty_port_operations rpmsg_tty_port_ops = {
+       .destruct = rpmsg_tty_destruct_port,
+};
+
 
 static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
 {
@@ -166,7 +185,8 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
                                           cport->id, dev);
        if (IS_ERR(tty_dev)) {
                ret = dev_err_probe(dev, PTR_ERR(tty_dev), "Failed to register tty port\n");
-               goto err_destroy;
+               tty_port_put(&cport->port);
+               return ret;
        }
 
        cport->rpdev = rpdev;
@@ -177,12 +197,6 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
                rpdev->src, rpdev->dst, cport->id);
 
        return 0;
-
-err_destroy:
-       tty_port_destroy(&cport->port);
-       rpmsg_tty_release_cport(cport);
-
-       return ret;
 }
 
 static void rpmsg_tty_remove(struct rpmsg_device *rpdev)
@@ -192,13 +206,11 @@ static void rpmsg_tty_remove(struct rpmsg_device *rpdev)
        dev_dbg(&rpdev->dev, "Removing rpmsg tty device %d\n", cport->id);
 
        /* User hang up to release the tty */
-       if (tty_port_initialized(&cport->port))
-               tty_port_tty_hangup(&cport->port, false);
+       tty_port_tty_hangup(&cport->port, false);
 
        tty_unregister_device(rpmsg_tty_driver, cport->id);
 
-       tty_port_destroy(&cport->port);
-       rpmsg_tty_release_cport(cport);
+       tty_port_put(&cport->port);
 }
 
 static struct rpmsg_device_id rpmsg_driver_tty_id_table[] = {
index bce2872..be86262 100644 (file)
@@ -83,8 +83,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
                port->mapsize = resource_size(&resource);
 
                /* Check for shifted address mapping */
-               if (of_property_read_u32(np, "reg-offset", &prop) == 0)
+               if (of_property_read_u32(np, "reg-offset", &prop) == 0) {
+                       if (prop >= port->mapsize) {
+                               dev_warn(&ofdev->dev, "reg-offset %u exceeds region size %pa\n",
+                                        prop, &port->mapsize);
+                               ret = -EINVAL;
+                               goto err_unprepare;
+                       }
+
                        port->mapbase += prop;
+                       port->mapsize -= prop;
+               }
 
                port->iotype = UPIO_MEM;
                if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
index e8b5469..e17e97e 100644 (file)
@@ -4779,8 +4779,30 @@ static const struct pci_device_id serial_pci_tbl[] = {
        {       PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400,
                PCI_ANY_ID, PCI_ANY_ID, 0, 0,    /* 135a.0dc0 */
                pbn_b2_4_115200 },
+       /* Brainboxes Devices */
        /*
-        * BrainBoxes UC-260
+       * Brainboxes UC-101
+       */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0BA1,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_2_115200 },
+       /*
+        * Brainboxes UC-235/246
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0AA1,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_1_115200 },
+       /*
+        * Brainboxes UC-257
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0861,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_2_115200 },
+       /*
+        * Brainboxes UC-260/271/701/756
         */
        {       PCI_VENDOR_ID_INTASHIELD, 0x0D21,
                PCI_ANY_ID, PCI_ANY_ID,
@@ -4788,7 +4810,81 @@ static const struct pci_device_id serial_pci_tbl[] = {
                pbn_b2_4_115200 },
        {       PCI_VENDOR_ID_INTASHIELD, 0x0E34,
                PCI_ANY_ID, PCI_ANY_ID,
-                PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
+               PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
+               pbn_b2_4_115200 },
+       /*
+        * Brainboxes UC-268
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0841,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_4_115200 },
+       /*
+        * Brainboxes UC-275/279
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0881,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_8_115200 },
+       /*
+        * Brainboxes UC-302
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x08E1,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_2_115200 },
+       /*
+        * Brainboxes UC-310
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x08C1,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_2_115200 },
+       /*
+        * Brainboxes UC-313
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x08A3,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_2_115200 },
+       /*
+        * Brainboxes UC-320/324
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0A61,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_1_115200 },
+       /*
+        * Brainboxes UC-346
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0B02,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_4_115200 },
+       /*
+        * Brainboxes UC-357
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0A81,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_2_115200 },
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0A83,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_2_115200 },
+       /*
+        * Brainboxes UC-368
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0C41,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_4_115200 },
+       /*
+        * Brainboxes UC-420/431
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0921,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
                pbn_b2_4_115200 },
        /*
         * Perle PCI-RAS cards
index 025b055..95ff10f 100644 (file)
@@ -117,7 +117,7 @@ static int pericom8250_probe(struct pci_dev *pdev, const struct pci_device_id *i
        uart.port.private_data = pericom;
        uart.port.iotype = UPIO_PORT;
        uart.port.uartclk = 921600 * 16;
-       uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ | UPF_MAGIC_MULTIPLIER;
+       uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
        uart.port.set_divisor = pericom_do_set_divisor;
        for (i = 0; i < nr && i < maxnr; i++) {
                unsigned int offset = (i == 3 && nr == 4) ? 0x38 : i * 0x8;
index 2abb3de..3b12bfc 100644 (file)
@@ -2056,7 +2056,10 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
        serial8250_rpm_put(up);
 }
 
-static void wait_for_lsr(struct uart_8250_port *up, int bits)
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static void wait_for_xmitr(struct uart_8250_port *up, int bits)
 {
        unsigned int status, tmout = 10000;
 
@@ -2073,16 +2076,6 @@ static void wait_for_lsr(struct uart_8250_port *up, int bits)
                udelay(1);
                touch_nmi_watchdog();
        }
-}
-
-/*
- *     Wait for transmitter & holding register to empty
- */
-static void wait_for_xmitr(struct uart_8250_port *up, int bits)
-{
-       unsigned int tmout;
-
-       wait_for_lsr(up, bits);
 
        /* Wait up to 1s for flow control if necessary */
        if (up->port.flags & UPF_CONS_FLOW) {
@@ -3332,35 +3325,6 @@ static void serial8250_console_restore(struct uart_8250_port *up)
        serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS);
 }
 
-/*
- * Print a string to the serial port using the device FIFO
- *
- * It sends fifosize bytes and then waits for the fifo
- * to get empty.
- */
-static void serial8250_console_fifo_write(struct uart_8250_port *up,
-                                         const char *s, unsigned int count)
-{
-       int i;
-       const char *end = s + count;
-       unsigned int fifosize = up->port.fifosize;
-       bool cr_sent = false;
-
-       while (s != end) {
-               wait_for_lsr(up, UART_LSR_THRE);
-
-               for (i = 0; i < fifosize && s != end; ++i) {
-                       if (*s == '\n' && !cr_sent) {
-                               serial_out(up, UART_TX, '\r');
-                               cr_sent = true;
-                       } else {
-                               serial_out(up, UART_TX, *s++);
-                               cr_sent = false;
-                       }
-               }
-       }
-}
-
 /*
  *     Print a string to the serial port trying not to disturb
  *     any possible real use of the port...
@@ -3376,7 +3340,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
        struct uart_8250_em485 *em485 = up->em485;
        struct uart_port *port = &up->port;
        unsigned long flags;
-       unsigned int ier, use_fifo;
+       unsigned int ier;
        int locked = 1;
 
        touch_nmi_watchdog();
@@ -3408,20 +3372,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
                mdelay(port->rs485.delay_rts_before_send);
        }
 
-       use_fifo = (up->capabilities & UART_CAP_FIFO) &&
-               port->fifosize > 1 &&
-               (serial_port_in(port, UART_FCR) & UART_FCR_ENABLE_FIFO) &&
-               /*
-                * After we put a data in the fifo, the controller will send
-                * it regardless of the CTS state. Therefore, only use fifo
-                * if we don't use control flow.
-                */
-               !(up->port.flags & UPF_CONS_FLOW);
-
-       if (likely(use_fifo))
-               serial8250_console_fifo_write(up, s, count);
-       else
-               uart_console_write(port, s, count, serial8250_console_putchar);
+       uart_console_write(port, s, count, serial8250_console_putchar);
 
        /*
         *      Finally, wait for transmitter to become empty
index 1f1df46..ba053a6 100644 (file)
@@ -1582,9 +1582,6 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
            container_of(port, struct uart_amba_port, port);
        unsigned int cr;
 
-       if (port->rs485.flags & SER_RS485_ENABLED)
-               mctrl &= ~TIOCM_RTS;
-
        cr = pl011_read(uap, REG_CR);
 
 #define        TIOCMBIT(tiocmbit, uartbit)             \
@@ -1808,14 +1805,8 @@ static int pl011_startup(struct uart_port *port)
        cr &= UART011_CR_RTS | UART011_CR_DTR;
        cr |= UART01x_CR_UARTEN | UART011_CR_RXE;
 
-       if (port->rs485.flags & SER_RS485_ENABLED) {
-               if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
-                       cr &= ~UART011_CR_RTS;
-               else
-                       cr |= UART011_CR_RTS;
-       } else {
+       if (!(port->rs485.flags & SER_RS485_ENABLED))
                cr |= UART011_CR_TXE;
-       }
 
        pl011_write(cr, uap, REG_CR);
 
index dc40c41..0db90be 100644 (file)
@@ -144,6 +144,11 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
        unsigned long flags;
        unsigned int old;
 
+       if (port->rs485.flags & SER_RS485_ENABLED) {
+               set &= ~TIOCM_RTS;
+               clear &= ~TIOCM_RTS;
+       }
+
        spin_lock_irqsave(&port->lock, flags);
        old = port->mctrl;
        port->mctrl = (old & ~clear) | set;
@@ -157,23 +162,10 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
 
 static void uart_port_dtr_rts(struct uart_port *uport, int raise)
 {
-       int rs485_on = uport->rs485_config &&
-               (uport->rs485.flags & SER_RS485_ENABLED);
-       int RTS_after_send = !!(uport->rs485.flags & SER_RS485_RTS_AFTER_SEND);
-
-       if (raise) {
-               if (rs485_on && RTS_after_send) {
-                       uart_set_mctrl(uport, TIOCM_DTR);
-                       uart_clear_mctrl(uport, TIOCM_RTS);
-               } else {
-                       uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
-               }
-       } else {
-               unsigned int clear = TIOCM_DTR;
-
-               clear |= (!rs485_on || RTS_after_send) ? TIOCM_RTS : 0;
-               uart_clear_mctrl(uport, clear);
-       }
+       if (raise)
+               uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+       else
+               uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
 }
 
 /*
@@ -1075,11 +1067,6 @@ uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
                goto out;
 
        if (!tty_io_error(tty)) {
-               if (uport->rs485.flags & SER_RS485_ENABLED) {
-                       set &= ~TIOCM_RTS;
-                       clear &= ~TIOCM_RTS;
-               }
-
                uart_update_mctrl(uport, set, clear);
                ret = 0;
        }
@@ -2390,6 +2377,9 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
                 */
                spin_lock_irqsave(&port->lock, flags);
                port->mctrl &= TIOCM_DTR;
+               if (port->rs485.flags & SER_RS485_ENABLED &&
+                   !(port->rs485.flags & SER_RS485_RTS_AFTER_SEND))
+                       port->mctrl |= TIOCM_RTS;
                port->ops->set_mctrl(port, port->mctrl);
                spin_unlock_irqrestore(&port->lock, flags);
 
index 1f89ab0..9570002 100644 (file)
@@ -550,11 +550,23 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
        struct stm32_port *stm32_port = to_stm32_port(port);
        const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
        struct circ_buf *xmit = &port->state->xmit;
+       u32 isr;
+       int ret;
 
        if (port->x_char) {
                if (stm32_usart_tx_dma_started(stm32_port) &&
                    stm32_usart_tx_dma_enabled(stm32_port))
                        stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
+
+               /* Check that TDR is empty before filling FIFO */
+               ret =
+               readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
+                                                 isr,
+                                                 (isr & USART_SR_TXE),
+                                                 10, 1000);
+               if (ret)
+                       dev_warn(port->dev, "1 character may be erased\n");
+
                writel_relaxed(port->x_char, port->membase + ofs->tdr);
                port->x_char = 0;
                port->icount.tx++;
@@ -730,7 +742,7 @@ static void stm32_usart_start_tx(struct uart_port *port)
        struct serial_rs485 *rs485conf = &port->rs485;
        struct circ_buf *xmit = &port->state->xmit;
 
-       if (uart_circ_empty(xmit))
+       if (uart_circ_empty(xmit) && !port->x_char)
                return;
 
        if (rs485conf->flags & SER_RS485_ENABLED) {
index 3639bb6..5801369 100644 (file)
@@ -599,8 +599,8 @@ static int vt_setactivate(struct vt_setactivate __user *sa)
        if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES)
                return -ENXIO;
 
-       vsa.console = array_index_nospec(vsa.console, MAX_NR_CONSOLES + 1);
        vsa.console--;
+       vsa.console = array_index_nospec(vsa.console, MAX_NR_CONSOLES);
        console_lock();
        ret = vc_allocate(vsa.console);
        if (ret) {
@@ -845,6 +845,7 @@ int vt_ioctl(struct tty_struct *tty,
                        return -ENXIO;
 
                arg--;
+               arg = array_index_nospec(arg, MAX_NR_CONSOLES);
                console_lock();
                ret = vc_allocate(arg);
                console_unlock();
index 55c73b1..d00ff98 100644 (file)
@@ -483,11 +483,11 @@ int cdns_drd_exit(struct cdns *cdns)
 /* Indicate the cdns3 core was power lost before */
 bool cdns_power_is_lost(struct cdns *cdns)
 {
-       if (cdns->version == CDNS3_CONTROLLER_V1) {
-               if (!(readl(&cdns->otg_v1_regs->simulate) & BIT(0)))
+       if (cdns->version == CDNS3_CONTROLLER_V0) {
+               if (!(readl(&cdns->otg_v0_regs->simulate) & BIT(0)))
                        return true;
        } else {
-               if (!(readl(&cdns->otg_v0_regs->simulate) & BIT(0)))
+               if (!(readl(&cdns->otg_v1_regs->simulate) & BIT(0)))
                        return true;
        }
        return false;
index 4169cf4..5509d38 100644 (file)
@@ -39,8 +39,11 @@ static int ulpi_match(struct device *dev, struct device_driver *driver)
        struct ulpi *ulpi = to_ulpi_dev(dev);
        const struct ulpi_device_id *id;
 
-       /* Some ULPI devices don't have a vendor id so rely on OF match */
-       if (ulpi->id.vendor == 0)
+       /*
+        * Some ULPI devices don't have a vendor id
+        * or provide an id_table so rely on OF match.
+        */
+       if (ulpi->id.vendor == 0 || !drv->id_table)
                return of_driver_match_device(dev, driver);
 
        for (id = drv->id_table; id->vendor; id++)
@@ -127,6 +130,7 @@ static const struct attribute_group *ulpi_dev_attr_groups[] = {
 
 static void ulpi_dev_release(struct device *dev)
 {
+       of_node_put(dev->of_node);
        kfree(to_ulpi_dev(dev));
 }
 
@@ -244,12 +248,16 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi)
                return ret;
 
        ret = ulpi_read_id(ulpi);
-       if (ret)
+       if (ret) {
+               of_node_put(ulpi->dev.of_node);
                return ret;
+       }
 
        ret = device_register(&ulpi->dev);
-       if (ret)
+       if (ret) {
+               put_device(&ulpi->dev);
                return ret;
+       }
 
        dev_dbg(&ulpi->dev, "registered ULPI PHY: vendor %04x, product %04x\n",
                ulpi->id.vendor, ulpi->id.product);
@@ -296,7 +304,6 @@ EXPORT_SYMBOL_GPL(ulpi_register_interface);
  */
 void ulpi_unregister_interface(struct ulpi *ulpi)
 {
-       of_node_put(ulpi->dev.of_node);
        device_unregister(&ulpi->dev);
 }
 EXPORT_SYMBOL_GPL(ulpi_unregister_interface);
index 3e01dd6..d9712c2 100644 (file)
@@ -1563,6 +1563,13 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
                urb->hcpriv = NULL;
                INIT_LIST_HEAD(&urb->urb_list);
                atomic_dec(&urb->use_count);
+               /*
+                * Order the write of urb->use_count above before the read
+                * of urb->reject below.  Pairs with the memory barriers in
+                * usb_kill_urb() and usb_poison_urb().
+                */
+               smp_mb__after_atomic();
+
                atomic_dec(&urb->dev->urbnum);
                if (atomic_read(&urb->reject))
                        wake_up(&usb_kill_urb_queue);
@@ -1665,6 +1672,13 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
 
        usb_anchor_resume_wakeups(anchor);
        atomic_dec(&urb->use_count);
+       /*
+        * Order the write of urb->use_count above before the read
+        * of urb->reject below.  Pairs with the memory barriers in
+        * usb_kill_urb() and usb_poison_urb().
+        */
+       smp_mb__after_atomic();
+
        if (unlikely(atomic_read(&urb->reject)))
                wake_up(&usb_kill_urb_queue);
        usb_put_urb(urb);
index c2bbf97..d5bc36c 100644 (file)
@@ -602,11 +602,14 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
                return retval;
        }
 
-       find_and_link_peer(hub, port1);
-
        retval = component_add(&port_dev->dev, &connector_ops);
-       if (retval)
+       if (retval) {
                dev_warn(&port_dev->dev, "failed to add component\n");
+               device_unregister(&port_dev->dev);
+               return retval;
+       }
+
+       find_and_link_peer(hub, port1);
 
        /*
         * Enable runtime pm and hold a refernce that hub_configure()
index 3072772..33d62d7 100644 (file)
@@ -715,6 +715,12 @@ void usb_kill_urb(struct urb *urb)
        if (!(urb && urb->dev && urb->ep))
                return;
        atomic_inc(&urb->reject);
+       /*
+        * Order the write of urb->reject above before the read
+        * of urb->use_count below.  Pairs with the barriers in
+        * __usb_hcd_giveback_urb() and usb_hcd_submit_urb().
+        */
+       smp_mb__after_atomic();
 
        usb_hcd_unlink_urb(urb, -ENOENT);
        wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
@@ -756,6 +762,12 @@ void usb_poison_urb(struct urb *urb)
        if (!urb)
                return;
        atomic_inc(&urb->reject);
+       /*
+        * Order the write of urb->reject above before the read
+        * of urb->use_count below.  Pairs with the barriers in
+        * __usb_hcd_giveback_urb() and usb_hcd_submit_urb().
+        */
+       smp_mb__after_atomic();
 
        if (!urb->dev || !urb->ep)
                return;
index 2bc03f4..eee3504 100644 (file)
@@ -5097,7 +5097,7 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg)
                hsotg->gadget.speed = USB_SPEED_UNKNOWN;
                spin_unlock_irqrestore(&hsotg->lock, flags);
 
-               for (ep = 0; ep < hsotg->num_of_eps; ep++) {
+               for (ep = 1; ep < hsotg->num_of_eps; ep++) {
                        if (hsotg->eps_in[ep])
                                dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep);
                        if (hsotg->eps_out[ep])
index 9cc3ad7..a6f3a9b 100644 (file)
@@ -99,17 +99,29 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
        struct device           *dev = priv_data->dev;
        struct reset_control    *crst, *hibrst, *apbrst;
        struct phy              *usb3_phy;
-       int                     ret;
+       int                     ret = 0;
        u32                     reg;
 
-       usb3_phy = devm_phy_get(dev, "usb3-phy");
-       if (PTR_ERR(usb3_phy) == -EPROBE_DEFER) {
-               ret = -EPROBE_DEFER;
+       usb3_phy = devm_phy_optional_get(dev, "usb3-phy");
+       if (IS_ERR(usb3_phy)) {
+               ret = PTR_ERR(usb3_phy);
+               dev_err_probe(dev, ret,
+                             "failed to get USB3 PHY\n");
                goto err;
-       } else if (IS_ERR(usb3_phy)) {
-               usb3_phy = NULL;
        }
 
+       /*
+        * The following core resets are not required unless a USB3 PHY
+        * is used, and the subsequent register settings are not required
+        * unless a core reset is performed (they should be set properly
+        * by the first-stage boot loader, but may be reverted by a core
+        * reset). They may also break the configuration if USB3 is actually
+        * in use but the usb3-phy entry is missing from the device tree.
+        * Therefore, skip these operations in this case.
+        */
+       if (!usb3_phy)
+               goto skip_usb3_phy;
+
        crst = devm_reset_control_get_exclusive(dev, "usb_crst");
        if (IS_ERR(crst)) {
                ret = PTR_ERR(crst);
@@ -188,6 +200,7 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
                goto err;
        }
 
+skip_usb3_phy:
        /*
         * This routes the USB DMA traffic to go through FPD path instead
         * of reaching DDR directly. This traffic routing is needed to
index 520031b..183b909 100644 (file)
@@ -1291,6 +1291,19 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
        if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
                trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(stream_id);
 
+       /*
+        * As per data book 4.2.3.2TRB Control Bit Rules section
+        *
+        * The controller autonomously checks the HWO field of a TRB to determine if the
+        * entire TRB is valid. Therefore, software must ensure that the rest of the TRB
+        * is valid before setting the HWO field to '1'. In most systems, this means that
+        * software must update the fourth DWORD of a TRB last.
+        *
+        * However there is a possibility of CPU re-ordering here which can cause
+        * controller to observe the HWO bit set prematurely.
+        * Add a write memory barrier to prevent CPU re-ordering.
+        */
+       wmb();
        trb->ctrl |= DWC3_TRB_CTRL_HWO;
 
        dwc3_ep_inc_enq(dep);
index 16f9e34..9315313 100644 (file)
@@ -1988,6 +1988,9 @@ unknown:
                                if (w_index != 0x5 || (w_value >> 8))
                                        break;
                                interface = w_value & 0xFF;
+                               if (interface >= MAX_CONFIG_INTERFACES ||
+                                   !os_desc_cfg->interface[interface])
+                                       break;
                                buf[6] = w_index;
                                count = count_ext_prop(os_desc_cfg,
                                        interface);
index 25ad1e9..1922fd0 100644 (file)
@@ -1711,16 +1711,24 @@ static void ffs_data_put(struct ffs_data *ffs)
 
 static void ffs_data_closed(struct ffs_data *ffs)
 {
+       struct ffs_epfile *epfiles;
+       unsigned long flags;
+
        ENTER();
 
        if (atomic_dec_and_test(&ffs->opened)) {
                if (ffs->no_disconnect) {
                        ffs->state = FFS_DEACTIVATED;
-                       if (ffs->epfiles) {
-                               ffs_epfiles_destroy(ffs->epfiles,
-                                                  ffs->eps_count);
-                               ffs->epfiles = NULL;
-                       }
+                       spin_lock_irqsave(&ffs->eps_lock, flags);
+                       epfiles = ffs->epfiles;
+                       ffs->epfiles = NULL;
+                       spin_unlock_irqrestore(&ffs->eps_lock,
+                                                       flags);
+
+                       if (epfiles)
+                               ffs_epfiles_destroy(epfiles,
+                                                ffs->eps_count);
+
                        if (ffs->setup_state == FFS_SETUP_PENDING)
                                __ffs_ep0_stall(ffs);
                } else {
@@ -1767,14 +1775,27 @@ static struct ffs_data *ffs_data_new(const char *dev_name)
 
 static void ffs_data_clear(struct ffs_data *ffs)
 {
+       struct ffs_epfile *epfiles;
+       unsigned long flags;
+
        ENTER();
 
        ffs_closed(ffs);
 
        BUG_ON(ffs->gadget);
 
-       if (ffs->epfiles) {
-               ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
+       spin_lock_irqsave(&ffs->eps_lock, flags);
+       epfiles = ffs->epfiles;
+       ffs->epfiles = NULL;
+       spin_unlock_irqrestore(&ffs->eps_lock, flags);
+
+       /*
+        * potential race possible between ffs_func_eps_disable
+        * & ffs_epfile_release therefore maintaining a local
+        * copy of epfile will save us from use-after-free.
+        */
+       if (epfiles) {
+               ffs_epfiles_destroy(epfiles, ffs->eps_count);
                ffs->epfiles = NULL;
        }
 
@@ -1922,12 +1943,15 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
 
 static void ffs_func_eps_disable(struct ffs_function *func)
 {
-       struct ffs_ep *ep         = func->eps;
-       struct ffs_epfile *epfile = func->ffs->epfiles;
-       unsigned count            = func->ffs->eps_count;
+       struct ffs_ep *ep;
+       struct ffs_epfile *epfile;
+       unsigned short count;
        unsigned long flags;
 
        spin_lock_irqsave(&func->ffs->eps_lock, flags);
+       count = func->ffs->eps_count;
+       epfile = func->ffs->epfiles;
+       ep = func->eps;
        while (count--) {
                /* pending requests get nuked */
                if (ep->ep)
@@ -1945,14 +1969,18 @@ static void ffs_func_eps_disable(struct ffs_function *func)
 
 static int ffs_func_eps_enable(struct ffs_function *func)
 {
-       struct ffs_data *ffs      = func->ffs;
-       struct ffs_ep *ep         = func->eps;
-       struct ffs_epfile *epfile = ffs->epfiles;
-       unsigned count            = ffs->eps_count;
+       struct ffs_data *ffs;
+       struct ffs_ep *ep;
+       struct ffs_epfile *epfile;
+       unsigned short count;
        unsigned long flags;
        int ret = 0;
 
        spin_lock_irqsave(&func->ffs->eps_lock, flags);
+       ffs = func->ffs;
+       ep = func->eps;
+       epfile = ffs->epfiles;
+       count = ffs->eps_count;
        while(count--) {
                ep->ep->driver_data = ep;
 
index 1abf08e..6803cd6 100644 (file)
@@ -584,6 +584,7 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
 
        if (is_iso) {
                switch (speed) {
+               case USB_SPEED_SUPER_PLUS:
                case USB_SPEED_SUPER:
                        size = ss->isoc_maxpacket *
                                        (ss->isoc_mult + 1) *
index 36fa6ef..097a709 100644 (file)
@@ -203,7 +203,7 @@ static struct uac2_input_terminal_descriptor io_in_it_desc = {
 
        .bDescriptorSubtype = UAC_INPUT_TERMINAL,
        /* .bTerminalID = DYNAMIC */
-       .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_UNDEFINED),
+       .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE),
        .bAssocTerminal = 0,
        /* .bCSourceID = DYNAMIC */
        .iChannelNames = 0,
@@ -231,7 +231,7 @@ static struct uac2_output_terminal_descriptor io_out_ot_desc = {
 
        .bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
        /* .bTerminalID = DYNAMIC */
-       .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_UNDEFINED),
+       .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER),
        .bAssocTerminal = 0,
        /* .bSourceID = DYNAMIC */
        /* .bCSourceID = DYNAMIC */
index 431d5a7..b7ccf18 100644 (file)
@@ -637,14 +637,17 @@ static int rndis_set_response(struct rndis_params *params,
        rndis_set_cmplt_type *resp;
        rndis_resp_t *r;
 
+       BufLength = le32_to_cpu(buf->InformationBufferLength);
+       BufOffset = le32_to_cpu(buf->InformationBufferOffset);
+       if ((BufLength > RNDIS_MAX_TOTAL_SIZE) ||
+           (BufOffset + 8 >= RNDIS_MAX_TOTAL_SIZE))
+                   return -EINVAL;
+
        r = rndis_add_response(params, sizeof(rndis_set_cmplt_type));
        if (!r)
                return -ENOMEM;
        resp = (rndis_set_cmplt_type *)r->buf;
 
-       BufLength = le32_to_cpu(buf->InformationBufferLength);
-       BufOffset = le32_to_cpu(buf->InformationBufferOffset);
-
 #ifdef VERBOSE_DEBUG
        pr_debug("%s: Length: %d\n", __func__, BufLength);
        pr_debug("%s: Offset: %d\n", __func__, BufOffset);
index c5a2c73..d86c3a3 100644 (file)
@@ -1004,7 +1004,7 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
                ret = -EBUSY;
                goto out_unlock;
        }
-       if ((in && !ep->ep->caps.dir_in) || (!in && ep->ep->caps.dir_in)) {
+       if (in != usb_endpoint_dir_in(ep->ep->desc)) {
                dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
                ret = -EINVAL;
                goto out_unlock;
index dd0819d..9040a05 100644 (file)
@@ -1895,7 +1895,7 @@ static int at91udc_probe(struct platform_device *pdev)
                                        at91_vbus_irq, 0, driver_name, udc);
                        if (retval) {
                                DBG("request vbus irq %d failed\n",
-                                   udc->board.vbus_pin);
+                                   desc_to_gpio(udc->board.vbus_pin));
                                goto err_unprepare_iclk;
                        }
                }
index 57d417a..601829a 100644 (file)
@@ -2378,6 +2378,8 @@ static void handle_ext_role_switch_states(struct device *dev,
        switch (role) {
        case USB_ROLE_NONE:
                usb3->connection_state = USB_ROLE_NONE;
+               if (cur_role == USB_ROLE_HOST)
+                       device_release_driver(host);
                if (usb3->driver)
                        usb3_disconnect(usb3);
                usb3_vbus_out(usb3, false);
index c1edcc9..dc570ce 100644 (file)
@@ -437,6 +437,9 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev)
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        int ret;
 
+       if (pm_runtime_suspended(dev))
+               pm_runtime_resume(dev);
+
        ret = xhci_priv_suspend_quirk(hcd);
        if (ret)
                return ret;
index 507deef..04c4e3f 100644 (file)
@@ -543,6 +543,9 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
        if (of_property_read_u16_array(np, "language-id", &hub->lang_id, 1))
                hub->lang_id = USB251XB_DEF_LANGUAGE_ID;
 
+       if (of_property_read_u8(np, "boost-up", &hub->boost_up))
+               hub->boost_up = USB251XB_DEF_BOOST_UP;
+
        cproperty_char = of_get_property(np, "manufacturer", NULL);
        strlcpy(str, cproperty_char ? : USB251XB_DEF_MANUFACTURER_STRING,
                sizeof(str));
@@ -584,7 +587,6 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
         * may be as soon as needed.
         */
        hub->bat_charge_en = USB251XB_DEF_BATTERY_CHARGING_ENABLE;
-       hub->boost_up = USB251XB_DEF_BOOST_UP;
        hub->boost_57 = USB251XB_DEF_BOOST_57;
        hub->boost_14 = USB251XB_DEF_BOOST_14;
        hub->port_map12 = USB251XB_DEF_PORT_MAP_12;
index 29f4b87..58cba8e 100644 (file)
@@ -85,6 +85,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x1a86, 0x5523) },
        { USB_DEVICE(0x1a86, 0x7522) },
        { USB_DEVICE(0x1a86, 0x7523) },
+       { USB_DEVICE(0x2184, 0x0057) },
        { USB_DEVICE(0x4348, 0x5523) },
        { USB_DEVICE(0x9986, 0x7523) },
        { },
index 8a60c0d..a27f7ef 100644 (file)
@@ -51,6 +51,7 @@ static void cp210x_enable_event_mode(struct usb_serial_port *port);
 static void cp210x_disable_event_mode(struct usb_serial_port *port);
 
 static const struct usb_device_id id_table[] = {
+       { USB_DEVICE(0x0404, 0x034C) }, /* NCR Retail IO Box */
        { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */
        { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */
        { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
@@ -68,6 +69,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */
        { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */
        { USB_DEVICE(0x0FDE, 0xCA05) }, /* OWL Wireless Electricity Monitor CM-160 */
+       { USB_DEVICE(0x106F, 0x0003) }, /* CPI / Money Controls Bulk Coin Recycler */
        { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
        { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
        { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
index 4edebd1..49c08f0 100644 (file)
@@ -969,6 +969,7 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_023_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_034_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_101_PID) },
+       { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_159_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_1_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_2_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_3_PID) },
@@ -977,12 +978,14 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_6_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_7_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_8_PID) },
+       { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_235_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_257_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_1_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_2_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_3_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_4_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_313_PID) },
+       { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_320_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_324_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_1_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_2_PID) },
index 755858c..d1a9564 100644 (file)
 #define BRAINBOXES_VX_023_PID          0x1003 /* VX-023 ExpressCard 1 Port RS422/485 */
 #define BRAINBOXES_VX_034_PID          0x1004 /* VX-034 ExpressCard 2 Port RS422/485 */
 #define BRAINBOXES_US_101_PID          0x1011 /* US-101 1xRS232 */
+#define BRAINBOXES_US_159_PID          0x1021 /* US-159 1xRS232 */
+#define BRAINBOXES_US_235_PID          0x1017 /* US-235 1xRS232 */
+#define BRAINBOXES_US_320_PID          0x1019 /* US-320 1xRS422/485 */
 #define BRAINBOXES_US_324_PID          0x1013 /* US-324 1xRS422/485 1Mbaud */
 #define BRAINBOXES_US_606_1_PID                0x2001 /* US-606 6 Port RS232 Serial Port 1 and 2 */
 #define BRAINBOXES_US_606_2_PID                0x2002 /* US-606 6 Port RS232 Serial Port 3 and 4 */
index 42420bf..962e994 100644 (file)
@@ -1649,6 +1649,8 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = RSVD(2) },
        { USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x1476, 0xff) },    /* GosunCn ZTE WeLink ME3630 (ECM/NCM mode) */
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1481, 0xff, 0x00, 0x00) }, /* ZTE MF871A */
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1485, 0xff, 0xff, 0xff),  /* ZTE MF286D */
+         .driver_info = RSVD(5) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1533, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1534, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1535, 0xff, 0xff, 0xff) },
index 29191d3..1a05e3d 100644 (file)
@@ -2301,6 +2301,16 @@ UNUSUAL_DEV(  0x2027, 0xa001, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
                US_FL_SCM_MULT_TARG ),
 
+/*
+ * Reported by DocMAX <mail@vacharakis.de>
+ * and Thomas Weißschuh <linux@weissschuh.net>
+ */
+UNUSUAL_DEV( 0x2109, 0x0715, 0x9999, 0x9999,
+               "VIA Labs, Inc.",
+               "VL817 SATA Bridge",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_IGNORE_UAS),
+
 UNUSUAL_DEV( 0x2116, 0x0320, 0x0001, 0x0001,
                "ST",
                "2A",
index 07d3074..a7d5078 100644 (file)
@@ -56,7 +56,12 @@ int typec_link_ports(struct typec_port *con)
 {
        struct each_port_arg arg = { .port = con, .match = NULL };
 
+       if (!has_acpi_companion(&con->dev))
+               return 0;
+
        bus_for_each_dev(&acpi_bus_type, NULL, &arg, typec_port_match);
+       if (!arg.match)
+               return 0;
 
        /*
         * REVISIT: Now each connector can have only a single component master.
@@ -74,5 +79,6 @@ int typec_link_ports(struct typec_port *con)
 
 void typec_unlink_ports(struct typec_port *con)
 {
-       component_master_del(&con->dev, &typec_aggregate_ops);
+       if (has_acpi_companion(&con->dev))
+               component_master_del(&con->dev, &typec_aggregate_ops);
 }
index 35a1307..e07d26a 100644 (file)
@@ -75,9 +75,25 @@ static int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val)
 static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
 {
        struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+       bool vconn_pres;
+       enum typec_cc_polarity polarity = TYPEC_POLARITY_CC1;
        unsigned int reg;
        int ret;
 
+       ret = regmap_read(tcpci->regmap, TCPC_POWER_STATUS, &reg);
+       if (ret < 0)
+               return ret;
+
+       vconn_pres = !!(reg & TCPC_POWER_STATUS_VCONN_PRES);
+       if (vconn_pres) {
+               ret = regmap_read(tcpci->regmap, TCPC_TCPC_CTRL, &reg);
+               if (ret < 0)
+                       return ret;
+
+               if (reg & TCPC_TCPC_CTRL_ORIENTATION)
+                       polarity = TYPEC_POLARITY_CC2;
+       }
+
        switch (cc) {
        case TYPEC_CC_RA:
                reg = (TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC1_SHIFT) |
@@ -112,6 +128,16 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
                break;
        }
 
+       if (vconn_pres) {
+               if (polarity == TYPEC_POLARITY_CC2) {
+                       reg &= ~(TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT);
+                       reg |= (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT);
+               } else {
+                       reg &= ~(TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT);
+                       reg |= (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC2_SHIFT);
+               }
+       }
+
        ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
        if (ret < 0)
                return ret;
index 2be7a77..b2edd45 100644 (file)
@@ -98,6 +98,7 @@
 #define TCPC_POWER_STATUS_SOURCING_VBUS        BIT(4)
 #define TCPC_POWER_STATUS_VBUS_DET     BIT(3)
 #define TCPC_POWER_STATUS_VBUS_PRES    BIT(2)
+#define TCPC_POWER_STATUS_VCONN_PRES   BIT(1)
 #define TCPC_POWER_STATUS_SINKING_VBUS BIT(0)
 
 #define TCPC_FAULT_STATUS              0x1f
index 59d4fa2..5fce795 100644 (file)
@@ -5156,7 +5156,8 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
        case SNK_TRYWAIT_DEBOUNCE:
                break;
        case SNK_ATTACH_WAIT:
-               tcpm_set_state(port, SNK_UNATTACHED, 0);
+       case SNK_DEBOUNCED:
+               /* Do nothing, as TCPM is still waiting for vbus to reaach VSAFE5V to connect */
                break;
 
        case SNK_NEGOTIATE_CAPABILITIES:
@@ -5263,6 +5264,10 @@ static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port)
        case PR_SWAP_SNK_SRC_SOURCE_ON:
                /* Do nothing, vsafe0v is expected during transition */
                break;
+       case SNK_ATTACH_WAIT:
+       case SNK_DEBOUNCED:
+               /*Do nothing, still waiting for VSAFE5V for connect */
+               break;
        default:
                if (port->pwr_role == TYPEC_SINK && port->auto_vbus_discharge_enabled)
                        tcpm_set_state(port, SNK_UNATTACHED, 0);
index bff96d6..6db7c8d 100644 (file)
@@ -325,7 +325,7 @@ static int ucsi_ccg_init(struct ucsi_ccg *uc)
                if (status < 0)
                        return status;
 
-               if (!data)
+               if (!(data & DEV_INT))
                        return 0;
 
                status = ccg_write(uc, CCGX_RAB_INTR_REG, &data, sizeof(data));
index 840d981..fcc4638 100644 (file)
@@ -78,6 +78,26 @@ config FRAMEBUFFER_CONSOLE
        help
          Low-level framebuffer-based console driver.
 
+config FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+       bool "Enable legacy fbcon hardware acceleration code"
+       depends on FRAMEBUFFER_CONSOLE
+       default y if PARISC
+       default n
+       help
+         This option enables the fbcon (framebuffer text-based) hardware
+         acceleration for graphics drivers which were written for the fbdev
+         graphics interface.
+
+         On modern machines, on mainstream machines (like x86-64) or when
+         using a modern Linux distribution those fbdev drivers usually aren't used.
+         So enabling this option wouldn't have any effect, which is why you want
+         to disable this option on such newer machines.
+
+         If you compile this kernel for older machines which still require the
+         fbdev drivers, you may want to say Y.
+
+         If unsure, select n.
+
 config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
        bool "Map the console to the primary display device"
        depends on FRAMEBUFFER_CONSOLE
index 01fae2c..f98e8f2 100644 (file)
@@ -43,6 +43,21 @@ static void update_attr(u8 *dst, u8 *src, int attribute,
        }
 }
 
+static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                     int sx, int dy, int dx, int height, int width)
+{
+       struct fb_copyarea area;
+
+       area.sx = sx * vc->vc_font.width;
+       area.sy = sy * vc->vc_font.height;
+       area.dx = dx * vc->vc_font.width;
+       area.dy = dy * vc->vc_font.height;
+       area.height = height * vc->vc_font.height;
+       area.width = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
 static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
                      int sx, int height, int width)
 {
@@ -378,6 +393,7 @@ static int bit_update_start(struct fb_info *info)
 
 void fbcon_set_bitops(struct fbcon_ops *ops)
 {
+       ops->bmove = bit_bmove;
        ops->clear = bit_clear;
        ops->putcs = bit_putcs;
        ops->clear_margins = bit_clear_margins;
index 99ecd9a..2fc1b80 100644 (file)
@@ -173,6 +173,8 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
                        int count, int ypos, int xpos);
 static void fbcon_clear_margins(struct vc_data *vc, int bottom_only);
 static void fbcon_cursor(struct vc_data *vc, int mode);
+static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
+                       int height, int width);
 static int fbcon_switch(struct vc_data *vc);
 static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch);
 static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table);
@@ -180,8 +182,16 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table);
 /*
  *  Internal routines
  */
+static __inline__ void ywrap_up(struct vc_data *vc, int count);
+static __inline__ void ywrap_down(struct vc_data *vc, int count);
+static __inline__ void ypan_up(struct vc_data *vc, int count);
+static __inline__ void ypan_down(struct vc_data *vc, int count);
+static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx,
+                           int dy, int dx, int height, int width, u_int y_break);
 static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
                           int unit);
+static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
+                             int line, int count, int dy);
 static void fbcon_modechanged(struct fb_info *info);
 static void fbcon_set_all_vcs(struct fb_info *info);
 static void fbcon_start(void);
@@ -1125,6 +1135,14 @@ static void fbcon_init(struct vc_data *vc, int init)
 
        ops->graphics = 0;
 
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+       if ((info->flags & FBINFO_HWACCEL_COPYAREA) &&
+           !(info->flags & FBINFO_HWACCEL_DISABLED))
+               p->scrollmode = SCROLL_MOVE;
+       else /* default to something safe */
+               p->scrollmode = SCROLL_REDRAW;
+#endif
+
        /*
         *  ++guenther: console.c:vc_allocate() relies on initializing
         *  vc_{cols,rows}, but we must not set those if we are only
@@ -1211,13 +1229,14 @@ finished:
  *  This system is now divided into two levels because of complications
  *  caused by hardware scrolling. Top level functions:
  *
- *     fbcon_clear(), fbcon_putc(), fbcon_clear_margins()
+ *     fbcon_bmove(), fbcon_clear(), fbcon_putc(), fbcon_clear_margins()
  *
  *  handles y values in range [0, scr_height-1] that correspond to real
  *  screen positions. y_wrap shift means that first line of bitmap may be
  *  anywhere on this display. These functions convert lineoffsets to
  *  bitmap offsets and deal with the wrap-around case by splitting blits.
  *
+ *     fbcon_bmove_physical_8()    -- These functions fast implementations
  *     fbcon_clear_physical_8()    -- of original fbcon_XXX fns.
  *     fbcon_putc_physical_8()     -- (font width != 8) may be added later
  *
@@ -1390,6 +1409,224 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
        }
 }
 
+static __inline__ void ywrap_up(struct vc_data *vc, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       p->yscroll += count;
+       if (p->yscroll >= p->vrows)     /* Deal with wrap */
+               p->yscroll -= p->vrows;
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode |= FB_VMODE_YWRAP;
+       ops->update_start(info);
+       scrollback_max += count;
+       if (scrollback_max > scrollback_phys_max)
+               scrollback_max = scrollback_phys_max;
+       scrollback_current = 0;
+}
+
+static __inline__ void ywrap_down(struct vc_data *vc, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       p->yscroll -= count;
+       if (p->yscroll < 0)     /* Deal with wrap */
+               p->yscroll += p->vrows;
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode |= FB_VMODE_YWRAP;
+       ops->update_start(info);
+       scrollback_max -= count;
+       if (scrollback_max < 0)
+               scrollback_max = 0;
+       scrollback_current = 0;
+}
+
+static __inline__ void ypan_up(struct vc_data *vc, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+       struct fbcon_ops *ops = info->fbcon_par;
+
+       p->yscroll += count;
+       if (p->yscroll > p->vrows - vc->vc_rows) {
+               ops->bmove(vc, info, p->vrows - vc->vc_rows,
+                           0, 0, 0, vc->vc_rows, vc->vc_cols);
+               p->yscroll -= p->vrows - vc->vc_rows;
+       }
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
+       fbcon_clear_margins(vc, 1);
+       scrollback_max += count;
+       if (scrollback_max > scrollback_phys_max)
+               scrollback_max = scrollback_phys_max;
+       scrollback_current = 0;
+}
+
+static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       p->yscroll += count;
+
+       if (p->yscroll > p->vrows - vc->vc_rows) {
+               p->yscroll -= p->vrows - vc->vc_rows;
+               fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t);
+       }
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
+       fbcon_clear_margins(vc, 1);
+       scrollback_max += count;
+       if (scrollback_max > scrollback_phys_max)
+               scrollback_max = scrollback_phys_max;
+       scrollback_current = 0;
+}
+
+static __inline__ void ypan_down(struct vc_data *vc, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+       struct fbcon_ops *ops = info->fbcon_par;
+
+       p->yscroll -= count;
+       if (p->yscroll < 0) {
+               ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows,
+                           0, vc->vc_rows, vc->vc_cols);
+               p->yscroll += p->vrows - vc->vc_rows;
+       }
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
+       fbcon_clear_margins(vc, 1);
+       scrollback_max -= count;
+       if (scrollback_max < 0)
+               scrollback_max = 0;
+       scrollback_current = 0;
+}
+
+static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       p->yscroll -= count;
+
+       if (p->yscroll < 0) {
+               p->yscroll += p->vrows - vc->vc_rows;
+               fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count);
+       }
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
+       fbcon_clear_margins(vc, 1);
+       scrollback_max -= count;
+       if (scrollback_max < 0)
+               scrollback_max = 0;
+       scrollback_current = 0;
+}
+
+static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
+                             int line, int count, int dy)
+{
+       unsigned short *s = (unsigned short *)
+               (vc->vc_origin + vc->vc_size_row * line);
+
+       while (count--) {
+               unsigned short *start = s;
+               unsigned short *le = advance_row(s, 1);
+               unsigned short c;
+               int x = 0;
+               unsigned short attr = 1;
+
+               do {
+                       c = scr_readw(s);
+                       if (attr != (c & 0xff00)) {
+                               attr = c & 0xff00;
+                               if (s > start) {
+                                       fbcon_putcs(vc, start, s - start,
+                                                   dy, x);
+                                       x += s - start;
+                                       start = s;
+                               }
+                       }
+                       console_conditional_schedule();
+                       s++;
+               } while (s < le);
+               if (s > start)
+                       fbcon_putcs(vc, start, s - start, dy, x);
+               console_conditional_schedule();
+               dy++;
+       }
+}
+
+static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
+                       struct fbcon_display *p, int line, int count, int ycount)
+{
+       int offset = ycount * vc->vc_cols;
+       unsigned short *d = (unsigned short *)
+           (vc->vc_origin + vc->vc_size_row * line);
+       unsigned short *s = d + offset;
+       struct fbcon_ops *ops = info->fbcon_par;
+
+       while (count--) {
+               unsigned short *start = s;
+               unsigned short *le = advance_row(s, 1);
+               unsigned short c;
+               int x = 0;
+
+               do {
+                       c = scr_readw(s);
+
+                       if (c == scr_readw(d)) {
+                               if (s > start) {
+                                       ops->bmove(vc, info, line + ycount, x,
+                                                  line, x, 1, s-start);
+                                       x += s - start + 1;
+                                       start = s + 1;
+                               } else {
+                                       x++;
+                                       start++;
+                               }
+                       }
+
+                       scr_writew(c, d);
+                       console_conditional_schedule();
+                       s++;
+                       d++;
+               } while (s < le);
+               if (s > start)
+                       ops->bmove(vc, info, line + ycount, x, line, x, 1,
+                                  s-start);
+               console_conditional_schedule();
+               if (ycount > 0)
+                       line++;
+               else {
+                       line--;
+                       /* NOTE: We subtract two lines from these pointers */
+                       s -= vc->vc_size_row;
+                       d -= vc->vc_size_row;
+               }
+       }
+}
+
 static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p,
                         int line, int count, int offset)
 {
@@ -1450,6 +1687,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
        struct fbcon_display *p = &fb_display[vc->vc_num];
+       int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
 
        if (fbcon_is_inactive(vc, info))
                return true;
@@ -1466,32 +1704,291 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
        case SM_UP:
                if (count > vc->vc_rows)        /* Maximum realistic size */
                        count = vc->vc_rows;
-               fbcon_redraw(vc, p, t, b - t - count,
-                            count * vc->vc_cols);
-               fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
-               scr_memsetw((unsigned short *) (vc->vc_origin +
-                                               vc->vc_size_row *
-                                               (b - count)),
-                           vc->vc_video_erase_char,
-                           vc->vc_size_row * count);
-               return true;
+               if (logo_shown >= 0)
+                       goto redraw_up;
+               switch (fb_scrollmode(p)) {
+               case SCROLL_MOVE:
+                       fbcon_redraw_blit(vc, info, p, t, b - t - count,
+                                    count);
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       scr_memsetw((unsigned short *) (vc->vc_origin +
+                                                       vc->vc_size_row *
+                                                       (b - count)),
+                                   vc->vc_video_erase_char,
+                                   vc->vc_size_row * count);
+                       return true;
+
+               case SCROLL_WRAP_MOVE:
+                       if (b - t - count > 3 * vc->vc_rows >> 2) {
+                               if (t > 0)
+                                       fbcon_bmove(vc, 0, 0, count, 0, t,
+                                                   vc->vc_cols);
+                               ywrap_up(vc, count);
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_bmove(vc, b - count, 0, b, 0,
+                                                   vc->vc_rows - b,
+                                                   vc->vc_cols);
+                       } else if (info->flags & FBINFO_READS_FAST)
+                               fbcon_bmove(vc, t + count, 0, t, 0,
+                                           b - t - count, vc->vc_cols);
+                       else
+                               goto redraw_up;
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_PAN_REDRAW:
+                       if ((p->yscroll + count <=
+                            2 * (p->vrows - vc->vc_rows))
+                           && ((!scroll_partial && (b - t == vc->vc_rows))
+                               || (scroll_partial
+                                   && (b - t - count >
+                                       3 * vc->vc_rows >> 2)))) {
+                               if (t > 0)
+                                       fbcon_redraw_move(vc, p, 0, t, count);
+                               ypan_up_redraw(vc, t, count);
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_redraw_move(vc, p, b,
+                                                         vc->vc_rows - b, b);
+                       } else
+                               fbcon_redraw_move(vc, p, t + count, b - t - count, t);
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_PAN_MOVE:
+                       if ((p->yscroll + count <=
+                            2 * (p->vrows - vc->vc_rows))
+                           && ((!scroll_partial && (b - t == vc->vc_rows))
+                               || (scroll_partial
+                                   && (b - t - count >
+                                       3 * vc->vc_rows >> 2)))) {
+                               if (t > 0)
+                                       fbcon_bmove(vc, 0, 0, count, 0, t,
+                                                   vc->vc_cols);
+                               ypan_up(vc, count);
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_bmove(vc, b - count, 0, b, 0,
+                                                   vc->vc_rows - b,
+                                                   vc->vc_cols);
+                       } else if (info->flags & FBINFO_READS_FAST)
+                               fbcon_bmove(vc, t + count, 0, t, 0,
+                                           b - t - count, vc->vc_cols);
+                       else
+                               goto redraw_up;
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_REDRAW:
+                     redraw_up:
+                       fbcon_redraw(vc, p, t, b - t - count,
+                                    count * vc->vc_cols);
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       scr_memsetw((unsigned short *) (vc->vc_origin +
+                                                       vc->vc_size_row *
+                                                       (b - count)),
+                                   vc->vc_video_erase_char,
+                                   vc->vc_size_row * count);
+                       return true;
+               }
+               break;
 
        case SM_DOWN:
                if (count > vc->vc_rows)        /* Maximum realistic size */
                        count = vc->vc_rows;
-               fbcon_redraw(vc, p, b - 1, b - t - count,
-                            -count * vc->vc_cols);
-               fbcon_clear(vc, t, 0, count, vc->vc_cols);
-               scr_memsetw((unsigned short *) (vc->vc_origin +
-                                               vc->vc_size_row *
-                                               t),
-                           vc->vc_video_erase_char,
-                           vc->vc_size_row * count);
-               return true;
+               if (logo_shown >= 0)
+                       goto redraw_down;
+               switch (fb_scrollmode(p)) {
+               case SCROLL_MOVE:
+                       fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
+                                    -count);
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       scr_memsetw((unsigned short *) (vc->vc_origin +
+                                                       vc->vc_size_row *
+                                                       t),
+                                   vc->vc_video_erase_char,
+                                   vc->vc_size_row * count);
+                       return true;
+
+               case SCROLL_WRAP_MOVE:
+                       if (b - t - count > 3 * vc->vc_rows >> 2) {
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_bmove(vc, b, 0, b - count, 0,
+                                                   vc->vc_rows - b,
+                                                   vc->vc_cols);
+                               ywrap_down(vc, count);
+                               if (t > 0)
+                                       fbcon_bmove(vc, count, 0, 0, 0, t,
+                                                   vc->vc_cols);
+                       } else if (info->flags & FBINFO_READS_FAST)
+                               fbcon_bmove(vc, t, 0, t + count, 0,
+                                           b - t - count, vc->vc_cols);
+                       else
+                               goto redraw_down;
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_PAN_MOVE:
+                       if ((count - p->yscroll <= p->vrows - vc->vc_rows)
+                           && ((!scroll_partial && (b - t == vc->vc_rows))
+                               || (scroll_partial
+                                   && (b - t - count >
+                                       3 * vc->vc_rows >> 2)))) {
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_bmove(vc, b, 0, b - count, 0,
+                                                   vc->vc_rows - b,
+                                                   vc->vc_cols);
+                               ypan_down(vc, count);
+                               if (t > 0)
+                                       fbcon_bmove(vc, count, 0, 0, 0, t,
+                                                   vc->vc_cols);
+                       } else if (info->flags & FBINFO_READS_FAST)
+                               fbcon_bmove(vc, t, 0, t + count, 0,
+                                           b - t - count, vc->vc_cols);
+                       else
+                               goto redraw_down;
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_PAN_REDRAW:
+                       if ((count - p->yscroll <= p->vrows - vc->vc_rows)
+                           && ((!scroll_partial && (b - t == vc->vc_rows))
+                               || (scroll_partial
+                                   && (b - t - count >
+                                       3 * vc->vc_rows >> 2)))) {
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_redraw_move(vc, p, b, vc->vc_rows - b,
+                                                         b - count);
+                               ypan_down_redraw(vc, t, count);
+                               if (t > 0)
+                                       fbcon_redraw_move(vc, p, count, t, 0);
+                       } else
+                               fbcon_redraw_move(vc, p, t, b - t - count, t + count);
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_REDRAW:
+                     redraw_down:
+                       fbcon_redraw(vc, p, b - 1, b - t - count,
+                                    -count * vc->vc_cols);
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       scr_memsetw((unsigned short *) (vc->vc_origin +
+                                                       vc->vc_size_row *
+                                                       t),
+                                   vc->vc_video_erase_char,
+                                   vc->vc_size_row * count);
+                       return true;
+               }
        }
        return false;
 }
 
+
+static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
+                       int height, int width)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       if (fbcon_is_inactive(vc, info))
+               return;
+
+       if (!width || !height)
+               return;
+
+       /*  Split blits that cross physical y_wrap case.
+        *  Pathological case involves 4 blits, better to use recursive
+        *  code rather than unrolled case
+        *
+        *  Recursive invocations don't need to erase the cursor over and
+        *  over again, so we use fbcon_bmove_rec()
+        */
+       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width,
+                       p->vrows - p->yscroll);
+}
+
+static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx,
+                           int dy, int dx, int height, int width, u_int y_break)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       u_int b;
+
+       if (sy < y_break && sy + height > y_break) {
+               b = y_break - sy;
+               if (dy < sy) {  /* Avoid trashing self */
+                       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+                                       y_break);
+                       fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+                                       height - b, width, y_break);
+               } else {
+                       fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+                                       height - b, width, y_break);
+                       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+                                       y_break);
+               }
+               return;
+       }
+
+       if (dy < y_break && dy + height > y_break) {
+               b = y_break - dy;
+               if (dy < sy) {  /* Avoid trashing self */
+                       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+                                       y_break);
+                       fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+                                       height - b, width, y_break);
+               } else {
+                       fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+                                       height - b, width, y_break);
+                       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+                                       y_break);
+               }
+               return;
+       }
+       ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx,
+                  height, width);
+}
+
+static void updatescrollmode_accel(struct fbcon_display *p,
+                                       struct fb_info *info,
+                                       struct vc_data *vc)
+{
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+       struct fbcon_ops *ops = info->fbcon_par;
+       int cap = info->flags;
+       u16 t = 0;
+       int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
+                                 info->fix.xpanstep);
+       int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
+       int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+       int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
+                                  info->var.xres_virtual);
+       int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
+               divides(ypan, vc->vc_font.height) && vyres > yres;
+       int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
+               divides(ywrap, vc->vc_font.height) &&
+               divides(vc->vc_font.height, vyres) &&
+               divides(vc->vc_font.height, yres);
+       int reading_fast = cap & FBINFO_READS_FAST;
+       int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
+               !(cap & FBINFO_HWACCEL_DISABLED);
+       int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
+               !(cap & FBINFO_HWACCEL_DISABLED);
+
+       if (good_wrap || good_pan) {
+               if (reading_fast || fast_copyarea)
+                       p->scrollmode = good_wrap ?
+                               SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
+               else
+                       p->scrollmode = good_wrap ? SCROLL_REDRAW :
+                               SCROLL_PAN_REDRAW;
+       } else {
+               if (reading_fast || (fast_copyarea && !fast_imageblit))
+                       p->scrollmode = SCROLL_MOVE;
+               else
+                       p->scrollmode = SCROLL_REDRAW;
+       }
+#endif
+}
+
 static void updatescrollmode(struct fbcon_display *p,
                                        struct fb_info *info,
                                        struct vc_data *vc)
@@ -1507,6 +2004,9 @@ static void updatescrollmode(struct fbcon_display *p,
                p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
        if ((yres % fh) && (vyres % fh < yres % fh))
                p->vrows--;
+
+       /* update scrollmode in case hardware acceleration is used */
+       updatescrollmode_accel(p, info, vc);
 }
 
 #define PITCH(w) (((w) + 7) >> 3)
@@ -1664,7 +2164,21 @@ static int fbcon_switch(struct vc_data *vc)
 
        updatescrollmode(p, info, vc);
 
-       scrollback_phys_max = 0;
+       switch (fb_scrollmode(p)) {
+       case SCROLL_WRAP_MOVE:
+               scrollback_phys_max = p->vrows - vc->vc_rows;
+               break;
+       case SCROLL_PAN_MOVE:
+       case SCROLL_PAN_REDRAW:
+               scrollback_phys_max = p->vrows - 2 * vc->vc_rows;
+               if (scrollback_phys_max < 0)
+                       scrollback_phys_max = 0;
+               break;
+       default:
+               scrollback_phys_max = 0;
+               break;
+       }
+
        scrollback_max = 0;
        scrollback_current = 0;
 
index a00603b..969d41e 100644 (file)
@@ -29,6 +29,9 @@ struct fbcon_display {
     /* Filled in by the low-level console driver */
     const u_char *fontdata;
     int userfont;                   /* != 0 if fontdata kmalloc()ed */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+    u_short scrollmode;             /* Scroll Method, use fb_scrollmode() */
+#endif
     u_short inverse;                /* != 0 text black on white as default */
     short yscroll;                  /* Hardware scrolling */
     int vrows;                      /* number of virtual rows */
@@ -51,6 +54,8 @@ struct fbcon_display {
 };
 
 struct fbcon_ops {
+       void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
+                     int sx, int dy, int dx, int height, int width);
        void (*clear)(struct vc_data *vc, struct fb_info *info, int sy,
                      int sx, int height, int width);
        void (*putcs)(struct vc_data *vc, struct fb_info *info,
@@ -149,6 +154,73 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
 #define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0)
 #define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1)
 
+    /*
+     *  Scroll Method
+     */
+
+/* There are several methods fbcon can use to move text around the screen:
+ *
+ *                     Operation   Pan    Wrap
+ *---------------------------------------------
+ * SCROLL_MOVE         copyarea    No     No
+ * SCROLL_PAN_MOVE     copyarea    Yes    No
+ * SCROLL_WRAP_MOVE    copyarea    No     Yes
+ * SCROLL_REDRAW       imageblit   No     No
+ * SCROLL_PAN_REDRAW   imageblit   Yes    No
+ * SCROLL_WRAP_REDRAW  imageblit   No     Yes
+ *
+ * (SCROLL_WRAP_REDRAW is not implemented yet)
+ *
+ * In general, fbcon will choose the best scrolling
+ * method based on the rule below:
+ *
+ * Pan/Wrap > accel imageblit > accel copyarea >
+ * soft imageblit > (soft copyarea)
+ *
+ * Exception to the rule: Pan + accel copyarea is
+ * preferred over Pan + accel imageblit.
+ *
+ * The above is typical for PCI/AGP cards. Unless
+ * overridden, fbcon will never use soft copyarea.
+ *
+ * If you need to override the above rule, set the
+ * appropriate flags in fb_info->flags.  For example,
+ * to prefer copyarea over imageblit, set
+ * FBINFO_READS_FAST.
+ *
+ * Other notes:
+ * + use the hardware engine to move the text
+ *    (hw-accelerated copyarea() and fillrect())
+ * + use hardware-supported panning on a large virtual screen
+ * + amifb can not only pan, but also wrap the display by N lines
+ *    (i.e. visible line i = physical line (i+N) % yres).
+ * + read what's already rendered on the screen and
+ *     write it in a different place (this is cfb_copyarea())
+ * + re-render the text to the screen
+ *
+ * Whether to use wrapping or panning can only be figured out at
+ * runtime (when we know whether our font height is a multiple
+ * of the pan/wrap step)
+ *
+ */
+
+#define SCROLL_MOVE       0x001
+#define SCROLL_PAN_MOVE           0x002
+#define SCROLL_WRAP_MOVE   0x003
+#define SCROLL_REDRAW     0x004
+#define SCROLL_PAN_REDRAW  0x005
+
+static inline u_short fb_scrollmode(struct fbcon_display *fb)
+{
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+       return fb->scrollmode;
+#else
+       /* hardcoded to SCROLL_REDRAW if acceleration was disabled. */
+       return SCROLL_REDRAW;
+#endif
+}
+
+
 #ifdef CONFIG_FB_TILEBLITTING
 extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
 #endif
index ffa7893..2789ace 100644 (file)
@@ -59,12 +59,31 @@ static void ccw_update_attr(u8 *dst, u8 *src, int attribute,
        }
 }
 
+
+static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int dy, int dx, int height, int width)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fb_copyarea area;
+       u32 vyres = GETVYRES(ops->p, info);
+
+       area.sx = sy * vc->vc_font.height;
+       area.sy = vyres - ((sx + width) * vc->vc_font.width);
+       area.dx = dy * vc->vc_font.height;
+       area.dy = vyres - ((dx + width) * vc->vc_font.width);
+       area.width = height * vc->vc_font.height;
+       area.height  = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
 static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
                     int sx, int height, int width)
 {
+       struct fbcon_ops *ops = info->fbcon_par;
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
-       u32 vyres = info->var.yres;
+       u32 vyres = GETVYRES(ops->p, info);
 
        region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dx = sy * vc->vc_font.height;
@@ -121,7 +140,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
        u32 cnt, pitch, size;
        u32 attribute = get_attribute(info, scr_readw(s));
        u8 *dst, *buf = NULL;
-       u32 vyres = info->var.yres;
+       u32 vyres = GETVYRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -210,7 +229,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
        int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
        int err = 1, dx, dy;
        char *src;
-       u32 vyres = info->var.yres;
+       u32 vyres = GETVYRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -368,7 +387,7 @@ static int ccw_update_start(struct fb_info *info)
 {
        struct fbcon_ops *ops = info->fbcon_par;
        u32 yoffset;
-       u32 vyres = info->var.yres;
+       u32 vyres = GETVYRES(ops->p, info);
        int err;
 
        yoffset = (vyres - info->var.yres) - ops->var.xoffset;
@@ -383,6 +402,7 @@ static int ccw_update_start(struct fb_info *info)
 
 void fbcon_rotate_ccw(struct fbcon_ops *ops)
 {
+       ops->bmove = ccw_bmove;
        ops->clear = ccw_clear;
        ops->putcs = ccw_putcs;
        ops->clear_margins = ccw_clear_margins;
index 92e5b7f..86a254c 100644 (file)
@@ -44,12 +44,31 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute,
        }
 }
 
+
+static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int dy, int dx, int height, int width)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fb_copyarea area;
+       u32 vxres = GETVXRES(ops->p, info);
+
+       area.sx = vxres - ((sy + height) * vc->vc_font.height);
+       area.sy = sx * vc->vc_font.width;
+       area.dx = vxres - ((dy + height) * vc->vc_font.height);
+       area.dy = dx * vc->vc_font.width;
+       area.width = height * vc->vc_font.height;
+       area.height  = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
 static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
                     int sx, int height, int width)
 {
+       struct fbcon_ops *ops = info->fbcon_par;
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
-       u32 vxres = info->var.xres;
+       u32 vxres = GETVXRES(ops->p, info);
 
        region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dx = vxres - ((sy + height) * vc->vc_font.height);
@@ -106,7 +125,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
        u32 cnt, pitch, size;
        u32 attribute = get_attribute(info, scr_readw(s));
        u8 *dst, *buf = NULL;
-       u32 vxres = info->var.xres;
+       u32 vxres = GETVXRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -193,7 +212,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
        int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
        int err = 1, dx, dy;
        char *src;
-       u32 vxres = info->var.xres;
+       u32 vxres = GETVXRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -350,7 +369,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
 static int cw_update_start(struct fb_info *info)
 {
        struct fbcon_ops *ops = info->fbcon_par;
-       u32 vxres = info->var.xres;
+       u32 vxres = GETVXRES(ops->p, info);
        u32 xoffset;
        int err;
 
@@ -366,6 +385,7 @@ static int cw_update_start(struct fb_info *info)
 
 void fbcon_rotate_cw(struct fbcon_ops *ops)
 {
+       ops->bmove = cw_bmove;
        ops->clear = cw_clear;
        ops->putcs = cw_putcs;
        ops->clear_margins = cw_clear_margins;
index b528b2e..01cbe30 100644 (file)
 #ifndef _FBCON_ROTATE_H
 #define _FBCON_ROTATE_H
 
+#define GETVYRES(s,i) ({                           \
+        (fb_scrollmode(s) == SCROLL_REDRAW || fb_scrollmode(s) == SCROLL_MOVE) ? \
+        (i)->var.yres : (i)->var.yres_virtual; })
+
+#define GETVXRES(s,i) ({                           \
+        (fb_scrollmode(s) == SCROLL_REDRAW || fb_scrollmode(s) == SCROLL_MOVE || !(i)->fix.xpanstep) ? \
+        (i)->var.xres : (i)->var.xres_virtual; })
+
+
 static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat)
 {
        u32 tmp = (y * pitch) + x, index = tmp / 8,  bit = tmp % 8;
index 09619bd..23bc045 100644 (file)
@@ -44,13 +44,33 @@ static void ud_update_attr(u8 *dst, u8 *src, int attribute,
        }
 }
 
+
+static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int dy, int dx, int height, int width)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fb_copyarea area;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
+
+       area.sy = vyres - ((sy + height) * vc->vc_font.height);
+       area.sx = vxres - ((sx + width) * vc->vc_font.width);
+       area.dy = vyres - ((dy + height) * vc->vc_font.height);
+       area.dx = vxres - ((dx + width) * vc->vc_font.width);
+       area.height = height * vc->vc_font.height;
+       area.width  = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
 static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
                     int sx, int height, int width)
 {
+       struct fbcon_ops *ops = info->fbcon_par;
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
-       u32 vyres = info->var.yres;
-       u32 vxres = info->var.xres;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
 
        region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dy = vyres - ((sy + height) * vc->vc_font.height);
@@ -142,8 +162,8 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
        u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
        u32 attribute = get_attribute(info, scr_readw(s));
        u8 *dst, *buf = NULL;
-       u32 vyres = info->var.yres;
-       u32 vxres = info->var.xres;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -239,8 +259,8 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
        int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
        int err = 1, dx, dy;
        char *src;
-       u32 vyres = info->var.yres;
-       u32 vxres = info->var.xres;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -390,8 +410,8 @@ static int ud_update_start(struct fb_info *info)
 {
        struct fbcon_ops *ops = info->fbcon_par;
        int xoffset, yoffset;
-       u32 vyres = info->var.yres;
-       u32 vxres = info->var.xres;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
        int err;
 
        xoffset = vxres - info->var.xres - ops->var.xoffset;
@@ -409,6 +429,7 @@ static int ud_update_start(struct fb_info *info)
 
 void fbcon_rotate_ud(struct fbcon_ops *ops)
 {
+       ops->bmove = ud_bmove;
        ops->clear = ud_clear;
        ops->putcs = ud_putcs;
        ops->clear_margins = ud_clear_margins;
index 0fa7ede..13083ad 100644 (file)
@@ -1160,6 +1160,8 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                ret = fbcon_set_con2fb_map_ioctl(argp);
                break;
        case FBIOBLANK:
+               if (arg > FB_BLANK_POWERDOWN)
+                       return -EINVAL;
                console_lock();
                lock_fb_info(info);
                ret = fb_blank(info, arg);
index 72af950..2768eff 100644 (file)
 #include <asm/types.h>
 #include "fbcon.h"
 
+static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                      int sx, int dy, int dx, int height, int width)
+{
+       struct fb_tilearea area;
+
+       area.sx = sx;
+       area.sy = sy;
+       area.dx = dx;
+       area.dy = dy;
+       area.height = height;
+       area.width = width;
+
+       info->tileops->fb_tilecopy(info, &area);
+}
+
 static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy,
                       int sx, int height, int width)
 {
@@ -118,6 +133,7 @@ void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info)
        struct fb_tilemap map;
        struct fbcon_ops *ops = info->fbcon_par;
 
+       ops->bmove = tile_bmove;
        ops->clear = tile_clear;
        ops->putcs = tile_putcs;
        ops->clear_margins = tile_clear_margins;
index 23999df..c8e0ea2 100644 (file)
@@ -287,8 +287,6 @@ struct hvfb_par {
 
 static uint screen_width = HVFB_WIDTH;
 static uint screen_height = HVFB_HEIGHT;
-static uint screen_width_max = HVFB_WIDTH;
-static uint screen_height_max = HVFB_HEIGHT;
 static uint screen_depth;
 static uint screen_fb_size;
 static uint dio_fb_size; /* FB size for deferred IO */
@@ -582,7 +580,6 @@ static int synthvid_get_supported_resolution(struct hv_device *hdev)
        int ret = 0;
        unsigned long t;
        u8 index;
-       int i;
 
        memset(msg, 0, sizeof(struct synthvid_msg));
        msg->vid_hdr.type = SYNTHVID_RESOLUTION_REQUEST;
@@ -613,13 +610,6 @@ static int synthvid_get_supported_resolution(struct hv_device *hdev)
                goto out;
        }
 
-       for (i = 0; i < msg->resolution_resp.resolution_count; i++) {
-               screen_width_max = max_t(unsigned int, screen_width_max,
-                   msg->resolution_resp.supported_resolution[i].width);
-               screen_height_max = max_t(unsigned int, screen_height_max,
-                   msg->resolution_resp.supported_resolution[i].height);
-       }
-
        screen_width =
                msg->resolution_resp.supported_resolution[index].width;
        screen_height =
@@ -941,7 +931,7 @@ static void hvfb_get_option(struct fb_info *info)
 
        if (x < HVFB_WIDTH_MIN || y < HVFB_HEIGHT_MIN ||
            (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10) &&
-           (x > screen_width_max || y > screen_height_max)) ||
+           (x * y * screen_depth / 8 > screen_fb_size)) ||
            (par->synthvid_version == SYNTHVID_VERSION_WIN8 &&
             x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8) ||
            (par->synthvid_version == SYNTHVID_VERSION_WIN7 &&
@@ -1194,8 +1184,8 @@ static int hvfb_probe(struct hv_device *hdev,
        }
 
        hvfb_get_option(info);
-       pr_info("Screen resolution: %dx%d, Color depth: %d\n",
-               screen_width, screen_height, screen_depth);
+       pr_info("Screen resolution: %dx%d, Color depth: %d, Frame buffer size: %d\n",
+               screen_width, screen_height, screen_depth, screen_fb_size);
 
        ret = hvfb_getmem(hdev, info);
        if (ret) {
index 0fe922f..bcacfb6 100644 (file)
@@ -505,15 +505,15 @@ void xxxfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)
 }
 
 /**
- *      xxxfb_copyarea - OBSOLETE function.
+ *      xxxfb_copyarea - REQUIRED function. Can use generic routines if
+ *                       non acclerated hardware and packed pixel based.
  *                       Copies one area of the screen to another area.
- *                       Will be deleted in a future version
  *
  *      @info: frame buffer structure that represents a single frame buffer
  *      @area: Structure providing the data to copy the framebuffer contents
  *            from one region to another.
  *
- *      This drawing operation copied a rectangular area from one area of the
+ *      This drawing operation copies a rectangular area from one area of the
  *     screen to another area.
  */
 void xxxfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) 
@@ -645,9 +645,9 @@ static const struct fb_ops xxxfb_ops = {
        .fb_setcolreg   = xxxfb_setcolreg,
        .fb_blank       = xxxfb_blank,
        .fb_pan_display = xxxfb_pan_display,
-       .fb_fillrect    = xxxfb_fillrect,       /* Needed !!!   */
-       .fb_copyarea    = xxxfb_copyarea,       /* Obsolete     */
-       .fb_imageblit   = xxxfb_imageblit,      /* Needed !!!   */
+       .fb_fillrect    = xxxfb_fillrect,       /* Needed !!! */
+       .fb_copyarea    = xxxfb_copyarea,       /* Needed !!! */
+       .fb_imageblit   = xxxfb_imageblit,      /* Needed !!! */
        .fb_cursor      = xxxfb_cursor,         /* Optional !!! */
        .fb_sync        = xxxfb_sync,
        .fb_ioctl       = xxxfb_ioctl,
index 2c890f4..72d4e3f 100644 (file)
@@ -264,7 +264,7 @@ struct xen_device_domain_owner {
 };
 
 static DEFINE_SPINLOCK(dev_domain_list_spinlock);
-static struct list_head dev_domain_list = LIST_HEAD_INIT(dev_domain_list);
+static LIST_HEAD(dev_domain_list);
 
 static struct xen_device_domain_owner *find_device(struct pci_dev *dev)
 {
index 6aab046..79df61f 100644 (file)
@@ -96,12 +96,8 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
                 dentry, dentry, from_kuid(&init_user_ns, uid),
                 any);
        ret = NULL;
-
-       if (d_inode(dentry))
-               ret = v9fs_fid_find_inode(d_inode(dentry), uid);
-
        /* we'll recheck under lock if there's anything to look in */
-       if (!ret && dentry->d_fsdata) {
+       if (dentry->d_fsdata) {
                struct hlist_head *h = (struct hlist_head *)&dentry->d_fsdata;
 
                spin_lock(&dentry->d_lock);
@@ -113,6 +109,9 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
                        }
                }
                spin_unlock(&dentry->d_lock);
+       } else {
+               if (dentry->d_inode)
+                       ret = v9fs_fid_find_inode(dentry->d_inode, uid);
        }
 
        return ret;
index 7a2b11c..6c7dc13 100644 (file)
@@ -369,8 +369,8 @@ source "fs/ksmbd/Kconfig"
 
 config SMBFS_COMMON
        tristate
-       default y if CIFS=y
-       default m if CIFS=m
+       default y if CIFS=y || SMB_SERVER=y
+       default m if CIFS=m || SMB_SERVER=m
 
 source "fs/coda/Kconfig"
 source "fs/afs/Kconfig"
index dab324a..208a74e 100644 (file)
@@ -96,7 +96,7 @@ obj-$(CONFIG_EXPORTFS)                += exportfs/
 obj-$(CONFIG_NFSD)             += nfsd/
 obj-$(CONFIG_LOCKD)            += lockd/
 obj-$(CONFIG_NLS)              += nls/
-obj-$(CONFIG_UNICODE)          += unicode/
+obj-y                          += unicode/
 obj-$(CONFIG_SYSV_FS)          += sysv/
 obj-$(CONFIG_SMBFS_COMMON)     += smbfs_common/
 obj-$(CONFIG_CIFS)             += cifs/
index 605017e..9e11e6f 100644 (file)
@@ -1117,7 +1117,7 @@ out_free_interp:
                         * without MAP_FIXED nor MAP_FIXED_NOREPLACE).
                         */
                        alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum);
-                       if (alignment > ELF_MIN_ALIGN) {
+                       if (interpreter || alignment > ELF_MIN_ALIGN) {
                                load_bias = ELF_ET_DYN_BASE;
                                if (current->flags & PF_RANDOMIZE)
                                        load_bias += arch_mmap_rnd();
index ddea6ac..e1eae7e 100644 (file)
@@ -822,11 +822,7 @@ static int __init init_misc_binfmt(void)
        int err = register_filesystem(&bm_fs_type);
        if (!err)
                insert_binfmt(&misc_format);
-       if (!register_sysctl_mount_point("fs/binfmt_misc")) {
-               pr_warn("Failed to create fs/binfmt_misc sysctl mount point");
-               return -ENOMEM;
-       }
-       return 0;
+       return err;
 }
 
 static void __exit exit_misc_binfmt(void)
index 1db24e6..8202ad6 100644 (file)
@@ -124,7 +124,16 @@ void btrfs_put_block_group(struct btrfs_block_group *cache)
 {
        if (refcount_dec_and_test(&cache->refs)) {
                WARN_ON(cache->pinned > 0);
-               WARN_ON(cache->reserved > 0);
+               /*
+                * If there was a failure to cleanup a log tree, very likely due
+                * to an IO failure on a writeback attempt of one or more of its
+                * extent buffers, we could not do proper (and cheap) unaccounting
+                * of their reserved space, so don't warn on reserved > 0 in that
+                * case.
+                */
+               if (!(cache->flags & BTRFS_BLOCK_GROUP_METADATA) ||
+                   !BTRFS_FS_LOG_CLEANUP_ERROR(cache->fs_info))
+                       WARN_ON(cache->reserved > 0);
 
                /*
                 * A block_group shouldn't be on the discard_list anymore.
@@ -2544,6 +2553,19 @@ int btrfs_inc_block_group_ro(struct btrfs_block_group *cache,
        int ret;
        bool dirty_bg_running;
 
+       /*
+        * This can only happen when we are doing read-only scrub on read-only
+        * mount.
+        * In that case we should not start a new transaction on read-only fs.
+        * Thus here we skip all chunk allocations.
+        */
+       if (sb_rdonly(fs_info->sb)) {
+               mutex_lock(&fs_info->ro_block_group_mutex);
+               ret = inc_block_group_ro(cache, 0);
+               mutex_unlock(&fs_info->ro_block_group_mutex);
+               return ret;
+       }
+
        do {
                trans = btrfs_join_transaction(root);
                if (IS_ERR(trans))
@@ -3974,9 +3996,22 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
                 * important and indicates a real bug if this happens.
                 */
                if (WARN_ON(space_info->bytes_pinned > 0 ||
-                           space_info->bytes_reserved > 0 ||
                            space_info->bytes_may_use > 0))
                        btrfs_dump_space_info(info, space_info, 0, 0);
+
+               /*
+                * If there was a failure to cleanup a log tree, very likely due
+                * to an IO failure on a writeback attempt of one or more of its
+                * extent buffers, we could not do proper (and cheap) unaccounting
+                * of their reserved space, so don't warn on bytes_reserved > 0 in
+                * that case.
+                */
+               if (!(space_info->flags & BTRFS_BLOCK_GROUP_METADATA) ||
+                   !BTRFS_FS_LOG_CLEANUP_ERROR(info)) {
+                       if (WARN_ON(space_info->bytes_reserved > 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 b4a9b1c..8992e00 100644 (file)
@@ -145,6 +145,9 @@ enum {
        BTRFS_FS_STATE_DUMMY_FS_INFO,
 
        BTRFS_FS_STATE_NO_CSUMS,
+
+       /* Indicates there was an error cleaning up a log tree. */
+       BTRFS_FS_STATE_LOG_CLEANUP_ERROR,
 };
 
 #define BTRFS_BACKREF_REV_MAX          256
@@ -3593,6 +3596,9 @@ do {                                                              \
 
 #define BTRFS_FS_ERROR(fs_info)        (unlikely(test_bit(BTRFS_FS_STATE_ERROR, \
                                                   &(fs_info)->fs_state)))
+#define BTRFS_FS_LOG_CLEANUP_ERROR(fs_info)                            \
+       (unlikely(test_bit(BTRFS_FS_STATE_LOG_CLEANUP_ERROR,            \
+                          &(fs_info)->fs_state)))
 
 __printf(5, 6)
 __cold
index a5bd692..33eda39 100644 (file)
@@ -805,10 +805,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
                goto fail;
        }
 
-       spin_lock(&fs_info->trans_lock);
-       list_add(&pending_snapshot->list,
-                &trans->transaction->pending_snapshots);
-       spin_unlock(&fs_info->trans_lock);
+       trans->pending_snapshot = pending_snapshot;
 
        ret = btrfs_commit_transaction(trans);
        if (ret)
@@ -1213,6 +1210,35 @@ static int defrag_collect_targets(struct btrfs_inode *inode,
                if (em->generation < newer_than)
                        goto next;
 
+               /*
+                * Our start offset might be in the middle of an existing extent
+                * map, so take that into account.
+                */
+               range_len = em->len - (cur - em->start);
+               /*
+                * If this range of the extent map is already flagged for delalloc,
+                * skip it, because:
+                *
+                * 1) We could deadlock later, when trying to reserve space for
+                *    delalloc, because in case we can't immediately reserve space
+                *    the flusher can start delalloc and wait for the respective
+                *    ordered extents to complete. The deadlock would happen
+                *    because we do the space reservation while holding the range
+                *    locked, and starting writeback, or finishing an ordered
+                *    extent, requires locking the range;
+                *
+                * 2) If there's delalloc there, it means there's dirty pages for
+                *    which writeback has not started yet (we clean the delalloc
+                *    flag when starting writeback and after creating an ordered
+                *    extent). If we mark pages in an adjacent range for defrag,
+                *    then we will have a larger contiguous range for delalloc,
+                *    very likely resulting in a larger extent after writeback is
+                *    triggered (except in a case of free space fragmentation).
+                */
+               if (test_range_bit(&inode->io_tree, cur, cur + range_len - 1,
+                                  EXTENT_DELALLOC, 0, NULL))
+                       goto next;
+
                /*
                 * For do_compress case, we want to compress all valid file
                 * extents, thus no @extent_thresh or mergeable check.
@@ -1221,7 +1247,7 @@ static int defrag_collect_targets(struct btrfs_inode *inode,
                        goto add;
 
                /* Skip too large extent */
-               if (em->len >= extent_thresh)
+               if (range_len >= extent_thresh)
                        goto next;
 
                next_mergeable = defrag_check_next_extent(&inode->vfs_inode, em,
@@ -1442,9 +1468,11 @@ static int defrag_one_cluster(struct btrfs_inode *inode,
        list_for_each_entry(entry, &target_list, list) {
                u32 range_len = entry->len;
 
-               /* Reached the limit */
-               if (max_sectors && max_sectors == *sectors_defragged)
+               /* Reached or beyond the limit */
+               if (max_sectors && *sectors_defragged >= max_sectors) {
+                       ret = 1;
                        break;
+               }
 
                if (max_sectors)
                        range_len = min_t(u32, range_len,
@@ -1465,7 +1493,8 @@ static int defrag_one_cluster(struct btrfs_inode *inode,
                                       extent_thresh, newer_than, do_compress);
                if (ret < 0)
                        break;
-               *sectors_defragged += range_len;
+               *sectors_defragged += range_len >>
+                                     inode->root->fs_info->sectorsize_bits;
        }
 out:
        list_for_each_entry_safe(entry, tmp, &target_list, list) {
@@ -1484,6 +1513,12 @@ out:
  * @newer_than:           minimum transid to defrag
  * @max_to_defrag: max number of sectors to be defragged, if 0, the whole inode
  *                will be defragged.
+ *
+ * Return <0 for error.
+ * Return >=0 for the number of sectors defragged, and range->start will be updated
+ * to indicate the file offset where next defrag should be started at.
+ * (Mostly for autodefrag, which sets @max_to_defrag thus we may exit early without
+ *  defragging all the range).
  */
 int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
                      struct btrfs_ioctl_defrag_range_args *range,
@@ -1499,6 +1534,7 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
        int compress_type = BTRFS_COMPRESS_ZLIB;
        int ret = 0;
        u32 extent_thresh = range->extent_thresh;
+       pgoff_t start_index;
 
        if (isize == 0)
                return 0;
@@ -1518,12 +1554,16 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
 
        if (range->start + range->len > range->start) {
                /* Got a specific range */
-               last_byte = min(isize, range->start + range->len) - 1;
+               last_byte = min(isize, range->start + range->len);
        } else {
                /* Defrag until file end */
-               last_byte = isize - 1;
+               last_byte = isize;
        }
 
+       /* Align the range */
+       cur = round_down(range->start, fs_info->sectorsize);
+       last_byte = round_up(last_byte, fs_info->sectorsize) - 1;
+
        /*
         * If we were not given a ra, allocate a readahead context. As
         * readahead is just an optimization, defrag will work without it so
@@ -1536,16 +1576,26 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
                        file_ra_state_init(ra, inode->i_mapping);
        }
 
-       /* Align the range */
-       cur = round_down(range->start, fs_info->sectorsize);
-       last_byte = round_up(last_byte, fs_info->sectorsize) - 1;
+       /*
+        * Make writeback start from the beginning of the range, so that the
+        * defrag range can be written sequentially.
+        */
+       start_index = cur >> PAGE_SHIFT;
+       if (start_index < inode->i_mapping->writeback_index)
+               inode->i_mapping->writeback_index = start_index;
 
        while (cur < last_byte) {
+               const unsigned long prev_sectors_defragged = sectors_defragged;
                u64 cluster_end;
 
                /* The cluster size 256K should always be page aligned */
                BUILD_BUG_ON(!IS_ALIGNED(CLUSTER_SIZE, PAGE_SIZE));
 
+               if (btrfs_defrag_cancelled(fs_info)) {
+                       ret = -EAGAIN;
+                       break;
+               }
+
                /* We want the cluster end at page boundary when possible */
                cluster_end = (((cur >> PAGE_SHIFT) +
                               (SZ_256K >> PAGE_SHIFT)) << PAGE_SHIFT) - 1;
@@ -1567,14 +1617,27 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
                                cluster_end + 1 - cur, extent_thresh,
                                newer_than, do_compress,
                                &sectors_defragged, max_to_defrag);
+
+               if (sectors_defragged > prev_sectors_defragged)
+                       balance_dirty_pages_ratelimited(inode->i_mapping);
+
                btrfs_inode_unlock(inode, 0);
                if (ret < 0)
                        break;
                cur = cluster_end + 1;
+               if (ret > 0) {
+                       ret = 0;
+                       break;
+               }
        }
 
        if (ra_allocated)
                kfree(ra);
+       /*
+        * Update range.start for autodefrag, this will indicate where to start
+        * in next run.
+        */
+       range->start = cur;
        if (sectors_defragged) {
                /*
                 * We have defragged some sectors, for compression case they
@@ -3086,10 +3149,8 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
        btrfs_inode_lock(inode, 0);
        err = btrfs_delete_subvolume(dir, dentry);
        btrfs_inode_unlock(inode, 0);
-       if (!err) {
-               fsnotify_rmdir(dir, dentry);
-               d_delete(dentry);
-       }
+       if (!err)
+               d_delete_notify(dir, dentry);
 
 out_dput:
        dput(dentry);
@@ -3290,7 +3351,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
        struct block_device *bdev = NULL;
        fmode_t mode;
        int ret;
-       bool cancel;
+       bool cancel = false;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
index 8928275..f12dc68 100644 (file)
@@ -1185,9 +1185,24 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
        struct btrfs_trans_handle *trans = NULL;
        int ret = 0;
 
+       /*
+        * We need to have subvol_sem write locked, to prevent races between
+        * concurrent tasks trying to disable quotas, because we will unlock
+        * and relock qgroup_ioctl_lock across BTRFS_FS_QUOTA_ENABLED changes.
+        */
+       lockdep_assert_held_write(&fs_info->subvol_sem);
+
        mutex_lock(&fs_info->qgroup_ioctl_lock);
        if (!fs_info->quota_root)
                goto out;
+
+       /*
+        * Request qgroup rescan worker to complete and wait for it. This wait
+        * must be done before transaction start for quota disable since it may
+        * deadlock with transaction by the qgroup rescan worker.
+        */
+       clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
+       btrfs_qgroup_wait_for_completion(fs_info, false);
        mutex_unlock(&fs_info->qgroup_ioctl_lock);
 
        /*
@@ -1205,14 +1220,13 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
        if (IS_ERR(trans)) {
                ret = PTR_ERR(trans);
                trans = NULL;
+               set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
                goto out;
        }
 
        if (!fs_info->quota_root)
                goto out;
 
-       clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
-       btrfs_qgroup_wait_for_completion(fs_info, false);
        spin_lock(&fs_info->qgroup_lock);
        quota_root = fs_info->quota_root;
        fs_info->quota_root = NULL;
@@ -3383,6 +3397,9 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
                        btrfs_warn(fs_info,
                        "qgroup rescan init failed, qgroup is not enabled");
                        ret = -EINVAL;
+               } else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
+                       /* Quota disable is in progress */
+                       ret = -EBUSY;
                }
 
                if (ret) {
index 03de89b..c43bbc7 100644 (file)
@@ -2000,6 +2000,27 @@ static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info)
                btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
 }
 
+/*
+ * Add a pending snapshot associated with the given transaction handle to the
+ * respective handle. This must be called after the transaction commit started
+ * and while holding fs_info->trans_lock.
+ * This serves to guarantee a caller of btrfs_commit_transaction() that it can
+ * safely free the pending snapshot pointer in case btrfs_commit_transaction()
+ * returns an error.
+ */
+static void add_pending_snapshot(struct btrfs_trans_handle *trans)
+{
+       struct btrfs_transaction *cur_trans = trans->transaction;
+
+       if (!trans->pending_snapshot)
+               return;
+
+       lockdep_assert_held(&trans->fs_info->trans_lock);
+       ASSERT(cur_trans->state >= TRANS_STATE_COMMIT_START);
+
+       list_add(&trans->pending_snapshot->list, &cur_trans->pending_snapshots);
+}
+
 int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 {
        struct btrfs_fs_info *fs_info = trans->fs_info;
@@ -2073,6 +2094,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
        if (cur_trans->state >= TRANS_STATE_COMMIT_START) {
                enum btrfs_trans_state want_state = TRANS_STATE_COMPLETED;
 
+               add_pending_snapshot(trans);
+
                spin_unlock(&fs_info->trans_lock);
                refcount_inc(&cur_trans->use_count);
 
@@ -2163,6 +2186,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
         * COMMIT_DOING so make sure to wait for num_writers to == 1 again.
         */
        spin_lock(&fs_info->trans_lock);
+       add_pending_snapshot(trans);
        cur_trans->state = TRANS_STATE_COMMIT_DOING;
        spin_unlock(&fs_info->trans_lock);
        wait_event(cur_trans->writer_wait,
index 1852ed9..9402d8d 100644 (file)
@@ -123,6 +123,8 @@ struct btrfs_trans_handle {
        struct btrfs_transaction *transaction;
        struct btrfs_block_rsv *block_rsv;
        struct btrfs_block_rsv *orig_rsv;
+       /* Set by a task that wants to create a snapshot. */
+       struct btrfs_pending_snapshot *pending_snapshot;
        refcount_t use_count;
        unsigned int type;
        /*
index 72e1c94..9fd145f 100644 (file)
@@ -965,6 +965,7 @@ static int check_dev_item(struct extent_buffer *leaf,
                          struct btrfs_key *key, int slot)
 {
        struct btrfs_dev_item *ditem;
+       const u32 item_size = btrfs_item_size(leaf, slot);
 
        if (unlikely(key->objectid != BTRFS_DEV_ITEMS_OBJECTID)) {
                dev_item_err(leaf, slot,
@@ -972,6 +973,13 @@ static int check_dev_item(struct extent_buffer *leaf,
                             key->objectid, BTRFS_DEV_ITEMS_OBJECTID);
                return -EUCLEAN;
        }
+
+       if (unlikely(item_size != sizeof(*ditem))) {
+               dev_item_err(leaf, slot, "invalid item size: has %u expect %zu",
+                            item_size, sizeof(*ditem));
+               return -EUCLEAN;
+       }
+
        ditem = btrfs_item_ptr(leaf, slot, struct btrfs_dev_item);
        if (unlikely(btrfs_device_id(leaf, ditem) != key->offset)) {
                dev_item_err(leaf, slot,
@@ -1007,6 +1015,7 @@ static int check_inode_item(struct extent_buffer *leaf,
        struct btrfs_inode_item *iitem;
        u64 super_gen = btrfs_super_generation(fs_info->super_copy);
        u32 valid_mask = (S_IFMT | S_ISUID | S_ISGID | S_ISVTX | 0777);
+       const u32 item_size = btrfs_item_size(leaf, slot);
        u32 mode;
        int ret;
        u32 flags;
@@ -1016,6 +1025,12 @@ static int check_inode_item(struct extent_buffer *leaf,
        if (unlikely(ret < 0))
                return ret;
 
+       if (unlikely(item_size != sizeof(*iitem))) {
+               generic_err(leaf, slot, "invalid item size: has %u expect %zu",
+                           item_size, sizeof(*iitem));
+               return -EUCLEAN;
+       }
+
        iitem = btrfs_item_ptr(leaf, slot, struct btrfs_inode_item);
 
        /* Here we use super block generation + 1 to handle log tree */
index c1ddbe8..3ee014c 100644 (file)
@@ -3414,6 +3414,29 @@ static void free_log_tree(struct btrfs_trans_handle *trans,
        if (log->node) {
                ret = walk_log_tree(trans, log, &wc);
                if (ret) {
+                       /*
+                        * We weren't able to traverse the entire log tree, the
+                        * typical scenario is getting an -EIO when reading an
+                        * extent buffer of the tree, due to a previous writeback
+                        * failure of it.
+                        */
+                       set_bit(BTRFS_FS_STATE_LOG_CLEANUP_ERROR,
+                               &log->fs_info->fs_state);
+
+                       /*
+                        * Some extent buffers of the log tree may still be dirty
+                        * and not yet written back to storage, because we may
+                        * have updates to a log tree without syncing a log tree,
+                        * such as during rename and link operations. So flush
+                        * them out and wait for their writeback to complete, so
+                        * that we properly cleanup their state and pages.
+                        */
+                       btrfs_write_marked_extents(log->fs_info,
+                                                  &log->dirty_log_pages,
+                                                  EXTENT_DIRTY | EXTENT_NEW);
+                       btrfs_wait_tree_log_extents(log,
+                                                   EXTENT_DIRTY | EXTENT_NEW);
+
                        if (trans)
                                btrfs_abort_transaction(trans, ret);
                        else
index 04eb527..753986e 100644 (file)
@@ -191,6 +191,64 @@ presubmission_error:
        return ret;
 }
 
+/*
+ * Query the occupancy of the cache in a region, returning where the next chunk
+ * of data starts and how long it is.
+ */
+static int cachefiles_query_occupancy(struct netfs_cache_resources *cres,
+                                     loff_t start, size_t len, size_t granularity,
+                                     loff_t *_data_start, size_t *_data_len)
+{
+       struct cachefiles_object *object;
+       struct file *file;
+       loff_t off, off2;
+
+       *_data_start = -1;
+       *_data_len = 0;
+
+       if (!fscache_wait_for_operation(cres, FSCACHE_WANT_READ))
+               return -ENOBUFS;
+
+       object = cachefiles_cres_object(cres);
+       file = cachefiles_cres_file(cres);
+       granularity = max_t(size_t, object->volume->cache->bsize, granularity);
+
+       _enter("%pD,%li,%llx,%zx/%llx",
+              file, file_inode(file)->i_ino, start, len,
+              i_size_read(file_inode(file)));
+
+       off = cachefiles_inject_read_error();
+       if (off == 0)
+               off = vfs_llseek(file, start, SEEK_DATA);
+       if (off == -ENXIO)
+               return -ENODATA; /* Beyond EOF */
+       if (off < 0 && off >= (loff_t)-MAX_ERRNO)
+               return -ENOBUFS; /* Error. */
+       if (round_up(off, granularity) >= start + len)
+               return -ENODATA; /* No data in range */
+
+       off2 = cachefiles_inject_read_error();
+       if (off2 == 0)
+               off2 = vfs_llseek(file, off, SEEK_HOLE);
+       if (off2 == -ENXIO)
+               return -ENODATA; /* Beyond EOF */
+       if (off2 < 0 && off2 >= (loff_t)-MAX_ERRNO)
+               return -ENOBUFS; /* Error. */
+
+       /* Round away partial blocks */
+       off = round_up(off, granularity);
+       off2 = round_down(off2, granularity);
+       if (off2 <= off)
+               return -ENODATA;
+
+       *_data_start = off;
+       if (off2 > start + len)
+               *_data_len = len;
+       else
+               *_data_len = off2 - off;
+       return 0;
+}
+
 /*
  * Handle completion of a write to the cache.
  */
@@ -545,6 +603,7 @@ static const struct netfs_cache_ops cachefiles_netfs_cache_ops = {
        .write                  = cachefiles_write,
        .prepare_read           = cachefiles_prepare_read,
        .prepare_write          = cachefiles_prepare_write,
+       .query_occupancy        = cachefiles_query_occupancy,
 };
 
 /*
index 7d305b9..b472cd0 100644 (file)
@@ -2218,6 +2218,7 @@ static int unsafe_request_wait(struct inode *inode)
        struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_mds_request *req1 = NULL, *req2 = NULL;
+       unsigned int max_sessions;
        int ret, err = 0;
 
        spin_lock(&ci->i_unsafe_lock);
@@ -2235,37 +2236,45 @@ static int unsafe_request_wait(struct inode *inode)
        }
        spin_unlock(&ci->i_unsafe_lock);
 
+       /*
+        * The mdsc->max_sessions is unlikely to be changed
+        * mostly, here we will retry it by reallocating the
+        * sessions array memory to get rid of the mdsc->mutex
+        * lock.
+        */
+retry:
+       max_sessions = mdsc->max_sessions;
+
        /*
         * Trigger to flush the journal logs in all the relevant MDSes
         * manually, or in the worst case we must wait at most 5 seconds
         * to wait the journal logs to be flushed by the MDSes periodically.
         */
-       if (req1 || req2) {
+       if ((req1 || req2) && likely(max_sessions)) {
                struct ceph_mds_session **sessions = NULL;
                struct ceph_mds_session *s;
                struct ceph_mds_request *req;
-               unsigned int max;
                int i;
 
-               /*
-                * The mdsc->max_sessions is unlikely to be changed
-                * mostly, here we will retry it by reallocating the
-                * sessions arrary memory to get rid of the mdsc->mutex
-                * lock.
-                */
-retry:
-               max = mdsc->max_sessions;
-               sessions = krealloc(sessions, max * sizeof(s), __GFP_ZERO);
-               if (!sessions)
-                       return -ENOMEM;
+               sessions = kzalloc(max_sessions * sizeof(s), GFP_KERNEL);
+               if (!sessions) {
+                       err = -ENOMEM;
+                       goto out;
+               }
 
                spin_lock(&ci->i_unsafe_lock);
                if (req1) {
                        list_for_each_entry(req, &ci->i_unsafe_dirops,
                                            r_unsafe_dir_item) {
                                s = req->r_session;
-                               if (unlikely(s->s_mds >= max)) {
+                               if (unlikely(s->s_mds >= max_sessions)) {
                                        spin_unlock(&ci->i_unsafe_lock);
+                                       for (i = 0; i < max_sessions; i++) {
+                                               s = sessions[i];
+                                               if (s)
+                                                       ceph_put_mds_session(s);
+                                       }
+                                       kfree(sessions);
                                        goto retry;
                                }
                                if (!sessions[s->s_mds]) {
@@ -2278,8 +2287,14 @@ retry:
                        list_for_each_entry(req, &ci->i_unsafe_iops,
                                            r_unsafe_target_item) {
                                s = req->r_session;
-                               if (unlikely(s->s_mds >= max)) {
+                               if (unlikely(s->s_mds >= max_sessions)) {
                                        spin_unlock(&ci->i_unsafe_lock);
+                                       for (i = 0; i < max_sessions; i++) {
+                                               s = sessions[i];
+                                               if (s)
+                                                       ceph_put_mds_session(s);
+                                       }
+                                       kfree(sessions);
                                        goto retry;
                                }
                                if (!sessions[s->s_mds]) {
@@ -2300,7 +2315,7 @@ retry:
                spin_unlock(&ci->i_ceph_lock);
 
                /* send flush mdlog request to MDSes */
-               for (i = 0; i < max; i++) {
+               for (i = 0; i < max_sessions; i++) {
                        s = sessions[i];
                        if (s) {
                                send_flush_mdlog(s);
@@ -2317,15 +2332,19 @@ retry:
                                        ceph_timeout_jiffies(req1->r_timeout));
                if (ret)
                        err = -EIO;
-               ceph_mdsc_put_request(req1);
        }
        if (req2) {
                ret = !wait_for_completion_timeout(&req2->r_safe_completion,
                                        ceph_timeout_jiffies(req2->r_timeout));
                if (ret)
                        err = -EIO;
-               ceph_mdsc_put_request(req2);
        }
+
+out:
+       if (req1)
+               ceph_mdsc_put_request(req1);
+       if (req2)
+               ceph_mdsc_put_request(req2);
        return err;
 }
 
index 5b9104b..bbed322 100644 (file)
@@ -583,6 +583,7 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,
        struct ceph_inode_info *ci = ceph_inode(dir);
        struct inode *inode;
        struct timespec64 now;
+       struct ceph_string *pool_ns;
        struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb);
        struct ceph_vino vino = { .ino = req->r_deleg_ino,
                                  .snap = CEPH_NOSNAP };
@@ -632,6 +633,12 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,
        in.max_size = cpu_to_le64(lo->stripe_unit);
 
        ceph_file_layout_to_legacy(lo, &in.layout);
+       /* lo is private, so pool_ns can't change */
+       pool_ns = rcu_dereference_raw(lo->pool_ns);
+       if (pool_ns) {
+               iinfo.pool_ns_len = pool_ns->len;
+               iinfo.pool_ns_data = pool_ns->str;
+       }
 
        down_read(&mdsc->snap_rwsem);
        ret = ceph_fill_inode(inode, NULL, &iinfo, NULL, req->r_session,
@@ -750,8 +757,10 @@ retry:
                                restore_deleg_ino(dir, req->r_deleg_ino);
                                ceph_mdsc_put_request(req);
                                try_async = false;
+                               ceph_put_string(rcu_dereference_raw(lo.pool_ns));
                                goto retry;
                        }
+                       ceph_put_string(rcu_dereference_raw(lo.pool_ns));
                        goto out_req;
                }
        }
index 463ebe3..cdce160 100644 (file)
@@ -396,11 +396,11 @@ static int cifs_swn_resource_state_changed(struct cifs_swn_reg *swnreg, const ch
        switch (state) {
        case CIFS_SWN_RESOURCE_STATE_UNAVAILABLE:
                cifs_dbg(FYI, "%s: resource name '%s' become unavailable\n", __func__, name);
-               cifs_reconnect(swnreg->tcon->ses->server, true);
+               cifs_mark_tcp_ses_conns_for_reconnect(swnreg->tcon->ses->server, true);
                break;
        case CIFS_SWN_RESOURCE_STATE_AVAILABLE:
                cifs_dbg(FYI, "%s: resource name '%s' become available\n", __func__, name);
-               cifs_reconnect(swnreg->tcon->ses->server, true);
+               cifs_mark_tcp_ses_conns_for_reconnect(swnreg->tcon->ses->server, true);
                break;
        case CIFS_SWN_RESOURCE_STATE_UNKNOWN:
                cifs_dbg(FYI, "%s: resource name '%s' changed to unknown state\n", __func__, name);
@@ -498,7 +498,7 @@ static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *a
                goto unlock;
        }
 
-       cifs_reconnect(tcon->ses->server, false);
+       cifs_mark_tcp_ses_conns_for_reconnect(tcon->ses->server, false);
 
 unlock:
        mutex_unlock(&tcon->ses->server->srv_mutex);
index 11a22a3..053cb44 100644 (file)
@@ -162,7 +162,7 @@ static void cifs_resolve_server(struct work_struct *work)
        mutex_unlock(&server->srv_mutex);
 }
 
-/**
+/*
  * Mark all sessions and tcons for reconnect.
  *
  * @server needs to be previously set to CifsNeedReconnect.
@@ -175,11 +175,6 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
        struct TCP_Server_Info *pserver;
        struct cifs_ses *ses;
        struct cifs_tcon *tcon;
-       struct mid_q_entry *mid, *nmid;
-       struct list_head retry_list;
-
-       server->maxBuf = 0;
-       server->max_read = 0;
 
        /*
         * before reconnecting the tcp session, mark the smb session (uid) and the tid bad so they
@@ -219,6 +214,16 @@ next_session:
                spin_unlock(&ses->chan_lock);
        }
        spin_unlock(&cifs_tcp_ses_lock);
+}
+
+static void
+cifs_abort_connection(struct TCP_Server_Info *server)
+{
+       struct mid_q_entry *mid, *nmid;
+       struct list_head retry_list;
+
+       server->maxBuf = 0;
+       server->max_read = 0;
 
        /* do not want to be sending data on a socket we are freeing */
        cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
@@ -310,6 +315,8 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
 
        cifs_mark_tcp_ses_conns_for_reconnect(server, mark_smb_session);
 
+       cifs_abort_connection(server);
+
        do {
                try_to_freeze();
                mutex_lock(&server->srv_mutex);
@@ -434,6 +441,8 @@ reconnect_dfs_server(struct TCP_Server_Info *server,
 
        cifs_mark_tcp_ses_conns_for_reconnect(server, mark_smb_session);
 
+       cifs_abort_connection(server);
+
        do {
                try_to_freeze();
                mutex_lock(&server->srv_mutex);
@@ -639,6 +648,7 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
 
                if (server->tcpStatus == CifsNeedReconnect) {
                        spin_unlock(&cifs_tcp_ses_lock);
+                       cifs_reconnect(server, false);
                        return -ECONNABORTED;
                }
                spin_unlock(&cifs_tcp_ses_lock);
@@ -1831,13 +1841,9 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
                int i;
 
                for (i = 1; i < chan_count; i++) {
-                       /*
-                        * note: for now, we're okay accessing ses->chans
-                        * without chan_lock. But when chans can go away, we'll
-                        * need to introduce ref counting to make sure that chan
-                        * is not freed from under us.
-                        */
+                       spin_unlock(&ses->chan_lock);
                        cifs_put_tcp_session(ses->chans[i].server, 0);
+                       spin_lock(&ses->chan_lock);
                        ses->chans[i].server = NULL;
                }
        }
@@ -1981,6 +1987,19 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
                }
        }
 
+       ctx->workstation_name = kstrdup(ses->workstation_name, GFP_KERNEL);
+       if (!ctx->workstation_name) {
+               cifs_dbg(FYI, "Unable to allocate memory for workstation_name\n");
+               rc = -ENOMEM;
+               kfree(ctx->username);
+               ctx->username = NULL;
+               kfree_sensitive(ctx->password);
+               ctx->password = NULL;
+               kfree(ctx->domainname);
+               ctx->domainname = NULL;
+               goto out_key_put;
+       }
+
 out_key_put:
        up_read(&key->sem);
        key_put(key);
@@ -2331,10 +2350,19 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
                if (ses->server->posix_ext_supported) {
                        tcon->posix_extensions = true;
                        pr_warn_once("SMB3.11 POSIX Extensions are experimental\n");
-               } else {
+               } else if ((ses->server->vals->protocol_id == SMB311_PROT_ID) ||
+                   (strcmp(ses->server->vals->version_string,
+                    SMB3ANY_VERSION_STRING) == 0) ||
+                   (strcmp(ses->server->vals->version_string,
+                    SMBDEFAULT_VERSION_STRING) == 0)) {
                        cifs_dbg(VFS, "Server does not support mounting with posix SMB3.11 extensions\n");
                        rc = -EOPNOTSUPP;
                        goto out_fail;
+               } else {
+                       cifs_dbg(VFS, "Check vers= mount option. SMB3.11 "
+                               "disabled but required for POSIX extensions\n");
+                       rc = -EOPNOTSUPP;
+                       goto out_fail;
                }
        }
 
index dd96437..831f424 100644 (file)
@@ -1355,7 +1355,7 @@ static void mark_for_reconnect_if_needed(struct cifs_tcon *tcon, struct dfs_cach
        }
 
        cifs_dbg(FYI, "%s: no cached or matched targets. mark dfs share for reconnect.\n", __func__);
-       cifs_reconnect(tcon->ses->server, true);
+       cifs_mark_tcp_ses_conns_for_reconnect(tcon->ses->server, true);
 }
 
 /* Refresh dfs referral of tcon and mark it for reconnect if needed */
index 59334be..e7af802 100644 (file)
@@ -4269,8 +4269,6 @@ cifs_readv_complete(struct work_struct *work)
        for (i = 0; i < rdata->nr_pages; i++) {
                struct page *page = rdata->pages[i];
 
-               lru_cache_add(page);
-
                if (rdata->result == 0 ||
                    (rdata->result == -EAGAIN && got_bytes)) {
                        flush_dcache_page(page);
@@ -4278,12 +4276,12 @@ cifs_readv_complete(struct work_struct *work)
                } else
                        SetPageError(page);
 
-               unlock_page(page);
-
                if (rdata->result == 0 ||
                    (rdata->result == -EAGAIN && got_bytes))
                        cifs_readpage_to_fscache(rdata->mapping->host, page);
 
+               unlock_page(page);
+
                got_bytes -= min_t(unsigned int, PAGE_SIZE, got_bytes);
 
                put_page(page);
@@ -4340,7 +4338,6 @@ readpages_fill_pages(struct TCP_Server_Info *server,
                         * fill them until the writes are flushed.
                         */
                        zero_user(page, 0, PAGE_SIZE);
-                       lru_cache_add(page);
                        flush_dcache_page(page);
                        SetPageUptodate(page);
                        unlock_page(page);
@@ -4350,7 +4347,6 @@ readpages_fill_pages(struct TCP_Server_Info *server,
                        continue;
                } else {
                        /* no need to hold page hostage */
-                       lru_cache_add(page);
                        unlock_page(page);
                        put_page(page);
                        rdata->pages[i] = NULL;
@@ -4393,92 +4389,20 @@ cifs_readpages_copy_into_pages(struct TCP_Server_Info *server,
        return readpages_fill_pages(server, rdata, iter, iter->count);
 }
 
-static int
-readpages_get_pages(struct address_space *mapping, struct list_head *page_list,
-                   unsigned int rsize, struct list_head *tmplist,
-                   unsigned int *nr_pages, loff_t *offset, unsigned int *bytes)
-{
-       struct page *page, *tpage;
-       unsigned int expected_index;
-       int rc;
-       gfp_t gfp = readahead_gfp_mask(mapping);
-
-       INIT_LIST_HEAD(tmplist);
-
-       page = lru_to_page(page_list);
-
-       /*
-        * Lock the page and put it in the cache. Since no one else
-        * should have access to this page, we're safe to simply set
-        * PG_locked without checking it first.
-        */
-       __SetPageLocked(page);
-       rc = add_to_page_cache_locked(page, mapping,
-                                     page->index, gfp);
-
-       /* give up if we can't stick it in the cache */
-       if (rc) {
-               __ClearPageLocked(page);
-               return rc;
-       }
-
-       /* move first page to the tmplist */
-       *offset = (loff_t)page->index << PAGE_SHIFT;
-       *bytes = PAGE_SIZE;
-       *nr_pages = 1;
-       list_move_tail(&page->lru, tmplist);
-
-       /* now try and add more pages onto the request */
-       expected_index = page->index + 1;
-       list_for_each_entry_safe_reverse(page, tpage, page_list, lru) {
-               /* discontinuity ? */
-               if (page->index != expected_index)
-                       break;
-
-               /* would this page push the read over the rsize? */
-               if (*bytes + PAGE_SIZE > rsize)
-                       break;
-
-               __SetPageLocked(page);
-               rc = add_to_page_cache_locked(page, mapping, page->index, gfp);
-               if (rc) {
-                       __ClearPageLocked(page);
-                       break;
-               }
-               list_move_tail(&page->lru, tmplist);
-               (*bytes) += PAGE_SIZE;
-               expected_index++;
-               (*nr_pages)++;
-       }
-       return rc;
-}
-
-static int cifs_readpages(struct file *file, struct address_space *mapping,
-       struct list_head *page_list, unsigned num_pages)
+static void cifs_readahead(struct readahead_control *ractl)
 {
        int rc;
-       int err = 0;
-       struct list_head tmplist;
-       struct cifsFileInfo *open_file = file->private_data;
-       struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
+       struct cifsFileInfo *open_file = ractl->file->private_data;
+       struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(ractl->file);
        struct TCP_Server_Info *server;
        pid_t pid;
-       unsigned int xid;
+       unsigned int xid, nr_pages, last_batch_size = 0, cache_nr_pages = 0;
+       pgoff_t next_cached = ULONG_MAX;
+       bool caching = fscache_cookie_enabled(cifs_inode_cookie(ractl->mapping->host)) &&
+               cifs_inode_cookie(ractl->mapping->host)->cache_priv;
+       bool check_cache = caching;
 
        xid = get_xid();
-       /*
-        * Reads as many pages as possible from fscache. Returns -ENOBUFS
-        * immediately if the cookie is negative
-        *
-        * After this point, every page in the list might have PG_fscache set,
-        * so we will need to clean that up off of every page we don't use.
-        */
-       rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
-                                        &num_pages);
-       if (rc == 0) {
-               free_xid(xid);
-               return rc;
-       }
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
                pid = open_file->pid;
@@ -4489,39 +4413,73 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
        server = cifs_pick_channel(tlink_tcon(open_file->tlink)->ses);
 
        cifs_dbg(FYI, "%s: file=%p mapping=%p num_pages=%u\n",
-                __func__, file, mapping, num_pages);
+                __func__, ractl->file, ractl->mapping, readahead_count(ractl));
 
        /*
-        * Start with the page at end of list and move it to private
-        * list. Do the same with any following pages until we hit
-        * the rsize limit, hit an index discontinuity, or run out of
-        * pages. Issue the async read and then start the loop again
-        * until the list is empty.
-        *
-        * Note that list order is important. The page_list is in
-        * the order of declining indexes. When we put the pages in
-        * the rdata->pages, then we want them in increasing order.
+        * Chop the readahead request up into rsize-sized read requests.
         */
-       while (!list_empty(page_list) && !err) {
-               unsigned int i, nr_pages, bytes, rsize;
-               loff_t offset;
-               struct page *page, *tpage;
+       while ((nr_pages = readahead_count(ractl) - last_batch_size)) {
+               unsigned int i, got, rsize;
+               struct page *page;
                struct cifs_readdata *rdata;
                struct cifs_credits credits_on_stack;
                struct cifs_credits *credits = &credits_on_stack;
+               pgoff_t index = readahead_index(ractl) + last_batch_size;
+
+               /*
+                * Find out if we have anything cached in the range of
+                * interest, and if so, where the next chunk of cached data is.
+                */
+               if (caching) {
+                       if (check_cache) {
+                               rc = cifs_fscache_query_occupancy(
+                                       ractl->mapping->host, index, nr_pages,
+                                       &next_cached, &cache_nr_pages);
+                               if (rc < 0)
+                                       caching = false;
+                               check_cache = false;
+                       }
+
+                       if (index == next_cached) {
+                               /*
+                                * TODO: Send a whole batch of pages to be read
+                                * by the cache.
+                                */
+                               page = readahead_page(ractl);
+                               last_batch_size = 1 << thp_order(page);
+                               if (cifs_readpage_from_fscache(ractl->mapping->host,
+                                                              page) < 0) {
+                                       /*
+                                        * TODO: Deal with cache read failure
+                                        * here, but for the moment, delegate
+                                        * that to readpage.
+                                        */
+                                       caching = false;
+                               }
+                               unlock_page(page);
+                               next_cached++;
+                               cache_nr_pages--;
+                               if (cache_nr_pages == 0)
+                                       check_cache = true;
+                               continue;
+                       }
+               }
 
                if (open_file->invalidHandle) {
                        rc = cifs_reopen_file(open_file, true);
-                       if (rc == -EAGAIN)
-                               continue;
-                       else if (rc)
+                       if (rc) {
+                               if (rc == -EAGAIN)
+                                       continue;
                                break;
+                       }
                }
 
                rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize,
                                                   &rsize, credits);
                if (rc)
                        break;
+               nr_pages = min_t(size_t, rsize / PAGE_SIZE, readahead_count(ractl));
+               nr_pages = min_t(size_t, nr_pages, next_cached - index);
 
                /*
                 * Give up immediately if rsize is too small to read an entire
@@ -4529,16 +4487,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                 * reach this point however since we set ra_pages to 0 when the
                 * rsize is smaller than a cache page.
                 */
-               if (unlikely(rsize < PAGE_SIZE)) {
-                       add_credits_and_wake_if(server, credits, 0);
-                       free_xid(xid);
-                       return 0;
-               }
-
-               nr_pages = 0;
-               err = readpages_get_pages(mapping, page_list, rsize, &tmplist,
-                                        &nr_pages, &offset, &bytes);
-               if (!nr_pages) {
+               if (unlikely(!nr_pages)) {
                        add_credits_and_wake_if(server, credits, 0);
                        break;
                }
@@ -4546,36 +4495,31 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                rdata = cifs_readdata_alloc(nr_pages, cifs_readv_complete);
                if (!rdata) {
                        /* best to give up if we're out of mem */
-                       list_for_each_entry_safe(page, tpage, &tmplist, lru) {
-                               list_del(&page->lru);
-                               lru_cache_add(page);
-                               unlock_page(page);
-                               put_page(page);
-                       }
-                       rc = -ENOMEM;
                        add_credits_and_wake_if(server, credits, 0);
                        break;
                }
 
-               rdata->cfile = cifsFileInfo_get(open_file);
-               rdata->server = server;
-               rdata->mapping = mapping;
-               rdata->offset = offset;
-               rdata->bytes = bytes;
-               rdata->pid = pid;
-               rdata->pagesz = PAGE_SIZE;
-               rdata->tailsz = PAGE_SIZE;
+               got = __readahead_batch(ractl, rdata->pages, nr_pages);
+               if (got != nr_pages) {
+                       pr_warn("__readahead_batch() returned %u/%u\n",
+                               got, nr_pages);
+                       nr_pages = got;
+               }
+
+               rdata->nr_pages = nr_pages;
+               rdata->bytes    = readahead_batch_length(ractl);
+               rdata->cfile    = cifsFileInfo_get(open_file);
+               rdata->server   = server;
+               rdata->mapping  = ractl->mapping;
+               rdata->offset   = readahead_pos(ractl);
+               rdata->pid      = pid;
+               rdata->pagesz   = PAGE_SIZE;
+               rdata->tailsz   = PAGE_SIZE;
                rdata->read_into_pages = cifs_readpages_read_into_pages;
                rdata->copy_into_pages = cifs_readpages_copy_into_pages;
-               rdata->credits = credits_on_stack;
-
-               list_for_each_entry_safe(page, tpage, &tmplist, lru) {
-                       list_del(&page->lru);
-                       rdata->pages[rdata->nr_pages++] = page;
-               }
+               rdata->credits  = credits_on_stack;
 
                rc = adjust_credits(server, &rdata->credits, rdata->bytes);
-
                if (!rc) {
                        if (rdata->cfile->invalidHandle)
                                rc = -EAGAIN;
@@ -4587,7 +4531,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                        add_credits_and_wake_if(server, &rdata->credits, 0);
                        for (i = 0; i < rdata->nr_pages; i++) {
                                page = rdata->pages[i];
-                               lru_cache_add(page);
                                unlock_page(page);
                                put_page(page);
                        }
@@ -4597,10 +4540,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                }
 
                kref_put(&rdata->refcount, cifs_readdata_release);
+               last_batch_size = nr_pages;
        }
 
        free_xid(xid);
-       return rc;
 }
 
 /*
@@ -4924,7 +4867,7 @@ oplock_break_done:
  * In the non-cached mode (mount with cache=none), we shunt off direct read and write requests
  * so this method should never be called.
  *
- * Direct IO is not yet supported in the cached mode. 
+ * Direct IO is not yet supported in the cached mode.
  */
 static ssize_t
 cifs_direct_io(struct kiocb *iocb, struct iov_iter *iter)
@@ -5006,7 +4949,7 @@ static int cifs_set_page_dirty(struct page *page)
 
 const struct address_space_operations cifs_addr_ops = {
        .readpage = cifs_readpage,
-       .readpages = cifs_readpages,
+       .readahead = cifs_readahead,
        .writepage = cifs_writepage,
        .writepages = cifs_writepages,
        .write_begin = cifs_write_begin,
index efaac4d..33af72e 100644 (file)
@@ -134,37 +134,127 @@ void cifs_fscache_release_inode_cookie(struct inode *inode)
        }
 }
 
+static inline void fscache_end_operation(struct netfs_cache_resources *cres)
+{
+       const struct netfs_cache_ops *ops = fscache_operation_valid(cres);
+
+       if (ops)
+               ops->end_operation(cres);
+}
+
 /*
- * Retrieve a page from FS-Cache
+ * Fallback page reading interface.
  */
-int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
+static int fscache_fallback_read_page(struct inode *inode, struct page *page)
 {
-       cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n",
-                __func__, CIFS_I(inode)->fscache, page, inode);
-       return -ENOBUFS; // Needs conversion to using netfslib
+       struct netfs_cache_resources cres;
+       struct fscache_cookie *cookie = cifs_inode_cookie(inode);
+       struct iov_iter iter;
+       struct bio_vec bvec[1];
+       int ret;
+
+       memset(&cres, 0, sizeof(cres));
+       bvec[0].bv_page         = page;
+       bvec[0].bv_offset       = 0;
+       bvec[0].bv_len          = PAGE_SIZE;
+       iov_iter_bvec(&iter, READ, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
+
+       ret = fscache_begin_read_operation(&cres, cookie);
+       if (ret < 0)
+               return ret;
+
+       ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL,
+                          NULL, NULL);
+       fscache_end_operation(&cres);
+       return ret;
 }
 
 /*
- * Retrieve a set of pages from FS-Cache
+ * Fallback page writing interface.
  */
-int __cifs_readpages_from_fscache(struct inode *inode,
-                               struct address_space *mapping,
-                               struct list_head *pages,
-                               unsigned *nr_pages)
+static int fscache_fallback_write_page(struct inode *inode, struct page *page,
+                                      bool no_space_allocated_yet)
 {
-       cifs_dbg(FYI, "%s: (0x%p/%u/0x%p)\n",
-                __func__, CIFS_I(inode)->fscache, *nr_pages, inode);
-       return -ENOBUFS; // Needs conversion to using netfslib
+       struct netfs_cache_resources cres;
+       struct fscache_cookie *cookie = cifs_inode_cookie(inode);
+       struct iov_iter iter;
+       struct bio_vec bvec[1];
+       loff_t start = page_offset(page);
+       size_t len = PAGE_SIZE;
+       int ret;
+
+       memset(&cres, 0, sizeof(cres));
+       bvec[0].bv_page         = page;
+       bvec[0].bv_offset       = 0;
+       bvec[0].bv_len          = PAGE_SIZE;
+       iov_iter_bvec(&iter, WRITE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
+
+       ret = fscache_begin_write_operation(&cres, cookie);
+       if (ret < 0)
+               return ret;
+
+       ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode),
+                                     no_space_allocated_yet);
+       if (ret == 0)
+               ret = fscache_write(&cres, page_offset(page), &iter, NULL, NULL);
+       fscache_end_operation(&cres);
+       return ret;
 }
 
-void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
+/*
+ * Retrieve a page from FS-Cache
+ */
+int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
 {
-       struct cifsInodeInfo *cifsi = CIFS_I(inode);
+       int ret;
 
-       WARN_ON(!cifsi->fscache);
+       cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n",
+                __func__, cifs_inode_cookie(inode), page, inode);
 
+       ret = fscache_fallback_read_page(inode, page);
+       if (ret < 0)
+               return ret;
+
+       /* Read completed synchronously */
+       SetPageUptodate(page);
+       return 0;
+}
+
+void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
+{
        cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)\n",
-                __func__, cifsi->fscache, page, inode);
+                __func__, cifs_inode_cookie(inode), page, inode);
+
+       fscache_fallback_write_page(inode, page, true);
+}
+
+/*
+ * Query the cache occupancy.
+ */
+int __cifs_fscache_query_occupancy(struct inode *inode,
+                                  pgoff_t first, unsigned int nr_pages,
+                                  pgoff_t *_data_first,
+                                  unsigned int *_data_nr_pages)
+{
+       struct netfs_cache_resources cres;
+       struct fscache_cookie *cookie = cifs_inode_cookie(inode);
+       loff_t start, data_start;
+       size_t len, data_len;
+       int ret;
 
-       // Needs conversion to using netfslib
+       ret = fscache_begin_read_operation(&cres, cookie);
+       if (ret < 0)
+               return ret;
+
+       start = first * PAGE_SIZE;
+       len = nr_pages * PAGE_SIZE;
+       ret = cres.ops->query_occupancy(&cres, start, len, PAGE_SIZE,
+                                       &data_start, &data_len);
+       if (ret == 0) {
+               *_data_first = data_start / PAGE_SIZE;
+               *_data_nr_pages = len / PAGE_SIZE;
+       }
+
+       fscache_end_operation(&cres);
+       return ret;
 }
index c6ca49a..5512990 100644 (file)
@@ -9,6 +9,7 @@
 #ifndef _CIFS_FSCACHE_H
 #define _CIFS_FSCACHE_H
 
+#include <linux/swap.h>
 #include <linux/fscache.h>
 
 #include "cifsglob.h"
@@ -58,14 +59,6 @@ void cifs_fscache_fill_coherency(struct inode *inode,
 }
 
 
-extern int cifs_fscache_release_page(struct page *page, gfp_t gfp);
-extern int __cifs_readpage_from_fscache(struct inode *, struct page *);
-extern int __cifs_readpages_from_fscache(struct inode *,
-                                        struct address_space *,
-                                        struct list_head *,
-                                        unsigned *);
-extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
-
 static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode)
 {
        return CIFS_I(inode)->fscache;
@@ -80,33 +73,52 @@ static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags
                           i_size_read(inode), flags);
 }
 
-static inline int cifs_readpage_from_fscache(struct inode *inode,
-                                            struct page *page)
-{
-       if (CIFS_I(inode)->fscache)
-               return __cifs_readpage_from_fscache(inode, page);
+extern int __cifs_fscache_query_occupancy(struct inode *inode,
+                                         pgoff_t first, unsigned int nr_pages,
+                                         pgoff_t *_data_first,
+                                         unsigned int *_data_nr_pages);
 
-       return -ENOBUFS;
+static inline int cifs_fscache_query_occupancy(struct inode *inode,
+                                              pgoff_t first, unsigned int nr_pages,
+                                              pgoff_t *_data_first,
+                                              unsigned int *_data_nr_pages)
+{
+       if (!cifs_inode_cookie(inode))
+               return -ENOBUFS;
+       return __cifs_fscache_query_occupancy(inode, first, nr_pages,
+                                             _data_first, _data_nr_pages);
 }
 
-static inline int cifs_readpages_from_fscache(struct inode *inode,
-                                             struct address_space *mapping,
-                                             struct list_head *pages,
-                                             unsigned *nr_pages)
+extern int __cifs_readpage_from_fscache(struct inode *pinode, struct page *ppage);
+extern void __cifs_readpage_to_fscache(struct inode *pinode, struct page *ppage);
+
+
+static inline int cifs_readpage_from_fscache(struct inode *inode,
+                                            struct page *page)
 {
-       if (CIFS_I(inode)->fscache)
-               return __cifs_readpages_from_fscache(inode, mapping, pages,
-                                                    nr_pages);
+       if (cifs_inode_cookie(inode))
+               return __cifs_readpage_from_fscache(inode, page);
        return -ENOBUFS;
 }
 
 static inline void cifs_readpage_to_fscache(struct inode *inode,
                                            struct page *page)
 {
-       if (PageFsCache(page))
+       if (cifs_inode_cookie(inode))
                __cifs_readpage_to_fscache(inode, page);
 }
 
+static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp)
+{
+       if (PageFsCache(page)) {
+               if (current_is_kswapd() || !(gfp & __GFP_FS))
+                       return false;
+               wait_on_page_fscache(page);
+               fscache_note_page_release(cifs_inode_cookie(page->mapping->host));
+       }
+       return true;
+}
+
 #else /* CONFIG_CIFS_FSCACHE */
 static inline
 void cifs_fscache_fill_coherency(struct inode *inode,
@@ -123,22 +135,29 @@ static inline void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool upd
 static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) { return NULL; }
 static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags) {}
 
-static inline int
-cifs_readpage_from_fscache(struct inode *inode, struct page *page)
+static inline int cifs_fscache_query_occupancy(struct inode *inode,
+                                              pgoff_t first, unsigned int nr_pages,
+                                              pgoff_t *_data_first,
+                                              unsigned int *_data_nr_pages)
 {
+       *_data_first = ULONG_MAX;
+       *_data_nr_pages = 0;
        return -ENOBUFS;
 }
 
-static inline int cifs_readpages_from_fscache(struct inode *inode,
-                                             struct address_space *mapping,
-                                             struct list_head *pages,
-                                             unsigned *nr_pages)
+static inline int
+cifs_readpage_from_fscache(struct inode *inode, struct page *page)
 {
        return -ENOBUFS;
 }
 
-static inline void cifs_readpage_to_fscache(struct inode *inode,
-                       struct page *page) {}
+static inline
+void cifs_readpage_to_fscache(struct inode *inode, struct page *page) {}
+
+static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
+{
+       return true; /* May release page */
+}
 
 #endif /* CONFIG_CIFS_FSCACHE */
 
index 7d8b3ce..60d853c 100644 (file)
@@ -83,6 +83,7 @@ static void cifs_set_ops(struct inode *inode)
 static void
 cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
 {
+       struct cifs_fscache_inode_coherency_data cd;
        struct cifsInodeInfo *cifs_i = CIFS_I(inode);
 
        cifs_dbg(FYI, "%s: revalidating inode %llu\n",
@@ -113,6 +114,9 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
        cifs_dbg(FYI, "%s: invalidating inode %llu mapping\n",
                 __func__, cifs_i->uniqueid);
        set_bit(CIFS_INO_INVALID_MAPPING, &cifs_i->flags);
+       /* Invalidate fscache cookie */
+       cifs_fscache_fill_coherency(&cifs_i->vfs_inode, &cd);
+       fscache_invalidate(cifs_inode_cookie(inode), &cd, i_size_read(inode), 0);
 }
 
 /*
@@ -2261,8 +2265,6 @@ cifs_dentry_needs_reval(struct dentry *dentry)
 int
 cifs_invalidate_mapping(struct inode *inode)
 {
-       struct cifs_fscache_inode_coherency_data cd;
-       struct cifsInodeInfo *cifsi = CIFS_I(inode);
        int rc = 0;
 
        if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
@@ -2272,8 +2274,6 @@ cifs_invalidate_mapping(struct inode *inode)
                                 __func__, inode);
        }
 
-       cifs_fscache_fill_coherency(&cifsi->vfs_inode, &cd);
-       fscache_invalidate(cifs_inode_cookie(inode), &cd, i_size_read(inode), 0);
        return rc;
 }
 
index dc3b16d..5723d50 100644 (file)
@@ -713,7 +713,11 @@ static int size_of_ntlmssp_blob(struct cifs_ses *ses, int base_size)
        else
                sz += sizeof(__le16);
 
-       sz += sizeof(__le16) * strnlen(ses->workstation_name, CIFS_MAX_WORKSTATION_LEN);
+       if (ses->workstation_name)
+               sz += sizeof(__le16) * strnlen(ses->workstation_name,
+                       CIFS_MAX_WORKSTATION_LEN);
+       else
+               sz += sizeof(__le16);
 
        return sz;
 }
index 8272c91..b2fb7bd 100644 (file)
@@ -228,9 +228,7 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
        spin_unlock(&GlobalMid_Lock);
 
        if (reconnect) {
-               spin_lock(&cifs_tcp_ses_lock);
-               server->tcpStatus = CifsNeedReconnect;
-               spin_unlock(&cifs_tcp_ses_lock);
+               cifs_mark_tcp_ses_conns_for_reconnect(server, false);
        }
 
        return mid;
index 8540f7c..a4c3e02 100644 (file)
@@ -430,10 +430,7 @@ unmask:
                 * be taken as the remainder of this one. We need to kill the
                 * socket so the server throws away the partial SMB
                 */
-               spin_lock(&cifs_tcp_ses_lock);
-               if (server->tcpStatus != CifsExiting)
-                       server->tcpStatus = CifsNeedReconnect;
-               spin_unlock(&cifs_tcp_ses_lock);
+               cifs_mark_tcp_ses_conns_for_reconnect(server, false);
                trace_smb3_partial_send_reconnect(server->CurrentMid,
                                                  server->conn_id, server->hostname);
        }
index 1466b5d..d3cd2a9 100644 (file)
@@ -1780,8 +1780,8 @@ void configfs_unregister_group(struct config_group *group)
        configfs_detach_group(&group->cg_item);
        d_inode(dentry)->i_flags |= S_DEAD;
        dont_mount(dentry);
+       d_drop(dentry);
        fsnotify_rmdir(d_inode(parent), dentry);
-       d_delete(dentry);
        inode_unlock(d_inode(parent));
 
        dput(dentry);
@@ -1922,10 +1922,10 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
        configfs_detach_group(&group->cg_item);
        d_inode(dentry)->i_flags |= S_DEAD;
        dont_mount(dentry);
-       fsnotify_rmdir(d_inode(root), dentry);
        inode_unlock(d_inode(dentry));
 
-       d_delete(dentry);
+       d_drop(dentry);
+       fsnotify_rmdir(d_inode(root), dentry);
 
        inode_unlock(d_inode(root));
 
index 42e5a76..4f25015 100644 (file)
@@ -621,8 +621,8 @@ void devpts_pty_kill(struct dentry *dentry)
 
        dentry->d_fsdata = NULL;
        drop_nlink(dentry->d_inode);
-       fsnotify_unlink(d_inode(dentry->d_parent), dentry);
        d_drop(dentry);
+       fsnotify_unlink(d_inode(dentry->d_parent), dentry);
        dput(dentry);   /* d_alloc_name() in devpts_pty_new() */
 }
 
index fa7ddb7..226a57c 100644 (file)
@@ -252,12 +252,10 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
                return ret;
 
        iomap->offset = map.m_la;
-       if (flags & IOMAP_DAX) {
+       if (flags & IOMAP_DAX)
                iomap->dax_dev = mdev.m_daxdev;
-               iomap->offset += mdev.m_dax_part_off;
-       } else {
+       else
                iomap->bdev = mdev.m_bdev;
-       }
        iomap->length = map.m_llen;
        iomap->flags = 0;
        iomap->private = NULL;
@@ -284,6 +282,8 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
        } else {
                iomap->type = IOMAP_MAPPED;
                iomap->addr = mdev.m_pa;
+               if (flags & IOMAP_DAX)
+                       iomap->addr += mdev.m_dax_part_off;
        }
        return 0;
 }
index 498b766..423bc1a 100644 (file)
@@ -810,68 +810,11 @@ static bool z_erofs_get_sync_decompress_policy(struct erofs_sb_info *sbi,
        return false;
 }
 
-static void z_erofs_decompressqueue_work(struct work_struct *work);
-static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
-                                      bool sync, int bios)
-{
-       struct erofs_sb_info *const sbi = EROFS_SB(io->sb);
-
-       /* wake up the caller thread for sync decompression */
-       if (sync) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&io->u.wait.lock, flags);
-               if (!atomic_add_return(bios, &io->pending_bios))
-                       wake_up_locked(&io->u.wait);
-               spin_unlock_irqrestore(&io->u.wait.lock, flags);
-               return;
-       }
-
-       if (atomic_add_return(bios, &io->pending_bios))
-               return;
-       /* Use workqueue and sync decompression for atomic contexts only */
-       if (in_atomic() || irqs_disabled()) {
-               queue_work(z_erofs_workqueue, &io->u.work);
-               /* enable sync decompression for readahead */
-               if (sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO)
-                       sbi->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON;
-               return;
-       }
-       z_erofs_decompressqueue_work(&io->u.work);
-}
-
 static bool z_erofs_page_is_invalidated(struct page *page)
 {
        return !page->mapping && !z_erofs_is_shortlived_page(page);
 }
 
-static void z_erofs_decompressqueue_endio(struct bio *bio)
-{
-       tagptr1_t t = tagptr_init(tagptr1_t, bio->bi_private);
-       struct z_erofs_decompressqueue *q = tagptr_unfold_ptr(t);
-       blk_status_t err = bio->bi_status;
-       struct bio_vec *bvec;
-       struct bvec_iter_all iter_all;
-
-       bio_for_each_segment_all(bvec, bio, iter_all) {
-               struct page *page = bvec->bv_page;
-
-               DBG_BUGON(PageUptodate(page));
-               DBG_BUGON(z_erofs_page_is_invalidated(page));
-
-               if (err)
-                       SetPageError(page);
-
-               if (erofs_page_is_managed(EROFS_SB(q->sb), page)) {
-                       if (!err)
-                               SetPageUptodate(page);
-                       unlock_page(page);
-               }
-       }
-       z_erofs_decompress_kickoff(q, tagptr_unfold_tags(t), -1);
-       bio_put(bio);
-}
-
 static int z_erofs_decompress_pcluster(struct super_block *sb,
                                       struct z_erofs_pcluster *pcl,
                                       struct page **pagepool)
@@ -1123,6 +1066,35 @@ static void z_erofs_decompressqueue_work(struct work_struct *work)
        kvfree(bgq);
 }
 
+static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
+                                      bool sync, int bios)
+{
+       struct erofs_sb_info *const sbi = EROFS_SB(io->sb);
+
+       /* wake up the caller thread for sync decompression */
+       if (sync) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&io->u.wait.lock, flags);
+               if (!atomic_add_return(bios, &io->pending_bios))
+                       wake_up_locked(&io->u.wait);
+               spin_unlock_irqrestore(&io->u.wait.lock, flags);
+               return;
+       }
+
+       if (atomic_add_return(bios, &io->pending_bios))
+               return;
+       /* Use workqueue and sync decompression for atomic contexts only */
+       if (in_atomic() || irqs_disabled()) {
+               queue_work(z_erofs_workqueue, &io->u.work);
+               /* enable sync decompression for readahead */
+               if (sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO)
+                       sbi->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON;
+               return;
+       }
+       z_erofs_decompressqueue_work(&io->u.work);
+}
+
 static struct page *pickup_page_for_submission(struct z_erofs_pcluster *pcl,
                                               unsigned int nr,
                                               struct page **pagepool,
@@ -1300,6 +1272,33 @@ static void move_to_bypass_jobqueue(struct z_erofs_pcluster *pcl,
        qtail[JQ_BYPASS] = &pcl->next;
 }
 
+static void z_erofs_decompressqueue_endio(struct bio *bio)
+{
+       tagptr1_t t = tagptr_init(tagptr1_t, bio->bi_private);
+       struct z_erofs_decompressqueue *q = tagptr_unfold_ptr(t);
+       blk_status_t err = bio->bi_status;
+       struct bio_vec *bvec;
+       struct bvec_iter_all iter_all;
+
+       bio_for_each_segment_all(bvec, bio, iter_all) {
+               struct page *page = bvec->bv_page;
+
+               DBG_BUGON(PageUptodate(page));
+               DBG_BUGON(z_erofs_page_is_invalidated(page));
+
+               if (err)
+                       SetPageError(page);
+
+               if (erofs_page_is_managed(EROFS_SB(q->sb), page)) {
+                       if (!err)
+                               SetPageUptodate(page);
+                       unlock_page(page);
+               }
+       }
+       z_erofs_decompress_kickoff(q, tagptr_unfold_tags(t), -1);
+       bio_put(bio);
+}
+
 static void z_erofs_submit_queue(struct super_block *sb,
                                 struct z_erofs_decompress_frontend *f,
                                 struct page **pagepool,
index 18d7fd1..361b1d6 100644 (file)
@@ -630,6 +630,13 @@ static int z_erofs_do_map_blocks(struct inode *inode,
                if (endoff >= m.clusterofs) {
                        m.headtype = m.type;
                        map->m_la = (m.lcn << lclusterbits) | m.clusterofs;
+                       /*
+                        * For ztailpacking files, in order to inline data more
+                        * effectively, special EOF lclusters are now supported
+                        * which can have three parts at most.
+                        */
+                       if (ztailpacking && end > inode->i_size)
+                               end = inode->i_size;
                        break;
                }
                /* m.lcn should be >= 1 if endoff < m.clusterofs */
index 5a35768..57e82e2 100644 (file)
@@ -139,7 +139,7 @@ fail:
 /*
  * Inode operation get_posix_acl().
  *
- * inode->i_mutex: don't care
+ * inode->i_rwsem: don't care
  */
 struct posix_acl *
 ext4_get_acl(struct inode *inode, int type, bool rcu)
@@ -183,7 +183,7 @@ ext4_get_acl(struct inode *inode, int type, bool rcu)
 /*
  * Set the access or default ACL of an inode.
  *
- * inode->i_mutex: down unless called from ext4_new_inode
+ * inode->i_rwsem: down unless called from ext4_new_inode
  */
 static int
 __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
@@ -271,8 +271,8 @@ out_stop:
 /*
  * Initialize the ACLs of a new inode. Called from ext4_new_inode.
  *
- * dir->i_mutex: down
- * inode->i_mutex: up (access to inode is still exclusive)
+ * dir->i_rwsem: down
+ * inode->i_rwsem: up (access to inode is still exclusive)
  */
 int
 ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
index 71a3cdc..bcd3b9b 100644 (file)
@@ -1028,7 +1028,7 @@ struct ext4_inode_info {
 
        /*
         * Extended attributes can be read independently of the main file
-        * data. Taking i_mutex even when reading would cause contention
+        * data. Taking i_rwsem even when reading would cause contention
         * between readers of EAs and writers of regular file data, so
         * instead we synchronize on xattr_sem when reading or changing
         * EAs.
@@ -1750,6 +1750,7 @@ struct ext4_sb_info {
        spinlock_t s_fc_lock;
        struct buffer_head *s_fc_bh;
        struct ext4_fc_stats s_fc_stats;
+       tid_t s_fc_ineligible_tid;
 #ifdef CONFIG_EXT4_DEBUG
        int s_fc_debug_max_replay;
 #endif
@@ -1795,10 +1796,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 enum {
        EXT4_MF_MNTDIR_SAMPLED,
        EXT4_MF_FS_ABORTED,     /* Fatal error detected */
-       EXT4_MF_FC_INELIGIBLE,  /* Fast commit ineligible */
-       EXT4_MF_FC_COMMITTING   /* File system underoing a fast
-                                * commit.
-                                */
+       EXT4_MF_FC_INELIGIBLE   /* Fast commit ineligible */
 };
 
 static inline void ext4_set_mount_flag(struct super_block *sb, int bit)
@@ -2485,7 +2483,7 @@ struct ext4_filename {
 #ifdef CONFIG_FS_ENCRYPTION
        struct fscrypt_str crypto_buf;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        struct fscrypt_str cf_name;
 #endif
 };
@@ -2721,7 +2719,7 @@ extern unsigned ext4_free_clusters_after_init(struct super_block *sb,
                                              struct ext4_group_desc *gdp);
 ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 extern int ext4_fname_setup_ci_filename(struct inode *dir,
                                         const struct qstr *iname,
                                         struct ext4_filename *fname);
@@ -2754,7 +2752,7 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
 
        ext4_fname_from_fscrypt_name(fname, &name);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        err = ext4_fname_setup_ci_filename(dir, iname, fname);
 #endif
        return err;
@@ -2773,7 +2771,7 @@ static inline int ext4_fname_prepare_lookup(struct inode *dir,
 
        ext4_fname_from_fscrypt_name(fname, &name);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        err = ext4_fname_setup_ci_filename(dir, &dentry->d_name, fname);
 #endif
        return err;
@@ -2790,7 +2788,7 @@ static inline void ext4_fname_free_filename(struct ext4_filename *fname)
        fname->usr_fname = NULL;
        fname->disk_name.name = NULL;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        kfree(fname->cf_name.name);
        fname->cf_name.name = NULL;
 #endif
@@ -2806,7 +2804,7 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
        fname->disk_name.name = (unsigned char *) iname->name;
        fname->disk_name.len = iname->len;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        err = ext4_fname_setup_ci_filename(dir, iname, fname);
 #endif
 
@@ -2822,7 +2820,7 @@ static inline int ext4_fname_prepare_lookup(struct inode *dir,
 
 static inline void ext4_fname_free_filename(struct ext4_filename *fname)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        kfree(fname->cf_name.name);
        fname->cf_name.name = NULL;
 #endif
@@ -2926,7 +2924,7 @@ void __ext4_fc_track_create(handle_t *handle, struct inode *inode,
                            struct dentry *dentry);
 void ext4_fc_track_create(handle_t *handle, struct dentry *dentry);
 void ext4_fc_track_inode(handle_t *handle, struct inode *inode);
-void ext4_fc_mark_ineligible(struct super_block *sb, int reason);
+void ext4_fc_mark_ineligible(struct super_block *sb, int reason, handle_t *handle);
 void ext4_fc_start_update(struct inode *inode);
 void ext4_fc_stop_update(struct inode *inode);
 void ext4_fc_del(struct inode *inode);
@@ -2935,6 +2933,9 @@ void ext4_fc_replay_cleanup(struct super_block *sb);
 int ext4_fc_commit(journal_t *journal, tid_t commit_tid);
 int __init ext4_fc_init_dentry_cache(void);
 void ext4_fc_destroy_dentry_cache(void);
+int ext4_fc_record_regions(struct super_block *sb, int ino,
+                          ext4_lblk_t lblk, ext4_fsblk_t pblk,
+                          int len, int replay);
 
 /* mballoc.c */
 extern const struct seq_operations ext4_mb_seq_groups_ops;
@@ -3407,7 +3408,7 @@ do {                                                              \
 #define EXT4_FREECLUSTERS_WATERMARK 0
 #endif
 
-/* Update i_disksize. Requires i_mutex to avoid races with truncate */
+/* Update i_disksize. Requires i_rwsem to avoid races with truncate */
 static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize)
 {
        WARN_ON_ONCE(S_ISREG(inode->i_mode) &&
@@ -3418,7 +3419,7 @@ static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize)
        up_write(&EXT4_I(inode)->i_data_sem);
 }
 
-/* Update i_size, i_disksize. Requires i_mutex to avoid races with truncate */
+/* Update i_size, i_disksize. Requires i_rwsem to avoid races with truncate */
 static inline int ext4_update_inode_size(struct inode *inode, loff_t newsize)
 {
        int changed = 0;
index 0e4fa64..db2ae4a 100644 (file)
@@ -491,7 +491,7 @@ static inline int ext4_free_data_revoke_credits(struct inode *inode, int blocks)
 /*
  * This function controls whether or not we should try to go down the
  * dioread_nolock code paths, which makes it safe to avoid taking
- * i_mutex for direct I/O reads.  This only works for extent-based
+ * i_rwsem for direct I/O reads.  This only works for extent-based
  * files, and it doesn't work if data journaling is enabled, since the
  * dioread_nolock code uses b_private to pass information back to the
  * I/O completion handler, and this conflicts with the jbd's use of
index 74c91da..c0f3f83 100644 (file)
@@ -97,7 +97,7 @@ static int ext4_ext_trunc_restart_fn(struct inode *inode, int *dropped)
         * Drop i_data_sem to avoid deadlock with ext4_map_blocks.  At this
         * moment, get_block can be called only for blocks inside i_size since
         * page cache has been already dropped and writes are blocked by
-        * i_mutex. So we can safely drop the i_data_sem here.
+        * i_rwsem. So we can safely drop the i_data_sem here.
         */
        BUG_ON(EXT4_JOURNAL(inode) == NULL);
        ext4_discard_preallocations(inode, 0);
@@ -4572,7 +4572,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
 
        flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
 
-       /* Wait all existing dio workers, newcomers will block on i_mutex */
+       /* Wait all existing dio workers, newcomers will block on i_rwsem */
        inode_dio_wait(inode);
 
        /* Preallocate the range including the unaligned edges */
@@ -4738,7 +4738,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
                        goto out;
        }
 
-       /* Wait all existing dio workers, newcomers will block on i_mutex */
+       /* Wait all existing dio workers, newcomers will block on i_rwsem */
        inode_dio_wait(inode);
 
        ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, flags);
@@ -5334,7 +5334,7 @@ static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
                ret = PTR_ERR(handle);
                goto out_mmap;
        }
-       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE);
+       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE, handle);
 
        down_write(&EXT4_I(inode)->i_data_sem);
        ext4_discard_preallocations(inode, 0);
@@ -5474,7 +5474,7 @@ static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
                ret = PTR_ERR(handle);
                goto out_mmap;
        }
-       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE);
+       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE, handle);
 
        /* Expand file to avoid data loss if there is error while shifting */
        inode->i_size += len;
@@ -5571,7 +5571,7 @@ out_mutex:
  * stuff such as page-cache locking consistency, bh mapping consistency or
  * extent's data copying must be performed by caller.
  * Locking:
- *             i_mutex is held for both inodes
+ *             i_rwsem is held for both inodes
  *             i_data_sem is locked for write for both inodes
  * Assumptions:
  *             All pages from requested range are locked for both inodes
@@ -6091,11 +6091,15 @@ int ext4_ext_clear_bb(struct inode *inode)
 
                                        ext4_mb_mark_bb(inode->i_sb,
                                                        path[j].p_block, 1, 0);
+                                       ext4_fc_record_regions(inode->i_sb, inode->i_ino,
+                                                       0, path[j].p_block, 1, 1);
                                }
                                ext4_ext_drop_refs(path);
                                kfree(path);
                        }
                        ext4_mb_mark_bb(inode->i_sb, map.m_pblk, map.m_len, 0);
+                       ext4_fc_record_regions(inode->i_sb, inode->i_ino,
+                                       map.m_lblk, map.m_pblk, map.m_len, 1);
                }
                cur = cur + map.m_len;
        }
index 5ae8026..7964ee3 100644 (file)
@@ -300,18 +300,32 @@ restart:
 }
 
 /*
- * Mark file system as fast commit ineligible. This means that next commit
- * operation would result in a full jbd2 commit.
+ * Mark file system as fast commit ineligible, and record latest
+ * ineligible transaction tid. This means until the recorded
+ * transaction, commit operation would result in a full jbd2 commit.
  */
-void ext4_fc_mark_ineligible(struct super_block *sb, int reason)
+void ext4_fc_mark_ineligible(struct super_block *sb, int reason, handle_t *handle)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
+       tid_t tid;
 
        if (!test_opt2(sb, JOURNAL_FAST_COMMIT) ||
            (EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY))
                return;
 
        ext4_set_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
+       if (handle && !IS_ERR(handle))
+               tid = handle->h_transaction->t_tid;
+       else {
+               read_lock(&sbi->s_journal->j_state_lock);
+               tid = sbi->s_journal->j_running_transaction ?
+                               sbi->s_journal->j_running_transaction->t_tid : 0;
+               read_unlock(&sbi->s_journal->j_state_lock);
+       }
+       spin_lock(&sbi->s_fc_lock);
+       if (sbi->s_fc_ineligible_tid < tid)
+               sbi->s_fc_ineligible_tid = tid;
+       spin_unlock(&sbi->s_fc_lock);
        WARN_ON(reason >= EXT4_FC_REASON_MAX);
        sbi->s_fc_stats.fc_ineligible_reason_count[reason]++;
 }
@@ -361,7 +375,8 @@ static int ext4_fc_track_template(
        spin_lock(&sbi->s_fc_lock);
        if (list_empty(&EXT4_I(inode)->i_fc_list))
                list_add_tail(&EXT4_I(inode)->i_fc_list,
-                               (ext4_test_mount_flag(inode->i_sb, EXT4_MF_FC_COMMITTING)) ?
+                               (sbi->s_journal->j_flags & JBD2_FULL_COMMIT_ONGOING ||
+                                sbi->s_journal->j_flags & JBD2_FAST_COMMIT_ONGOING) ?
                                &sbi->s_fc_q[FC_Q_STAGING] :
                                &sbi->s_fc_q[FC_Q_MAIN]);
        spin_unlock(&sbi->s_fc_lock);
@@ -387,7 +402,7 @@ static int __track_dentry_update(struct inode *inode, void *arg, bool update)
        mutex_unlock(&ei->i_fc_lock);
        node = kmem_cache_alloc(ext4_fc_dentry_cachep, GFP_NOFS);
        if (!node) {
-               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM);
+               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM, NULL);
                mutex_lock(&ei->i_fc_lock);
                return -ENOMEM;
        }
@@ -400,7 +415,7 @@ static int __track_dentry_update(struct inode *inode, void *arg, bool update)
                if (!node->fcd_name.name) {
                        kmem_cache_free(ext4_fc_dentry_cachep, node);
                        ext4_fc_mark_ineligible(inode->i_sb,
-                               EXT4_FC_REASON_NOMEM);
+                               EXT4_FC_REASON_NOMEM, NULL);
                        mutex_lock(&ei->i_fc_lock);
                        return -ENOMEM;
                }
@@ -414,7 +429,8 @@ static int __track_dentry_update(struct inode *inode, void *arg, bool update)
        node->fcd_name.len = dentry->d_name.len;
 
        spin_lock(&sbi->s_fc_lock);
-       if (ext4_test_mount_flag(inode->i_sb, EXT4_MF_FC_COMMITTING))
+       if (sbi->s_journal->j_flags & JBD2_FULL_COMMIT_ONGOING ||
+               sbi->s_journal->j_flags & JBD2_FAST_COMMIT_ONGOING)
                list_add_tail(&node->fcd_list,
                                &sbi->s_fc_dentry_q[FC_Q_STAGING]);
        else
@@ -502,7 +518,7 @@ void ext4_fc_track_inode(handle_t *handle, struct inode *inode)
 
        if (ext4_should_journal_data(inode)) {
                ext4_fc_mark_ineligible(inode->i_sb,
-                                       EXT4_FC_REASON_INODE_JOURNAL_DATA);
+                                       EXT4_FC_REASON_INODE_JOURNAL_DATA, handle);
                return;
        }
 
@@ -879,7 +895,6 @@ static int ext4_fc_submit_inode_data_all(journal_t *journal)
        int ret = 0;
 
        spin_lock(&sbi->s_fc_lock);
-       ext4_set_mount_flag(sb, EXT4_MF_FC_COMMITTING);
        list_for_each_entry(ei, &sbi->s_fc_q[FC_Q_MAIN], i_fc_list) {
                ext4_set_inode_state(&ei->vfs_inode, EXT4_STATE_FC_COMMITTING);
                while (atomic_read(&ei->i_fc_updates)) {
@@ -1179,7 +1194,7 @@ fallback:
  * Fast commit cleanup routine. This is called after every fast commit and
  * full commit. full is true if we are called after a full commit.
  */
-static void ext4_fc_cleanup(journal_t *journal, int full)
+static void ext4_fc_cleanup(journal_t *journal, int full, tid_t tid)
 {
        struct super_block *sb = journal->j_private;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -1197,7 +1212,8 @@ static void ext4_fc_cleanup(journal_t *journal, int full)
                list_del_init(&iter->i_fc_list);
                ext4_clear_inode_state(&iter->vfs_inode,
                                       EXT4_STATE_FC_COMMITTING);
-               ext4_fc_reset_inode(&iter->vfs_inode);
+               if (iter->i_sync_tid <= tid)
+                       ext4_fc_reset_inode(&iter->vfs_inode);
                /* Make sure EXT4_STATE_FC_COMMITTING bit is clear */
                smp_mb();
 #if (BITS_PER_LONG < 64)
@@ -1226,8 +1242,10 @@ static void ext4_fc_cleanup(journal_t *journal, int full)
        list_splice_init(&sbi->s_fc_q[FC_Q_STAGING],
                                &sbi->s_fc_q[FC_Q_MAIN]);
 
-       ext4_clear_mount_flag(sb, EXT4_MF_FC_COMMITTING);
-       ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
+       if (tid >= sbi->s_fc_ineligible_tid) {
+               sbi->s_fc_ineligible_tid = 0;
+               ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
+       }
 
        if (full)
                sbi->s_fc_bytes = 0;
@@ -1392,14 +1410,15 @@ static int ext4_fc_record_modified_inode(struct super_block *sb, int ino)
                if (state->fc_modified_inodes[i] == ino)
                        return 0;
        if (state->fc_modified_inodes_used == state->fc_modified_inodes_size) {
-               state->fc_modified_inodes_size +=
-                       EXT4_FC_REPLAY_REALLOC_INCREMENT;
                state->fc_modified_inodes = krealloc(
-                                       state->fc_modified_inodes, sizeof(int) *
-                                       state->fc_modified_inodes_size,
-                                       GFP_KERNEL);
+                               state->fc_modified_inodes,
+                               sizeof(int) * (state->fc_modified_inodes_size +
+                               EXT4_FC_REPLAY_REALLOC_INCREMENT),
+                               GFP_KERNEL);
                if (!state->fc_modified_inodes)
                        return -ENOMEM;
+               state->fc_modified_inodes_size +=
+                       EXT4_FC_REPLAY_REALLOC_INCREMENT;
        }
        state->fc_modified_inodes[state->fc_modified_inodes_used++] = ino;
        return 0;
@@ -1431,7 +1450,9 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl,
        }
        inode = NULL;
 
-       ext4_fc_record_modified_inode(sb, ino);
+       ret = ext4_fc_record_modified_inode(sb, ino);
+       if (ret)
+               goto out;
 
        raw_fc_inode = (struct ext4_inode *)
                (val + offsetof(struct ext4_fc_inode, fc_raw_inode));
@@ -1563,16 +1584,23 @@ out:
 }
 
 /*
- * Record physical disk regions which are in use as per fast commit area. Our
- * simple replay phase allocator excludes these regions from allocation.
+ * Record physical disk regions which are in use as per fast commit area,
+ * and used by inodes during replay phase. Our simple replay phase
+ * allocator excludes these regions from allocation.
  */
-static int ext4_fc_record_regions(struct super_block *sb, int ino,
-               ext4_lblk_t lblk, ext4_fsblk_t pblk, int len)
+int ext4_fc_record_regions(struct super_block *sb, int ino,
+               ext4_lblk_t lblk, ext4_fsblk_t pblk, int len, int replay)
 {
        struct ext4_fc_replay_state *state;
        struct ext4_fc_alloc_region *region;
 
        state = &EXT4_SB(sb)->s_fc_replay_state;
+       /*
+        * during replay phase, the fc_regions_valid may not same as
+        * fc_regions_used, update it when do new additions.
+        */
+       if (replay && state->fc_regions_used != state->fc_regions_valid)
+               state->fc_regions_used = state->fc_regions_valid;
        if (state->fc_regions_used == state->fc_regions_size) {
                state->fc_regions_size +=
                        EXT4_FC_REPLAY_REALLOC_INCREMENT;
@@ -1590,6 +1618,9 @@ static int ext4_fc_record_regions(struct super_block *sb, int ino,
        region->pblk = pblk;
        region->len = len;
 
+       if (replay)
+               state->fc_regions_valid++;
+
        return 0;
 }
 
@@ -1621,6 +1652,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
        }
 
        ret = ext4_fc_record_modified_inode(sb, inode->i_ino);
+       if (ret)
+               goto out;
 
        start = le32_to_cpu(ex->ee_block);
        start_pblk = ext4_ext_pblock(ex);
@@ -1638,18 +1671,14 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
                map.m_pblk = 0;
                ret = ext4_map_blocks(NULL, inode, &map, 0);
 
-               if (ret < 0) {
-                       iput(inode);
-                       return 0;
-               }
+               if (ret < 0)
+                       goto out;
 
                if (ret == 0) {
                        /* Range is not mapped */
                        path = ext4_find_extent(inode, cur, NULL, 0);
-                       if (IS_ERR(path)) {
-                               iput(inode);
-                               return 0;
-                       }
+                       if (IS_ERR(path))
+                               goto out;
                        memset(&newex, 0, sizeof(newex));
                        newex.ee_block = cpu_to_le32(cur);
                        ext4_ext_store_pblock(
@@ -1663,10 +1692,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
                        up_write((&EXT4_I(inode)->i_data_sem));
                        ext4_ext_drop_refs(path);
                        kfree(path);
-                       if (ret) {
-                               iput(inode);
-                               return 0;
-                       }
+                       if (ret)
+                               goto out;
                        goto next;
                }
 
@@ -1679,10 +1706,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
                        ret = ext4_ext_replay_update_ex(inode, cur, map.m_len,
                                        ext4_ext_is_unwritten(ex),
                                        start_pblk + cur - start);
-                       if (ret) {
-                               iput(inode);
-                               return 0;
-                       }
+                       if (ret)
+                               goto out;
                        /*
                         * Mark the old blocks as free since they aren't used
                         * anymore. We maintain an array of all the modified
@@ -1702,10 +1727,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
                        ext4_ext_is_unwritten(ex), map.m_pblk);
                ret = ext4_ext_replay_update_ex(inode, cur, map.m_len,
                                        ext4_ext_is_unwritten(ex), map.m_pblk);
-               if (ret) {
-                       iput(inode);
-                       return 0;
-               }
+               if (ret)
+                       goto out;
                /*
                 * We may have split the extent tree while toggling the state.
                 * Try to shrink the extent tree now.
@@ -1717,6 +1740,7 @@ next:
        }
        ext4_ext_replay_shrink_inode(inode, i_size_read(inode) >>
                                        sb->s_blocksize_bits);
+out:
        iput(inode);
        return 0;
 }
@@ -1746,6 +1770,8 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl,
        }
 
        ret = ext4_fc_record_modified_inode(sb, inode->i_ino);
+       if (ret)
+               goto out;
 
        jbd_debug(1, "DEL_RANGE, inode %ld, lblk %d, len %d\n",
                        inode->i_ino, le32_to_cpu(lrange.fc_lblk),
@@ -1755,10 +1781,8 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl,
                map.m_len = remaining;
 
                ret = ext4_map_blocks(NULL, inode, &map, 0);
-               if (ret < 0) {
-                       iput(inode);
-                       return 0;
-               }
+               if (ret < 0)
+                       goto out;
                if (ret > 0) {
                        remaining -= ret;
                        cur += ret;
@@ -1770,18 +1794,17 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl,
        }
 
        down_write(&EXT4_I(inode)->i_data_sem);
-       ret = ext4_ext_remove_space(inode, lrange.fc_lblk,
-                               lrange.fc_lblk + lrange.fc_len - 1);
+       ret = ext4_ext_remove_space(inode, le32_to_cpu(lrange.fc_lblk),
+                               le32_to_cpu(lrange.fc_lblk) +
+                               le32_to_cpu(lrange.fc_len) - 1);
        up_write(&EXT4_I(inode)->i_data_sem);
-       if (ret) {
-               iput(inode);
-               return 0;
-       }
+       if (ret)
+               goto out;
        ext4_ext_replay_shrink_inode(inode,
                i_size_read(inode) >> sb->s_blocksize_bits);
        ext4_mark_inode_dirty(NULL, inode);
+out:
        iput(inode);
-
        return 0;
 }
 
@@ -1937,7 +1960,7 @@ static int ext4_fc_replay_scan(journal_t *journal,
                        ret = ext4_fc_record_regions(sb,
                                le32_to_cpu(ext.fc_ino),
                                le32_to_cpu(ex->ee_block), ext4_ext_pblock(ex),
-                               ext4_ext_get_actual_len(ex));
+                               ext4_ext_get_actual_len(ex), 0);
                        if (ret < 0)
                                break;
                        ret = JBD2_FC_REPLAY_CONTINUE;
index f34f417..147b524 100644 (file)
@@ -290,7 +290,7 @@ static int __ext4fs_dirhash(const struct inode *dir, const char *name, int len,
 int ext4fs_dirhash(const struct inode *dir, const char *name, int len,
                   struct dx_hash_info *hinfo)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        const struct unicode_map *um = dir->i_sb->s_encoding;
        int r, dlen;
        unsigned char *buff;
index 89efa78..07a8c75 100644 (file)
@@ -696,7 +696,7 @@ static int ext4_ind_trunc_restart_fn(handle_t *handle, struct inode *inode,
         * Drop i_data_sem to avoid deadlock with ext4_map_blocks.  At this
         * moment, get_block can be called only for blocks inside i_size since
         * page cache has been already dropped and writes are blocked by
-        * i_mutex. So we can safely drop the i_data_sem here.
+        * i_rwsem. So we can safely drop the i_data_sem here.
         */
        BUG_ON(EXT4_JOURNAL(inode) == NULL);
        ext4_discard_preallocations(inode, 0);
index 635bcf6..e429418 100644 (file)
@@ -911,7 +911,7 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,
                                    struct page **pagep,
                                    void **fsdata)
 {
-       int ret, inline_size;
+       int ret;
        handle_t *handle;
        struct page *page;
        struct ext4_iloc iloc;
@@ -928,14 +928,9 @@ retry_journal:
                goto out;
        }
 
-       inline_size = ext4_get_max_inline_size(inode);
-
-       ret = -ENOSPC;
-       if (inline_size >= pos + len) {
-               ret = ext4_prepare_inline_data(handle, inode, pos + len);
-               if (ret && ret != -ENOSPC)
-                       goto out_journal;
-       }
+       ret = ext4_prepare_inline_data(handle, inode, pos + len);
+       if (ret && ret != -ENOSPC)
+               goto out_journal;
 
        /*
         * We cannot recurse into the filesystem as the transaction
@@ -1133,7 +1128,15 @@ static void ext4_restore_inline_data(handle_t *handle, struct inode *inode,
                                     struct ext4_iloc *iloc,
                                     void *buf, int inline_size)
 {
-       ext4_create_inline_data(handle, inode, inline_size);
+       int ret;
+
+       ret = ext4_create_inline_data(handle, inode, inline_size);
+       if (ret) {
+               ext4_msg(inode->i_sb, KERN_EMERG,
+                       "error restoring inline_data for inode -- potential data loss! (inode %lu, error %d)",
+                       inode->i_ino, ret);
+               return;
+       }
        ext4_write_inline_data(inode, iloc, buf, 0, inline_size);
        ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
 }
index 5f79d26..01c9e4f 100644 (file)
@@ -338,7 +338,7 @@ stop_handle:
        return;
 no_delete:
        if (!list_empty(&EXT4_I(inode)->i_fc_list))
-               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM);
+               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM, NULL);
        ext4_clear_inode(inode);        /* We must guarantee clearing of inode... */
 }
 
@@ -1224,7 +1224,7 @@ retry_journal:
                /*
                 * __block_write_begin may have instantiated a few blocks
                 * outside i_size.  Trim these off again. Don't need
-                * i_size_read because we hold i_mutex.
+                * i_size_read because we hold i_rwsem.
                 *
                 * Add inode to orphan list in case we crash before
                 * truncate finishes
@@ -3979,7 +3979,7 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
 
        }
 
-       /* Wait all existing dio workers, newcomers will block on i_mutex */
+       /* Wait all existing dio workers, newcomers will block on i_rwsem */
        inode_dio_wait(inode);
 
        /*
@@ -4129,7 +4129,7 @@ int ext4_truncate(struct inode *inode)
        /*
         * There is a possibility that we're either freeing the inode
         * or it's a completely new inode. In those cases we might not
-        * have i_mutex locked because it's not necessary.
+        * have i_rwsem locked because it's not necessary.
         */
        if (!(inode->i_state & (I_NEW|I_FREEING)))
                WARN_ON(!inode_is_locked(inode));
@@ -5271,7 +5271,7 @@ static void ext4_wait_for_tail_page_commit(struct inode *inode)
  * transaction are already on disk (truncate waits for pages under
  * writeback).
  *
- * Called with inode->i_mutex down.
+ * Called with inode->i_rwsem down.
  */
 int ext4_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
                 struct iattr *attr)
@@ -5983,7 +5983,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
                return PTR_ERR(handle);
 
        ext4_fc_mark_ineligible(inode->i_sb,
-               EXT4_FC_REASON_JOURNAL_FLAG_CHANGE);
+               EXT4_FC_REASON_JOURNAL_FLAG_CHANGE, handle);
        err = ext4_mark_inode_dirty(handle, inode);
        ext4_handle_sync(handle);
        ext4_journal_stop(handle);
index bbbedf2..a8022c2 100644 (file)
@@ -411,7 +411,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
                err = -EINVAL;
                goto err_out;
        }
-       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_SWAP_BOOT);
+       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_SWAP_BOOT, handle);
 
        /* Protect extent tree against block allocations via delalloc */
        ext4_double_down_write_data_sem(inode, inode_bl);
@@ -1373,7 +1373,7 @@ mext_out:
 
                err = ext4_resize_fs(sb, n_blocks_count);
                if (EXT4_SB(sb)->s_journal) {
-                       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_RESIZE);
+                       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_RESIZE, NULL);
                        jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
                        err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal, 0);
                        jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
index 9f86dd9..67ac95c 100644 (file)
@@ -5753,7 +5753,8 @@ static ext4_fsblk_t ext4_mb_new_blocks_simple(handle_t *handle,
        struct super_block *sb = ar->inode->i_sb;
        ext4_group_t group;
        ext4_grpblk_t blkoff;
-       int i = sb->s_blocksize;
+       ext4_grpblk_t max = EXT4_CLUSTERS_PER_GROUP(sb);
+       ext4_grpblk_t i = 0;
        ext4_fsblk_t goal, block;
        struct ext4_super_block *es = EXT4_SB(sb)->s_es;
 
@@ -5775,19 +5776,26 @@ static ext4_fsblk_t ext4_mb_new_blocks_simple(handle_t *handle,
                ext4_get_group_no_and_offset(sb,
                        max(ext4_group_first_block_no(sb, group), goal),
                        NULL, &blkoff);
-               i = mb_find_next_zero_bit(bitmap_bh->b_data, sb->s_blocksize,
+               while (1) {
+                       i = mb_find_next_zero_bit(bitmap_bh->b_data, max,
                                                blkoff);
+                       if (i >= max)
+                               break;
+                       if (ext4_fc_replay_check_excluded(sb,
+                               ext4_group_first_block_no(sb, group) + i)) {
+                               blkoff = i + 1;
+                       } else
+                               break;
+               }
                brelse(bitmap_bh);
-               if (i >= sb->s_blocksize)
-                       continue;
-               if (ext4_fc_replay_check_excluded(sb,
-                       ext4_group_first_block_no(sb, group) + i))
-                       continue;
-               break;
+               if (i < max)
+                       break;
        }
 
-       if (group >= ext4_get_groups_count(sb) && i >= sb->s_blocksize)
+       if (group >= ext4_get_groups_count(sb) || i >= max) {
+               *errp = -ENOSPC;
                return 0;
+       }
 
        block = ext4_group_first_block_no(sb, group) + i;
        ext4_mb_mark_bb(sb, block, 1, 1);
index ff8916e..7a5353a 100644 (file)
@@ -485,7 +485,7 @@ int ext4_ext_migrate(struct inode *inode)
         * when we add extents we extent the journal
         */
        /*
-        * Even though we take i_mutex we can still cause block
+        * Even though we take i_rwsem we can still cause block
         * allocation via mmap write to holes. If we have allocated
         * new blocks we fail migrate.  New block allocation will
         * clear EXT4_STATE_EXT_MIGRATE flag.  The flag is updated
index 52c9bd1..8cf0a92 100644 (file)
@@ -1317,7 +1317,7 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block)
        dx_set_count(entries, count + 1);
 }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 /*
  * Test whether a case-insensitive directory entry matches the filename
  * being searched for.  If quick is set, assume the name being looked up
@@ -1428,7 +1428,7 @@ static bool ext4_match(struct inode *parent,
        f.crypto_buf = fname->crypto_buf;
 #endif
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent) &&
            (!IS_ENCRYPTED(parent) || fscrypt_has_encryption_key(parent))) {
                if (fname->cf_name.name) {
@@ -1800,7 +1800,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
                }
        }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (!inode && IS_CASEFOLDED(dir)) {
                /* Eventually we want to call d_add_ci(dentry, NULL)
                 * for negative dentries in the encoding case as
@@ -2308,7 +2308,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
        if (fscrypt_is_nokey_name(dentry))
                return -ENOKEY;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (sb_has_strict_encoding(sb) && IS_CASEFOLDED(dir) &&
            sb->s_encoding && utf8_validate(sb->s_encoding, &dentry->d_name))
                return -EINVAL;
@@ -3126,7 +3126,7 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
        ext4_fc_track_unlink(handle, dentry);
        retval = ext4_mark_inode_dirty(handle, dir);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        /* VFS negative dentries are incompatible with Encoding and
         * Case-insensitiveness. Eventually we'll want avoid
         * invalidating the dentries here, alongside with returning the
@@ -3231,7 +3231,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
        retval = __ext4_unlink(handle, dir, &dentry->d_name, d_inode(dentry));
        if (!retval)
                ext4_fc_track_unlink(handle, dentry);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        /* VFS negative dentries are incompatible with Encoding and
         * Case-insensitiveness. Eventually we'll want avoid
         * invalidating the dentries here, alongside with returning the
@@ -3889,7 +3889,7 @@ static int ext4_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
                 * dirents in directories.
                 */
                ext4_fc_mark_ineligible(old.inode->i_sb,
-                       EXT4_FC_REASON_RENAME_DIR);
+                       EXT4_FC_REASON_RENAME_DIR, handle);
        } else {
                if (new.inode)
                        ext4_fc_track_unlink(handle, new.dentry);
@@ -4049,7 +4049,7 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (unlikely(retval))
                goto end_rename;
        ext4_fc_mark_ineligible(new.inode->i_sb,
-                               EXT4_FC_REASON_CROSS_RENAME);
+                               EXT4_FC_REASON_CROSS_RENAME, handle);
        if (old.dir_bh) {
                retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino);
                if (retval)
index 53adc8f..7de0612 100644 (file)
@@ -93,7 +93,7 @@ static int ext4_orphan_file_add(handle_t *handle, struct inode *inode)
  * At filesystem recovery time, we walk this list deleting unlinked
  * inodes and truncating linked inodes in ext4_orphan_cleanup().
  *
- * Orphan list manipulation functions must be called under i_mutex unless
+ * Orphan list manipulation functions must be called under i_rwsem unless
  * we are just creating the inode or deleting it.
  */
 int ext4_orphan_add(handle_t *handle, struct inode *inode)
@@ -119,7 +119,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
        /*
         * Orphan handling is only valid for files with data blocks
         * being truncated, or files being unlinked. Note that we either
-        * hold i_mutex, or the inode can not be referenced from outside,
+        * hold i_rwsem, or the inode can not be referenced from outside,
         * so i_nlink should not be bumped due to race
         */
        ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
index eee0d9e..c5021ca 100644 (file)
@@ -1301,7 +1301,7 @@ static void ext4_put_super(struct super_block *sb)
        kfree(sbi->s_blockgroup_lock);
        fs_put_dax(sbi->s_daxdev);
        fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        utf8_unload(sb->s_encoding);
 #endif
        kfree(sbi);
@@ -1961,7 +1961,7 @@ static const struct mount_opts {
        {Opt_err, 0, 0}
 };
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 static const struct ext4_sb_encodings {
        __u16 magic;
        char *name;
@@ -3606,7 +3606,7 @@ int ext4_feature_set_ok(struct super_block *sb, int readonly)
                return 0;
        }
 
-#ifndef CONFIG_UNICODE
+#if !IS_ENABLED(CONFIG_UNICODE)
        if (ext4_has_feature_casefold(sb)) {
                ext4_msg(sb, KERN_ERR,
                         "Filesystem with casefold feature cannot be "
@@ -4610,7 +4610,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
        if (err < 0)
                goto failed_mount;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (ext4_has_feature_casefold(sb) && !sb->s_encoding) {
                const struct ext4_sb_encodings *encoding_info;
                struct unicode_map *encoding;
@@ -5082,7 +5082,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
        INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_STAGING]);
        sbi->s_fc_bytes = 0;
        ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
-       ext4_clear_mount_flag(sb, EXT4_MF_FC_COMMITTING);
+       sbi->s_fc_ineligible_tid = 0;
        spin_lock_init(&sbi->s_fc_lock);
        memset(&sbi->s_fc_stats, 0, sizeof(sbi->s_fc_stats));
        sbi->s_fc_replay_state.fc_regions = NULL;
@@ -5514,7 +5514,7 @@ failed_mount:
        if (sbi->s_chksum_driver)
                crypto_free_shash(sbi->s_chksum_driver);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        utf8_unload(sb->s_encoding);
 #endif
 
@@ -5540,7 +5540,7 @@ static int ext4_fill_super(struct super_block *sb, struct fs_context *fc)
 
        sbi = ext4_alloc_sbi(sb);
        if (!sbi)
-               ret = -ENOMEM;
+               return -ENOMEM;
 
        fc->s_fs_info = sbi;
 
index f61e65a..d233c24 100644 (file)
@@ -309,7 +309,7 @@ EXT4_ATTR_FEATURE(meta_bg_resize);
 EXT4_ATTR_FEATURE(encryption);
 EXT4_ATTR_FEATURE(test_dummy_encryption_v2);
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 EXT4_ATTR_FEATURE(casefold);
 #endif
 #ifdef CONFIG_FS_VERITY
@@ -317,7 +317,7 @@ EXT4_ATTR_FEATURE(verity);
 #endif
 EXT4_ATTR_FEATURE(metadata_csum_seed);
 EXT4_ATTR_FEATURE(fast_commit);
-#if defined(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)
+#if IS_ENABLED(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)
 EXT4_ATTR_FEATURE(encrypted_casefold);
 #endif
 
@@ -329,7 +329,7 @@ static struct attribute *ext4_feat_attrs[] = {
        ATTR_LIST(encryption),
        ATTR_LIST(test_dummy_encryption_v2),
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        ATTR_LIST(casefold),
 #endif
 #ifdef CONFIG_FS_VERITY
@@ -337,7 +337,7 @@ static struct attribute *ext4_feat_attrs[] = {
 #endif
        ATTR_LIST(metadata_csum_seed),
        ATTR_LIST(fast_commit),
-#if defined(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)
+#if IS_ENABLED(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)
        ATTR_LIST(encrypted_casefold),
 #endif
        NULL,
index 1e0fc1e..0423253 100644 (file)
@@ -2408,7 +2408,7 @@ retry_inode:
                if (IS_SYNC(inode))
                        ext4_handle_sync(handle);
        }
-       ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR);
+       ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR, handle);
 
 cleanup:
        brelse(is.iloc.bh);
@@ -2486,7 +2486,7 @@ retry:
                if (error == 0)
                        error = error2;
        }
-       ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR);
+       ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR, NULL);
 
        return error;
 }
@@ -2920,7 +2920,7 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
                                         error);
                        goto cleanup;
                }
-               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR);
+               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR, handle);
        }
        error = 0;
 cleanup:
index 1820e9c..166f086 100644 (file)
@@ -16,7 +16,7 @@
 #include "xattr.h"
 #include <trace/events/f2fs.h>
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 extern struct kmem_cache *f2fs_cf_name_slab;
 #endif
 
@@ -79,7 +79,7 @@ unsigned char f2fs_get_de_type(struct f2fs_dir_entry *de)
 int f2fs_init_casefolded_name(const struct inode *dir,
                              struct f2fs_filename *fname)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        struct super_block *sb = dir->i_sb;
 
        if (IS_CASEFOLDED(dir)) {
@@ -174,7 +174,7 @@ void f2fs_free_filename(struct f2fs_filename *fname)
        kfree(fname->crypto_buf.name);
        fname->crypto_buf.name = NULL;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (fname->cf_name.name) {
                kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name);
                fname->cf_name.name = NULL;
@@ -208,7 +208,7 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir,
        return f2fs_find_target_dentry(&d, fname, max_slots);
 }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 /*
  * Test whether a case-insensitive directory entry matches the filename
  * being searched for.
@@ -266,7 +266,7 @@ static inline int f2fs_match_name(const struct inode *dir,
 {
        struct fscrypt_name f;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (fname->cf_name.name) {
                struct qstr cf = FSTR_TO_QSTR(&fname->cf_name);
 
index eb22fa9..68b4401 100644 (file)
@@ -488,7 +488,7 @@ struct f2fs_filename {
         */
        struct fscrypt_str crypto_buf;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        /*
         * For casefolded directories: the casefolded name, but it's left NULL
         * if the original name is not valid Unicode, if the directory is both
index e3beac5..3cb1e7a 100644 (file)
@@ -105,7 +105,7 @@ void f2fs_hash_filename(const struct inode *dir, struct f2fs_filename *fname)
                return;
        }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (IS_CASEFOLDED(dir)) {
                /*
                 * If the casefolded name is provided, hash it instead of the
index a728a0a..5f213f0 100644 (file)
@@ -561,7 +561,7 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
                goto out_iput;
        }
 out_splice:
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (!inode && IS_CASEFOLDED(dir)) {
                /* Eventually we want to call d_add_ci(dentry, NULL)
                 * for negative dentries in the encoding case as
@@ -622,7 +622,7 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
                goto fail;
        }
        f2fs_delete_entry(de, page, dir, inode);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        /* VFS negative dentries are incompatible with Encoding and
         * Case-insensitiveness. Eventually we'll want avoid
         * invalidating the dentries here, alongside with returning the
index 9683c80..79773d3 100644 (file)
@@ -46,7 +46,7 @@
 
 static struct kmem_cache *fsync_entry_slab;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 extern struct kmem_cache *f2fs_cf_name_slab;
 #endif
 
@@ -149,7 +149,7 @@ static int init_recovered_filename(const struct inode *dir,
                if (err)
                        return err;
                f2fs_hash_filename(dir, fname);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
                /* Case-sensitive match is fine for recovery */
                kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name);
                fname->cf_name.name = NULL;
index 76e6a3d..baefd39 100644 (file)
@@ -257,7 +257,7 @@ void f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...)
        va_end(args);
 }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 static const struct f2fs_sb_encodings {
        __u16 magic;
        char *name;
@@ -1259,7 +1259,7 @@ default_check:
                return -EINVAL;
        }
 #endif
-#ifndef CONFIG_UNICODE
+#if !IS_ENABLED(CONFIG_UNICODE)
        if (f2fs_sb_has_casefold(sbi)) {
                f2fs_err(sbi,
                        "Filesystem with casefold feature cannot be mounted without CONFIG_UNICODE");
@@ -1619,7 +1619,7 @@ static void f2fs_put_super(struct super_block *sb)
        f2fs_destroy_iostat(sbi);
        for (i = 0; i < NR_PAGE_TYPE; i++)
                kvfree(sbi->write_io[i]);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        utf8_unload(sb->s_encoding);
 #endif
        kfree(sbi);
@@ -3903,7 +3903,7 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
 
 static int f2fs_setup_casefold(struct f2fs_sb_info *sbi)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (f2fs_sb_has_casefold(sbi) && !sbi->sb->s_encoding) {
                const struct f2fs_sb_encodings *encoding_info;
                struct unicode_map *encoding;
@@ -4458,7 +4458,7 @@ free_bio_info:
        for (i = 0; i < NR_PAGE_TYPE; i++)
                kvfree(sbi->write_io[i]);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        utf8_unload(sb->s_encoding);
        sb->s_encoding = NULL;
 #endif
index df406c1..8ac5066 100644 (file)
@@ -201,7 +201,7 @@ static ssize_t unusable_show(struct f2fs_attr *a,
 static ssize_t encoding_show(struct f2fs_attr *a,
                struct f2fs_sb_info *sbi, char *buf)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        struct super_block *sb = sbi->sb;
 
        if (f2fs_sb_has_casefold(sbi))
@@ -778,7 +778,7 @@ F2FS_GENERAL_RO_ATTR(avg_vblocks);
 #ifdef CONFIG_FS_ENCRYPTION
 F2FS_FEATURE_RO_ATTR(encryption);
 F2FS_FEATURE_RO_ATTR(test_dummy_encryption_v2);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 F2FS_FEATURE_RO_ATTR(encrypted_casefold);
 #endif
 #endif /* CONFIG_FS_ENCRYPTION */
@@ -797,7 +797,7 @@ F2FS_FEATURE_RO_ATTR(lost_found);
 F2FS_FEATURE_RO_ATTR(verity);
 #endif
 F2FS_FEATURE_RO_ATTR(sb_checksum);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 F2FS_FEATURE_RO_ATTR(casefold);
 #endif
 F2FS_FEATURE_RO_ATTR(readonly);
@@ -910,7 +910,7 @@ static struct attribute *f2fs_feat_attrs[] = {
 #ifdef CONFIG_FS_ENCRYPTION
        ATTR_LIST(encryption),
        ATTR_LIST(test_dummy_encryption_v2),
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        ATTR_LIST(encrypted_casefold),
 #endif
 #endif /* CONFIG_FS_ENCRYPTION */
@@ -929,7 +929,7 @@ static struct attribute *f2fs_feat_attrs[] = {
        ATTR_LIST(verity),
 #endif
        ATTR_LIST(sb_checksum),
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        ATTR_LIST(casefold),
 #endif
        ATTR_LIST(readonly),
index 57edef1..4969021 100644 (file)
@@ -119,6 +119,8 @@ static struct ctl_table fs_stat_sysctls[] = {
 static int __init init_fs_stat_sysctls(void)
 {
        register_sysctl_init("fs", fs_stat_sysctls);
+       if (IS_ENABLED(CONFIG_BINFMT_MISC))
+               register_sysctl_mount_point("fs/binfmt_misc");
        return 0;
 }
 fs_initcall(init_fs_stat_sysctls);
index 3e718cf..8c39a85 100644 (file)
@@ -704,10 +704,11 @@ static int gfs2_release(struct inode *inode, struct file *file)
        kfree(file->private_data);
        file->private_data = NULL;
 
-       if (gfs2_rs_active(&ip->i_res))
-               gfs2_rs_delete(ip, &inode->i_writecount);
-       if (file->f_mode & FMODE_WRITE)
+       if (file->f_mode & FMODE_WRITE) {
+               if (gfs2_rs_active(&ip->i_res))
+                       gfs2_rs_delete(ip, &inode->i_writecount);
                gfs2_qa_put(ip);
+       }
        return 0;
 }
 
index b7ab843..6b23399 100644 (file)
@@ -301,9 +301,6 @@ void gfs2_glock_queue_put(struct gfs2_glock *gl)
 
 void gfs2_glock_put(struct gfs2_glock *gl)
 {
-       /* last put could call sleepable dlm api */
-       might_sleep();
-
        if (lockref_put_or_lock(&gl->gl_lockref))
                return;
 
index e54c412..77b9c7e 100644 (file)
@@ -5228,7 +5228,6 @@ static int io_recv(struct io_kiocb *req, unsigned int issue_flags)
                min_ret = iov_iter_count(&msg.msg_iter);
 
        ret = sock_recvmsg(sock, &msg, flags);
-out_free:
        if (ret < min_ret) {
                if (ret == -EAGAIN && force_nonblock)
                        return -EAGAIN;
@@ -5236,9 +5235,9 @@ out_free:
                        ret = -EINTR;
                req_set_fail(req);
        } else if ((flags & MSG_WAITALL) && (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) {
+out_free:
                req_set_fail(req);
        }
-
        __io_req_complete(req, issue_flags, ret, io_put_kbuf(req));
        return 0;
 }
@@ -7822,10 +7821,15 @@ static __cold void io_rsrc_node_ref_zero(struct percpu_ref *ref)
        struct io_ring_ctx *ctx = node->rsrc_data->ctx;
        unsigned long flags;
        bool first_add = false;
+       unsigned long delay = HZ;
 
        spin_lock_irqsave(&ctx->rsrc_ref_lock, flags);
        node->done = true;
 
+       /* if we are mid-quiesce then do not delay */
+       if (node->rsrc_data->quiesce)
+               delay = 0;
+
        while (!list_empty(&ctx->rsrc_ref_list)) {
                node = list_first_entry(&ctx->rsrc_ref_list,
                                            struct io_rsrc_node, node);
@@ -7838,10 +7842,10 @@ static __cold void io_rsrc_node_ref_zero(struct percpu_ref *ref)
        spin_unlock_irqrestore(&ctx->rsrc_ref_lock, flags);
 
        if (first_add)
-               mod_delayed_work(system_wq, &ctx->rsrc_put_work, HZ);
+               mod_delayed_work(system_wq, &ctx->rsrc_put_work, delay);
 }
 
-static struct io_rsrc_node *io_rsrc_node_alloc(struct io_ring_ctx *ctx)
+static struct io_rsrc_node *io_rsrc_node_alloc(void)
 {
        struct io_rsrc_node *ref_node;
 
@@ -7892,7 +7896,7 @@ static int io_rsrc_node_switch_start(struct io_ring_ctx *ctx)
 {
        if (ctx->rsrc_backup_node)
                return 0;
-       ctx->rsrc_backup_node = io_rsrc_node_alloc(ctx);
+       ctx->rsrc_backup_node = io_rsrc_node_alloc();
        return ctx->rsrc_backup_node ? 0 : -ENOMEM;
 }
 
@@ -8928,10 +8932,9 @@ static void io_mem_free(void *ptr)
 
 static void *io_mem_alloc(size_t size)
 {
-       gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN | __GFP_COMP |
-                               __GFP_NORETRY | __GFP_ACCOUNT;
+       gfp_t gfp = GFP_KERNEL_ACCOUNT | __GFP_ZERO | __GFP_NOWARN | __GFP_COMP;
 
-       return (void *) __get_free_pages(gfp_flags, get_order(size));
+       return (void *) __get_free_pages(gfp, get_order(size));
 }
 
 static unsigned long rings_size(unsigned sq_entries, unsigned cq_entries,
index c938bba..6c51a75 100644 (file)
@@ -21,6 +21,8 @@
 
 #include "../internal.h"
 
+#define IOEND_BATCH_SIZE       4096
+
 /*
  * Structure allocated for each folio when block size < folio size
  * to track sub-folio uptodate status and I/O completions.
@@ -1039,7 +1041,7 @@ static void iomap_finish_folio_write(struct inode *inode, struct folio *folio,
  * state, release holds on bios, and finally free up memory.  Do not use the
  * ioend after this.
  */
-static void
+static u32
 iomap_finish_ioend(struct iomap_ioend *ioend, int error)
 {
        struct inode *inode = ioend->io_inode;
@@ -1048,6 +1050,7 @@ iomap_finish_ioend(struct iomap_ioend *ioend, int error)
        u64 start = bio->bi_iter.bi_sector;
        loff_t offset = ioend->io_offset;
        bool quiet = bio_flagged(bio, BIO_QUIET);
+       u32 folio_count = 0;
 
        for (bio = &ioend->io_inline_bio; bio; bio = next) {
                struct folio_iter fi;
@@ -1062,9 +1065,11 @@ iomap_finish_ioend(struct iomap_ioend *ioend, int error)
                        next = bio->bi_private;
 
                /* walk all folios in bio, ending page IO on them */
-               bio_for_each_folio_all(fi, bio)
+               bio_for_each_folio_all(fi, bio) {
                        iomap_finish_folio_write(inode, fi.folio, fi.length,
                                        error);
+                       folio_count++;
+               }
                bio_put(bio);
        }
        /* The ioend has been freed by bio_put() */
@@ -1074,20 +1079,36 @@ iomap_finish_ioend(struct iomap_ioend *ioend, int error)
 "%s: writeback error on inode %lu, offset %lld, sector %llu",
                        inode->i_sb->s_id, inode->i_ino, offset, start);
        }
+       return folio_count;
 }
 
+/*
+ * Ioend completion routine for merged bios. This can only be called from task
+ * contexts as merged ioends can be of unbound length. Hence we have to break up
+ * the writeback completions into manageable chunks to avoid long scheduler
+ * holdoffs. We aim to keep scheduler holdoffs down below 10ms so that we get
+ * good batch processing throughput without creating adverse scheduler latency
+ * conditions.
+ */
 void
 iomap_finish_ioends(struct iomap_ioend *ioend, int error)
 {
        struct list_head tmp;
+       u32 completions;
+
+       might_sleep();
 
        list_replace_init(&ioend->io_list, &tmp);
-       iomap_finish_ioend(ioend, error);
+       completions = iomap_finish_ioend(ioend, error);
 
        while (!list_empty(&tmp)) {
+               if (completions > IOEND_BATCH_SIZE * 8) {
+                       cond_resched();
+                       completions = 0;
+               }
                ioend = list_first_entry(&tmp, struct iomap_ioend, io_list);
                list_del_init(&ioend->io_list);
-               iomap_finish_ioend(ioend, error);
+               completions += iomap_finish_ioend(ioend, error);
        }
 }
 EXPORT_SYMBOL_GPL(iomap_finish_ioends);
@@ -1108,6 +1129,18 @@ iomap_ioend_can_merge(struct iomap_ioend *ioend, struct iomap_ioend *next)
                return false;
        if (ioend->io_offset + ioend->io_size != next->io_offset)
                return false;
+       /*
+        * Do not merge physically discontiguous ioends. The filesystem
+        * completion functions will have to iterate the physical
+        * discontiguities even if we merge the ioends at a logical level, so
+        * we don't gain anything by merging physical discontiguities here.
+        *
+        * We cannot use bio->bi_iter.bi_sector here as it is modified during
+        * submission so does not point to the start sector of the bio at
+        * completion.
+        */
+       if (ioend->io_sector + (ioend->io_size >> 9) != next->io_sector)
+               return false;
        return true;
 }
 
@@ -1209,8 +1242,10 @@ iomap_alloc_ioend(struct inode *inode, struct iomap_writepage_ctx *wpc,
        ioend->io_flags = wpc->iomap.flags;
        ioend->io_inode = inode;
        ioend->io_size = 0;
+       ioend->io_folios = 0;
        ioend->io_offset = offset;
        ioend->io_bio = bio;
+       ioend->io_sector = sector;
        return ioend;
 }
 
@@ -1251,6 +1286,13 @@ iomap_can_add_to_ioend(struct iomap_writepage_ctx *wpc, loff_t offset,
                return false;
        if (sector != bio_end_sector(wpc->ioend->io_bio))
                return false;
+       /*
+        * Limit ioend bio chain lengths to minimise IO completion latency. This
+        * also prevents long tight loops ending page writeback on all the
+        * folios in the ioend.
+        */
+       if (wpc->ioend->io_folios >= IOEND_BATCH_SIZE)
+               return false;
        return true;
 }
 
@@ -1335,6 +1377,8 @@ iomap_writepage_map(struct iomap_writepage_ctx *wpc,
                                 &submit_list);
                count++;
        }
+       if (count)
+               wpc->ioend->io_folios++;
 
        WARN_ON_ONCE(!wpc->ioend && !list_empty(&submit_list));
        WARN_ON_ONCE(!folio_test_locked(folio));
index 3cc4ab2..5b9408e 100644 (file)
@@ -484,22 +484,9 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        stats.run.rs_running = jbd2_time_diff(commit_transaction->t_start,
                                              stats.run.rs_locked);
 
-       spin_lock(&commit_transaction->t_handle_lock);
-       while (atomic_read(&commit_transaction->t_updates)) {
-               DEFINE_WAIT(wait);
+       // waits for any t_updates to finish
+       jbd2_journal_wait_updates(journal);
 
-               prepare_to_wait(&journal->j_wait_updates, &wait,
-                                       TASK_UNINTERRUPTIBLE);
-               if (atomic_read(&commit_transaction->t_updates)) {
-                       spin_unlock(&commit_transaction->t_handle_lock);
-                       write_unlock(&journal->j_state_lock);
-                       schedule();
-                       write_lock(&journal->j_state_lock);
-                       spin_lock(&commit_transaction->t_handle_lock);
-               }
-               finish_wait(&journal->j_wait_updates, &wait);
-       }
-       spin_unlock(&commit_transaction->t_handle_lock);
        commit_transaction->t_state = T_SWITCH;
        write_unlock(&journal->j_state_lock);
 
@@ -817,7 +804,7 @@ start_journal_io:
        commit_transaction->t_state = T_COMMIT_DFLUSH;
        write_unlock(&journal->j_state_lock);
 
-       /* 
+       /*
         * If the journal is not located on the file system device,
         * then we must flush the file system device before we issue
         * the commit record
@@ -1170,7 +1157,7 @@ restart_loop:
        if (journal->j_commit_callback)
                journal->j_commit_callback(journal, commit_transaction);
        if (journal->j_fc_cleanup_callback)
-               journal->j_fc_cleanup_callback(journal, 1);
+               journal->j_fc_cleanup_callback(journal, 1, commit_transaction->t_tid);
 
        trace_jbd2_end_commit(journal, commit_transaction);
        jbd_debug(1, "JBD2: commit %d complete, head %d\n",
index f13d548..c2cf74b 100644 (file)
@@ -771,7 +771,7 @@ static int __jbd2_fc_end_commit(journal_t *journal, tid_t tid, bool fallback)
 {
        jbd2_journal_unlock_updates(journal);
        if (journal->j_fc_cleanup_callback)
-               journal->j_fc_cleanup_callback(journal, 0);
+               journal->j_fc_cleanup_callback(journal, 0, tid);
        write_lock(&journal->j_state_lock);
        journal->j_flags &= ~JBD2_FAST_COMMIT_ONGOING;
        if (fallback)
@@ -1287,6 +1287,8 @@ static int jbd2_min_tag_size(void)
 
 /**
  * jbd2_journal_shrink_scan()
+ * @shrink: shrinker to work on
+ * @sc: reclaim request to process
  *
  * Scan the checkpointed buffer on the checkpoint list and release the
  * journal_head.
@@ -1312,6 +1314,8 @@ static unsigned long jbd2_journal_shrink_scan(struct shrinker *shrink,
 
 /**
  * jbd2_journal_shrink_count()
+ * @shrink: shrinker to work on
+ * @sc: reclaim request to process
  *
  * Count the number of checkpoint buffers on the checkpoint list.
  */
@@ -2972,6 +2976,7 @@ struct journal_head *jbd2_journal_grab_journal_head(struct buffer_head *bh)
        jbd_unlock_bh_journal_head(bh);
        return jh;
 }
+EXPORT_SYMBOL(jbd2_journal_grab_journal_head);
 
 static void __journal_remove_journal_head(struct buffer_head *bh)
 {
@@ -3024,6 +3029,7 @@ void jbd2_journal_put_journal_head(struct journal_head *jh)
                jbd_unlock_bh_journal_head(bh);
        }
 }
+EXPORT_SYMBOL(jbd2_journal_put_journal_head);
 
 /*
  * Initialize jbd inode head
index 6a3caed..8e2f827 100644 (file)
@@ -449,7 +449,7 @@ repeat:
        }
 
        /* OK, account for the buffers that this operation expects to
-        * use and add the handle to the running transaction. 
+        * use and add the handle to the running transaction.
         */
        update_t_max_wait(transaction, ts);
        handle->h_transaction = transaction;
@@ -836,6 +836,35 @@ int jbd2_journal_restart(handle_t *handle, int nblocks)
 }
 EXPORT_SYMBOL(jbd2_journal_restart);
 
+/*
+ * Waits for any outstanding t_updates to finish.
+ * This is called with write j_state_lock held.
+ */
+void jbd2_journal_wait_updates(journal_t *journal)
+{
+       transaction_t *commit_transaction = journal->j_running_transaction;
+
+       if (!commit_transaction)
+               return;
+
+       spin_lock(&commit_transaction->t_handle_lock);
+       while (atomic_read(&commit_transaction->t_updates)) {
+               DEFINE_WAIT(wait);
+
+               prepare_to_wait(&journal->j_wait_updates, &wait,
+                                       TASK_UNINTERRUPTIBLE);
+               if (atomic_read(&commit_transaction->t_updates)) {
+                       spin_unlock(&commit_transaction->t_handle_lock);
+                       write_unlock(&journal->j_state_lock);
+                       schedule();
+                       write_lock(&journal->j_state_lock);
+                       spin_lock(&commit_transaction->t_handle_lock);
+               }
+               finish_wait(&journal->j_wait_updates, &wait);
+       }
+       spin_unlock(&commit_transaction->t_handle_lock);
+}
+
 /**
  * jbd2_journal_lock_updates () - establish a transaction barrier.
  * @journal:  Journal to establish a barrier on.
@@ -863,27 +892,9 @@ void jbd2_journal_lock_updates(journal_t *journal)
                write_lock(&journal->j_state_lock);
        }
 
-       /* Wait until there are no running updates */
-       while (1) {
-               transaction_t *transaction = journal->j_running_transaction;
-
-               if (!transaction)
-                       break;
+       /* Wait until there are no running t_updates */
+       jbd2_journal_wait_updates(journal);
 
-               spin_lock(&transaction->t_handle_lock);
-               prepare_to_wait(&journal->j_wait_updates, &wait,
-                               TASK_UNINTERRUPTIBLE);
-               if (!atomic_read(&transaction->t_updates)) {
-                       spin_unlock(&transaction->t_handle_lock);
-                       finish_wait(&journal->j_wait_updates, &wait);
-                       break;
-               }
-               spin_unlock(&transaction->t_handle_lock);
-               write_unlock(&journal->j_state_lock);
-               schedule();
-               finish_wait(&journal->j_wait_updates, &wait);
-               write_lock(&journal->j_state_lock);
-       }
        write_unlock(&journal->j_state_lock);
 
        /*
index dc3d061..911444d 100644 (file)
@@ -29,6 +29,7 @@
 #include "mgmt/user_config.h"
 #include "crypto_ctx.h"
 #include "transport_ipc.h"
+#include "../smbfs_common/arc4.h"
 
 /*
  * Fixed format data defining GSS header and fixed string
@@ -336,6 +337,29 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
                                nt_len - CIFS_ENCPWD_SIZE,
                                domain_name, conn->ntlmssp.cryptkey);
        kfree(domain_name);
+
+       /* The recovered secondary session key */
+       if (conn->ntlmssp.client_flags & NTLMSSP_NEGOTIATE_KEY_XCH) {
+               struct arc4_ctx *ctx_arc4;
+               unsigned int sess_key_off, sess_key_len;
+
+               sess_key_off = le32_to_cpu(authblob->SessionKey.BufferOffset);
+               sess_key_len = le16_to_cpu(authblob->SessionKey.Length);
+
+               if (blob_len < (u64)sess_key_off + sess_key_len)
+                       return -EINVAL;
+
+               ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL);
+               if (!ctx_arc4)
+                       return -ENOMEM;
+
+               cifs_arc4_setkey(ctx_arc4, sess->sess_key,
+                                SMB2_NTLMV2_SESSKEY_SIZE);
+               cifs_arc4_crypt(ctx_arc4, sess->sess_key,
+                               (char *)authblob + sess_key_off, sess_key_len);
+               kfree_sensitive(ctx_arc4);
+       }
+
        return ret;
 }
 
@@ -408,6 +432,9 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
            (cflags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
                flags |= NTLMSSP_NEGOTIATE_EXTENDED_SEC;
 
+       if (cflags & NTLMSSP_NEGOTIATE_KEY_XCH)
+               flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
+
        chgblob->NegotiateFlags = cpu_to_le32(flags);
        len = strlen(ksmbd_netbios_name());
        name = kmalloc(2 + UNICODE_LEN(len), GFP_KERNEL);
index 1866c81..67e8e28 100644 (file)
@@ -2688,7 +2688,7 @@ int smb2_open(struct ksmbd_work *work)
                                        (struct create_posix *)context;
                                if (le16_to_cpu(context->DataOffset) +
                                    le32_to_cpu(context->DataLength) <
-                                   sizeof(struct create_posix)) {
+                                   sizeof(struct create_posix) - 4) {
                                        rc = -EINVAL;
                                        goto err_out1;
                                }
@@ -3422,9 +3422,9 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level,
                goto free_conv_name;
        }
 
-       struct_sz = readdir_info_level_struct_sz(info_level);
-       next_entry_offset = ALIGN(struct_sz - 1 + conv_len,
-                                 KSMBD_DIR_INFO_ALIGNMENT);
+       struct_sz = readdir_info_level_struct_sz(info_level) - 1 + conv_len;
+       next_entry_offset = ALIGN(struct_sz, KSMBD_DIR_INFO_ALIGNMENT);
+       d_info->last_entry_off_align = next_entry_offset - struct_sz;
 
        if (next_entry_offset > d_info->out_buf_len) {
                d_info->out_buf_len = 0;
@@ -3976,6 +3976,7 @@ int smb2_query_dir(struct ksmbd_work *work)
                ((struct file_directory_info *)
                ((char *)rsp->Buffer + d_info.last_entry_offset))
                ->NextEntryOffset = 0;
+               d_info.data_count -= d_info.last_entry_off_align;
 
                rsp->StructureSize = cpu_to_le16(9);
                rsp->OutputBufferOffset = cpu_to_le16(72);
@@ -6126,13 +6127,26 @@ static int smb2_set_remote_key_for_rdma(struct ksmbd_work *work,
                                        __le16 ChannelInfoOffset,
                                        __le16 ChannelInfoLength)
 {
+       unsigned int i, ch_count;
+
        if (work->conn->dialect == SMB30_PROT_ID &&
            Channel != SMB2_CHANNEL_RDMA_V1)
                return -EINVAL;
 
-       if (ChannelInfoOffset == 0 ||
-           le16_to_cpu(ChannelInfoLength) < sizeof(*desc))
+       ch_count = le16_to_cpu(ChannelInfoLength) / sizeof(*desc);
+       if (ksmbd_debug_types & KSMBD_DEBUG_RDMA) {
+               for (i = 0; i < ch_count; i++) {
+                       pr_info("RDMA r/w request %#x: token %#x, length %#x\n",
+                               i,
+                               le32_to_cpu(desc[i].token),
+                               le32_to_cpu(desc[i].length));
+               }
+       }
+       if (ch_count != 1) {
+               ksmbd_debug(RDMA, "RDMA multiple buffer descriptors %d are not supported yet\n",
+                           ch_count);
                return -EINVAL;
+       }
 
        work->need_invalidate_rkey =
                (Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE);
@@ -6185,9 +6199,15 @@ int smb2_read(struct ksmbd_work *work)
 
        if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE ||
            req->Channel == SMB2_CHANNEL_RDMA_V1) {
+               unsigned int ch_offset = le16_to_cpu(req->ReadChannelInfoOffset);
+
+               if (ch_offset < offsetof(struct smb2_read_req, Buffer)) {
+                       err = -EINVAL;
+                       goto out;
+               }
                err = smb2_set_remote_key_for_rdma(work,
                                                   (struct smb2_buffer_desc_v1 *)
-                                                  &req->Buffer[0],
+                                                  ((char *)req + ch_offset),
                                                   req->Channel,
                                                   req->ReadChannelInfoOffset,
                                                   req->ReadChannelInfoLength);
@@ -6428,11 +6448,16 @@ int smb2_write(struct ksmbd_work *work)
 
        if (req->Channel == SMB2_CHANNEL_RDMA_V1 ||
            req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE) {
-               if (req->Length != 0 || req->DataOffset != 0)
-                       return -EINVAL;
+               unsigned int ch_offset = le16_to_cpu(req->WriteChannelInfoOffset);
+
+               if (req->Length != 0 || req->DataOffset != 0 ||
+                   ch_offset < offsetof(struct smb2_write_req, Buffer)) {
+                       err = -EINVAL;
+                       goto out;
+               }
                err = smb2_set_remote_key_for_rdma(work,
                                                   (struct smb2_buffer_desc_v1 *)
-                                                  &req->Buffer[0],
+                                                  ((char *)req + ch_offset),
                                                   req->Channel,
                                                   req->WriteChannelInfoOffset,
                                                   req->WriteChannelInfoLength);
index ef7f42b..9a7e211 100644 (file)
@@ -308,14 +308,17 @@ int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level,
        for (i = 0; i < 2; i++) {
                struct kstat kstat;
                struct ksmbd_kstat ksmbd_kstat;
+               struct dentry *dentry;
 
                if (!dir->dot_dotdot[i]) { /* fill dot entry info */
                        if (i == 0) {
                                d_info->name = ".";
                                d_info->name_len = 1;
+                               dentry = dir->filp->f_path.dentry;
                        } else {
                                d_info->name = "..";
                                d_info->name_len = 2;
+                               dentry = dir->filp->f_path.dentry->d_parent;
                        }
 
                        if (!match_pattern(d_info->name, d_info->name_len,
@@ -327,7 +330,7 @@ int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level,
                        ksmbd_kstat.kstat = &kstat;
                        ksmbd_vfs_fill_dentry_attrs(work,
                                                    user_ns,
-                                                   dir->filp->f_path.dentry->d_parent,
+                                                   dentry,
                                                    &ksmbd_kstat);
                        rc = fn(conn, info_level, d_info, &ksmbd_kstat);
                        if (rc)
index 3c1ec1a..ba5a22b 100644 (file)
@@ -80,7 +80,7 @@ static int smb_direct_max_fragmented_recv_size = 1024 * 1024;
 /*  The maximum single-message size which can be received */
 static int smb_direct_max_receive_size = 8192;
 
-static int smb_direct_max_read_write_size = 1048512;
+static int smb_direct_max_read_write_size = 524224;
 
 static int smb_direct_max_outstanding_rw_ops = 8;
 
index adf94a4..8c37aaf 100644 (file)
@@ -47,6 +47,7 @@ struct ksmbd_dir_info {
        int             last_entry_offset;
        bool            hide_dot_file;
        int             flags;
+       int             last_entry_off_align;
 };
 
 struct ksmbd_readdir_data {
index ba7438a..9741252 100644 (file)
@@ -1379,7 +1379,7 @@ bool is_empty_dir_inode(struct inode *inode)
                (inode->i_op == &empty_dir_inode_operations);
 }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 /*
  * Determine if the name of a dentry should be casefolded.
  *
@@ -1473,7 +1473,7 @@ static const struct dentry_operations generic_encrypted_dentry_ops = {
 };
 #endif
 
-#if defined(CONFIG_FS_ENCRYPTION) && defined(CONFIG_UNICODE)
+#if defined(CONFIG_FS_ENCRYPTION) && IS_ENABLED(CONFIG_UNICODE)
 static const struct dentry_operations generic_encrypted_ci_dentry_ops = {
        .d_hash = generic_ci_d_hash,
        .d_compare = generic_ci_d_compare,
@@ -1508,10 +1508,10 @@ void generic_set_encrypted_ci_d_ops(struct dentry *dentry)
 #ifdef CONFIG_FS_ENCRYPTION
        bool needs_encrypt_ops = dentry->d_flags & DCACHE_NOKEY_NAME;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        bool needs_ci_ops = dentry->d_sb->s_encoding;
 #endif
-#if defined(CONFIG_FS_ENCRYPTION) && defined(CONFIG_UNICODE)
+#if defined(CONFIG_FS_ENCRYPTION) && IS_ENABLED(CONFIG_UNICODE)
        if (needs_encrypt_ops && needs_ci_ops) {
                d_set_d_op(dentry, &generic_encrypted_ci_dentry_ops);
                return;
@@ -1523,7 +1523,7 @@ void generic_set_encrypted_ci_d_ops(struct dentry *dentry)
                return;
        }
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (needs_ci_ops) {
                d_set_d_op(dentry, &generic_ci_dentry_ops);
                return;
index cb3a751..0a22a2f 100644 (file)
@@ -179,19 +179,21 @@ nlm_delete_file(struct nlm_file *file)
 static int nlm_unlock_files(struct nlm_file *file)
 {
        struct file_lock lock;
-       struct file *f;
 
+       locks_init_lock(&lock);
        lock.fl_type  = F_UNLCK;
        lock.fl_start = 0;
        lock.fl_end   = OFFSET_MAX;
-       for (f = file->f_file[0]; f <= file->f_file[1]; f++) {
-               if (f && vfs_lock_file(f, F_SETLK, &lock, NULL) < 0) {
-                       pr_warn("lockd: unlock failure in %s:%d\n",
-                               __FILE__, __LINE__);
-                       return 1;
-               }
-       }
+       if (file->f_file[O_RDONLY] &&
+           vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, &lock, NULL))
+               goto out_err;
+       if (file->f_file[O_WRONLY] &&
+           vfs_lock_file(file->f_file[O_WRONLY], F_SETLK, &lock, NULL))
+               goto out_err;
        return 0;
+out_err:
+       pr_warn("lockd: unlock failure in %s:%d\n", __FILE__, __LINE__);
+       return 1;
 }
 
 /*
index b867a92..3f1829b 100644 (file)
@@ -4024,13 +4024,12 @@ int vfs_rmdir(struct user_namespace *mnt_userns, struct inode *dir,
        dentry->d_inode->i_flags |= S_DEAD;
        dont_mount(dentry);
        detach_mounts(dentry);
-       fsnotify_rmdir(dir, dentry);
 
 out:
        inode_unlock(dentry->d_inode);
        dput(dentry);
        if (!error)
-               d_delete(dentry);
+               d_delete_notify(dir, dentry);
        return error;
 }
 EXPORT_SYMBOL(vfs_rmdir);
@@ -4152,7 +4151,6 @@ int vfs_unlink(struct user_namespace *mnt_userns, struct inode *dir,
                        if (!error) {
                                dont_mount(dentry);
                                detach_mounts(dentry);
-                               fsnotify_unlink(dir, dentry);
                        }
                }
        }
@@ -4160,9 +4158,11 @@ out:
        inode_unlock(target);
 
        /* We don't d_delete() NFS sillyrenamed files--they still exist. */
-       if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
+       if (!error && dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+               fsnotify_unlink(dir, dentry);
+       } else if (!error) {
                fsnotify_link_count(target);
-               d_delete(dentry);
+               d_delete_notify(dir, dentry);
        }
 
        return error;
index 6a20331..ccd4f24 100644 (file)
@@ -170,7 +170,7 @@ struct cb_devicenotifyitem {
 };
 
 struct cb_devicenotifyargs {
-       int                              ndevs;
+       uint32_t                         ndevs;
        struct cb_devicenotifyitem       *devs;
 };
 
index 09c5b1c..c343666 100644 (file)
@@ -358,7 +358,7 @@ __be32 nfs4_callback_devicenotify(void *argp, void *resp,
                                  struct cb_process_state *cps)
 {
        struct cb_devicenotifyargs *args = argp;
-       int i;
+       uint32_t i;
        __be32 res = 0;
        struct nfs_client *clp = cps->clp;
        struct nfs_server *server = NULL;
index a67c41e..f90de80 100644 (file)
@@ -258,11 +258,9 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
                                void *argp)
 {
        struct cb_devicenotifyargs *args = argp;
+       uint32_t tmp, n, i;
        __be32 *p;
        __be32 status = 0;
-       u32 tmp;
-       int n, i;
-       args->ndevs = 0;
 
        /* Num of device notifications */
        p = xdr_inline_decode(xdr, sizeof(uint32_t));
@@ -271,7 +269,7 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
                goto out;
        }
        n = ntohl(*p++);
-       if (n <= 0)
+       if (n == 0)
                goto out;
        if (n > ULONG_MAX / sizeof(*args->devs)) {
                status = htonl(NFS4ERR_BADXDR);
@@ -330,19 +328,21 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
                        dev->cbd_immediate = 0;
                }
 
-               args->ndevs++;
-
                dprintk("%s: type %d layout 0x%x immediate %d\n",
                        __func__, dev->cbd_notify_type, dev->cbd_layout_type,
                        dev->cbd_immediate);
        }
+       args->ndevs = n;
+       dprintk("%s: ndevs %d\n", __func__, args->ndevs);
+       return 0;
+err:
+       kfree(args->devs);
 out:
+       args->devs = NULL;
+       args->ndevs = 0;
        dprintk("%s: status %d ndevs %d\n",
                __func__, ntohl(status), args->ndevs);
        return status;
-err:
-       kfree(args->devs);
-       goto out;
 }
 
 static __be32 decode_sessionid(struct xdr_stream *xdr,
index 8d8b85b..d1f3422 100644 (file)
@@ -177,6 +177,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
        INIT_LIST_HEAD(&clp->cl_superblocks);
        clp->cl_rpcclient = ERR_PTR(-EINVAL);
 
+       clp->cl_flags = cl_init->init_flags;
        clp->cl_proto = cl_init->proto;
        clp->cl_nconnect = cl_init->nconnect;
        clp->cl_max_connect = cl_init->max_connect ? cl_init->max_connect : 1;
@@ -423,7 +424,6 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init)
                        list_add_tail(&new->cl_share_link,
                                        &nn->nfs_client_list);
                        spin_unlock(&nn->nfs_client_lock);
-                       new->cl_flags = cl_init->init_flags;
                        return rpc_ops->init_client(new, cl_init);
                }
 
@@ -856,6 +856,13 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str
                        server->namelen = pathinfo.max_namelen;
        }
 
+       if (clp->rpc_ops->discover_trunking != NULL &&
+                       (server->caps & NFS_CAP_FS_LOCATIONS)) {
+               error = clp->rpc_ops->discover_trunking(server, mntfh);
+               if (error < 0)
+                       return error;
+       }
+
        return 0;
 }
 
index 3477936..7bc7cf6 100644 (file)
@@ -80,6 +80,7 @@ static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir
                ctx->dir_cookie = 0;
                ctx->dup_cookie = 0;
                ctx->page_index = 0;
+               ctx->eof = false;
                spin_lock(&dir->i_lock);
                if (list_empty(&nfsi->open_files) &&
                    (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER))
@@ -168,6 +169,7 @@ struct nfs_readdir_descriptor {
        unsigned int    cache_entry_index;
        signed char duped;
        bool plus;
+       bool eob;
        bool eof;
 };
 
@@ -867,7 +869,8 @@ static int nfs_readdir_xdr_to_array(struct nfs_readdir_descriptor *desc,
 
                status = nfs_readdir_page_filler(desc, entry, pages, pglen,
                                                 arrays, narrays);
-       } while (!status && nfs_readdir_page_needs_filling(page));
+       } while (!status && nfs_readdir_page_needs_filling(page) &&
+               page_mapping(page));
 
        nfs_readdir_free_pages(pages, array_size);
 out:
@@ -988,7 +991,7 @@ static void nfs_do_filldir(struct nfs_readdir_descriptor *desc,
                ent = &array->array[i];
                if (!dir_emit(desc->ctx, ent->name, ent->name_len,
                    nfs_compat_user_ino64(ent->ino), ent->d_type)) {
-                       desc->eof = true;
+                       desc->eob = true;
                        break;
                }
                memcpy(desc->verf, verf, sizeof(desc->verf));
@@ -1004,7 +1007,7 @@ static void nfs_do_filldir(struct nfs_readdir_descriptor *desc,
                        desc->duped = 1;
        }
        if (array->page_is_eof)
-               desc->eof = true;
+               desc->eof = !desc->eob;
 
        kunmap(desc->page);
        dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %llu\n",
@@ -1041,12 +1044,13 @@ static int uncached_readdir(struct nfs_readdir_descriptor *desc)
                goto out;
 
        desc->page_index = 0;
+       desc->cache_entry_index = 0;
        desc->last_cookie = desc->dir_cookie;
        desc->duped = 0;
 
        status = nfs_readdir_xdr_to_array(desc, desc->verf, verf, arrays, sz);
 
-       for (i = 0; !desc->eof && i < sz && arrays[i]; i++) {
+       for (i = 0; !desc->eob && i < sz && arrays[i]; i++) {
                desc->page = arrays[i];
                nfs_do_filldir(desc, verf);
        }
@@ -1105,9 +1109,15 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
        desc->duped = dir_ctx->duped;
        page_index = dir_ctx->page_index;
        desc->attr_gencount = dir_ctx->attr_gencount;
+       desc->eof = dir_ctx->eof;
        memcpy(desc->verf, dir_ctx->verf, sizeof(desc->verf));
        spin_unlock(&file->f_lock);
 
+       if (desc->eof) {
+               res = 0;
+               goto out_free;
+       }
+
        if (test_and_clear_bit(NFS_INO_FORCE_READDIR, &nfsi->flags) &&
            list_is_singular(&nfsi->open_files))
                invalidate_mapping_pages(inode->i_mapping, page_index + 1, -1);
@@ -1141,7 +1151,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
 
                nfs_do_filldir(desc, nfsi->cookieverf);
                nfs_readdir_page_unlock_and_put_cached(desc);
-       } while (!desc->eof);
+       } while (!desc->eob && !desc->eof);
 
        spin_lock(&file->f_lock);
        dir_ctx->dir_cookie = desc->dir_cookie;
@@ -1149,9 +1159,10 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
        dir_ctx->duped = desc->duped;
        dir_ctx->attr_gencount = desc->attr_gencount;
        dir_ctx->page_index = desc->page_index;
+       dir_ctx->eof = desc->eof;
        memcpy(dir_ctx->verf, desc->verf, sizeof(dir_ctx->verf));
        spin_unlock(&file->f_lock);
-
+out_free:
        kfree(desc);
 
 out:
@@ -1193,6 +1204,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
                if (offset == 0)
                        memset(dir_ctx->verf, 0, sizeof(dir_ctx->verf));
                dir_ctx->duped = 0;
+               dir_ctx->eof = false;
        }
        spin_unlock(&filp->f_lock);
        return offset;
@@ -1325,6 +1337,14 @@ void nfs_clear_verifier_delegated(struct inode *inode)
 EXPORT_SYMBOL_GPL(nfs_clear_verifier_delegated);
 #endif /* IS_ENABLED(CONFIG_NFS_V4) */
 
+static int nfs_dentry_verify_change(struct inode *dir, struct dentry *dentry)
+{
+       if (nfs_server_capable(dir, NFS_CAP_CASE_INSENSITIVE) &&
+           d_really_is_negative(dentry))
+               return dentry->d_time == inode_peek_iversion_raw(dir);
+       return nfs_verify_change_attribute(dir, dentry->d_time);
+}
+
 /*
  * A check for whether or not the parent directory has changed.
  * In the case it has, we assume that the dentries are untrustworthy
@@ -1338,7 +1358,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry,
                return 1;
        if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONE)
                return 0;
-       if (!nfs_verify_change_attribute(dir, dentry->d_time))
+       if (!nfs_dentry_verify_change(dir, dentry))
                return 0;
        /* Revalidate nfsi->cache_change_attribute before we declare a match */
        if (nfs_mapping_need_revalidate_inode(dir)) {
@@ -1347,7 +1367,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry,
                if (__nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
                        return 0;
        }
-       if (!nfs_verify_change_attribute(dir, dentry->d_time))
+       if (!nfs_dentry_verify_change(dir, dentry))
                return 0;
        return 1;
 }
@@ -1437,6 +1457,9 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
                return 0;
        if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG)
                return 1;
+       /* Case insensitive server? Revalidate negative dentries */
+       if (nfs_server_capable(dir, NFS_CAP_CASE_INSENSITIVE))
+               return 1;
        return !nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU);
 }
 
@@ -1537,7 +1560,7 @@ out:
         * If the lookup failed despite the dentry change attribute being
         * a match, then we should revalidate the directory cache.
         */
-       if (!ret && nfs_verify_change_attribute(dir, dentry->d_time))
+       if (!ret && nfs_dentry_verify_change(dir, dentry))
                nfs_mark_dir_for_revalidate(dir);
        return nfs_lookup_revalidate_done(dir, dentry, inode, ret);
 }
@@ -1776,8 +1799,11 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
        dir_verifier = nfs_save_change_attribute(dir);
        trace_nfs_lookup_enter(dir, dentry, flags);
        error = NFS_PROTO(dir)->lookup(dir, dentry, fhandle, fattr);
-       if (error == -ENOENT)
+       if (error == -ENOENT) {
+               if (nfs_server_capable(dir, NFS_CAP_CASE_INSENSITIVE))
+                       dir_verifier = inode_peek_iversion_raw(dir);
                goto no_entry;
+       }
        if (error < 0) {
                res = ERR_PTR(error);
                goto out;
@@ -1806,6 +1832,14 @@ out:
 }
 EXPORT_SYMBOL_GPL(nfs_lookup);
 
+void nfs_d_prune_case_insensitive_aliases(struct inode *inode)
+{
+       /* Case insensitive server? Revalidate dentries */
+       if (inode && nfs_server_capable(inode, NFS_CAP_CASE_INSENSITIVE))
+               d_prune_aliases(inode);
+}
+EXPORT_SYMBOL_GPL(nfs_d_prune_case_insensitive_aliases);
+
 #if IS_ENABLED(CONFIG_NFS_V4)
 static int nfs4_lookup_revalidate(struct dentry *, unsigned int);
 
@@ -1867,6 +1901,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
        struct iattr attr = { .ia_valid = ATTR_OPEN };
        struct inode *inode;
        unsigned int lookup_flags = 0;
+       unsigned long dir_verifier;
        bool switched = false;
        int created = 0;
        int err;
@@ -1940,7 +1975,11 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
                switch (err) {
                case -ENOENT:
                        d_splice_alias(NULL, dentry);
-                       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+                       if (nfs_server_capable(dir, NFS_CAP_CASE_INSENSITIVE))
+                               dir_verifier = inode_peek_iversion_raw(dir);
+                       else
+                               dir_verifier = nfs_save_change_attribute(dir);
+                       nfs_set_verifier(dentry, dir_verifier);
                        break;
                case -EISDIR:
                case -ENOTDIR:
@@ -1968,6 +2007,24 @@ out:
 
 no_open:
        res = nfs_lookup(dir, dentry, lookup_flags);
+       if (!res) {
+               inode = d_inode(dentry);
+               if ((lookup_flags & LOOKUP_DIRECTORY) && inode &&
+                   !S_ISDIR(inode->i_mode))
+                       res = ERR_PTR(-ENOTDIR);
+               else if (inode && S_ISREG(inode->i_mode))
+                       res = ERR_PTR(-EOPENSTALE);
+       } else if (!IS_ERR(res)) {
+               inode = d_inode(res);
+               if ((lookup_flags & LOOKUP_DIRECTORY) && inode &&
+                   !S_ISDIR(inode->i_mode)) {
+                       dput(res);
+                       res = ERR_PTR(-ENOTDIR);
+               } else if (inode && S_ISREG(inode->i_mode)) {
+                       dput(res);
+                       res = ERR_PTR(-EOPENSTALE);
+               }
+       }
        if (switched) {
                d_lookup_done(dentry);
                if (!res)
@@ -2186,8 +2243,10 @@ static void nfs_dentry_remove_handle_error(struct inode *dir,
        switch (error) {
        case -ENOENT:
                d_delete(dentry);
-               fallthrough;
+               nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+               break;
        case 0:
+               nfs_d_prune_case_insensitive_aliases(d_inode(dentry));
                nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        }
 }
@@ -2380,6 +2439,8 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 
        trace_nfs_link_enter(inode, dir, dentry);
        d_drop(dentry);
+       if (S_ISREG(inode->i_mode))
+               nfs_sync_inode(inode);
        error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
        if (error == 0) {
                nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
@@ -2469,6 +2530,8 @@ int nfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
                }
        }
 
+       if (S_ISREG(old_inode->i_mode))
+               nfs_sync_inode(old_inode);
        task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, NULL);
        if (IS_ERR(task)) {
                error = PTR_ERR(task);
@@ -2529,7 +2592,7 @@ MODULE_PARM_DESC(nfs_access_max_cachesize, "NFS access maximum total cache lengt
 
 static void nfs_access_free_entry(struct nfs_access_entry *entry)
 {
-       put_cred(entry->cred);
+       put_group_info(entry->group_info);
        kfree_rcu(entry, rcu_head);
        smp_mb__before_atomic();
        atomic_long_dec(&nfs_access_nr_entries);
@@ -2655,6 +2718,43 @@ void nfs_access_zap_cache(struct inode *inode)
 }
 EXPORT_SYMBOL_GPL(nfs_access_zap_cache);
 
+static int access_cmp(const struct cred *a, const struct nfs_access_entry *b)
+{
+       struct group_info *ga, *gb;
+       int g;
+
+       if (uid_lt(a->fsuid, b->fsuid))
+               return -1;
+       if (uid_gt(a->fsuid, b->fsuid))
+               return 1;
+
+       if (gid_lt(a->fsgid, b->fsgid))
+               return -1;
+       if (gid_gt(a->fsgid, b->fsgid))
+               return 1;
+
+       ga = a->group_info;
+       gb = b->group_info;
+       if (ga == gb)
+               return 0;
+       if (ga == NULL)
+               return -1;
+       if (gb == NULL)
+               return 1;
+       if (ga->ngroups < gb->ngroups)
+               return -1;
+       if (ga->ngroups > gb->ngroups)
+               return 1;
+
+       for (g = 0; g < ga->ngroups; g++) {
+               if (gid_lt(ga->gid[g], gb->gid[g]))
+                       return -1;
+               if (gid_gt(ga->gid[g], gb->gid[g]))
+                       return 1;
+       }
+       return 0;
+}
+
 static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, const struct cred *cred)
 {
        struct rb_node *n = NFS_I(inode)->access_cache.rb_node;
@@ -2662,7 +2762,7 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, co
        while (n != NULL) {
                struct nfs_access_entry *entry =
                        rb_entry(n, struct nfs_access_entry, rb_node);
-               int cmp = cred_fscmp(cred, entry->cred);
+               int cmp = access_cmp(cred, entry);
 
                if (cmp < 0)
                        n = n->rb_left;
@@ -2674,7 +2774,7 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, co
        return NULL;
 }
 
-static int nfs_access_get_cached_locked(struct inode *inode, const struct cred *cred, struct nfs_access_entry *res, bool may_block)
+static int nfs_access_get_cached_locked(struct inode *inode, const struct cred *cred, u32 *mask, bool may_block)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        struct nfs_access_entry *cache;
@@ -2704,8 +2804,7 @@ static int nfs_access_get_cached_locked(struct inode *inode, const struct cred *
                spin_lock(&inode->i_lock);
                retry = false;
        }
-       res->cred = cache->cred;
-       res->mask = cache->mask;
+       *mask = cache->mask;
        list_move_tail(&cache->lru, &nfsi->access_cache_entry_lru);
        err = 0;
 out:
@@ -2717,7 +2816,7 @@ out_zap:
        return -ENOENT;
 }
 
-static int nfs_access_get_cached_rcu(struct inode *inode, const struct cred *cred, struct nfs_access_entry *res)
+static int nfs_access_get_cached_rcu(struct inode *inode, const struct cred *cred, u32 *mask)
 {
        /* Only check the most recently returned cache entry,
         * but do it without locking.
@@ -2733,35 +2832,36 @@ static int nfs_access_get_cached_rcu(struct inode *inode, const struct cred *cre
        lh = rcu_dereference(list_tail_rcu(&nfsi->access_cache_entry_lru));
        cache = list_entry(lh, struct nfs_access_entry, lru);
        if (lh == &nfsi->access_cache_entry_lru ||
-           cred_fscmp(cred, cache->cred) != 0)
+           access_cmp(cred, cache) != 0)
                cache = NULL;
        if (cache == NULL)
                goto out;
        if (nfs_check_cache_invalid(inode, NFS_INO_INVALID_ACCESS))
                goto out;
-       res->cred = cache->cred;
-       res->mask = cache->mask;
+       *mask = cache->mask;
        err = 0;
 out:
        rcu_read_unlock();
        return err;
 }
 
-int nfs_access_get_cached(struct inode *inode, const struct cred *cred, struct
-nfs_access_entry *res, bool may_block)
+int nfs_access_get_cached(struct inode *inode, const struct cred *cred,
+                         u32 *mask, bool may_block)
 {
        int status;
 
-       status = nfs_access_get_cached_rcu(inode, cred, res);
+       status = nfs_access_get_cached_rcu(inode, cred, mask);
        if (status != 0)
-               status = nfs_access_get_cached_locked(inode, cred, res,
+               status = nfs_access_get_cached_locked(inode, cred, mask,
                    may_block);
 
        return status;
 }
 EXPORT_SYMBOL_GPL(nfs_access_get_cached);
 
-static void nfs_access_add_rbtree(struct inode *inode, struct nfs_access_entry *set)
+static void nfs_access_add_rbtree(struct inode *inode,
+                                 struct nfs_access_entry *set,
+                                 const struct cred *cred)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        struct rb_root *root_node = &nfsi->access_cache;
@@ -2774,7 +2874,7 @@ static void nfs_access_add_rbtree(struct inode *inode, struct nfs_access_entry *
        while (*p != NULL) {
                parent = *p;
                entry = rb_entry(parent, struct nfs_access_entry, rb_node);
-               cmp = cred_fscmp(set->cred, entry->cred);
+               cmp = access_cmp(cred, entry);
 
                if (cmp < 0)
                        p = &parent->rb_left;
@@ -2796,13 +2896,16 @@ found:
        nfs_access_free_entry(entry);
 }
 
-void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
+void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set,
+                         const struct cred *cred)
 {
        struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL);
        if (cache == NULL)
                return;
        RB_CLEAR_NODE(&cache->rb_node);
-       cache->cred = get_cred(set->cred);
+       cache->fsuid = cred->fsuid;
+       cache->fsgid = cred->fsgid;
+       cache->group_info = get_group_info(cred->group_info);
        cache->mask = set->mask;
 
        /* The above field assignments must be visible
@@ -2810,7 +2913,7 @@ void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
         * use rcu_assign_pointer, so just force the memory barrier.
         */
        smp_wmb();
-       nfs_access_add_rbtree(inode, cache);
+       nfs_access_add_rbtree(inode, cache, cred);
 
        /* Update accounting */
        smp_mb__before_atomic();
@@ -2875,7 +2978,7 @@ static int nfs_do_access(struct inode *inode, const struct cred *cred, int mask)
 
        trace_nfs_access_enter(inode);
 
-       status = nfs_access_get_cached(inode, cred, &cache, may_block);
+       status = nfs_access_get_cached(inode, cred, &cache.mask, may_block);
        if (status == 0)
                goto out_cached;
 
@@ -2895,8 +2998,7 @@ static int nfs_do_access(struct inode *inode, const struct cred *cred, int mask)
                cache.mask |= NFS_ACCESS_DELETE | NFS_ACCESS_LOOKUP;
        else
                cache.mask |= NFS_ACCESS_EXECUTE;
-       cache.cred = cred;
-       status = NFS_PROTO(inode)->access(inode, &cache);
+       status = NFS_PROTO(inode)->access(inode, &cache, cred);
        if (status != 0) {
                if (status == -ESTALE) {
                        if (!S_ISDIR(inode->i_mode))
@@ -2906,7 +3008,7 @@ static int nfs_do_access(struct inode *inode, const struct cred *cred, int mask)
                }
                goto out;
        }
-       nfs_access_add_cache(inode, &cache);
+       nfs_access_add_cache(inode, &cache, cred);
 out_cached:
        cache_mask = nfs_access_calc_mask(cache.mask, inode->i_mode);
        if ((mask & ~cache_mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) != 0)
index 79323b5..aed0748 100644 (file)
@@ -51,7 +51,7 @@ struct nfs4_file_layout_dsaddr {
        u32                             stripe_count;
        u8                              *stripe_indices;
        u32                             ds_num;
-       struct nfs4_pnfs_ds             *ds_list[1];
+       struct nfs4_pnfs_ds             *ds_list[];
 };
 
 struct nfs4_filelayout_segment {
index 86c3f7e..acf4b88 100644 (file)
@@ -136,9 +136,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
                goto out_err_free_stripe_indices;
        }
 
-       dsaddr = kzalloc(sizeof(*dsaddr) +
-                       (sizeof(struct nfs4_pnfs_ds *) * (num - 1)),
-                       gfp_flags);
+       dsaddr = kzalloc(struct_size(dsaddr, ds_list, num), gfp_flags);
        if (!dsaddr)
                goto out_err_free_stripe_indices;
 
index 12f6acb..2de7c56 100644 (file)
@@ -373,6 +373,7 @@ extern unsigned long nfs_access_cache_count(struct shrinker *shrink,
 extern unsigned long nfs_access_cache_scan(struct shrinker *shrink,
                                           struct shrink_control *sc);
 struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int);
+void nfs_d_prune_case_insensitive_aliases(struct inode *inode);
 int nfs_create(struct user_namespace *, struct inode *, struct dentry *,
               umode_t, bool);
 int nfs_mkdir(struct user_namespace *, struct inode *, struct dentry *,
index 7100514..1597eef 100644 (file)
@@ -220,7 +220,8 @@ static int nfs3_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle,
                                  task_flags);
 }
 
-static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry)
+static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry,
+                           const struct cred *cred)
 {
        struct nfs3_accessargs  arg = {
                .fh             = NFS_FH(inode),
@@ -231,7 +232,7 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry)
                .rpc_proc       = &nfs3_procedures[NFS3PROC_ACCESS],
                .rpc_argp       = &arg,
                .rpc_resp       = &res,
-               .rpc_cred       = entry->cred,
+               .rpc_cred       = cred,
        };
        int status = -ENOMEM;
 
index 8b21ff1..3212944 100644 (file)
@@ -46,7 +46,7 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
 {
        struct inode *inode = file_inode(filep);
        struct nfs_server *server = NFS_SERVER(inode);
-       u32 bitmask[3];
+       u32 bitmask[NFS_BITMASK_SZ];
        struct nfs42_falloc_args args = {
                .falloc_fh      = NFS_FH(inode),
                .falloc_offset  = offset,
@@ -69,9 +69,8 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
                return status;
        }
 
-       memcpy(bitmask, server->cache_consistency_bitmask, sizeof(bitmask));
-       if (server->attr_bitmask[1] & FATTR4_WORD1_SPACE_USED)
-               bitmask[1] |= FATTR4_WORD1_SPACE_USED;
+       nfs4_bitmask_set(bitmask, server->cache_consistency_bitmask, inode,
+                        NFS_INO_INVALID_BLOCKS);
 
        res.falloc_fattr = nfs_alloc_fattr();
        if (!res.falloc_fattr)
@@ -1044,13 +1043,14 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
        struct inode *src_inode = file_inode(src_f);
        struct inode *dst_inode = file_inode(dst_f);
        struct nfs_server *server = NFS_SERVER(dst_inode);
+       __u32 dst_bitmask[NFS_BITMASK_SZ];
        struct nfs42_clone_args args = {
                .src_fh = NFS_FH(src_inode),
                .dst_fh = NFS_FH(dst_inode),
                .src_offset = src_offset,
                .dst_offset = dst_offset,
                .count = count,
-               .dst_bitmask = server->cache_consistency_bitmask,
+               .dst_bitmask = dst_bitmask,
        };
        struct nfs42_clone_res res = {
                .server = server,
@@ -1079,6 +1079,9 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
        if (!res.dst_fattr)
                return -ENOMEM;
 
+       nfs4_bitmask_set(dst_bitmask, server->cache_consistency_bitmask,
+                        dst_inode, NFS_INO_INVALID_BLOCKS);
+
        status = nfs4_call_sync(server->client, server, msg,
                                &args.seq_args, &res.seq_res, 0);
        trace_nfs4_clone(src_inode, dst_inode, &args, status);
index ed5eaca..84f39b6 100644 (file)
@@ -260,8 +260,8 @@ struct nfs4_state_maintenance_ops {
 };
 
 struct nfs4_mig_recovery_ops {
-       int (*get_locations)(struct inode *, struct nfs4_fs_locations *,
-               struct page *, const struct cred *);
+       int (*get_locations)(struct nfs_server *, struct nfs_fh *,
+               struct nfs4_fs_locations *, struct page *, const struct cred *);
        int (*fsid_present)(struct inode *, const struct cred *);
 };
 
@@ -280,7 +280,8 @@ struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *,
 int nfs4_submount(struct fs_context *, struct nfs_server *);
 int nfs4_replace_transport(struct nfs_server *server,
                                const struct nfs4_fs_locations *locations);
-
+size_t nfs_parse_server_name(char *string, size_t len, struct sockaddr *sa,
+                            size_t salen, struct net *net, int port);
 /* nfs4proc.c */
 extern int nfs4_handle_exception(struct nfs_server *, int, struct nfs4_exception *);
 extern int nfs4_async_handle_error(struct rpc_task *task,
@@ -302,8 +303,9 @@ extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait);
 extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
 extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *,
                                  struct nfs4_fs_locations *, struct page *);
-extern int nfs4_proc_get_locations(struct inode *, struct nfs4_fs_locations *,
-               struct page *page, const struct cred *);
+extern int nfs4_proc_get_locations(struct nfs_server *, struct nfs_fh *,
+                                  struct nfs4_fs_locations *,
+                                  struct page *page, const struct cred *);
 extern int nfs4_proc_fsid_present(struct inode *, const struct cred *);
 extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *,
                                                    struct dentry *,
@@ -315,6 +317,8 @@ extern int nfs4_set_rw_stateid(nfs4_stateid *stateid,
                const struct nfs_open_context *ctx,
                const struct nfs_lock_context *l_ctx,
                fmode_t fmode);
+extern void nfs4_bitmask_set(__u32 bitmask[], const __u32 src[],
+                            struct inode *inode, unsigned long cache_validity);
 extern int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
                             struct nfs_fattr *fattr, struct inode *inode);
 extern int update_open_stateid(struct nfs4_state *state,
index d8b5a25..47a6cf8 100644 (file)
@@ -1343,8 +1343,11 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
        }
        nfs_put_client(clp);
 
-       if (server->nfs_client->cl_hostname == NULL)
+       if (server->nfs_client->cl_hostname == NULL) {
                server->nfs_client->cl_hostname = kstrdup(hostname, GFP_KERNEL);
+               if (server->nfs_client->cl_hostname == NULL)
+                       return -ENOMEM;
+       }
        nfs_server_insert_lists(server);
 
        return nfs_probe_server(server, NFS_FH(d_inode(server->super->s_root)));
index 8733423..3680c8d 100644 (file)
@@ -164,16 +164,21 @@ static int nfs4_validate_fspath(struct dentry *dentry,
        return 0;
 }
 
-static size_t nfs_parse_server_name(char *string, size_t len,
-               struct sockaddr *sa, size_t salen, struct net *net)
+size_t nfs_parse_server_name(char *string, size_t len, struct sockaddr *sa,
+                            size_t salen, struct net *net, int port)
 {
        ssize_t ret;
 
        ret = rpc_pton(net, string, len, sa, salen);
        if (ret == 0) {
-               ret = nfs_dns_resolve_name(net, string, len, sa, salen);
-               if (ret < 0)
-                       ret = 0;
+               ret = rpc_uaddr2sockaddr(net, string, len, sa, salen);
+               if (ret == 0) {
+                       ret = nfs_dns_resolve_name(net, string, len, sa, salen);
+                       if (ret < 0)
+                               ret = 0;
+               }
+       } else if (port) {
+               rpc_set_port(sa, port);
        }
        return ret;
 }
@@ -328,7 +333,7 @@ static int try_location(struct fs_context *fc,
                        nfs_parse_server_name(buf->data, buf->len,
                                              &ctx->nfs_server.address,
                                              sizeof(ctx->nfs_server._address),
-                                             fc->net_ns);
+                                             fc->net_ns, 0);
                if (ctx->nfs_server.addrlen == 0)
                        continue;
 
@@ -496,7 +501,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server,
                        continue;
 
                salen = nfs_parse_server_name(buf->data, buf->len,
-                                               sap, addr_bufsize, net);
+                                               sap, addr_bufsize, net, 0);
                if (salen == 0)
                        continue;
                rpc_set_port(sap, NFS_PORT);
index ee3bc79..f502082 100644 (file)
@@ -108,10 +108,6 @@ static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *,
 static int nfs41_free_stateid(struct nfs_server *, const nfs4_stateid *,
                const struct cred *, bool);
 #endif
-static void nfs4_bitmask_set(__u32 bitmask[NFS4_BITMASK_SZ],
-                            const __u32 *src, struct inode *inode,
-                            struct nfs_server *server,
-                            struct nfs4_label *label);
 
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
 static inline struct nfs4_label *
@@ -2653,9 +2649,8 @@ static int nfs4_opendata_access(const struct cred *cred,
        } else if ((fmode & FMODE_READ) && !opendata->file_created)
                mask = NFS4_ACCESS_READ;
 
-       cache.cred = cred;
        nfs_access_set_mask(&cache, opendata->o_res.access_result);
-       nfs_access_add_cache(state->inode, &cache);
+       nfs_access_add_cache(state->inode, &cache, cred);
 
        flags = NFS4_ACCESS_READ | NFS4_ACCESS_EXECUTE | NFS4_ACCESS_LOOKUP;
        if ((mask & ~cache.mask & flags) == 0)
@@ -3670,7 +3665,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
                if (!nfs4_have_delegation(inode, FMODE_READ)) {
                        nfs4_bitmask_set(calldata->arg.bitmask_store,
                                         server->cache_consistency_bitmask,
-                                        inode, server, NULL);
+                                        inode, 0);
                        calldata->arg.bitmask = calldata->arg.bitmask_store;
                } else
                        calldata->arg.bitmask = NULL;
@@ -3841,7 +3836,9 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
                     FATTR4_WORD0_FH_EXPIRE_TYPE |
                     FATTR4_WORD0_LINK_SUPPORT |
                     FATTR4_WORD0_SYMLINK_SUPPORT |
-                    FATTR4_WORD0_ACLSUPPORT;
+                    FATTR4_WORD0_ACLSUPPORT |
+                    FATTR4_WORD0_CASE_INSENSITIVE |
+                    FATTR4_WORD0_CASE_PRESERVING;
        if (minorversion)
                bitmask[2] = FATTR4_WORD2_SUPPATTR_EXCLCREAT;
 
@@ -3870,10 +3867,16 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
                        server->caps |= NFS_CAP_HARDLINKS;
                if (res.has_symlinks != 0)
                        server->caps |= NFS_CAP_SYMLINKS;
+               if (res.case_insensitive)
+                       server->caps |= NFS_CAP_CASE_INSENSITIVE;
+               if (res.case_preserving)
+                       server->caps |= NFS_CAP_CASE_PRESERVING;
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
                if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL)
                        server->caps |= NFS_CAP_SECURITY_LABEL;
 #endif
+               if (res.attr_bitmask[0] & FATTR4_WORD0_FS_LOCATIONS)
+                       server->caps |= NFS_CAP_FS_LOCATIONS;
                if (!(res.attr_bitmask[0] & FATTR4_WORD0_FILEID))
                        server->fattr_valid &= ~NFS_ATTR_FATTR_FILEID;
                if (!(res.attr_bitmask[1] & FATTR4_WORD1_MODE))
@@ -3932,6 +3935,114 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
        return err;
 }
 
+static void test_fs_location_for_trunking(struct nfs4_fs_location *location,
+                                         struct nfs_client *clp,
+                                         struct nfs_server *server)
+{
+       int i;
+
+       for (i = 0; i < location->nservers; i++) {
+               struct nfs4_string *srv_loc = &location->servers[i];
+               struct sockaddr addr;
+               size_t addrlen;
+               struct xprt_create xprt_args = {
+                       .ident = 0,
+                       .net = clp->cl_net,
+               };
+               struct nfs4_add_xprt_data xprtdata = {
+                       .clp = clp,
+               };
+               struct rpc_add_xprt_test rpcdata = {
+                       .add_xprt_test = clp->cl_mvops->session_trunk,
+                       .data = &xprtdata,
+               };
+               char *servername = NULL;
+
+               if (!srv_loc->len)
+                       continue;
+
+               addrlen = nfs_parse_server_name(srv_loc->data, srv_loc->len,
+                                               &addr, sizeof(addr),
+                                               clp->cl_net, server->port);
+               if (!addrlen)
+                       return;
+               xprt_args.dstaddr = &addr;
+               xprt_args.addrlen = addrlen;
+               servername = kmalloc(srv_loc->len + 1, GFP_KERNEL);
+               if (!servername)
+                       return;
+               memcpy(servername, srv_loc->data, srv_loc->len);
+               servername[srv_loc->len] = '\0';
+               xprt_args.servername = servername;
+
+               xprtdata.cred = nfs4_get_clid_cred(clp);
+               rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
+                                 rpc_clnt_setup_test_and_add_xprt,
+                                 &rpcdata);
+               if (xprtdata.cred)
+                       put_cred(xprtdata.cred);
+               kfree(servername);
+       }
+}
+
+static int _nfs4_discover_trunking(struct nfs_server *server,
+                                  struct nfs_fh *fhandle)
+{
+       struct nfs4_fs_locations *locations = NULL;
+       struct page *page;
+       const struct cred *cred;
+       struct nfs_client *clp = server->nfs_client;
+       const struct nfs4_state_maintenance_ops *ops =
+               clp->cl_mvops->state_renewal_ops;
+       int status = -ENOMEM, i;
+
+       cred = ops->get_state_renewal_cred(clp);
+       if (cred == NULL) {
+               cred = nfs4_get_clid_cred(clp);
+               if (cred == NULL)
+                       return -ENOKEY;
+       }
+
+       page = alloc_page(GFP_KERNEL);
+       locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
+       if (page == NULL || locations == NULL)
+               goto out;
+
+       status = nfs4_proc_get_locations(server, fhandle, locations, page,
+                                        cred);
+       if (status)
+               goto out;
+
+       for (i = 0; i < locations->nlocations; i++)
+               test_fs_location_for_trunking(&locations->locations[i], clp,
+                                             server);
+out:
+       if (page)
+               __free_page(page);
+       kfree(locations);
+       return status;
+}
+
+static int nfs4_discover_trunking(struct nfs_server *server,
+                                 struct nfs_fh *fhandle)
+{
+       struct nfs4_exception exception = {
+               .interruptible = true,
+       };
+       struct nfs_client *clp = server->nfs_client;
+       int err = 0;
+
+       if (!nfs4_has_session(clp))
+               goto out;
+       do {
+               err = nfs4_handle_exception(server,
+                               _nfs4_discover_trunking(server, fhandle),
+                               &exception);
+       } while (exception.retry);
+out:
+       return err;
+}
+
 static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
                struct nfs_fsinfo *info)
 {
@@ -4441,7 +4552,8 @@ static int nfs4_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle,
        return err;
 }
 
-static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
+static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry,
+                            const struct cred *cred)
 {
        struct nfs_server *server = NFS_SERVER(inode);
        struct nfs4_accessargs args = {
@@ -4455,7 +4567,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
                .rpc_argp = &args,
                .rpc_resp = &res,
-               .rpc_cred = entry->cred,
+               .rpc_cred = cred,
        };
        int status = 0;
 
@@ -4475,14 +4587,15 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
        return status;
 }
 
-static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
+static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry,
+                           const struct cred *cred)
 {
        struct nfs4_exception exception = {
                .interruptible = true,
        };
        int err;
        do {
-               err = _nfs4_proc_access(inode, entry);
+               err = _nfs4_proc_access(inode, entry, cred);
                trace_nfs4_access(inode, err);
                err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
@@ -4663,8 +4776,10 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg,
 
        nfs_fattr_init(res->dir_attr);
 
-       if (inode)
+       if (inode) {
                nfs4_inode_return_delegation(inode);
+               nfs_d_prune_case_insensitive_aliases(inode);
+       }
 }
 
 static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
@@ -4730,6 +4845,7 @@ static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
                return 0;
 
        if (task->tk_status == 0) {
+               nfs_d_prune_case_insensitive_aliases(d_inode(data->old_dentry));
                if (new_dir != old_dir) {
                        /* Note: If we moved a directory, nlink will change */
                        nfs4_update_changeattr(old_dir, &res->old_cinfo,
@@ -5422,14 +5538,14 @@ bool nfs4_write_need_cache_consistency_data(struct nfs_pgio_header *hdr)
        return nfs4_have_delegation(hdr->inode, FMODE_READ) == 0;
 }
 
-static void nfs4_bitmask_set(__u32 bitmask[NFS4_BITMASK_SZ], const __u32 *src,
-                            struct inode *inode, struct nfs_server *server,
-                            struct nfs4_label *label)
+void nfs4_bitmask_set(__u32 bitmask[], const __u32 src[],
+                     struct inode *inode, unsigned long cache_validity)
 {
-       unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
+       struct nfs_server *server = NFS_SERVER(inode);
        unsigned int i;
 
        memcpy(bitmask, src, sizeof(*bitmask) * NFS4_BITMASK_SZ);
+       cache_validity |= READ_ONCE(NFS_I(inode)->cache_validity);
 
        if (cache_validity & NFS_INO_INVALID_CHANGE)
                bitmask[0] |= FATTR4_WORD0_CHANGE;
@@ -5441,8 +5557,6 @@ static void nfs4_bitmask_set(__u32 bitmask[NFS4_BITMASK_SZ], const __u32 *src,
                bitmask[1] |= FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP;
        if (cache_validity & NFS_INO_INVALID_NLINK)
                bitmask[1] |= FATTR4_WORD1_NUMLINKS;
-       if (label && label->len && cache_validity & NFS_INO_INVALID_LABEL)
-               bitmask[2] |= FATTR4_WORD2_SECURITY_LABEL;
        if (cache_validity & NFS_INO_INVALID_CTIME)
                bitmask[1] |= FATTR4_WORD1_TIME_METADATA;
        if (cache_validity & NFS_INO_INVALID_MTIME)
@@ -5469,7 +5583,7 @@ static void nfs4_proc_write_setup(struct nfs_pgio_header *hdr,
        } else {
                nfs4_bitmask_set(hdr->args.bitmask_store,
                                 server->cache_consistency_bitmask,
-                                hdr->inode, server, NULL);
+                                hdr->inode, NFS_INO_INVALID_BLOCKS);
                hdr->args.bitmask = hdr->args.bitmask_store;
        }
 
@@ -6507,8 +6621,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred,
        data->args.fhandle = &data->fh;
        data->args.stateid = &data->stateid;
        nfs4_bitmask_set(data->args.bitmask_store,
-                        server->cache_consistency_bitmask, inode, server,
-                        NULL);
+                        server->cache_consistency_bitmask, inode, 0);
        data->args.bitmask = data->args.bitmask_store;
        nfs_copy_fh(&data->fh, NFS_FH(inode));
        nfs4_stateid_copy(&data->stateid, stateid);
@@ -7611,7 +7724,7 @@ static int nfs4_xattr_set_nfs4_user(const struct xattr_handler *handler,
                                    const char *key, const void *buf,
                                    size_t buflen, int flags)
 {
-       struct nfs_access_entry cache;
+       u32 mask;
        int ret;
 
        if (!nfs_server_capable(inode, NFS_CAP_XATTR))
@@ -7626,8 +7739,8 @@ static int nfs4_xattr_set_nfs4_user(const struct xattr_handler *handler,
         * do a cached access check for the XA* flags to possibly avoid
         * doing an RPC and getting EACCES back.
         */
-       if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
-               if (!(cache.mask & NFS_ACCESS_XAWRITE))
+       if (!nfs_access_get_cached(inode, current_cred(), &mask, true)) {
+               if (!(mask & NFS_ACCESS_XAWRITE))
                        return -EACCES;
        }
 
@@ -7648,14 +7761,14 @@ static int nfs4_xattr_get_nfs4_user(const struct xattr_handler *handler,
                                    struct dentry *unused, struct inode *inode,
                                    const char *key, void *buf, size_t buflen)
 {
-       struct nfs_access_entry cache;
+       u32 mask;
        ssize_t ret;
 
        if (!nfs_server_capable(inode, NFS_CAP_XATTR))
                return -EOPNOTSUPP;
 
-       if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
-               if (!(cache.mask & NFS_ACCESS_XAREAD))
+       if (!nfs_access_get_cached(inode, current_cred(), &mask, true)) {
+               if (!(mask & NFS_ACCESS_XAREAD))
                        return -EACCES;
        }
 
@@ -7680,13 +7793,13 @@ nfs4_listxattr_nfs4_user(struct inode *inode, char *list, size_t list_len)
        ssize_t ret, size;
        char *buf;
        size_t buflen;
-       struct nfs_access_entry cache;
+       u32 mask;
 
        if (!nfs_server_capable(inode, NFS_CAP_XATTR))
                return 0;
 
-       if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
-               if (!(cache.mask & NFS_ACCESS_XALIST))
+       if (!nfs_access_get_cached(inode, current_cred(), &mask, true)) {
+               if (!(mask & NFS_ACCESS_XALIST))
                        return 0;
        }
 
@@ -7818,18 +7931,18 @@ int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
  * appended to this compound to identify the client ID which is
  * performing recovery.
  */
-static int _nfs40_proc_get_locations(struct inode *inode,
+static int _nfs40_proc_get_locations(struct nfs_server *server,
+                                    struct nfs_fh *fhandle,
                                     struct nfs4_fs_locations *locations,
                                     struct page *page, const struct cred *cred)
 {
-       struct nfs_server *server = NFS_SERVER(inode);
        struct rpc_clnt *clnt = server->client;
        u32 bitmask[2] = {
                [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
        };
        struct nfs4_fs_locations_arg args = {
                .clientid       = server->nfs_client->cl_clientid,
-               .fh             = NFS_FH(inode),
+               .fh             = fhandle,
                .page           = page,
                .bitmask        = bitmask,
                .migration      = 1,            /* skip LOOKUP */
@@ -7875,17 +7988,17 @@ static int _nfs40_proc_get_locations(struct inode *inode,
  * When the client supports GETATTR(fs_locations_info), it can
  * be plumbed in here.
  */
-static int _nfs41_proc_get_locations(struct inode *inode,
+static int _nfs41_proc_get_locations(struct nfs_server *server,
+                                    struct nfs_fh *fhandle,
                                     struct nfs4_fs_locations *locations,
                                     struct page *page, const struct cred *cred)
 {
-       struct nfs_server *server = NFS_SERVER(inode);
        struct rpc_clnt *clnt = server->client;
        u32 bitmask[2] = {
                [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
        };
        struct nfs4_fs_locations_arg args = {
-               .fh             = NFS_FH(inode),
+               .fh             = fhandle,
                .page           = page,
                .bitmask        = bitmask,
                .migration      = 1,            /* skip LOOKUP */
@@ -7919,7 +8032,8 @@ static int _nfs41_proc_get_locations(struct inode *inode,
 
 /**
  * nfs4_proc_get_locations - discover locations for a migrated FSID
- * @inode: inode on FSID that is migrating
+ * @server: pointer to nfs_server to process
+ * @fhandle: pointer to the kernel NFS client file handle
  * @locations: result of query
  * @page: buffer
  * @cred: credential to use for this operation
@@ -7934,11 +8048,11 @@ static int _nfs41_proc_get_locations(struct inode *inode,
  * -NFS4ERR_LEASE_MOVED is returned if the server still has leases
  * from this client that require migration recovery.
  */
-int nfs4_proc_get_locations(struct inode *inode,
+int nfs4_proc_get_locations(struct nfs_server *server,
+                           struct nfs_fh *fhandle,
                            struct nfs4_fs_locations *locations,
                            struct page *page, const struct cred *cred)
 {
-       struct nfs_server *server = NFS_SERVER(inode);
        struct nfs_client *clp = server->nfs_client;
        const struct nfs4_mig_recovery_ops *ops =
                                        clp->cl_mvops->mig_recovery_ops;
@@ -7951,10 +8065,11 @@ int nfs4_proc_get_locations(struct inode *inode,
                (unsigned long long)server->fsid.major,
                (unsigned long long)server->fsid.minor,
                clp->cl_hostname);
-       nfs_display_fhandle(NFS_FH(inode), __func__);
+       nfs_display_fhandle(fhandle, __func__);
 
        do {
-               status = ops->get_locations(inode, locations, page, cred);
+               status = ops->get_locations(server, fhandle, locations, page,
+                                           cred);
                if (status != -NFS4ERR_DELAY)
                        break;
                nfs4_handle_exception(server, status, &exception);
@@ -10423,6 +10538,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .free_client    = nfs4_free_client,
        .create_server  = nfs4_create_server,
        .clone_server   = nfs_clone_server,
+       .discover_trunking = nfs4_discover_trunking,
 };
 
 static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
index d88b779..f5a62c0 100644 (file)
@@ -2098,7 +2098,8 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred
        }
 
        inode = d_inode(server->super->s_root);
-       result = nfs4_proc_get_locations(inode, locations, page, cred);
+       result = nfs4_proc_get_locations(server, NFS_FH(inode), locations,
+                                        page, cred);
        if (result) {
                dprintk("<-- %s: failed to retrieve fs_locations: %d\n",
                        __func__, result);
@@ -2106,6 +2107,9 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred
        }
 
        result = -NFS4ERR_NXIO;
+       if (!locations->nlocations)
+               goto out;
+
        if (!(locations->fattr.valid & NFS_ATTR_FATTR_V4_LOCATIONS)) {
                dprintk("<-- %s: No fs_locations data, migration skipped\n",
                        __func__);
index 69862bf..8e70b92 100644 (file)
@@ -3533,6 +3533,42 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint
        return 0;
 }
 
+static int decode_attr_case_insensitive(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+       __be32 *p;
+
+       *res = 0;
+       if (unlikely(bitmap[0] & (FATTR4_WORD0_CASE_INSENSITIVE - 1U)))
+               return -EIO;
+       if (likely(bitmap[0] & FATTR4_WORD0_CASE_INSENSITIVE)) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       return -EIO;
+               *res = be32_to_cpup(p);
+               bitmap[0] &= ~FATTR4_WORD0_CASE_INSENSITIVE;
+       }
+       dprintk("%s: case_insensitive=%s\n", __func__, *res == 0 ? "false" : "true");
+       return 0;
+}
+
+static int decode_attr_case_preserving(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+       __be32 *p;
+
+       *res = 0;
+       if (unlikely(bitmap[0] & (FATTR4_WORD0_CASE_PRESERVING - 1U)))
+               return -EIO;
+       if (likely(bitmap[0] & FATTR4_WORD0_CASE_PRESERVING)) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       return -EIO;
+               *res = be32_to_cpup(p);
+               bitmap[0] &= ~FATTR4_WORD0_CASE_PRESERVING;
+       }
+       dprintk("%s: case_preserving=%s\n", __func__, *res == 0 ? "false" : "true");
+       return 0;
+}
+
 static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
 {
        __be32 *p;
@@ -3696,8 +3732,6 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
        if (unlikely(!p))
                goto out_eio;
        n = be32_to_cpup(p);
-       if (n <= 0)
-               goto out_eio;
        for (res->nlocations = 0; res->nlocations < n; res->nlocations++) {
                u32 m;
                struct nfs4_fs_location *loc;
@@ -4200,10 +4234,11 @@ static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap,
                } else
                        printk(KERN_WARNING "%s: label too long (%u)!\n",
                                        __func__, len);
+               if (label && label->label)
+                       dprintk("%s: label=%.*s, len=%d, PI=%d, LFS=%d\n",
+                               __func__, label->len, (char *)label->label,
+                               label->len, label->pi, label->lfs);
        }
-       if (label && label->label)
-               dprintk("%s: label=%s, len=%d, PI=%d, LFS=%d\n", __func__,
-                       (char *)label->label, label->len, label->pi, label->lfs);
        return status;
 }
 
@@ -4412,6 +4447,10 @@ static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_re
                goto xdr_error;
        if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0)
                goto xdr_error;
+       if ((status = decode_attr_case_insensitive(xdr, bitmap, &res->case_insensitive)) != 0)
+               goto xdr_error;
+       if ((status = decode_attr_case_preserving(xdr, bitmap, &res->case_preserving)) != 0)
+               goto xdr_error;
        if ((status = decode_attr_exclcreat_supported(xdr, bitmap,
                                res->exclcreat_bitmask)) != 0)
                goto xdr_error;
index 8cb7075..a6f7403 100644 (file)
@@ -142,10 +142,11 @@ static struct attribute *nfs_netns_client_attrs[] = {
        &nfs_netns_client_id.attr,
        NULL,
 };
+ATTRIBUTE_GROUPS(nfs_netns_client);
 
 static struct kobj_type nfs_netns_client_type = {
        .release = nfs_netns_client_release,
-       .default_attrs = nfs_netns_client_attrs,
+       .default_groups = nfs_netns_client_groups,
        .sysfs_ops = &kobj_sysfs_ops,
        .namespace = nfs_netns_client_namespace,
 };
index 8ef53f6..936eebd 100644 (file)
@@ -150,13 +150,17 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
        unsigned int len;
        int v;
 
-       argp->count = min_t(u32, argp->count, max_blocksize);
-
        dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
                                SVCFH_fmt(&argp->fh),
                                (unsigned long) argp->count,
                                (unsigned long long) argp->offset);
 
+       argp->count = min_t(u32, argp->count, max_blocksize);
+       if (argp->offset > (u64)OFFSET_MAX)
+               argp->offset = (u64)OFFSET_MAX;
+       if (argp->offset + argp->count > (u64)OFFSET_MAX)
+               argp->count = (u64)OFFSET_MAX - argp->offset;
+
        v = 0;
        len = argp->count;
        resp->pages = rqstp->rq_next_page;
@@ -199,6 +203,11 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
                                (unsigned long long) argp->offset,
                                argp->stable? " stable" : "");
 
+       resp->status = nfserr_fbig;
+       if (argp->offset > (u64)OFFSET_MAX ||
+           argp->offset + argp->len > (u64)OFFSET_MAX)
+               return rpc_success;
+
        fh_copy(&resp->fh, &argp->fh);
        resp->committed = argp->stable;
        nvecs = svc_fill_write_vector(rqstp, &argp->payload);
@@ -651,15 +660,9 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
                                argp->count,
                                (unsigned long long) argp->offset);
 
-       if (argp->offset > NFS_OFFSET_MAX) {
-               resp->status = nfserr_inval;
-               goto out;
-       }
-
        fh_copy(&resp->fh, &argp->fh);
        resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset,
                                   argp->count, resp->verf);
-out:
        return rpc_success;
 }
 
index 7c45ba4..0293b8d 100644 (file)
@@ -254,7 +254,7 @@ svcxdr_decode_sattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr,
                if (xdr_stream_decode_u64(xdr, &newsize) < 0)
                        return false;
                iap->ia_valid |= ATTR_SIZE;
-               iap->ia_size = min_t(u64, newsize, NFS_OFFSET_MAX);
+               iap->ia_size = newsize;
        }
        if (xdr_stream_decode_u32(xdr, &set_it) < 0)
                return false;
@@ -1060,7 +1060,7 @@ svcxdr_encode_entry3_common(struct nfsd3_readdirres *resp, const char *name,
                return false;
        /* cookie */
        resp->cookie_offset = dirlist->len;
-       if (xdr_stream_encode_u64(xdr, NFS_OFFSET_MAX) < 0)
+       if (xdr_stream_encode_u64(xdr, OFFSET_MAX) < 0)
                return false;
 
        return true;
index ed1ee25..b207c76 100644 (file)
@@ -782,12 +782,16 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        __be32 status;
 
        read->rd_nf = NULL;
-       if (read->rd_offset >= OFFSET_MAX)
-               return nfserr_inval;
 
        trace_nfsd_read_start(rqstp, &cstate->current_fh,
                              read->rd_offset, read->rd_length);
 
+       read->rd_length = min_t(u32, read->rd_length, svc_max_payload(rqstp));
+       if (read->rd_offset > (u64)OFFSET_MAX)
+               read->rd_offset = (u64)OFFSET_MAX;
+       if (read->rd_offset + read->rd_length > (u64)OFFSET_MAX)
+               read->rd_length = (u64)OFFSET_MAX - read->rd_offset;
+
        /*
         * If we do a zero copy read, then a client will see read data
         * that reflects the state of the file *after* performing the
@@ -1018,8 +1022,9 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        unsigned long cnt;
        int nvecs;
 
-       if (write->wr_offset >= OFFSET_MAX)
-               return nfserr_inval;
+       if (write->wr_offset > (u64)OFFSET_MAX ||
+           write->wr_offset + write->wr_buflen > (u64)OFFSET_MAX)
+               return nfserr_fbig;
 
        cnt = write->wr_buflen;
        trace_nfsd_write_start(rqstp, &cstate->current_fh,
index 72900b8..3206373 100644 (file)
@@ -4130,8 +4130,10 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        status = nfserr_clid_inuse;
                        if (client_has_state(old)
                                        && !same_creds(&unconf->cl_cred,
-                                                       &old->cl_cred))
+                                                       &old->cl_cred)) {
+                               old = NULL;
                                goto out;
+                       }
                        status = mark_client_expired_locked(old);
                        if (status) {
                                old = NULL;
index 899de43..714a3a3 100644 (file)
@@ -3495,7 +3495,7 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
        p = xdr_reserve_space(xdr, 3*4 + namlen);
        if (!p)
                goto fail;
-       p = xdr_encode_hyper(p, NFS_OFFSET_MAX);    /* offset of next entry */
+       p = xdr_encode_hyper(p, OFFSET_MAX);        /* offset of next entry */
        p = xdr_encode_array(p, name, namlen);      /* name length & name */
 
        nfserr = nfsd4_encode_dirent_fattr(xdr, cd, name, namlen);
@@ -3986,10 +3986,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
        }
        xdr_commit_encode(xdr);
 
-       maxcount = svc_max_payload(resp->rqstp);
-       maxcount = min_t(unsigned long, maxcount,
+       maxcount = min_t(unsigned long, read->rd_length,
                         (xdr->buf->buflen - xdr->buf->len));
-       maxcount = min_t(unsigned long, maxcount, read->rd_length);
 
        if (file->f_op->splice_read &&
            test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
@@ -4826,10 +4824,8 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
                return nfserr_resource;
        xdr_commit_encode(xdr);
 
-       maxcount = svc_max_payload(resp->rqstp);
-       maxcount = min_t(unsigned long, maxcount,
+       maxcount = min_t(unsigned long, read->rd_length,
                         (xdr->buf->buflen - xdr->buf->len));
-       maxcount = min_t(unsigned long, maxcount, read->rd_length);
        count    = maxcount;
 
        eof = read->rd_offset >= i_size_read(file_inode(file));
index b9f27fb..68b020f 100644 (file)
@@ -1247,7 +1247,8 @@ static void nfsdfs_remove_file(struct inode *dir, struct dentry *dentry)
        clear_ncl(d_inode(dentry));
        dget(dentry);
        ret = simple_unlink(dir, dentry);
-       d_delete(dentry);
+       d_drop(dentry);
+       fsnotify_unlink(dir, dentry);
        dput(dentry);
        WARN_ON_ONCE(ret);
 }
@@ -1338,8 +1339,8 @@ void nfsd_client_rmdir(struct dentry *dentry)
        dget(dentry);
        ret = simple_rmdir(dir, dentry);
        WARN_ON_ONCE(ret);
+       d_drop(dentry);
        fsnotify_rmdir(dir, dentry);
-       d_delete(dentry);
        dput(dentry);
        inode_unlock(dir);
 }
index c4cf563..5889db6 100644 (file)
@@ -306,14 +306,14 @@ TRACE_EVENT(nfsd_export_update,
 DECLARE_EVENT_CLASS(nfsd_io_class,
        TP_PROTO(struct svc_rqst *rqstp,
                 struct svc_fh  *fhp,
-                loff_t         offset,
-                unsigned long  len),
+                u64            offset,
+                u32            len),
        TP_ARGS(rqstp, fhp, offset, len),
        TP_STRUCT__entry(
                __field(u32, xid)
                __field(u32, fh_hash)
-               __field(loff_t, offset)
-               __field(unsigned long, len)
+               __field(u64, offset)
+               __field(u32, len)
        ),
        TP_fast_assign(
                __entry->xid = be32_to_cpu(rqstp->rq_xid);
@@ -321,7 +321,7 @@ DECLARE_EVENT_CLASS(nfsd_io_class,
                __entry->offset = offset;
                __entry->len = len;
        ),
-       TP_printk("xid=0x%08x fh_hash=0x%08x offset=%lld len=%lu",
+       TP_printk("xid=0x%08x fh_hash=0x%08x offset=%llu len=%u",
                  __entry->xid, __entry->fh_hash,
                  __entry->offset, __entry->len)
 )
@@ -330,8 +330,8 @@ DECLARE_EVENT_CLASS(nfsd_io_class,
 DEFINE_EVENT(nfsd_io_class, nfsd_##name,       \
        TP_PROTO(struct svc_rqst *rqstp,        \
                 struct svc_fh  *fhp,           \
-                loff_t         offset,         \
-                unsigned long  len),           \
+                u64            offset,         \
+                u32            len),           \
        TP_ARGS(rqstp, fhp, offset, len))
 
 DEFINE_NFSD_IO_EVENT(read_start);
index 99c2b9d..91600e7 100644 (file)
@@ -435,6 +435,10 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
                        .ia_size        = iap->ia_size,
                };
 
+               host_err = -EFBIG;
+               if (iap->ia_size < 0)
+                       goto out_unlock;
+
                host_err = notify_change(&init_user_ns, dentry, &size_attr, NULL);
                if (host_err)
                        goto out_unlock;
@@ -1110,42 +1114,61 @@ out:
 }
 
 #ifdef CONFIG_NFSD_V3
-/*
- * Commit all pending writes to stable storage.
+/**
+ * nfsd_commit - Commit pending writes to stable storage
+ * @rqstp: RPC request being processed
+ * @fhp: NFS filehandle
+ * @offset: raw offset from beginning of file
+ * @count: raw count of bytes to sync
+ * @verf: filled in with the server's current write verifier
  *
- * Note: we only guarantee that data that lies within the range specified
- * by the 'offset' and 'count' parameters will be synced.
+ * Note: we guarantee that data that lies within the range specified
+ * by the 'offset' and 'count' parameters will be synced. The server
+ * is permitted to sync data that lies outside this range at the
+ * same time.
  *
  * Unfortunately we cannot lock the file to make sure we return full WCC
  * data to the client, as locking happens lower down in the filesystem.
+ *
+ * Return values:
+ *   An nfsstat value in network byte order.
  */
 __be32
-nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
-               loff_t offset, unsigned long count, __be32 *verf)
+nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset,
+           u32 count, __be32 *verf)
 {
+       u64                     maxbytes;
+       loff_t                  start, end;
        struct nfsd_net         *nn;
        struct nfsd_file        *nf;
-       loff_t                  end = LLONG_MAX;
-       __be32                  err = nfserr_inval;
-
-       if (offset < 0)
-               goto out;
-       if (count != 0) {
-               end = offset + (loff_t)count - 1;
-               if (end < offset)
-                       goto out;
-       }
+       __be32                  err;
 
        err = nfsd_file_acquire(rqstp, fhp,
                        NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf);
        if (err)
                goto out;
+
+       /*
+        * Convert the client-provided (offset, count) range to a
+        * (start, end) range. If the client-provided range falls
+        * outside the maximum file size of the underlying FS,
+        * clamp the sync range appropriately.
+        */
+       start = 0;
+       end = LLONG_MAX;
+       maxbytes = (u64)fhp->fh_dentry->d_sb->s_maxbytes;
+       if (offset < maxbytes) {
+               start = offset;
+               if (count && (offset + count - 1 < maxbytes))
+                       end = offset + count - 1;
+       }
+
        nn = net_generic(nf->nf_net, nfsd_net_id);
        if (EX_ISSYNC(fhp->fh_export)) {
                errseq_t since = READ_ONCE(nf->nf_file->f_wb_err);
                int err2;
 
-               err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
+               err2 = vfs_fsync_range(nf->nf_file, start, end, 0);
                switch (err2) {
                case 0:
                        nfsd_copy_write_verifier(verf, nn);
index 9f56dcb..2c43d10 100644 (file)
@@ -74,8 +74,8 @@ __be32                do_nfsd_create(struct svc_rqst *, struct svc_fh *,
                                char *name, int len, struct iattr *attrs,
                                struct svc_fh *res, int createmode,
                                u32 *verifier, bool *truncp, bool *created);
-__be32         nfsd_commit(struct svc_rqst *, struct svc_fh *,
-                               loff_t, unsigned long, __be32 *verf);
+__be32         nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp,
+                               u64 offset, u32 count, __be32 *verf);
 #endif /* CONFIG_NFSD_V3 */
 #ifdef CONFIG_NFSD_V4
 __be32         nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
index 73b1615..2ff6bd8 100644 (file)
@@ -158,7 +158,6 @@ static size_t fanotify_event_len(unsigned int info_mode,
                                 struct fanotify_event *event)
 {
        size_t event_len = FAN_EVENT_METADATA_LEN;
-       struct fanotify_info *info;
        int fh_len;
        int dot_len = 0;
 
@@ -168,8 +167,6 @@ static size_t fanotify_event_len(unsigned int info_mode,
        if (fanotify_is_error_event(event->mask))
                event_len += FANOTIFY_ERROR_INFO_LEN;
 
-       info = fanotify_event_info(event);
-
        if (fanotify_event_has_any_dir_fh(event)) {
                event_len += fanotify_dir_name_info_len(event);
        } else if ((info_mode & FAN_REPORT_NAME) &&
@@ -704,9 +701,6 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
        if (fanotify_is_perm_event(event->mask))
                FANOTIFY_PERM(event)->fd = fd;
 
-       if (f)
-               fd_install(fd, f);
-
        if (info_mode) {
                ret = copy_info_records_to_user(event, info, info_mode, pidfd,
                                                buf, count);
@@ -714,6 +708,9 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
                        goto out_close_fd;
        }
 
+       if (f)
+               fd_install(fd, f);
+
        return metadata.event_len;
 
 out_close_fd:
index 731558a..dd77b7a 100644 (file)
@@ -661,17 +661,6 @@ static struct ctl_table ocfs2_nm_table[] = {
        { }
 };
 
-static struct ctl_table ocfs2_mod_table[] = {
-       {
-               .procname       = "nm",
-               .data           = NULL,
-               .maxlen         = 0,
-               .mode           = 0555,
-               .child          = ocfs2_nm_table
-       },
-       { }
-};
-
 static struct ctl_table_header *ocfs2_table_header;
 
 /*
@@ -682,7 +671,7 @@ static int __init ocfs2_stack_glue_init(void)
 {
        strcpy(cluster_stack_name, OCFS2_STACK_PLUGIN_O2CB);
 
-       ocfs2_table_header = register_sysctl("fs/ocfs2", ocfs2_mod_table);
+       ocfs2_table_header = register_sysctl("fs/ocfs2/nm", ocfs2_nm_table);
        if (!ocfs2_table_header) {
                printk(KERN_ERR
                       "ocfs2 stack glue: unable to register sysctl\n");
index 481017e..166c891 100644 (file)
@@ -1251,26 +1251,23 @@ static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh,
 {
        struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) bg_bh->b_data;
        struct journal_head *jh;
-       int ret = 1;
+       int ret;
 
        if (ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap))
                return 0;
 
-       if (!buffer_jbd(bg_bh))
+       jh = jbd2_journal_grab_journal_head(bg_bh);
+       if (!jh)
                return 1;
 
-       jbd_lock_bh_journal_head(bg_bh);
-       if (buffer_jbd(bg_bh)) {
-               jh = bh2jh(bg_bh);
-               spin_lock(&jh->b_state_lock);
-               bg = (struct ocfs2_group_desc *) jh->b_committed_data;
-               if (bg)
-                       ret = !ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap);
-               else
-                       ret = 1;
-               spin_unlock(&jh->b_state_lock);
-       }
-       jbd_unlock_bh_journal_head(bg_bh);
+       spin_lock(&jh->b_state_lock);
+       bg = (struct ocfs2_group_desc *) jh->b_committed_data;
+       if (bg)
+               ret = !ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap);
+       else
+               ret = 1;
+       spin_unlock(&jh->b_state_lock);
+       jbd2_journal_put_journal_head(jh);
 
        return ret;
 }
index b193d08..e040970 100644 (file)
@@ -145,7 +145,7 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
                if (err == -ENOTTY || err == -EINVAL)
                        return 0;
                pr_warn("failed to retrieve lower fileattr (%pd2, err=%i)\n",
-                       old, err);
+                       old->dentry, err);
                return err;
        }
 
@@ -157,7 +157,9 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
         */
        if (oldfa.flags & OVL_PROT_FS_FLAGS_MASK) {
                err = ovl_set_protattr(inode, new->dentry, &oldfa);
-               if (err)
+               if (err == -EPERM)
+                       pr_warn_once("copying fileattr: no xattr on upper\n");
+               else if (err)
                        return err;
        }
 
@@ -167,8 +169,16 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
 
        err = ovl_real_fileattr_get(new, &newfa);
        if (err) {
+               /*
+                * Returning an error if upper doesn't support fileattr will
+                * result in a regression, so revert to the old behavior.
+                */
+               if (err == -ENOTTY || err == -EINVAL) {
+                       pr_warn_once("copying fileattr: no support on upper\n");
+                       return 0;
+               }
                pr_warn("failed to retrieve upper fileattr (%pd2, err=%i)\n",
-                       new, err);
+                       new->dentry, err);
                return err;
        }
 
index 18f8c3a..6e97ed7 100644 (file)
@@ -440,7 +440,8 @@ static void smaps_page_accumulate(struct mem_size_stats *mss,
 }
 
 static void smaps_account(struct mem_size_stats *mss, struct page *page,
-               bool compound, bool young, bool dirty, bool locked)
+               bool compound, bool young, bool dirty, bool locked,
+               bool migration)
 {
        int i, nr = compound ? compound_nr(page) : 1;
        unsigned long size = nr * PAGE_SIZE;
@@ -467,8 +468,15 @@ static void smaps_account(struct mem_size_stats *mss, struct page *page,
         * page_count(page) == 1 guarantees the page is mapped exactly once.
         * If any subpage of the compound page mapped with PTE it would elevate
         * page_count().
+        *
+        * The page_mapcount() is called to get a snapshot of the mapcount.
+        * Without holding the page lock this snapshot can be slightly wrong as
+        * we cannot always read the mapcount atomically.  It is not safe to
+        * call page_mapcount() even with PTL held if the page is not mapped,
+        * especially for migration entries.  Treat regular migration entries
+        * as mapcount == 1.
         */
-       if (page_count(page) == 1) {
+       if ((page_count(page) == 1) || migration) {
                smaps_page_accumulate(mss, page, size, size << PSS_SHIFT, dirty,
                        locked, true);
                return;
@@ -517,6 +525,7 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
        struct vm_area_struct *vma = walk->vma;
        bool locked = !!(vma->vm_flags & VM_LOCKED);
        struct page *page = NULL;
+       bool migration = false;
 
        if (pte_present(*pte)) {
                page = vm_normal_page(vma, addr, *pte);
@@ -536,8 +545,11 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
                        } else {
                                mss->swap_pss += (u64)PAGE_SIZE << PSS_SHIFT;
                        }
-               } else if (is_pfn_swap_entry(swpent))
+               } else if (is_pfn_swap_entry(swpent)) {
+                       if (is_migration_entry(swpent))
+                               migration = true;
                        page = pfn_swap_entry_to_page(swpent);
+               }
        } else {
                smaps_pte_hole_lookup(addr, walk);
                return;
@@ -546,7 +558,8 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
        if (!page)
                return;
 
-       smaps_account(mss, page, false, pte_young(*pte), pte_dirty(*pte), locked);
+       smaps_account(mss, page, false, pte_young(*pte), pte_dirty(*pte),
+                     locked, migration);
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
@@ -557,6 +570,7 @@ static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
        struct vm_area_struct *vma = walk->vma;
        bool locked = !!(vma->vm_flags & VM_LOCKED);
        struct page *page = NULL;
+       bool migration = false;
 
        if (pmd_present(*pmd)) {
                /* FOLL_DUMP will return -EFAULT on huge zero page */
@@ -564,8 +578,10 @@ static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
        } else if (unlikely(thp_migration_supported() && is_swap_pmd(*pmd))) {
                swp_entry_t entry = pmd_to_swp_entry(*pmd);
 
-               if (is_migration_entry(entry))
+               if (is_migration_entry(entry)) {
+                       migration = true;
                        page = pfn_swap_entry_to_page(entry);
+               }
        }
        if (IS_ERR_OR_NULL(page))
                return;
@@ -577,7 +593,9 @@ static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
                /* pass */;
        else
                mss->file_thp += HPAGE_PMD_SIZE;
-       smaps_account(mss, page, true, pmd_young(*pmd), pmd_dirty(*pmd), locked);
+
+       smaps_account(mss, page, true, pmd_young(*pmd), pmd_dirty(*pmd),
+                     locked, migration);
 }
 #else
 static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
@@ -1378,6 +1396,7 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm,
 {
        u64 frame = 0, flags = 0;
        struct page *page = NULL;
+       bool migration = false;
 
        if (pte_present(pte)) {
                if (pm->show_pfn)
@@ -1399,13 +1418,14 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm,
                        frame = swp_type(entry) |
                                (swp_offset(entry) << MAX_SWAPFILES_SHIFT);
                flags |= PM_SWAP;
+               migration = is_migration_entry(entry);
                if (is_pfn_swap_entry(entry))
                        page = pfn_swap_entry_to_page(entry);
        }
 
        if (page && !PageAnon(page))
                flags |= PM_FILE;
-       if (page && page_mapcount(page) == 1)
+       if (page && !migration && page_mapcount(page) == 1)
                flags |= PM_MMAP_EXCLUSIVE;
        if (vma->vm_flags & VM_SOFTDIRTY)
                flags |= PM_SOFT_DIRTY;
@@ -1421,8 +1441,9 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end,
        spinlock_t *ptl;
        pte_t *pte, *orig_pte;
        int err = 0;
-
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
+       bool migration = false;
+
        ptl = pmd_trans_huge_lock(pmdp, vma);
        if (ptl) {
                u64 flags = 0, frame = 0;
@@ -1461,11 +1482,12 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end,
                        if (pmd_swp_uffd_wp(pmd))
                                flags |= PM_UFFD_WP;
                        VM_BUG_ON(!is_pmd_migration_entry(pmd));
+                       migration = is_migration_entry(entry);
                        page = pfn_swap_entry_to_page(entry);
                }
 #endif
 
-               if (page && page_mapcount(page) == 1)
+               if (page && !migration && page_mapcount(page) == 1)
                        flags |= PM_MMAP_EXCLUSIVE;
 
                for (; addr != end; addr += PAGE_SIZE) {
index 22d904b..a74aef9 100644 (file)
@@ -690,9 +690,14 @@ int dquot_quota_sync(struct super_block *sb, int type)
        /* This is not very clever (and fast) but currently I don't know about
         * any other simple way of getting quota data to disk and we must get
         * them there for userspace to be visible... */
-       if (sb->s_op->sync_fs)
-               sb->s_op->sync_fs(sb, 1);
-       sync_blockdev(sb->s_bdev);
+       if (sb->s_op->sync_fs) {
+               ret = sb->s_op->sync_fs(sb, 1);
+               if (ret)
+                       return ret;
+       }
+       ret = sync_blockdev(sb->s_bdev);
+       if (ret)
+               return ret;
 
        /*
         * Now when everything is written we can discard the pagecache so
index 7af820b..f1d4a19 100644 (file)
@@ -1616,11 +1616,9 @@ static void lockdep_sb_freeze_acquire(struct super_block *sb)
                percpu_rwsem_acquire(sb->s_writers.rw_sem + level, 0, _THIS_IP_);
 }
 
-static void sb_freeze_unlock(struct super_block *sb)
+static void sb_freeze_unlock(struct super_block *sb, int level)
 {
-       int level;
-
-       for (level = SB_FREEZE_LEVELS - 1; level >= 0; level--)
+       for (level--; level >= 0; level--)
                percpu_up_write(sb->s_writers.rw_sem + level);
 }
 
@@ -1691,7 +1689,14 @@ int freeze_super(struct super_block *sb)
        sb_wait_write(sb, SB_FREEZE_PAGEFAULT);
 
        /* All writers are done so after syncing there won't be dirty data */
-       sync_filesystem(sb);
+       ret = sync_filesystem(sb);
+       if (ret) {
+               sb->s_writers.frozen = SB_UNFROZEN;
+               sb_freeze_unlock(sb, SB_FREEZE_PAGEFAULT);
+               wake_up(&sb->s_writers.wait_unfrozen);
+               deactivate_locked_super(sb);
+               return ret;
+       }
 
        /* Now wait for internal filesystem counter */
        sb->s_writers.frozen = SB_FREEZE_FS;
@@ -1703,7 +1708,7 @@ int freeze_super(struct super_block *sb)
                        printk(KERN_ERR
                                "VFS:Filesystem freeze failed\n");
                        sb->s_writers.frozen = SB_UNFROZEN;
-                       sb_freeze_unlock(sb);
+                       sb_freeze_unlock(sb, SB_FREEZE_FS);
                        wake_up(&sb->s_writers.wait_unfrozen);
                        deactivate_locked_super(sb);
                        return ret;
@@ -1748,7 +1753,7 @@ static int thaw_super_locked(struct super_block *sb)
        }
 
        sb->s_writers.frozen = SB_UNFROZEN;
-       sb_freeze_unlock(sb);
+       sb_freeze_unlock(sb, SB_FREEZE_FS);
 out:
        wake_up(&sb->s_writers.wait_unfrozen);
        deactivate_locked_super(sb);
index 3ce8e21..c769001 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -29,7 +29,7 @@
  */
 int sync_filesystem(struct super_block *sb)
 {
-       int ret;
+       int ret = 0;
 
        /*
         * We need to be protected against the filesystem going from
@@ -52,15 +52,21 @@ int sync_filesystem(struct super_block *sb)
         * at a time.
         */
        writeback_inodes_sb(sb, WB_REASON_SYNC);
-       if (sb->s_op->sync_fs)
-               sb->s_op->sync_fs(sb, 0);
+       if (sb->s_op->sync_fs) {
+               ret = sb->s_op->sync_fs(sb, 0);
+               if (ret)
+                       return ret;
+       }
        ret = sync_blockdev_nowait(sb->s_bdev);
-       if (ret < 0)
+       if (ret)
                return ret;
 
        sync_inodes_sb(sb);
-       if (sb->s_op->sync_fs)
-               sb->s_op->sync_fs(sb, 1);
+       if (sb->s_op->sync_fs) {
+               ret = sb->s_op->sync_fs(sb, 1);
+               if (ret)
+                       return ret;
+       }
        return sync_blockdev(sb->s_bdev);
 }
 EXPORT_SYMBOL(sync_filesystem);
index 1d6b7a5..ea8f6cd 100644 (file)
@@ -258,10 +258,6 @@ int udf_expand_file_adinicb(struct inode *inode)
        char *kaddr;
        struct udf_inode_info *iinfo = UDF_I(inode);
        int err;
-       struct writeback_control udf_wbc = {
-               .sync_mode = WB_SYNC_NONE,
-               .nr_to_write = 1,
-       };
 
        WARN_ON_ONCE(!inode_is_locked(inode));
        if (!iinfo->i_lenAlloc) {
@@ -305,8 +301,10 @@ int udf_expand_file_adinicb(struct inode *inode)
                iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
        /* from now on we have normal address_space methods */
        inode->i_data.a_ops = &udf_aops;
+       set_page_dirty(page);
+       unlock_page(page);
        up_write(&iinfo->i_data_sem);
-       err = inode->i_data.a_ops->writepage(page, &udf_wbc);
+       err = filemap_fdatawrite(inode->i_mapping);
        if (err) {
                /* Restore everything back so that we don't lose data... */
                lock_page(page);
@@ -317,6 +315,7 @@ int udf_expand_file_adinicb(struct inode *inode)
                unlock_page(page);
                iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
                inode->i_data.a_ops = &udf_adinicb_aops;
+               iinfo->i_lenAlloc = inode->i_size;
                up_write(&iinfo->i_data_sem);
        }
        put_page(page);
index 610d7bc..da786a6 100644 (file)
@@ -3,21 +3,13 @@
 # UTF-8 normalization
 #
 config UNICODE
-       bool "UTF-8 normalization and casefolding support"
+       tristate "UTF-8 normalization and casefolding support"
        help
          Say Y here to enable UTF-8 NFD normalization and NFD+CF casefolding
-         support.
-
-config UNICODE_UTF8_DATA
-       tristate "UTF-8 normalization and casefolding tables"
-       depends on UNICODE
-       default UNICODE
-       help
-         This contains a large table of case foldings, which can be loaded as
-         a separate module if you say M here.  To be on the safe side stick
-         to the default of Y.  Saying N here makes no sense, if you do not want
-         utf8 casefolding support, disable CONFIG_UNICODE instead.
+         support.  If you say M here the large table of case foldings will
+         be a separate loadable module that gets requested only when a file
+         system actually use it.
 
 config UNICODE_NORMALIZATION_SELFTEST
        tristate "Test UTF-8 normalization support"
-       depends on UNICODE_UTF8_DATA
+       depends on UNICODE
index 2f9d918..0cc8742 100644 (file)
@@ -1,8 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_UNICODE) += unicode.o
+ifneq ($(CONFIG_UNICODE),)
+obj-y                  += unicode.o
+endif
+obj-$(CONFIG_UNICODE)  += utf8data.o
 obj-$(CONFIG_UNICODE_NORMALIZATION_SELFTEST) += utf8-selftest.o
-obj-$(CONFIG_UNICODE_UTF8_DATA) += utf8data.o
 
 unicode-y := utf8-norm.o utf8-core.o
 
index 2705f91..9d6a67c 100644 (file)
@@ -136,7 +136,20 @@ done:
        memalloc_nofs_restore(nofs_flag);
 }
 
-/* Finish all pending io completions. */
+/*
+ * Finish all pending IO completions that require transactional modifications.
+ *
+ * We try to merge physical and logically contiguous ioends before completion to
+ * minimise the number of transactions we need to perform during IO completion.
+ * Both unwritten extent conversion and COW remapping need to iterate and modify
+ * one physical extent at a time, so we gain nothing by merging physically
+ * discontiguous extents here.
+ *
+ * The ioend chain length that we can be processing here is largely unbound in
+ * length and we may have to perform significant amounts of work on each ioend
+ * to complete it. Hence we have to be careful about holding the CPU for too
+ * long in this loop.
+ */
 void
 xfs_end_io(
        struct work_struct      *work)
@@ -157,6 +170,7 @@ xfs_end_io(
                list_del_init(&ioend->io_list);
                iomap_ioend_try_merge(ioend, &tmp);
                xfs_end_ioend(ioend);
+               cond_resched();
        }
 }
 
index d4a387d..eb2e387 100644 (file)
@@ -850,9 +850,6 @@ xfs_alloc_file_space(
                        rblocks = 0;
                }
 
-               /*
-                * Allocate and setup the transaction.
-                */
                error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_write,
                                dblocks, rblocks, false, &tp);
                if (error)
@@ -869,9 +866,9 @@ xfs_alloc_file_space(
                if (error)
                        goto error;
 
-               /*
-                * Complete the transaction
-                */
+               ip->i_diflags |= XFS_DIFLAG_PREALLOC;
+               xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
                error = xfs_trans_commit(tp);
                xfs_iunlock(ip, XFS_ILOCK_EXCL);
                if (error)
index 22ad207..5bddb1e 100644 (file)
@@ -66,40 +66,6 @@ xfs_is_falloc_aligned(
        return !((pos | len) & mask);
 }
 
-int
-xfs_update_prealloc_flags(
-       struct xfs_inode        *ip,
-       enum xfs_prealloc_flags flags)
-{
-       struct xfs_trans        *tp;
-       int                     error;
-
-       error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_writeid,
-                       0, 0, 0, &tp);
-       if (error)
-               return error;
-
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-
-       if (!(flags & XFS_PREALLOC_INVISIBLE)) {
-               VFS_I(ip)->i_mode &= ~S_ISUID;
-               if (VFS_I(ip)->i_mode & S_IXGRP)
-                       VFS_I(ip)->i_mode &= ~S_ISGID;
-               xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-       }
-
-       if (flags & XFS_PREALLOC_SET)
-               ip->i_diflags |= XFS_DIFLAG_PREALLOC;
-       if (flags & XFS_PREALLOC_CLEAR)
-               ip->i_diflags &= ~XFS_DIFLAG_PREALLOC;
-
-       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-       if (flags & XFS_PREALLOC_SYNC)
-               xfs_trans_set_sync(tp);
-       return xfs_trans_commit(tp);
-}
-
 /*
  * Fsync operations on directories are much simpler than on regular files,
  * as there is no file data to flush, and thus also no need for explicit
@@ -895,6 +861,21 @@ xfs_break_layouts(
        return error;
 }
 
+/* Does this file, inode, or mount want synchronous writes? */
+static inline bool xfs_file_sync_writes(struct file *filp)
+{
+       struct xfs_inode        *ip = XFS_I(file_inode(filp));
+
+       if (xfs_has_wsync(ip->i_mount))
+               return true;
+       if (filp->f_flags & (__O_SYNC | O_DSYNC))
+               return true;
+       if (IS_SYNC(file_inode(filp)))
+               return true;
+
+       return false;
+}
+
 #define        XFS_FALLOC_FL_SUPPORTED                                         \
                (FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |           \
                 FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE |      \
@@ -910,7 +891,6 @@ xfs_file_fallocate(
        struct inode            *inode = file_inode(file);
        struct xfs_inode        *ip = XFS_I(inode);
        long                    error;
-       enum xfs_prealloc_flags flags = 0;
        uint                    iolock = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
        loff_t                  new_size = 0;
        bool                    do_file_insert = false;
@@ -955,6 +935,10 @@ xfs_file_fallocate(
                        goto out_unlock;
        }
 
+       error = file_modified(file);
+       if (error)
+               goto out_unlock;
+
        if (mode & FALLOC_FL_PUNCH_HOLE) {
                error = xfs_free_file_space(ip, offset, len);
                if (error)
@@ -1004,8 +988,6 @@ xfs_file_fallocate(
                }
                do_file_insert = true;
        } else {
-               flags |= XFS_PREALLOC_SET;
-
                if (!(mode & FALLOC_FL_KEEP_SIZE) &&
                    offset + len > i_size_read(inode)) {
                        new_size = offset + len;
@@ -1057,13 +1039,6 @@ xfs_file_fallocate(
                }
        }
 
-       if (file->f_flags & O_DSYNC)
-               flags |= XFS_PREALLOC_SYNC;
-
-       error = xfs_update_prealloc_flags(ip, flags);
-       if (error)
-               goto out_unlock;
-
        /* Change file size if needed */
        if (new_size) {
                struct iattr iattr;
@@ -1082,8 +1057,14 @@ xfs_file_fallocate(
         * leave shifted extents past EOF and hence losing access to
         * the data that is contained within them.
         */
-       if (do_file_insert)
+       if (do_file_insert) {
                error = xfs_insert_file_space(ip, offset, len);
+               if (error)
+                       goto out_unlock;
+       }
+
+       if (xfs_file_sync_writes(file))
+               error = xfs_log_force_inode(ip);
 
 out_unlock:
        xfs_iunlock(ip, iolock);
@@ -1115,21 +1096,6 @@ xfs_file_fadvise(
        return ret;
 }
 
-/* Does this file, inode, or mount want synchronous writes? */
-static inline bool xfs_file_sync_writes(struct file *filp)
-{
-       struct xfs_inode        *ip = XFS_I(file_inode(filp));
-
-       if (xfs_has_wsync(ip->i_mount))
-               return true;
-       if (filp->f_flags & (__O_SYNC | O_DSYNC))
-               return true;
-       if (IS_SYNC(file_inode(filp)))
-               return true;
-
-       return false;
-}
-
 STATIC loff_t
 xfs_file_remap_range(
        struct file             *file_in,
index c447bf0..b7e8f14 100644 (file)
@@ -462,15 +462,6 @@ xfs_itruncate_extents(
 }
 
 /* from xfs_file.c */
-enum xfs_prealloc_flags {
-       XFS_PREALLOC_SET        = (1 << 1),
-       XFS_PREALLOC_CLEAR      = (1 << 2),
-       XFS_PREALLOC_SYNC       = (1 << 3),
-       XFS_PREALLOC_INVISIBLE  = (1 << 4),
-};
-
-int    xfs_update_prealloc_flags(struct xfs_inode *ip,
-                                 enum xfs_prealloc_flags flags);
 int    xfs_break_layouts(struct inode *inode, uint *iolock,
                enum layout_break_reason reason);
 
index 03a6198..2515fe8 100644 (file)
@@ -1464,7 +1464,7 @@ xfs_ioc_getbmap(
 
        if (bmx.bmv_count < 2)
                return -EINVAL;
-       if (bmx.bmv_count > ULONG_MAX / recsize)
+       if (bmx.bmv_count >= INT_MAX / recsize)
                return -ENOMEM;
 
        buf = kvcalloc(bmx.bmv_count, sizeof(*buf), GFP_KERNEL);
index d6334ab..4abe173 100644 (file)
@@ -70,6 +70,40 @@ xfs_fs_get_uuid(
        return 0;
 }
 
+/*
+ * We cannot use file based VFS helpers such as file_modified() to update
+ * inode state as we modify the data/metadata in the inode here. Hence we have
+ * to open code the timestamp updates and SUID/SGID stripping. We also need
+ * to set the inode prealloc flag to ensure that the extents we allocate are not
+ * removed if the inode is reclaimed from memory before xfs_fs_block_commit()
+ * is from the client to indicate that data has been written and the file size
+ * can be extended.
+ */
+static int
+xfs_fs_map_update_inode(
+       struct xfs_inode        *ip)
+{
+       struct xfs_trans        *tp;
+       int                     error;
+
+       error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_writeid,
+                       0, 0, 0, &tp);
+       if (error)
+               return error;
+
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+
+       VFS_I(ip)->i_mode &= ~S_ISUID;
+       if (VFS_I(ip)->i_mode & S_IXGRP)
+               VFS_I(ip)->i_mode &= ~S_ISGID;
+       xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+       ip->i_diflags |= XFS_DIFLAG_PREALLOC;
+
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+       return xfs_trans_commit(tp);
+}
+
 /*
  * Get a layout for the pNFS client.
  */
@@ -164,10 +198,12 @@ xfs_fs_map_blocks(
                 * that the blocks allocated and handed out to the client are
                 * guaranteed to be present even after a server crash.
                 */
-               error = xfs_update_prealloc_flags(ip,
-                               XFS_PREALLOC_SET | XFS_PREALLOC_SYNC);
+               error = xfs_fs_map_update_inode(ip);
+               if (!error)
+                       error = xfs_log_force_inode(ip);
                if (error)
                        goto out_unlock;
+
        } else {
                xfs_iunlock(ip, lock_flags);
        }
@@ -255,7 +291,7 @@ xfs_fs_commit_blocks(
                length = end - start;
                if (!length)
                        continue;
-       
+
                /*
                 * Make sure reads through the pagecache see the new data.
                 */
index e8f37bd..4c0dee7 100644 (file)
@@ -735,6 +735,7 @@ xfs_fs_sync_fs(
        int                     wait)
 {
        struct xfs_mount        *mp = XFS_M(sb);
+       int                     error;
 
        trace_xfs_fs_sync_fs(mp, __return_address);
 
@@ -744,7 +745,10 @@ xfs_fs_sync_fs(
        if (!wait)
                return 0;
 
-       xfs_log_force(mp, XFS_LOG_SYNC);
+       error = xfs_log_force(mp, XFS_LOG_SYNC);
+       if (error)
+               return error;
+
        if (laptop_mode) {
                /*
                 * The disk must be active because we're syncing.
index d39cfa0..52363ee 100644 (file)
@@ -24,14 +24,11 @@ static inline void blake2s_set_lastblock(struct blake2s_state *state)
        state->f[0] = -1;
 }
 
-typedef void (*blake2s_compress_t)(struct blake2s_state *state,
-                                  const u8 *block, size_t nblocks, u32 inc);
-
 /* Helper functions for BLAKE2s shared by the library and shash APIs */
 
-static inline void __blake2s_update(struct blake2s_state *state,
-                                   const u8 *in, size_t inlen,
-                                   blake2s_compress_t compress)
+static __always_inline void
+__blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen,
+                bool force_generic)
 {
        const size_t fill = BLAKE2S_BLOCK_SIZE - state->buflen;
 
@@ -39,7 +36,12 @@ static inline void __blake2s_update(struct blake2s_state *state,
                return;
        if (inlen > fill) {
                memcpy(state->buf + state->buflen, in, fill);
-               (*compress)(state, state->buf, 1, BLAKE2S_BLOCK_SIZE);
+               if (force_generic)
+                       blake2s_compress_generic(state, state->buf, 1,
+                                                BLAKE2S_BLOCK_SIZE);
+               else
+                       blake2s_compress(state, state->buf, 1,
+                                        BLAKE2S_BLOCK_SIZE);
                state->buflen = 0;
                in += fill;
                inlen -= fill;
@@ -47,7 +49,12 @@ static inline void __blake2s_update(struct blake2s_state *state,
        if (inlen > BLAKE2S_BLOCK_SIZE) {
                const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE);
                /* Hash one less (full) block than strictly possible */
-               (*compress)(state, in, nblocks - 1, BLAKE2S_BLOCK_SIZE);
+               if (force_generic)
+                       blake2s_compress_generic(state, in, nblocks - 1,
+                                                BLAKE2S_BLOCK_SIZE);
+               else
+                       blake2s_compress(state, in, nblocks - 1,
+                                        BLAKE2S_BLOCK_SIZE);
                in += BLAKE2S_BLOCK_SIZE * (nblocks - 1);
                inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1);
        }
@@ -55,13 +62,16 @@ static inline void __blake2s_update(struct blake2s_state *state,
        state->buflen += inlen;
 }
 
-static inline void __blake2s_final(struct blake2s_state *state, u8 *out,
-                                  blake2s_compress_t compress)
+static __always_inline void
+__blake2s_final(struct blake2s_state *state, u8 *out, bool force_generic)
 {
        blake2s_set_lastblock(state);
        memset(state->buf + state->buflen, 0,
               BLAKE2S_BLOCK_SIZE - state->buflen); /* Padding */
-       (*compress)(state, state->buf, 1, state->buflen);
+       if (force_generic)
+               blake2s_compress_generic(state, state->buf, 1, state->buflen);
+       else
+               blake2s_compress(state, state->buf, 1, state->buflen);
        cpu_to_le32_array(state->h, ARRAY_SIZE(state->h));
        memcpy(out, state->h, state->outlen);
 }
@@ -99,20 +109,20 @@ static inline int crypto_blake2s_init(struct shash_desc *desc)
 
 static inline int crypto_blake2s_update(struct shash_desc *desc,
                                        const u8 *in, unsigned int inlen,
-                                       blake2s_compress_t compress)
+                                       bool force_generic)
 {
        struct blake2s_state *state = shash_desc_ctx(desc);
 
-       __blake2s_update(state, in, inlen, compress);
+       __blake2s_update(state, in, inlen, force_generic);
        return 0;
 }
 
 static inline int crypto_blake2s_final(struct shash_desc *desc, u8 *out,
-                                      blake2s_compress_t compress)
+                                      bool force_generic)
 {
        struct blake2s_state *state = shash_desc_ctx(desc);
 
-       __blake2s_final(state, out, compress);
+       __blake2s_final(state, out, force_generic);
        return 0;
 }
 
index 98e1b2a..3e3972a 100644 (file)
@@ -24,6 +24,7 @@
 #define PMC_PLLACK             7
 #define PMC_PLLBCK             8
 #define PMC_AUDIOPLLCK         9
+#define PMC_AUDIOPINCK         10
 
 /* SAMA7G5 */
 #define PMC_CPUPLL             (PMC_MAIN + 1)
@@ -35,6 +36,7 @@
 #define PMC_AUDIOIOPLL         (PMC_MAIN + 7)
 #define PMC_ETHPLL             (PMC_MAIN + 8)
 #define PMC_CPU                        (PMC_MAIN + 9)
+#define PMC_MCK1               (PMC_MAIN + 10)
 
 #ifndef AT91_PMC_MOSCS
 #define AT91_PMC_MOSCS         0               /* MOSCS Flag */
diff --git a/include/dt-bindings/clock/cirrus,cs2000-cp.h b/include/dt-bindings/clock/cirrus,cs2000-cp.h
new file mode 100644 (file)
index 0000000..fe3ac71
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2021 Daniel Mack
+ */
+
+#ifndef __DT_BINDINGS_CS2000CP_CLK_H
+#define __DT_BINDINGS_CS2000CP_CLK_H
+
+#define CS2000CP_AUX_OUTPUT_REF_CLK    0
+#define CS2000CP_AUX_OUTPUT_CLK_IN     1
+#define CS2000CP_AUX_OUTPUT_CLK_OUT    2
+#define CS2000CP_AUX_OUTPUT_PLL_LOCK   3
+
+#endif /* __DT_BINDINGS_CS2000CP_CLK_H */
index 7d57063..29ff6b8 100644 (file)
 #define DRA7_L3_MAIN_2_CLKCTRL DRA7_CLKCTRL_INDEX(0x20)
 #define DRA7_L3_INSTR_CLKCTRL  DRA7_CLKCTRL_INDEX(0x28)
 
-/* iva clocks */
-#define DRA7_IVA_CLKCTRL       DRA7_CLKCTRL_INDEX(0x20)
-#define DRA7_SL2IF_CLKCTRL     DRA7_CLKCTRL_INDEX(0x28)
-
 /* dss clocks */
 #define DRA7_DSS_CORE_CLKCTRL  DRA7_CLKCTRL_INDEX(0x20)
 #define DRA7_BB2D_CLKCTRL      DRA7_CLKCTRL_INDEX(0x30)
 
-/* gpu clocks */
-#define DRA7_GPU_CLKCTRL       DRA7_CLKCTRL_INDEX(0x20)
-
 /* l3init clocks */
 #define DRA7_MMC1_CLKCTRL      DRA7_CLKCTRL_INDEX(0x28)
 #define DRA7_MMC2_CLKCTRL      DRA7_CLKCTRL_INDEX(0x30)
 #define DRA7_L3INSTR_L3_MAIN_2_CLKCTRL DRA7_CLKCTRL_INDEX(0x20)
 #define DRA7_L3INSTR_L3_INSTR_CLKCTRL  DRA7_CLKCTRL_INDEX(0x28)
 
+/* iva clocks */
+#define DRA7_IVA_CLKCTRL               DRA7_CLKCTRL_INDEX(0x20)
+#define DRA7_SL2IF_CLKCTRL             DRA7_CLKCTRL_INDEX(0x28)
+
 /* dss clocks */
 #define DRA7_DSS_DSS_CORE_CLKCTRL      DRA7_CLKCTRL_INDEX(0x20)
 #define DRA7_DSS_BB2D_CLKCTRL  DRA7_CLKCTRL_INDEX(0x30)
 
+/* gpu clocks */
+#define DRA7_GPU_CLKCTRL               DRA7_CLKCTRL_INDEX(0x20)
+
 /* l3init clocks */
 #define DRA7_L3INIT_MMC1_CLKCTRL       DRA7_CLKCTRL_INDEX(0x28)
 #define DRA7_L3INIT_MMC2_CLKCTRL       DRA7_CLKCTRL_INDEX(0x30)
diff --git a/include/dt-bindings/clock/microchip,mpfs-clock.h b/include/dt-bindings/clock/microchip,mpfs-clock.h
new file mode 100644 (file)
index 0000000..73f2a93
--- /dev/null
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Daire McNamara,<daire.mcnamara@microchip.com>
+ * Copyright (C) 2020 Microchip Technology Inc.  All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_CLK_MICROCHIP_MPFS_H_
+#define _DT_BINDINGS_CLK_MICROCHIP_MPFS_H_
+
+#define CLK_CPU                0
+#define CLK_AXI                1
+#define CLK_AHB                2
+
+#define CLK_ENVM       3
+#define CLK_MAC0       4
+#define CLK_MAC1       5
+#define CLK_MMC                6
+#define CLK_TIMER      7
+#define CLK_MMUART0    8
+#define CLK_MMUART1    9
+#define CLK_MMUART2    10
+#define CLK_MMUART3    11
+#define CLK_MMUART4    12
+#define CLK_SPI0       13
+#define CLK_SPI1       14
+#define CLK_I2C0       15
+#define CLK_I2C1       16
+#define CLK_CAN0       17
+#define CLK_CAN1       18
+#define CLK_USB                19
+#define CLK_RESERVED   20
+#define CLK_RTC                21
+#define CLK_QSPI       22
+#define CLK_GPIO0      23
+#define CLK_GPIO1      24
+#define CLK_GPIO2      25
+#define CLK_DDRC       26
+#define CLK_FIC0       27
+#define CLK_FIC1       28
+#define CLK_FIC2       29
+#define CLK_FIC3       30
+#define CLK_ATHENA     31
+#define CLK_CFM                32
+
+#endif /* _DT_BINDINGS_CLK_MICROCHIP_MPFS_H_ */
diff --git a/include/dt-bindings/clock/r9a07g054-cpg.h b/include/dt-bindings/clock/r9a07g054-cpg.h
new file mode 100644 (file)
index 0000000..43f4dbd
--- /dev/null
@@ -0,0 +1,229 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+ *
+ * Copyright (C) 2022 Renesas Electronics Corp.
+ */
+#ifndef __DT_BINDINGS_CLOCK_R9A07G054_CPG_H__
+#define __DT_BINDINGS_CLOCK_R9A07G054_CPG_H__
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+/* R9A07G054 CPG Core Clocks */
+#define R9A07G054_CLK_I                        0
+#define R9A07G054_CLK_I2               1
+#define R9A07G054_CLK_G                        2
+#define R9A07G054_CLK_S0               3
+#define R9A07G054_CLK_S1               4
+#define R9A07G054_CLK_SPI0             5
+#define R9A07G054_CLK_SPI1             6
+#define R9A07G054_CLK_SD0              7
+#define R9A07G054_CLK_SD1              8
+#define R9A07G054_CLK_M0               9
+#define R9A07G054_CLK_M1               10
+#define R9A07G054_CLK_M2               11
+#define R9A07G054_CLK_M3               12
+#define R9A07G054_CLK_M4               13
+#define R9A07G054_CLK_HP               14
+#define R9A07G054_CLK_TSU              15
+#define R9A07G054_CLK_ZT               16
+#define R9A07G054_CLK_P0               17
+#define R9A07G054_CLK_P1               18
+#define R9A07G054_CLK_P2               19
+#define R9A07G054_CLK_AT               20
+#define R9A07G054_OSCCLK               21
+#define R9A07G054_CLK_P0_DIV2          22
+#define R9A07G054_CLK_DRP_M            23
+#define R9A07G054_CLK_DRP_D            24
+#define R9A07G054_CLK_DRP_A            25
+
+/* R9A07G054 Module Clocks */
+#define R9A07G054_CA55_SCLK            0
+#define R9A07G054_CA55_PCLK            1
+#define R9A07G054_CA55_ATCLK           2
+#define R9A07G054_CA55_GICCLK          3
+#define R9A07G054_CA55_PERICLK         4
+#define R9A07G054_CA55_ACLK            5
+#define R9A07G054_CA55_TSCLK           6
+#define R9A07G054_GIC600_GICCLK                7
+#define R9A07G054_IA55_CLK             8
+#define R9A07G054_IA55_PCLK            9
+#define R9A07G054_MHU_PCLK             10
+#define R9A07G054_SYC_CNT_CLK          11
+#define R9A07G054_DMAC_ACLK            12
+#define R9A07G054_DMAC_PCLK            13
+#define R9A07G054_OSTM0_PCLK           14
+#define R9A07G054_OSTM1_PCLK           15
+#define R9A07G054_OSTM2_PCLK           16
+#define R9A07G054_MTU_X_MCK_MTU3       17
+#define R9A07G054_POE3_CLKM_POE                18
+#define R9A07G054_GPT_PCLK             19
+#define R9A07G054_POEG_A_CLKP          20
+#define R9A07G054_POEG_B_CLKP          21
+#define R9A07G054_POEG_C_CLKP          22
+#define R9A07G054_POEG_D_CLKP          23
+#define R9A07G054_WDT0_PCLK            24
+#define R9A07G054_WDT0_CLK             25
+#define R9A07G054_WDT1_PCLK            26
+#define R9A07G054_WDT1_CLK             27
+#define R9A07G054_WDT2_PCLK            28
+#define R9A07G054_WDT2_CLK             29
+#define R9A07G054_SPI_CLK2             30
+#define R9A07G054_SPI_CLK              31
+#define R9A07G054_SDHI0_IMCLK          32
+#define R9A07G054_SDHI0_IMCLK2         33
+#define R9A07G054_SDHI0_CLK_HS         34
+#define R9A07G054_SDHI0_ACLK           35
+#define R9A07G054_SDHI1_IMCLK          36
+#define R9A07G054_SDHI1_IMCLK2         37
+#define R9A07G054_SDHI1_CLK_HS         38
+#define R9A07G054_SDHI1_ACLK           39
+#define R9A07G054_GPU_CLK              40
+#define R9A07G054_GPU_AXI_CLK          41
+#define R9A07G054_GPU_ACE_CLK          42
+#define R9A07G054_ISU_ACLK             43
+#define R9A07G054_ISU_PCLK             44
+#define R9A07G054_H264_CLK_A           45
+#define R9A07G054_H264_CLK_P           46
+#define R9A07G054_CRU_SYSCLK           47
+#define R9A07G054_CRU_VCLK             48
+#define R9A07G054_CRU_PCLK             49
+#define R9A07G054_CRU_ACLK             50
+#define R9A07G054_MIPI_DSI_PLLCLK      51
+#define R9A07G054_MIPI_DSI_SYSCLK      52
+#define R9A07G054_MIPI_DSI_ACLK                53
+#define R9A07G054_MIPI_DSI_PCLK                54
+#define R9A07G054_MIPI_DSI_VCLK                55
+#define R9A07G054_MIPI_DSI_LPCLK       56
+#define R9A07G054_LCDC_CLK_A           57
+#define R9A07G054_LCDC_CLK_P           58
+#define R9A07G054_LCDC_CLK_D           59
+#define R9A07G054_SSI0_PCLK2           60
+#define R9A07G054_SSI0_PCLK_SFR                61
+#define R9A07G054_SSI1_PCLK2           62
+#define R9A07G054_SSI1_PCLK_SFR                63
+#define R9A07G054_SSI2_PCLK2           64
+#define R9A07G054_SSI2_PCLK_SFR                65
+#define R9A07G054_SSI3_PCLK2           66
+#define R9A07G054_SSI3_PCLK_SFR                67
+#define R9A07G054_SRC_CLKP             68
+#define R9A07G054_USB_U2H0_HCLK                69
+#define R9A07G054_USB_U2H1_HCLK                70
+#define R9A07G054_USB_U2P_EXR_CPUCLK   71
+#define R9A07G054_USB_PCLK             72
+#define R9A07G054_ETH0_CLK_AXI         73
+#define R9A07G054_ETH0_CLK_CHI         74
+#define R9A07G054_ETH1_CLK_AXI         75
+#define R9A07G054_ETH1_CLK_CHI         76
+#define R9A07G054_I2C0_PCLK            77
+#define R9A07G054_I2C1_PCLK            78
+#define R9A07G054_I2C2_PCLK            79
+#define R9A07G054_I2C3_PCLK            80
+#define R9A07G054_SCIF0_CLK_PCK                81
+#define R9A07G054_SCIF1_CLK_PCK                82
+#define R9A07G054_SCIF2_CLK_PCK                83
+#define R9A07G054_SCIF3_CLK_PCK                84
+#define R9A07G054_SCIF4_CLK_PCK                85
+#define R9A07G054_SCI0_CLKP            86
+#define R9A07G054_SCI1_CLKP            87
+#define R9A07G054_IRDA_CLKP            88
+#define R9A07G054_RSPI0_CLKB           89
+#define R9A07G054_RSPI1_CLKB           90
+#define R9A07G054_RSPI2_CLKB           91
+#define R9A07G054_CANFD_PCLK           92
+#define R9A07G054_GPIO_HCLK            93
+#define R9A07G054_ADC_ADCLK            94
+#define R9A07G054_ADC_PCLK             95
+#define R9A07G054_TSU_PCLK             96
+#define R9A07G054_STPAI_INITCLK                97
+#define R9A07G054_STPAI_ACLK           98
+#define R9A07G054_STPAI_MCLK           99
+#define R9A07G054_STPAI_DCLKIN         100
+#define R9A07G054_STPAI_ACLK_DRP       101
+
+/* R9A07G054 Resets */
+#define R9A07G054_CA55_RST_1_0         0
+#define R9A07G054_CA55_RST_1_1         1
+#define R9A07G054_CA55_RST_3_0         2
+#define R9A07G054_CA55_RST_3_1         3
+#define R9A07G054_CA55_RST_4           4
+#define R9A07G054_CA55_RST_5           5
+#define R9A07G054_CA55_RST_6           6
+#define R9A07G054_CA55_RST_7           7
+#define R9A07G054_CA55_RST_8           8
+#define R9A07G054_CA55_RST_9           9
+#define R9A07G054_CA55_RST_10          10
+#define R9A07G054_CA55_RST_11          11
+#define R9A07G054_CA55_RST_12          12
+#define R9A07G054_GIC600_GICRESET_N    13
+#define R9A07G054_GIC600_DBG_GICRESET_N        14
+#define R9A07G054_IA55_RESETN          15
+#define R9A07G054_MHU_RESETN           16
+#define R9A07G054_DMAC_ARESETN         17
+#define R9A07G054_DMAC_RST_ASYNC       18
+#define R9A07G054_SYC_RESETN           19
+#define R9A07G054_OSTM0_PRESETZ                20
+#define R9A07G054_OSTM1_PRESETZ                21
+#define R9A07G054_OSTM2_PRESETZ                22
+#define R9A07G054_MTU_X_PRESET_MTU3    23
+#define R9A07G054_POE3_RST_M_REG       24
+#define R9A07G054_GPT_RST_C            25
+#define R9A07G054_POEG_A_RST           26
+#define R9A07G054_POEG_B_RST           27
+#define R9A07G054_POEG_C_RST           28
+#define R9A07G054_POEG_D_RST           29
+#define R9A07G054_WDT0_PRESETN         30
+#define R9A07G054_WDT1_PRESETN         31
+#define R9A07G054_WDT2_PRESETN         32
+#define R9A07G054_SPI_RST              33
+#define R9A07G054_SDHI0_IXRST          34
+#define R9A07G054_SDHI1_IXRST          35
+#define R9A07G054_GPU_RESETN           36
+#define R9A07G054_GPU_AXI_RESETN       37
+#define R9A07G054_GPU_ACE_RESETN       38
+#define R9A07G054_ISU_ARESETN          39
+#define R9A07G054_ISU_PRESETN          40
+#define R9A07G054_H264_X_RESET_VCP     41
+#define R9A07G054_H264_CP_PRESET_P     42
+#define R9A07G054_CRU_CMN_RSTB         43
+#define R9A07G054_CRU_PRESETN          44
+#define R9A07G054_CRU_ARESETN          45
+#define R9A07G054_MIPI_DSI_CMN_RSTB    46
+#define R9A07G054_MIPI_DSI_ARESET_N    47
+#define R9A07G054_MIPI_DSI_PRESET_N    48
+#define R9A07G054_LCDC_RESET_N         49
+#define R9A07G054_SSI0_RST_M2_REG      50
+#define R9A07G054_SSI1_RST_M2_REG      51
+#define R9A07G054_SSI2_RST_M2_REG      52
+#define R9A07G054_SSI3_RST_M2_REG      53
+#define R9A07G054_SRC_RST              54
+#define R9A07G054_USB_U2H0_HRESETN     55
+#define R9A07G054_USB_U2H1_HRESETN     56
+#define R9A07G054_USB_U2P_EXL_SYSRST   57
+#define R9A07G054_USB_PRESETN          58
+#define R9A07G054_ETH0_RST_HW_N                59
+#define R9A07G054_ETH1_RST_HW_N                60
+#define R9A07G054_I2C0_MRST            61
+#define R9A07G054_I2C1_MRST            62
+#define R9A07G054_I2C2_MRST            63
+#define R9A07G054_I2C3_MRST            64
+#define R9A07G054_SCIF0_RST_SYSTEM_N   65
+#define R9A07G054_SCIF1_RST_SYSTEM_N   66
+#define R9A07G054_SCIF2_RST_SYSTEM_N   67
+#define R9A07G054_SCIF3_RST_SYSTEM_N   68
+#define R9A07G054_SCIF4_RST_SYSTEM_N   69
+#define R9A07G054_SCI0_RST             70
+#define R9A07G054_SCI1_RST             71
+#define R9A07G054_IRDA_RST             72
+#define R9A07G054_RSPI0_RST            73
+#define R9A07G054_RSPI1_RST            74
+#define R9A07G054_RSPI2_RST            75
+#define R9A07G054_CANFD_RSTP_N         76
+#define R9A07G054_CANFD_RSTC_N         77
+#define R9A07G054_GPIO_RSTN            78
+#define R9A07G054_GPIO_PORT_RESETN     79
+#define R9A07G054_GPIO_SPARE_RESETN    80
+#define R9A07G054_ADC_PRESETN          81
+#define R9A07G054_ADC_ADRST_N          82
+#define R9A07G054_TSU_PRESETN          83
+#define R9A07G054_STPAI_ARESETN                84
+
+#endif /* __DT_BINDINGS_CLOCK_R9A07G054_CPG_H__ */
index 199e47e..21292b5 100644 (file)
@@ -324,12 +324,12 @@ enum {
        ATA_LOG_NCQ_NON_DATA    = 0x12,
        ATA_LOG_NCQ_SEND_RECV   = 0x13,
        ATA_LOG_IDENTIFY_DEVICE = 0x30,
+       ATA_LOG_CONCURRENT_POSITIONING_RANGES = 0x47,
 
        /* Identify device log pages: */
        ATA_LOG_SECURITY          = 0x06,
        ATA_LOG_SATA_SETTINGS     = 0x08,
        ATA_LOG_ZONED_INFORMATION = 0x09,
-       ATA_LOG_CONCURRENT_POSITIONING_RANGES = 0x47,
 
        /* Identify device SATA settings log:*/
        ATA_LOG_DEVSLP_OFFSET     = 0x30,
index 9c95df2..f35aea9 100644 (file)
@@ -1258,6 +1258,7 @@ unsigned long disk_start_io_acct(struct gendisk *disk, unsigned int sectors,
 void disk_end_io_acct(struct gendisk *disk, unsigned int op,
                unsigned long start_time);
 
+void bio_start_io_acct_time(struct bio *bio, unsigned long start_time);
 unsigned long bio_start_io_acct(struct bio *bio);
 void bio_end_io_acct_remapped(struct bio *bio, unsigned long start_time,
                struct block_device *orig_bdev);
index 6a89ea4..edf62ea 100644 (file)
@@ -35,6 +35,7 @@
 #define CEPH_OPT_TCP_NODELAY      (1<<4) /* TCP_NODELAY on TCP sockets */
 #define CEPH_OPT_NOMSGSIGN        (1<<5) /* don't sign msgs (msgr1) */
 #define CEPH_OPT_ABORT_ON_FULL    (1<<6) /* abort w/ ENOSPC when full */
+#define CEPH_OPT_RXBOUNCE         (1<<7) /* double-buffer read data */
 
 #define CEPH_OPT_DEFAULT   (CEPH_OPT_TCP_NODELAY)
 
index ff99ce0..e7f2fb2 100644 (file)
@@ -383,6 +383,10 @@ struct ceph_connection_v2_info {
        struct ceph_gcm_nonce in_gcm_nonce;
        struct ceph_gcm_nonce out_gcm_nonce;
 
+       struct page **in_enc_pages;
+       int in_enc_page_cnt;
+       int in_enc_resid;
+       int in_enc_i;
        struct page **out_enc_pages;
        int out_enc_page_cnt;
        int out_enc_resid;
@@ -457,6 +461,7 @@ struct ceph_connection {
        struct ceph_msg *out_msg;        /* sending message (== tail of
                                            out_sent) */
 
+       struct page *bounce_page;
        u32 in_front_crc, in_middle_crc, in_data_crc;  /* calculated crc */
 
        struct timespec64 last_keepalive_ack; /* keepalive2 ack stamp */
index 2faa6f7..c10dc4c 100644 (file)
@@ -888,7 +888,7 @@ void clk_hw_unregister_divider(struct clk_hw *hw);
 struct clk_mux {
        struct clk_hw   hw;
        void __iomem    *reg;
-       u32             *table;
+       const u32       *table;
        u32             mask;
        u8              shift;
        u8              flags;
@@ -913,18 +913,18 @@ struct clk_hw *__clk_hw_register_mux(struct device *dev, struct device_node *np,
                const struct clk_hw **parent_hws,
                const struct clk_parent_data *parent_data,
                unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
-               u8 clk_mux_flags, u32 *table, spinlock_t *lock);
+               u8 clk_mux_flags, const u32 *table, spinlock_t *lock);
 struct clk_hw *__devm_clk_hw_register_mux(struct device *dev, struct device_node *np,
                const char *name, u8 num_parents,
                const char * const *parent_names,
                const struct clk_hw **parent_hws,
                const struct clk_parent_data *parent_data,
                unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
-               u8 clk_mux_flags, u32 *table, spinlock_t *lock);
+               u8 clk_mux_flags, const u32 *table, spinlock_t *lock);
 struct clk *clk_register_mux_table(struct device *dev, const char *name,
                const char * const *parent_names, u8 num_parents,
                unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
-               u8 clk_mux_flags, u32 *table, spinlock_t *lock);
+               u8 clk_mux_flags, const u32 *table, spinlock_t *lock);
 
 #define clk_register_mux(dev, name, parent_names, num_parents, flags, reg,    \
                         shift, width, clk_mux_flags, lock)                   \
@@ -962,9 +962,9 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
                              (shift), BIT((width)) - 1, (clk_mux_flags),     \
                              NULL, (lock))
 
-int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags,
+int clk_mux_val_to_index(struct clk_hw *hw, const u32 *table, unsigned int flags,
                         unsigned int val);
-unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index);
+unsigned int clk_mux_index_to_val(const u32 *table, unsigned int flags, u8 index);
 
 void clk_unregister_mux(struct clk *clk);
 void clk_hw_unregister_mux(struct clk_hw *hw);
@@ -1003,6 +1003,9 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw);
 struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev,
                const char *name, const char *parent_name, unsigned long flags,
                unsigned int mult, unsigned int div);
+struct clk_hw *devm_clk_hw_register_fixed_factor_index(struct device *dev,
+               const char *name, unsigned int index, unsigned long flags,
+               unsigned int mult, unsigned int div);
 /**
  * struct clk_fractional_divider - adjustable fractional divider clock
  *
index 429dceb..0f7fd20 100644 (file)
@@ -117,14 +117,6 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
  */
 #define __stringify_label(n) #n
 
-#define __annotate_reachable(c) ({                                     \
-       asm volatile(__stringify_label(c) ":\n\t"                       \
-                    ".pushsection .discard.reachable\n\t"              \
-                    ".long " __stringify_label(c) "b - .\n\t"          \
-                    ".popsection\n\t" : : "i" (c));                    \
-})
-#define annotate_reachable() __annotate_reachable(__COUNTER__)
-
 #define __annotate_unreachable(c) ({                                   \
        asm volatile(__stringify_label(c) ":\n\t"                       \
                     ".pushsection .discard.unreachable\n\t"            \
@@ -133,24 +125,21 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
 })
 #define annotate_unreachable() __annotate_unreachable(__COUNTER__)
 
-#define ASM_UNREACHABLE                                                        \
-       "999:\n\t"                                                      \
-       ".pushsection .discard.unreachable\n\t"                         \
-       ".long 999b - .\n\t"                                            \
+#define ASM_REACHABLE                                                  \
+       "998:\n\t"                                                      \
+       ".pushsection .discard.reachable\n\t"                           \
+       ".long 998b - .\n\t"                                            \
        ".popsection\n\t"
 
 /* Annotate a C jump table to allow objtool to follow the code flow */
 #define __annotate_jump_table __section(".rodata..c_jump_table")
 
 #else
-#define annotate_reachable()
 #define annotate_unreachable()
+# define ASM_REACHABLE
 #define __annotate_jump_table
 #endif
 
-#ifndef ASM_UNREACHABLE
-# define ASM_UNREACHABLE
-#endif
 #ifndef unreachable
 # define unreachable() do {            \
        annotate_unreachable();         \
index a26f37a..11efc45 100644 (file)
@@ -111,7 +111,7 @@ struct ethtool_link_ext_state_info {
                enum ethtool_link_ext_substate_bad_signal_integrity bad_signal_integrity;
                enum ethtool_link_ext_substate_cable_issue cable_issue;
                enum ethtool_link_ext_substate_module module;
-               u8 __link_ext_substate;
+               u32 __link_ext_substate;
        };
 };
 
index 3da9584..02f362c 100644 (file)
@@ -262,7 +262,7 @@ struct fb_ops {
 
        /* Draws a rectangle */
        void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
-       /* Copy data from area to another. Obsolete. */
+       /* Copy data from area to another */
        void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
        /* Draws a image to the display */
        void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
index f3daaea..e2d892b 100644 (file)
@@ -1483,7 +1483,7 @@ struct super_block {
 #ifdef CONFIG_FS_VERITY
        const struct fsverity_operations *s_vop;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        struct unicode_map *s_encoding;
        __u16 s_encoding_flags;
 #endif
index 3a2d7dc..bb8467c 100644 (file)
@@ -224,6 +224,43 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode,
                      dir, &new_dentry->d_name, 0);
 }
 
+/*
+ * fsnotify_delete - @dentry was unlinked and unhashed
+ *
+ * Caller must make sure that dentry->d_name is stable.
+ *
+ * Note: unlike fsnotify_unlink(), we have to pass also the unlinked inode
+ * as this may be called after d_delete() and old_dentry may be negative.
+ */
+static inline void fsnotify_delete(struct inode *dir, struct inode *inode,
+                                  struct dentry *dentry)
+{
+       __u32 mask = FS_DELETE;
+
+       if (S_ISDIR(inode->i_mode))
+               mask |= FS_ISDIR;
+
+       fsnotify_name(mask, inode, FSNOTIFY_EVENT_INODE, dir, &dentry->d_name,
+                     0);
+}
+
+/**
+ * d_delete_notify - delete a dentry and call fsnotify_delete()
+ * @dentry: The dentry to delete
+ *
+ * This helper is used to guaranty that the unlinked inode cannot be found
+ * by lookup of this name after fsnotify_delete() event has been delivered.
+ */
+static inline void d_delete_notify(struct inode *dir, struct dentry *dentry)
+{
+       struct inode *inode = d_inode(dentry);
+
+       ihold(inode);
+       d_delete(dentry);
+       fsnotify_delete(dir, inode, dentry);
+       iput(inode);
+}
+
 /*
  * fsnotify_unlink - 'name' was unlinked
  *
@@ -231,10 +268,10 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode,
  */
 static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry)
 {
-       /* Expected to be called before d_delete() */
-       WARN_ON_ONCE(d_is_negative(dentry));
+       if (WARN_ON_ONCE(d_is_negative(dentry)))
+               return;
 
-       fsnotify_dirent(dir, dentry, FS_DELETE);
+       fsnotify_delete(dir, d_inode(dentry), dentry);
 }
 
 /*
@@ -258,10 +295,10 @@ static inline void fsnotify_mkdir(struct inode *dir, struct dentry *dentry)
  */
 static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry)
 {
-       /* Expected to be called before d_delete() */
-       WARN_ON_ONCE(d_is_negative(dentry));
+       if (WARN_ON_ONCE(d_is_negative(dentry)))
+               return;
 
-       fsnotify_dirent(dir, dentry, FS_DELETE | FS_ISDIR);
+       fsnotify_delete(dir, d_inode(dentry), dentry);
 }
 
 /*
index 8420fe5..2be4dd7 100644 (file)
@@ -46,8 +46,10 @@ struct vlan_hdr {
  *     @h_vlan_encapsulated_proto: packet type ID or len
  */
 struct vlan_ethhdr {
-       unsigned char   h_dest[ETH_ALEN];
-       unsigned char   h_source[ETH_ALEN];
+       struct_group(addrs,
+               unsigned char   h_dest[ETH_ALEN];
+               unsigned char   h_source[ETH_ALEN];
+       );
        __be16          h_vlan_proto;
        __be16          h_vlan_TCI;
        __be16          h_vlan_encapsulated_proto;
index b55bd49..97a3a2e 100644 (file)
@@ -263,9 +263,11 @@ struct iomap_ioend {
        struct list_head        io_list;        /* next ioend in chain */
        u16                     io_type;
        u16                     io_flags;       /* IOMAP_F_* */
+       u32                     io_folios;      /* folios added to ioend */
        struct inode            *io_inode;      /* file being written to */
        size_t                  io_size;        /* size of the extent */
        loff_t                  io_offset;      /* offset in the file */
+       sector_t                io_sector;      /* start sector of ioend */
        struct bio              *io_bio;        /* bio being built */
        struct bio              io_inline_bio;  /* MUST BE LAST! */
 };
index fd933c4..9c3ada7 100644 (file)
@@ -594,7 +594,7 @@ struct transaction_s
         */
        unsigned long           t_log_start;
 
-       /* 
+       /*
         * Number of buffers on the t_buffers list [j_list_lock, no locks
         * needed for jbd2 thread]
         */
@@ -1295,7 +1295,7 @@ struct journal_s
         * Clean-up after fast commit or full commit. JBD2 calls this function
         * after every commit operation.
         */
-       void (*j_fc_cleanup_callback)(struct journal_s *journal, int);
+       void (*j_fc_cleanup_callback)(struct journal_s *journal, int full, tid_t tid);
 
        /**
         * @j_fc_replay_callback:
@@ -1419,9 +1419,7 @@ extern void jbd2_journal_unfile_buffer(journal_t *, struct journal_head *);
 extern bool __jbd2_journal_refile_buffer(struct journal_head *);
 extern void jbd2_journal_refile_buffer(journal_t *, struct journal_head *);
 extern void __jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int);
-extern void __journal_free_buffer(struct journal_head *bh);
 extern void jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int);
-extern void __journal_clean_data_list(transaction_t *transaction);
 static inline void jbd2_file_log_bh(struct list_head *head, struct buffer_head *bh)
 {
        list_add_tail(&bh->b_assoc_buffers, head);
@@ -1486,9 +1484,6 @@ extern int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
                                              struct buffer_head **bh_out,
                                              sector_t blocknr);
 
-/* Transaction locking */
-extern void            __wait_on_journal (journal_t *);
-
 /* Transaction cache support */
 extern void jbd2_journal_destroy_transaction_cache(void);
 extern int __init jbd2_journal_init_transaction_cache(void);
@@ -1543,6 +1538,8 @@ extern int         jbd2_journal_flush(journal_t *journal, unsigned int flags);
 extern void     jbd2_journal_lock_updates (journal_t *);
 extern void     jbd2_journal_unlock_updates (journal_t *);
 
+void jbd2_journal_wait_updates(journal_t *);
+
 extern journal_t * jbd2_journal_init_dev(struct block_device *bdev,
                                struct block_device *fs_dev,
                                unsigned long long start, int len, int bsize);
@@ -1774,8 +1771,6 @@ static inline unsigned long jbd2_log_space_left(journal_t *journal)
 #define BJ_Reserved    4       /* Buffer is reserved for access by journal */
 #define BJ_Types       5
 
-extern int jbd_blocks_per_page(struct inode *inode);
-
 /* JBD uses a CRC32 checksum */
 #define JBD_MAX_CHECKSUM_SIZE 4
 
index 4b5e367..f49e642 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/atomic.h>
 #include <linux/static_key.h>
 
+extern unsigned long kfence_sample_interval;
+
 /*
  * We allocate an even number of pages, as it simplifies calculations to map
  * address to metadata indices; effectively, the very first page serves as an
index 06912d6..f110399 100644 (file)
@@ -29,7 +29,9 @@
 #include <linux/refcount.h>
 #include <linux/nospec.h>
 #include <linux/notifier.h>
+#include <linux/ftrace.h>
 #include <linux/hashtable.h>
+#include <linux/instrumentation.h>
 #include <linux/interval_tree.h>
 #include <linux/rbtree.h>
 #include <linux/xarray.h>
@@ -368,8 +370,11 @@ struct kvm_vcpu {
        u64 last_used_slot_gen;
 };
 
-/* must be called with irqs disabled */
-static __always_inline void guest_enter_irqoff(void)
+/*
+ * Start accounting time towards a guest.
+ * Must be called before entering guest context.
+ */
+static __always_inline void guest_timing_enter_irqoff(void)
 {
        /*
         * This is running in ioctl context so its safe to assume that it's the
@@ -378,7 +383,18 @@ static __always_inline void guest_enter_irqoff(void)
        instrumentation_begin();
        vtime_account_guest_enter();
        instrumentation_end();
+}
 
+/*
+ * Enter guest context and enter an RCU extended quiescent state.
+ *
+ * Between guest_context_enter_irqoff() and guest_context_exit_irqoff() it is
+ * unsafe to use any code which may directly or indirectly use RCU, tracing
+ * (including IRQ flag tracing), or lockdep. All code in this period must be
+ * non-instrumentable.
+ */
+static __always_inline void guest_context_enter_irqoff(void)
+{
        /*
         * KVM does not hold any references to rcu protected data when it
         * switches CPU into a guest mode. In fact switching to a guest mode
@@ -394,16 +410,79 @@ static __always_inline void guest_enter_irqoff(void)
        }
 }
 
-static __always_inline void guest_exit_irqoff(void)
+/*
+ * Deprecated. Architectures should move to guest_timing_enter_irqoff() and
+ * guest_state_enter_irqoff().
+ */
+static __always_inline void guest_enter_irqoff(void)
+{
+       guest_timing_enter_irqoff();
+       guest_context_enter_irqoff();
+}
+
+/**
+ * guest_state_enter_irqoff - Fixup state when entering a guest
+ *
+ * Entry to a guest will enable interrupts, but the kernel state is interrupts
+ * disabled when this is invoked. Also tell RCU about it.
+ *
+ * 1) Trace interrupts on state
+ * 2) Invoke context tracking if enabled to adjust RCU state
+ * 3) Tell lockdep that interrupts are enabled
+ *
+ * Invoked from architecture specific code before entering a guest.
+ * Must be called with interrupts disabled and the caller must be
+ * non-instrumentable.
+ * The caller has to invoke guest_timing_enter_irqoff() before this.
+ *
+ * Note: this is analogous to exit_to_user_mode().
+ */
+static __always_inline void guest_state_enter_irqoff(void)
+{
+       instrumentation_begin();
+       trace_hardirqs_on_prepare();
+       lockdep_hardirqs_on_prepare(CALLER_ADDR0);
+       instrumentation_end();
+
+       guest_context_enter_irqoff();
+       lockdep_hardirqs_on(CALLER_ADDR0);
+}
+
+/*
+ * Exit guest context and exit an RCU extended quiescent state.
+ *
+ * Between guest_context_enter_irqoff() and guest_context_exit_irqoff() it is
+ * unsafe to use any code which may directly or indirectly use RCU, tracing
+ * (including IRQ flag tracing), or lockdep. All code in this period must be
+ * non-instrumentable.
+ */
+static __always_inline void guest_context_exit_irqoff(void)
 {
        context_tracking_guest_exit();
+}
 
+/*
+ * Stop accounting time towards a guest.
+ * Must be called after exiting guest context.
+ */
+static __always_inline void guest_timing_exit_irqoff(void)
+{
        instrumentation_begin();
        /* Flush the guest cputime we spent on the guest */
        vtime_account_guest_exit();
        instrumentation_end();
 }
 
+/*
+ * Deprecated. Architectures should move to guest_state_exit_irqoff() and
+ * guest_timing_exit_irqoff().
+ */
+static __always_inline void guest_exit_irqoff(void)
+{
+       guest_context_exit_irqoff();
+       guest_timing_exit_irqoff();
+}
+
 static inline void guest_exit(void)
 {
        unsigned long flags;
@@ -413,6 +492,33 @@ static inline void guest_exit(void)
        local_irq_restore(flags);
 }
 
+/**
+ * guest_state_exit_irqoff - Establish state when returning from guest mode
+ *
+ * Entry from a guest disables interrupts, but guest mode is traced as
+ * interrupts enabled. Also with NO_HZ_FULL RCU might be idle.
+ *
+ * 1) Tell lockdep that interrupts are disabled
+ * 2) Invoke context tracking if enabled to reactivate RCU
+ * 3) Trace interrupts off state
+ *
+ * Invoked from architecture specific code after exiting a guest.
+ * Must be invoked with interrupts disabled and the caller must be
+ * non-instrumentable.
+ * The caller has to invoke guest_timing_exit_irqoff() after this.
+ *
+ * Note: this is analogous to enter_from_user_mode().
+ */
+static __always_inline void guest_state_exit_irqoff(void)
+{
+       lockdep_hardirqs_off(CALLER_ADDR0);
+       guest_context_exit_irqoff();
+
+       instrumentation_begin();
+       trace_hardirqs_off_finish();
+       instrumentation_end();
+}
+
 static inline int kvm_vcpu_exiting_guest_mode(struct kvm_vcpu *vcpu)
 {
        /*
index 605756f..7f99b4d 100644 (file)
@@ -380,6 +380,7 @@ enum {
        ATA_HORKAGE_MAX_TRIM_128M = (1 << 26),  /* Limit max trim size to 128M */
        ATA_HORKAGE_NO_NCQ_ON_ATI = (1 << 27),  /* Disable NCQ on ATI chipset */
        ATA_HORKAGE_NO_ID_DEV_LOG = (1 << 28),  /* Identify device log missing */
+       ATA_HORKAGE_NO_LOG_DIR  = (1 << 29),    /* Do not read log directory */
 
         /* DMA mask for user DMA control: User visible values; DO NOT
            renumber */
index a5a724c..819ec92 100644 (file)
@@ -80,7 +80,7 @@ LSM_HOOK(int, 0, sb_clone_mnt_opts, const struct super_block *oldsb,
         unsigned long *set_kern_flags)
 LSM_HOOK(int, 0, move_mount, const struct path *from_path,
         const struct path *to_path)
-LSM_HOOK(int, 0, dentry_init_security, struct dentry *dentry,
+LSM_HOOK(int, -EOPNOTSUPP, dentry_init_security, struct dentry *dentry,
         int mode, const struct qstr *name, const char **xattr_name,
         void **ctx, u32 *ctxlen)
 LSM_HOOK(int, 0, dentry_create_files_as, struct dentry *dentry, int mode,
index b72d751..0abbd68 100644 (file)
@@ -219,7 +219,7 @@ struct obj_cgroup {
        struct mem_cgroup *memcg;
        atomic_t nr_charged_bytes;
        union {
-               struct list_head list;
+               struct list_head list; /* protected by objcg_lock */
                struct rcu_head rcu;
        };
 };
@@ -315,7 +315,8 @@ struct mem_cgroup {
 #ifdef CONFIG_MEMCG_KMEM
        int kmemcg_id;
        struct obj_cgroup __rcu *objcg;
-       struct list_head objcg_list; /* list of inherited objcgs */
+       /* list of inherited objcgs, protected by objcg_lock */
+       struct list_head objcg_list;
 #endif
 
        MEMCG_PADDING(_pad2_);
index e1a84b1..213cc56 100644 (file)
@@ -1506,11 +1506,18 @@ static inline u8 page_kasan_tag(const struct page *page)
 
 static inline void page_kasan_tag_set(struct page *page, u8 tag)
 {
-       if (kasan_enabled()) {
-               tag ^= 0xff;
-               page->flags &= ~(KASAN_TAG_MASK << KASAN_TAG_PGSHIFT);
-               page->flags |= (tag & KASAN_TAG_MASK) << KASAN_TAG_PGSHIFT;
-       }
+       unsigned long old_flags, flags;
+
+       if (!kasan_enabled())
+               return;
+
+       tag ^= 0xff;
+       old_flags = READ_ONCE(page->flags);
+       do {
+               flags = old_flags;
+               flags &= ~(KASAN_TAG_MASK << KASAN_TAG_PGSHIFT);
+               flags |= (tag & KASAN_TAG_MASK) << KASAN_TAG_PGSHIFT;
+       } while (unlikely(!try_cmpxchg(&page->flags, &old_flags, flags)));
 }
 
 static inline void page_kasan_tag_reset(struct page *page)
index 9db36dc..5140e5f 100644 (file)
@@ -261,6 +261,7 @@ static_assert(sizeof(struct page) == sizeof(struct folio));
        static_assert(offsetof(struct page, pg) == offsetof(struct folio, fl))
 FOLIO_MATCH(flags, flags);
 FOLIO_MATCH(lru, lru);
+FOLIO_MATCH(mapping, mapping);
 FOLIO_MATCH(compound_head, lru);
 FOLIO_MATCH(index, index);
 FOLIO_MATCH(private, private);
index 3213c72..e490b84 100644 (file)
@@ -2548,6 +2548,7 @@ struct packet_type {
                                              struct net_device *);
        bool                    (*id_match)(struct packet_type *ptype,
                                            struct sock *sk);
+       struct net              *af_packet_net;
        void                    *af_packet_priv;
        struct list_head        list;
 };
index b46c39d..614f222 100644 (file)
@@ -244,6 +244,13 @@ struct netfs_cache_ops {
        int (*prepare_write)(struct netfs_cache_resources *cres,
                             loff_t *_start, size_t *_len, loff_t i_size,
                             bool no_space_allocated_yet);
+
+       /* Query the occupancy of the cache in a region, returning where the
+        * next chunk of data starts and how long it is.
+        */
+       int (*query_occupancy)(struct netfs_cache_resources *cres,
+                              loff_t start, size_t len, size_t granularity,
+                              loff_t *_data_start, size_t *_data_len);
 };
 
 struct readahead_control;
index 0dc7ad3..b06375e 100644 (file)
@@ -36,14 +36,6 @@ static inline void nfs_copy_fh(struct nfs_fh *target, const struct nfs_fh *sourc
        memcpy(target->data, source->data, source->size);
 }
 
-
-/*
- * This is really a general kernel constant, but since nothing like
- * this is defined in the kernel headers, I have to do it here.
- */
-#define NFS_OFFSET_MAX         ((__s64)((~(__u64)0) >> 1))
-
-
 enum nfs3_stable_how {
        NFS_UNSTABLE = 0,
        NFS_DATA_SYNC = 1,
index 00835ba..68f81d8 100644 (file)
@@ -61,7 +61,9 @@
 struct nfs_access_entry {
        struct rb_node          rb_node;
        struct list_head        lru;
-       const struct cred *     cred;
+       kuid_t                  fsuid;
+       kgid_t                  fsgid;
+       struct group_info       *group_info;
        __u32                   mask;
        struct rcu_head         rcu_head;
 };
@@ -105,6 +107,7 @@ struct nfs_open_dir_context {
        __u64 dup_cookie;
        pgoff_t page_index;
        signed char duped;
+       bool eof;
 };
 
 /*
@@ -395,7 +398,7 @@ extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fa
 extern int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr);
 extern int nfs_getattr(struct user_namespace *, const struct path *,
                       struct kstat *, u32, unsigned int);
-extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
+extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *, const struct cred *);
 extern void nfs_access_set_mask(struct nfs_access_entry *, u32);
 extern int nfs_permission(struct user_namespace *, struct inode *, int);
 extern int nfs_open(struct inode *, struct file *);
@@ -532,8 +535,8 @@ extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh,
                        struct nfs_fattr *fattr);
 extern int nfs_may_open(struct inode *inode, const struct cred *cred, int openflags);
 extern void nfs_access_zap_cache(struct inode *inode);
-extern int nfs_access_get_cached(struct inode *inode, const struct cred *cred, struct nfs_access_entry *res,
-                                bool may_block);
+extern int nfs_access_get_cached(struct inode *inode, const struct cred *cred,
+                                u32 *mask, bool may_block);
 
 /*
  * linux/fs/nfs/symlink.c
index 77b2dba..ca0959e 100644 (file)
@@ -266,6 +266,8 @@ struct nfs_server {
 #define NFS_CAP_ACLS           (1U << 3)
 #define NFS_CAP_ATOMIC_OPEN    (1U << 4)
 #define NFS_CAP_LGOPEN         (1U << 5)
+#define NFS_CAP_CASE_INSENSITIVE       (1U << 6)
+#define NFS_CAP_CASE_PRESERVING        (1U << 7)
 #define NFS_CAP_POSIX_LOCK     (1U << 14)
 #define NFS_CAP_UIDGID_NOMAP   (1U << 15)
 #define NFS_CAP_STATEID_NFSV41 (1U << 16)
@@ -282,5 +284,5 @@ struct nfs_server {
 #define NFS_CAP_COPY_NOTIFY    (1U << 27)
 #define NFS_CAP_XATTR          (1U << 28)
 #define NFS_CAP_READ_PLUS      (1U << 29)
-
+#define NFS_CAP_FS_LOCATIONS   (1U << 30)
 #endif
index 967a009..728cb0c 100644 (file)
@@ -1194,6 +1194,8 @@ struct nfs4_server_caps_res {
        u32                             has_links;
        u32                             has_symlinks;
        u32                             fh_expire_type;
+       u32                             case_insensitive;
+       u32                             case_preserving;
 };
 
 #define NFS4_PATHNAME_MAXCOMPONENTS 512
@@ -1737,7 +1739,7 @@ struct nfs_rpc_ops {
                            struct nfs_fh *, struct nfs_fattr *);
        int     (*lookupp) (struct inode *, struct nfs_fh *,
                            struct nfs_fattr *);
-       int     (*access)  (struct inode *, struct nfs_access_entry *);
+       int     (*access)  (struct inode *, struct nfs_access_entry *, const struct cred *);
        int     (*readlink)(struct inode *, struct page *, unsigned int,
                            unsigned int);
        int     (*create)  (struct inode *, struct dentry *,
@@ -1795,6 +1797,7 @@ struct nfs_rpc_ops {
        struct nfs_server *(*create_server)(struct fs_context *);
        struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *,
                                           struct nfs_fattr *, rpc_authflavor_t);
+       int     (*discover_trunking)(struct nfs_server *, struct nfs_fh *);
 };
 
 /*
index 38cace1..01e16c7 100644 (file)
@@ -26,6 +26,9 @@ void __page_table_check_pmd_set(struct mm_struct *mm, unsigned long addr,
                                pmd_t *pmdp, pmd_t pmd);
 void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
                                pud_t *pudp, pud_t pud);
+void __page_table_check_pte_clear_range(struct mm_struct *mm,
+                                       unsigned long addr,
+                                       pmd_t pmd);
 
 static inline void page_table_check_alloc(struct page *page, unsigned int order)
 {
@@ -100,6 +103,16 @@ static inline void page_table_check_pud_set(struct mm_struct *mm,
        __page_table_check_pud_set(mm, addr, pudp, pud);
 }
 
+static inline void page_table_check_pte_clear_range(struct mm_struct *mm,
+                                                   unsigned long addr,
+                                                   pmd_t pmd)
+{
+       if (static_branch_likely(&page_table_check_disabled))
+               return;
+
+       __page_table_check_pte_clear_range(mm, addr, pmd);
+}
+
 #else
 
 static inline void page_table_check_alloc(struct page *page, unsigned int order)
@@ -143,5 +156,11 @@ static inline void page_table_check_pud_set(struct mm_struct *mm,
 {
 }
 
+static inline void page_table_check_pte_clear_range(struct mm_struct *mm,
+                                                   unsigned long addr,
+                                                   pmd_t pmd)
+{
+}
+
 #endif /* CONFIG_PAGE_TABLE_CHECK */
 #endif /* __LINUX_PAGE_TABLE_CHECK_H */
index 117f230..7336491 100644 (file)
@@ -693,18 +693,6 @@ struct perf_event {
        u64                             total_time_running;
        u64                             tstamp;
 
-       /*
-        * timestamp shadows the actual context timing but it can
-        * be safely used in NMI interrupt context. It reflects the
-        * context time as it was when the event was last scheduled in,
-        * or when ctx_sched_in failed to schedule the event because we
-        * run out of PMC.
-        *
-        * ctx_time already accounts for ctx->timestamp. Therefore to
-        * compute ctx_time for a sample, simply add perf_clock().
-        */
-       u64                             shadow_ctx_time;
-
        struct perf_event_attr          attr;
        u16                             header_size;
        u16                             id_header_size;
@@ -852,6 +840,7 @@ struct perf_event_context {
         */
        u64                             time;
        u64                             timestamp;
+       u64                             timeoffset;
 
        /*
         * These fields let us detect when two contexts have both
@@ -934,6 +923,8 @@ struct bpf_perf_event_data_kern {
 struct perf_cgroup_info {
        u64                             time;
        u64                             timestamp;
+       u64                             timeoffset;
+       int                             active;
 };
 
 struct perf_cgroup {
index bc8713a..f4f4077 100644 (file)
@@ -62,6 +62,7 @@ static inline unsigned long pte_index(unsigned long address)
 {
        return (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
 }
+#define pte_index pte_index
 
 #ifndef pmd_index
 static inline unsigned long pmd_index(unsigned long address)
index 7c7e627..07481bb 100644 (file)
@@ -86,4 +86,9 @@ extern struct pid_namespace *task_active_pid_ns(struct task_struct *tsk);
 void pidhash_init(void);
 void pid_idr_init(void);
 
+static inline bool task_is_in_init_pid_ns(struct task_struct *tsk)
+{
+       return task_active_pid_ns(tsk) == &init_pid_ns;
+}
+
 #endif /* _LINUX_PID_NS_H */
index a70ca83..7f7d1d8 100644 (file)
@@ -25,18 +25,17 @@ void psi_memstall_enter(unsigned long *flags);
 void psi_memstall_leave(unsigned long *flags);
 
 int psi_show(struct seq_file *s, struct psi_group *group, enum psi_res res);
-
-#ifdef CONFIG_CGROUPS
-int psi_cgroup_alloc(struct cgroup *cgrp);
-void psi_cgroup_free(struct cgroup *cgrp);
-void cgroup_move_task(struct task_struct *p, struct css_set *to);
-
 struct psi_trigger *psi_trigger_create(struct psi_group *group,
                        char *buf, size_t nbytes, enum psi_res res);
-void psi_trigger_replace(void **trigger_ptr, struct psi_trigger *t);
+void psi_trigger_destroy(struct psi_trigger *t);
 
 __poll_t psi_trigger_poll(void **trigger_ptr, struct file *file,
                        poll_table *wait);
+
+#ifdef CONFIG_CGROUPS
+int psi_cgroup_alloc(struct cgroup *cgrp);
+void psi_cgroup_free(struct cgroup *cgrp);
+void cgroup_move_task(struct task_struct *p, struct css_set *to);
 #endif
 
 #else /* CONFIG_PSI */
index 516c0fe..1a3cef2 100644 (file)
@@ -141,9 +141,6 @@ struct psi_trigger {
         * events to one per window
         */
        u64 last_event_time;
-
-       /* Refcounting to prevent premature destruction */
-       struct kref refcount;
 };
 
 struct psi_group {
index 18ebd39..fd692b4 100644 (file)
@@ -91,7 +91,7 @@ extern bool qid_valid(struct kqid qid);
  *
  *     When there is no mapping defined for the user-namespace, type,
  *     qid tuple an invalid kqid is returned.  Callers are expected to
- *     test for and handle handle invalid kqids being returned.
+ *     test for and handle invalid kqids being returned.
  *     Invalid kqids may be tested for using qid_valid().
  */
 static inline struct kqid make_kqid(struct user_namespace *from,
index 508b91d..75ba8aa 100644 (file)
@@ -619,10 +619,6 @@ struct sched_dl_entity {
         * task has to wait for a replenishment to be performed at the
         * next firing of dl_timer.
         *
-        * @dl_boosted tells if we are boosted due to DI. If so we are
-        * outside bandwidth enforcement mechanism (but only until we
-        * exit the critical section);
-        *
         * @dl_yielded tells if task gave up the CPU before consuming
         * all its available runtime during the last job.
         *
@@ -1684,7 +1680,6 @@ extern struct pid *cad_pid;
 #define PF_MEMALLOC            0x00000800      /* Allocating memory */
 #define PF_NPROC_EXCEEDED      0x00001000      /* set_user() noticed that RLIMIT_NPROC was exceeded */
 #define PF_USED_MATH           0x00002000      /* If unset the fpu must be initialized before use */
-#define PF_USED_ASYNC          0x00004000      /* Used async_schedule*(), used by module init */
 #define PF_NOFREEZE            0x00008000      /* This thread should not be frozen */
 #define PF_FROZEN              0x00010000      /* Frozen for system suspend */
 #define PF_KSWAPD              0x00020000      /* I am kswapd */
index bf11e1f..8a636e6 100644 (file)
@@ -318,7 +318,7 @@ enum skb_drop_reason {
        SKB_DROP_REASON_NO_SOCKET,
        SKB_DROP_REASON_PKT_TOO_SMALL,
        SKB_DROP_REASON_TCP_CSUM,
-       SKB_DROP_REASON_TCP_FILTER,
+       SKB_DROP_REASON_SOCKET_FILTER,
        SKB_DROP_REASON_UDP_CSUM,
        SKB_DROP_REASON_MAX,
 };
index 5785d90..300273f 100644 (file)
@@ -430,15 +430,7 @@ struct platform_hibernation_ops {
 
 #ifdef CONFIG_HIBERNATION
 /* kernel/power/snapshot.c */
-extern void __register_nosave_region(unsigned long b, unsigned long e, int km);
-static inline void __init register_nosave_region(unsigned long b, unsigned long e)
-{
-       __register_nosave_region(b, e, 0);
-}
-static inline void __init register_nosave_region_late(unsigned long b, unsigned long e)
-{
-       __register_nosave_region(b, e, 1);
-}
+extern void register_nosave_region(unsigned long b, unsigned long e);
 extern int swsusp_page_is_forbidden(struct page *);
 extern void swsusp_set_page_free(struct page *);
 extern void swsusp_unset_page_free(struct page *);
@@ -458,7 +450,6 @@ int pfn_is_nosave(unsigned long pfn);
 int hibernate_quiet_exec(int (*func)(void *data), void *data);
 #else /* CONFIG_HIBERNATION */
 static inline void register_nosave_region(unsigned long b, unsigned long e) {}
-static inline void register_nosave_region_late(unsigned long b, unsigned long e) {}
 static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
 static inline void swsusp_set_page_free(struct page *p) {}
 static inline void swsusp_unset_page_free(struct page *p) {}
@@ -506,14 +497,14 @@ extern void ksys_sync_helper(void);
 
 /* drivers/base/power/wakeup.c */
 extern bool events_check_enabled;
-extern unsigned int pm_wakeup_irq;
 extern suspend_state_t pm_suspend_target_state;
 
 extern bool pm_wakeup_pending(void);
 extern void pm_system_wakeup(void);
 extern void pm_system_cancel_wakeup(void);
-extern void pm_wakeup_clear(bool reset);
+extern void pm_wakeup_clear(unsigned int irq_number);
 extern void pm_system_irq_wakeup(unsigned int irq_number);
+extern unsigned int pm_wakeup_irq(void);
 extern bool pm_get_wakeup_count(unsigned int *count, bool block);
 extern bool pm_save_wakeup_count(unsigned int count);
 extern void pm_wakep_autosleep_enabled(bool set);
index 180adf7..6353d6d 100644 (file)
@@ -265,7 +265,7 @@ static inline struct ctl_table_header *register_sysctl_table(struct ctl_table *
        return NULL;
 }
 
-static inline struct sysctl_header *register_sysctl_mount_point(const char *path)
+static inline struct ctl_table_header *register_sysctl_mount_point(const char *path)
 {
        return NULL;
 }
index 031f148..b5deafd 100644 (file)
@@ -91,6 +91,12 @@ fwnode_usb_role_switch_get(struct fwnode_handle *node)
 
 static inline void usb_role_switch_put(struct usb_role_switch *sw) { }
 
+static inline struct usb_role_switch *
+usb_role_switch_find_by_fwnode(const struct fwnode_handle *fwnode)
+{
+       return NULL;
+}
+
 static inline struct usb_role_switch *
 usb_role_switch_register(struct device *parent,
                         const struct usb_role_switch_desc *desc)
index 78ea3e3..e7ce719 100644 (file)
@@ -6,6 +6,8 @@
 #define RTR_SOLICITATION_INTERVAL      (4*HZ)
 #define RTR_SOLICITATION_MAX_INTERVAL  (3600*HZ)       /* 1 hour */
 
+#define MIN_VALID_LIFETIME             (2*3600)        /* 2 hours */
+
 #define TEMP_VALID_LIFETIME            (7*86400)
 #define TEMP_PREFERRED_LIFETIME                (86400)
 #define REGEN_MAX_RETRY                        (3)
index 526e495..8221af1 100644 (file)
@@ -239,6 +239,7 @@ typedef struct ax25_dev {
 #if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER)
        ax25_dama_info          dama;
 #endif
+       refcount_t              refcount;
 } ax25_dev;
 
 typedef struct ax25_cb {
@@ -293,6 +294,17 @@ static __inline__ void ax25_cb_put(ax25_cb *ax25)
        }
 }
 
+static inline void ax25_dev_hold(ax25_dev *ax25_dev)
+{
+       refcount_inc(&ax25_dev->refcount);
+}
+
+static inline void ax25_dev_put(ax25_dev *ax25_dev)
+{
+       if (refcount_dec_and_test(&ax25_dev->refcount)) {
+               kfree(ax25_dev);
+       }
+}
 static inline __be16 ax25_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
        skb->dev      = dev;
index f6ae3a4..83cfd2d 100644 (file)
@@ -346,7 +346,7 @@ static inline bool bond_uses_primary(struct bonding *bond)
 
 static inline struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond)
 {
-       struct slave *slave = rcu_dereference(bond->curr_active_slave);
+       struct slave *slave = rcu_dereference_rtnl(bond->curr_active_slave);
 
        return bond_uses_primary(bond) && slave ? slave->dev : NULL;
 }
index 14efa0d..adab27b 100644 (file)
@@ -123,8 +123,20 @@ static inline struct metadata_dst *tun_dst_unclone(struct sk_buff *skb)
 
        memcpy(&new_md->u.tun_info, &md_dst->u.tun_info,
               sizeof(struct ip_tunnel_info) + md_size);
+#ifdef CONFIG_DST_CACHE
+       /* Unclone the dst cache if there is one */
+       if (new_md->u.tun_info.dst_cache.cache) {
+               int ret;
+
+               ret = dst_cache_init(&new_md->u.tun_info.dst_cache, GFP_ATOMIC);
+               if (ret) {
+                       metadata_dst_free(new_md);
+                       return ERR_PTR(ret);
+               }
+       }
+#endif
+
        skb_dst_drop(skb);
-       dst_hold(&new_md->dst);
        skb_dst_set(skb, &new_md->dst);
        return new_md;
 }
index 81e23a1..b51bae4 100644 (file)
@@ -525,19 +525,18 @@ static inline void ip_select_ident_segs(struct net *net, struct sk_buff *skb,
 {
        struct iphdr *iph = ip_hdr(skb);
 
+       /* We had many attacks based on IPID, use the private
+        * generator as much as we can.
+        */
+       if (sk && inet_sk(sk)->inet_daddr) {
+               iph->id = htons(inet_sk(sk)->inet_id);
+               inet_sk(sk)->inet_id += segs;
+               return;
+       }
        if ((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) {
-               /* This is only to work around buggy Windows95/2000
-                * VJ compression implementations.  If the ID field
-                * does not change, they drop every other packet in
-                * a TCP stream using header compression.
-                */
-               if (sk && inet_sk(sk)->inet_daddr) {
-                       iph->id = htons(inet_sk(sk)->inet_id);
-                       inet_sk(sk)->inet_id += segs;
-               } else {
-                       iph->id = 0;
-               }
+               iph->id = 0;
        } else {
+               /* Unfortunately we need the big hammer to get a suitable IPID */
                __ip_select_ident(net, iph, segs);
        }
 }
index a9a4ccc..40ae8f1 100644 (file)
@@ -282,7 +282,7 @@ static inline bool fib6_get_cookie_safe(const struct fib6_info *f6i,
        fn = rcu_dereference(f6i->fib6_node);
 
        if (fn) {
-               *cookie = fn->fn_sernum;
+               *cookie = READ_ONCE(fn->fn_sernum);
                /* pairs with smp_wmb() in __fib6_update_sernum_upto_root() */
                smp_rmb();
                status = true;
index 937389e..87419f7 100644 (file)
@@ -350,7 +350,8 @@ static inline struct neighbour *neigh_create(struct neigh_table *tbl,
        return __neigh_create(tbl, pkey, dev, true);
 }
 void neigh_destroy(struct neighbour *neigh);
-int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb);
+int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb,
+                      const bool immediate_ok);
 int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, u32 flags,
                 u32 nlmsg_pid);
 void __neigh_set_probe_once(struct neighbour *neigh);
@@ -460,17 +461,24 @@ static inline struct neighbour * neigh_clone(struct neighbour *neigh)
 
 #define neigh_hold(n)  refcount_inc(&(n)->refcnt)
 
-static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
+static __always_inline int neigh_event_send_probe(struct neighbour *neigh,
+                                                 struct sk_buff *skb,
+                                                 const bool immediate_ok)
 {
        unsigned long now = jiffies;
-       
+
        if (READ_ONCE(neigh->used) != now)
                WRITE_ONCE(neigh->used, now);
-       if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE)))
-               return __neigh_event_send(neigh, skb);
+       if (!(neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE)))
+               return __neigh_event_send(neigh, skb, immediate_ok);
        return 0;
 }
 
+static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
+{
+       return neigh_event_send_probe(neigh, skb, true);
+}
+
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
 static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb)
 {
index 4c858dc..25404fc 100644 (file)
@@ -370,7 +370,7 @@ static inline struct neighbour *ip_neigh_gw4(struct net_device *dev,
 {
        struct neighbour *neigh;
 
-       neigh = __ipv4_neigh_lookup_noref(dev, daddr);
+       neigh = __ipv4_neigh_lookup_noref(dev, (__force u32)daddr);
        if (unlikely(!neigh))
                neigh = __neigh_create(&arp_tbl, &daddr, dev, false);
 
index 44e442b..b9fc978 100644 (file)
@@ -1369,6 +1369,7 @@ static inline bool tcp_checksum_complete(struct sk_buff *skb)
 
 bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb);
 
+#ifdef CONFIG_INET
 void __sk_defer_free_flush(struct sock *sk);
 
 static inline void sk_defer_free_flush(struct sock *sk)
@@ -1377,6 +1378,9 @@ static inline void sk_defer_free_flush(struct sock *sk)
                return;
        __sk_defer_free_flush(sk);
 }
+#else
+static inline void sk_defer_free_flush(struct sock *sk) {}
+#endif
 
 int tcp_filter(struct sock *sk, struct sk_buff *skb);
 void tcp_set_state(struct sock *sk, int state);
index 9b187d8..36da42c 100644 (file)
@@ -617,6 +617,7 @@ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream);
 void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream);
 void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream);
 unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream);
+unsigned long _snd_pcm_stream_lock_irqsave_nested(struct snd_pcm_substream *substream);
 
 /**
  * snd_pcm_stream_lock_irqsave - Lock the PCM stream
@@ -635,6 +636,20 @@ unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream);
 void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
                                      unsigned long flags);
 
+/**
+ * snd_pcm_stream_lock_irqsave_nested - Single-nested PCM stream locking
+ * @substream: PCM substream
+ * @flags: irq flags
+ *
+ * This locks the PCM stream like snd_pcm_stream_lock_irqsave() but with
+ * the single-depth lockdep subclass.
+ */
+#define snd_pcm_stream_lock_irqsave_nested(substream, flags)           \
+       do {                                                            \
+               typecheck(unsigned long, flags);                        \
+               flags = _snd_pcm_stream_lock_irqsave_nested(substream); \
+       } while (0)
+
 /**
  * snd_pcm_group_for_each_entry - iterate over the linked substreams
  * @s: the iterator
index 3e042ca..a8a64b9 100644 (file)
@@ -14,7 +14,7 @@
        EM(SKB_DROP_REASON_NO_SOCKET, NO_SOCKET)                \
        EM(SKB_DROP_REASON_PKT_TOO_SMALL, PKT_TOO_SMALL)        \
        EM(SKB_DROP_REASON_TCP_CSUM, TCP_CSUM)                  \
-       EM(SKB_DROP_REASON_TCP_FILTER, TCP_FILTER)              \
+       EM(SKB_DROP_REASON_SOCKET_FILTER, SOCKET_FILTER)        \
        EM(SKB_DROP_REASON_UDP_CSUM, UDP_CSUM)                  \
        EMe(SKB_DROP_REASON_MAX, MAX)
 
index 1e566ac..29982d6 100644 (file)
@@ -794,6 +794,9 @@ RPC_SHOW_SOCKET
 
 RPC_SHOW_SOCK
 
+
+#include <trace/events/net_probe_common.h>
+
 /*
  * Now redefine the EM() and EMe() macros to map the enums to the strings
  * that will be printed in the output.
@@ -816,27 +819,32 @@ DECLARE_EVENT_CLASS(xs_socket_event,
                        __field(unsigned int, socket_state)
                        __field(unsigned int, sock_state)
                        __field(unsigned long long, ino)
-                       __string(dstaddr,
-                               xprt->address_strings[RPC_DISPLAY_ADDR])
-                       __string(dstport,
-                               xprt->address_strings[RPC_DISPLAY_PORT])
+                       __array(__u8, saddr, sizeof(struct sockaddr_in6))
+                       __array(__u8, daddr, sizeof(struct sockaddr_in6))
                ),
 
                TP_fast_assign(
                        struct inode *inode = SOCK_INODE(socket);
+                       const struct sock *sk = socket->sk;
+                       const struct inet_sock *inet = inet_sk(sk);
+
+                       memset(__entry->saddr, 0, sizeof(struct sockaddr_in6));
+                       memset(__entry->daddr, 0, sizeof(struct sockaddr_in6));
+
+                       TP_STORE_ADDR_PORTS(__entry, inet, sk);
+
                        __entry->socket_state = socket->state;
                        __entry->sock_state = socket->sk->sk_state;
                        __entry->ino = (unsigned long long)inode->i_ino;
-                       __assign_str(dstaddr,
-                               xprt->address_strings[RPC_DISPLAY_ADDR]);
-                       __assign_str(dstport,
-                               xprt->address_strings[RPC_DISPLAY_PORT]);
+
                ),
 
                TP_printk(
-                       "socket:[%llu] dstaddr=%s/%s "
+                       "socket:[%llu] srcaddr=%pISpc dstaddr=%pISpc "
                        "state=%u (%s) sk_state=%u (%s)",
-                       __entry->ino, __get_str(dstaddr), __get_str(dstport),
+                       __entry->ino,
+                       __entry->saddr,
+                       __entry->daddr,
                        __entry->socket_state,
                        rpc_show_socket_state(__entry->socket_state),
                        __entry->sock_state,
@@ -866,29 +874,33 @@ DECLARE_EVENT_CLASS(xs_socket_event_done,
                        __field(unsigned int, socket_state)
                        __field(unsigned int, sock_state)
                        __field(unsigned long long, ino)
-                       __string(dstaddr,
-                               xprt->address_strings[RPC_DISPLAY_ADDR])
-                       __string(dstport,
-                               xprt->address_strings[RPC_DISPLAY_PORT])
+                       __array(__u8, saddr, sizeof(struct sockaddr_in6))
+                       __array(__u8, daddr, sizeof(struct sockaddr_in6))
                ),
 
                TP_fast_assign(
                        struct inode *inode = SOCK_INODE(socket);
+                       const struct sock *sk = socket->sk;
+                       const struct inet_sock *inet = inet_sk(sk);
+
+                       memset(__entry->saddr, 0, sizeof(struct sockaddr_in6));
+                       memset(__entry->daddr, 0, sizeof(struct sockaddr_in6));
+
+                       TP_STORE_ADDR_PORTS(__entry, inet, sk);
+
                        __entry->socket_state = socket->state;
                        __entry->sock_state = socket->sk->sk_state;
                        __entry->ino = (unsigned long long)inode->i_ino;
                        __entry->error = error;
-                       __assign_str(dstaddr,
-                               xprt->address_strings[RPC_DISPLAY_ADDR]);
-                       __assign_str(dstport,
-                               xprt->address_strings[RPC_DISPLAY_PORT]);
                ),
 
                TP_printk(
-                       "error=%d socket:[%llu] dstaddr=%s/%s "
+                       "error=%d socket:[%llu] srcaddr=%pISpc dstaddr=%pISpc "
                        "state=%u (%s) sk_state=%u (%s)",
                        __entry->error,
-                       __entry->ino, __get_str(dstaddr), __get_str(dstport),
+                       __entry->ino,
+                       __entry->saddr,
+                       __entry->daddr,
                        __entry->socket_state,
                        rpc_show_socket_state(__entry->socket_state),
                        __entry->sock_state,
@@ -953,7 +965,8 @@ TRACE_EVENT(rpc_socket_nospace,
                { BIT(XPRT_REMOVE),             "REMOVE" },             \
                { BIT(XPRT_CONGESTED),          "CONGESTED" },          \
                { BIT(XPRT_CWND_WAIT),          "CWND_WAIT" },          \
-               { BIT(XPRT_WRITE_SPACE),        "WRITE_SPACE" })
+               { BIT(XPRT_WRITE_SPACE),        "WRITE_SPACE" },        \
+               { BIT(XPRT_SND_IS_COOKIE),      "SND_IS_COOKIE" })
 
 DECLARE_EVENT_CLASS(rpc_xprt_lifetime_class,
        TP_PROTO(
@@ -1150,8 +1163,11 @@ DECLARE_EVENT_CLASS(xprt_writelock_event,
                        __entry->task_id = -1;
                        __entry->client_id = -1;
                }
-               __entry->snd_task_id = xprt->snd_task ?
-                                       xprt->snd_task->tk_pid : -1;
+               if (xprt->snd_task &&
+                   !test_bit(XPRT_SND_IS_COOKIE, &xprt->state))
+                       __entry->snd_task_id = xprt->snd_task->tk_pid;
+               else
+                       __entry->snd_task_id = -1;
        ),
 
        TP_printk(SUNRPC_TRACE_TASK_SPECIFIER
@@ -1196,8 +1212,12 @@ DECLARE_EVENT_CLASS(xprt_cong_event,
                        __entry->task_id = -1;
                        __entry->client_id = -1;
                }
-               __entry->snd_task_id = xprt->snd_task ?
-                                       xprt->snd_task->tk_pid : -1;
+               if (xprt->snd_task &&
+                   !test_bit(XPRT_SND_IS_COOKIE, &xprt->state))
+                       __entry->snd_task_id = xprt->snd_task->tk_pid;
+               else
+                       __entry->snd_task_id = -1;
+
                __entry->cong = xprt->cong;
                __entry->cwnd = xprt->cwnd;
                __entry->wait = test_bit(XPRT_CWND_WAIT, &xprt->state);
index ea4405d..5d48c46 100644 (file)
@@ -23,8 +23,9 @@
 
 #undef __get_rel_dynamic_array
 #define __get_rel_dynamic_array(field) \
-               ((void *)(&__entry->__rel_loc_##field) +        \
-                sizeof(__entry->__rel_loc_##field) +           \
+               ((void *)__entry +                                      \
+                offsetof(typeof(*__entry), __rel_loc_##field) +        \
+                sizeof(__entry->__rel_loc_##field) +                   \
                 (__entry->__rel_loc_##field & 0xffff))
 
 #undef __get_rel_dynamic_array_len
index 8c6f7c4..3d29919 100644 (file)
@@ -128,7 +128,7 @@ TRACE_MAKE_SYSTEM_STR();
        struct trace_event_raw_##name {                                 \
                struct trace_entry      ent;                            \
                tstruct                                                 \
-               char                    __data[0];                      \
+               char                    __data[];                       \
        };                                                              \
                                                                        \
        static struct trace_event_class event_class_##name;
@@ -318,9 +318,10 @@ TRACE_MAKE_SYSTEM_STR();
 #define __get_str(field) ((char *)__get_dynamic_array(field))
 
 #undef __get_rel_dynamic_array
-#define __get_rel_dynamic_array(field) \
-               ((void *)(&__entry->__rel_loc_##field) +        \
-                sizeof(__entry->__rel_loc_##field) +           \
+#define __get_rel_dynamic_array(field)                                 \
+               ((void *)__entry +                                      \
+                offsetof(typeof(*__entry), __rel_loc_##field) +        \
+                sizeof(__entry->__rel_loc_##field) +                   \
                 (__entry->__rel_loc_##field & 0xffff))
 
 #undef __get_rel_dynamic_array_len
diff --git a/include/uapi/linux/cyclades.h b/include/uapi/linux/cyclades.h
new file mode 100644 (file)
index 0000000..6225c5a
--- /dev/null
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#ifndef _UAPI_LINUX_CYCLADES_H
+#define _UAPI_LINUX_CYCLADES_H
+
+#warning "Support for features provided by this header has been removed"
+#warning "Please consider updating your code"
+
+struct cyclades_monitor {
+       unsigned long int_count;
+       unsigned long char_count;
+       unsigned long char_max;
+       unsigned long char_last;
+};
+
+#define CYGETMON               0x435901
+#define CYGETTHRESH            0x435902
+#define CYSETTHRESH            0x435903
+#define CYGETDEFTHRESH         0x435904
+#define CYSETDEFTHRESH         0x435905
+#define CYGETTIMEOUT           0x435906
+#define CYSETTIMEOUT           0x435907
+#define CYGETDEFTIMEOUT                0x435908
+#define CYSETDEFTIMEOUT                0x435909
+#define CYSETRFLOW             0x43590a
+#define CYGETRFLOW             0x43590b
+#define CYSETRTSDTR_INV                0x43590c
+#define CYGETRTSDTR_INV                0x43590d
+#define CYZSETPOLLCYCLE                0x43590e
+#define CYZGETPOLLCYCLE                0x43590f
+#define CYGETCD1400VER         0x435910
+#define CYSETWAIT              0x435912
+#define CYGETWAIT              0x435913
+
+#endif /* _UAPI_LINUX_CYCLADES_H */
index 9563d29..5191b57 100644 (file)
@@ -1133,6 +1133,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM 206
 #define KVM_CAP_VM_GPA_BITS 207
 #define KVM_CAP_XSAVE2 208
+#define KVM_CAP_SYS_ATTRIBUTES 209
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1623,9 +1624,6 @@ struct kvm_enc_region {
 #define KVM_S390_NORMAL_RESET  _IO(KVMIO,   0xc3)
 #define KVM_S390_CLEAR_RESET   _IO(KVMIO,   0xc4)
 
-/* Available with KVM_CAP_XSAVE2 */
-#define KVM_GET_XSAVE2           _IOR(KVMIO,  0xcf, struct kvm_xsave)
-
 struct kvm_s390_pv_sec_parm {
        __u64 origin;
        __u64 length;
@@ -2047,4 +2045,7 @@ struct kvm_stats_desc {
 
 #define KVM_GET_STATS_FD  _IO(KVMIO,  0xce)
 
+/* Available with KVM_CAP_XSAVE2 */
+#define KVM_GET_XSAVE2           _IOR(KVMIO,  0xcf, struct kvm_xsave)
+
 #endif /* __LINUX_KVM_H */
index 4b33950..2607102 100644 (file)
@@ -106,7 +106,7 @@ enum ip_conntrack_status {
        IPS_NAT_CLASH = IPS_UNTRACKED,
 #endif
 
-       /* Conntrack got a helper explicitly attached via CT target. */
+       /* Conntrack got a helper explicitly attached (ruleset, ctnetlink). */
        IPS_HELPER_BIT = 13,
        IPS_HELPER = (1 << IPS_HELPER_BIT),
 
index 1b65042..82858b6 100644 (file)
@@ -465,6 +465,8 @@ struct perf_event_attr {
        /*
         * User provided data if sigtrap=1, passed back to user via
         * siginfo_t::si_perf_data, e.g. to permit user to identify the event.
+        * Note, siginfo_t::si_perf_data is long-sized, and sig_data will be
+        * truncated accordingly on 32 bit architectures.
         */
        __u64   sig_data;
 };
index c7008d8..8cb3a6f 100644 (file)
@@ -84,12 +84,11 @@ struct smc_diag_conninfo {
 /* SMC_DIAG_LINKINFO */
 
 struct smc_diag_linkinfo {
-       __u8            link_id;                    /* link identifier */
-       __u8            ibname[IB_DEVICE_NAME_MAX]; /* name of the RDMA device */
-       __u8            ibport;                     /* RDMA device port number */
-       __u8            gid[40];                    /* local GID */
-       __u8            peer_gid[40];               /* peer GID */
-       __aligned_u64   net_cookie;                 /* RDMA device net namespace */
+       __u8 link_id;                   /* link identifier */
+       __u8 ibname[IB_DEVICE_NAME_MAX]; /* name of the RDMA device */
+       __u8 ibport;                    /* RDMA device port number */
+       __u8 gid[40];                   /* local GID */
+       __u8 peer_gid[40];              /* peer GID */
 };
 
 struct smc_diag_lgrinfo {
index ef0cafe..2d3e5df 100644 (file)
  *                                                                          *
  ****************************************************************************/
 
+#define AES_IEC958_STATUS_SIZE         24
+
 struct snd_aes_iec958 {
-       unsigned char status[24];       /* AES/IEC958 channel status bits */
+       unsigned char status[AES_IEC958_STATUS_SIZE]; /* AES/IEC958 channel status bits */
        unsigned char subcode[147];     /* AES/IEC958 subcode bits */
        unsigned char pad;              /* nothing */
        unsigned char dig_subframe[4];  /* AES/IEC958 subframe bits */
index 9ac5515..7a71453 100644 (file)
@@ -47,7 +47,13 @@ struct ioctl_gntdev_grant_ref {
 /*
  * Inserts the grant references into the mapping table of an instance
  * of gntdev. N.B. This does not perform the mapping, which is deferred
- * until mmap() is called with @index as the offset.
+ * until mmap() is called with @index as the offset. @index should be
+ * considered opaque to userspace, with one exception: if no grant
+ * references have ever been inserted into the mapping table of this
+ * instance, @index will be set to 0. This is necessary to use gntdev
+ * with userspace APIs that expect a file descriptor that can be
+ * mmap()'d at offset 0, such as Wayland. If @count is set to 0, this
+ * ioctl will fail.
  */
 #define IOCTL_GNTDEV_MAP_GRANT_REF \
 _IOC(_IOC_NONE, 'G', 0, sizeof(struct ioctl_gntdev_map_grant_ref))
index bbee8c6..4dc45a5 100644 (file)
@@ -1,6 +1,4 @@
 /******************************************************************************
- * evtchn.h
- *
  * Interface to /dev/xen/xenbus_backend.
  *
  * Copyright (c) 2011 Bastian Blank <waldi@debian.org>
index 6693daf..0dbdb98 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1964,6 +1964,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
         */
        un = lookup_undo(ulp, semid);
        if (un) {
+               spin_unlock(&ulp->lock);
                kvfree(new);
                goto success;
        }
@@ -1976,9 +1977,8 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        ipc_assert_locked_object(&sma->sem_perm);
        list_add(&new->list_id, &sma->list_id);
        un = new;
-
-success:
        spin_unlock(&ulp->lock);
+success:
        sem_unlock(sma, -1);
 out:
        return un;
index b8d7a66..b2c4ba5 100644 (file)
@@ -205,9 +205,6 @@ async_cookie_t async_schedule_node_domain(async_func_t func, void *data,
        atomic_inc(&entry_count);
        spin_unlock_irqrestore(&async_lock, flags);
 
-       /* mark that this task has queued an async job, used by module init */
-       current->flags |= PF_USED_ASYNC;
-
        /* schedule for execution */
        queue_work_node(node, system_unbound_wq, &entry->work);
 
index e4bbe2c..7690c29 100644 (file)
@@ -541,20 +541,22 @@ static void kauditd_printk_skb(struct sk_buff *skb)
 /**
  * kauditd_rehold_skb - Handle a audit record send failure in the hold queue
  * @skb: audit record
+ * @error: error code (unused)
  *
  * Description:
  * This should only be used by the kauditd_thread when it fails to flush the
  * hold queue.
  */
-static void kauditd_rehold_skb(struct sk_buff *skb)
+static void kauditd_rehold_skb(struct sk_buff *skb, __always_unused int error)
 {
-       /* put the record back in the queue at the same place */
-       skb_queue_head(&audit_hold_queue, skb);
+       /* put the record back in the queue */
+       skb_queue_tail(&audit_hold_queue, skb);
 }
 
 /**
  * kauditd_hold_skb - Queue an audit record, waiting for auditd
  * @skb: audit record
+ * @error: error code
  *
  * Description:
  * Queue the audit record, waiting for an instance of auditd.  When this
@@ -564,19 +566,31 @@ static void kauditd_rehold_skb(struct sk_buff *skb)
  * and queue it, if we have room.  If we want to hold on to the record, but we
  * don't have room, record a record lost message.
  */
-static void kauditd_hold_skb(struct sk_buff *skb)
+static void kauditd_hold_skb(struct sk_buff *skb, int error)
 {
        /* at this point it is uncertain if we will ever send this to auditd so
         * try to send the message via printk before we go any further */
        kauditd_printk_skb(skb);
 
        /* can we just silently drop the message? */
-       if (!audit_default) {
-               kfree_skb(skb);
-               return;
+       if (!audit_default)
+               goto drop;
+
+       /* the hold queue is only for when the daemon goes away completely,
+        * not -EAGAIN failures; if we are in a -EAGAIN state requeue the
+        * record on the retry queue unless it's full, in which case drop it
+        */
+       if (error == -EAGAIN) {
+               if (!audit_backlog_limit ||
+                   skb_queue_len(&audit_retry_queue) < audit_backlog_limit) {
+                       skb_queue_tail(&audit_retry_queue, skb);
+                       return;
+               }
+               audit_log_lost("kauditd retry queue overflow");
+               goto drop;
        }
 
-       /* if we have room, queue the message */
+       /* if we have room in the hold queue, queue the message */
        if (!audit_backlog_limit ||
            skb_queue_len(&audit_hold_queue) < audit_backlog_limit) {
                skb_queue_tail(&audit_hold_queue, skb);
@@ -585,24 +599,32 @@ static void kauditd_hold_skb(struct sk_buff *skb)
 
        /* we have no other options - drop the message */
        audit_log_lost("kauditd hold queue overflow");
+drop:
        kfree_skb(skb);
 }
 
 /**
  * kauditd_retry_skb - Queue an audit record, attempt to send again to auditd
  * @skb: audit record
+ * @error: error code (unused)
  *
  * Description:
  * Not as serious as kauditd_hold_skb() as we still have a connected auditd,
  * but for some reason we are having problems sending it audit records so
  * queue the given record and attempt to resend.
  */
-static void kauditd_retry_skb(struct sk_buff *skb)
+static void kauditd_retry_skb(struct sk_buff *skb, __always_unused int error)
 {
-       /* NOTE: because records should only live in the retry queue for a
-        * short period of time, before either being sent or moved to the hold
-        * queue, we don't currently enforce a limit on this queue */
-       skb_queue_tail(&audit_retry_queue, skb);
+       if (!audit_backlog_limit ||
+           skb_queue_len(&audit_retry_queue) < audit_backlog_limit) {
+               skb_queue_tail(&audit_retry_queue, skb);
+               return;
+       }
+
+       /* we have to drop the record, send it via printk as a last effort */
+       kauditd_printk_skb(skb);
+       audit_log_lost("kauditd retry queue overflow");
+       kfree_skb(skb);
 }
 
 /**
@@ -640,7 +662,7 @@ static void auditd_reset(const struct auditd_connection *ac)
        /* flush the retry queue to the hold queue, but don't touch the main
         * queue since we need to process that normally for multicast */
        while ((skb = skb_dequeue(&audit_retry_queue)))
-               kauditd_hold_skb(skb);
+               kauditd_hold_skb(skb, -ECONNREFUSED);
 }
 
 /**
@@ -714,16 +736,18 @@ static int kauditd_send_queue(struct sock *sk, u32 portid,
                              struct sk_buff_head *queue,
                              unsigned int retry_limit,
                              void (*skb_hook)(struct sk_buff *skb),
-                             void (*err_hook)(struct sk_buff *skb))
+                             void (*err_hook)(struct sk_buff *skb, int error))
 {
        int rc = 0;
-       struct sk_buff *skb;
+       struct sk_buff *skb = NULL;
+       struct sk_buff *skb_tail;
        unsigned int failed = 0;
 
        /* NOTE: kauditd_thread takes care of all our locking, we just use
         *       the netlink info passed to us (e.g. sk and portid) */
 
-       while ((skb = skb_dequeue(queue))) {
+       skb_tail = skb_peek_tail(queue);
+       while ((skb != skb_tail) && (skb = skb_dequeue(queue))) {
                /* call the skb_hook for each skb we touch */
                if (skb_hook)
                        (*skb_hook)(skb);
@@ -731,7 +755,7 @@ static int kauditd_send_queue(struct sock *sk, u32 portid,
                /* can we send to anyone via unicast? */
                if (!sk) {
                        if (err_hook)
-                               (*err_hook)(skb);
+                               (*err_hook)(skb, -ECONNREFUSED);
                        continue;
                }
 
@@ -745,7 +769,7 @@ retry:
                            rc == -ECONNREFUSED || rc == -EPERM) {
                                sk = NULL;
                                if (err_hook)
-                                       (*err_hook)(skb);
+                                       (*err_hook)(skb, rc);
                                if (rc == -EAGAIN)
                                        rc = 0;
                                /* continue to drain the queue */
index fce5d43..a83928c 100644 (file)
@@ -185,7 +185,7 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
        case AUDITSC_EXECVE:
                return mask & AUDIT_PERM_EXEC;
        case AUDITSC_OPENAT2:
-               return mask & ACC_MODE((u32)((struct open_how *)ctx->argv[2])->flags);
+               return mask & ACC_MODE((u32)ctx->openat2.flags);
        default:
                return 0;
        }
index 0606237..9e4ecc9 100644 (file)
@@ -207,7 +207,7 @@ BTF_ID(func, bpf_lsm_socket_socketpair)
 
 BTF_ID(func, bpf_lsm_syslog)
 BTF_ID(func, bpf_lsm_task_alloc)
-BTF_ID(func, bpf_lsm_task_getsecid_subj)
+BTF_ID(func, bpf_lsm_current_getsecid_subj)
 BTF_ID(func, bpf_lsm_task_getsecid_obj)
 BTF_ID(func, bpf_lsm_task_prctl)
 BTF_ID(func, bpf_lsm_task_setscheduler)
index 638d7fd..710ba9d 100644 (file)
@@ -104,7 +104,7 @@ static struct bpf_ringbuf *bpf_ringbuf_area_alloc(size_t data_sz, int numa_node)
        }
 
        rb = vmap(pages, nr_meta_pages + 2 * nr_data_pages,
-                 VM_ALLOC | VM_USERMAP, PAGE_KERNEL);
+                 VM_MAP | VM_USERMAP, PAGE_KERNEL);
        if (rb) {
                kmemleak_not_leak(pages);
                rb->pages = pages;
index 49e5672..22c8ae9 100644 (file)
@@ -472,13 +472,14 @@ BPF_CALL_4(bpf_get_task_stack, struct task_struct *, task, void *, buf,
           u32, size, u64, flags)
 {
        struct pt_regs *regs;
-       long res;
+       long res = -EINVAL;
 
        if (!try_get_task_stack(task))
                return -EFAULT;
 
        regs = task_pt_regs(task);
-       res = __bpf_get_stack(regs, task, NULL, buf, size, flags);
+       if (regs)
+               res = __bpf_get_stack(regs, task, NULL, buf, size, flags);
        put_task_stack(task);
 
        return res;
index 4b6974a..5e7edf9 100644 (file)
@@ -550,11 +550,12 @@ static __always_inline u64 notrace bpf_prog_start_time(void)
 static void notrace inc_misses_counter(struct bpf_prog *prog)
 {
        struct bpf_prog_stats *stats;
+       unsigned int flags;
 
        stats = this_cpu_ptr(prog->stats);
-       u64_stats_update_begin(&stats->syncp);
+       flags = u64_stats_update_begin_irqsave(&stats->syncp);
        u64_stats_inc(&stats->misses);
-       u64_stats_update_end(&stats->syncp);
+       u64_stats_update_end_irqrestore(&stats->syncp, flags);
 }
 
 /* The logic is similar to bpf_prog_run(), but with an explicit
index 41e0837..0e877db 100644 (file)
@@ -549,6 +549,14 @@ static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of,
 
        BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
 
+       /*
+        * Release agent gets called with all capabilities,
+        * require capabilities to set release agent.
+        */
+       if ((of->file->f_cred->user_ns != &init_user_ns) ||
+           !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
        cgrp = cgroup_kn_lock_live(of->kn, false);
        if (!cgrp)
                return -ENODEV;
@@ -954,6 +962,12 @@ int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param)
                /* Specifying two release agents is forbidden */
                if (ctx->release_agent)
                        return invalfc(fc, "release_agent respecified");
+               /*
+                * Release agent gets called with all capabilities,
+                * require capabilities to set release agent.
+                */
+               if ((fc->user_ns != &init_user_ns) || !capable(CAP_SYS_ADMIN))
+                       return invalfc(fc, "Setting release_agent not allowed");
                ctx->release_agent = param->string;
                param->string = NULL;
                break;
index b31e146..9d05c3c 100644 (file)
@@ -3643,6 +3643,12 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf,
        cgroup_get(cgrp);
        cgroup_kn_unlock(of->kn);
 
+       /* Allow only one trigger per file descriptor */
+       if (ctx->psi.trigger) {
+               cgroup_put(cgrp);
+               return -EBUSY;
+       }
+
        psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi;
        new = psi_trigger_create(psi, buf, nbytes, res);
        if (IS_ERR(new)) {
@@ -3650,8 +3656,7 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf,
                return PTR_ERR(new);
        }
 
-       psi_trigger_replace(&ctx->psi.trigger, new);
-
+       smp_store_release(&ctx->psi.trigger, new);
        cgroup_put(cgrp);
 
        return nbytes;
@@ -3690,7 +3695,7 @@ static void cgroup_pressure_release(struct kernfs_open_file *of)
 {
        struct cgroup_file_ctx *ctx = of->priv;
 
-       psi_trigger_replace(&ctx->psi.trigger, NULL);
+       psi_trigger_destroy(ctx->psi.trigger);
 }
 
 bool cgroup_psi_enabled(void)
index dc653ab..4c7254e 100644 (file)
@@ -590,6 +590,35 @@ static inline void free_cpuset(struct cpuset *cs)
        kfree(cs);
 }
 
+/*
+ * validate_change_legacy() - Validate conditions specific to legacy (v1)
+ *                            behavior.
+ */
+static int validate_change_legacy(struct cpuset *cur, struct cpuset *trial)
+{
+       struct cgroup_subsys_state *css;
+       struct cpuset *c, *par;
+       int ret;
+
+       WARN_ON_ONCE(!rcu_read_lock_held());
+
+       /* Each of our child cpusets must be a subset of us */
+       ret = -EBUSY;
+       cpuset_for_each_child(c, css, cur)
+               if (!is_cpuset_subset(c, trial))
+                       goto out;
+
+       /* On legacy hierarchy, we must be a subset of our parent cpuset. */
+       ret = -EACCES;
+       par = parent_cs(cur);
+       if (par && !is_cpuset_subset(trial, par))
+               goto out;
+
+       ret = 0;
+out:
+       return ret;
+}
+
 /*
  * validate_change() - Used to validate that any proposed cpuset change
  *                    follows the structural rules for cpusets.
@@ -614,20 +643,21 @@ static int validate_change(struct cpuset *cur, struct cpuset *trial)
 {
        struct cgroup_subsys_state *css;
        struct cpuset *c, *par;
-       int ret;
-
-       /* The checks don't apply to root cpuset */
-       if (cur == &top_cpuset)
-               return 0;
+       int ret = 0;
 
        rcu_read_lock();
-       par = parent_cs(cur);
 
-       /* On legacy hierarchy, we must be a subset of our parent cpuset. */
-       ret = -EACCES;
-       if (!is_in_v2_mode() && !is_cpuset_subset(trial, par))
+       if (!is_in_v2_mode())
+               ret = validate_change_legacy(cur, trial);
+       if (ret)
+               goto out;
+
+       /* Remaining checks don't apply to root cpuset */
+       if (cur == &top_cpuset)
                goto out;
 
+       par = parent_cs(cur);
+
        /*
         * If either I or some sibling (!= me) is exclusive, we can't
         * overlap
@@ -1175,9 +1205,7 @@ enum subparts_cmd {
  *
  * Because of the implicit cpu exclusive nature of a partition root,
  * cpumask changes that violates the cpu exclusivity rule will not be
- * permitted when checked by validate_change(). The validate_change()
- * function will also prevent any changes to the cpu list if it is not
- * a superset of children's cpu lists.
+ * permitted when checked by validate_change().
  */
 static int update_parent_subparts_cpumask(struct cpuset *cpuset, int cmd,
                                          struct cpumask *newmask,
@@ -1522,10 +1550,15 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs,
        struct cpuset *sibling;
        struct cgroup_subsys_state *pos_css;
 
+       percpu_rwsem_assert_held(&cpuset_rwsem);
+
        /*
         * Check all its siblings and call update_cpumasks_hier()
         * if their use_parent_ecpus flag is set in order for them
         * to use the right effective_cpus value.
+        *
+        * The update_cpumasks_hier() function may sleep. So we have to
+        * release the RCU read lock before calling it.
         */
        rcu_read_lock();
        cpuset_for_each_child(sibling, pos_css, parent) {
@@ -1533,8 +1566,13 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs,
                        continue;
                if (!sibling->use_parent_ecpus)
                        continue;
+               if (!css_tryget_online(&sibling->css))
+                       continue;
 
+               rcu_read_unlock();
                update_cpumasks_hier(sibling, tmp);
+               rcu_read_lock();
+               css_put(&sibling->css);
        }
        rcu_read_unlock();
 }
@@ -1607,8 +1645,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
         * Make sure that subparts_cpus is a subset of cpus_allowed.
         */
        if (cs->nr_subparts_cpus) {
-               cpumask_andnot(cs->subparts_cpus, cs->subparts_cpus,
-                              cs->cpus_allowed);
+               cpumask_and(cs->subparts_cpus, cs->subparts_cpus, cs->cpus_allowed);
                cs->nr_subparts_cpus = cpumask_weight(cs->subparts_cpus);
        }
        spin_unlock_irq(&callback_lock);
index fc18664..6859229 100644 (file)
@@ -674,6 +674,23 @@ perf_event_set_state(struct perf_event *event, enum perf_event_state state)
        WRITE_ONCE(event->state, state);
 }
 
+/*
+ * UP store-release, load-acquire
+ */
+
+#define __store_release(ptr, val)                                      \
+do {                                                                   \
+       barrier();                                                      \
+       WRITE_ONCE(*(ptr), (val));                                      \
+} while (0)
+
+#define __load_acquire(ptr)                                            \
+({                                                                     \
+       __unqual_scalar_typeof(*(ptr)) ___p = READ_ONCE(*(ptr));        \
+       barrier();                                                      \
+       ___p;                                                           \
+})
+
 #ifdef CONFIG_CGROUP_PERF
 
 static inline bool
@@ -719,34 +736,51 @@ static inline u64 perf_cgroup_event_time(struct perf_event *event)
        return t->time;
 }
 
-static inline void __update_cgrp_time(struct perf_cgroup *cgrp)
+static inline u64 perf_cgroup_event_time_now(struct perf_event *event, u64 now)
 {
-       struct perf_cgroup_info *info;
-       u64 now;
-
-       now = perf_clock();
+       struct perf_cgroup_info *t;
 
-       info = this_cpu_ptr(cgrp->info);
+       t = per_cpu_ptr(event->cgrp->info, event->cpu);
+       if (!__load_acquire(&t->active))
+               return t->time;
+       now += READ_ONCE(t->timeoffset);
+       return now;
+}
 
-       info->time += now - info->timestamp;
+static inline void __update_cgrp_time(struct perf_cgroup_info *info, u64 now, bool adv)
+{
+       if (adv)
+               info->time += now - info->timestamp;
        info->timestamp = now;
+       /*
+        * see update_context_time()
+        */
+       WRITE_ONCE(info->timeoffset, info->time - info->timestamp);
 }
 
-static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx)
+static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx, bool final)
 {
        struct perf_cgroup *cgrp = cpuctx->cgrp;
        struct cgroup_subsys_state *css;
+       struct perf_cgroup_info *info;
 
        if (cgrp) {
+               u64 now = perf_clock();
+
                for (css = &cgrp->css; css; css = css->parent) {
                        cgrp = container_of(css, struct perf_cgroup, css);
-                       __update_cgrp_time(cgrp);
+                       info = this_cpu_ptr(cgrp->info);
+
+                       __update_cgrp_time(info, now, true);
+                       if (final)
+                               __store_release(&info->active, 0);
                }
        }
 }
 
 static inline void update_cgrp_time_from_event(struct perf_event *event)
 {
+       struct perf_cgroup_info *info;
        struct perf_cgroup *cgrp;
 
        /*
@@ -760,8 +794,10 @@ static inline void update_cgrp_time_from_event(struct perf_event *event)
        /*
         * Do not update time when cgroup is not active
         */
-       if (cgroup_is_descendant(cgrp->css.cgroup, event->cgrp->css.cgroup))
-               __update_cgrp_time(event->cgrp);
+       if (cgroup_is_descendant(cgrp->css.cgroup, event->cgrp->css.cgroup)) {
+               info = this_cpu_ptr(event->cgrp->info);
+               __update_cgrp_time(info, perf_clock(), true);
+       }
 }
 
 static inline void
@@ -785,7 +821,8 @@ perf_cgroup_set_timestamp(struct task_struct *task,
        for (css = &cgrp->css; css; css = css->parent) {
                cgrp = container_of(css, struct perf_cgroup, css);
                info = this_cpu_ptr(cgrp->info);
-               info->timestamp = ctx->timestamp;
+               __update_cgrp_time(info, ctx->timestamp, false);
+               __store_release(&info->active, 1);
        }
 }
 
@@ -802,7 +839,7 @@ static DEFINE_PER_CPU(struct list_head, cgrp_cpuctx_list);
  */
 static void perf_cgroup_switch(struct task_struct *task, int mode)
 {
-       struct perf_cpu_context *cpuctx;
+       struct perf_cpu_context *cpuctx, *tmp;
        struct list_head *list;
        unsigned long flags;
 
@@ -813,7 +850,7 @@ static void perf_cgroup_switch(struct task_struct *task, int mode)
        local_irq_save(flags);
 
        list = this_cpu_ptr(&cgrp_cpuctx_list);
-       list_for_each_entry(cpuctx, list, cgrp_cpuctx_entry) {
+       list_for_each_entry_safe(cpuctx, tmp, list, cgrp_cpuctx_entry) {
                WARN_ON_ONCE(cpuctx->ctx.nr_cgroups == 0);
 
                perf_ctx_lock(cpuctx, cpuctx->task_ctx);
@@ -981,14 +1018,6 @@ out:
        return ret;
 }
 
-static inline void
-perf_cgroup_set_shadow_time(struct perf_event *event, u64 now)
-{
-       struct perf_cgroup_info *t;
-       t = per_cpu_ptr(event->cgrp->info, event->cpu);
-       event->shadow_ctx_time = now - t->timestamp;
-}
-
 static inline void
 perf_cgroup_event_enable(struct perf_event *event, struct perf_event_context *ctx)
 {
@@ -1066,7 +1095,8 @@ static inline void update_cgrp_time_from_event(struct perf_event *event)
 {
 }
 
-static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx)
+static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx,
+                                               bool final)
 {
 }
 
@@ -1098,12 +1128,12 @@ perf_cgroup_switch(struct task_struct *task, struct task_struct *next)
 {
 }
 
-static inline void
-perf_cgroup_set_shadow_time(struct perf_event *event, u64 now)
+static inline u64 perf_cgroup_event_time(struct perf_event *event)
 {
+       return 0;
 }
 
-static inline u64 perf_cgroup_event_time(struct perf_event *event)
+static inline u64 perf_cgroup_event_time_now(struct perf_event *event, u64 now)
 {
        return 0;
 }
@@ -1525,22 +1555,59 @@ static void perf_unpin_context(struct perf_event_context *ctx)
 /*
  * Update the record of the current time in a context.
  */
-static void update_context_time(struct perf_event_context *ctx)
+static void __update_context_time(struct perf_event_context *ctx, bool adv)
 {
        u64 now = perf_clock();
 
-       ctx->time += now - ctx->timestamp;
+       if (adv)
+               ctx->time += now - ctx->timestamp;
        ctx->timestamp = now;
+
+       /*
+        * The above: time' = time + (now - timestamp), can be re-arranged
+        * into: time` = now + (time - timestamp), which gives a single value
+        * offset to compute future time without locks on.
+        *
+        * See perf_event_time_now(), which can be used from NMI context where
+        * it's (obviously) not possible to acquire ctx->lock in order to read
+        * both the above values in a consistent manner.
+        */
+       WRITE_ONCE(ctx->timeoffset, ctx->time - ctx->timestamp);
+}
+
+static void update_context_time(struct perf_event_context *ctx)
+{
+       __update_context_time(ctx, true);
 }
 
 static u64 perf_event_time(struct perf_event *event)
 {
        struct perf_event_context *ctx = event->ctx;
 
+       if (unlikely(!ctx))
+               return 0;
+
        if (is_cgroup_event(event))
                return perf_cgroup_event_time(event);
 
-       return ctx ? ctx->time : 0;
+       return ctx->time;
+}
+
+static u64 perf_event_time_now(struct perf_event *event, u64 now)
+{
+       struct perf_event_context *ctx = event->ctx;
+
+       if (unlikely(!ctx))
+               return 0;
+
+       if (is_cgroup_event(event))
+               return perf_cgroup_event_time_now(event, now);
+
+       if (!(__load_acquire(&ctx->is_active) & EVENT_TIME))
+               return ctx->time;
+
+       now += READ_ONCE(ctx->timeoffset);
+       return now;
 }
 
 static enum event_type_t get_event_type(struct perf_event *event)
@@ -2350,7 +2417,7 @@ __perf_remove_from_context(struct perf_event *event,
 
        if (ctx->is_active & EVENT_TIME) {
                update_context_time(ctx);
-               update_cgrp_time_from_cpuctx(cpuctx);
+               update_cgrp_time_from_cpuctx(cpuctx, false);
        }
 
        event_sched_out(event, cpuctx, ctx);
@@ -2361,6 +2428,9 @@ __perf_remove_from_context(struct perf_event *event,
        list_del_event(event, ctx);
 
        if (!ctx->nr_events && ctx->is_active) {
+               if (ctx == &cpuctx->ctx)
+                       update_cgrp_time_from_cpuctx(cpuctx, true);
+
                ctx->is_active = 0;
                ctx->rotate_necessary = 0;
                if (ctx->task) {
@@ -2392,7 +2462,11 @@ static void perf_remove_from_context(struct perf_event *event, unsigned long fla
         * event_function_call() user.
         */
        raw_spin_lock_irq(&ctx->lock);
-       if (!ctx->is_active) {
+       /*
+        * Cgroup events are per-cpu events, and must IPI because of
+        * cgrp_cpuctx_list.
+        */
+       if (!ctx->is_active && !is_cgroup_event(event)) {
                __perf_remove_from_context(event, __get_cpu_context(ctx),
                                           ctx, (void *)flags);
                raw_spin_unlock_irq(&ctx->lock);
@@ -2482,40 +2556,6 @@ void perf_event_disable_inatomic(struct perf_event *event)
        irq_work_queue(&event->pending);
 }
 
-static void perf_set_shadow_time(struct perf_event *event,
-                                struct perf_event_context *ctx)
-{
-       /*
-        * use the correct time source for the time snapshot
-        *
-        * We could get by without this by leveraging the
-        * fact that to get to this function, the caller
-        * has most likely already called update_context_time()
-        * and update_cgrp_time_xx() and thus both timestamp
-        * are identical (or very close). Given that tstamp is,
-        * already adjusted for cgroup, we could say that:
-        *    tstamp - ctx->timestamp
-        * is equivalent to
-        *    tstamp - cgrp->timestamp.
-        *
-        * Then, in perf_output_read(), the calculation would
-        * work with no changes because:
-        * - event is guaranteed scheduled in
-        * - no scheduled out in between
-        * - thus the timestamp would be the same
-        *
-        * But this is a bit hairy.
-        *
-        * So instead, we have an explicit cgroup call to remain
-        * within the time source all along. We believe it
-        * is cleaner and simpler to understand.
-        */
-       if (is_cgroup_event(event))
-               perf_cgroup_set_shadow_time(event, event->tstamp);
-       else
-               event->shadow_ctx_time = event->tstamp - ctx->timestamp;
-}
-
 #define MAX_INTERRUPTS (~0ULL)
 
 static void perf_log_throttle(struct perf_event *event, int enable);
@@ -2556,8 +2596,6 @@ event_sched_in(struct perf_event *event,
 
        perf_pmu_disable(event->pmu);
 
-       perf_set_shadow_time(event, ctx);
-
        perf_log_itrace_start(event);
 
        if (event->pmu->add(event, PERF_EF_START)) {
@@ -2861,11 +2899,14 @@ perf_install_in_context(struct perf_event_context *ctx,
         * perf_event_attr::disabled events will not run and can be initialized
         * without IPI. Except when this is the first event for the context, in
         * that case we need the magic of the IPI to set ctx->is_active.
+        * Similarly, cgroup events for the context also needs the IPI to
+        * manipulate the cgrp_cpuctx_list.
         *
         * The IOC_ENABLE that is sure to follow the creation of a disabled
         * event will issue the IPI and reprogram the hardware.
         */
-       if (__perf_effective_state(event) == PERF_EVENT_STATE_OFF && ctx->nr_events) {
+       if (__perf_effective_state(event) == PERF_EVENT_STATE_OFF &&
+           ctx->nr_events && !is_cgroup_event(event)) {
                raw_spin_lock_irq(&ctx->lock);
                if (ctx->task == TASK_TOMBSTONE) {
                        raw_spin_unlock_irq(&ctx->lock);
@@ -3197,6 +3238,15 @@ static int perf_event_modify_breakpoint(struct perf_event *bp,
        return err;
 }
 
+/*
+ * Copy event-type-independent attributes that may be modified.
+ */
+static void perf_event_modify_copy_attr(struct perf_event_attr *to,
+                                       const struct perf_event_attr *from)
+{
+       to->sig_data = from->sig_data;
+}
+
 static int perf_event_modify_attr(struct perf_event *event,
                                  struct perf_event_attr *attr)
 {
@@ -3219,10 +3269,17 @@ static int perf_event_modify_attr(struct perf_event *event,
        WARN_ON_ONCE(event->ctx->parent_ctx);
 
        mutex_lock(&event->child_mutex);
+       /*
+        * Event-type-independent attributes must be copied before event-type
+        * modification, which will validate that final attributes match the
+        * source attributes after all relevant attributes have been copied.
+        */
+       perf_event_modify_copy_attr(&event->attr, attr);
        err = func(event, attr);
        if (err)
                goto out;
        list_for_each_entry(child, &event->child_list, child_list) {
+               perf_event_modify_copy_attr(&child->attr, attr);
                err = func(child, attr);
                if (err)
                        goto out;
@@ -3251,16 +3308,6 @@ static void ctx_sched_out(struct perf_event_context *ctx,
                return;
        }
 
-       ctx->is_active &= ~event_type;
-       if (!(ctx->is_active & EVENT_ALL))
-               ctx->is_active = 0;
-
-       if (ctx->task) {
-               WARN_ON_ONCE(cpuctx->task_ctx != ctx);
-               if (!ctx->is_active)
-                       cpuctx->task_ctx = NULL;
-       }
-
        /*
         * Always update time if it was set; not only when it changes.
         * Otherwise we can 'forget' to update time for any but the last
@@ -3274,7 +3321,22 @@ static void ctx_sched_out(struct perf_event_context *ctx,
        if (is_active & EVENT_TIME) {
                /* update (and stop) ctx time */
                update_context_time(ctx);
-               update_cgrp_time_from_cpuctx(cpuctx);
+               update_cgrp_time_from_cpuctx(cpuctx, ctx == &cpuctx->ctx);
+               /*
+                * CPU-release for the below ->is_active store,
+                * see __load_acquire() in perf_event_time_now()
+                */
+               barrier();
+       }
+
+       ctx->is_active &= ~event_type;
+       if (!(ctx->is_active & EVENT_ALL))
+               ctx->is_active = 0;
+
+       if (ctx->task) {
+               WARN_ON_ONCE(cpuctx->task_ctx != ctx);
+               if (!ctx->is_active)
+                       cpuctx->task_ctx = NULL;
        }
 
        is_active ^= ctx->is_active; /* changed bits */
@@ -3711,13 +3773,19 @@ static noinline int visit_groups_merge(struct perf_cpu_context *cpuctx,
        return 0;
 }
 
+/*
+ * Because the userpage is strictly per-event (there is no concept of context,
+ * so there cannot be a context indirection), every userpage must be updated
+ * when context time starts :-(
+ *
+ * IOW, we must not miss EVENT_TIME edges.
+ */
 static inline bool event_update_userpage(struct perf_event *event)
 {
        if (likely(!atomic_read(&event->mmap_count)))
                return false;
 
        perf_event_update_time(event);
-       perf_set_shadow_time(event, event->ctx);
        perf_event_update_userpage(event);
 
        return true;
@@ -3801,13 +3869,23 @@ ctx_sched_in(struct perf_event_context *ctx,
             struct task_struct *task)
 {
        int is_active = ctx->is_active;
-       u64 now;
 
        lockdep_assert_held(&ctx->lock);
 
        if (likely(!ctx->nr_events))
                return;
 
+       if (is_active ^ EVENT_TIME) {
+               /* start ctx time */
+               __update_context_time(ctx, false);
+               perf_cgroup_set_timestamp(task, ctx);
+               /*
+                * CPU-release for the below ->is_active store,
+                * see __load_acquire() in perf_event_time_now()
+                */
+               barrier();
+       }
+
        ctx->is_active |= (event_type | EVENT_TIME);
        if (ctx->task) {
                if (!is_active)
@@ -3818,13 +3896,6 @@ ctx_sched_in(struct perf_event_context *ctx,
 
        is_active ^= ctx->is_active; /* changed bits */
 
-       if (is_active & EVENT_TIME) {
-               /* start ctx time */
-               now = perf_clock();
-               ctx->timestamp = now;
-               perf_cgroup_set_timestamp(task, ctx);
-       }
-
        /*
         * First go through the list and put on any pinned groups
         * in order to give them the best chance of going on.
@@ -4418,6 +4489,18 @@ static inline u64 perf_event_count(struct perf_event *event)
        return local64_read(&event->count) + atomic64_read(&event->child_count);
 }
 
+static void calc_timer_values(struct perf_event *event,
+                               u64 *now,
+                               u64 *enabled,
+                               u64 *running)
+{
+       u64 ctx_time;
+
+       *now = perf_clock();
+       ctx_time = perf_event_time_now(event, *now);
+       __perf_update_times(event, ctx_time, enabled, running);
+}
+
 /*
  * NMI-safe method to read a local event, that is an event that
  * is:
@@ -4477,10 +4560,9 @@ int perf_event_read_local(struct perf_event *event, u64 *value,
 
        *value = local64_read(&event->count);
        if (enabled || running) {
-               u64 now = event->shadow_ctx_time + perf_clock();
-               u64 __enabled, __running;
+               u64 __enabled, __running, __now;;
 
-               __perf_update_times(event, now, &__enabled, &__running);
+               calc_timer_values(event, &__now, &__enabled, &__running);
                if (enabled)
                        *enabled = __enabled;
                if (running)
@@ -5802,18 +5884,6 @@ static int perf_event_index(struct perf_event *event)
        return event->pmu->event_idx(event);
 }
 
-static void calc_timer_values(struct perf_event *event,
-                               u64 *now,
-                               u64 *enabled,
-                               u64 *running)
-{
-       u64 ctx_time;
-
-       *now = perf_clock();
-       ctx_time = event->shadow_ctx_time + *now;
-       __perf_update_times(event, ctx_time, enabled, running);
-}
-
 static void perf_event_init_userpage(struct perf_event *event)
 {
        struct perf_event_mmap_page *userpg;
@@ -5938,6 +6008,8 @@ static void ring_buffer_attach(struct perf_event *event,
        struct perf_buffer *old_rb = NULL;
        unsigned long flags;
 
+       WARN_ON_ONCE(event->parent);
+
        if (event->rb) {
                /*
                 * Should be impossible, we set this when removing
@@ -5995,6 +6067,9 @@ static void ring_buffer_wakeup(struct perf_event *event)
 {
        struct perf_buffer *rb;
 
+       if (event->parent)
+               event = event->parent;
+
        rcu_read_lock();
        rb = rcu_dereference(event->rb);
        if (rb) {
@@ -6008,6 +6083,9 @@ struct perf_buffer *ring_buffer_get(struct perf_event *event)
 {
        struct perf_buffer *rb;
 
+       if (event->parent)
+               event = event->parent;
+
        rcu_read_lock();
        rb = rcu_dereference(event->rb);
        if (rb) {
@@ -6353,7 +6431,6 @@ accounting:
                ring_buffer_attach(event, rb);
 
                perf_event_update_time(event);
-               perf_set_shadow_time(event, event->ctx);
                perf_event_init_userpage(event);
                perf_event_update_userpage(event);
        } else {
@@ -6717,7 +6794,7 @@ static unsigned long perf_prepare_sample_aux(struct perf_event *event,
        if (WARN_ON_ONCE(READ_ONCE(sampler->oncpu) != smp_processor_id()))
                goto out;
 
-       rb = ring_buffer_get(sampler->parent ? sampler->parent : sampler);
+       rb = ring_buffer_get(sampler);
        if (!rb)
                goto out;
 
@@ -6783,7 +6860,7 @@ static void perf_aux_sample_output(struct perf_event *event,
        if (WARN_ON_ONCE(!sampler || !data->aux_size))
                return;
 
-       rb = ring_buffer_get(sampler->parent ? sampler->parent : sampler);
+       rb = ring_buffer_get(sampler);
        if (!rb)
                return;
 
index 24dab04..46a5c2e 100644 (file)
@@ -3725,12 +3725,6 @@ static noinline int do_init_module(struct module *mod)
        }
        freeinit->module_init = mod->init_layout.base;
 
-       /*
-        * We want to find out whether @mod uses async during init.  Clear
-        * PF_USED_ASYNC.  async_schedule*() will set it.
-        */
-       current->flags &= ~PF_USED_ASYNC;
-
        do_mod_ctors(mod);
        /* Start the module */
        if (mod->init != NULL)
@@ -3756,22 +3750,13 @@ static noinline int do_init_module(struct module *mod)
 
        /*
         * We need to finish all async code before the module init sequence
-        * is done.  This has potential to deadlock.  For example, a newly
-        * detected block device can trigger request_module() of the
-        * default iosched from async probing task.  Once userland helper
-        * reaches here, async_synchronize_full() will wait on the async
-        * task waiting on request_module() and deadlock.
-        *
-        * This deadlock is avoided by perfomring async_synchronize_full()
-        * iff module init queued any async jobs.  This isn't a full
-        * solution as it will deadlock the same if module loading from
-        * async jobs nests more than once; however, due to the various
-        * constraints, this hack seems to be the best option for now.
-        * Please refer to the following thread for details.
+        * is done. This has potential to deadlock if synchronous module
+        * loading is requested from async (which is not allowed!).
         *
-        * http://thread.gmane.org/gmane.linux.kernel/1420814
+        * See commit 0fdff3ec6d87 ("async, kmod: warn on synchronous
+        * request_module() from async workers") for more details.
         */
-       if (!mod->async_probe_requested && (current->flags & PF_USED_ASYNC))
+       if (!mod->async_probe_requested)
                async_synchronize_full();
 
        ftrace_free_mem(mod, mod->init_layout.base, mod->init_layout.base +
index 44169f3..7e64607 100644 (file)
@@ -504,7 +504,10 @@ static ssize_t pm_wakeup_irq_show(struct kobject *kobj,
                                        struct kobj_attribute *attr,
                                        char *buf)
 {
-       return pm_wakeup_irq ? sprintf(buf, "%u\n", pm_wakeup_irq) : -ENODATA;
+       if (!pm_wakeup_irq())
+               return -ENODATA;
+
+       return sprintf(buf, "%u\n", pm_wakeup_irq());
 }
 
 power_attr_ro(pm_wakeup_irq);
index b7e7798..11b570f 100644 (file)
@@ -134,7 +134,7 @@ int freeze_processes(void)
        if (!pm_freezing)
                atomic_inc(&system_freezing_cnt);
 
-       pm_wakeup_clear(true);
+       pm_wakeup_clear(0);
        pr_info("Freezing user space processes ... ");
        pm_freezing = true;
        error = try_to_freeze_tasks(true);
index f7a9860..330d499 100644 (file)
@@ -978,8 +978,7 @@ static void memory_bm_recycle(struct memory_bitmap *bm)
  * Register a range of page frames the contents of which should not be saved
  * during hibernation (to be used in the early initialization code).
  */
-void __init __register_nosave_region(unsigned long start_pfn,
-                                    unsigned long end_pfn, int use_kmalloc)
+void __init register_nosave_region(unsigned long start_pfn, unsigned long end_pfn)
 {
        struct nosave_region *region;
 
@@ -995,18 +994,12 @@ void __init __register_nosave_region(unsigned long start_pfn,
                        goto Report;
                }
        }
-       if (use_kmalloc) {
-               /* During init, this shouldn't fail */
-               region = kmalloc(sizeof(struct nosave_region), GFP_KERNEL);
-               BUG_ON(!region);
-       } else {
-               /* This allocation cannot fail */
-               region = memblock_alloc(sizeof(struct nosave_region),
-                                       SMP_CACHE_BYTES);
-               if (!region)
-                       panic("%s: Failed to allocate %zu bytes\n", __func__,
-                             sizeof(struct nosave_region));
-       }
+       /* This allocation cannot fail */
+       region = memblock_alloc(sizeof(struct nosave_region),
+                               SMP_CACHE_BYTES);
+       if (!region)
+               panic("%s: Failed to allocate %zu bytes\n", __func__,
+                     sizeof(struct nosave_region));
        region->start_pfn = start_pfn;
        region->end_pfn = end_pfn;
        list_add_tail(&region->list, &nosave_regions);
index 80cc1f0..6fcdee7 100644 (file)
@@ -136,8 +136,6 @@ static void s2idle_loop(void)
                        break;
                }
 
-               pm_wakeup_clear(false);
-
                s2idle_enter();
        }
 
index 105df4d..52571dc 100644 (file)
@@ -39,23 +39,20 @@ ssize_t pm_show_wakelocks(char *buf, bool show_active)
 {
        struct rb_node *node;
        struct wakelock *wl;
-       char *str = buf;
-       char *end = buf + PAGE_SIZE;
+       int len = 0;
 
        mutex_lock(&wakelocks_lock);
 
        for (node = rb_first(&wakelocks_tree); node; node = rb_next(node)) {
                wl = rb_entry(node, struct wakelock, node);
                if (wl->ws->active == show_active)
-                       str += scnprintf(str, end - str, "%s ", wl->name);
+                       len += sysfs_emit_at(buf, len, "%s ", wl->name);
        }
-       if (str > buf)
-               str--;
 
-       str += scnprintf(str, end - str, "\n");
+       len += sysfs_emit_at(buf, len, "\n");
 
        mutex_unlock(&wakelocks_lock);
-       return (str - buf);
+       return len;
 }
 
 #if CONFIG_PM_WAKELOCKS_LIMIT > 0
index 653ae04..c228343 100644 (file)
@@ -12,7 +12,7 @@
 static const int ten_thousand = 10000;
 
 static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write,
-                               void __user *buffer, size_t *lenp, loff_t *ppos)
+                               void *buffer, size_t *lenp, loff_t *ppos)
 {
        if (write && !capable(CAP_SYS_ADMIN))
                return -EPERM;
index 84f1d91..d64f0b1 100644 (file)
@@ -123,7 +123,7 @@ static struct rcu_tasks rt_name =                                                   \
        .call_func = call,                                                              \
        .rtpcpu = &rt_name ## __percpu,                                                 \
        .name = n,                                                                      \
-       .percpu_enqueue_shift = ilog2(CONFIG_NR_CPUS),                                  \
+       .percpu_enqueue_shift = ilog2(CONFIG_NR_CPUS) + 1,                              \
        .percpu_enqueue_lim = 1,                                                        \
        .percpu_dequeue_lim = 1,                                                        \
        .barrier_q_mutex = __MUTEX_INITIALIZER(rt_name.barrier_q_mutex),                \
@@ -216,6 +216,7 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
        int cpu;
        unsigned long flags;
        int lim;
+       int shift;
 
        raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
        if (rcu_task_enqueue_lim < 0) {
@@ -229,7 +230,10 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
 
        if (lim > nr_cpu_ids)
                lim = nr_cpu_ids;
-       WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids / lim));
+       shift = ilog2(nr_cpu_ids / lim);
+       if (((nr_cpu_ids - 1) >> shift) >= lim)
+               shift++;
+       WRITE_ONCE(rtp->percpu_enqueue_shift, shift);
        WRITE_ONCE(rtp->percpu_dequeue_lim, lim);
        smp_store_release(&rtp->percpu_enqueue_lim, lim);
        for_each_possible_cpu(cpu) {
@@ -298,7 +302,7 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
        if (unlikely(needadjust)) {
                raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
                if (rtp->percpu_enqueue_lim != nr_cpu_ids) {
-                       WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids));
+                       WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids) + 1);
                        WRITE_ONCE(rtp->percpu_dequeue_lim, nr_cpu_ids);
                        smp_store_release(&rtp->percpu_enqueue_lim, nr_cpu_ids);
                        pr_info("Switching %s to per-CPU callback queuing.\n", rtp->name);
@@ -413,7 +417,7 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp)
        if (rcu_task_cb_adjust && ncbs <= rcu_task_collapse_lim) {
                raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
                if (rtp->percpu_enqueue_lim > 1) {
-                       WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids));
+                       WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids) + 1);
                        smp_store_release(&rtp->percpu_enqueue_lim, 1);
                        rtp->percpu_dequeue_gpseq = get_state_synchronize_rcu();
                        pr_info("Starting switch %s to CPU-0 callback queuing.\n", rtp->name);
index 2e4ae00..fcf0c18 100644 (file)
@@ -1214,8 +1214,9 @@ int tg_nop(struct task_group *tg, void *data)
 }
 #endif
 
-static void set_load_weight(struct task_struct *p, bool update_load)
+static void set_load_weight(struct task_struct *p)
 {
+       bool update_load = !(READ_ONCE(p->__state) & TASK_NEW);
        int prio = p->static_prio - MAX_RT_PRIO;
        struct load_weight *load = &p->se.load;
 
@@ -4406,7 +4407,7 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
                        p->static_prio = NICE_TO_PRIO(0);
 
                p->prio = p->normal_prio = p->static_prio;
-               set_load_weight(p, false);
+               set_load_weight(p);
 
                /*
                 * We don't need the reset flag anymore after the fork. It has
@@ -5822,8 +5823,7 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
        }
 
        if (schedstat_enabled() && rq->core->core_forceidle_count) {
-               if (cookie)
-                       rq->core->core_forceidle_start = rq_clock(rq->core);
+               rq->core->core_forceidle_start = rq_clock(rq->core);
                rq->core->core_forceidle_occupation = occ;
        }
 
@@ -6922,7 +6922,7 @@ void set_user_nice(struct task_struct *p, long nice)
                put_prev_task(rq, p);
 
        p->static_prio = NICE_TO_PRIO(nice);
-       set_load_weight(p, true);
+       set_load_weight(p);
        old_prio = p->prio;
        p->prio = effective_prio(p);
 
@@ -7213,7 +7213,7 @@ static void __setscheduler_params(struct task_struct *p,
         */
        p->rt_priority = attr->sched_priority;
        p->normal_prio = normal_prio(p);
-       set_load_weight(p, true);
+       set_load_weight(p);
 }
 
 /*
@@ -8219,9 +8219,7 @@ int __cond_resched_lock(spinlock_t *lock)
 
        if (spin_needbreak(lock) || resched) {
                spin_unlock(lock);
-               if (resched)
-                       preempt_schedule_common();
-               else
+               if (!_cond_resched())
                        cpu_relax();
                ret = 1;
                spin_lock(lock);
@@ -8239,9 +8237,7 @@ int __cond_resched_rwlock_read(rwlock_t *lock)
 
        if (rwlock_needbreak(lock) || resched) {
                read_unlock(lock);
-               if (resched)
-                       preempt_schedule_common();
-               else
+               if (!_cond_resched())
                        cpu_relax();
                ret = 1;
                read_lock(lock);
@@ -8259,9 +8255,7 @@ int __cond_resched_rwlock_write(rwlock_t *lock)
 
        if (rwlock_needbreak(lock) || resched) {
                write_unlock(lock);
-               if (resched)
-                       preempt_schedule_common();
-               else
+               if (!_cond_resched())
                        cpu_relax();
                ret = 1;
                write_lock(lock);
@@ -9452,7 +9446,7 @@ void __init sched_init(void)
 #endif
        }
 
-       set_load_weight(&init_task, false);
+       set_load_weight(&init_task);
 
        /*
         * The boot idle thread does lazy MMU switching as well:
index 1fb4567..c8746a9 100644 (file)
@@ -277,7 +277,7 @@ void __sched_core_account_forceidle(struct rq *rq)
                rq_i = cpu_rq(i);
                p = rq_i->core_pick ?: rq_i->curr;
 
-               if (!p->core_cookie)
+               if (p == rq_i->idle)
                        continue;
 
                __schedstat_add(p->stats.core_forceidle_sum, delta);
index 095b0aa..5146163 100644 (file)
@@ -3028,9 +3028,11 @@ enqueue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 static inline void
 dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       u32 divider = get_pelt_divider(&se->avg);
        sub_positive(&cfs_rq->avg.load_avg, se->avg.load_avg);
-       cfs_rq->avg.load_sum = cfs_rq->avg.load_avg * divider;
+       sub_positive(&cfs_rq->avg.load_sum, se_weight(se) * se->avg.load_sum);
+       /* See update_cfs_rq_load_avg() */
+       cfs_rq->avg.load_sum = max_t(u32, cfs_rq->avg.load_sum,
+                                         cfs_rq->avg.load_avg * PELT_MIN_DIVIDER);
 }
 #else
 static inline void
@@ -3381,7 +3383,6 @@ void set_task_rq_fair(struct sched_entity *se,
        se->avg.last_update_time = n_last_update_time;
 }
 
-
 /*
  * When on migration a sched_entity joins/leaves the PELT hierarchy, we need to
  * propagate its contribution. The key to this propagation is the invariant
@@ -3449,15 +3450,14 @@ void set_task_rq_fair(struct sched_entity *se,
  * XXX: only do this for the part of runnable > running ?
  *
  */
-
 static inline void
 update_tg_cfs_util(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq *gcfs_rq)
 {
-       long delta = gcfs_rq->avg.util_avg - se->avg.util_avg;
-       u32 divider;
+       long delta_sum, delta_avg = gcfs_rq->avg.util_avg - se->avg.util_avg;
+       u32 new_sum, divider;
 
        /* Nothing to update */
-       if (!delta)
+       if (!delta_avg)
                return;
 
        /*
@@ -3466,23 +3466,30 @@ update_tg_cfs_util(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq
         */
        divider = get_pelt_divider(&cfs_rq->avg);
 
+
        /* Set new sched_entity's utilization */
        se->avg.util_avg = gcfs_rq->avg.util_avg;
-       se->avg.util_sum = se->avg.util_avg * divider;
+       new_sum = se->avg.util_avg * divider;
+       delta_sum = (long)new_sum - (long)se->avg.util_sum;
+       se->avg.util_sum = new_sum;
 
        /* Update parent cfs_rq utilization */
-       add_positive(&cfs_rq->avg.util_avg, delta);
-       cfs_rq->avg.util_sum = cfs_rq->avg.util_avg * divider;
+       add_positive(&cfs_rq->avg.util_avg, delta_avg);
+       add_positive(&cfs_rq->avg.util_sum, delta_sum);
+
+       /* See update_cfs_rq_load_avg() */
+       cfs_rq->avg.util_sum = max_t(u32, cfs_rq->avg.util_sum,
+                                         cfs_rq->avg.util_avg * PELT_MIN_DIVIDER);
 }
 
 static inline void
 update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq *gcfs_rq)
 {
-       long delta = gcfs_rq->avg.runnable_avg - se->avg.runnable_avg;
-       u32 divider;
+       long delta_sum, delta_avg = gcfs_rq->avg.runnable_avg - se->avg.runnable_avg;
+       u32 new_sum, divider;
 
        /* Nothing to update */
-       if (!delta)
+       if (!delta_avg)
                return;
 
        /*
@@ -3493,19 +3500,25 @@ update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cf
 
        /* Set new sched_entity's runnable */
        se->avg.runnable_avg = gcfs_rq->avg.runnable_avg;
-       se->avg.runnable_sum = se->avg.runnable_avg * divider;
+       new_sum = se->avg.runnable_avg * divider;
+       delta_sum = (long)new_sum - (long)se->avg.runnable_sum;
+       se->avg.runnable_sum = new_sum;
 
        /* Update parent cfs_rq runnable */
-       add_positive(&cfs_rq->avg.runnable_avg, delta);
-       cfs_rq->avg.runnable_sum = cfs_rq->avg.runnable_avg * divider;
+       add_positive(&cfs_rq->avg.runnable_avg, delta_avg);
+       add_positive(&cfs_rq->avg.runnable_sum, delta_sum);
+       /* See update_cfs_rq_load_avg() */
+       cfs_rq->avg.runnable_sum = max_t(u32, cfs_rq->avg.runnable_sum,
+                                             cfs_rq->avg.runnable_avg * PELT_MIN_DIVIDER);
 }
 
 static inline void
 update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq *gcfs_rq)
 {
-       long delta, running_sum, runnable_sum = gcfs_rq->prop_runnable_sum;
+       long delta_avg, running_sum, runnable_sum = gcfs_rq->prop_runnable_sum;
        unsigned long load_avg;
        u64 load_sum = 0;
+       s64 delta_sum;
        u32 divider;
 
        if (!runnable_sum)
@@ -3532,7 +3545,7 @@ update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq
                 * assuming all tasks are equally runnable.
                 */
                if (scale_load_down(gcfs_rq->load.weight)) {
-                       load_sum = div_s64(gcfs_rq->avg.load_sum,
+                       load_sum = div_u64(gcfs_rq->avg.load_sum,
                                scale_load_down(gcfs_rq->load.weight));
                }
 
@@ -3549,19 +3562,22 @@ update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq
        running_sum = se->avg.util_sum >> SCHED_CAPACITY_SHIFT;
        runnable_sum = max(runnable_sum, running_sum);
 
-       load_sum = (s64)se_weight(se) * runnable_sum;
-       load_avg = div_s64(load_sum, divider);
-
-       se->avg.load_sum = runnable_sum;
+       load_sum = se_weight(se) * runnable_sum;
+       load_avg = div_u64(load_sum, divider);
 
-       delta = load_avg - se->avg.load_avg;
-       if (!delta)
+       delta_avg = load_avg - se->avg.load_avg;
+       if (!delta_avg)
                return;
 
-       se->avg.load_avg = load_avg;
+       delta_sum = load_sum - (s64)se_weight(se) * se->avg.load_sum;
 
-       add_positive(&cfs_rq->avg.load_avg, delta);
-       cfs_rq->avg.load_sum = cfs_rq->avg.load_avg * divider;
+       se->avg.load_sum = runnable_sum;
+       se->avg.load_avg = load_avg;
+       add_positive(&cfs_rq->avg.load_avg, delta_avg);
+       add_positive(&cfs_rq->avg.load_sum, delta_sum);
+       /* See update_cfs_rq_load_avg() */
+       cfs_rq->avg.load_sum = max_t(u32, cfs_rq->avg.load_sum,
+                                         cfs_rq->avg.load_avg * PELT_MIN_DIVIDER);
 }
 
 static inline void add_tg_cfs_propagate(struct cfs_rq *cfs_rq, long runnable_sum)
@@ -3652,7 +3668,7 @@ static inline void add_tg_cfs_propagate(struct cfs_rq *cfs_rq, long runnable_sum
  *
  * cfs_rq->avg is used for task_h_load() and update_cfs_share() for example.
  *
- * Returns true if the load decayed or we removed load.
+ * Return: true if the load decayed or we removed load.
  *
  * Since both these conditions indicate a changed cfs_rq->avg.load we should
  * call update_tg_load_avg() when this function returns true.
@@ -3677,15 +3693,32 @@ update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
 
                r = removed_load;
                sub_positive(&sa->load_avg, r);
-               sa->load_sum = sa->load_avg * divider;
+               sub_positive(&sa->load_sum, r * divider);
+               /* See sa->util_sum below */
+               sa->load_sum = max_t(u32, sa->load_sum, sa->load_avg * PELT_MIN_DIVIDER);
 
                r = removed_util;
                sub_positive(&sa->util_avg, r);
-               sa->util_sum = sa->util_avg * divider;
+               sub_positive(&sa->util_sum, r * divider);
+               /*
+                * Because of rounding, se->util_sum might ends up being +1 more than
+                * cfs->util_sum. Although this is not a problem by itself, detaching
+                * a lot of tasks with the rounding problem between 2 updates of
+                * util_avg (~1ms) can make cfs->util_sum becoming null whereas
+                * cfs_util_avg is not.
+                * Check that util_sum is still above its lower bound for the new
+                * util_avg. Given that period_contrib might have moved since the last
+                * sync, we are only sure that util_sum must be above or equal to
+                *    util_avg * minimum possible divider
+                */
+               sa->util_sum = max_t(u32, sa->util_sum, sa->util_avg * PELT_MIN_DIVIDER);
 
                r = removed_runnable;
                sub_positive(&sa->runnable_avg, r);
-               sa->runnable_sum = sa->runnable_avg * divider;
+               sub_positive(&sa->runnable_sum, r * divider);
+               /* See sa->util_sum above */
+               sa->runnable_sum = max_t(u32, sa->runnable_sum,
+                                             sa->runnable_avg * PELT_MIN_DIVIDER);
 
                /*
                 * removed_runnable is the unweighted version of removed_load so we
@@ -3772,17 +3805,18 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
  */
 static void detach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       /*
-        * cfs_rq->avg.period_contrib can be used for both cfs_rq and se.
-        * See ___update_load_avg() for details.
-        */
-       u32 divider = get_pelt_divider(&cfs_rq->avg);
-
        dequeue_load_avg(cfs_rq, se);
        sub_positive(&cfs_rq->avg.util_avg, se->avg.util_avg);
-       cfs_rq->avg.util_sum = cfs_rq->avg.util_avg * divider;
+       sub_positive(&cfs_rq->avg.util_sum, se->avg.util_sum);
+       /* See update_cfs_rq_load_avg() */
+       cfs_rq->avg.util_sum = max_t(u32, cfs_rq->avg.util_sum,
+                                         cfs_rq->avg.util_avg * PELT_MIN_DIVIDER);
+
        sub_positive(&cfs_rq->avg.runnable_avg, se->avg.runnable_avg);
-       cfs_rq->avg.runnable_sum = cfs_rq->avg.runnable_avg * divider;
+       sub_positive(&cfs_rq->avg.runnable_sum, se->avg.runnable_sum);
+       /* See update_cfs_rq_load_avg() */
+       cfs_rq->avg.runnable_sum = max_t(u32, cfs_rq->avg.runnable_sum,
+                                             cfs_rq->avg.runnable_avg * PELT_MIN_DIVIDER);
 
        add_tg_cfs_propagate(cfs_rq, -se->avg.load_sum);
 
@@ -8539,6 +8573,8 @@ group_type group_classify(unsigned int imbalance_pct,
  *
  * If @sg does not have SMT siblings, only pull tasks if all of the SMT siblings
  * of @dst_cpu are idle and @sg has lower priority.
+ *
+ * Return: true if @dst_cpu can pull tasks, false otherwise.
  */
 static bool asym_smt_can_pull_tasks(int dst_cpu, struct sd_lb_stats *sds,
                                    struct sg_lb_stats *sgs,
@@ -8614,6 +8650,7 @@ sched_asym(struct lb_env *env, struct sd_lb_stats *sds,  struct sg_lb_stats *sgs
 /**
  * update_sg_lb_stats - Update sched_group's statistics for load balancing.
  * @env: The load balancing environment.
+ * @sds: Load-balancing data with statistics of the local group.
  * @group: sched_group whose statistics are to be updated.
  * @sgs: variable to hold the statistics for this group.
  * @sg_status: Holds flag indicating the status of the sched_group
@@ -9421,12 +9458,11 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
 /**
  * find_busiest_group - Returns the busiest group within the sched_domain
  * if there is an imbalance.
+ * @env: The load balancing environment.
  *
  * Also calculates the amount of runnable load which should be moved
  * to restore balance.
  *
- * @env: The load balancing environment.
- *
  * Return:     - The busiest group if imbalance exists.
  */
 static struct sched_group *find_busiest_group(struct lb_env *env)
index b5add64..3d28254 100644 (file)
 #endif
 
 #ifdef CONFIG_RSEQ
-#define MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ_BITMASK          \
+#define MEMBARRIER_PRIVATE_EXPEDITED_RSEQ_BITMASK              \
        (MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ                  \
-       | MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ_BITMASK)
+       | MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ)
 #else
-#define MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ_BITMASK  0
+#define MEMBARRIER_PRIVATE_EXPEDITED_RSEQ_BITMASK      0
 #endif
 
 #define MEMBARRIER_CMD_BITMASK                                         \
        | MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED                      \
        | MEMBARRIER_CMD_PRIVATE_EXPEDITED                              \
        | MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED                     \
-       | MEMBARRIER_PRIVATE_EXPEDITED_SYNC_CORE_BITMASK)
+       | MEMBARRIER_PRIVATE_EXPEDITED_SYNC_CORE_BITMASK                \
+       | MEMBARRIER_PRIVATE_EXPEDITED_RSEQ_BITMASK)
 
 static void ipi_mb(void *info)
 {
index e06071b..c336f5f 100644 (file)
@@ -37,9 +37,11 @@ update_irq_load_avg(struct rq *rq, u64 running)
 }
 #endif
 
+#define PELT_MIN_DIVIDER       (LOAD_AVG_MAX - 1024)
+
 static inline u32 get_pelt_divider(struct sched_avg *avg)
 {
-       return LOAD_AVG_MAX - 1024 + avg->period_contrib;
+       return PELT_MIN_DIVIDER + avg->period_contrib;
 }
 
 static inline void cfs_se_util_change(struct sched_avg *avg)
index a679613..e143581 100644 (file)
@@ -1082,44 +1082,6 @@ int psi_show(struct seq_file *m, struct psi_group *group, enum psi_res res)
        return 0;
 }
 
-static int psi_io_show(struct seq_file *m, void *v)
-{
-       return psi_show(m, &psi_system, PSI_IO);
-}
-
-static int psi_memory_show(struct seq_file *m, void *v)
-{
-       return psi_show(m, &psi_system, PSI_MEM);
-}
-
-static int psi_cpu_show(struct seq_file *m, void *v)
-{
-       return psi_show(m, &psi_system, PSI_CPU);
-}
-
-static int psi_open(struct file *file, int (*psi_show)(struct seq_file *, void *))
-{
-       if (file->f_mode & FMODE_WRITE && !capable(CAP_SYS_RESOURCE))
-               return -EPERM;
-
-       return single_open(file, psi_show, NULL);
-}
-
-static int psi_io_open(struct inode *inode, struct file *file)
-{
-       return psi_open(file, psi_io_show);
-}
-
-static int psi_memory_open(struct inode *inode, struct file *file)
-{
-       return psi_open(file, psi_memory_show);
-}
-
-static int psi_cpu_open(struct inode *inode, struct file *file)
-{
-       return psi_open(file, psi_cpu_show);
-}
-
 struct psi_trigger *psi_trigger_create(struct psi_group *group,
                        char *buf, size_t nbytes, enum psi_res res)
 {
@@ -1162,7 +1124,6 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group,
        t->event = 0;
        t->last_event_time = 0;
        init_waitqueue_head(&t->event_wait);
-       kref_init(&t->refcount);
 
        mutex_lock(&group->trigger_lock);
 
@@ -1191,15 +1152,19 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group,
        return t;
 }
 
-static void psi_trigger_destroy(struct kref *ref)
+void psi_trigger_destroy(struct psi_trigger *t)
 {
-       struct psi_trigger *t = container_of(ref, struct psi_trigger, refcount);
-       struct psi_group *group = t->group;
+       struct psi_group *group;
        struct task_struct *task_to_destroy = NULL;
 
-       if (static_branch_likely(&psi_disabled))
+       /*
+        * We do not check psi_disabled since it might have been disabled after
+        * the trigger got created.
+        */
+       if (!t)
                return;
 
+       group = t->group;
        /*
         * Wakeup waiters to stop polling. Can happen if cgroup is deleted
         * from under a polling process.
@@ -1235,9 +1200,9 @@ static void psi_trigger_destroy(struct kref *ref)
        mutex_unlock(&group->trigger_lock);
 
        /*
-        * Wait for both *trigger_ptr from psi_trigger_replace and
-        * poll_task RCUs to complete their read-side critical sections
-        * before destroying the trigger and optionally the poll_task
+        * Wait for psi_schedule_poll_work RCU to complete its read-side
+        * critical section before destroying the trigger and optionally the
+        * poll_task.
         */
        synchronize_rcu();
        /*
@@ -1254,18 +1219,6 @@ static void psi_trigger_destroy(struct kref *ref)
        kfree(t);
 }
 
-void psi_trigger_replace(void **trigger_ptr, struct psi_trigger *new)
-{
-       struct psi_trigger *old = *trigger_ptr;
-
-       if (static_branch_likely(&psi_disabled))
-               return;
-
-       rcu_assign_pointer(*trigger_ptr, new);
-       if (old)
-               kref_put(&old->refcount, psi_trigger_destroy);
-}
-
 __poll_t psi_trigger_poll(void **trigger_ptr,
                                struct file *file, poll_table *wait)
 {
@@ -1275,27 +1228,57 @@ __poll_t psi_trigger_poll(void **trigger_ptr,
        if (static_branch_likely(&psi_disabled))
                return DEFAULT_POLLMASK | EPOLLERR | EPOLLPRI;
 
-       rcu_read_lock();
-
-       t = rcu_dereference(*(void __rcu __force **)trigger_ptr);
-       if (!t) {
-               rcu_read_unlock();
+       t = smp_load_acquire(trigger_ptr);
+       if (!t)
                return DEFAULT_POLLMASK | EPOLLERR | EPOLLPRI;
-       }
-       kref_get(&t->refcount);
-
-       rcu_read_unlock();
 
        poll_wait(file, &t->event_wait, wait);
 
        if (cmpxchg(&t->event, 1, 0) == 1)
                ret |= EPOLLPRI;
 
-       kref_put(&t->refcount, psi_trigger_destroy);
-
        return ret;
 }
 
+#ifdef CONFIG_PROC_FS
+static int psi_io_show(struct seq_file *m, void *v)
+{
+       return psi_show(m, &psi_system, PSI_IO);
+}
+
+static int psi_memory_show(struct seq_file *m, void *v)
+{
+       return psi_show(m, &psi_system, PSI_MEM);
+}
+
+static int psi_cpu_show(struct seq_file *m, void *v)
+{
+       return psi_show(m, &psi_system, PSI_CPU);
+}
+
+static int psi_open(struct file *file, int (*psi_show)(struct seq_file *, void *))
+{
+       if (file->f_mode & FMODE_WRITE && !capable(CAP_SYS_RESOURCE))
+               return -EPERM;
+
+       return single_open(file, psi_show, NULL);
+}
+
+static int psi_io_open(struct inode *inode, struct file *file)
+{
+       return psi_open(file, psi_io_show);
+}
+
+static int psi_memory_open(struct inode *inode, struct file *file)
+{
+       return psi_open(file, psi_memory_show);
+}
+
+static int psi_cpu_open(struct inode *inode, struct file *file)
+{
+       return psi_open(file, psi_cpu_show);
+}
+
 static ssize_t psi_write(struct file *file, const char __user *user_buf,
                         size_t nbytes, enum psi_res res)
 {
@@ -1316,14 +1299,24 @@ static ssize_t psi_write(struct file *file, const char __user *user_buf,
 
        buf[buf_size - 1] = '\0';
 
-       new = psi_trigger_create(&psi_system, buf, nbytes, res);
-       if (IS_ERR(new))
-               return PTR_ERR(new);
-
        seq = file->private_data;
+
        /* Take seq->lock to protect seq->private from concurrent writes */
        mutex_lock(&seq->lock);
-       psi_trigger_replace(&seq->private, new);
+
+       /* Allow only one trigger per file descriptor */
+       if (seq->private) {
+               mutex_unlock(&seq->lock);
+               return -EBUSY;
+       }
+
+       new = psi_trigger_create(&psi_system, buf, nbytes, res);
+       if (IS_ERR(new)) {
+               mutex_unlock(&seq->lock);
+               return PTR_ERR(new);
+       }
+
+       smp_store_release(&seq->private, new);
        mutex_unlock(&seq->lock);
 
        return nbytes;
@@ -1358,7 +1351,7 @@ static int psi_fop_release(struct inode *inode, struct file *file)
 {
        struct seq_file *seq = file->private_data;
 
-       psi_trigger_replace(&seq->private, NULL);
+       psi_trigger_destroy(seq->private);
        return single_release(inode, file);
 }
 
@@ -1400,3 +1393,5 @@ static int __init psi_proc_init(void)
        return 0;
 }
 module_init(psi_proc_init);
+
+#endif /* CONFIG_PROC_FS */
index 4d8f44a..db10e73 100644 (file)
@@ -29,6 +29,9 @@
 #include <linux/syscalls.h>
 #include <linux/sysctl.h>
 
+/* Not exposed in headers: strictly internal use only. */
+#define SECCOMP_MODE_DEAD      (SECCOMP_MODE_FILTER + 1)
+
 #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
 #include <asm/syscall.h>
 #endif
@@ -1010,6 +1013,7 @@ static void __secure_computing_strict(int this_syscall)
 #ifdef SECCOMP_DEBUG
        dump_stack();
 #endif
+       current->seccomp.mode = SECCOMP_MODE_DEAD;
        seccomp_log(this_syscall, SIGKILL, SECCOMP_RET_KILL_THREAD, true);
        do_exit(SIGKILL);
 }
@@ -1261,6 +1265,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
        case SECCOMP_RET_KILL_THREAD:
        case SECCOMP_RET_KILL_PROCESS:
        default:
+               current->seccomp.mode = SECCOMP_MODE_DEAD;
                seccomp_log(this_syscall, SIGSYS, action, true);
                /* Dump core only if this is the last remaining thread. */
                if (action != SECCOMP_RET_KILL_THREAD ||
@@ -1309,6 +1314,11 @@ int __secure_computing(const struct seccomp_data *sd)
                return 0;
        case SECCOMP_MODE_FILTER:
                return __seccomp_filter(this_syscall, sd, false);
+       /* Surviving SECCOMP_RET_KILL_* must be proactively impossible. */
+       case SECCOMP_MODE_DEAD:
+               WARN_ON_ONCE(1);
+               do_exit(SIGKILL);
+               return -1;
        default:
                BUG();
        }
index 3860273..9b04631 100644 (file)
@@ -1342,9 +1342,10 @@ force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t,
        }
        /*
         * Don't clear SIGNAL_UNKILLABLE for traced tasks, users won't expect
-        * debugging to leave init killable.
+        * debugging to leave init killable. But HANDLER_EXIT is always fatal.
         */
-       if (action->sa.sa_handler == SIG_DFL && !t->ptrace)
+       if (action->sa.sa_handler == SIG_DFL &&
+           (!t->ptrace || (handler == HANDLER_EXIT)))
                t->signal->flags &= ~SIGNAL_UNKILLABLE;
        ret = send_signal(sig, info, t, PIDTYPE_PID);
        spin_unlock_irqrestore(&t->sighand->siglock, flags);
index 66b8af3..ddb5a7f 100644 (file)
@@ -70,7 +70,7 @@ late_initcall(stackleak_sysctls_init);
 #define skip_erasing() false
 #endif /* CONFIG_STACKLEAK_RUNTIME_DISABLE */
 
-asmlinkage void notrace stackleak_erase(void)
+asmlinkage void noinstr stackleak_erase(void)
 {
        /* It would be nice not to have 'kstack_ptr' and 'boundary' on stack */
        unsigned long kstack_ptr = current->lowest_stack;
@@ -124,9 +124,8 @@ asmlinkage void notrace stackleak_erase(void)
        /* Reset the 'lowest_stack' value for the next syscall */
        current->lowest_stack = current_top_of_stack() - THREAD_SIZE/64;
 }
-NOKPROBE_SYMBOL(stackleak_erase);
 
-void __used __no_caller_saved_registers notrace stackleak_track_stack(void)
+void __used __no_caller_saved_registers noinstr stackleak_track_stack(void)
 {
        unsigned long sp = current_stack_pointer;
 
index 752ed89..a5eb5e7 100644 (file)
@@ -70,10 +70,16 @@ config HAVE_C_RECORDMCOUNT
        help
          C version of recordmcount available?
 
+config HAVE_BUILDTIME_MCOUNT_SORT
+       bool
+       help
+         An architecture selects this if it sorts the mcount_loc section
+        at build time.
+
 config BUILDTIME_MCOUNT_SORT
        bool
        default y
-       depends on BUILDTIME_TABLE_SORT && !S390
+       depends on HAVE_BUILDTIME_MCOUNT_SORT && DYNAMIC_FTRACE
        help
          Sort the mcount_loc section at build time.
 
index a569a0c..7c2578e 100644 (file)
@@ -252,6 +252,10 @@ __setup("trace_clock=", set_trace_boot_clock);
 
 static int __init set_tracepoint_printk(char *str)
 {
+       /* Ignore the "tp_printk_stop_on_boot" param */
+       if (*str == '_')
+               return 0;
+
        if ((strcmp(str, "=0") != 0 && strcmp(str, "=off") != 0))
                tracepoint_printk = 1;
        return 1;
@@ -7740,7 +7744,8 @@ static struct tracing_log_err *get_tracing_log_err(struct trace_array *tr)
                err = kzalloc(sizeof(*err), GFP_KERNEL);
                if (!err)
                        err = ERR_PTR(-ENOMEM);
-               tr->n_err_log_entries++;
+               else
+                       tr->n_err_log_entries++;
 
                return err;
        }
index 5e6a988..ada87bf 100644 (file)
@@ -2503,6 +2503,8 @@ static struct hist_field *parse_unary(struct hist_trigger_data *hist_data,
                (HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS);
        expr->fn = hist_field_unary_minus;
        expr->operands[0] = operand1;
+       expr->size = operand1->size;
+       expr->is_signed = operand1->is_signed;
        expr->operator = FIELD_OP_UNARY_MINUS;
        expr->name = expr_str(expr, 0);
        expr->type = kstrdup_const(operand1->type, GFP_KERNEL);
@@ -2719,6 +2721,7 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
 
                /* The operand sizes should be the same, so just pick one */
                expr->size = operand1->size;
+               expr->is_signed = operand1->is_signed;
 
                expr->operator = field_op;
                expr->type = kstrdup_const(operand1->type, GFP_KERNEL);
@@ -3935,6 +3938,7 @@ static int trace_action_create(struct hist_trigger_data *hist_data,
 
                        var_ref_idx = find_var_ref_idx(hist_data, var_ref);
                        if (WARN_ON(var_ref_idx < 0)) {
+                               kfree(p);
                                ret = var_ref_idx;
                                goto err;
                        }
@@ -6163,7 +6167,9 @@ static int event_hist_trigger_parse(struct event_command *cmd_ops,
 
        lockdep_assert_held(&event_mutex);
 
-       if (glob && strlen(glob)) {
+       WARN_ON(!glob);
+
+       if (strlen(glob)) {
                hist_err_clear();
                last_cmd_set(file, param);
        }
@@ -6196,7 +6202,7 @@ static int event_hist_trigger_parse(struct event_command *cmd_ops,
                        continue;
                }
                break;
-       } while (p);
+       } while (1);
 
        if (!p)
                param = NULL;
index 7b32c35..65b5974 100644 (file)
@@ -190,6 +190,7 @@ struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid)
                        kfree(new);
                } else {
                        hlist_add_head(&new->node, hashent);
+                       get_user_ns(new->ns);
                        spin_unlock_irq(&ucounts_lock);
                        return new;
                }
@@ -210,6 +211,7 @@ void put_ucounts(struct ucounts *ucounts)
        if (atomic_dec_and_lock_irqsave(&ucounts->count, &ucounts_lock, flags)) {
                hlist_del_init(&ucounts->node);
                spin_unlock_irqrestore(&ucounts_lock, flags);
+               put_user_ns(ucounts->ns);
                kfree(ucounts);
        }
 }
index 9364f79..c71c096 100644 (file)
 
 void blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen)
 {
-       __blake2s_update(state, in, inlen, blake2s_compress);
+       __blake2s_update(state, in, inlen, false);
 }
 EXPORT_SYMBOL(blake2s_update);
 
 void blake2s_final(struct blake2s_state *state, u8 *out)
 {
        WARN_ON(IS_ENABLED(DEBUG) && !out);
-       __blake2s_final(state, out, blake2s_compress);
+       __blake2s_final(state, out, false);
        memzero_explicit(state, sizeof(*state));
 }
 EXPORT_SYMBOL(blake2s_final);
index 6220fa6..09d293c 100644 (file)
@@ -488,9 +488,13 @@ void sbitmap_queue_recalculate_wake_batch(struct sbitmap_queue *sbq,
                                            unsigned int users)
 {
        unsigned int wake_batch;
+       unsigned int min_batch;
+       unsigned int depth = (sbq->sb.depth + users - 1) / users;
 
-       wake_batch = clamp_val((sbq->sb.depth + users - 1) /
-                       users, 4, SBQ_WAKE_BATCH);
+       min_batch = sbq->sb.depth >= (4 * SBQ_WAIT_QUEUES) ? 4 : 1;
+
+       wake_batch = clamp_val(depth / SBQ_WAIT_QUEUES,
+                       min_batch, SBQ_WAKE_BATCH);
        __sbitmap_queue_update_wake_batch(sbq, wake_batch);
 }
 EXPORT_SYMBOL_GPL(sbitmap_queue_recalculate_wake_batch);
index 847cdbe..26a5c90 100644 (file)
@@ -492,6 +492,7 @@ static void kmalloc_oob_in_memset(struct kunit *test)
        ptr = kmalloc(size, GFP_KERNEL);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
 
+       OPTIMIZER_HIDE_VAR(ptr);
        OPTIMIZER_HIDE_VAR(size);
        KUNIT_EXPECT_KASAN_FAIL(test,
                                memset(ptr, 0, size + KASAN_GRANULE_SIZE));
@@ -515,6 +516,7 @@ static void kmalloc_memmove_negative_size(struct kunit *test)
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
 
        memset((char *)ptr, 0, 64);
+       OPTIMIZER_HIDE_VAR(ptr);
        OPTIMIZER_HIDE_VAR(invalid_size);
        KUNIT_EXPECT_KASAN_FAIL(test,
                memmove((char *)ptr, (char *)ptr + 4, invalid_size));
@@ -531,6 +533,7 @@ static void kmalloc_memmove_invalid_size(struct kunit *test)
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
 
        memset((char *)ptr, 0, 64);
+       OPTIMIZER_HIDE_VAR(ptr);
        KUNIT_EXPECT_KASAN_FAIL(test,
                memmove((char *)ptr, (char *)ptr + 4, invalid_size));
        kfree(ptr);
@@ -893,6 +896,7 @@ static void kasan_memchr(struct kunit *test)
        ptr = kmalloc(size, GFP_KERNEL | __GFP_ZERO);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
 
+       OPTIMIZER_HIDE_VAR(ptr);
        OPTIMIZER_HIDE_VAR(size);
        KUNIT_EXPECT_KASAN_FAIL(test,
                kasan_ptr_result = memchr(ptr, '1', size + 1));
@@ -919,6 +923,7 @@ static void kasan_memcmp(struct kunit *test)
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
        memset(arr, 0, sizeof(arr));
 
+       OPTIMIZER_HIDE_VAR(ptr);
        OPTIMIZER_HIDE_VAR(size);
        KUNIT_EXPECT_KASAN_FAIL(test,
                kasan_int_result = memcmp(ptr, arr, size+1));
index a7ac97c..db2abd9 100644 (file)
@@ -171,6 +171,8 @@ static void __init pte_advanced_tests(struct pgtable_debug_args *args)
        ptep_test_and_clear_young(args->vma, args->vaddr, args->ptep);
        pte = ptep_get(args->ptep);
        WARN_ON(pte_young(pte));
+
+       ptep_get_and_clear_full(args->mm, args->vaddr, args->ptep, 1);
 }
 
 static void __init pte_savedwrite_tests(struct pgtable_debug_args *args)
index f0af462..a9d4d72 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -124,8 +124,8 @@ static inline struct page *try_get_compound_head(struct page *page, int refs)
  * considered failure, and furthermore, a likely bug in the caller, so a warning
  * is also emitted.
  */
-struct page *try_grab_compound_head(struct page *page,
-                                   int refs, unsigned int flags)
+__maybe_unused struct page *try_grab_compound_head(struct page *page,
+                                                  int refs, unsigned int flags)
 {
        if (flags & FOLL_GET)
                return try_get_compound_head(page, refs);
@@ -208,10 +208,35 @@ static void put_compound_head(struct page *page, int refs, unsigned int flags)
  */
 bool __must_check try_grab_page(struct page *page, unsigned int flags)
 {
-       if (!(flags & (FOLL_GET | FOLL_PIN)))
-               return true;
+       WARN_ON_ONCE((flags & (FOLL_GET | FOLL_PIN)) == (FOLL_GET | FOLL_PIN));
 
-       return try_grab_compound_head(page, 1, flags);
+       if (flags & FOLL_GET)
+               return try_get_page(page);
+       else if (flags & FOLL_PIN) {
+               int refs = 1;
+
+               page = compound_head(page);
+
+               if (WARN_ON_ONCE(page_ref_count(page) <= 0))
+                       return false;
+
+               if (hpage_pincount_available(page))
+                       hpage_pincount_add(page, 1);
+               else
+                       refs = GUP_PIN_COUNTING_BIAS;
+
+               /*
+                * Similar to try_grab_compound_head(): even if using the
+                * hpage_pincount_add/_sub() routines, be sure to
+                * *also* increment the normal page refcount field at least
+                * once, so that the page really is pinned.
+                */
+               page_ref_add(page, refs);
+
+               mod_node_page_state(page_pgdat(page), NR_FOLL_PIN_ACQUIRED, 1);
+       }
+
+       return true;
 }
 
 /**
index 5ad40e3..13128fa 100644 (file)
@@ -47,7 +47,8 @@
 
 static bool kfence_enabled __read_mostly;
 
-static unsigned long kfence_sample_interval __read_mostly = CONFIG_KFENCE_SAMPLE_INTERVAL;
+unsigned long kfence_sample_interval __read_mostly = CONFIG_KFENCE_SAMPLE_INTERVAL;
+EXPORT_SYMBOL_GPL(kfence_sample_interval); /* Export for test modules. */
 
 #ifdef MODULE_PARAM_PREFIX
 #undef MODULE_PARAM_PREFIX
index a22b1af..50dbb81 100644 (file)
@@ -268,13 +268,13 @@ static void *test_alloc(struct kunit *test, size_t size, gfp_t gfp, enum allocat
         * 100x the sample interval should be more than enough to ensure we get
         * a KFENCE allocation eventually.
         */
-       timeout = jiffies + msecs_to_jiffies(100 * CONFIG_KFENCE_SAMPLE_INTERVAL);
+       timeout = jiffies + msecs_to_jiffies(100 * kfence_sample_interval);
        /*
         * Especially for non-preemption kernels, ensure the allocation-gate
         * timer can catch up: after @resched_after, every failed allocation
         * attempt yields, to ensure the allocation-gate timer is scheduled.
         */
-       resched_after = jiffies + msecs_to_jiffies(CONFIG_KFENCE_SAMPLE_INTERVAL);
+       resched_after = jiffies + msecs_to_jiffies(kfence_sample_interval);
        do {
                if (test_cache)
                        alloc = kmem_cache_alloc(test_cache, gfp);
@@ -608,7 +608,7 @@ static void test_gfpzero(struct kunit *test)
        int i;
 
        /* Skip if we think it'd take too long. */
-       KFENCE_TEST_REQUIRES(test, CONFIG_KFENCE_SAMPLE_INTERVAL <= 100);
+       KFENCE_TEST_REQUIRES(test, kfence_sample_interval <= 100);
 
        setup_test_cache(test, size, 0, NULL);
        buf1 = test_alloc(test, size, GFP_KERNEL, ALLOCATE_ANY);
@@ -739,7 +739,7 @@ static void test_memcache_alloc_bulk(struct kunit *test)
         * 100x the sample interval should be more than enough to ensure we get
         * a KFENCE allocation eventually.
         */
-       timeout = jiffies + msecs_to_jiffies(100 * CONFIG_KFENCE_SAMPLE_INTERVAL);
+       timeout = jiffies + msecs_to_jiffies(100 * kfence_sample_interval);
        do {
                void *objects[100];
                int i, num = kmem_cache_alloc_bulk(test_cache, GFP_ATOMIC, ARRAY_SIZE(objects),
index 35f14d0..131492f 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/hashtable.h>
 #include <linux/userfaultfd_k.h>
 #include <linux/page_idle.h>
+#include <linux/page_table_check.h>
 #include <linux/swapops.h>
 #include <linux/shmem_fs.h>
 
@@ -1416,6 +1417,21 @@ static int khugepaged_add_pte_mapped_thp(struct mm_struct *mm,
        return 0;
 }
 
+static void collapse_and_free_pmd(struct mm_struct *mm, struct vm_area_struct *vma,
+                                 unsigned long addr, pmd_t *pmdp)
+{
+       spinlock_t *ptl;
+       pmd_t pmd;
+
+       mmap_assert_write_locked(mm);
+       ptl = pmd_lock(vma->vm_mm, pmdp);
+       pmd = pmdp_collapse_flush(vma, addr, pmdp);
+       spin_unlock(ptl);
+       mm_dec_nr_ptes(mm);
+       page_table_check_pte_clear_range(mm, addr, pmd);
+       pte_free(mm, pmd_pgtable(pmd));
+}
+
 /**
  * collapse_pte_mapped_thp - Try to collapse a pte-mapped THP for mm at
  * address haddr.
@@ -1433,7 +1449,7 @@ void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr)
        struct vm_area_struct *vma = find_vma(mm, haddr);
        struct page *hpage;
        pte_t *start_pte, *pte;
-       pmd_t *pmd, _pmd;
+       pmd_t *pmd;
        spinlock_t *ptl;
        int count = 0;
        int i;
@@ -1509,12 +1525,7 @@ void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr)
        }
 
        /* step 4: collapse pmd */
-       ptl = pmd_lock(vma->vm_mm, pmd);
-       _pmd = pmdp_collapse_flush(vma, haddr, pmd);
-       spin_unlock(ptl);
-       mm_dec_nr_ptes(mm);
-       pte_free(mm, pmd_pgtable(_pmd));
-
+       collapse_and_free_pmd(mm, vma, haddr, pmd);
 drop_hpage:
        unlock_page(hpage);
        put_page(hpage);
@@ -1552,7 +1563,7 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
        struct vm_area_struct *vma;
        struct mm_struct *mm;
        unsigned long addr;
-       pmd_t *pmd, _pmd;
+       pmd_t *pmd;
 
        i_mmap_lock_write(mapping);
        vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
@@ -1591,14 +1602,8 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
                 * reverse order. Trylock is a way to avoid deadlock.
                 */
                if (mmap_write_trylock(mm)) {
-                       if (!khugepaged_test_exit(mm)) {
-                               spinlock_t *ptl = pmd_lock(mm, pmd);
-                               /* assume page table is clear */
-                               _pmd = pmdp_collapse_flush(vma, addr, pmd);
-                               spin_unlock(ptl);
-                               mm_dec_nr_ptes(mm);
-                               pte_free(mm, pmd_pgtable(_pmd));
-                       }
+                       if (!khugepaged_test_exit(mm))
+                               collapse_and_free_pmd(mm, vma, addr, pmd);
                        mmap_write_unlock(mm);
                } else {
                        /* Try again later */
index dc3758f..7580baa 100644 (file)
@@ -1410,7 +1410,8 @@ static void kmemleak_scan(void)
 {
        unsigned long flags;
        struct kmemleak_object *object;
-       int i;
+       struct zone *zone;
+       int __maybe_unused i;
        int new_leaks = 0;
 
        jiffies_last_scan = jiffies;
@@ -1450,9 +1451,9 @@ static void kmemleak_scan(void)
         * Struct page scanning for each node.
         */
        get_online_mems();
-       for_each_online_node(i) {
-               unsigned long start_pfn = node_start_pfn(i);
-               unsigned long end_pfn = node_end_pfn(i);
+       for_each_populated_zone(zone) {
+               unsigned long start_pfn = zone->zone_start_pfn;
+               unsigned long end_pfn = zone_end_pfn(zone);
                unsigned long pfn;
 
                for (pfn = start_pfn; pfn < end_pfn; pfn++) {
@@ -1461,8 +1462,8 @@ static void kmemleak_scan(void)
                        if (!page)
                                continue;
 
-                       /* only scan pages belonging to this node */
-                       if (page_to_nid(page) != i)
+                       /* only scan pages belonging to this zone */
+                       if (page_zone(page) != zone)
                                continue;
                        /* only scan if page is in use */
                        if (page_count(page) == 0)
index 09d342c..36e9f38 100644 (file)
@@ -254,7 +254,7 @@ struct mem_cgroup *vmpressure_to_memcg(struct vmpressure *vmpr)
 }
 
 #ifdef CONFIG_MEMCG_KMEM
-extern spinlock_t css_set_lock;
+static DEFINE_SPINLOCK(objcg_lock);
 
 bool mem_cgroup_kmem_disabled(void)
 {
@@ -298,9 +298,9 @@ static void obj_cgroup_release(struct percpu_ref *ref)
        if (nr_pages)
                obj_cgroup_uncharge_pages(objcg, nr_pages);
 
-       spin_lock_irqsave(&css_set_lock, flags);
+       spin_lock_irqsave(&objcg_lock, flags);
        list_del(&objcg->list);
-       spin_unlock_irqrestore(&css_set_lock, flags);
+       spin_unlock_irqrestore(&objcg_lock, flags);
 
        percpu_ref_exit(ref);
        kfree_rcu(objcg, rcu);
@@ -332,7 +332,7 @@ static void memcg_reparent_objcgs(struct mem_cgroup *memcg,
 
        objcg = rcu_replace_pointer(memcg->objcg, NULL, true);
 
-       spin_lock_irq(&css_set_lock);
+       spin_lock_irq(&objcg_lock);
 
        /* 1) Ready to reparent active objcg. */
        list_add(&objcg->list, &memcg->objcg_list);
@@ -342,7 +342,7 @@ static void memcg_reparent_objcgs(struct mem_cgroup *memcg,
        /* 3) Move already reparented objcgs to the parent's list */
        list_splice(&memcg->objcg_list, &parent->objcg_list);
 
-       spin_unlock_irq(&css_set_lock);
+       spin_unlock_irq(&objcg_lock);
 
        percpu_ref_kill(&objcg->refcnt);
 }
index 14ae5c1..97a9ed8 100644 (file)
@@ -1595,6 +1595,12 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
                goto out;
        }
 
+       /*
+        * Pages instantiated by device-dax (not filesystem-dax)
+        * may be compound pages.
+        */
+       page = compound_head(page);
+
        /*
         * Prevent the inode from being freed while we are interrogating
         * the address_space, typically this would be handled by
index 6a0ddda..f67c4c7 100644 (file)
@@ -115,7 +115,7 @@ static void unset_migratetype_isolate(struct page *page, unsigned migratetype)
         * onlining - just onlined memory won't immediately be considered for
         * allocation.
         */
-       if (!isolated_page && PageBuddy(page)) {
+       if (!isolated_page) {
                nr_pages = move_freepages_block(zone, page, migratetype, NULL);
                __mod_zone_freepage_state(zone, nr_pages, migratetype);
        }
index 7504e7c..3763bd0 100644 (file)
@@ -86,8 +86,8 @@ static void page_table_check_clear(struct mm_struct *mm, unsigned long addr,
 {
        struct page_ext *page_ext;
        struct page *page;
+       unsigned long i;
        bool anon;
-       int i;
 
        if (!pfn_valid(pfn))
                return;
@@ -121,8 +121,8 @@ static void page_table_check_set(struct mm_struct *mm, unsigned long addr,
 {
        struct page_ext *page_ext;
        struct page *page;
+       unsigned long i;
        bool anon;
-       int i;
 
        if (!pfn_valid(pfn))
                return;
@@ -152,10 +152,10 @@ static void page_table_check_set(struct mm_struct *mm, unsigned long addr,
 void __page_table_check_zero(struct page *page, unsigned int order)
 {
        struct page_ext *page_ext = lookup_page_ext(page);
-       int i;
+       unsigned long i;
 
        BUG_ON(!page_ext);
-       for (i = 0; i < (1 << order); i++) {
+       for (i = 0; i < (1ul << order); i++) {
                struct page_table_check *ptc = get_page_table_check(page_ext);
 
                BUG_ON(atomic_read(&ptc->anon_map_count));
@@ -206,17 +206,10 @@ EXPORT_SYMBOL(__page_table_check_pud_clear);
 void __page_table_check_pte_set(struct mm_struct *mm, unsigned long addr,
                                pte_t *ptep, pte_t pte)
 {
-       pte_t old_pte;
-
        if (&init_mm == mm)
                return;
 
-       old_pte = *ptep;
-       if (pte_user_accessible_page(old_pte)) {
-               page_table_check_clear(mm, addr, pte_pfn(old_pte),
-                                      PAGE_SIZE >> PAGE_SHIFT);
-       }
-
+       __page_table_check_pte_clear(mm, addr, *ptep);
        if (pte_user_accessible_page(pte)) {
                page_table_check_set(mm, addr, pte_pfn(pte),
                                     PAGE_SIZE >> PAGE_SHIFT,
@@ -228,17 +221,10 @@ EXPORT_SYMBOL(__page_table_check_pte_set);
 void __page_table_check_pmd_set(struct mm_struct *mm, unsigned long addr,
                                pmd_t *pmdp, pmd_t pmd)
 {
-       pmd_t old_pmd;
-
        if (&init_mm == mm)
                return;
 
-       old_pmd = *pmdp;
-       if (pmd_user_accessible_page(old_pmd)) {
-               page_table_check_clear(mm, addr, pmd_pfn(old_pmd),
-                                      PMD_PAGE_SIZE >> PAGE_SHIFT);
-       }
-
+       __page_table_check_pmd_clear(mm, addr, *pmdp);
        if (pmd_user_accessible_page(pmd)) {
                page_table_check_set(mm, addr, pmd_pfn(pmd),
                                     PMD_PAGE_SIZE >> PAGE_SHIFT,
@@ -250,17 +236,10 @@ EXPORT_SYMBOL(__page_table_check_pmd_set);
 void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
                                pud_t *pudp, pud_t pud)
 {
-       pud_t old_pud;
-
        if (&init_mm == mm)
                return;
 
-       old_pud = *pudp;
-       if (pud_user_accessible_page(old_pud)) {
-               page_table_check_clear(mm, addr, pud_pfn(old_pud),
-                                      PUD_PAGE_SIZE >> PAGE_SHIFT);
-       }
-
+       __page_table_check_pud_clear(mm, addr, *pudp);
        if (pud_user_accessible_page(pud)) {
                page_table_check_set(mm, addr, pud_pfn(pud),
                                     PUD_PAGE_SIZE >> PAGE_SHIFT,
@@ -268,3 +247,23 @@ void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
        }
 }
 EXPORT_SYMBOL(__page_table_check_pud_set);
+
+void __page_table_check_pte_clear_range(struct mm_struct *mm,
+                                       unsigned long addr,
+                                       pmd_t pmd)
+{
+       if (&init_mm == mm)
+               return;
+
+       if (!pmd_bad(pmd) && !pmd_leaf(pmd)) {
+               pte_t *ptep = pte_offset_map(&pmd, addr);
+               unsigned long i;
+
+               pte_unmap(ptep);
+               for (i = 0; i < PTRS_PER_PTE; i++) {
+                       __page_table_check_pte_clear(mm, addr, *ptep);
+                       addr += PAGE_SIZE;
+                       ptep++;
+               }
+       }
+}
index 090bfb6..59b14e0 100644 (file)
@@ -1066,8 +1066,10 @@ void reclaim_throttle(pg_data_t *pgdat, enum vmscan_throttle_state reason)
         * forward progress (e.g. journalling workqueues or kthreads).
         */
        if (!current_is_kswapd() &&
-           current->flags & (PF_IO_WORKER|PF_KTHREAD))
+           current->flags & (PF_IO_WORKER|PF_KTHREAD)) {
+               cond_resched();
                return;
+       }
 
        /*
         * These figures are pulled out of thin air.
index 1a705a4..5eaf388 100644 (file)
@@ -129,6 +129,7 @@ void vlan_dev_set_ingress_priority(const struct net_device *dev,
                                   u32 skb_prio, u16 vlan_prio);
 int vlan_dev_set_egress_priority(const struct net_device *dev,
                                 u32 skb_prio, u16 vlan_prio);
+void vlan_dev_free_egress_priority(const struct net_device *dev);
 int vlan_dev_change_flags(const struct net_device *dev, u32 flag, u32 mask);
 void vlan_dev_get_realdev_name(const struct net_device *dev, char *result,
                               size_t size);
@@ -139,7 +140,6 @@ int vlan_check_real_dev(struct net_device *real_dev,
 void vlan_setup(struct net_device *dev);
 int register_vlan_dev(struct net_device *dev, struct netlink_ext_ack *extack);
 void unregister_vlan_dev(struct net_device *dev, struct list_head *head);
-void vlan_dev_uninit(struct net_device *dev);
 bool vlan_dev_inherit_address(struct net_device *dev,
                              struct net_device *real_dev);
 
index 26d031a..d190282 100644 (file)
@@ -622,7 +622,7 @@ static int vlan_dev_init(struct net_device *dev)
 }
 
 /* Note: this function might be called multiple times for the same device. */
-void vlan_dev_uninit(struct net_device *dev)
+void vlan_dev_free_egress_priority(const struct net_device *dev)
 {
        struct vlan_priority_tci_mapping *pm;
        struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
@@ -636,6 +636,16 @@ void vlan_dev_uninit(struct net_device *dev)
        }
 }
 
+static void vlan_dev_uninit(struct net_device *dev)
+{
+       struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
+
+       vlan_dev_free_egress_priority(dev);
+
+       /* Get rid of the vlan's reference to real_dev */
+       dev_put_track(vlan->real_dev, &vlan->dev_tracker);
+}
+
 static netdev_features_t vlan_dev_fix_features(struct net_device *dev,
        netdev_features_t features)
 {
@@ -846,9 +856,6 @@ static void vlan_dev_free(struct net_device *dev)
 
        free_percpu(vlan->vlan_pcpu_stats);
        vlan->vlan_pcpu_stats = NULL;
-
-       /* Get rid of the vlan's reference to real_dev */
-       dev_put_track(vlan->real_dev, &vlan->dev_tracker);
 }
 
 void vlan_setup(struct net_device *dev)
index 0db85ae..53b1955 100644 (file)
@@ -183,10 +183,11 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,
                return -EINVAL;
 
        err = vlan_changelink(dev, tb, data, extack);
-       if (!err)
-               err = register_vlan_dev(dev, extack);
        if (err)
-               vlan_dev_uninit(dev);
+               return err;
+       err = register_vlan_dev(dev, extack);
+       if (err)
+               vlan_dev_free_egress_priority(dev);
        return err;
 }
 
index 02f43f3..d53cbb4 100644 (file)
@@ -77,6 +77,7 @@ static void ax25_kill_by_device(struct net_device *dev)
 {
        ax25_dev *ax25_dev;
        ax25_cb *s;
+       struct sock *sk;
 
        if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
                return;
@@ -85,13 +86,17 @@ static void ax25_kill_by_device(struct net_device *dev)
 again:
        ax25_for_each(s, &ax25_list) {
                if (s->ax25_dev == ax25_dev) {
+                       sk = s->sk;
+                       sock_hold(sk);
                        spin_unlock_bh(&ax25_list_lock);
-                       lock_sock(s->sk);
+                       lock_sock(sk);
                        s->ax25_dev = NULL;
-                       release_sock(s->sk);
+                       dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
+                       ax25_dev_put(ax25_dev);
                        ax25_disconnect(s, ENETUNREACH);
+                       release_sock(sk);
                        spin_lock_bh(&ax25_list_lock);
-
+                       sock_put(sk);
                        /* The entry could have been deleted from the
                         * list meanwhile and thus the next pointer is
                         * no longer valid.  Play it safe and restart
@@ -355,21 +360,25 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg)
        if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl)))
                return -EFAULT;
 
-       if ((ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr)) == NULL)
-               return -ENODEV;
-
        if (ax25_ctl.digi_count > AX25_MAX_DIGIS)
                return -EINVAL;
 
        if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL)
                return -EINVAL;
 
+       ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr);
+       if (!ax25_dev)
+               return -ENODEV;
+
        digi.ndigi = ax25_ctl.digi_count;
        for (k = 0; k < digi.ndigi; k++)
                digi.calls[k] = ax25_ctl.digi_addr[k];
 
-       if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev)) == NULL)
+       ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev);
+       if (!ax25) {
+               ax25_dev_put(ax25_dev);
                return -ENOTCONN;
+       }
 
        switch (ax25_ctl.cmd) {
        case AX25_KILL:
@@ -436,6 +445,7 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg)
          }
 
 out_put:
+       ax25_dev_put(ax25_dev);
        ax25_cb_put(ax25);
        return ret;
 
@@ -1107,8 +1117,10 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                }
        }
 
-       if (ax25_dev != NULL)
+       if (ax25_dev) {
                ax25_fillin_cb(ax25, ax25_dev);
+               dev_hold_track(ax25_dev->dev, &ax25_dev->dev_tracker, GFP_ATOMIC);
+       }
 
 done:
        ax25_cb_add(ax25);
index 256fadb..d2a244e 100644 (file)
@@ -37,6 +37,7 @@ ax25_dev *ax25_addr_ax25dev(ax25_address *addr)
        for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
                if (ax25cmp(addr, (const ax25_address *)ax25_dev->dev->dev_addr) == 0) {
                        res = ax25_dev;
+                       ax25_dev_hold(ax25_dev);
                }
        spin_unlock_bh(&ax25_dev_lock);
 
@@ -56,6 +57,7 @@ void ax25_dev_device_up(struct net_device *dev)
                return;
        }
 
+       refcount_set(&ax25_dev->refcount, 1);
        dev->ax25_ptr     = ax25_dev;
        ax25_dev->dev     = dev;
        dev_hold_track(dev, &ax25_dev->dev_tracker, GFP_ATOMIC);
@@ -84,6 +86,7 @@ void ax25_dev_device_up(struct net_device *dev)
        ax25_dev->next = ax25_dev_list;
        ax25_dev_list  = ax25_dev;
        spin_unlock_bh(&ax25_dev_lock);
+       ax25_dev_hold(ax25_dev);
 
        ax25_register_dev_sysctl(ax25_dev);
 }
@@ -113,9 +116,10 @@ void ax25_dev_device_down(struct net_device *dev)
        if ((s = ax25_dev_list) == ax25_dev) {
                ax25_dev_list = s->next;
                spin_unlock_bh(&ax25_dev_lock);
+               ax25_dev_put(ax25_dev);
                dev->ax25_ptr = NULL;
                dev_put_track(dev, &ax25_dev->dev_tracker);
-               kfree(ax25_dev);
+               ax25_dev_put(ax25_dev);
                return;
        }
 
@@ -123,9 +127,10 @@ void ax25_dev_device_down(struct net_device *dev)
                if (s->next == ax25_dev) {
                        s->next = ax25_dev->next;
                        spin_unlock_bh(&ax25_dev_lock);
+                       ax25_dev_put(ax25_dev);
                        dev->ax25_ptr = NULL;
                        dev_put_track(dev, &ax25_dev->dev_tracker);
-                       kfree(ax25_dev);
+                       ax25_dev_put(ax25_dev);
                        return;
                }
 
@@ -133,6 +138,7 @@ void ax25_dev_device_down(struct net_device *dev)
        }
        spin_unlock_bh(&ax25_dev_lock);
        dev->ax25_ptr = NULL;
+       ax25_dev_put(ax25_dev);
 }
 
 int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
@@ -144,20 +150,32 @@ int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
 
        switch (cmd) {
        case SIOCAX25ADDFWD:
-               if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL)
+               fwd_dev = ax25_addr_ax25dev(&fwd->port_to);
+               if (!fwd_dev) {
+                       ax25_dev_put(ax25_dev);
                        return -EINVAL;
-               if (ax25_dev->forward != NULL)
+               }
+               if (ax25_dev->forward) {
+                       ax25_dev_put(fwd_dev);
+                       ax25_dev_put(ax25_dev);
                        return -EINVAL;
+               }
                ax25_dev->forward = fwd_dev->dev;
+               ax25_dev_put(fwd_dev);
+               ax25_dev_put(ax25_dev);
                break;
 
        case SIOCAX25DELFWD:
-               if (ax25_dev->forward == NULL)
+               if (!ax25_dev->forward) {
+                       ax25_dev_put(ax25_dev);
                        return -EINVAL;
+               }
                ax25_dev->forward = NULL;
+               ax25_dev_put(ax25_dev);
                break;
 
        default:
+               ax25_dev_put(ax25_dev);
                return -EINVAL;
        }
 
index d0b2e09..9751207 100644 (file)
@@ -75,11 +75,13 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
        ax25_dev *ax25_dev;
        int i;
 
-       if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
-               return -EINVAL;
        if (route->digi_count > AX25_MAX_DIGIS)
                return -EINVAL;
 
+       ax25_dev = ax25_addr_ax25dev(&route->port_addr);
+       if (!ax25_dev)
+               return -EINVAL;
+
        write_lock_bh(&ax25_route_lock);
 
        ax25_rt = ax25_route_list;
@@ -91,6 +93,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
                        if (route->digi_count != 0) {
                                if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
                                        write_unlock_bh(&ax25_route_lock);
+                                       ax25_dev_put(ax25_dev);
                                        return -ENOMEM;
                                }
                                ax25_rt->digipeat->lastrepeat = -1;
@@ -101,6 +104,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
                                }
                        }
                        write_unlock_bh(&ax25_route_lock);
+                       ax25_dev_put(ax25_dev);
                        return 0;
                }
                ax25_rt = ax25_rt->next;
@@ -108,6 +112,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
 
        if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
                write_unlock_bh(&ax25_route_lock);
+               ax25_dev_put(ax25_dev);
                return -ENOMEM;
        }
 
@@ -120,6 +125,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
                if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
                        write_unlock_bh(&ax25_route_lock);
                        kfree(ax25_rt);
+                       ax25_dev_put(ax25_dev);
                        return -ENOMEM;
                }
                ax25_rt->digipeat->lastrepeat = -1;
@@ -132,6 +138,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
        ax25_rt->next   = ax25_route_list;
        ax25_route_list = ax25_rt;
        write_unlock_bh(&ax25_route_lock);
+       ax25_dev_put(ax25_dev);
 
        return 0;
 }
@@ -173,6 +180,7 @@ static int ax25_rt_del(struct ax25_routes_struct *route)
                }
        }
        write_unlock_bh(&ax25_route_lock);
+       ax25_dev_put(ax25_dev);
 
        return 0;
 }
@@ -215,6 +223,7 @@ static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
 
 out:
        write_unlock_bh(&ax25_route_lock);
+       ax25_dev_put(ax25_dev);
        return err;
 }
 
index 84ba456..1402d5c 100644 (file)
@@ -560,10 +560,10 @@ static bool __allowed_ingress(const struct net_bridge *br,
                    !br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) {
                        if (*state == BR_STATE_FORWARDING) {
                                *state = br_vlan_get_pvid_state(vg);
-                               return br_vlan_state_allowed(*state, true);
-                       } else {
-                               return true;
+                               if (!br_vlan_state_allowed(*state, true))
+                                       goto drop;
                        }
+                       return true;
                }
        }
        v = br_vlan_find(vg, *vid);
@@ -2020,7 +2020,8 @@ static int br_vlan_rtm_dump(struct sk_buff *skb, struct netlink_callback *cb)
                        goto out_err;
                }
                err = br_vlan_dump_dev(dev, skb, cb, dump_flags);
-               if (err && err != -EMSGSIZE)
+               /* if the dump completed without an error we return 0 here */
+               if (err != -EMSGSIZE)
                        goto out_err;
        } else {
                for_each_netdev_rcu(net, dev) {
index eba0efe..fbf858d 100644 (file)
@@ -49,7 +49,7 @@ static void nft_reject_br_send_v4_tcp_reset(struct net *net,
 {
        struct sk_buff *nskb;
 
-       nskb = nf_reject_skb_v4_tcp_reset(net, oldskb, dev, hook);
+       nskb = nf_reject_skb_v4_tcp_reset(net, oldskb, NULL, hook);
        if (!nskb)
                return;
 
@@ -65,7 +65,7 @@ static void nft_reject_br_send_v4_unreach(struct net *net,
 {
        struct sk_buff *nskb;
 
-       nskb = nf_reject_skb_v4_unreach(net, oldskb, dev, hook, code);
+       nskb = nf_reject_skb_v4_unreach(net, oldskb, NULL, hook, code);
        if (!nskb)
                return;
 
@@ -81,7 +81,7 @@ static void nft_reject_br_send_v6_tcp_reset(struct net *net,
 {
        struct sk_buff *nskb;
 
-       nskb = nf_reject_skb_v6_tcp_reset(net, oldskb, dev, hook);
+       nskb = nf_reject_skb_v6_tcp_reset(net, oldskb, NULL, hook);
        if (!nskb)
                return;
 
@@ -98,7 +98,7 @@ static void nft_reject_br_send_v6_unreach(struct net *net,
 {
        struct sk_buff *nskb;
 
-       nskb = nf_reject_skb_v6_unreach(net, oldskb, dev, hook, code);
+       nskb = nf_reject_skb_v6_unreach(net, oldskb, NULL, hook, code);
        if (!nskb)
                return;
 
index 02cbcb2..d2a430b 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/spinlock.h>
 #include <linux/hrtimer.h>
 #include <linux/wait.h>
 #include <linux/uio.h>
@@ -145,6 +146,7 @@ struct isotp_sock {
        struct tpcon rx, tx;
        struct list_head notifier;
        wait_queue_head_t wait;
+       spinlock_t rx_lock; /* protect single thread state machine */
 };
 
 static LIST_HEAD(isotp_notifier_list);
@@ -615,11 +617,17 @@ static void isotp_rcv(struct sk_buff *skb, void *data)
 
        n_pci_type = cf->data[ae] & 0xF0;
 
+       /* Make sure the state changes and data structures stay consistent at
+        * CAN frame reception time. This locking is not needed in real world
+        * use cases but the inconsistency can be triggered with syzkaller.
+        */
+       spin_lock(&so->rx_lock);
+
        if (so->opt.flags & CAN_ISOTP_HALF_DUPLEX) {
                /* check rx/tx path half duplex expectations */
                if ((so->tx.state != ISOTP_IDLE && n_pci_type != N_PCI_FC) ||
                    (so->rx.state != ISOTP_IDLE && n_pci_type == N_PCI_FC))
-                       return;
+                       goto out_unlock;
        }
 
        switch (n_pci_type) {
@@ -668,6 +676,9 @@ static void isotp_rcv(struct sk_buff *skb, void *data)
                isotp_rcv_cf(sk, cf, ae, skb);
                break;
        }
+
+out_unlock:
+       spin_unlock(&so->rx_lock);
 }
 
 static void isotp_fill_dataframe(struct canfd_frame *cf, struct isotp_sock *so,
@@ -876,7 +887,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 
        if (!size || size > MAX_MSG_LENGTH) {
                err = -EINVAL;
-               goto err_out;
+               goto err_out_drop;
        }
 
        /* take care of a potential SF_DL ESC offset for TX_DL > 8 */
@@ -886,24 +897,24 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
        if ((so->opt.flags & CAN_ISOTP_SF_BROADCAST) &&
            (size > so->tx.ll_dl - SF_PCI_SZ4 - ae - off)) {
                err = -EINVAL;
-               goto err_out;
+               goto err_out_drop;
        }
 
        err = memcpy_from_msg(so->tx.buf, msg, size);
        if (err < 0)
-               goto err_out;
+               goto err_out_drop;
 
        dev = dev_get_by_index(sock_net(sk), so->ifindex);
        if (!dev) {
                err = -ENXIO;
-               goto err_out;
+               goto err_out_drop;
        }
 
        skb = sock_alloc_send_skb(sk, so->ll.mtu + sizeof(struct can_skb_priv),
                                  msg->msg_flags & MSG_DONTWAIT, &err);
        if (!skb) {
                dev_put(dev);
-               goto err_out;
+               goto err_out_drop;
        }
 
        can_skb_reserve(skb);
@@ -965,7 +976,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
        if (err) {
                pr_notice_once("can-isotp: %s: can_send_ret %pe\n",
                               __func__, ERR_PTR(err));
-               goto err_out;
+               goto err_out_drop;
        }
 
        if (wait_tx_done) {
@@ -978,6 +989,9 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 
        return size;
 
+err_out_drop:
+       /* drop this PDU and unlock a potential wait queue */
+       old_state = ISOTP_IDLE;
 err_out:
        so->tx.state = old_state;
        if (so->tx.state == ISOTP_IDLE)
@@ -1444,6 +1458,7 @@ static int isotp_init(struct sock *sk)
        so->txtimer.function = isotp_tx_timer_handler;
 
        init_waitqueue_head(&so->wait);
+       spin_lock_init(&so->rx_lock);
 
        spin_lock(&isotp_notifier_lock);
        list_add_tail(&so->notifier, &isotp_notifier_list);
index ecc400a..4c64415 100644 (file)
@@ -246,6 +246,7 @@ enum {
        Opt_cephx_sign_messages,
        Opt_tcp_nodelay,
        Opt_abort_on_full,
+       Opt_rxbounce,
 };
 
 enum {
@@ -295,6 +296,7 @@ static const struct fs_parameter_spec ceph_parameters[] = {
        fsparam_u32     ("osdkeepalive",                Opt_osdkeepalivetimeout),
        fsparam_enum    ("read_from_replica",           Opt_read_from_replica,
                         ceph_param_read_from_replica),
+       fsparam_flag    ("rxbounce",                    Opt_rxbounce),
        fsparam_enum    ("ms_mode",                     Opt_ms_mode,
                         ceph_param_ms_mode),
        fsparam_string  ("secret",                      Opt_secret),
@@ -584,6 +586,9 @@ int ceph_parse_param(struct fs_parameter *param, struct ceph_options *opt,
        case Opt_abort_on_full:
                opt->flags |= CEPH_OPT_ABORT_ON_FULL;
                break;
+       case Opt_rxbounce:
+               opt->flags |= CEPH_OPT_RXBOUNCE;
+               break;
 
        default:
                BUG();
@@ -660,6 +665,8 @@ int ceph_print_client_options(struct seq_file *m, struct ceph_client *client,
                seq_puts(m, "notcp_nodelay,");
        if (show_all && (opt->flags & CEPH_OPT_ABORT_ON_FULL))
                seq_puts(m, "abort_on_full,");
+       if (opt->flags & CEPH_OPT_RXBOUNCE)
+               seq_puts(m, "rxbounce,");
 
        if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT)
                seq_printf(m, "mount_timeout=%d,",
index 45eba2d..d3bb656 100644 (file)
@@ -515,6 +515,10 @@ static void ceph_con_reset_protocol(struct ceph_connection *con)
                ceph_msg_put(con->out_msg);
                con->out_msg = NULL;
        }
+       if (con->bounce_page) {
+               __free_page(con->bounce_page);
+               con->bounce_page = NULL;
+       }
 
        if (ceph_msgr2(from_msgr(con->msgr)))
                ceph_con_v2_reset_protocol(con);
index 2cb5ffd..6b014ec 100644 (file)
@@ -992,8 +992,7 @@ static int read_partial_message_section(struct ceph_connection *con,
 
 static int read_partial_msg_data(struct ceph_connection *con)
 {
-       struct ceph_msg *msg = con->in_msg;
-       struct ceph_msg_data_cursor *cursor = &msg->cursor;
+       struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor;
        bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC);
        struct page *page;
        size_t page_offset;
@@ -1001,9 +1000,6 @@ static int read_partial_msg_data(struct ceph_connection *con)
        u32 crc = 0;
        int ret;
 
-       if (!msg->num_data_items)
-               return -EIO;
-
        if (do_datacrc)
                crc = con->in_data_crc;
        while (cursor->total_resid) {
@@ -1031,6 +1027,46 @@ static int read_partial_msg_data(struct ceph_connection *con)
        return 1;       /* must return > 0 to indicate success */
 }
 
+static int read_partial_msg_data_bounce(struct ceph_connection *con)
+{
+       struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor;
+       struct page *page;
+       size_t off, len;
+       u32 crc;
+       int ret;
+
+       if (unlikely(!con->bounce_page)) {
+               con->bounce_page = alloc_page(GFP_NOIO);
+               if (!con->bounce_page) {
+                       pr_err("failed to allocate bounce page\n");
+                       return -ENOMEM;
+               }
+       }
+
+       crc = con->in_data_crc;
+       while (cursor->total_resid) {
+               if (!cursor->resid) {
+                       ceph_msg_data_advance(cursor, 0);
+                       continue;
+               }
+
+               page = ceph_msg_data_next(cursor, &off, &len, NULL);
+               ret = ceph_tcp_recvpage(con->sock, con->bounce_page, 0, len);
+               if (ret <= 0) {
+                       con->in_data_crc = crc;
+                       return ret;
+               }
+
+               crc = crc32c(crc, page_address(con->bounce_page), ret);
+               memcpy_to_page(page, off, page_address(con->bounce_page), ret);
+
+               ceph_msg_data_advance(cursor, ret);
+       }
+       con->in_data_crc = crc;
+
+       return 1;       /* must return > 0 to indicate success */
+}
+
 /*
  * read (part of) a message.
  */
@@ -1141,7 +1177,13 @@ static int read_partial_message(struct ceph_connection *con)
 
        /* (page) data */
        if (data_len) {
-               ret = read_partial_msg_data(con);
+               if (!m->num_data_items)
+                       return -EIO;
+
+               if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE))
+                       ret = read_partial_msg_data_bounce(con);
+               else
+                       ret = read_partial_msg_data(con);
                if (ret <= 0)
                        return ret;
        }
index c4099b6..c81379f 100644 (file)
@@ -57,8 +57,9 @@
 #define IN_S_HANDLE_CONTROL_REMAINDER  3
 #define IN_S_PREPARE_READ_DATA         4
 #define IN_S_PREPARE_READ_DATA_CONT    5
-#define IN_S_HANDLE_EPILOGUE           6
-#define IN_S_FINISH_SKIP               7
+#define IN_S_PREPARE_READ_ENC_PAGE     6
+#define IN_S_HANDLE_EPILOGUE           7
+#define IN_S_FINISH_SKIP               8
 
 #define OUT_S_QUEUE_DATA               1
 #define OUT_S_QUEUE_DATA_CONT          2
@@ -1032,22 +1033,41 @@ static int decrypt_control_remainder(struct ceph_connection *con)
                         padded_len(rem_len) + CEPH_GCM_TAG_LEN);
 }
 
-static int decrypt_message(struct ceph_connection *con)
+static int decrypt_tail(struct ceph_connection *con)
 {
+       struct sg_table enc_sgt = {};
        struct sg_table sgt = {};
+       int tail_len;
        int ret;
 
+       tail_len = tail_onwire_len(con->in_msg, true);
+       ret = sg_alloc_table_from_pages(&enc_sgt, con->v2.in_enc_pages,
+                                       con->v2.in_enc_page_cnt, 0, tail_len,
+                                       GFP_NOIO);
+       if (ret)
+               goto out;
+
        ret = setup_message_sgs(&sgt, con->in_msg, FRONT_PAD(con->v2.in_buf),
                        MIDDLE_PAD(con->v2.in_buf), DATA_PAD(con->v2.in_buf),
                        con->v2.in_buf, true);
        if (ret)
                goto out;
 
-       ret = gcm_crypt(con, false, sgt.sgl, sgt.sgl,
-                       tail_onwire_len(con->in_msg, true));
+       dout("%s con %p msg %p enc_page_cnt %d sg_cnt %d\n", __func__, con,
+            con->in_msg, con->v2.in_enc_page_cnt, sgt.orig_nents);
+       ret = gcm_crypt(con, false, enc_sgt.sgl, sgt.sgl, tail_len);
+       if (ret)
+               goto out;
+
+       WARN_ON(!con->v2.in_enc_page_cnt);
+       ceph_release_page_vector(con->v2.in_enc_pages,
+                                con->v2.in_enc_page_cnt);
+       con->v2.in_enc_pages = NULL;
+       con->v2.in_enc_page_cnt = 0;
 
 out:
        sg_free_table(&sgt);
+       sg_free_table(&enc_sgt);
        return ret;
 }
 
@@ -1733,54 +1753,157 @@ static int prepare_read_control_remainder(struct ceph_connection *con)
        return 0;
 }
 
-static void prepare_read_data(struct ceph_connection *con)
+static int prepare_read_data(struct ceph_connection *con)
 {
        struct bio_vec bv;
 
-       if (!con_secure(con))
-               con->in_data_crc = -1;
+       con->in_data_crc = -1;
        ceph_msg_data_cursor_init(&con->v2.in_cursor, con->in_msg,
                                  data_len(con->in_msg));
 
        get_bvec_at(&con->v2.in_cursor, &bv);
-       set_in_bvec(con, &bv);
+       if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
+               if (unlikely(!con->bounce_page)) {
+                       con->bounce_page = alloc_page(GFP_NOIO);
+                       if (!con->bounce_page) {
+                               pr_err("failed to allocate bounce page\n");
+                               return -ENOMEM;
+                       }
+               }
+
+               bv.bv_page = con->bounce_page;
+               bv.bv_offset = 0;
+               set_in_bvec(con, &bv);
+       } else {
+               set_in_bvec(con, &bv);
+       }
        con->v2.in_state = IN_S_PREPARE_READ_DATA_CONT;
+       return 0;
 }
 
 static void prepare_read_data_cont(struct ceph_connection *con)
 {
        struct bio_vec bv;
 
-       if (!con_secure(con))
+       if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
+               con->in_data_crc = crc32c(con->in_data_crc,
+                                         page_address(con->bounce_page),
+                                         con->v2.in_bvec.bv_len);
+
+               get_bvec_at(&con->v2.in_cursor, &bv);
+               memcpy_to_page(bv.bv_page, bv.bv_offset,
+                              page_address(con->bounce_page),
+                              con->v2.in_bvec.bv_len);
+       } else {
                con->in_data_crc = ceph_crc32c_page(con->in_data_crc,
                                                    con->v2.in_bvec.bv_page,
                                                    con->v2.in_bvec.bv_offset,
                                                    con->v2.in_bvec.bv_len);
+       }
 
        ceph_msg_data_advance(&con->v2.in_cursor, con->v2.in_bvec.bv_len);
        if (con->v2.in_cursor.total_resid) {
                get_bvec_at(&con->v2.in_cursor, &bv);
-               set_in_bvec(con, &bv);
+               if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
+                       bv.bv_page = con->bounce_page;
+                       bv.bv_offset = 0;
+                       set_in_bvec(con, &bv);
+               } else {
+                       set_in_bvec(con, &bv);
+               }
                WARN_ON(con->v2.in_state != IN_S_PREPARE_READ_DATA_CONT);
                return;
        }
 
        /*
-        * We've read all data.  Prepare to read data padding (if any)
-        * and epilogue.
+        * We've read all data.  Prepare to read epilogue.
         */
        reset_in_kvecs(con);
-       if (con_secure(con)) {
-               if (need_padding(data_len(con->in_msg)))
-                       add_in_kvec(con, DATA_PAD(con->v2.in_buf),
-                                   padding_len(data_len(con->in_msg)));
-               add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_SECURE_LEN);
+       add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN);
+       con->v2.in_state = IN_S_HANDLE_EPILOGUE;
+}
+
+static int prepare_read_tail_plain(struct ceph_connection *con)
+{
+       struct ceph_msg *msg = con->in_msg;
+
+       if (!front_len(msg) && !middle_len(msg)) {
+               WARN_ON(!data_len(msg));
+               return prepare_read_data(con);
+       }
+
+       reset_in_kvecs(con);
+       if (front_len(msg)) {
+               add_in_kvec(con, msg->front.iov_base, front_len(msg));
+               WARN_ON(msg->front.iov_len != front_len(msg));
+       }
+       if (middle_len(msg)) {
+               add_in_kvec(con, msg->middle->vec.iov_base, middle_len(msg));
+               WARN_ON(msg->middle->vec.iov_len != middle_len(msg));
+       }
+
+       if (data_len(msg)) {
+               con->v2.in_state = IN_S_PREPARE_READ_DATA;
        } else {
                add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN);
+               con->v2.in_state = IN_S_HANDLE_EPILOGUE;
        }
+       return 0;
+}
+
+static void prepare_read_enc_page(struct ceph_connection *con)
+{
+       struct bio_vec bv;
+
+       dout("%s con %p i %d resid %d\n", __func__, con, con->v2.in_enc_i,
+            con->v2.in_enc_resid);
+       WARN_ON(!con->v2.in_enc_resid);
+
+       bv.bv_page = con->v2.in_enc_pages[con->v2.in_enc_i];
+       bv.bv_offset = 0;
+       bv.bv_len = min(con->v2.in_enc_resid, (int)PAGE_SIZE);
+
+       set_in_bvec(con, &bv);
+       con->v2.in_enc_i++;
+       con->v2.in_enc_resid -= bv.bv_len;
+
+       if (con->v2.in_enc_resid) {
+               con->v2.in_state = IN_S_PREPARE_READ_ENC_PAGE;
+               return;
+       }
+
+       /*
+        * We are set to read the last piece of ciphertext (ending
+        * with epilogue) + auth tag.
+        */
+       WARN_ON(con->v2.in_enc_i != con->v2.in_enc_page_cnt);
        con->v2.in_state = IN_S_HANDLE_EPILOGUE;
 }
 
+static int prepare_read_tail_secure(struct ceph_connection *con)
+{
+       struct page **enc_pages;
+       int enc_page_cnt;
+       int tail_len;
+
+       tail_len = tail_onwire_len(con->in_msg, true);
+       WARN_ON(!tail_len);
+
+       enc_page_cnt = calc_pages_for(0, tail_len);
+       enc_pages = ceph_alloc_page_vector(enc_page_cnt, GFP_NOIO);
+       if (IS_ERR(enc_pages))
+               return PTR_ERR(enc_pages);
+
+       WARN_ON(con->v2.in_enc_pages || con->v2.in_enc_page_cnt);
+       con->v2.in_enc_pages = enc_pages;
+       con->v2.in_enc_page_cnt = enc_page_cnt;
+       con->v2.in_enc_resid = tail_len;
+       con->v2.in_enc_i = 0;
+
+       prepare_read_enc_page(con);
+       return 0;
+}
+
 static void __finish_skip(struct ceph_connection *con)
 {
        con->in_seq++;
@@ -2589,47 +2712,26 @@ static int __handle_control(struct ceph_connection *con, void *p)
        }
 
        msg = con->in_msg;  /* set in process_message_header() */
-       if (!front_len(msg) && !middle_len(msg)) {
-               if (!data_len(msg))
-                       return process_message(con);
-
-               prepare_read_data(con);
-               return 0;
-       }
-
-       reset_in_kvecs(con);
        if (front_len(msg)) {
                WARN_ON(front_len(msg) > msg->front_alloc_len);
-               add_in_kvec(con, msg->front.iov_base, front_len(msg));
                msg->front.iov_len = front_len(msg);
-
-               if (con_secure(con) && need_padding(front_len(msg)))
-                       add_in_kvec(con, FRONT_PAD(con->v2.in_buf),
-                                   padding_len(front_len(msg)));
        } else {
                msg->front.iov_len = 0;
        }
        if (middle_len(msg)) {
                WARN_ON(middle_len(msg) > msg->middle->alloc_len);
-               add_in_kvec(con, msg->middle->vec.iov_base, middle_len(msg));
                msg->middle->vec.iov_len = middle_len(msg);
-
-               if (con_secure(con) && need_padding(middle_len(msg)))
-                       add_in_kvec(con, MIDDLE_PAD(con->v2.in_buf),
-                                   padding_len(middle_len(msg)));
        } else if (msg->middle) {
                msg->middle->vec.iov_len = 0;
        }
 
-       if (data_len(msg)) {
-               con->v2.in_state = IN_S_PREPARE_READ_DATA;
-       } else {
-               add_in_kvec(con, con->v2.in_buf,
-                           con_secure(con) ? CEPH_EPILOGUE_SECURE_LEN :
-                                             CEPH_EPILOGUE_PLAIN_LEN);
-               con->v2.in_state = IN_S_HANDLE_EPILOGUE;
-       }
-       return 0;
+       if (!front_len(msg) && !middle_len(msg) && !data_len(msg))
+               return process_message(con);
+
+       if (con_secure(con))
+               return prepare_read_tail_secure(con);
+
+       return prepare_read_tail_plain(con);
 }
 
 static int handle_preamble(struct ceph_connection *con)
@@ -2717,7 +2819,7 @@ static int handle_epilogue(struct ceph_connection *con)
        int ret;
 
        if (con_secure(con)) {
-               ret = decrypt_message(con);
+               ret = decrypt_tail(con);
                if (ret) {
                        if (ret == -EBADMSG)
                                con->error_msg = "integrity error, bad epilogue auth tag";
@@ -2785,13 +2887,16 @@ static int populate_in_iter(struct ceph_connection *con)
                        ret = handle_control_remainder(con);
                        break;
                case IN_S_PREPARE_READ_DATA:
-                       prepare_read_data(con);
-                       ret = 0;
+                       ret = prepare_read_data(con);
                        break;
                case IN_S_PREPARE_READ_DATA_CONT:
                        prepare_read_data_cont(con);
                        ret = 0;
                        break;
+               case IN_S_PREPARE_READ_ENC_PAGE:
+                       prepare_read_enc_page(con);
+                       ret = 0;
+                       break;
                case IN_S_HANDLE_EPILOGUE:
                        ret = handle_epilogue(con);
                        break;
@@ -3326,20 +3431,16 @@ void ceph_con_v2_revoke(struct ceph_connection *con)
 
 static void revoke_at_prepare_read_data(struct ceph_connection *con)
 {
-       int remaining;  /* data + [data padding] + epilogue */
+       int remaining;
        int resid;
 
+       WARN_ON(con_secure(con));
        WARN_ON(!data_len(con->in_msg));
        WARN_ON(!iov_iter_is_kvec(&con->v2.in_iter));
        resid = iov_iter_count(&con->v2.in_iter);
        WARN_ON(!resid);
 
-       if (con_secure(con))
-               remaining = padded_len(data_len(con->in_msg)) +
-                           CEPH_EPILOGUE_SECURE_LEN;
-       else
-               remaining = data_len(con->in_msg) + CEPH_EPILOGUE_PLAIN_LEN;
-
+       remaining = data_len(con->in_msg) + CEPH_EPILOGUE_PLAIN_LEN;
        dout("%s con %p resid %d remaining %d\n", __func__, con, resid,
             remaining);
        con->v2.in_iter.count -= resid;
@@ -3350,8 +3451,9 @@ static void revoke_at_prepare_read_data(struct ceph_connection *con)
 static void revoke_at_prepare_read_data_cont(struct ceph_connection *con)
 {
        int recved, resid;  /* current piece of data */
-       int remaining;  /* [data padding] + epilogue */
+       int remaining;
 
+       WARN_ON(con_secure(con));
        WARN_ON(!data_len(con->in_msg));
        WARN_ON(!iov_iter_is_bvec(&con->v2.in_iter));
        resid = iov_iter_count(&con->v2.in_iter);
@@ -3363,12 +3465,7 @@ static void revoke_at_prepare_read_data_cont(struct ceph_connection *con)
                ceph_msg_data_advance(&con->v2.in_cursor, recved);
        WARN_ON(resid > con->v2.in_cursor.total_resid);
 
-       if (con_secure(con))
-               remaining = padding_len(data_len(con->in_msg)) +
-                           CEPH_EPILOGUE_SECURE_LEN;
-       else
-               remaining = CEPH_EPILOGUE_PLAIN_LEN;
-
+       remaining = CEPH_EPILOGUE_PLAIN_LEN;
        dout("%s con %p total_resid %zu remaining %d\n", __func__, con,
             con->v2.in_cursor.total_resid, remaining);
        con->v2.in_iter.count -= resid;
@@ -3376,11 +3473,26 @@ static void revoke_at_prepare_read_data_cont(struct ceph_connection *con)
        con->v2.in_state = IN_S_FINISH_SKIP;
 }
 
+static void revoke_at_prepare_read_enc_page(struct ceph_connection *con)
+{
+       int resid;  /* current enc page (not necessarily data) */
+
+       WARN_ON(!con_secure(con));
+       WARN_ON(!iov_iter_is_bvec(&con->v2.in_iter));
+       resid = iov_iter_count(&con->v2.in_iter);
+       WARN_ON(!resid || resid > con->v2.in_bvec.bv_len);
+
+       dout("%s con %p resid %d enc_resid %d\n", __func__, con, resid,
+            con->v2.in_enc_resid);
+       con->v2.in_iter.count -= resid;
+       set_in_skip(con, resid + con->v2.in_enc_resid);
+       con->v2.in_state = IN_S_FINISH_SKIP;
+}
+
 static void revoke_at_handle_epilogue(struct ceph_connection *con)
 {
        int resid;
 
-       WARN_ON(!iov_iter_is_kvec(&con->v2.in_iter));
        resid = iov_iter_count(&con->v2.in_iter);
        WARN_ON(!resid);
 
@@ -3399,6 +3511,9 @@ void ceph_con_v2_revoke_incoming(struct ceph_connection *con)
        case IN_S_PREPARE_READ_DATA_CONT:
                revoke_at_prepare_read_data_cont(con);
                break;
+       case IN_S_PREPARE_READ_ENC_PAGE:
+               revoke_at_prepare_read_enc_page(con);
+               break;
        case IN_S_HANDLE_EPILOGUE:
                revoke_at_handle_epilogue(con);
                break;
@@ -3432,6 +3547,13 @@ void ceph_con_v2_reset_protocol(struct ceph_connection *con)
        clear_out_sign_kvecs(con);
        free_conn_bufs(con);
 
+       if (con->v2.in_enc_pages) {
+               WARN_ON(!con->v2.in_enc_page_cnt);
+               ceph_release_page_vector(con->v2.in_enc_pages,
+                                        con->v2.in_enc_page_cnt);
+               con->v2.in_enc_pages = NULL;
+               con->v2.in_enc_page_cnt = 0;
+       }
        if (con->v2.out_enc_pages) {
                WARN_ON(!con->v2.out_enc_page_cnt);
                ceph_release_page_vector(con->v2.out_enc_pages,
index 6c2016f..ec0bf73 100644 (file)
@@ -1133,7 +1133,8 @@ out:
        neigh_release(neigh);
 }
 
-int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
+int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb,
+                      const bool immediate_ok)
 {
        int rc;
        bool immediate_probe = false;
@@ -1154,12 +1155,17 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
                        atomic_set(&neigh->probes,
                                   NEIGH_VAR(neigh->parms, UCAST_PROBES));
                        neigh_del_timer(neigh);
-                       neigh->nud_state     = NUD_INCOMPLETE;
+                       neigh->nud_state = NUD_INCOMPLETE;
                        neigh->updated = now;
-                       next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
-                                        HZ/100);
+                       if (!immediate_ok) {
+                               next = now + 1;
+                       } else {
+                               immediate_probe = true;
+                               next = now + max(NEIGH_VAR(neigh->parms,
+                                                          RETRANS_TIME),
+                                                HZ / 100);
+                       }
                        neigh_add_timer(neigh, next);
-                       immediate_probe = true;
                } else {
                        neigh->nud_state = NUD_FAILED;
                        neigh->updated = jiffies;
@@ -1571,7 +1577,7 @@ static void neigh_managed_work(struct work_struct *work)
 
        write_lock_bh(&tbl->lock);
        list_for_each_entry(neigh, &tbl->managed_list, managed_list)
-               neigh_event_send(neigh, NULL);
+               neigh_event_send_probe(neigh, NULL, false);
        queue_delayed_work(system_power_efficient_wq, &tbl->managed_work,
                           NEIGH_VAR(&tbl->parms, DELAY_PROBE_TIME));
        write_unlock_bh(&tbl->lock);
index d8b9dba..88cc0ad 100644 (file)
@@ -190,12 +190,23 @@ static const struct seq_operations softnet_seq_ops = {
        .show  = softnet_seq_show,
 };
 
-static void *ptype_get_idx(loff_t pos)
+static void *ptype_get_idx(struct seq_file *seq, loff_t pos)
 {
+       struct list_head *ptype_list = NULL;
        struct packet_type *pt = NULL;
+       struct net_device *dev;
        loff_t i = 0;
        int t;
 
+       for_each_netdev_rcu(seq_file_net(seq), dev) {
+               ptype_list = &dev->ptype_all;
+               list_for_each_entry_rcu(pt, ptype_list, list) {
+                       if (i == pos)
+                               return pt;
+                       ++i;
+               }
+       }
+
        list_for_each_entry_rcu(pt, &ptype_all, list) {
                if (i == pos)
                        return pt;
@@ -216,22 +227,40 @@ static void *ptype_seq_start(struct seq_file *seq, loff_t *pos)
        __acquires(RCU)
 {
        rcu_read_lock();
-       return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN;
+       return *pos ? ptype_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
 }
 
 static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
+       struct net_device *dev;
        struct packet_type *pt;
        struct list_head *nxt;
        int hash;
 
        ++*pos;
        if (v == SEQ_START_TOKEN)
-               return ptype_get_idx(0);
+               return ptype_get_idx(seq, 0);
 
        pt = v;
        nxt = pt->list.next;
+       if (pt->dev) {
+               if (nxt != &pt->dev->ptype_all)
+                       goto found;
+
+               dev = pt->dev;
+               for_each_netdev_continue_rcu(seq_file_net(seq), dev) {
+                       if (!list_empty(&dev->ptype_all)) {
+                               nxt = dev->ptype_all.next;
+                               goto found;
+                       }
+               }
+
+               nxt = ptype_all.next;
+               goto ptype_all;
+       }
+
        if (pt->type == htons(ETH_P_ALL)) {
+ptype_all:
                if (nxt != &ptype_all)
                        goto found;
                hash = 0;
@@ -260,7 +289,8 @@ static int ptype_seq_show(struct seq_file *seq, void *v)
 
        if (v == SEQ_START_TOKEN)
                seq_puts(seq, "Type Device      Function\n");
-       else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) {
+       else if ((!pt->af_packet_net || net_eq(pt->af_packet_net, seq_file_net(seq))) &&
+                (!pt->dev || net_eq(dev_net(pt->dev), seq_file_net(seq)))) {
                if (pt->type == htons(ETH_P_ALL))
                        seq_puts(seq, "ALL ");
                else
index e476403..710da8a 100644 (file)
@@ -3275,8 +3275,8 @@ static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
        struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1];
        unsigned char name_assign_type = NET_NAME_USER;
        struct nlattr *linkinfo[IFLA_INFO_MAX + 1];
-       const struct rtnl_link_ops *m_ops = NULL;
-       struct net_device *master_dev = NULL;
+       const struct rtnl_link_ops *m_ops;
+       struct net_device *master_dev;
        struct net *net = sock_net(skb->sk);
        const struct rtnl_link_ops *ops;
        struct nlattr *tb[IFLA_MAX + 1];
@@ -3314,6 +3314,8 @@ replay:
        else
                dev = NULL;
 
+       master_dev = NULL;
+       m_ops = NULL;
        if (dev) {
                master_dev = netdev_master_upper_dev_get(dev);
                if (master_dev)
index 0118f0a..9d0388b 100644 (file)
@@ -681,7 +681,7 @@ exit:
         * while trying to recycle fragments on __skb_frag_unref() we need
         * to make one SKB responsible for triggering the recycle path.
         * So disable the recycling bit if an SKB is cloned and we have
-        * additional references to to the fragmented part of the SKB.
+        * additional references to the fragmented part of the SKB.
         * Eventually the last SKB will have the recycling bit set and it's
         * dataref set to 0, which will trigger the recycling
         */
index 3d21521..dcad310 100644 (file)
@@ -1718,7 +1718,6 @@ EXPORT_SYMBOL_GPL(dsa_unregister_switch);
 void dsa_switch_shutdown(struct dsa_switch *ds)
 {
        struct net_device *master, *slave_dev;
-       LIST_HEAD(unregister_list);
        struct dsa_port *dp;
 
        mutex_lock(&dsa2_mutex);
@@ -1729,25 +1728,13 @@ void dsa_switch_shutdown(struct dsa_switch *ds)
                slave_dev = dp->slave;
 
                netdev_upper_dev_unlink(master, slave_dev);
-               /* Just unlinking ourselves as uppers of the master is not
-                * sufficient. When the master net device unregisters, that will
-                * also call dev_close, which we will catch as NETDEV_GOING_DOWN
-                * and trigger a dev_close on our own devices (dsa_slave_close).
-                * In turn, that will call dev_mc_unsync on the master's net
-                * device. If the master is also a DSA switch port, this will
-                * trigger dsa_slave_set_rx_mode which will call dev_mc_sync on
-                * its own master. Lockdep will complain about the fact that
-                * all cascaded masters have the same dsa_master_addr_list_lock_key,
-                * which it normally would not do if the cascaded masters would
-                * be in a proper upper/lower relationship, which we've just
-                * destroyed.
-                * To suppress the lockdep warnings, let's actually unregister
-                * the DSA slave interfaces too, to avoid the nonsensical
-                * multicast address list synchronization on shutdown.
-                */
-               unregister_netdevice_queue(slave_dev, &unregister_list);
        }
-       unregister_netdevice_many(&unregister_list);
+
+       /* Disconnect from further netdevice notifiers on the master,
+        * since netdev_uses_dsa() will now return false.
+        */
+       dsa_switch_for_each_cpu_port(dp, ds)
+               dp->master->dsa_ptr = NULL;
 
        rtnl_unlock();
        mutex_unlock(&dsa2_mutex);
index 277124f..e0b072a 100644 (file)
@@ -1441,7 +1441,7 @@ static int nl802154_send_key(struct sk_buff *msg, u32 cmd, u32 portid,
 
        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
        if (!hdr)
-               return -1;
+               return -ENOBUFS;
 
        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
                goto nla_put_failure;
@@ -1634,7 +1634,7 @@ static int nl802154_send_device(struct sk_buff *msg, u32 cmd, u32 portid,
 
        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
        if (!hdr)
-               return -1;
+               return -ENOBUFS;
 
        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
                goto nla_put_failure;
@@ -1812,7 +1812,7 @@ static int nl802154_send_devkey(struct sk_buff *msg, u32 cmd, u32 portid,
 
        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
        if (!hdr)
-               return -1;
+               return -ENOBUFS;
 
        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
                goto nla_put_failure;
@@ -1988,7 +1988,7 @@ static int nl802154_send_seclevel(struct sk_buff *msg, u32 cmd, u32 portid,
 
        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
        if (!hdr)
-               return -1;
+               return -ENOBUFS;
 
        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
                goto nla_put_failure;
index 57c1d84..139cec2 100644 (file)
@@ -162,12 +162,19 @@ int ip_build_and_send_pkt(struct sk_buff *skb, const struct sock *sk,
        iph->daddr    = (opt && opt->opt.srr ? opt->opt.faddr : daddr);
        iph->saddr    = saddr;
        iph->protocol = sk->sk_protocol;
-       if (ip_dont_fragment(sk, &rt->dst)) {
+       /* Do not bother generating IPID for small packets (eg SYNACK) */
+       if (skb->len <= IPV4_MIN_MTU || ip_dont_fragment(sk, &rt->dst)) {
                iph->frag_off = htons(IP_DF);
                iph->id = 0;
        } else {
                iph->frag_off = 0;
-               __ip_select_ident(net, iph, 1);
+               /* TCP packets here are SYNACK with fat IPv4/TCP options.
+                * Avoid using the hashed IP ident generator.
+                */
+               if (sk->sk_protocol == IPPROTO_TCP)
+                       iph->id = (__force __be16)prandom_u32();
+               else
+                       __ip_select_ident(net, iph, 1);
        }
 
        if (opt && opt->opt.optlen) {
@@ -825,15 +832,24 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
                /* Everything is OK. Generate! */
                ip_fraglist_init(skb, iph, hlen, &iter);
 
-               if (iter.frag)
-                       ip_options_fragment(iter.frag);
-
                for (;;) {
                        /* Prepare header of the next frame,
                         * before previous one went down. */
                        if (iter.frag) {
+                               bool first_frag = (iter.offset == 0);
+
                                IPCB(iter.frag)->flags = IPCB(skb)->flags;
                                ip_fraglist_prepare(skb, &iter);
+                               if (first_frag && IPCB(skb)->opt.optlen) {
+                                       /* ipcb->opt is not populated for frags
+                                        * coming from __ip_make_skb(),
+                                        * ip_options_fragment() needs optlen
+                                        */
+                                       IPCB(iter.frag)->opt.optlen =
+                                               IPCB(skb)->opt.optlen;
+                                       ip_options_fragment(iter.frag);
+                                       ip_send_check(iter.iph);
+                               }
                        }
 
                        skb->tstamp = tstamp;
index 0727461..29bbe2b 100644 (file)
@@ -256,7 +256,9 @@ static int __net_init ipmr_rules_init(struct net *net)
        return 0;
 
 err2:
+       rtnl_lock();
        ipmr_free_table(mrt);
+       rtnl_unlock();
 err1:
        fib_rules_unregister(ops);
        return err;
index 67087f9..aab3841 100644 (file)
@@ -58,10 +58,6 @@ config NF_TABLES_ARP
 
 endif # NF_TABLES
 
-config NF_FLOW_TABLE_IPV4
-       tristate
-       select NF_FLOW_TABLE_INET
-
 config NF_DUP_IPV4
        tristate "Netfilter IPv4 packet duplication to alternate destination"
        depends on !NF_CONNTRACK || NF_CONNTRACK
index 0e56df3..bcf7bc7 100644 (file)
@@ -220,7 +220,8 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
                        continue;
                }
 
-               if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)
+               if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif &&
+                   sk->sk_bound_dev_if != inet_sdif(skb))
                        continue;
 
                sock_hold(sk);
index 9eb5fc2..9f97b9c 100644 (file)
@@ -722,6 +722,7 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        int ret = -EINVAL;
        int chk_addr_ret;
 
+       lock_sock(sk);
        if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in))
                goto out;
 
@@ -741,7 +742,9 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                inet->inet_saddr = 0;  /* Use device */
        sk_dst_reset(sk);
        ret = 0;
-out:   return ret;
+out:
+       release_sock(sk);
+       return ret;
 }
 
 /*
index 3b75836..02cb275 100644 (file)
@@ -842,6 +842,7 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos,
        }
 
        release_sock(sk);
+       sk_defer_free_flush(sk);
 
        if (spliced)
                return spliced;
@@ -936,6 +937,22 @@ void tcp_remove_empty_skb(struct sock *sk)
        }
 }
 
+/* skb changing from pure zc to mixed, must charge zc */
+static int tcp_downgrade_zcopy_pure(struct sock *sk, struct sk_buff *skb)
+{
+       if (unlikely(skb_zcopy_pure(skb))) {
+               u32 extra = skb->truesize -
+                           SKB_TRUESIZE(skb_end_offset(skb));
+
+               if (!sk_wmem_schedule(sk, extra))
+                       return -ENOMEM;
+
+               sk_mem_charge(sk, extra);
+               skb_shinfo(skb)->flags &= ~SKBFL_PURE_ZEROCOPY;
+       }
+       return 0;
+}
+
 static struct sk_buff *tcp_build_frag(struct sock *sk, int size_goal, int flags,
                                      struct page *page, int offset, size_t *size)
 {
@@ -971,7 +988,7 @@ new_segment:
                tcp_mark_push(tp, skb);
                goto new_segment;
        }
-       if (!sk_wmem_schedule(sk, copy))
+       if (tcp_downgrade_zcopy_pure(sk, skb) || !sk_wmem_schedule(sk, copy))
                return NULL;
 
        if (can_coalesce) {
@@ -1319,16 +1336,8 @@ new_segment:
 
                        copy = min_t(int, copy, pfrag->size - pfrag->offset);
 
-                       /* skb changing from pure zc to mixed, must charge zc */
-                       if (unlikely(skb_zcopy_pure(skb))) {
-                               if (!sk_wmem_schedule(sk, skb->data_len))
-                                       goto wait_for_space;
-
-                               sk_mem_charge(sk, skb->data_len);
-                               skb_shinfo(skb)->flags &= ~SKBFL_PURE_ZEROCOPY;
-                       }
-
-                       if (!sk_wmem_schedule(sk, copy))
+                       if (tcp_downgrade_zcopy_pure(sk, skb) ||
+                           !sk_wmem_schedule(sk, copy))
                                goto wait_for_space;
 
                        err = skb_copy_to_page_nocache(sk, &msg->msg_iter, skb,
index dc49a3d..bfe4112 100644 (file)
@@ -1660,6 +1660,8 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
            (mss != tcp_skb_seglen(skb)))
                goto out;
 
+       if (!tcp_skb_can_collapse(prev, skb))
+               goto out;
        len = skb->len;
        pcount = tcp_skb_pcount(skb);
        if (tcp_skb_shift(prev, skb, pcount, len))
index b53476e..fec656f 100644 (file)
@@ -2095,7 +2095,7 @@ process:
        nf_reset_ct(skb);
 
        if (tcp_filter(sk, skb)) {
-               drop_reason = SKB_DROP_REASON_TCP_FILTER;
+               drop_reason = SKB_DROP_REASON_SOCKET_FILTER;
                goto discard_and_relse;
        }
        th = (const struct tcphdr *)skb->data;
index 3eee177..f927c19 100644 (file)
@@ -2589,7 +2589,7 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
                                 __u32 valid_lft, u32 prefered_lft)
 {
        struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
-       int create = 0;
+       int create = 0, update_lft = 0;
 
        if (!ifp && valid_lft) {
                int max_addresses = in6_dev->cnf.max_addresses;
@@ -2633,19 +2633,32 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
                unsigned long now;
                u32 stored_lft;
 
-               /* Update lifetime (RFC4862 5.5.3 e)
-                * We deviate from RFC4862 by honoring all Valid Lifetimes to
-                * improve the reaction of SLAAC to renumbering events
-                * (draft-gont-6man-slaac-renum-06, Section 4.2)
-                */
+               /* update lifetime (RFC2462 5.5.3 e) */
                spin_lock_bh(&ifp->lock);
                now = jiffies;
                if (ifp->valid_lft > (now - ifp->tstamp) / HZ)
                        stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ;
                else
                        stored_lft = 0;
-
                if (!create && stored_lft) {
+                       const u32 minimum_lft = min_t(u32,
+                               stored_lft, MIN_VALID_LIFETIME);
+                       valid_lft = max(valid_lft, minimum_lft);
+
+                       /* RFC4862 Section 5.5.3e:
+                        * "Note that the preferred lifetime of the
+                        *  corresponding address is always reset to
+                        *  the Preferred Lifetime in the received
+                        *  Prefix Information option, regardless of
+                        *  whether the valid lifetime is also reset or
+                        *  ignored."
+                        *
+                        * So we should always update prefered_lft here.
+                        */
+                       update_lft = 1;
+               }
+
+               if (update_lft) {
                        ifp->valid_lft = valid_lft;
                        ifp->prefered_lft = prefered_lft;
                        ifp->tstamp = now;
index 463c37d..413f667 100644 (file)
@@ -112,7 +112,7 @@ void fib6_update_sernum(struct net *net, struct fib6_info *f6i)
        fn = rcu_dereference_protected(f6i->fib6_node,
                        lockdep_is_held(&f6i->fib6_table->tb6_lock));
        if (fn)
-               fn->fn_sernum = fib6_new_sernum(net);
+               WRITE_ONCE(fn->fn_sernum, fib6_new_sernum(net));
 }
 
 /*
@@ -590,12 +590,13 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
                spin_unlock_bh(&table->tb6_lock);
                if (res > 0) {
                        cb->args[4] = 1;
-                       cb->args[5] = w->root->fn_sernum;
+                       cb->args[5] = READ_ONCE(w->root->fn_sernum);
                }
        } else {
-               if (cb->args[5] != w->root->fn_sernum) {
+               int sernum = READ_ONCE(w->root->fn_sernum);
+               if (cb->args[5] != sernum) {
                        /* Begin at the root if the tree changed */
-                       cb->args[5] = w->root->fn_sernum;
+                       cb->args[5] = sernum;
                        w->state = FWS_INIT;
                        w->node = w->root;
                        w->skip = w->count;
@@ -1345,7 +1346,7 @@ static void __fib6_update_sernum_upto_root(struct fib6_info *rt,
        /* paired with smp_rmb() in fib6_get_cookie_safe() */
        smp_wmb();
        while (fn) {
-               fn->fn_sernum = sernum;
+               WRITE_ONCE(fn->fn_sernum, sernum);
                fn = rcu_dereference_protected(fn->parent,
                                lockdep_is_held(&rt->fib6_table->tb6_lock));
        }
@@ -2174,8 +2175,8 @@ static int fib6_clean_node(struct fib6_walker *w)
        };
 
        if (c->sernum != FIB6_NO_SERNUM_CHANGE &&
-           w->node->fn_sernum != c->sernum)
-               w->node->fn_sernum = c->sernum;
+           READ_ONCE(w->node->fn_sernum) != c->sernum)
+               WRITE_ONCE(w->node->fn_sernum, c->sernum);
 
        if (!c->func) {
                WARN_ON_ONCE(c->sernum == FIB6_NO_SERNUM_CHANGE);
@@ -2543,7 +2544,7 @@ static void ipv6_route_seq_setup_walk(struct ipv6_route_iter *iter,
        iter->w.state = FWS_INIT;
        iter->w.node = iter->w.root;
        iter->w.args = iter;
-       iter->sernum = iter->w.root->fn_sernum;
+       iter->sernum = READ_ONCE(iter->w.root->fn_sernum);
        INIT_LIST_HEAD(&iter->w.lh);
        fib6_walker_link(net, &iter->w);
 }
@@ -2571,8 +2572,10 @@ static struct fib6_table *ipv6_route_seq_next_table(struct fib6_table *tbl,
 
 static void ipv6_route_check_sernum(struct ipv6_route_iter *iter)
 {
-       if (iter->sernum != iter->w.root->fn_sernum) {
-               iter->sernum = iter->w.root->fn_sernum;
+       int sernum = READ_ONCE(iter->w.root->fn_sernum);
+
+       if (iter->sernum != sernum) {
+               iter->sernum = sernum;
                iter->w.state = FWS_INIT;
                iter->w.node = iter->w.root;
                WARN_ON(iter->w.skip);
index fe786df..97ade83 100644 (file)
@@ -1036,14 +1036,14 @@ int ip6_tnl_xmit_ctl(struct ip6_tnl *t,
 
                if (unlikely(!ipv6_chk_addr_and_flags(net, laddr, ldev, false,
                                                      0, IFA_F_TENTATIVE)))
-                       pr_warn("%s xmit: Local address not yet configured!\n",
-                               p->name);
+                       pr_warn_ratelimited("%s xmit: Local address not yet configured!\n",
+                                           p->name);
                else if (!(p->flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE) &&
                         !ipv6_addr_is_multicast(raddr) &&
                         unlikely(ipv6_chk_addr_and_flags(net, raddr, ldev,
                                                          true, 0, IFA_F_TENTATIVE)))
-                       pr_warn("%s xmit: Routing loop! Remote address found on this node!\n",
-                               p->name);
+                       pr_warn_ratelimited("%s xmit: Routing loop! Remote address found on this node!\n",
+                                           p->name);
                else
                        ret = 1;
                rcu_read_unlock();
index 7cf73e6..8a2db92 100644 (file)
@@ -243,7 +243,9 @@ static int __net_init ip6mr_rules_init(struct net *net)
        return 0;
 
 err2:
+       rtnl_lock();
        ip6mr_free_table(mrt);
+       rtnl_unlock();
 err1:
        fib_rules_unregister(ops);
        return err;
index 97d3d1b..0ba62f4 100644 (file)
@@ -47,10 +47,6 @@ config NFT_FIB_IPV6
 endif # NF_TABLES_IPV6
 endif # NF_TABLES
 
-config NF_FLOW_TABLE_IPV6
-       tristate
-       select NF_FLOW_TABLE_INET
-
 config NF_DUP_IPV6
        tristate "Netfilter IPv6 packet duplication to alternate destination"
        depends on !NF_CONNTRACK || NF_CONNTRACK
index b853836..b8d6dc9 100644 (file)
@@ -28,9 +28,6 @@ obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o
 obj-$(CONFIG_NFT_DUP_IPV6) += nft_dup_ipv6.o
 obj-$(CONFIG_NFT_FIB_IPV6) += nft_fib_ipv6.o
 
-# flow table support
-obj-$(CONFIG_NF_FLOW_TABLE_IPV6) += nf_flow_table_ipv6.o
-
 # matches
 obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
 obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
diff --git a/net/ipv6/netfilter/nf_flow_table_ipv6.c b/net/ipv6/netfilter/nf_flow_table_ipv6.c
deleted file mode 100644 (file)
index e69de29..0000000
index e6de942..f4884cd 100644 (file)
@@ -2802,7 +2802,7 @@ static void ip6_link_failure(struct sk_buff *skb)
                        if (from) {
                                fn = rcu_dereference(from->fib6_node);
                                if (fn && (rt->rt6i_flags & RTF_DEFAULT))
-                                       fn->fn_sernum = -1;
+                                       WRITE_ONCE(fn->fn_sernum, -1);
                        }
                }
                rcu_read_unlock();
index 48f75a5..d6fdc57 100644 (file)
@@ -1607,6 +1607,7 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        struct mpls_dev *mdev;
        unsigned int flags;
+       int err;
 
        if (event == NETDEV_REGISTER) {
                mdev = mpls_add_dev(dev);
@@ -1621,7 +1622,6 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
                return NOTIFY_OK;
 
        switch (event) {
-               int err;
 
        case NETDEV_DOWN:
                err = mpls_ifdown(dev, event);
index 75af1f7..356f596 100644 (file)
@@ -478,6 +478,20 @@ __lookup_addr_by_id(struct pm_nl_pernet *pernet, unsigned int id)
        return NULL;
 }
 
+static struct mptcp_pm_addr_entry *
+__lookup_addr(struct pm_nl_pernet *pernet, const struct mptcp_addr_info *info,
+             bool lookup_by_id)
+{
+       struct mptcp_pm_addr_entry *entry;
+
+       list_for_each_entry(entry, &pernet->local_addr_list, list) {
+               if ((!lookup_by_id && addresses_equal(&entry->addr, info, true)) ||
+                   (lookup_by_id && entry->addr.id == info->id))
+                       return entry;
+       }
+       return NULL;
+}
+
 static int
 lookup_id_by_addr(struct pm_nl_pernet *pernet, const struct mptcp_addr_info *addr)
 {
@@ -777,7 +791,7 @@ static void mptcp_pm_nl_rm_addr_or_subflow(struct mptcp_sock *msk,
                        removed = true;
                        __MPTCP_INC_STATS(sock_net(sk), rm_type);
                }
-               __set_bit(rm_list->ids[1], msk->pm.id_avail_bitmap);
+               __set_bit(rm_list->ids[i], msk->pm.id_avail_bitmap);
                if (!removed)
                        continue;
 
@@ -911,6 +925,7 @@ out:
 static int mptcp_pm_nl_create_listen_socket(struct sock *sk,
                                            struct mptcp_pm_addr_entry *entry)
 {
+       int addrlen = sizeof(struct sockaddr_in);
        struct sockaddr_storage addr;
        struct mptcp_sock *msk;
        struct socket *ssock;
@@ -935,8 +950,11 @@ static int mptcp_pm_nl_create_listen_socket(struct sock *sk,
        }
 
        mptcp_info2sockaddr(&entry->addr, &addr, entry->addr.family);
-       err = kernel_bind(ssock, (struct sockaddr *)&addr,
-                         sizeof(struct sockaddr_in));
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+       if (entry->addr.family == AF_INET6)
+               addrlen = sizeof(struct sockaddr_in6);
+#endif
+       err = kernel_bind(ssock, (struct sockaddr *)&addr, addrlen);
        if (err) {
                pr_warn("kernel_bind error, err=%d", err);
                goto out;
@@ -1763,18 +1781,21 @@ static int mptcp_nl_cmd_set_flags(struct sk_buff *skb, struct genl_info *info)
                        return -EOPNOTSUPP;
        }
 
-       list_for_each_entry(entry, &pernet->local_addr_list, list) {
-               if ((!lookup_by_id && addresses_equal(&entry->addr, &addr.addr, true)) ||
-                   (lookup_by_id && entry->addr.id == addr.addr.id)) {
-                       mptcp_nl_addr_backup(net, &entry->addr, bkup);
-
-                       if (bkup)
-                               entry->flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
-                       else
-                               entry->flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP;
-               }
+       spin_lock_bh(&pernet->lock);
+       entry = __lookup_addr(pernet, &addr.addr, lookup_by_id);
+       if (!entry) {
+               spin_unlock_bh(&pernet->lock);
+               return -EINVAL;
        }
 
+       if (bkup)
+               entry->flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
+       else
+               entry->flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP;
+       addr = *entry;
+       spin_unlock_bh(&pernet->lock);
+
+       mptcp_nl_addr_backup(net, &addr.addr, bkup);
        return 0;
 }
 
index 0e6b42c..85317ce 100644 (file)
@@ -408,7 +408,7 @@ DECLARE_PER_CPU(struct mptcp_delegated_action, mptcp_delegated_actions);
 struct mptcp_subflow_context {
        struct  list_head node;/* conn_list of subflows */
 
-       char    reset_start[0];
+       struct_group(reset,
 
        unsigned long avg_pacing_rate; /* protected by msk socket lock */
        u64     local_key;
@@ -458,7 +458,7 @@ struct mptcp_subflow_context {
 
        long    delegated_status;
 
-       char    reset_end[0];
+       );
 
        struct  list_head delegated_node;   /* link into delegated_action, protected by local BH */
 
@@ -494,7 +494,7 @@ mptcp_subflow_tcp_sock(const struct mptcp_subflow_context *subflow)
 static inline void
 mptcp_subflow_ctx_reset(struct mptcp_subflow_context *subflow)
 {
-       memset(subflow->reset_start, 0, subflow->reset_end - subflow->reset_start);
+       memset(&subflow->reset, 0, sizeof(subflow->reset));
        subflow->request_mptcp = 1;
 }
 
index 894a325..d6aa5b4 100644 (file)
@@ -1924,15 +1924,17 @@ repeat:
                pr_debug("nf_conntrack_in: Can't track with proto module\n");
                nf_ct_put(ct);
                skb->_nfct = 0;
-               NF_CT_STAT_INC_ATOMIC(state->net, invalid);
-               if (ret == -NF_DROP)
-                       NF_CT_STAT_INC_ATOMIC(state->net, drop);
                /* Special case: TCP tracker reports an attempt to reopen a
                 * closed/aborted connection. We have to go back and create a
                 * fresh conntrack.
                 */
                if (ret == -NF_REPEAT)
                        goto repeat;
+
+               NF_CT_STAT_INC_ATOMIC(state->net, invalid);
+               if (ret == -NF_DROP)
+                       NF_CT_STAT_INC_ATOMIC(state->net, drop);
+
                ret = -ret;
                goto out;
        }
index 7f19ee2..55415f0 100644 (file)
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 
+#define HELPER_NAME    "netbios-ns"
 #define NMBD_PORT      137
 
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
 MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("ip_conntrack_netbios_ns");
-MODULE_ALIAS_NFCT_HELPER("netbios_ns");
+MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);
 
 static unsigned int timeout __read_mostly = 3;
 module_param(timeout, uint, 0400);
@@ -44,7 +45,7 @@ static int netbios_ns_help(struct sk_buff *skb, unsigned int protoff,
 }
 
 static struct nf_conntrack_helper helper __read_mostly = {
-       .name                   = "netbios-ns",
+       .name                   = HELPER_NAME,
        .tuple.src.l3num        = NFPROTO_IPV4,
        .tuple.src.u.udp.port   = cpu_to_be16(NMBD_PORT),
        .tuple.dst.protonum     = IPPROTO_UDP,
index ac43837..7032402 100644 (file)
@@ -2311,7 +2311,8 @@ ctnetlink_create_conntrack(struct net *net,
                        if (helper->from_nlattr)
                                helper->from_nlattr(helpinfo, ct);
 
-                       /* not in hash table yet so not strictly necessary */
+                       /* disable helper auto-assignment for this entry */
+                       ct->status |= IPS_HELPER;
                        RCU_INIT_POINTER(help->helper, helper);
                }
        } else {
index 2394238..5a93633 100644 (file)
@@ -489,6 +489,15 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
                        pr_debug("Setting vtag %x for dir %d\n",
                                 ih->init_tag, !dir);
                        ct->proto.sctp.vtag[!dir] = ih->init_tag;
+
+                       /* don't renew timeout on init retransmit so
+                        * port reuse by client or NAT middlebox cannot
+                        * keep entry alive indefinitely (incl. nat info).
+                        */
+                       if (new_state == SCTP_CONNTRACK_CLOSED &&
+                           old_state == SCTP_CONNTRACK_CLOSED &&
+                           nf_ct_is_confirmed(ct))
+                               ignore = true;
                }
 
                ct->proto.sctp.state = new_state;
index af5115e..d1582b8 100644 (file)
@@ -446,6 +446,32 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
        }
 }
 
+static void tcp_init_sender(struct ip_ct_tcp_state *sender,
+                           struct ip_ct_tcp_state *receiver,
+                           const struct sk_buff *skb,
+                           unsigned int dataoff,
+                           const struct tcphdr *tcph,
+                           u32 end, u32 win)
+{
+       /* SYN-ACK in reply to a SYN
+        * or SYN from reply direction in simultaneous open.
+        */
+       sender->td_end =
+       sender->td_maxend = end;
+       sender->td_maxwin = (win == 0 ? 1 : win);
+
+       tcp_options(skb, dataoff, tcph, sender);
+       /* RFC 1323:
+        * Both sides must send the Window Scale option
+        * to enable window scaling in either direction.
+        */
+       if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE &&
+             receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE)) {
+               sender->td_scale = 0;
+               receiver->td_scale = 0;
+       }
+}
+
 static bool tcp_in_window(struct nf_conn *ct,
                          enum ip_conntrack_dir dir,
                          unsigned int index,
@@ -499,24 +525,9 @@ static bool tcp_in_window(struct nf_conn *ct,
                 * Initialize sender data.
                 */
                if (tcph->syn) {
-                       /*
-                        * SYN-ACK in reply to a SYN
-                        * or SYN from reply direction in simultaneous open.
-                        */
-                       sender->td_end =
-                       sender->td_maxend = end;
-                       sender->td_maxwin = (win == 0 ? 1 : win);
-
-                       tcp_options(skb, dataoff, tcph, sender);
-                       /*
-                        * RFC 1323:
-                        * Both sides must send the Window Scale option
-                        * to enable window scaling in either direction.
-                        */
-                       if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE
-                             && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE))
-                               sender->td_scale =
-                               receiver->td_scale = 0;
+                       tcp_init_sender(sender, receiver,
+                                       skb, dataoff, tcph,
+                                       end, win);
                        if (!tcph->ack)
                                /* Simultaneous open */
                                return true;
@@ -560,6 +571,18 @@ static bool tcp_in_window(struct nf_conn *ct,
                sender->td_maxwin = (win == 0 ? 1 : win);
 
                tcp_options(skb, dataoff, tcph, sender);
+       } else if (tcph->syn && dir == IP_CT_DIR_REPLY &&
+                  state->state == TCP_CONNTRACK_SYN_SENT) {
+               /* Retransmitted syn-ack, or syn (simultaneous open).
+                *
+                * Re-init state for this direction, just like for the first
+                * syn(-ack) reply, it might differ in seq, ack or tcp options.
+                */
+               tcp_init_sender(sender, receiver,
+                               skb, dataoff, tcph,
+                               end, win);
+               if (!tcph->ack)
+                       return true;
        }
 
        if (!(tcph->ack)) {
index 77938b1..5fa1699 100644 (file)
@@ -2011,7 +2011,6 @@ static void nft_last_rule(struct nft_rule_blob *blob, const void *ptr)
 
        prule = (struct nft_rule_dp *)ptr;
        prule->is_last = 1;
-       ptr += offsetof(struct nft_rule_dp, data);
        /* blob size does not include the trailer rule */
 }
 
@@ -8264,14 +8263,12 @@ static int nf_tables_commit_chain_prepare(struct net *net, struct nft_chain *cha
        void *data, *data_boundary;
        struct nft_rule_dp *prule;
        struct nft_rule *rule;
-       int i;
 
        /* already handled or inactive chain? */
        if (chain->blob_next || !nft_is_active_next(net, chain))
                return 0;
 
        rule = list_entry(&chain->rules, struct nft_rule, list);
-       i = 0;
 
        data_size = 0;
        list_for_each_entry_continue(rule, &chain->rules, list) {
@@ -8301,7 +8298,7 @@ static int nf_tables_commit_chain_prepare(struct net *net, struct nft_chain *cha
                        return -ENOMEM;
 
                size = 0;
-               track.last = last;
+               track.last = nft_expr_last(rule);
                nft_rule_for_each_expr(expr, last, rule) {
                        track.cur = expr;
 
index 9d5947a..e646e9e 100644 (file)
@@ -167,12 +167,24 @@ nla_put_failure:
        return -1;
 }
 
+static bool nft_byteorder_reduce(struct nft_regs_track *track,
+                                const struct nft_expr *expr)
+{
+       struct nft_byteorder *priv = nft_expr_priv(expr);
+
+       track->regs[priv->dreg].selector = NULL;
+       track->regs[priv->dreg].bitwise = NULL;
+
+       return false;
+}
+
 static const struct nft_expr_ops nft_byteorder_ops = {
        .type           = &nft_byteorder_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_byteorder)),
        .eval           = nft_byteorder_eval,
        .init           = nft_byteorder_init,
        .dump           = nft_byteorder_dump,
+       .reduce         = nft_byteorder_reduce,
 };
 
 struct nft_expr_type nft_byteorder_type __read_mostly = {
index 7d00a14..3362417 100644 (file)
@@ -62,6 +62,7 @@ static int nft_connlimit_do_init(const struct nft_ctx *ctx,
 {
        bool invert = false;
        u32 flags, limit;
+       int err;
 
        if (!tb[NFTA_CONNLIMIT_COUNT])
                return -EINVAL;
@@ -84,7 +85,15 @@ static int nft_connlimit_do_init(const struct nft_ctx *ctx,
        priv->limit     = limit;
        priv->invert    = invert;
 
-       return nf_ct_netns_get(ctx->net, ctx->family);
+       err = nf_ct_netns_get(ctx->net, ctx->family);
+       if (err < 0)
+               goto err_netns;
+
+       return 0;
+err_netns:
+       kfree(priv->list);
+
+       return err;
 }
 
 static void nft_connlimit_do_destroy(const struct nft_ctx *ctx,
index 518d96c..5adf8bb 100644 (file)
@@ -260,9 +260,12 @@ static void nft_ct_set_zone_eval(const struct nft_expr *expr,
        ct = this_cpu_read(nft_ct_pcpu_template);
 
        if (likely(refcount_read(&ct->ct_general.use) == 1)) {
+               refcount_inc(&ct->ct_general.use);
                nf_ct_zone_add(ct, &zone);
        } else {
-               /* previous skb got queued to userspace */
+               /* previous skb got queued to userspace, allocate temporary
+                * one until percpu template can be reused.
+                */
                ct = nf_ct_tmpl_alloc(nft_net(pkt), &zone, GFP_ATOMIC);
                if (!ct) {
                        regs->verdict.code = NF_DROP;
index dbe1f2e..9e927ab 100644 (file)
@@ -167,7 +167,7 @@ nft_tcp_header_pointer(const struct nft_pktinfo *pkt,
 {
        struct tcphdr *tcph;
 
-       if (pkt->tprot != IPPROTO_TCP)
+       if (pkt->tprot != IPPROTO_TCP || pkt->fragoff)
                return NULL;
 
        tcph = skb_header_pointer(pkt->skb, nft_thoff(pkt), sizeof(*tcph), buffer);
index 940fed9..5cc06ae 100644 (file)
@@ -83,7 +83,7 @@ static int __nft_payload_inner_offset(struct nft_pktinfo *pkt)
 {
        unsigned int thoff = nft_thoff(pkt);
 
-       if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+       if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
                return -1;
 
        switch (pkt->tprot) {
@@ -147,7 +147,7 @@ void nft_payload_eval(const struct nft_expr *expr,
                offset = skb_network_offset(skb);
                break;
        case NFT_PAYLOAD_TRANSPORT_HEADER:
-               if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+               if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
                        goto err;
                offset = nft_thoff(pkt);
                break;
@@ -688,7 +688,7 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
                offset = skb_network_offset(skb);
                break;
        case NFT_PAYLOAD_TRANSPORT_HEADER:
-               if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+               if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
                        goto err;
                offset = nft_thoff(pkt);
                break;
@@ -728,7 +728,8 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
        if (priv->csum_type == NFT_PAYLOAD_CSUM_SCTP &&
            pkt->tprot == IPPROTO_SCTP &&
            skb->ip_summed != CHECKSUM_PARTIAL) {
-               if (nft_payload_csum_sctp(skb, nft_thoff(pkt)))
+               if (pkt->fragoff == 0 &&
+                   nft_payload_csum_sctp(skb, nft_thoff(pkt)))
                        goto err;
        }
 
index 5bd409a..ab87f22 100644 (file)
@@ -1774,6 +1774,7 @@ static int fanout_add(struct sock *sk, struct fanout_args *args)
                match->prot_hook.dev = po->prot_hook.dev;
                match->prot_hook.func = packet_rcv_fanout;
                match->prot_hook.af_packet_priv = match;
+               match->prot_hook.af_packet_net = read_pnet(&match->net);
                match->prot_hook.id_match = match_fanout_group;
                match->max_num_members = args->max_num_members;
                list_add(&match->list, &fanout_list);
@@ -1788,7 +1789,10 @@ static int fanout_add(struct sock *sk, struct fanout_args *args)
                err = -ENOSPC;
                if (refcount_read(&match->sk_ref) < match->max_num_members) {
                        __dev_remove_pack(&po->prot_hook);
-                       po->fanout = match;
+
+                       /* Paired with packet_setsockopt(PACKET_FANOUT_DATA) */
+                       WRITE_ONCE(po->fanout, match);
+
                        po->rollover = rollover;
                        rollover = NULL;
                        refcount_set(&match->sk_ref, refcount_read(&match->sk_ref) + 1);
@@ -3353,6 +3357,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
                po->prot_hook.func = packet_rcv_spkt;
 
        po->prot_hook.af_packet_priv = sk;
+       po->prot_hook.af_packet_net = sock_net(sk);
 
        if (proto) {
                po->prot_hook.type = proto;
@@ -3932,7 +3937,8 @@ packet_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval,
        }
        case PACKET_FANOUT_DATA:
        {
-               if (!po->fanout)
+               /* Paired with the WRITE_ONCE() in fanout_add() */
+               if (!READ_ONCE(po->fanout))
                        return -EINVAL;
 
                return fanout_set_data(po, optval, optlen);
index 6be2672..df864e6 100644 (file)
@@ -157,7 +157,7 @@ static void rxrpc_congestion_timeout(struct rxrpc_call *call)
 static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
 {
        struct sk_buff *skb;
-       unsigned long resend_at, rto_j;
+       unsigned long resend_at;
        rxrpc_seq_t cursor, seq, top;
        ktime_t now, max_age, oldest, ack_ts;
        int ix;
@@ -165,10 +165,8 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
 
        _enter("{%d,%d}", call->tx_hard_ack, call->tx_top);
 
-       rto_j = call->peer->rto_j;
-
        now = ktime_get_real();
-       max_age = ktime_sub(now, jiffies_to_usecs(rto_j));
+       max_age = ktime_sub(now, jiffies_to_usecs(call->peer->rto_j));
 
        spin_lock_bh(&call->lock);
 
@@ -213,7 +211,7 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
        }
 
        resend_at = nsecs_to_jiffies(ktime_to_ns(ktime_sub(now, oldest)));
-       resend_at += jiffies + rto_j;
+       resend_at += jiffies + rxrpc_get_rto_backoff(call->peer, retrans);
        WRITE_ONCE(call->resend_at, resend_at);
 
        if (unacked)
index 10f2bf2..a45c83f 100644 (file)
@@ -468,7 +468,7 @@ done:
                        if (call->peer->rtt_count > 1) {
                                unsigned long nowj = jiffies, ack_lost_at;
 
-                               ack_lost_at = rxrpc_get_rto_backoff(call->peer, retrans);
+                               ack_lost_at = rxrpc_get_rto_backoff(call->peer, false);
                                ack_lost_at += nowj;
                                WRITE_ONCE(call->ack_lost_at, ack_lost_at);
                                rxrpc_reduce_call_timer(call, ack_lost_at, nowj,
index d4e27c6..5f0f346 100644 (file)
@@ -1945,9 +1945,9 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
        bool prio_allocate;
        u32 parent;
        u32 chain_index;
-       struct Qdisc *q = NULL;
+       struct Qdisc *q;
        struct tcf_chain_info chain_info;
-       struct tcf_chain *chain = NULL;
+       struct tcf_chain *chain;
        struct tcf_block *block;
        struct tcf_proto *tp;
        unsigned long cl;
@@ -1976,6 +1976,8 @@ replay:
        tp = NULL;
        cl = 0;
        block = NULL;
+       q = NULL;
+       chain = NULL;
        flags = 0;
 
        if (prio == 0) {
@@ -2798,8 +2800,8 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n,
        struct tcmsg *t;
        u32 parent;
        u32 chain_index;
-       struct Qdisc *q = NULL;
-       struct tcf_chain *chain = NULL;
+       struct Qdisc *q;
+       struct tcf_chain *chain;
        struct tcf_block *block;
        unsigned long cl;
        int err;
@@ -2809,6 +2811,7 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n,
                return -EPERM;
 
 replay:
+       q = NULL;
        err = nlmsg_parse_deprecated(n, sizeof(*t), tca, TCA_MAX,
                                     rtm_tca_policy, extack);
        if (err < 0)
index 2cb496c..179825a 100644 (file)
@@ -1204,7 +1204,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
 
        err = -ENOENT;
        if (!ops) {
-               NL_SET_ERR_MSG(extack, "Specified qdisc not found");
+               NL_SET_ERR_MSG(extack, "Specified qdisc kind is unknown");
                goto err_out;
        }
 
index 9267922..23a9d62 100644 (file)
@@ -1810,6 +1810,26 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
        if (!hopt->rate.rate || !hopt->ceil.rate)
                goto failure;
 
+       if (q->offload) {
+               /* Options not supported by the offload. */
+               if (hopt->rate.overhead || hopt->ceil.overhead) {
+                       NL_SET_ERR_MSG(extack, "HTB offload doesn't support the overhead parameter");
+                       goto failure;
+               }
+               if (hopt->rate.mpu || hopt->ceil.mpu) {
+                       NL_SET_ERR_MSG(extack, "HTB offload doesn't support the mpu parameter");
+                       goto failure;
+               }
+               if (hopt->quantum) {
+                       NL_SET_ERR_MSG(extack, "HTB offload doesn't support the quantum parameter");
+                       goto failure;
+               }
+               if (hopt->prio) {
+                       NL_SET_ERR_MSG(extack, "HTB offload doesn't support the prio parameter");
+                       goto failure;
+               }
+       }
+
        /* Keeping backward compatible with rate_table based iproute2 tc */
        if (hopt->rate.linklayer == TC_LINKLAYER_UNAWARE)
                qdisc_put_rtab(qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB],
index 961854e..8c89d0b 100644 (file)
@@ -566,11 +566,114 @@ static void smc_stat_fallback(struct smc_sock *smc)
        mutex_unlock(&net->smc.mutex_fback_rsn);
 }
 
-static void smc_switch_to_fallback(struct smc_sock *smc, int reason_code)
+/* must be called under rcu read lock */
+static void smc_fback_wakeup_waitqueue(struct smc_sock *smc, void *key)
 {
-       wait_queue_head_t *smc_wait = sk_sleep(&smc->sk);
-       wait_queue_head_t *clc_wait = sk_sleep(smc->clcsock->sk);
-       unsigned long flags;
+       struct socket_wq *wq;
+       __poll_t flags;
+
+       wq = rcu_dereference(smc->sk.sk_wq);
+       if (!skwq_has_sleeper(wq))
+               return;
+
+       /* wake up smc sk->sk_wq */
+       if (!key) {
+               /* sk_state_change */
+               wake_up_interruptible_all(&wq->wait);
+       } else {
+               flags = key_to_poll(key);
+               if (flags & (EPOLLIN | EPOLLOUT))
+                       /* sk_data_ready or sk_write_space */
+                       wake_up_interruptible_sync_poll(&wq->wait, flags);
+               else if (flags & EPOLLERR)
+                       /* sk_error_report */
+                       wake_up_interruptible_poll(&wq->wait, flags);
+       }
+}
+
+static int smc_fback_mark_woken(wait_queue_entry_t *wait,
+                               unsigned int mode, int sync, void *key)
+{
+       struct smc_mark_woken *mark =
+               container_of(wait, struct smc_mark_woken, wait_entry);
+
+       mark->woken = true;
+       mark->key = key;
+       return 0;
+}
+
+static void smc_fback_forward_wakeup(struct smc_sock *smc, struct sock *clcsk,
+                                    void (*clcsock_callback)(struct sock *sk))
+{
+       struct smc_mark_woken mark = { .woken = false };
+       struct socket_wq *wq;
+
+       init_waitqueue_func_entry(&mark.wait_entry,
+                                 smc_fback_mark_woken);
+       rcu_read_lock();
+       wq = rcu_dereference(clcsk->sk_wq);
+       if (!wq)
+               goto out;
+       add_wait_queue(sk_sleep(clcsk), &mark.wait_entry);
+       clcsock_callback(clcsk);
+       remove_wait_queue(sk_sleep(clcsk), &mark.wait_entry);
+
+       if (mark.woken)
+               smc_fback_wakeup_waitqueue(smc, mark.key);
+out:
+       rcu_read_unlock();
+}
+
+static void smc_fback_state_change(struct sock *clcsk)
+{
+       struct smc_sock *smc =
+               smc_clcsock_user_data(clcsk);
+
+       if (!smc)
+               return;
+       smc_fback_forward_wakeup(smc, clcsk, smc->clcsk_state_change);
+}
+
+static void smc_fback_data_ready(struct sock *clcsk)
+{
+       struct smc_sock *smc =
+               smc_clcsock_user_data(clcsk);
+
+       if (!smc)
+               return;
+       smc_fback_forward_wakeup(smc, clcsk, smc->clcsk_data_ready);
+}
+
+static void smc_fback_write_space(struct sock *clcsk)
+{
+       struct smc_sock *smc =
+               smc_clcsock_user_data(clcsk);
+
+       if (!smc)
+               return;
+       smc_fback_forward_wakeup(smc, clcsk, smc->clcsk_write_space);
+}
+
+static void smc_fback_error_report(struct sock *clcsk)
+{
+       struct smc_sock *smc =
+               smc_clcsock_user_data(clcsk);
+
+       if (!smc)
+               return;
+       smc_fback_forward_wakeup(smc, clcsk, smc->clcsk_error_report);
+}
+
+static int smc_switch_to_fallback(struct smc_sock *smc, int reason_code)
+{
+       struct sock *clcsk;
+
+       mutex_lock(&smc->clcsock_release_lock);
+       if (!smc->clcsock) {
+               mutex_unlock(&smc->clcsock_release_lock);
+               return -EBADF;
+       }
+       clcsk = smc->clcsock->sk;
 
        smc->use_fallback = true;
        smc->fallback_rsn = reason_code;
@@ -582,22 +685,40 @@ static void smc_switch_to_fallback(struct smc_sock *smc, int reason_code)
                smc->clcsock->wq.fasync_list =
                        smc->sk.sk_socket->wq.fasync_list;
 
-               /* There may be some entries remaining in
-                * smc socket->wq, which should be removed
-                * to clcsocket->wq during the fallback.
+               /* There might be some wait entries remaining
+                * in smc sk->sk_wq and they should be woken up
+                * as clcsock's wait queue is woken up.
                 */
-               spin_lock_irqsave(&smc_wait->lock, flags);
-               spin_lock_nested(&clc_wait->lock, SINGLE_DEPTH_NESTING);
-               list_splice_init(&smc_wait->head, &clc_wait->head);
-               spin_unlock(&clc_wait->lock);
-               spin_unlock_irqrestore(&smc_wait->lock, flags);
+               smc->clcsk_state_change = clcsk->sk_state_change;
+               smc->clcsk_data_ready = clcsk->sk_data_ready;
+               smc->clcsk_write_space = clcsk->sk_write_space;
+               smc->clcsk_error_report = clcsk->sk_error_report;
+
+               clcsk->sk_state_change = smc_fback_state_change;
+               clcsk->sk_data_ready = smc_fback_data_ready;
+               clcsk->sk_write_space = smc_fback_write_space;
+               clcsk->sk_error_report = smc_fback_error_report;
+
+               smc->clcsock->sk->sk_user_data =
+                       (void *)((uintptr_t)smc | SK_USER_DATA_NOCOPY);
        }
+       mutex_unlock(&smc->clcsock_release_lock);
+       return 0;
 }
 
 /* fall back during connect */
 static int smc_connect_fallback(struct smc_sock *smc, int reason_code)
 {
-       smc_switch_to_fallback(smc, reason_code);
+       struct net *net = sock_net(&smc->sk);
+       int rc = 0;
+
+       rc = smc_switch_to_fallback(smc, reason_code);
+       if (rc) { /* fallback fails */
+               this_cpu_inc(net->smc.smc_stats->clnt_hshake_err_cnt);
+               if (smc->sk.sk_state == SMC_INIT)
+                       sock_put(&smc->sk); /* passive closing */
+               return rc;
+       }
        smc_copy_sock_settings_to_clc(smc);
        smc->connect_nonblock = 0;
        if (smc->sk.sk_state == SMC_INIT)
@@ -1518,11 +1639,12 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code,
 {
        /* RDMA setup failed, switch back to TCP */
        smc_conn_abort(new_smc, local_first);
-       if (reason_code < 0) { /* error, no fallback possible */
+       if (reason_code < 0 ||
+           smc_switch_to_fallback(new_smc, reason_code)) {
+               /* error, no fallback possible */
                smc_listen_out_err(new_smc);
                return;
        }
-       smc_switch_to_fallback(new_smc, reason_code);
        if (reason_code && reason_code != SMC_CLC_DECL_PEERDECL) {
                if (smc_clc_send_decline(new_smc, reason_code, version) < 0) {
                        smc_listen_out_err(new_smc);
@@ -1964,8 +2086,11 @@ static void smc_listen_work(struct work_struct *work)
 
        /* check if peer is smc capable */
        if (!tcp_sk(newclcsock->sk)->syn_smc) {
-               smc_switch_to_fallback(new_smc, SMC_CLC_DECL_PEERNOSMC);
-               smc_listen_out_connected(new_smc);
+               rc = smc_switch_to_fallback(new_smc, SMC_CLC_DECL_PEERNOSMC);
+               if (rc)
+                       smc_listen_out_err(new_smc);
+               else
+                       smc_listen_out_connected(new_smc);
                return;
        }
 
@@ -2094,10 +2219,9 @@ out:
 
 static void smc_clcsock_data_ready(struct sock *listen_clcsock)
 {
-       struct smc_sock *lsmc;
+       struct smc_sock *lsmc =
+               smc_clcsock_user_data(listen_clcsock);
 
-       lsmc = (struct smc_sock *)
-              ((uintptr_t)listen_clcsock->sk_user_data & ~SK_USER_DATA_NOCOPY);
        if (!lsmc)
                return;
        lsmc->clcsk_data_ready(listen_clcsock);
@@ -2254,7 +2378,9 @@ static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 
        if (msg->msg_flags & MSG_FASTOPEN) {
                if (sk->sk_state == SMC_INIT && !smc->connect_nonblock) {
-                       smc_switch_to_fallback(smc, SMC_CLC_DECL_OPTUNSUPP);
+                       rc = smc_switch_to_fallback(smc, SMC_CLC_DECL_OPTUNSUPP);
+                       if (rc)
+                               goto out;
                } else {
                        rc = -EINVAL;
                        goto out;
@@ -2447,6 +2573,11 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
        /* generic setsockopts reaching us here always apply to the
         * CLC socket
         */
+       mutex_lock(&smc->clcsock_release_lock);
+       if (!smc->clcsock) {
+               mutex_unlock(&smc->clcsock_release_lock);
+               return -EBADF;
+       }
        if (unlikely(!smc->clcsock->ops->setsockopt))
                rc = -EOPNOTSUPP;
        else
@@ -2456,6 +2587,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
                sk->sk_err = smc->clcsock->sk->sk_err;
                sk_error_report(sk);
        }
+       mutex_unlock(&smc->clcsock_release_lock);
 
        if (optlen < sizeof(int))
                return -EINVAL;
@@ -2472,7 +2604,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
        case TCP_FASTOPEN_NO_COOKIE:
                /* option not supported by SMC */
                if (sk->sk_state == SMC_INIT && !smc->connect_nonblock) {
-                       smc_switch_to_fallback(smc, SMC_CLC_DECL_OPTUNSUPP);
+                       rc = smc_switch_to_fallback(smc, SMC_CLC_DECL_OPTUNSUPP);
                } else {
                        rc = -EINVAL;
                }
@@ -2515,13 +2647,23 @@ static int smc_getsockopt(struct socket *sock, int level, int optname,
                          char __user *optval, int __user *optlen)
 {
        struct smc_sock *smc;
+       int rc;
 
        smc = smc_sk(sock->sk);
+       mutex_lock(&smc->clcsock_release_lock);
+       if (!smc->clcsock) {
+               mutex_unlock(&smc->clcsock_release_lock);
+               return -EBADF;
+       }
        /* socket options apply to the CLC socket */
-       if (unlikely(!smc->clcsock->ops->getsockopt))
+       if (unlikely(!smc->clcsock->ops->getsockopt)) {
+               mutex_unlock(&smc->clcsock_release_lock);
                return -EOPNOTSUPP;
-       return smc->clcsock->ops->getsockopt(smc->clcsock, level, optname,
-                                            optval, optlen);
+       }
+       rc = smc->clcsock->ops->getsockopt(smc->clcsock, level, optname,
+                                          optval, optlen);
+       mutex_unlock(&smc->clcsock_release_lock);
+       return rc;
 }
 
 static int smc_ioctl(struct socket *sock, unsigned int cmd,
index 3d0b8e3..37b2001 100644 (file)
@@ -139,6 +139,12 @@ enum smc_urg_state {
        SMC_URG_READ    = 3,                    /* data was already read */
 };
 
+struct smc_mark_woken {
+       bool woken;
+       void *key;
+       wait_queue_entry_t wait_entry;
+};
+
 struct smc_connection {
        struct rb_node          alert_node;
        struct smc_link_group   *lgr;           /* link group of connection */
@@ -228,8 +234,14 @@ struct smc_connection {
 struct smc_sock {                              /* smc sock container */
        struct sock             sk;
        struct socket           *clcsock;       /* internal tcp socket */
+       void                    (*clcsk_state_change)(struct sock *sk);
+                                               /* original stat_change fct. */
        void                    (*clcsk_data_ready)(struct sock *sk);
-                                               /* original data_ready fct. **/
+                                               /* original data_ready fct. */
+       void                    (*clcsk_write_space)(struct sock *sk);
+                                               /* original write_space fct. */
+       void                    (*clcsk_error_report)(struct sock *sk);
+                                               /* original error_report fct. */
        struct smc_connection   conn;           /* smc connection */
        struct smc_sock         *listen_smc;    /* listen parent */
        struct work_struct      connect_work;   /* handle non-blocking connect*/
@@ -264,6 +276,12 @@ static inline struct smc_sock *smc_sk(const struct sock *sk)
        return (struct smc_sock *)sk;
 }
 
+static inline struct smc_sock *smc_clcsock_user_data(struct sock *clcsk)
+{
+       return (struct smc_sock *)
+              ((uintptr_t)clcsk->sk_user_data & ~SK_USER_DATA_NOCOPY);
+}
+
 extern struct workqueue_struct *smc_hs_wq;     /* wq for handshake work */
 extern struct workqueue_struct *smc_close_wq;  /* wq for close work */
 
index b8898c7..1fca2f9 100644 (file)
@@ -146,13 +146,11 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
            (req->diag_ext & (1 << (SMC_DIAG_LGRINFO - 1))) &&
            !list_empty(&smc->conn.lgr->list)) {
                struct smc_link *link = smc->conn.lnk;
-               struct net *net = read_pnet(&link->smcibdev->ibdev->coredev.rdma_net);
 
                struct smc_diag_lgrinfo linfo = {
                        .role = smc->conn.lgr->role,
                        .lnk[0].ibport = link->ibport,
                        .lnk[0].link_id = link->link_id,
-                       .lnk[0].net_cookie = net->net_cookie,
                };
 
                memcpy(linfo.lnk[0].ibname,
index 291f148..0599246 100644 (file)
@@ -368,9 +368,6 @@ static int smc_pnet_add_eth(struct smc_pnettable *pnettable, struct net *net,
        new_pe->type = SMC_PNET_ETH;
        memcpy(new_pe->pnet_name, pnet_name, SMC_MAX_PNETID_LEN);
        strncpy(new_pe->eth_name, eth_name, IFNAMSIZ);
-       new_pe->ndev = ndev;
-       if (ndev)
-               netdev_tracker_alloc(ndev, &new_pe->dev_tracker, GFP_KERNEL);
        rc = -EEXIST;
        new_netdev = true;
        write_lock(&pnettable->lock);
@@ -382,6 +379,11 @@ static int smc_pnet_add_eth(struct smc_pnettable *pnettable, struct net *net,
                }
        }
        if (new_netdev) {
+               if (ndev) {
+                       new_pe->ndev = ndev;
+                       netdev_tracker_alloc(ndev, &new_pe->dev_tracker,
+                                            GFP_ATOMIC);
+               }
                list_add_tail(&new_pe->list, &pnettable->pnetlist);
                write_unlock(&pnettable->lock);
        } else {
index fe97f31..4a4082b 100644 (file)
@@ -222,10 +222,8 @@ g_verify_token_header(struct xdr_netobj *mech, int *body_size,
        if (ret)
                return ret;
 
-       if (!ret) {
-               *buf_in = buf;
-               *body_size = toksize;
-       }
+       *buf_in = buf;
+       *body_size = toksize;
 
        return ret;
 }
index a312ea2..c83fe61 100644 (file)
@@ -2900,7 +2900,7 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
        unsigned long connect_timeout;
        unsigned long reconnect_timeout;
        unsigned char resvport, reuseport;
-       int ret = 0;
+       int ret = 0, ident;
 
        rcu_read_lock();
        xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
@@ -2914,8 +2914,11 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
        reuseport = xprt->reuseport;
        connect_timeout = xprt->connect_timeout;
        reconnect_timeout = xprt->max_reconnect_timeout;
+       ident = xprt->xprt_class->ident;
        rcu_read_unlock();
 
+       if (!xprtargs->ident)
+               xprtargs->ident = ident;
        xprt = xprt_create_transport(xprtargs);
        if (IS_ERR(xprt)) {
                ret = PTR_ERR(xprt);
index ee5336d..35588f0 100644 (file)
@@ -600,9 +600,9 @@ static int __rpc_rmdir(struct inode *dir, struct dentry *dentry)
 
        dget(dentry);
        ret = simple_rmdir(dir, dentry);
+       d_drop(dentry);
        if (!ret)
                fsnotify_rmdir(dir, dentry);
-       d_delete(dentry);
        dput(dentry);
        return ret;
 }
@@ -613,9 +613,9 @@ static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
 
        dget(dentry);
        ret = simple_unlink(dir, dentry);
+       d_drop(dentry);
        if (!ret)
                fsnotify_unlink(dir, dentry);
-       d_delete(dentry);
        dput(dentry);
        return ret;
 }
index 2766dd2..05c758d 100644 (file)
@@ -115,11 +115,14 @@ static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,
        }
 
        sock = container_of(xprt, struct sock_xprt, xprt);
-       if (kernel_getsockname(sock->sock, (struct sockaddr *)&saddr) < 0)
+       mutex_lock(&sock->recv_mutex);
+       if (sock->sock == NULL ||
+           kernel_getsockname(sock->sock, (struct sockaddr *)&saddr) < 0)
                goto out;
 
        ret = sprintf(buf, "%pISc\n", &saddr);
 out:
+       mutex_unlock(&sock->recv_mutex);
        xprt_put(xprt);
        return ret + 1;
 }
@@ -295,8 +298,10 @@ static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
                online = 1;
        else if (!strncmp(buf, "remove", 6))
                remove = 1;
-       else
-               return -EINVAL;
+       else {
+               count = -EINVAL;
+               goto out_put;
+       }
 
        if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
                count = -EINTR;
@@ -307,25 +312,28 @@ static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
                goto release_tasks;
        }
        if (offline) {
-               set_bit(XPRT_OFFLINE, &xprt->state);
-               spin_lock(&xps->xps_lock);
-               xps->xps_nactive--;
-               spin_unlock(&xps->xps_lock);
+               if (!test_and_set_bit(XPRT_OFFLINE, &xprt->state)) {
+                       spin_lock(&xps->xps_lock);
+                       xps->xps_nactive--;
+                       spin_unlock(&xps->xps_lock);
+               }
        } else if (online) {
-               clear_bit(XPRT_OFFLINE, &xprt->state);
-               spin_lock(&xps->xps_lock);
-               xps->xps_nactive++;
-               spin_unlock(&xps->xps_lock);
+               if (test_and_clear_bit(XPRT_OFFLINE, &xprt->state)) {
+                       spin_lock(&xps->xps_lock);
+                       xps->xps_nactive++;
+                       spin_unlock(&xps->xps_lock);
+               }
        } else if (remove) {
                if (test_bit(XPRT_OFFLINE, &xprt->state)) {
-                       set_bit(XPRT_REMOVE, &xprt->state);
-                       xprt_force_disconnect(xprt);
-                       if (test_bit(XPRT_CONNECTED, &xprt->state)) {
-                               if (!xprt->sending.qlen &&
-                                   !xprt->pending.qlen &&
-                                   !xprt->backlog.qlen &&
-                                   !atomic_long_read(&xprt->queuelen))
-                                       rpc_xprt_switch_remove_xprt(xps, xprt);
+                       if (!test_and_set_bit(XPRT_REMOVE, &xprt->state)) {
+                               xprt_force_disconnect(xprt);
+                               if (test_bit(XPRT_CONNECTED, &xprt->state)) {
+                                       if (!xprt->sending.qlen &&
+                                           !xprt->pending.qlen &&
+                                           !xprt->backlog.qlen &&
+                                           !atomic_long_read(&xprt->queuelen))
+                                               rpc_xprt_switch_remove_xprt(xps, xprt);
+                               }
                        }
                } else {
                        count = -EINVAL;
@@ -422,6 +430,7 @@ static struct attribute *rpc_sysfs_xprt_attrs[] = {
        &rpc_sysfs_xprt_change_state.attr,
        NULL,
 };
+ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
 
 static struct kobj_attribute rpc_sysfs_xprt_switch_info =
        __ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
@@ -430,6 +439,7 @@ static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
        &rpc_sysfs_xprt_switch_info.attr,
        NULL,
 };
+ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch);
 
 static struct kobj_type rpc_sysfs_client_type = {
        .release = rpc_sysfs_client_release,
@@ -439,14 +449,14 @@ static struct kobj_type rpc_sysfs_client_type = {
 
 static struct kobj_type rpc_sysfs_xprt_switch_type = {
        .release = rpc_sysfs_xprt_switch_release,
-       .default_attrs = rpc_sysfs_xprt_switch_attrs,
+       .default_groups = rpc_sysfs_xprt_switch_groups,
        .sysfs_ops = &kobj_sysfs_ops,
        .namespace = rpc_sysfs_xprt_switch_namespace,
 };
 
 static struct kobj_type rpc_sysfs_xprt_type = {
        .release = rpc_sysfs_xprt_release,
-       .default_attrs = rpc_sysfs_xprt_attrs,
+       .default_groups = rpc_sysfs_xprt_groups,
        .sysfs_ops = &kobj_sysfs_ops,
        .namespace = rpc_sysfs_xprt_namespace,
 };
index 17f174d..faba713 100644 (file)
 #include "xprt_rdma.h"
 #include <trace/events/rpcrdma.h>
 
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-# define RPCDBG_FACILITY       RPCDBG_TRANS
-#endif
-
 #undef RPCRDMA_BACKCHANNEL_DEBUG
 
 /**
index ff69930..515dd7a 100644 (file)
 #include "xprt_rdma.h"
 #include <trace/events/rpcrdma.h>
 
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-# define RPCDBG_FACILITY       RPCDBG_TRANS
-#endif
-
 static void frwr_cid_init(struct rpcrdma_ep *ep,
                          struct rpcrdma_mr *mr)
 {
index 8035a98..281ddb8 100644 (file)
 #include "xprt_rdma.h"
 #include <trace/events/rpcrdma.h>
 
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-# define RPCDBG_FACILITY       RPCDBG_TRANS
-#endif
-
 /* Returns size of largest RPC-over-RDMA header in a Call message
  *
  * The largest Call header contains a full-size Read list and a
index 16e5696..42e375d 100644 (file)
 #include "xprt_rdma.h"
 #include <trace/events/rpcrdma.h>
 
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-# define RPCDBG_FACILITY       RPCDBG_TRANS
-#endif
-
 /*
  * tunables
  */
index 3d3673b..7b5fce2 100644 (file)
 #include "xprt_rdma.h"
 #include <trace/events/rpcrdma.h>
 
-/*
- * Globals/Macros
- */
-
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-# define RPCDBG_FACILITY       RPCDBG_TRANS
-#endif
-
-/*
- * internal functions
- */
 static int rpcrdma_sendctxs_create(struct rpcrdma_xprt *r_xprt);
 static void rpcrdma_sendctxs_destroy(struct rpcrdma_xprt *r_xprt);
 static void rpcrdma_sendctx_put_locked(struct rpcrdma_xprt *r_xprt,
@@ -274,8 +263,6 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
                ep->re_connect_status = -ENETUNREACH;
                goto wake_connect_worker;
        case RDMA_CM_EVENT_REJECTED:
-               dprintk("rpcrdma: connection to %pISpc rejected: %s\n",
-                       sap, rdma_reject_msg(id, event->status));
                ep->re_connect_status = -ECONNREFUSED;
                if (event->status == IB_CM_REJ_STALE_CONN)
                        ep->re_connect_status = -ENOTCONN;
@@ -291,8 +278,6 @@ disconnected:
                break;
        }
 
-       dprintk("RPC:       %s: %pISpc on %s/frwr: %s\n", __func__, sap,
-               ep->re_id->device->name, rdma_event_msg(event->event));
        return 0;
 }
 
@@ -419,14 +404,6 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
        ep->re_attr.qp_type = IB_QPT_RC;
        ep->re_attr.port_num = ~0;
 
-       dprintk("RPC:       %s: requested max: dtos: send %d recv %d; "
-               "iovs: send %d recv %d\n",
-               __func__,
-               ep->re_attr.cap.max_send_wr,
-               ep->re_attr.cap.max_recv_wr,
-               ep->re_attr.cap.max_send_sge,
-               ep->re_attr.cap.max_recv_sge);
-
        ep->re_send_batch = ep->re_max_requests >> 3;
        ep->re_send_count = ep->re_send_batch;
        init_waitqueue_head(&ep->re_connect_wait);
@@ -436,6 +413,7 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
                                              IB_POLL_WORKQUEUE);
        if (IS_ERR(ep->re_attr.send_cq)) {
                rc = PTR_ERR(ep->re_attr.send_cq);
+               ep->re_attr.send_cq = NULL;
                goto out_destroy;
        }
 
@@ -444,6 +422,7 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
                                              IB_POLL_WORKQUEUE);
        if (IS_ERR(ep->re_attr.recv_cq)) {
                rc = PTR_ERR(ep->re_attr.recv_cq);
+               ep->re_attr.recv_cq = NULL;
                goto out_destroy;
        }
        ep->re_receive_count = 0;
@@ -482,6 +461,7 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
        ep->re_pd = ib_alloc_pd(device, 0);
        if (IS_ERR(ep->re_pd)) {
                rc = PTR_ERR(ep->re_pd);
+               ep->re_pd = NULL;
                goto out_destroy;
        }
 
index d8ee06a..0f39e08 100644 (file)
@@ -1641,7 +1641,12 @@ static int xs_get_srcport(struct sock_xprt *transport)
 unsigned short get_srcport(struct rpc_xprt *xprt)
 {
        struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt);
-       return xs_sock_getport(sock->sock);
+       unsigned short ret = 0;
+       mutex_lock(&sock->recv_mutex);
+       if (sock->sock)
+               ret = xs_sock_getport(sock->sock);
+       mutex_unlock(&sock->recv_mutex);
+       return ret;
 }
 EXPORT_SYMBOL(get_srcport);
 
@@ -1910,7 +1915,7 @@ static void xs_local_connect(struct rpc_xprt *xprt, struct rpc_task *task)
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
        int ret;
 
-        if (RPC_IS_ASYNC(task)) {
+       if (RPC_IS_ASYNC(task)) {
                /*
                 * We want the AF_LOCAL connect to be resolved in the
                 * filesystem namespace of the process making the rpc
index 8d9e09f..1e14d7f 100644 (file)
@@ -2200,7 +2200,7 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
        struct tipc_msg *hdr = buf_msg(skb);
        struct tipc_gap_ack_blks *ga = NULL;
        bool reply = msg_probe(hdr), retransmitted = false;
-       u16 dlen = msg_data_sz(hdr), glen = 0;
+       u32 dlen = msg_data_sz(hdr), glen = 0;
        u16 peers_snd_nxt =  msg_next_sent(hdr);
        u16 peers_tol = msg_link_tolerance(hdr);
        u16 peers_prio = msg_linkprio(hdr);
@@ -2214,6 +2214,10 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
        void *data;
 
        trace_tipc_proto_rcv(skb, false, l->name);
+
+       if (dlen > U16_MAX)
+               goto exit;
+
        if (tipc_link_is_blocked(l) || !xmitq)
                goto exit;
 
@@ -2309,7 +2313,8 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
 
                /* Receive Gap ACK blocks from peer if any */
                glen = tipc_get_gap_ack_blks(&ga, l, hdr, true);
-
+               if(glen > dlen)
+                       break;
                tipc_mon_rcv(l->net, data + glen, dlen - glen, l->addr,
                             &l->mon_state, l->bearer_id);
 
index 4076196..2f4d232 100644 (file)
@@ -496,6 +496,8 @@ void tipc_mon_rcv(struct net *net, void *data, u16 dlen, u32 addr,
        state->probing = false;
 
        /* Sanity check received domain record */
+       if (new_member_cnt > MAX_MON_DOMAIN)
+               return;
        if (dlen < dom_rec_len(arrv_dom, 0))
                return;
        if (dlen != dom_rec_len(arrv_dom, new_member_cnt))
index bda902c..8267b75 100644 (file)
@@ -313,7 +313,7 @@ static bool tipc_update_nametbl(struct net *net, struct distr_item *i,
                pr_warn_ratelimited("Failed to remove binding %u,%u from %u\n",
                                    ua.sr.type, ua.sr.lower, node);
        } else {
-               pr_warn("Unrecognized name table message received\n");
+               pr_warn_ratelimited("Unknown name table message received\n");
        }
        return false;
 }
index cc0648e..4bca4b7 100644 (file)
@@ -25,7 +25,7 @@
 #include <sys/prctl.h>
 #include <unistd.h>
 
-static int install_filter(int nr, int arch, int error)
+static int install_filter(int arch, int nr, int error)
 {
        struct sock_filter filter[] = {
                BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
@@ -42,6 +42,10 @@ static int install_filter(int nr, int arch, int error)
                .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),
                .filter = filter,
        };
+       if (error == -1) {
+               struct sock_filter kill = BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL);
+               filter[4] = kill;
+       }
        if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
                perror("prctl(NO_NEW_PRIVS)");
                return 1;
@@ -57,9 +61,10 @@ int main(int argc, char **argv)
 {
        if (argc < 5) {
                fprintf(stderr, "Usage:\n"
-                       "dropper <syscall_nr> <arch> <errno> <prog> [<args>]\n"
+                       "dropper <arch> <syscall_nr> <errno> <prog> [<args>]\n"
                        "Hint:  AUDIT_ARCH_I386: 0x%X\n"
                        "       AUDIT_ARCH_X86_64: 0x%X\n"
+                       "       errno == -1 means SECCOMP_RET_KILL\n"
                        "\n", AUDIT_ARCH_I386, AUDIT_ARCH_X86_64);
                return 1;
        }
index ecd3aca..ce5aa90 100644 (file)
@@ -25,7 +25,7 @@ HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include
 HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED
 endif
 
-ifdef CONFIG_DYNAMIC_FTRACE
+ifdef CONFIG_BUILDTIME_MCOUNT_SORT
 HOSTCFLAGS_sorttable.o += -DMCOUNT_SORT_ENABLED
 endif
 
index d538255..8be8928 100644 (file)
@@ -51,6 +51,7 @@ 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
+KBUILD_CFLAGS += $(call cc-disable-warning, unaligned-access)
 endif
 
 endif
index 59717be..d3c3a61 100644 (file)
@@ -979,10 +979,10 @@ static int conf_write_autoconf_cmd(const char *autoconf_name)
 
        fprintf(out, "\n$(deps_config): ;\n");
 
-       if (ferror(out)) /* error check for all fprintf() calls */
-               return -1;
-
+       ret = ferror(out); /* error check for all fprintf() calls */
        fclose(out);
+       if (ret)
+               return -1;
 
        if (rename(tmp, name)) {
                perror("rename");
@@ -994,14 +994,19 @@ static int conf_write_autoconf_cmd(const char *autoconf_name)
 
 static int conf_touch_deps(void)
 {
-       const char *name;
+       const char *name, *tmp;
        struct symbol *sym;
        int res, i;
 
-       strcpy(depfile_path, "include/config/");
-       depfile_prefix_len = strlen(depfile_path);
-
        name = conf_get_autoconfig_name();
+       tmp = strrchr(name, '/');
+       depfile_prefix_len = tmp ? tmp - name + 1 : 0;
+       if (depfile_prefix_len + 1 > sizeof(depfile_path))
+               return -1;
+
+       strncpy(depfile_path, name, depfile_prefix_len);
+       depfile_path[depfile_prefix_len] = 0;
+
        conf_read_simple(name, S_DEF_AUTO);
        sym_calc_value(modules_sym);
 
@@ -1093,10 +1098,10 @@ static int __conf_write_autoconf(const char *filename,
                        print_symbol(file, sym);
 
        /* check possible errors in conf_write_heading() and print_symbol() */
-       if (ferror(file))
-               return -1;
-
+       ret = ferror(file);
        fclose(file);
+       if (ret)
+               return -1;
 
        if (rename(tmp, filename)) {
                perror("rename");
index 0590f86..748da57 100644 (file)
@@ -141,7 +141,7 @@ static char *do_lineno(int argc, char *argv[])
 static char *do_shell(int argc, char *argv[])
 {
        FILE *p;
-       char buf[256];
+       char buf[4096];
        char *cmd;
        size_t nread;
        int i;
index 23240d7..895f4b9 100644 (file)
@@ -109,22 +109,25 @@ int asymmetric_verify(struct key *keyring, const char *sig,
 
        pk = asymmetric_key_public_key(key);
        pks.pkey_algo = pk->pkey_algo;
-       if (!strcmp(pk->pkey_algo, "rsa"))
+       if (!strcmp(pk->pkey_algo, "rsa")) {
                pks.encoding = "pkcs1";
-       else if (!strncmp(pk->pkey_algo, "ecdsa-", 6))
+       } else if (!strncmp(pk->pkey_algo, "ecdsa-", 6)) {
                /* edcsa-nist-p192 etc. */
                pks.encoding = "x962";
-       else if (!strcmp(pk->pkey_algo, "ecrdsa") ||
-                  !strcmp(pk->pkey_algo, "sm2"))
+       else if (!strcmp(pk->pkey_algo, "ecrdsa") ||
+                  !strcmp(pk->pkey_algo, "sm2")) {
                pks.encoding = "raw";
-       else
-               return -ENOPKG;
+       } else {
+               ret = -ENOPKG;
+               goto out;
+       }
 
        pks.digest = (u8 *)data;
        pks.digest_size = datalen;
        pks.s = hdr->sig;
        pks.s_size = siglen;
        ret = verify_signature(key, &pks);
+out:
        key_put(key);
        pr_debug("%s() = %d\n", __func__, ret);
        return ret;
index 3d8e9d5..3ad8f77 100644 (file)
@@ -496,12 +496,12 @@ int __init ima_fs_init(void)
 
        return 0;
 out:
+       securityfs_remove(ima_policy);
        securityfs_remove(violations);
        securityfs_remove(runtime_measurements_count);
        securityfs_remove(ascii_runtime_measurements);
        securityfs_remove(binary_runtime_measurements);
        securityfs_remove(ima_symlink);
        securityfs_remove(ima_dir);
-       securityfs_remove(ima_policy);
        return -1;
 }
index 320ca80..2a1f641 100644 (file)
@@ -1967,6 +1967,14 @@ int ima_policy_show(struct seq_file *m, void *v)
 
        rcu_read_lock();
 
+       /* Do not print rules with inactive LSM labels */
+       for (i = 0; i < MAX_LSM_RULES; i++) {
+               if (entry->lsm[i].args_p && !entry->lsm[i].rule) {
+                       rcu_read_unlock();
+                       return 0;
+               }
+       }
+
        if (entry->action & MEASURE)
                seq_puts(m, pt(Opt_measure));
        if (entry->action & DONT_MEASURE)
index 6945603..db1ad6d 100644 (file)
@@ -29,6 +29,7 @@ static struct ima_template_desc builtin_templates[] = {
 
 static LIST_HEAD(defined_templates);
 static DEFINE_SPINLOCK(template_list);
+static int template_setup_done;
 
 static const struct ima_template_field supported_fields[] = {
        {.field_id = "d", .field_init = ima_eventdigest_init,
@@ -101,10 +102,11 @@ static int __init ima_template_setup(char *str)
        struct ima_template_desc *template_desc;
        int template_len = strlen(str);
 
-       if (ima_template)
+       if (template_setup_done)
                return 1;
 
-       ima_init_template_list();
+       if (!ima_template)
+               ima_init_template_list();
 
        /*
         * Verify that a template with the supplied name exists.
@@ -128,6 +130,7 @@ static int __init ima_template_setup(char *str)
        }
 
        ima_template = template_desc;
+       template_setup_done = 1;
        return 1;
 }
 __setup("ima_template=", ima_template_setup);
@@ -136,7 +139,7 @@ static int __init ima_template_fmt_setup(char *str)
 {
        int num_templates = ARRAY_SIZE(builtin_templates);
 
-       if (ima_template)
+       if (template_setup_done)
                return 1;
 
        if (template_desc_init_fields(str, NULL, NULL) < 0) {
@@ -147,6 +150,7 @@ static int __init ima_template_fmt_setup(char *str)
 
        builtin_templates[num_templates - 1].fmt = str;
        ima_template = builtin_templates + num_templates - 1;
+       template_setup_done = 1;
 
        return 1;
 }
index 2922005..0ec5e4c 100644 (file)
@@ -45,6 +45,8 @@ void integrity_audit_message(int audit_msgno, struct inode *inode,
                return;
 
        ab = audit_log_start(audit_context(), GFP_KERNEL, audit_msgno);
+       if (!ab)
+               return;
        audit_log_format(ab, "pid=%d uid=%u auid=%u ses=%u",
                         task_pid_nr(current),
                         from_kuid(&init_user_ns, current_uid()),
index 3d4eb47..22261d7 100644 (file)
@@ -1048,8 +1048,19 @@ int security_dentry_init_security(struct dentry *dentry, int mode,
                                  const char **xattr_name, void **ctx,
                                  u32 *ctxlen)
 {
-       return call_int_hook(dentry_init_security, -EOPNOTSUPP, dentry, mode,
-                               name, xattr_name, ctx, ctxlen);
+       struct security_hook_list *hp;
+       int rc;
+
+       /*
+        * Only one module will provide a security context.
+        */
+       hlist_for_each_entry(hp, &security_hook_heads.dentry_init_security, list) {
+               rc = hp->hook.dentry_init_security(dentry, mode, name,
+                                                  xattr_name, ctx, ctxlen);
+               if (rc != LSM_RET_DEFAULT(dentry_init_security))
+                       return rc;
+       }
+       return LSM_RET_DEFAULT(dentry_init_security);
 }
 EXPORT_SYMBOL(security_dentry_init_security);
 
index 2ec6e5c..feb206f 100644 (file)
@@ -152,6 +152,8 @@ static void cond_list_destroy(struct policydb *p)
        for (i = 0; i < p->cond_list_len; i++)
                cond_node_destroy(&p->cond_list[i]);
        kfree(p->cond_list);
+       p->cond_list = NULL;
+       p->cond_list_len = 0;
 }
 
 void cond_policydb_destroy(struct policydb *p)
@@ -441,7 +443,6 @@ int cond_read_list(struct policydb *p, void *fp)
        return 0;
 err:
        cond_list_destroy(p);
-       p->cond_list = NULL;
        return rc;
 }
 
index 621883e..a056b3e 100644 (file)
@@ -172,6 +172,19 @@ unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream)
 }
 EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave);
 
+unsigned long _snd_pcm_stream_lock_irqsave_nested(struct snd_pcm_substream *substream)
+{
+       unsigned long flags = 0;
+       if (substream->pcm->nonatomic)
+               mutex_lock_nested(&substream->self_group.mutex,
+                                 SINGLE_DEPTH_NESTING);
+       else
+               spin_lock_irqsave_nested(&substream->self_group.lock, flags,
+                                        SINGLE_DEPTH_NESTING);
+       return flags;
+}
+EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave_nested);
+
 /**
  * snd_pcm_stream_unlock_irqrestore - Unlock the PCM stream
  * @substream: PCM substream
index b7758db..5cb92f7 100644 (file)
@@ -50,11 +50,11 @@ static bool is_link_enabled(struct fwnode_handle *fw_node, int i)
 static int
 sdw_intel_scan_controller(struct sdw_intel_acpi_info *info)
 {
-       struct acpi_device *adev;
+       struct acpi_device *adev = acpi_fetch_acpi_dev(info->handle);
        int ret, i;
        u8 count;
 
-       if (acpi_bus_get_device(info->handle, &adev))
+       if (!adev)
                return -EINVAL;
 
        /* Found controller, find links supported */
@@ -119,7 +119,6 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
                                     void *cdata, void **return_value)
 {
        struct sdw_intel_acpi_info *info = cdata;
-       struct acpi_device *adev;
        acpi_status status;
        u64 adr;
 
@@ -127,7 +126,7 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
        if (ACPI_FAILURE(status))
                return AE_OK; /* keep going */
 
-       if (acpi_bus_get_device(handle, &adev)) {
+       if (!acpi_fetch_acpi_dev(handle)) {
                pr_err("%s: Couldn't find ACPI handle\n", __func__);
                return AE_NOT_FOUND;
        }
index 82c492b..cd1db94 100644 (file)
@@ -981,7 +981,7 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
        int id = HDA_FIXUP_ID_NOT_SET;
        const char *name = NULL;
        const char *type = NULL;
-       int vendor, device;
+       unsigned int vendor, device;
 
        if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET)
                return;
index 7016b48..f552785 100644 (file)
@@ -3000,6 +3000,10 @@ void snd_hda_codec_shutdown(struct hda_codec *codec)
 {
        struct hda_pcm *cpcm;
 
+       /* Skip the shutdown if codec is not registered */
+       if (!codec->registered)
+               return;
+
        list_for_each_entry(cpcm, &codec->pcm_list_head, list)
                snd_pcm_suspend_all(cpcm->pcm);
 
index 3bf5e34..fc114e5 100644 (file)
@@ -91,6 +91,12 @@ static void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
        free_kctls(spec);
        snd_array_free(&spec->paths);
        snd_array_free(&spec->loopback_list);
+#ifdef CONFIG_SND_HDA_GENERIC_LEDS
+       if (spec->led_cdevs[LED_AUDIO_MUTE])
+               led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MUTE]);
+       if (spec->led_cdevs[LED_AUDIO_MICMUTE])
+               led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MICMUTE]);
+#endif
 }
 
 /*
@@ -3922,7 +3928,10 @@ static int create_mute_led_cdev(struct hda_codec *codec,
                                                enum led_brightness),
                                bool micmute)
 {
+       struct hda_gen_spec *spec = codec->spec;
        struct led_classdev *cdev;
+       int idx = micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE;
+       int err;
 
        cdev = devm_kzalloc(&codec->core.dev, sizeof(*cdev), GFP_KERNEL);
        if (!cdev)
@@ -3932,10 +3941,14 @@ static int create_mute_led_cdev(struct hda_codec *codec,
        cdev->max_brightness = 1;
        cdev->default_trigger = micmute ? "audio-micmute" : "audio-mute";
        cdev->brightness_set_blocking = callback;
-       cdev->brightness = ledtrig_audio_get(micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE);
+       cdev->brightness = ledtrig_audio_get(idx);
        cdev->flags = LED_CORE_SUSPENDRESUME;
 
-       return devm_led_classdev_register(&codec->core.dev, cdev);
+       err = led_classdev_register(&codec->core.dev, cdev);
+       if (err < 0)
+               return err;
+       spec->led_cdevs[idx] = cdev;
+       return 0;
 }
 
 /**
index 8e1bc8e..34eba40 100644 (file)
@@ -294,6 +294,9 @@ struct hda_gen_spec {
                                   struct hda_jack_callback *cb);
        void (*mic_autoswitch_hook)(struct hda_codec *codec,
                                    struct hda_jack_callback *cb);
+
+       /* leds */
+       struct led_classdev *led_cdevs[NUM_AUDIO_LEDS];
 };
 
 /* values for add_stereo_mix_input flag */
index 668274e..8315bf7 100644 (file)
@@ -98,6 +98,7 @@ struct alc_spec {
        unsigned int gpio_mic_led_mask;
        struct alc_coef_led mute_led_coef;
        struct alc_coef_led mic_led_coef;
+       struct mutex coef_mutex;
 
        hda_nid_t headset_mic_pin;
        hda_nid_t headphone_mic_pin;
@@ -137,8 +138,8 @@ struct alc_spec {
  * COEF access helper functions
  */
 
-static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-                              unsigned int coef_idx)
+static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                unsigned int coef_idx)
 {
        unsigned int val;
 
@@ -147,28 +148,61 @@ static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
        return val;
 }
 
+static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                              unsigned int coef_idx)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int val;
+
+       mutex_lock(&spec->coef_mutex);
+       val = __alc_read_coefex_idx(codec, nid, coef_idx);
+       mutex_unlock(&spec->coef_mutex);
+       return val;
+}
+
 #define alc_read_coef_idx(codec, coef_idx) \
        alc_read_coefex_idx(codec, 0x20, coef_idx)
 
-static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-                                unsigned int coef_idx, unsigned int coef_val)
+static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                  unsigned int coef_idx, unsigned int coef_val)
 {
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val);
 }
 
+static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                unsigned int coef_idx, unsigned int coef_val)
+{
+       struct alc_spec *spec = codec->spec;
+
+       mutex_lock(&spec->coef_mutex);
+       __alc_write_coefex_idx(codec, nid, coef_idx, coef_val);
+       mutex_unlock(&spec->coef_mutex);
+}
+
 #define alc_write_coef_idx(codec, coef_idx, coef_val) \
        alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
 
+static void __alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                   unsigned int coef_idx, unsigned int mask,
+                                   unsigned int bits_set)
+{
+       unsigned int val = __alc_read_coefex_idx(codec, nid, coef_idx);
+
+       if (val != -1)
+               __alc_write_coefex_idx(codec, nid, coef_idx,
+                                      (val & ~mask) | bits_set);
+}
+
 static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
                                  unsigned int coef_idx, unsigned int mask,
                                  unsigned int bits_set)
 {
-       unsigned int val = alc_read_coefex_idx(codec, nid, coef_idx);
+       struct alc_spec *spec = codec->spec;
 
-       if (val != -1)
-               alc_write_coefex_idx(codec, nid, coef_idx,
-                                    (val & ~mask) | bits_set);
+       mutex_lock(&spec->coef_mutex);
+       __alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set);
+       mutex_unlock(&spec->coef_mutex);
 }
 
 #define alc_update_coef_idx(codec, coef_idx, mask, bits_set)   \
@@ -201,13 +235,17 @@ struct coef_fw {
 static void alc_process_coef_fw(struct hda_codec *codec,
                                const struct coef_fw *fw)
 {
+       struct alc_spec *spec = codec->spec;
+
+       mutex_lock(&spec->coef_mutex);
        for (; fw->nid; fw++) {
                if (fw->mask == (unsigned short)-1)
-                       alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
+                       __alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
                else
-                       alc_update_coefex_idx(codec, fw->nid, fw->idx,
-                                             fw->mask, fw->val);
+                       __alc_update_coefex_idx(codec, fw->nid, fw->idx,
+                                               fw->mask, fw->val);
        }
+       mutex_unlock(&spec->coef_mutex);
 }
 
 /*
@@ -1153,6 +1191,7 @@ static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
        codec->spdif_status_reset = 1;
        codec->forced_resume = 1;
        codec->patch_ops = alc_patch_ops;
+       mutex_init(&spec->coef_mutex);
 
        err = alc_codec_rename_from_preset(codec);
        if (err < 0) {
@@ -2125,6 +2164,7 @@ static void alc1220_fixup_gb_x570(struct hda_codec *codec,
 {
        static const hda_nid_t conn1[] = { 0x0c };
        static const struct coef_fw gb_x570_coefs[] = {
+               WRITE_COEF(0x07, 0x03c0),
                WRITE_COEF(0x1a, 0x01c1),
                WRITE_COEF(0x1b, 0x0202),
                WRITE_COEF(0x43, 0x3005),
@@ -2551,7 +2591,8 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
        SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
        SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_GB_X570),
-       SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_GB_X570),
+       SND_PCI_QUIRK(0x1458, 0xa0d5, "Gigabyte X570S Aorus Master", ALC1220_FIXUP_GB_X570),
        SND_PCI_QUIRK(0x1462, 0x11f7, "MSI-GE63", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1229, "MSI-GP73", ALC1220_FIXUP_CLEVO_P950),
@@ -2626,6 +2667,7 @@ static const struct hda_model_fixup alc882_fixup_models[] = {
        {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
        {.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"},
        {.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"},
+       {.id = ALC1220_FIXUP_GB_X570, .name = "gb-x570"},
        {.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"},
        {}
 };
@@ -8969,6 +9011,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS),
        SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
+       SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
        SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
index c9caade..cd05ee2 100644 (file)
@@ -303,11 +303,11 @@ static const struct snd_soc_dapm_route rt1019_map_lr[] = {
 
 static struct snd_soc_codec_conf rt1019_conf[] = {
        {
-                .dlc = COMP_CODEC_CONF("i2c-10EC1019:00"),
+                .dlc = COMP_CODEC_CONF("i2c-10EC1019:01"),
                 .name_prefix = "Left",
        },
        {
-                .dlc = COMP_CODEC_CONF("i2c-10EC1019:01"),
+                .dlc = COMP_CODEC_CONF("i2c-10EC1019:00"),
                 .name_prefix = "Right",
        },
 };
index 598e090..ffdf8b6 100644 (file)
@@ -1667,6 +1667,8 @@ static int cpcap_codec_probe(struct platform_device *pdev)
 {
        struct device_node *codec_node =
                of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec");
+       if (!codec_node)
+               return -ENODEV;
 
        pdev->dev.of_node = codec_node;
 
index b61f980..b07607a 100644 (file)
@@ -277,7 +277,7 @@ struct hdmi_codec_priv {
        bool busy;
        struct snd_soc_jack *jack;
        unsigned int jack_status;
-       u8 iec_status[5];
+       u8 iec_status[AES_IEC958_STATUS_SIZE];
 };
 
 static const struct snd_soc_dapm_widget hdmi_widgets[] = {
index aec5127..6ffe883 100644 (file)
@@ -2688,8 +2688,8 @@ static uint32_t get_iir_band_coeff(struct snd_soc_component *component,
        int reg, b2_reg;
 
        /* Address does not automatically update if reading */
-       reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
-       b2_reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
+       reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx;
+       b2_reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx;
 
        snd_soc_component_write(component, reg,
                                ((band_idx * BAND_MAX + coeff_idx) *
@@ -2718,7 +2718,7 @@ static uint32_t get_iir_band_coeff(struct snd_soc_component *component,
 static void set_iir_band_coeff(struct snd_soc_component *component,
                               int iir_idx, int band_idx, uint32_t value)
 {
-       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
+       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx;
 
        snd_soc_component_write(component, reg, (value & 0xFF));
        snd_soc_component_write(component, reg, (value >> 8) & 0xFF);
@@ -2739,7 +2739,7 @@ static int rx_macro_put_iir_band_audio_mixer(
        int iir_idx = ctl->iir_idx;
        int band_idx = ctl->band_idx;
        u32 coeff[BAND_MAX];
-       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
+       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx;
 
        memcpy(&coeff[0], ucontrol->value.bytes.data, params->max);
 
index d75fd61..bc57d76 100644 (file)
@@ -64,7 +64,8 @@ static int speaker_gain_control_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
        struct max9759 *priv = snd_soc_component_get_drvdata(c);
 
-       if (ucontrol->value.integer.value[0] > 3)
+       if (ucontrol->value.integer.value[0] < 0 ||
+           ucontrol->value.integer.value[0] > 3)
                return -EINVAL;
 
        priv->gain = ucontrol->value.integer.value[0];
index 20e0f90..20fc0f3 100644 (file)
@@ -59,18 +59,12 @@ static void rt5682_jd_check_handler(struct work_struct *work)
        struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv,
                jd_check_work.work);
 
-       if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL)
-               & RT5682_JDH_RS_MASK) {
+       if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) & RT5682_JDH_RS_MASK)
                /* jack out */
-               rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
-
-               snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
-                       SND_JACK_HEADSET |
-                       SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                       SND_JACK_BTN_2 | SND_JACK_BTN_3);
-       } else {
+               mod_delayed_work(system_power_efficient_wq,
+                                &rt5682->jack_detect_work, 0);
+       else
                schedule_delayed_work(&rt5682->jd_check_work, 500);
-       }
 }
 
 static irqreturn_t rt5682_irq(int irq, void *data)
@@ -198,7 +192,6 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
        }
 
        mutex_init(&rt5682->calibrate_mutex);
-       mutex_init(&rt5682->jdet_mutex);
        rt5682_calibrate(rt5682);
 
        rt5682_apply_patch_list(rt5682, &i2c->dev);
index 415ec56..0a0ec4a 100644 (file)
@@ -922,15 +922,13 @@ static void rt5682_enable_push_button_irq(struct snd_soc_component *component,
  *
  * Returns detect status.
  */
-int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
+static int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
 {
        struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
        struct snd_soc_dapm_context *dapm = &component->dapm;
        unsigned int val, count;
 
        if (jack_insert) {
-               snd_soc_dapm_mutex_lock(dapm);
-
                snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1,
                        RT5682_PWR_VREF2 | RT5682_PWR_MB,
                        RT5682_PWR_VREF2 | RT5682_PWR_MB);
@@ -981,8 +979,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
                snd_soc_component_update_bits(component, RT5682_MICBIAS_2,
                        RT5682_PWR_CLK25M_MASK | RT5682_PWR_CLK1M_MASK,
                        RT5682_PWR_CLK25M_PU | RT5682_PWR_CLK1M_PU);
-
-               snd_soc_dapm_mutex_unlock(dapm);
        } else {
                rt5682_enable_push_button_irq(component, false);
                snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
@@ -1011,7 +1007,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
        dev_dbg(component->dev, "jack_type = %d\n", rt5682->jack_type);
        return rt5682->jack_type;
 }
-EXPORT_SYMBOL_GPL(rt5682_headset_detect);
 
 static int rt5682_set_jack_detect(struct snd_soc_component *component,
                struct snd_soc_jack *hs_jack, void *data)
@@ -1094,6 +1089,7 @@ void rt5682_jack_detect_handler(struct work_struct *work)
 {
        struct rt5682_priv *rt5682 =
                container_of(work, struct rt5682_priv, jack_detect_work.work);
+       struct snd_soc_dapm_context *dapm;
        int val, btn_type;
 
        while (!rt5682->component)
@@ -1102,7 +1098,9 @@ void rt5682_jack_detect_handler(struct work_struct *work)
        while (!rt5682->component->card->instantiated)
                usleep_range(10000, 15000);
 
-       mutex_lock(&rt5682->jdet_mutex);
+       dapm = snd_soc_component_get_dapm(rt5682->component);
+
+       snd_soc_dapm_mutex_lock(dapm);
        mutex_lock(&rt5682->calibrate_mutex);
 
        val = snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL)
@@ -1162,6 +1160,9 @@ void rt5682_jack_detect_handler(struct work_struct *work)
                rt5682->irq_work_delay_time = 50;
        }
 
+       mutex_unlock(&rt5682->calibrate_mutex);
+       snd_soc_dapm_mutex_unlock(dapm);
+
        snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
                SND_JACK_HEADSET |
                SND_JACK_BTN_0 | SND_JACK_BTN_1 |
@@ -1174,9 +1175,6 @@ void rt5682_jack_detect_handler(struct work_struct *work)
                else
                        cancel_delayed_work_sync(&rt5682->jd_check_work);
        }
-
-       mutex_unlock(&rt5682->calibrate_mutex);
-       mutex_unlock(&rt5682->jdet_mutex);
 }
 EXPORT_SYMBOL_GPL(rt5682_jack_detect_handler);
 
@@ -1526,7 +1524,6 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_component *component =
                snd_soc_dapm_to_component(w->dapm);
-       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -1538,17 +1535,12 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
                        RT5682_DEPOP_1, 0x60, 0x60);
                snd_soc_component_update_bits(component,
                        RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080);
-
-               mutex_lock(&rt5682->jdet_mutex);
-
                snd_soc_component_update_bits(component, RT5682_HP_CTRL_2,
                        RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN,
                        RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN);
                usleep_range(5000, 10000);
                snd_soc_component_update_bits(component, RT5682_CHARGE_PUMP_1,
                        RT5682_CP_SW_SIZE_MASK, RT5682_CP_SW_SIZE_L);
-
-               mutex_unlock(&rt5682->jdet_mutex);
                break;
 
        case SND_SOC_DAPM_POST_PMD:
index c917c76..52ff0d9 100644 (file)
@@ -1463,7 +1463,6 @@ struct rt5682_priv {
 
        int jack_type;
        int irq_work_delay_time;
-       struct mutex jdet_mutex;
 };
 
 extern const char *rt5682_supply_names[RT5682_NUM_SUPPLIES];
@@ -1473,7 +1472,6 @@ int rt5682_sel_asrc_clk_src(struct snd_soc_component *component,
 
 void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev);
 
-int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert);
 void rt5682_jack_detect_handler(struct work_struct *work);
 
 bool rt5682_volatile_register(struct device *dev, unsigned int reg);
index eff200a..36cbc66 100644 (file)
@@ -1432,14 +1432,10 @@ static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info,
        return 0;
 }
 
-static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 ch_id, u8 enable)
+static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 port_num, u8 ch_id, u8 enable)
 {
-       u8 port_num;
-
-       port_num = wcd->ch_info[ch_id].port_num;
-
        return wcd938x_sdw_connect_port(&wcd->ch_info[ch_id],
-                                       &wcd->port_config[port_num],
+                                       &wcd->port_config[port_num - 1],
                                        enable);
 }
 
@@ -2563,7 +2559,7 @@ static int wcd938x_ear_pa_put_gain(struct snd_kcontrol *kcontrol,
                                      WCD938X_EAR_GAIN_MASK,
                                      ucontrol->value.integer.value[0]);
 
-       return 0;
+       return 1;
 }
 
 static int wcd938x_get_compander(struct snd_kcontrol *kcontrol,
@@ -2593,6 +2589,7 @@ static int wcd938x_set_compander(struct snd_kcontrol *kcontrol,
        struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
        struct wcd938x_sdw_priv *wcd;
        int value = ucontrol->value.integer.value[0];
+       int portidx;
        struct soc_mixer_control *mc;
        bool hphr;
 
@@ -2606,12 +2603,14 @@ static int wcd938x_set_compander(struct snd_kcontrol *kcontrol,
        else
                wcd938x->comp1_enable = value;
 
+       portidx = wcd->ch_info[mc->reg].port_num;
+
        if (value)
-               wcd938x_connect_port(wcd, mc->reg, true);
+               wcd938x_connect_port(wcd, portidx, mc->reg, true);
        else
-               wcd938x_connect_port(wcd, mc->reg, false);
+               wcd938x_connect_port(wcd, portidx, mc->reg, false);
 
-       return 0;
+       return 1;
 }
 
 static int wcd938x_ldoh_get(struct snd_kcontrol *kcontrol,
@@ -2882,9 +2881,11 @@ static int wcd938x_get_swr_port(struct snd_kcontrol *kcontrol,
        struct wcd938x_sdw_priv *wcd;
        struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
        int dai_id = mixer->shift;
-       int portidx = mixer->reg;
+       int portidx, ch_idx = mixer->reg;
+
 
        wcd = wcd938x->sdw_priv[dai_id];
+       portidx = wcd->ch_info[ch_idx].port_num;
 
        ucontrol->value.integer.value[0] = wcd->port_enable[portidx];
 
@@ -2899,12 +2900,14 @@ static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol,
        struct wcd938x_sdw_priv *wcd;
        struct soc_mixer_control *mixer =
                (struct soc_mixer_control *)kcontrol->private_value;
-       int portidx = mixer->reg;
+       int ch_idx = mixer->reg;
+       int portidx;
        int dai_id = mixer->shift;
        bool enable;
 
        wcd = wcd938x->sdw_priv[dai_id];
 
+       portidx = wcd->ch_info[ch_idx].port_num;
        if (ucontrol->value.integer.value[0])
                enable = true;
        else
@@ -2912,9 +2915,9 @@ static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol,
 
        wcd->port_enable[portidx] = enable;
 
-       wcd938x_connect_port(wcd, portidx, enable);
+       wcd938x_connect_port(wcd, portidx, ch_idx, enable);
 
-       return 0;
+       return 1;
 
 }
 
index af3c3b9..83b4a22 100644 (file)
@@ -93,16 +93,21 @@ static int pcm030_fabric_probe(struct platform_device *op)
                dev_err(&op->dev, "platform_device_alloc() failed\n");
 
        ret = platform_device_add(pdata->codec_device);
-       if (ret)
+       if (ret) {
                dev_err(&op->dev, "platform_device_add() failed: %d\n", ret);
+               platform_device_put(pdata->codec_device);
+       }
 
        ret = snd_soc_register_card(card);
-       if (ret)
+       if (ret) {
                dev_err(&op->dev, "snd_soc_register_card() failed: %d\n", ret);
+               platform_device_del(pdata->codec_device);
+               platform_device_put(pdata->codec_device);
+       }
 
        platform_set_drvdata(op, pdata);
-
        return ret;
+
 }
 
 static int pcm030_fabric_remove(struct platform_device *op)
index a89d1cf..78419e1 100644 (file)
@@ -28,6 +28,30 @@ static const struct snd_soc_ops simple_ops = {
        .hw_params      = asoc_simple_hw_params,
 };
 
+static int asoc_simple_parse_platform(struct device_node *node,
+                                     struct snd_soc_dai_link_component *dlc)
+{
+       struct of_phandle_args args;
+       int ret;
+
+       if (!node)
+               return 0;
+
+       /*
+        * Get node via "sound-dai = <&phandle port>"
+        * it will be used as xxx_of_node on soc_bind_dai_link()
+        */
+       ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
+       if (ret)
+               return ret;
+
+       /* dai_name is not required and may not exist for plat component */
+
+       dlc->of_node = args.np;
+
+       return 0;
+}
+
 static int asoc_simple_parse_dai(struct device_node *node,
                                 struct snd_soc_dai_link_component *dlc,
                                 int *is_single_link)
@@ -289,7 +313,7 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv,
        if (ret < 0)
                goto dai_link_of_err;
 
-       ret = asoc_simple_parse_dai(plat, platforms, NULL);
+       ret = asoc_simple_parse_platform(plat, platforms);
        if (ret < 0)
                goto dai_link_of_err;
 
index 9306b7c..0d15435 100644 (file)
@@ -216,7 +216,7 @@ config SND_SOC_MT8195_MT6359_RT1019_RT5682
 
 config SND_SOC_MT8195_MT6359_RT1011_RT5682
        tristate "ASoC Audio driver for MT8195 with MT6359 RT1011 RT5682 codec"
-       depends on I2C
+       depends on I2C && GPIOLIB
        depends on SND_SOC_MT8195 && MTK_PMIC_WRAP
        select SND_SOC_MT6359
        select SND_SOC_RT1011
index eb1c3ae..19c4a90 100644 (file)
@@ -308,8 +308,11 @@ static int q6apm_dai_close(struct snd_soc_component *component,
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct q6apm_dai_rtd *prtd = runtime->private_data;
 
-       q6apm_graph_stop(prtd->graph);
-       q6apm_unmap_memory_regions(prtd->graph, substream->stream);
+       if (prtd->state) { /* only stop graph that is started */
+               q6apm_graph_stop(prtd->graph);
+               q6apm_unmap_memory_regions(prtd->graph, substream->stream);
+       }
+
        q6apm_graph_close(prtd->graph);
        prtd->graph = NULL;
        kfree(prtd);
index cbd7ea4..142476f 100644 (file)
@@ -55,16 +55,13 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_find_machine);
 static acpi_status snd_soc_acpi_find_package(acpi_handle handle, u32 level,
                                             void *context, void **ret)
 {
-       struct acpi_device *adev;
+       struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
        acpi_status status;
        struct snd_soc_acpi_package_context *pkg_ctx = context;
 
        pkg_ctx->data_valid = false;
 
-       if (acpi_bus_get_device(handle, &adev))
-               return AE_OK;
-
-       if (adev->status.present && adev->status.functional) {
+       if (adev && adev->status.present && adev->status.functional) {
                struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
                union acpi_object  *myobj = NULL;
 
index 08eaa9d..9833611 100644 (file)
@@ -316,13 +316,27 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
        if (sign_bit)
                mask = BIT(sign_bit + 1) - 1;
 
-       val = ((ucontrol->value.integer.value[0] + min) & mask);
+       if (ucontrol->value.integer.value[0] < 0)
+               return -EINVAL;
+       val = ucontrol->value.integer.value[0];
+       if (mc->platform_max && val > mc->platform_max)
+               return -EINVAL;
+       if (val > max - min)
+               return -EINVAL;
+       val = (val + min) & mask;
        if (invert)
                val = max - val;
        val_mask = mask << shift;
        val = val << shift;
        if (snd_soc_volsw_is_stereo(mc)) {
-               val2 = ((ucontrol->value.integer.value[1] + min) & mask);
+               if (ucontrol->value.integer.value[1] < 0)
+                       return -EINVAL;
+               val2 = ucontrol->value.integer.value[1];
+               if (mc->platform_max && val2 > mc->platform_max)
+                       return -EINVAL;
+               if (val2 > max - min)
+                       return -EINVAL;
+               val2 = (val2 + min) & mask;
                if (invert)
                        val2 = max - val2;
                if (reg == reg2) {
@@ -409,8 +423,15 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
        int err = 0;
        unsigned int val, val_mask;
 
+       if (ucontrol->value.integer.value[0] < 0)
+               return -EINVAL;
+       val = ucontrol->value.integer.value[0];
+       if (mc->platform_max && val > mc->platform_max)
+               return -EINVAL;
+       if (val > max - min)
+               return -EINVAL;
        val_mask = mask << shift;
-       val = (ucontrol->value.integer.value[0] + min) & mask;
+       val = (val + min) & mask;
        val = val << shift;
 
        err = snd_soc_component_update_bits(component, reg, val_mask, val);
@@ -858,6 +879,8 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
        long val = ucontrol->value.integer.value[0];
        unsigned int i;
 
+       if (val < mc->min || val > mc->max)
+               return -EINVAL;
        if (invert)
                val = max - val;
        val &= mask;
index 7abfc48..9a95468 100644 (file)
@@ -46,8 +46,8 @@ static inline void snd_soc_dpcm_stream_lock_irq(struct snd_soc_pcm_runtime *rtd,
        snd_pcm_stream_lock_irq(snd_soc_dpcm_get_substream(rtd, stream));
 }
 
-#define snd_soc_dpcm_stream_lock_irqsave(rtd, stream, flags) \
-       snd_pcm_stream_lock_irqsave(snd_soc_dpcm_get_substream(rtd, stream), flags)
+#define snd_soc_dpcm_stream_lock_irqsave_nested(rtd, stream, flags) \
+       snd_pcm_stream_lock_irqsave_nested(snd_soc_dpcm_get_substream(rtd, stream), flags)
 
 static inline void snd_soc_dpcm_stream_unlock_irq(struct snd_soc_pcm_runtime *rtd,
                                                  int stream)
@@ -1268,6 +1268,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
 void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
 {
        struct snd_soc_dpcm *dpcm, *d;
+       LIST_HEAD(deleted_dpcms);
 
        snd_soc_dpcm_mutex_assert_held(fe);
 
@@ -1287,13 +1288,18 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
                /* BEs still alive need new FE */
                dpcm_be_reparent(fe, dpcm->be, stream);
 
-               dpcm_remove_debugfs_state(dpcm);
-
                list_del(&dpcm->list_be);
+               list_move(&dpcm->list_fe, &deleted_dpcms);
+       }
+       snd_soc_dpcm_stream_unlock_irq(fe, stream);
+
+       while (!list_empty(&deleted_dpcms)) {
+               dpcm = list_first_entry(&deleted_dpcms, struct snd_soc_dpcm,
+                                       list_fe);
                list_del(&dpcm->list_fe);
+               dpcm_remove_debugfs_state(dpcm);
                kfree(dpcm);
        }
-       snd_soc_dpcm_stream_unlock_irq(fe, stream);
 }
 
 /* get BE for DAI widget and stream */
@@ -2094,7 +2100,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                be = dpcm->be;
                be_substream = snd_soc_dpcm_get_substream(be, stream);
 
-               snd_soc_dpcm_stream_lock_irqsave(be, stream, flags);
+               snd_soc_dpcm_stream_lock_irqsave_nested(be, stream, flags);
 
                /* is this op for this BE ? */
                if (!snd_soc_dpcm_be_can_update(fe, be, stream))
index 91afea9..ce19a60 100644 (file)
@@ -37,6 +37,7 @@
 #define XLNX_AUD_XFER_COUNT    0x28
 #define XLNX_AUD_CH_STS_START  0x2C
 #define XLNX_BYTES_PER_CH      0x44
+#define XLNX_AUD_ALIGN_BYTES   64
 
 #define AUD_STS_IOC_IRQ_MASK   BIT(31)
 #define AUD_STS_CH_STS_MASK    BIT(29)
@@ -368,12 +369,32 @@ static int xlnx_formatter_pcm_open(struct snd_soc_component *component,
        snd_soc_set_runtime_hwparams(substream, &xlnx_pcm_hardware);
        runtime->private_data = stream_data;
 
-       /* Resize the period size divisible by 64 */
+       /* Resize the period bytes as divisible by 64 */
        err = snd_pcm_hw_constraint_step(runtime, 0,
-                                        SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
+                                        SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+                                        XLNX_AUD_ALIGN_BYTES);
        if (err) {
                dev_err(component->dev,
-                       "unable to set constraint on period bytes\n");
+                       "Unable to set constraint on period bytes\n");
+               return err;
+       }
+
+       /* Resize the buffer bytes as divisible by 64 */
+       err = snd_pcm_hw_constraint_step(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+                                        XLNX_AUD_ALIGN_BYTES);
+       if (err) {
+               dev_err(component->dev,
+                       "Unable to set constraint on buffer bytes\n");
+               return err;
+       }
+
+       /* Set periods as integer multiple */
+       err = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0) {
+               dev_err(component->dev,
+                       "Unable to set constraint on periods to be integer\n");
                return err;
        }
 
index e8f3f8d..630766b 100644 (file)
@@ -1527,6 +1527,10 @@ error:
                usb_audio_err(chip,
                        "cannot get connectors status: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
                        UAC_GET_CUR, validx, idx, cval->val_type);
+
+               if (val)
+                       *val = 0;
+
                return filter_error(cval, ret);
        }
 
index b1522e4..0ea3956 100644 (file)
@@ -84,7 +84,7 @@
  * combination.
  */
 {
-       USB_DEVICE(0x041e, 0x4095),
+       USB_AUDIO_DEVICE(0x041e, 0x4095),
        .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
                .ifnum = QUIRK_ANY_INTERFACE,
                .type = QUIRK_COMPOSITE,
index 18de5f7..6db4e29 100644 (file)
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX_VNNI           (12*32+ 4) /* AVX VNNI instructions */
 #define X86_FEATURE_AVX512_BF16                (12*32+ 5) /* AVX512 BFLOAT16 instructions */
+#define X86_FEATURE_AMX_BF16           (18*32+22) /* AMX bf16 Support */
 #define X86_FEATURE_AMX_TILE           (18*32+24) /* AMX tile Support */
+#define X86_FEATURE_AMX_INT8           (18*32+25) /* AMX int8 Support */
 
 /* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 13 */
 #define X86_FEATURE_CLZERO             (13*32+ 0) /* CLZERO instruction */
index 2da3316..bf6e960 100644 (file)
@@ -452,6 +452,9 @@ struct kvm_sync_regs {
 
 #define KVM_STATE_VMX_PREEMPTION_TIMER_DEADLINE        0x00000001
 
+/* attributes for system fd (group 0) */
+#define KVM_X86_XCOMP_GUEST_SUPP       0
+
 struct kvm_vmx_nested_state_data {
        __u8 vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
        __u8 shadow_vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
index 9ddeca9..320a88a 100644 (file)
@@ -9,7 +9,11 @@ ifeq ($(V),1)
   msg =
 else
   Q = @
-  msg = @printf '  %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
+  ifeq ($(silent),1)
+    msg =
+  else
+    msg = @printf '  %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
+  endif
   MAKEFLAGS=--no-print-directory
 endif
 
index ab9353f..9a5c1f0 100644 (file)
@@ -68,7 +68,7 @@ int handle__sched_switch(u64 *ctx)
         */
        struct task_struct *prev = (struct task_struct *)ctx[1];
        struct task_struct *next = (struct task_struct *)ctx[2];
-       struct event event = {};
+       struct runq_event event = {};
        u64 *tsp, delta_us;
        long state;
        u32 pid;
index 2414cc7..d78f414 100644 (file)
@@ -100,7 +100,7 @@ static int bump_memlock_rlimit(void)
 
 void handle_event(void *ctx, int cpu, void *data, __u32 data_sz)
 {
-       const struct event *e = data;
+       const struct runq_event *e = data;
        struct tm *tm;
        char ts[32];
        time_t t;
index 9db2254..4f70f07 100644 (file)
@@ -4,7 +4,7 @@
 
 #define TASK_COMM_LEN 16
 
-struct event {
+struct runq_event {
        char task[TASK_COMM_LEN];
        __u64 delta_us;
        pid_t pid;
index 9563d29..5191b57 100644 (file)
@@ -1133,6 +1133,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM 206
 #define KVM_CAP_VM_GPA_BITS 207
 #define KVM_CAP_XSAVE2 208
+#define KVM_CAP_SYS_ATTRIBUTES 209
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1623,9 +1624,6 @@ struct kvm_enc_region {
 #define KVM_S390_NORMAL_RESET  _IO(KVMIO,   0xc3)
 #define KVM_S390_CLEAR_RESET   _IO(KVMIO,   0xc4)
 
-/* Available with KVM_CAP_XSAVE2 */
-#define KVM_GET_XSAVE2           _IOR(KVMIO,  0xcf, struct kvm_xsave)
-
 struct kvm_s390_pv_sec_parm {
        __u64 origin;
        __u64 length;
@@ -2047,4 +2045,7 @@ struct kvm_stats_desc {
 
 #define KVM_GET_STATS_FD  _IO(KVMIO,  0xce)
 
+/* Available with KVM_CAP_XSAVE2 */
+#define KVM_GET_XSAVE2           _IOR(KVMIO,  0xcf, struct kvm_xsave)
+
 #endif /* __LINUX_KVM_H */
diff --git a/tools/include/uapi/linux/lirc.h b/tools/include/uapi/linux/lirc.h
deleted file mode 100644 (file)
index 45fcbf9..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * lirc.h - linux infrared remote control header file
- * last modified 2010/07/13 by Jarod Wilson
- */
-
-#ifndef _LINUX_LIRC_H
-#define _LINUX_LIRC_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-
-#define PULSE_BIT       0x01000000
-#define PULSE_MASK      0x00FFFFFF
-
-#define LIRC_MODE2_SPACE     0x00000000
-#define LIRC_MODE2_PULSE     0x01000000
-#define LIRC_MODE2_FREQUENCY 0x02000000
-#define LIRC_MODE2_TIMEOUT   0x03000000
-
-#define LIRC_VALUE_MASK      0x00FFFFFF
-#define LIRC_MODE2_MASK      0xFF000000
-
-#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE)
-#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE)
-#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY)
-#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT)
-
-#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK)
-#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK)
-
-#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE)
-#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE)
-#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY)
-#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT)
-
-/* used heavily by lirc userspace */
-#define lirc_t int
-
-/*** lirc compatible hardware features ***/
-
-#define LIRC_MODE2SEND(x) (x)
-#define LIRC_SEND2MODE(x) (x)
-#define LIRC_MODE2REC(x) ((x) << 16)
-#define LIRC_REC2MODE(x) ((x) >> 16)
-
-#define LIRC_MODE_RAW                  0x00000001
-#define LIRC_MODE_PULSE                0x00000002
-#define LIRC_MODE_MODE2                0x00000004
-#define LIRC_MODE_SCANCODE             0x00000008
-#define LIRC_MODE_LIRCCODE             0x00000010
-
-
-#define LIRC_CAN_SEND_RAW              LIRC_MODE2SEND(LIRC_MODE_RAW)
-#define LIRC_CAN_SEND_PULSE            LIRC_MODE2SEND(LIRC_MODE_PULSE)
-#define LIRC_CAN_SEND_MODE2            LIRC_MODE2SEND(LIRC_MODE_MODE2)
-#define LIRC_CAN_SEND_LIRCCODE         LIRC_MODE2SEND(LIRC_MODE_LIRCCODE)
-
-#define LIRC_CAN_SEND_MASK             0x0000003f
-
-#define LIRC_CAN_SET_SEND_CARRIER      0x00000100
-#define LIRC_CAN_SET_SEND_DUTY_CYCLE   0x00000200
-#define LIRC_CAN_SET_TRANSMITTER_MASK  0x00000400
-
-#define LIRC_CAN_REC_RAW               LIRC_MODE2REC(LIRC_MODE_RAW)
-#define LIRC_CAN_REC_PULSE             LIRC_MODE2REC(LIRC_MODE_PULSE)
-#define LIRC_CAN_REC_MODE2             LIRC_MODE2REC(LIRC_MODE_MODE2)
-#define LIRC_CAN_REC_SCANCODE          LIRC_MODE2REC(LIRC_MODE_SCANCODE)
-#define LIRC_CAN_REC_LIRCCODE          LIRC_MODE2REC(LIRC_MODE_LIRCCODE)
-
-#define LIRC_CAN_REC_MASK              LIRC_MODE2REC(LIRC_CAN_SEND_MASK)
-
-#define LIRC_CAN_SET_REC_CARRIER       (LIRC_CAN_SET_SEND_CARRIER << 16)
-#define LIRC_CAN_SET_REC_DUTY_CYCLE    (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16)
-
-#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000
-#define LIRC_CAN_SET_REC_CARRIER_RANGE    0x80000000
-#define LIRC_CAN_GET_REC_RESOLUTION       0x20000000
-#define LIRC_CAN_SET_REC_TIMEOUT          0x10000000
-#define LIRC_CAN_SET_REC_FILTER           0x08000000
-
-#define LIRC_CAN_MEASURE_CARRIER          0x02000000
-#define LIRC_CAN_USE_WIDEBAND_RECEIVER    0x04000000
-
-#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK)
-#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK)
-
-#define LIRC_CAN_NOTIFY_DECODE            0x01000000
-
-/*** IOCTL commands for lirc driver ***/
-
-#define LIRC_GET_FEATURES              _IOR('i', 0x00000000, __u32)
-
-#define LIRC_GET_SEND_MODE             _IOR('i', 0x00000001, __u32)
-#define LIRC_GET_REC_MODE              _IOR('i', 0x00000002, __u32)
-#define LIRC_GET_REC_RESOLUTION        _IOR('i', 0x00000007, __u32)
-
-#define LIRC_GET_MIN_TIMEOUT           _IOR('i', 0x00000008, __u32)
-#define LIRC_GET_MAX_TIMEOUT           _IOR('i', 0x00000009, __u32)
-
-/* code length in bits, currently only for LIRC_MODE_LIRCCODE */
-#define LIRC_GET_LENGTH                _IOR('i', 0x0000000f, __u32)
-
-#define LIRC_SET_SEND_MODE             _IOW('i', 0x00000011, __u32)
-#define LIRC_SET_REC_MODE              _IOW('i', 0x00000012, __u32)
-/* Note: these can reset the according pulse_width */
-#define LIRC_SET_SEND_CARRIER          _IOW('i', 0x00000013, __u32)
-#define LIRC_SET_REC_CARRIER           _IOW('i', 0x00000014, __u32)
-#define LIRC_SET_SEND_DUTY_CYCLE       _IOW('i', 0x00000015, __u32)
-#define LIRC_SET_TRANSMITTER_MASK      _IOW('i', 0x00000017, __u32)
-
-/*
- * when a timeout != 0 is set the driver will send a
- * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is
- * never sent, timeout is disabled by default
- */
-#define LIRC_SET_REC_TIMEOUT           _IOW('i', 0x00000018, __u32)
-
-/* 1 enables, 0 disables timeout reports in MODE2 */
-#define LIRC_SET_REC_TIMEOUT_REPORTS   _IOW('i', 0x00000019, __u32)
-
-/*
- * if enabled from the next key press on the driver will send
- * LIRC_MODE2_FREQUENCY packets
- */
-#define LIRC_SET_MEASURE_CARRIER_MODE  _IOW('i', 0x0000001d, __u32)
-
-/*
- * to set a range use LIRC_SET_REC_CARRIER_RANGE with the
- * lower bound first and later LIRC_SET_REC_CARRIER with the upper bound
- */
-#define LIRC_SET_REC_CARRIER_RANGE     _IOW('i', 0x0000001f, __u32)
-
-#define LIRC_SET_WIDEBAND_RECEIVER     _IOW('i', 0x00000023, __u32)
-
-/*
- * Return the recording timeout, which is either set by
- * the ioctl LIRC_SET_REC_TIMEOUT or by the kernel after setting the protocols.
- */
-#define LIRC_GET_REC_TIMEOUT          _IOR('i', 0x00000024, __u32)
-
-/*
- * struct lirc_scancode - decoded scancode with protocol for use with
- *     LIRC_MODE_SCANCODE
- *
- * @timestamp: Timestamp in nanoseconds using CLOCK_MONOTONIC when IR
- *     was decoded.
- * @flags: should be 0 for transmit. When receiving scancodes,
- *     LIRC_SCANCODE_FLAG_TOGGLE or LIRC_SCANCODE_FLAG_REPEAT can be set
- *     depending on the protocol
- * @rc_proto: see enum rc_proto
- * @keycode: the translated keycode. Set to 0 for transmit.
- * @scancode: the scancode received or to be sent
- */
-struct lirc_scancode {
-       __u64   timestamp;
-       __u16   flags;
-       __u16   rc_proto;
-       __u32   keycode;
-       __u64   scancode;
-};
-
-/* Set if the toggle bit of rc-5 or rc-6 is enabled */
-#define LIRC_SCANCODE_FLAG_TOGGLE      1
-/* Set if this is a nec or sanyo repeat */
-#define LIRC_SCANCODE_FLAG_REPEAT      2
-
-/**
- * enum rc_proto - the Remote Controller protocol
- *
- * @RC_PROTO_UNKNOWN: Protocol not known
- * @RC_PROTO_OTHER: Protocol known but proprietary
- * @RC_PROTO_RC5: Philips RC5 protocol
- * @RC_PROTO_RC5X_20: Philips RC5x 20 bit protocol
- * @RC_PROTO_RC5_SZ: StreamZap variant of RC5
- * @RC_PROTO_JVC: JVC protocol
- * @RC_PROTO_SONY12: Sony 12 bit protocol
- * @RC_PROTO_SONY15: Sony 15 bit protocol
- * @RC_PROTO_SONY20: Sony 20 bit protocol
- * @RC_PROTO_NEC: NEC protocol
- * @RC_PROTO_NECX: Extended NEC protocol
- * @RC_PROTO_NEC32: NEC 32 bit protocol
- * @RC_PROTO_SANYO: Sanyo protocol
- * @RC_PROTO_MCIR2_KBD: RC6-ish MCE keyboard
- * @RC_PROTO_MCIR2_MSE: RC6-ish MCE mouse
- * @RC_PROTO_RC6_0: Philips RC6-0-16 protocol
- * @RC_PROTO_RC6_6A_20: Philips RC6-6A-20 protocol
- * @RC_PROTO_RC6_6A_24: Philips RC6-6A-24 protocol
- * @RC_PROTO_RC6_6A_32: Philips RC6-6A-32 protocol
- * @RC_PROTO_RC6_MCE: MCE (Philips RC6-6A-32 subtype) protocol
- * @RC_PROTO_SHARP: Sharp protocol
- * @RC_PROTO_XMP: XMP protocol
- * @RC_PROTO_CEC: CEC protocol
- * @RC_PROTO_IMON: iMon Pad protocol
- * @RC_PROTO_RCMM12: RC-MM protocol 12 bits
- * @RC_PROTO_RCMM24: RC-MM protocol 24 bits
- * @RC_PROTO_RCMM32: RC-MM protocol 32 bits
- */
-enum rc_proto {
-       RC_PROTO_UNKNOWN        = 0,
-       RC_PROTO_OTHER          = 1,
-       RC_PROTO_RC5            = 2,
-       RC_PROTO_RC5X_20        = 3,
-       RC_PROTO_RC5_SZ         = 4,
-       RC_PROTO_JVC            = 5,
-       RC_PROTO_SONY12         = 6,
-       RC_PROTO_SONY15         = 7,
-       RC_PROTO_SONY20         = 8,
-       RC_PROTO_NEC            = 9,
-       RC_PROTO_NECX           = 10,
-       RC_PROTO_NEC32          = 11,
-       RC_PROTO_SANYO          = 12,
-       RC_PROTO_MCIR2_KBD      = 13,
-       RC_PROTO_MCIR2_MSE      = 14,
-       RC_PROTO_RC6_0          = 15,
-       RC_PROTO_RC6_6A_20      = 16,
-       RC_PROTO_RC6_6A_24      = 17,
-       RC_PROTO_RC6_6A_32      = 18,
-       RC_PROTO_RC6_MCE        = 19,
-       RC_PROTO_SHARP          = 20,
-       RC_PROTO_XMP            = 21,
-       RC_PROTO_CEC            = 22,
-       RC_PROTO_IMON           = 23,
-       RC_PROTO_RCMM12         = 24,
-       RC_PROTO_RCMM24         = 25,
-       RC_PROTO_RCMM32         = 26,
-};
-
-#endif
index 4cd39aa..1b65042 100644 (file)
@@ -1332,9 +1332,9 @@ union perf_mem_data_src {
 
 /* hop level */
 #define PERF_MEM_HOPS_0                0x01 /* remote core, same node */
-#define PERF_MEM_HOPS_1         0x02 /* remote node, same socket */
-#define PERF_MEM_HOPS_2         0x03 /* remote socket, same board */
-#define PERF_MEM_HOPS_3         0x04 /* remote board */
+#define PERF_MEM_HOPS_1                0x02 /* remote node, same socket */
+#define PERF_MEM_HOPS_2                0x03 /* remote socket, same board */
+#define PERF_MEM_HOPS_3                0x04 /* remote board */
 /* 5-7 available */
 #define PERF_MEM_HOPS_SHIFT    43
 
index bb73e9a..e998764 100644 (file)
@@ -272,4 +272,7 @@ struct prctl_mm_map {
 # define PR_SCHED_CORE_SCOPE_THREAD_GROUP      1
 # define PR_SCHED_CORE_SCOPE_PROCESS_GROUP     2
 
+#define PR_SET_VMA             0x53564d41
+# define PR_SET_VMA_ANON_NAME          0
+
 #endif /* _LINUX_PRCTL_H */
index 5fbb79e..2d3e5df 100644 (file)
  *                                                                          *
  ****************************************************************************/
 
+#define AES_IEC958_STATUS_SIZE         24
+
 struct snd_aes_iec958 {
-       unsigned char status[24];       /* AES/IEC958 channel status bits */
+       unsigned char status[AES_IEC958_STATUS_SIZE]; /* AES/IEC958 channel status bits */
        unsigned char subcode[147];     /* AES/IEC958 subcode bits */
        unsigned char pad;              /* nothing */
        unsigned char dig_subframe[4];  /* AES/IEC958 subframe bits */
@@ -202,6 +204,11 @@ typedef int __bitwise snd_pcm_format_t;
 #define        SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7) /* low three bytes */
 #define        SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8) /* low three bytes */
 #define        SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9) /* low three bytes */
+/*
+ * For S32/U32 formats, 'msbits' hardware parameter is often used to deliver information about the
+ * available bit count in most significant bit. It's for the case of so-called 'left-justified' or
+ * `right-padding` sample which has less width than 32 bit.
+ */
 #define        SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10)
 #define        SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11)
 #define        SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12)
@@ -300,7 +307,7 @@ typedef int __bitwise snd_pcm_subformat_t;
 #define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME    0x04000000  /* report estimated link audio time */
 #define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000  /* report synchronized audio/system time */
 #define SNDRV_PCM_INFO_EXPLICIT_SYNC   0x10000000      /* needs explicit sync of pointers and data */
-
+#define SNDRV_PCM_INFO_NO_REWINDS      0x20000000      /* hardware can only support monotonic changes of appl_ptr */
 #define SNDRV_PCM_INFO_DRAIN_TRIGGER   0x40000000              /* internal kernel flag - trigger in drain */
 #define SNDRV_PCM_INFO_FIFO_IN_FRAMES  0x80000000      /* internal kernel flag - FIFO size is in frames */
 
index f7ee07c..0d1634c 100644 (file)
@@ -13,6 +13,7 @@
 #include <internal/lib.h>
 #include <linux/kernel.h>
 #include <linux/math64.h>
+#include <linux/stringify.h>
 #include "internal.h"
 
 void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev,
@@ -294,6 +295,103 @@ static u64 read_timestamp(void)
 
        return low | ((u64)high) << 32;
 }
+#elif defined(__aarch64__)
+#define read_sysreg(r) ({                                              \
+       u64 __val;                                                      \
+       asm volatile("mrs %0, " __stringify(r) : "=r" (__val));         \
+       __val;                                                          \
+})
+
+static u64 read_pmccntr(void)
+{
+       return read_sysreg(pmccntr_el0);
+}
+
+#define PMEVCNTR_READ(idx)                                     \
+       static u64 read_pmevcntr_##idx(void) {                  \
+               return read_sysreg(pmevcntr##idx##_el0);        \
+       }
+
+PMEVCNTR_READ(0);
+PMEVCNTR_READ(1);
+PMEVCNTR_READ(2);
+PMEVCNTR_READ(3);
+PMEVCNTR_READ(4);
+PMEVCNTR_READ(5);
+PMEVCNTR_READ(6);
+PMEVCNTR_READ(7);
+PMEVCNTR_READ(8);
+PMEVCNTR_READ(9);
+PMEVCNTR_READ(10);
+PMEVCNTR_READ(11);
+PMEVCNTR_READ(12);
+PMEVCNTR_READ(13);
+PMEVCNTR_READ(14);
+PMEVCNTR_READ(15);
+PMEVCNTR_READ(16);
+PMEVCNTR_READ(17);
+PMEVCNTR_READ(18);
+PMEVCNTR_READ(19);
+PMEVCNTR_READ(20);
+PMEVCNTR_READ(21);
+PMEVCNTR_READ(22);
+PMEVCNTR_READ(23);
+PMEVCNTR_READ(24);
+PMEVCNTR_READ(25);
+PMEVCNTR_READ(26);
+PMEVCNTR_READ(27);
+PMEVCNTR_READ(28);
+PMEVCNTR_READ(29);
+PMEVCNTR_READ(30);
+
+/*
+ * Read a value direct from PMEVCNTR<idx>
+ */
+static u64 read_perf_counter(unsigned int counter)
+{
+       static u64 (* const read_f[])(void) = {
+               read_pmevcntr_0,
+               read_pmevcntr_1,
+               read_pmevcntr_2,
+               read_pmevcntr_3,
+               read_pmevcntr_4,
+               read_pmevcntr_5,
+               read_pmevcntr_6,
+               read_pmevcntr_7,
+               read_pmevcntr_8,
+               read_pmevcntr_9,
+               read_pmevcntr_10,
+               read_pmevcntr_11,
+               read_pmevcntr_13,
+               read_pmevcntr_12,
+               read_pmevcntr_14,
+               read_pmevcntr_15,
+               read_pmevcntr_16,
+               read_pmevcntr_17,
+               read_pmevcntr_18,
+               read_pmevcntr_19,
+               read_pmevcntr_20,
+               read_pmevcntr_21,
+               read_pmevcntr_22,
+               read_pmevcntr_23,
+               read_pmevcntr_24,
+               read_pmevcntr_25,
+               read_pmevcntr_26,
+               read_pmevcntr_27,
+               read_pmevcntr_28,
+               read_pmevcntr_29,
+               read_pmevcntr_30,
+               read_pmccntr
+       };
+
+       if (counter < ARRAY_SIZE(read_f))
+               return (read_f[counter])();
+
+       return 0;
+}
+
+static u64 read_timestamp(void) { return read_sysreg(cntvct_el0); }
+
 #else
 static u64 read_perf_counter(unsigned int counter __maybe_unused) { return 0; }
 static u64 read_timestamp(void) { return 0; }
index 33ae933..89be89a 100644 (file)
@@ -130,6 +130,9 @@ static int test_stat_user_read(int event)
        struct perf_event_attr attr = {
                .type   = PERF_TYPE_HARDWARE,
                .config = event,
+#ifdef __aarch64__
+               .config1 = 0x2,         /* Request user access */
+#endif
        };
        int err, i;
 
@@ -150,7 +153,7 @@ static int test_stat_user_read(int event)
        pc = perf_evsel__mmap_base(evsel, 0, 0);
        __T("failed to get mmapped address", pc);
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
        __T("userspace counter access not supported", pc->cap_user_rdpmc);
        __T("userspace counter access not enabled", pc->index);
        __T("userspace counter width not set", pc->pmc_width >= 32);
index c2d2ab9..7c33ec6 100644 (file)
@@ -2854,7 +2854,7 @@ static inline bool func_uaccess_safe(struct symbol *func)
 
 static inline const char *call_dest_name(struct instruction *insn)
 {
-       static char pvname[16];
+       static char pvname[19];
        struct reloc *rel;
        int idx;
 
index dec24dc..a8785de 100644 (file)
@@ -1115,6 +1115,7 @@ enum perf_ftrace_subcommand {
 int cmd_ftrace(int argc, const char **argv)
 {
        int ret;
+       int (*cmd_func)(struct perf_ftrace *) = NULL;
        struct perf_ftrace ftrace = {
                .tracer = DEFAULT_TRACER,
                .target = { .uid = UINT_MAX, },
@@ -1221,6 +1222,28 @@ int cmd_ftrace(int argc, const char **argv)
                goto out_delete_filters;
        }
 
+       switch (subcmd) {
+       case PERF_FTRACE_TRACE:
+               if (!argc && target__none(&ftrace.target))
+                       ftrace.target.system_wide = true;
+               cmd_func = __cmd_ftrace;
+               break;
+       case PERF_FTRACE_LATENCY:
+               if (list_empty(&ftrace.filters)) {
+                       pr_err("Should provide a function to measure\n");
+                       parse_options_usage(ftrace_usage, options, "T", 1);
+                       ret = -EINVAL;
+                       goto out_delete_filters;
+               }
+               cmd_func = __cmd_latency;
+               break;
+       case PERF_FTRACE_NONE:
+       default:
+               pr_err("Invalid subcommand\n");
+               ret = -EINVAL;
+               goto out_delete_filters;
+       }
+
        ret = target__validate(&ftrace.target);
        if (ret) {
                char errbuf[512];
@@ -1248,27 +1271,7 @@ int cmd_ftrace(int argc, const char **argv)
                        goto out_delete_evlist;
        }
 
-       switch (subcmd) {
-       case PERF_FTRACE_TRACE:
-               if (!argc && target__none(&ftrace.target))
-                       ftrace.target.system_wide = true;
-               ret = __cmd_ftrace(&ftrace);
-               break;
-       case PERF_FTRACE_LATENCY:
-               if (list_empty(&ftrace.filters)) {
-                       pr_err("Should provide a function to measure\n");
-                       parse_options_usage(ftrace_usage, options, "T", 1);
-                       ret = -EINVAL;
-                       goto out_delete_evlist;
-               }
-               ret = __cmd_latency(&ftrace);
-               break;
-       case PERF_FTRACE_NONE:
-       default:
-               pr_err("Invalid subcommand\n");
-               ret = -EINVAL;
-               break;
-       }
+       ret = cmd_func(&ftrace);
 
 out_delete_evlist:
        evlist__delete(ftrace.evlist);
index 3109d7b..3d27878 100755 (executable)
@@ -4,7 +4,7 @@
 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/
 
 printf "static const char *prctl_options[] = {\n"
-regex='^#define[[:space:]]+PR_(\w+)[[:space:]]*([[:xdigit:]]+).*'
+regex='^#define[[:space:]]{1}PR_(\w+)[[:space:]]*([[:xdigit:]]+)([[:space:]]*\/.*)?$'
 egrep $regex ${header_dir}/prctl.h | grep -v PR_SET_PTRACER | \
        sed -r "s/$regex/\2 \1/g"       | \
        sort -n | xargs printf "\t[%s] = \"%s\",\n"
index 0190068..8190a12 100644 (file)
@@ -2036,6 +2036,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
        memset(&objdump_process, 0, sizeof(objdump_process));
        objdump_process.argv = objdump_argv;
        objdump_process.out = -1;
+       objdump_process.err = -1;
        if (start_command(&objdump_process)) {
                pr_err("Failure starting to run %s\n", command);
                err = -1;
index 631e34a..ac60c08 100644 (file)
@@ -266,7 +266,7 @@ static int bperf_cgrp__read(struct evsel *evsel)
                idx = evsel->core.idx;
                err = bpf_map_lookup_elem(reading_map_fd, &idx, values);
                if (err) {
-                       pr_err("bpf map lookup falied: idx=%u, event=%s, cgrp=%s\n",
+                       pr_err("bpf map lookup failed: idx=%u, event=%s, cgrp=%s\n",
                               idx, evsel__name(evsel), evsel->cgrp->name);
                        goto out;
                }
index f70ba56..3945500 100644 (file)
@@ -2073,6 +2073,7 @@ static void ip__resolve_ams(struct thread *thread,
 
        ams->addr = ip;
        ams->al_addr = al.addr;
+       ams->al_level = al.level;
        ams->ms.maps = al.maps;
        ams->ms.sym = al.sym;
        ams->ms.map = al.map;
@@ -2092,6 +2093,7 @@ static void ip__resolve_data(struct thread *thread,
 
        ams->addr = addr;
        ams->al_addr = al.addr;
+       ams->al_level = al.level;
        ams->ms.maps = al.maps;
        ams->ms.sym = al.sym;
        ams->ms.map = al.map;
index 7d22ade..e08817b 100644 (file)
@@ -18,6 +18,7 @@ struct addr_map_symbol {
        struct map_symbol ms;
        u64           addr;
        u64           al_addr;
+       char          al_level;
        u64           phys_addr;
        u64           data_page_size;
 };
index 47b7531..98af3fa 100644 (file)
@@ -52,7 +52,7 @@ static void __p_branch_sample_type(char *buf, size_t size, u64 value)
                bit_name(ABORT_TX), bit_name(IN_TX), bit_name(NO_TX),
                bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP),
                bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES),
-               bit_name(HW_INDEX),
+               bit_name(TYPE_SAVE), bit_name(HW_INDEX),
                { .name = NULL, }
        };
 #undef bit_name
index 2c0d30f..498b057 100644 (file)
@@ -1503,11 +1503,12 @@ static int machines__deliver_event(struct machines *machines,
                        ++evlist->stats.nr_unknown_id;
                        return 0;
                }
-               dump_sample(evsel, event, sample, perf_env__arch(machine->env));
                if (machine == NULL) {
                        ++evlist->stats.nr_unprocessable_samples;
+                       dump_sample(evsel, event, sample, perf_env__arch(NULL));
                        return 0;
                }
+               dump_sample(evsel, event, sample, perf_env__arch(machine->env));
                return evlist__deliver_sample(evlist, tool, event, sample, evsel, machine);
        case PERF_RECORD_MMAP:
                return tool->mmap(tool, event, sample, machine);
index cfba8c3..2da081e 100644 (file)
@@ -915,7 +915,7 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
                struct addr_map_symbol *from = &he->branch_info->from;
 
                return _hist_entry__sym_snprintf(&from->ms, from->al_addr,
-                                                he->level, bf, size, width);
+                                                from->al_level, bf, size, width);
        }
 
        return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
@@ -928,7 +928,7 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
                struct addr_map_symbol *to = &he->branch_info->to;
 
                return _hist_entry__sym_snprintf(&to->ms, to->al_addr,
-                                                he->level, bf, size, width);
+                                                to->al_level, bf, size, width);
        }
 
        return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
index 5db83e5..9cbe351 100644 (file)
@@ -585,15 +585,16 @@ static void collect_all_aliases(struct perf_stat_config *config, struct evsel *c
 
        alias = list_prepare_entry(counter, &(evlist->core.entries), core.node);
        list_for_each_entry_continue (alias, &evlist->core.entries, core.node) {
-               if (strcmp(evsel__name(alias), evsel__name(counter)) ||
-                   alias->scale != counter->scale ||
-                   alias->cgrp != counter->cgrp ||
-                   strcmp(alias->unit, counter->unit) ||
-                   evsel__is_clock(alias) != evsel__is_clock(counter) ||
-                   !strcmp(alias->pmu_name, counter->pmu_name))
-                       break;
-               alias->merged_stat = true;
-               cb(config, alias, data, false);
+               /* Merge events with the same name, etc. but on different PMUs. */
+               if (!strcmp(evsel__name(alias), evsel__name(counter)) &&
+                       alias->scale == counter->scale &&
+                       alias->cgrp == counter->cgrp &&
+                       !strcmp(alias->unit, counter->unit) &&
+                       evsel__is_clock(alias) == evsel__is_clock(counter) &&
+                       strcmp(alias->pmu_name, counter->pmu_name)) {
+                       alias->merged_stat = true;
+                       cb(config, alias, data, false);
+               }
        }
 }
 
index 70f0956..b654de0 100644 (file)
@@ -1784,6 +1784,25 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too
                                  perf_event__handler_t process, bool needs_mmap,
                                  bool data_mmap, unsigned int nr_threads_synthesize)
 {
+       /*
+        * When perf runs in non-root PID namespace, and the namespace's proc FS
+        * is not mounted, nsinfo__is_in_root_namespace() returns false.
+        * In this case, the proc FS is coming for the parent namespace, thus
+        * perf tool will wrongly gather process info from its parent PID
+        * namespace.
+        *
+        * To avoid the confusion that the perf tool runs in a child PID
+        * namespace but it synthesizes thread info from its parent PID
+        * namespace, returns failure with warning.
+        */
+       if (!nsinfo__is_in_root_namespace()) {
+               pr_err("Perf runs in non-root PID namespace but it tries to ");
+               pr_err("gather process info from its parent PID namespace.\n");
+               pr_err("Please mount the proc file system properly, e.g. ");
+               pr_err("add the option '--mount-proc' for unshare command.\n");
+               return -EPERM;
+       }
+
        if (target__has_task(target))
                return perf_event__synthesize_thread_map(tool, threads, process, machine,
                                                         needs_mmap, data_mmap);
index b0be5f4..79d1023 100644 (file)
@@ -90,7 +90,7 @@ EXTRA_WARNINGS += -Wstrict-aliasing=3
 
 else ifneq ($(CROSS_COMPILE),)
 CLANG_CROSS_FLAGS := --target=$(notdir $(CROSS_COMPILE:%-=%))
-GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE)gcc))
+GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE)gcc 2>/dev/null))
 ifneq ($(GCC_TOOLCHAIN_DIR),)
 CLANG_CROSS_FLAGS += --prefix=$(GCC_TOOLCHAIN_DIR)$(notdir $(CROSS_COMPILE))
 CLANG_CROSS_FLAGS += --sysroot=$(shell $(CROSS_COMPILE)gcc -print-sysroot)
index 44bbe54..3c4196c 100644 (file)
@@ -6,6 +6,7 @@
 # Author: Felix Guo <felixguoxiuping@gmail.com>
 # Author: Brendan Higgins <brendanhiggins@google.com>
 
+import importlib.abc
 import importlib.util
 import logging
 import subprocess
index 4f32133..13d854a 100755 (executable)
@@ -61,7 +61,7 @@ def main(argv: Sequence[str]) -> None:
                elif isinstance(ex, subprocess.CalledProcessError):
                        print(f'{name}: FAILED')
                else:
-                       print('{name}: unexpected exception: {ex}')
+                       print(f'{name}: unexpected exception: {ex}')
                        continue
 
                output = ex.output
index 16ec895..5bd9e6e 100644 (file)
@@ -74,7 +74,7 @@ static inline unsigned long page_to_phys(struct page *page)
              __UNIQUE_ID(min1_), __UNIQUE_ID(min2_),   \
              x, y)
 
-#define preemptible() (1)
+#define pagefault_disabled() (0)
 
 static inline void *kmap(struct page *page)
 {
@@ -127,6 +127,7 @@ kmalloc_array(unsigned int n, unsigned int size, unsigned int flags)
 #define kmemleak_free(a)
 
 #define PageSlab(p) (0)
+#define flush_dcache_page(p)
 
 #define MAX_ERRNO      4095
 
index af798b9..a3c1e67 100644 (file)
@@ -261,7 +261,7 @@ static void ptrace_sve_fpsimd(pid_t child, const struct vec_type *type)
        }
 
        ksft_test_result((sve->flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD,
-                        "Set FPSIMD registers via %s\n", type->name);
+                        "Got FPSIMD registers via %s\n", type->name);
        if ((sve->flags & SVE_PT_REGS_MASK) != SVE_PT_REGS_FPSIMD)
                goto out;
 
@@ -557,7 +557,14 @@ static int do_parent(pid_t child)
                }
 
                /* prctl() flags */
-               ptrace_set_get_inherit(child, &vec_types[i]);
+               if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
+                       ptrace_set_get_inherit(child, &vec_types[i]);
+               } else {
+                       ksft_test_result_skip("%s SVE_PT_VL_INHERIT set\n",
+                                             vec_types[i].name);
+                       ksft_test_result_skip("%s SVE_PT_VL_INHERIT cleared\n",
+                                             vec_types[i].name);
+               }
 
                /* Step through every possible VQ */
                for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) {
index ebf68dc..2893e9f 100644 (file)
@@ -28,7 +28,6 @@
 // 5. We can read keycode from same /dev/lirc device
 
 #include <linux/bpf.h>
-#include <linux/lirc.h>
 #include <linux/input.h>
 #include <errno.h>
 #include <stdio.h>
index 076cf43..cd45821 100644 (file)
@@ -126,8 +126,6 @@ static void test_clone3(uint64_t flags, size_t size, int expected,
 
 int main(int argc, char *argv[])
 {
-       pid_t pid;
-
        uid_t uid = getuid();
 
        ksft_print_header();
index 31f8c9a..60ce18e 100755 (executable)
@@ -194,5 +194,5 @@ prerequisite
 
 # Run requested functions
 clear_dumps $OUTFILE
-do_test >> $OUTFILE.txt
+do_test | tee -a $OUTFILE.txt
 dmesg_dumps $OUTFILE
index dd61118..12c5e27 100644 (file)
@@ -5,7 +5,7 @@ CFLAGS += -D_GNU_SOURCE
 
 TEST_PROGS := binfmt_script non-regular
 TEST_GEN_PROGS := execveat load_address_4096 load_address_2097152 load_address_16777216
-TEST_GEN_FILES := execveat.symlink execveat.denatured script subdir pipe
+TEST_GEN_FILES := execveat.symlink execveat.denatured script subdir
 # Makefile is a run-time dependency, since it's accessed by the execveat test
 TEST_FILES := Makefile
 
index 12631f0..11e157d 100644 (file)
@@ -11,7 +11,7 @@ all:
        @for DIR in $(SUBDIRS); do              \
                BUILD_TARGET=$(OUTPUT)/$$DIR;   \
                mkdir $$BUILD_TARGET  -p;       \
-               make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
+               $(MAKE) OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
                if [ -e $$DIR/$(TEST_PROGS) ]; then \
                        rsync -a $$DIR/$(TEST_PROGS) $$BUILD_TARGET/; \
                fi \
@@ -32,6 +32,6 @@ override define CLEAN
        @for DIR in $(SUBDIRS); do              \
                BUILD_TARGET=$(OUTPUT)/$$DIR;   \
                mkdir $$BUILD_TARGET  -p;       \
-               make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
+               $(MAKE) OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
        done
 endef
index 06256c9..f4a15cb 100644 (file)
 #define SYSFS_PATH_MAX 256
 #define DNAME_PATH_MAX 256
 
+/*
+ * Support ancient lirc.h which does not have these values. Can be removed
+ * once RHEL 8 is no longer a relevant testing platform.
+ */
+#if RC_PROTO_MAX < 26
+#define RC_PROTO_RCMM12 24
+#define RC_PROTO_RCMM24 25
+#define RC_PROTO_RCMM32 26
+#endif
+
 static const struct {
        enum rc_proto proto;
        const char *name;
index 471eaa7..1177940 100644 (file)
@@ -877,7 +877,8 @@ static void __timeout_handler(int sig, siginfo_t *info, void *ucontext)
        }
 
        t->timed_out = true;
-       kill(t->pid, SIGKILL);
+       // signal process group
+       kill(-(t->pid), SIGKILL);
 }
 
 void __wait_for_test(struct __test_metadata *t)
@@ -987,6 +988,7 @@ void __run_test(struct __fixture_metadata *f,
                ksft_print_msg("ERROR SPAWNING TEST CHILD\n");
                t->passed = 0;
        } else if (t->pid == 0) {
+               setpgrp();
                t->fn(t, variant);
                if (t->skip)
                        _exit(255);
index 81ebf99..0e4926b 100644 (file)
@@ -85,6 +85,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/xen_vmcall_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_pi_mmio_test
 TEST_GEN_PROGS_x86_64 += x86_64/sev_migrate_tests
 TEST_GEN_PROGS_x86_64 += x86_64/amx_test
+TEST_GEN_PROGS_x86_64 += access_tracking_perf_test
 TEST_GEN_PROGS_x86_64 += demand_paging_test
 TEST_GEN_PROGS_x86_64 += dirty_log_test
 TEST_GEN_PROGS_x86_64 += dirty_log_perf_test
index 66775de..4ed6aa0 100644 (file)
@@ -345,7 +345,6 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus,
  *   guest_code - The vCPU's entry point
  */
 void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code);
-void vm_xsave_req_perm(void);
 
 bool vm_is_unrestricted_guest(struct kvm_vm *vm);
 
index 423d8a6..8a470da 100644 (file)
@@ -458,6 +458,7 @@ uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2,
 struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void);
 void vcpu_set_hv_cpuid(struct kvm_vm *vm, uint32_t vcpuid);
 struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vm *vm, uint32_t vcpuid);
+void vm_xsave_req_perm(int bit);
 
 enum x86_page_size {
        X86_PAGE_SIZE_4K = 0,
index 8c53f96..d8cf851 100644 (file)
@@ -393,13 +393,6 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus,
        struct kvm_vm *vm;
        int i;
 
-#ifdef __x86_64__
-       /*
-        * Permission needs to be requested before KVM_SET_CPUID2.
-        */
-       vm_xsave_req_perm();
-#endif
-
        /* Force slot0 memory size not small than DEFAULT_GUEST_PHY_PAGES */
        if (slot0_mem_pages < DEFAULT_GUEST_PHY_PAGES)
                slot0_mem_pages = DEFAULT_GUEST_PHY_PAGES;
index 5f9d7e9..9f000df 100644 (file)
@@ -665,16 +665,31 @@ static bool is_xfd_supported(void)
        return !!(eax & CPUID_XFD_BIT);
 }
 
-void vm_xsave_req_perm(void)
+void vm_xsave_req_perm(int bit)
 {
-       unsigned long bitmask;
+       int kvm_fd;
+       u64 bitmask;
        long rc;
+       struct kvm_device_attr attr = {
+               .group = 0,
+               .attr = KVM_X86_XCOMP_GUEST_SUPP,
+               .addr = (unsigned long) &bitmask
+       };
+
+       kvm_fd = open_kvm_dev_path_or_exit();
+       rc = ioctl(kvm_fd, KVM_GET_DEVICE_ATTR, &attr);
+       close(kvm_fd);
+       if (rc == -1 && (errno == ENXIO || errno == EINVAL))
+               exit(KSFT_SKIP);
+       TEST_ASSERT(rc == 0, "KVM_GET_DEVICE_ATTR(0, KVM_X86_XCOMP_GUEST_SUPP) error: %ld", rc);
+       if (!(bitmask & (1ULL << bit)))
+               exit(KSFT_SKIP);
 
        if (!is_xfd_supported())
-               return;
+               exit(KSFT_SKIP);
+
+       rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_GUEST_PERM, bit);
 
-       rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_GUEST_PERM,
-                    XSTATE_XTILE_DATA_BIT);
        /*
         * The older kernel version(<5.15) can't support
         * ARCH_REQ_XCOMP_GUEST_PERM and directly return.
@@ -684,7 +699,7 @@ void vm_xsave_req_perm(void)
 
        rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_GUEST_PERM, &bitmask);
        TEST_ASSERT(rc == 0, "prctl(ARCH_GET_XCOMP_GUEST_PERM) error: %ld", rc);
-       TEST_ASSERT(bitmask & XFEATURE_XTILE_MASK,
+       TEST_ASSERT(bitmask & (1ULL << bit),
                    "prctl(ARCH_REQ_XCOMP_GUEST_PERM) failure bitmask=0x%lx",
                    bitmask);
 }
index 523c1e9..52a3ef6 100644 (file)
@@ -329,6 +329,8 @@ int main(int argc, char *argv[])
        u32 amx_offset;
        int stage, ret;
 
+       vm_xsave_req_perm(XSTATE_XTILE_DATA_BIT);
+
        /* Create VM */
        vm = vm_create_default(VCPU_ID, 0, guest_code);
 
index 2da8eb8..a626d40 100644 (file)
@@ -105,7 +105,6 @@ static void guest_code(void *arg)
 
                if (cpu_has_svm()) {
                        run_guest(svm->vmcb, svm->vmcb_gpa);
-                       svm->vmcb->save.rip += 3;
                        run_guest(svm->vmcb, svm->vmcb_gpa);
                } else {
                        vmlaunch();
index e541066..4c88238 100644 (file)
@@ -207,15 +207,21 @@ TEST(check_file_mmap)
 
        errno = 0;
        fd = open(".", O_TMPFILE | O_RDWR, 0600);
-       ASSERT_NE(-1, fd) {
-               TH_LOG("Can't create temporary file: %s",
-                       strerror(errno));
+       if (fd < 0) {
+               ASSERT_EQ(errno, EOPNOTSUPP) {
+                       TH_LOG("Can't create temporary file: %s",
+                              strerror(errno));
+               }
+               SKIP(goto out_free, "O_TMPFILE not supported by filesystem.");
        }
        errno = 0;
        retval = fallocate(fd, 0, 0, FILE_SIZE);
-       ASSERT_EQ(0, retval) {
-               TH_LOG("Error allocating space for the temporary file: %s",
-                       strerror(errno));
+       if (retval) {
+               ASSERT_EQ(errno, EOPNOTSUPP) {
+                       TH_LOG("Error allocating space for the temporary file: %s",
+                              strerror(errno));
+               }
+               SKIP(goto out_close, "fallocate not supported by filesystem.");
        }
 
        /*
@@ -271,7 +277,9 @@ TEST(check_file_mmap)
        }
 
        munmap(addr, FILE_SIZE);
+out_close:
        close(fd);
+out_free:
        free(vec);
 }
 
index 8f6997d..d9d1d41 100644 (file)
@@ -240,11 +240,8 @@ static int check_ioam6_data(__u8 **p, struct ioam6_trace_hdr *ioam6h,
                *p += sizeof(__u32);
        }
 
-       if (ioam6h->type.bit6) {
-               if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
-                       return 1;
+       if (ioam6h->type.bit6)
                *p += sizeof(__u32);
-       }
 
        if (ioam6h->type.bit7) {
                if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
index 27d0eb9..c0801df 100755 (executable)
@@ -75,6 +75,7 @@ init()
 
                # let $ns2 reach any $ns1 address from any interface
                ip -net "$ns2" route add default via 10.0.$i.1 dev ns2eth$i metric 10$i
+               ip -net "$ns2" route add default via dead:beef:$i::1 dev ns2eth$i metric 10$i
        done
 }
 
@@ -1158,6 +1159,7 @@ signal_address_tests()
        ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags signal
        ip netns exec $ns2 ./pm_nl_ctl add 10.0.4.2 flags signal
        run_tests $ns1 $ns2 10.0.1.1
+       chk_join_nr "signal addresses race test" 3 3 3
 
        # the server will not signal the address terminating
        # the MPC subflow
@@ -1476,7 +1478,7 @@ ipv6_tests()
        reset
        ip netns exec $ns1 ./pm_nl_ctl limits 0 1
        ip netns exec $ns2 ./pm_nl_ctl limits 0 1
-       ip netns exec $ns2 ./pm_nl_ctl add dead:beef:3::2 flags subflow
+       ip netns exec $ns2 ./pm_nl_ctl add dead:beef:3::2 dev ns2eth3 flags subflow
        run_tests $ns1 $ns2 dead:beef:1::1 0 0 0 slow
        chk_join_nr "single subflow IPv6" 1 1 1
 
@@ -1511,7 +1513,7 @@ ipv6_tests()
        ip netns exec $ns1 ./pm_nl_ctl limits 0 2
        ip netns exec $ns1 ./pm_nl_ctl add dead:beef:2::1 flags signal
        ip netns exec $ns2 ./pm_nl_ctl limits 1 2
-       ip netns exec $ns2 ./pm_nl_ctl add dead:beef:3::2 flags subflow
+       ip netns exec $ns2 ./pm_nl_ctl add dead:beef:3::2 dev ns2eth3 flags subflow
        run_tests $ns1 $ns2 dead:beef:1::1 0 -1 -1 slow
        chk_join_nr "remove subflow and signal IPv6" 2 2 2
        chk_add_nr 1 1
index ed61f6c..df322e4 100755 (executable)
@@ -27,7 +27,7 @@ TYPES="net_port port_net net6_port port_proto net6_port_mac net6_port_mac_proto
        net6_port_net6_port net_port_mac_proto_net"
 
 # Reported bugs, also described by TYPE_ variables below
-BUGS="flush_remove_add"
+BUGS="flush_remove_add reload"
 
 # List of possible paths to pktgen script from kernel tree for performance tests
 PKTGEN_SCRIPT_PATHS="
@@ -354,6 +354,23 @@ TYPE_flush_remove_add="
 display                Add two elements, flush, re-add
 "
 
+TYPE_reload="
+display                net,mac with reload
+type_spec      ipv4_addr . ether_addr
+chain_spec     ip daddr . ether saddr
+dst            addr4
+src            mac
+start          1
+count          1
+src_delta      2000
+tools          sendip nc bash
+proto          udp
+
+race_repeat    0
+
+perf_duration  0
+"
+
 # Set template for all tests, types and rules are filled in depending on test
 set_template='
 flush ruleset
@@ -1473,6 +1490,59 @@ test_bug_flush_remove_add() {
        nft flush ruleset
 }
 
+# - add ranged element, check that packets match it
+# - reload the set, check packets still match
+test_bug_reload() {
+       setup veth send_"${proto}" set || return ${KSELFTEST_SKIP}
+       rstart=${start}
+
+       range_size=1
+       for i in $(seq "${start}" $((start + count))); do
+               end=$((start + range_size))
+
+               # Avoid negative or zero-sized port ranges
+               if [ $((end / 65534)) -gt $((start / 65534)) ]; then
+                       start=${end}
+                       end=$((end + 1))
+               fi
+               srcstart=$((start + src_delta))
+               srcend=$((end + src_delta))
+
+               add "$(format)" || return 1
+               range_size=$((range_size + 1))
+               start=$((end + range_size))
+       done
+
+       # check kernel does allocate pcpu sctrach map
+       # for reload with no elemet add/delete
+       ( echo flush set inet filter test ;
+         nft list set inet filter test ) | nft -f -
+
+       start=${rstart}
+       range_size=1
+
+       for i in $(seq "${start}" $((start + count))); do
+               end=$((start + range_size))
+
+               # Avoid negative or zero-sized port ranges
+               if [ $((end / 65534)) -gt $((start / 65534)) ]; then
+                       start=${end}
+                       end=$((end + 1))
+               fi
+               srcstart=$((start + src_delta))
+               srcend=$((end + src_delta))
+
+               for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
+                       send_match "${j}" $((j + src_delta)) || return 1
+               done
+
+               range_size=$((range_size + 1))
+               start=$((end + range_size))
+       done
+
+       nft flush ruleset
+}
+
 test_reported_issues() {
        eval test_bug_"${subtest}"
 }
index 349a319..79fe627 100755 (executable)
@@ -899,6 +899,144 @@ EOF
        ip netns exec "$ns0" nft delete table $family nat
 }
 
+test_stateless_nat_ip()
+{
+       local lret=0
+
+       ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
+       ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
+
+       ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
+       if [ $? -ne 0 ] ; then
+               echo "ERROR: cannot ping $ns1 from $ns2 before loading stateless rules"
+               return 1
+       fi
+
+ip netns exec "$ns0" nft -f /dev/stdin <<EOF
+table ip stateless {
+       map xlate_in {
+               typeof meta iifname . ip saddr . ip daddr : ip daddr
+               elements = {
+                       "veth1" . 10.0.2.99 . 10.0.1.99 : 10.0.2.2,
+               }
+       }
+       map xlate_out {
+               typeof meta iifname . ip saddr . ip daddr : ip daddr
+               elements = {
+                       "veth0" . 10.0.1.99 . 10.0.2.2 : 10.0.2.99
+               }
+       }
+
+       chain prerouting {
+               type filter hook prerouting priority -400; policy accept;
+               ip saddr set meta iifname . ip saddr . ip daddr map @xlate_in
+               ip daddr set meta iifname . ip saddr . ip daddr map @xlate_out
+       }
+}
+EOF
+       if [ $? -ne 0 ]; then
+               echo "SKIP: Could not add ip statless rules"
+               return $ksft_skip
+       fi
+
+       reset_counters
+
+       ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
+       if [ $? -ne 0 ] ; then
+               echo "ERROR: cannot ping $ns1 from $ns2 with stateless rules"
+               lret=1
+       fi
+
+       # ns1 should have seen packets from .2.2, due to stateless rewrite.
+       expect="packets 1 bytes 84"
+       cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0insl | grep -q "$expect")
+       if [ $? -ne 0 ]; then
+               bad_counter "$ns1" ns0insl "$expect" "test_stateless 1"
+               lret=1
+       fi
+
+       for dir in "in" "out" ; do
+               cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect")
+               if [ $? -ne 0 ]; then
+                       bad_counter "$ns2" ns1$dir "$expect" "test_stateless 2"
+                       lret=1
+               fi
+       done
+
+       # ns1 should not have seen packets from ns2, due to masquerade
+       expect="packets 0 bytes 0"
+       for dir in "in" "out" ; do
+               cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect")
+               if [ $? -ne 0 ]; then
+                       bad_counter "$ns1" ns0$dir "$expect" "test_stateless 3"
+                       lret=1
+               fi
+
+               cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect")
+               if [ $? -ne 0 ]; then
+                       bad_counter "$ns0" ns1$dir "$expect" "test_stateless 4"
+                       lret=1
+               fi
+       done
+
+       reset_counters
+
+       socat -h > /dev/null 2>&1
+       if [ $? -ne 0 ];then
+               echo "SKIP: Could not run stateless nat frag test without socat tool"
+               if [ $lret -eq 0 ]; then
+                       return $ksft_skip
+               fi
+
+               ip netns exec "$ns0" nft delete table ip stateless
+               return $lret
+       fi
+
+       local tmpfile=$(mktemp)
+       dd if=/dev/urandom of=$tmpfile bs=4096 count=1 2>/dev/null
+
+       local outfile=$(mktemp)
+       ip netns exec "$ns1" timeout 3 socat -u UDP4-RECV:4233 OPEN:$outfile < /dev/null &
+       sc_r=$!
+
+       sleep 1
+       # re-do with large ping -> ip fragmentation
+       ip netns exec "$ns2" timeout 3 socat - UDP4-SENDTO:"10.0.1.99:4233" < "$tmpfile" > /dev/null
+       if [ $? -ne 0 ] ; then
+               echo "ERROR: failed to test udp $ns1 to $ns2 with stateless ip nat" 1>&2
+               lret=1
+       fi
+
+       wait
+
+       cmp "$tmpfile" "$outfile"
+       if [ $? -ne 0 ]; then
+               ls -l "$tmpfile" "$outfile"
+               echo "ERROR: in and output file mismatch when checking udp with stateless nat" 1>&2
+               lret=1
+       fi
+
+       rm -f "$tmpfile" "$outfile"
+
+       # ns1 should have seen packets from 2.2, due to stateless rewrite.
+       expect="packets 3 bytes 4164"
+       cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0insl | grep -q "$expect")
+       if [ $? -ne 0 ]; then
+               bad_counter "$ns1" ns0insl "$expect" "test_stateless 5"
+               lret=1
+       fi
+
+       ip netns exec "$ns0" nft delete table ip stateless
+       if [ $? -ne 0 ]; then
+               echo "ERROR: Could not delete table ip stateless" 1>&2
+               lret=1
+       fi
+
+       test $lret -eq 0 && echo "PASS: IP statless for $ns2"
+
+       return $lret
+}
+
 # ip netns exec "$ns0" ping -c 1 -q 10.0.$i.99
 for i in 0 1 2; do
 ip netns exec ns$i-$sfx nft -f /dev/stdin <<EOF
@@ -965,6 +1103,19 @@ table inet filter {
 EOF
 done
 
+# special case for stateless nat check, counter needs to
+# be done before (input) ip defragmentation
+ip netns exec ns1-$sfx nft -f /dev/stdin <<EOF
+table inet filter {
+       counter ns0insl {}
+
+       chain pre {
+               type filter hook prerouting priority -400; policy accept;
+               ip saddr 10.0.2.2 counter name "ns0insl"
+       }
+}
+EOF
+
 sleep 3
 # test basic connectivity
 for i in 1 2; do
@@ -1019,6 +1170,7 @@ $test_inet_nat && test_redirect inet
 $test_inet_nat && test_redirect6 inet
 
 test_port_shadowing
+test_stateless_nat_ip
 
 if [ $ret -ne 0 ];then
        echo -n "FAIL: "
index 0463311..5a8db0b 100755 (executable)
@@ -9,7 +9,7 @@ ns="ns-$sfx"
 # Kselftest framework requirement - SKIP code is 4.
 ksft_skip=4
 
-zones=20000
+zones=2000
 have_ct_tool=0
 ret=0
 
@@ -75,10 +75,10 @@ EOF
 
        while [ $i -lt $max_zones ]; do
                local start=$(date +%s%3N)
-               i=$((i + 10000))
+               i=$((i + 1000))
                j=$((j + 1))
                # nft rule in output places each packet in a different zone.
-               dd if=/dev/zero of=/dev/stdout bs=8k count=10000 2>/dev/null | ip netns exec "$ns" socat STDIN UDP:127.0.0.1:12345,sourceport=12345
+               dd if=/dev/zero of=/dev/stdout bs=8k count=1000 2>/dev/null | ip netns exec "$ns" socat STDIN UDP:127.0.0.1:12345,sourceport=12345
                if [ $? -ne 0 ] ;then
                        ret=1
                        break
@@ -86,7 +86,7 @@ EOF
 
                stop=$(date +%s%3N)
                local duration=$((stop-start))
-               echo "PASS: added 10000 entries in $duration ms (now $i total, loop $j)"
+               echo "PASS: added 1000 entries in $duration ms (now $i total, loop $j)"
        done
 
        if [ $have_ct_tool -eq 1 ]; then
@@ -128,11 +128,11 @@ test_conntrack_tool() {
                        break
                fi
 
-               if [ $((i%10000)) -eq 0 ];then
+               if [ $((i%1000)) -eq 0 ];then
                        stop=$(date +%s%3N)
 
                        local duration=$((stop-start))
-                       echo "PASS: added 10000 entries in $duration ms (now $i total)"
+                       echo "PASS: added 1000 entries in $duration ms (now $i total)"
                        start=$stop
                fi
        done
index 4b93b14..843ba56 100644 (file)
@@ -5,4 +5,4 @@ TEST_GEN_PROGS := openat2_test resolve_test rename_attack_test
 
 include ../lib.mk
 
-$(TEST_GEN_PROGS): helpers.c
+$(TEST_GEN_PROGS): helpers.c helpers.h
index a6ea273..7056340 100644 (file)
@@ -9,6 +9,7 @@
 
 #define _GNU_SOURCE
 #include <stdint.h>
+#include <stdbool.h>
 #include <errno.h>
 #include <linux/types.h>
 #include "../kselftest.h"
@@ -62,11 +63,12 @@ bool needs_openat2(const struct open_how *how);
                                        (similar to chroot(2)). */
 #endif /* RESOLVE_IN_ROOT */
 
-#define E_func(func, ...)                                              \
-       do {                                                            \
-               if (func(__VA_ARGS__) < 0)                              \
-                       ksft_exit_fail_msg("%s:%d %s failed\n", \
-                                          __FILE__, __LINE__, #func);\
+#define E_func(func, ...)                                                    \
+       do {                                                                  \
+               errno = 0;                                                    \
+               if (func(__VA_ARGS__) < 0)                                    \
+                       ksft_exit_fail_msg("%s:%d %s failed - errno:%d\n",    \
+                                          __FILE__, __LINE__, #func, errno); \
        } while (0)
 
 #define E_asprintf(...)                E_func(asprintf,        __VA_ARGS__)
index 1bddbe9..7fb9020 100644 (file)
@@ -259,6 +259,16 @@ void test_openat2_flags(void)
                unlink(path);
 
                fd = sys_openat2(AT_FDCWD, path, &test->how);
+               if (fd < 0 && fd == -EOPNOTSUPP) {
+                       /*
+                        * Skip the testcase if it failed because not supported
+                        * by FS. (e.g. a valid O_TMPFILE combination on NFS)
+                        */
+                       ksft_test_result_skip("openat2 with %s fails with %d (%s)\n",
+                                             test->name, fd, strerror(-fd));
+                       goto next;
+               }
+
                if (test->err >= 0)
                        failed = (fd < 0);
                else
@@ -303,7 +313,7 @@ skip:
                else
                        resultfn("openat2 with %s fails with %d (%s)\n",
                                 test->name, test->err, strerror(-test->err));
-
+next:
                free(fdpath);
                fflush(stdout);
        }
index 8e83cf9..6d849dc 100644 (file)
@@ -44,9 +44,10 @@ static struct {
 } ctx;
 
 /* Unique value to check si_perf_data is correctly set from perf_event_attr::sig_data. */
-#define TEST_SIG_DATA(addr) (~(unsigned long)(addr))
+#define TEST_SIG_DATA(addr, id) (~(unsigned long)(addr) + id)
 
-static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr)
+static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr,
+                                             unsigned long id)
 {
        struct perf_event_attr attr = {
                .type           = PERF_TYPE_BREAKPOINT,
@@ -60,7 +61,7 @@ static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr)
                .inherit_thread = 1, /* ... but only cloned with CLONE_THREAD. */
                .remove_on_exec = 1, /* Required by sigtrap. */
                .sigtrap        = 1, /* Request synchronous SIGTRAP on event. */
-               .sig_data       = TEST_SIG_DATA(addr),
+               .sig_data       = TEST_SIG_DATA(addr, id),
        };
        return attr;
 }
@@ -110,7 +111,7 @@ FIXTURE(sigtrap_threads)
 
 FIXTURE_SETUP(sigtrap_threads)
 {
-       struct perf_event_attr attr = make_event_attr(false, &ctx.iterate_on);
+       struct perf_event_attr attr = make_event_attr(false, &ctx.iterate_on, 0);
        struct sigaction action = {};
        int i;
 
@@ -165,7 +166,7 @@ TEST_F(sigtrap_threads, enable_event)
        EXPECT_EQ(ctx.tids_want_signal, 0);
        EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
        EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
-       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on));
+       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
 
        /* Check enabled for parent. */
        ctx.iterate_on = 0;
@@ -175,7 +176,7 @@ TEST_F(sigtrap_threads, enable_event)
 /* Test that modification propagates to all inherited events. */
 TEST_F(sigtrap_threads, modify_and_enable_event)
 {
-       struct perf_event_attr new_attr = make_event_attr(true, &ctx.iterate_on);
+       struct perf_event_attr new_attr = make_event_attr(true, &ctx.iterate_on, 42);
 
        EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr), 0);
        run_test_threads(_metadata, self);
@@ -184,7 +185,7 @@ TEST_F(sigtrap_threads, modify_and_enable_event)
        EXPECT_EQ(ctx.tids_want_signal, 0);
        EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
        EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
-       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on));
+       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 42));
 
        /* Check enabled for parent. */
        ctx.iterate_on = 0;
@@ -204,7 +205,7 @@ TEST_F(sigtrap_threads, signal_stress)
        EXPECT_EQ(ctx.tids_want_signal, 0);
        EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
        EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
-       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on));
+       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
 }
 
 TEST_HARNESS_MAIN
index 01f8d3c..6922d64 100644 (file)
@@ -68,7 +68,7 @@
 #define PIDFD_SKIP 3
 #define PIDFD_XFAIL 4
 
-int wait_for_pid(pid_t pid)
+static inline int wait_for_pid(pid_t pid)
 {
        int status, ret;
 
@@ -78,13 +78,20 @@ again:
                if (errno == EINTR)
                        goto again;
 
+               ksft_print_msg("waitpid returned -1, errno=%d\n", errno);
                return -1;
        }
 
-       if (!WIFEXITED(status))
+       if (!WIFEXITED(status)) {
+               ksft_print_msg(
+                      "waitpid !WIFEXITED, WIFSIGNALED=%d, WTERMSIG=%d\n",
+                      WIFSIGNALED(status), WTERMSIG(status));
                return -1;
+       }
 
-       return WEXITSTATUS(status);
+       ret = WEXITSTATUS(status);
+       ksft_print_msg("waitpid WEXITSTATUS=%d\n", ret);
+       return ret;
 }
 
 static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
index 2255852..3fd8e90 100644 (file)
@@ -12,6 +12,7 @@
 #include <string.h>
 #include <syscall.h>
 #include <sys/wait.h>
+#include <sys/mman.h>
 
 #include "pidfd.h"
 #include "../kselftest.h"
@@ -80,7 +81,10 @@ static inline int error_check(struct error *err, const char *test_name)
        return err->code;
 }
 
+#define CHILD_STACK_SIZE 8192
+
 struct child {
+       char *stack;
        pid_t pid;
        int   fd;
 };
@@ -89,17 +93,22 @@ static struct child clone_newns(int (*fn)(void *), void *args,
                                struct error *err)
 {
        static int flags = CLONE_PIDFD | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD;
-       size_t stack_size = 1024;
-       char *stack[1024] = { 0 };
        struct child ret;
 
        if (!(flags & CLONE_NEWUSER) && geteuid() != 0)
                flags |= CLONE_NEWUSER;
 
+       ret.stack = mmap(NULL, CHILD_STACK_SIZE, PROT_READ | PROT_WRITE,
+                        MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
+       if (ret.stack == MAP_FAILED) {
+               error_set(err, -1, "mmap of stack failed (errno %d)", errno);
+               return ret;
+       }
+
 #ifdef __ia64__
-       ret.pid = __clone2(fn, stack, stack_size, flags, args, &ret.fd);
+       ret.pid = __clone2(fn, ret.stack, CHILD_STACK_SIZE, flags, args, &ret.fd);
 #else
-       ret.pid = clone(fn, stack + stack_size, flags, args, &ret.fd);
+       ret.pid = clone(fn, ret.stack + CHILD_STACK_SIZE, flags, args, &ret.fd);
 #endif
 
        if (ret.pid < 0) {
@@ -129,6 +138,11 @@ static inline int child_join(struct child *child, struct error *err)
        else if (r > 0)
                error_set(err, r, "child %d reported: %d", child->pid, r);
 
+       if (munmap(child->stack, CHILD_STACK_SIZE)) {
+               error_set(err, -1, "munmap of child stack failed (errno %d)", errno);
+               r = -1;
+       }
+
        return r;
 }
 
index 529eb70..9a2d649 100644 (file)
@@ -441,7 +441,6 @@ static void test_pidfd_poll_exec(int use_waitpid)
 {
        int pid, pidfd = 0;
        int status, ret;
-       pthread_t t1;
        time_t prog_start = time(NULL);
        const char *test_name = "pidfd_poll check for premature notification on child thread exec";
 
@@ -500,13 +499,14 @@ static int child_poll_leader_exit_test(void *args)
         */
        *child_exit_secs = time(NULL);
        syscall(SYS_exit, 0);
+       /* Never reached, but appeases compiler thinking we should return. */
+       exit(0);
 }
 
 static void test_pidfd_poll_leader_exit(int use_waitpid)
 {
        int pid, pidfd = 0;
-       int status, ret;
-       time_t prog_start = time(NULL);
+       int status, ret = 0;
        const char *test_name = "pidfd_poll check for premature notification on non-empty"
                                "group leader exit";
 
index be2943f..17999e0 100644 (file)
@@ -39,7 +39,7 @@ static int sys_waitid(int which, pid_t pid, siginfo_t *info, int options,
 
 TEST(wait_simple)
 {
-       int pidfd = -1, status = 0;
+       int pidfd = -1;
        pid_t parent_tid = -1;
        struct clone_args args = {
                .parent_tid = ptr_to_u64(&parent_tid),
@@ -47,7 +47,6 @@ TEST(wait_simple)
                .flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
                .exit_signal = SIGCHLD,
        };
-       int ret;
        pid_t pid;
        siginfo_t info = {
                .si_signo = 0,
@@ -88,7 +87,7 @@ TEST(wait_simple)
 
 TEST(wait_states)
 {
-       int pidfd = -1, status = 0;
+       int pidfd = -1;
        pid_t parent_tid = -1;
        struct clone_args args = {
                .parent_tid = ptr_to_u64(&parent_tid),
index 3d603f1..883ca85 100644 (file)
@@ -33,110 +33,114 @@ typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts);
 typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts);
 typedef time_t (*vdso_time_t)(time_t *t);
 
-static int vdso_test_gettimeofday(void)
+#define VDSO_TEST_PASS_MSG()   "\n%s(): PASS\n", __func__
+#define VDSO_TEST_FAIL_MSG(x)  "\n%s(): %s FAIL\n", __func__, x
+#define VDSO_TEST_SKIP_MSG(x)  "\n%s(): SKIP: Could not find %s\n", __func__, x
+
+static void vdso_test_gettimeofday(void)
 {
        /* Find gettimeofday. */
        vdso_gettimeofday_t vdso_gettimeofday =
                (vdso_gettimeofday_t)vdso_sym(version, name[0]);
 
        if (!vdso_gettimeofday) {
-               printf("Could not find %s\n", name[0]);
-               return KSFT_SKIP;
+               ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[0]));
+               return;
        }
 
        struct timeval tv;
        long ret = vdso_gettimeofday(&tv, 0);
 
        if (ret == 0) {
-               printf("The time is %lld.%06lld\n",
-                      (long long)tv.tv_sec, (long long)tv.tv_usec);
+               ksft_print_msg("The time is %lld.%06lld\n",
+                              (long long)tv.tv_sec, (long long)tv.tv_usec);
+               ksft_test_result_pass(VDSO_TEST_PASS_MSG());
        } else {
-               printf("%s failed\n", name[0]);
-               return KSFT_FAIL;
+               ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[0]));
        }
-
-       return KSFT_PASS;
 }
 
-static int vdso_test_clock_gettime(clockid_t clk_id)
+static void vdso_test_clock_gettime(clockid_t clk_id)
 {
        /* Find clock_gettime. */
        vdso_clock_gettime_t vdso_clock_gettime =
                (vdso_clock_gettime_t)vdso_sym(version, name[1]);
 
        if (!vdso_clock_gettime) {
-               printf("Could not find %s\n", name[1]);
-               return KSFT_SKIP;
+               ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[1]));
+               return;
        }
 
        struct timespec ts;
        long ret = vdso_clock_gettime(clk_id, &ts);
 
        if (ret == 0) {
-               printf("The time is %lld.%06lld\n",
-                      (long long)ts.tv_sec, (long long)ts.tv_nsec);
+               ksft_print_msg("The time is %lld.%06lld\n",
+                              (long long)ts.tv_sec, (long long)ts.tv_nsec);
+               ksft_test_result_pass(VDSO_TEST_PASS_MSG());
        } else {
-               printf("%s failed\n", name[1]);
-               return KSFT_FAIL;
+               ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[1]));
        }
-
-       return KSFT_PASS;
 }
 
-static int vdso_test_time(void)
+static void vdso_test_time(void)
 {
        /* Find time. */
        vdso_time_t vdso_time =
                (vdso_time_t)vdso_sym(version, name[2]);
 
        if (!vdso_time) {
-               printf("Could not find %s\n", name[2]);
-               return KSFT_SKIP;
+               ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[2]));
+               return;
        }
 
        long ret = vdso_time(NULL);
 
        if (ret > 0) {
-               printf("The time in hours since January 1, 1970 is %lld\n",
+               ksft_print_msg("The time in hours since January 1, 1970 is %lld\n",
                                (long long)(ret / 3600));
+               ksft_test_result_pass(VDSO_TEST_PASS_MSG());
        } else {
-               printf("%s failed\n", name[2]);
-               return KSFT_FAIL;
+               ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[2]));
        }
-
-       return KSFT_PASS;
 }
 
-static int vdso_test_clock_getres(clockid_t clk_id)
+static void vdso_test_clock_getres(clockid_t clk_id)
 {
+       int clock_getres_fail = 0;
+
        /* Find clock_getres. */
        vdso_clock_getres_t vdso_clock_getres =
                (vdso_clock_getres_t)vdso_sym(version, name[3]);
 
        if (!vdso_clock_getres) {
-               printf("Could not find %s\n", name[3]);
-               return KSFT_SKIP;
+               ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[3]));
+               return;
        }
 
        struct timespec ts, sys_ts;
        long ret = vdso_clock_getres(clk_id, &ts);
 
        if (ret == 0) {
-               printf("The resolution is %lld %lld\n",
-                      (long long)ts.tv_sec, (long long)ts.tv_nsec);
+               ksft_print_msg("The vdso resolution is %lld %lld\n",
+                              (long long)ts.tv_sec, (long long)ts.tv_nsec);
        } else {
-               printf("%s failed\n", name[3]);
-               return KSFT_FAIL;
+               clock_getres_fail++;
        }
 
        ret = syscall(SYS_clock_getres, clk_id, &sys_ts);
 
-       if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec)) {
-               printf("%s failed\n", name[3]);
-               return KSFT_FAIL;
-       }
+       ksft_print_msg("The syscall resolution is %lld %lld\n",
+                       (long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec);
 
-       return KSFT_PASS;
+       if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec))
+               clock_getres_fail++;
+
+       if (clock_getres_fail > 0) {
+               ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[3]));
+       } else {
+               ksft_test_result_pass(VDSO_TEST_PASS_MSG());
+       }
 }
 
 const char *vdso_clock_name[12] = {
@@ -158,36 +162,23 @@ const char *vdso_clock_name[12] = {
  * This function calls vdso_test_clock_gettime and vdso_test_clock_getres
  * with different values for clock_id.
  */
-static inline int vdso_test_clock(clockid_t clock_id)
+static inline void vdso_test_clock(clockid_t clock_id)
 {
-       int ret0, ret1;
-
-       ret0 = vdso_test_clock_gettime(clock_id);
-       /* A skipped test is considered passed */
-       if (ret0 == KSFT_SKIP)
-               ret0 = KSFT_PASS;
-
-       ret1 = vdso_test_clock_getres(clock_id);
-       /* A skipped test is considered passed */
-       if (ret1 == KSFT_SKIP)
-               ret1 = KSFT_PASS;
+       ksft_print_msg("\nclock_id: %s\n", vdso_clock_name[clock_id]);
 
-       ret0 += ret1;
+       vdso_test_clock_gettime(clock_id);
 
-       printf("clock_id: %s", vdso_clock_name[clock_id]);
-
-       if (ret0 > 0)
-               printf(" [FAIL]\n");
-       else
-               printf(" [PASS]\n");
-
-       return ret0;
+       vdso_test_clock_getres(clock_id);
 }
 
+#define VDSO_TEST_PLAN 16
+
 int main(int argc, char **argv)
 {
        unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
-       int ret;
+
+       ksft_print_header();
+       ksft_set_plan(VDSO_TEST_PLAN);
 
        if (!sysinfo_ehdr) {
                printf("AT_SYSINFO_EHDR is not present!\n");
@@ -201,44 +192,42 @@ int main(int argc, char **argv)
 
        vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
 
-       ret = vdso_test_gettimeofday();
+       vdso_test_gettimeofday();
 
 #if _POSIX_TIMERS > 0
 
 #ifdef CLOCK_REALTIME
-       ret += vdso_test_clock(CLOCK_REALTIME);
+       vdso_test_clock(CLOCK_REALTIME);
 #endif
 
 #ifdef CLOCK_BOOTTIME
-       ret += vdso_test_clock(CLOCK_BOOTTIME);
+       vdso_test_clock(CLOCK_BOOTTIME);
 #endif
 
 #ifdef CLOCK_TAI
-       ret += vdso_test_clock(CLOCK_TAI);
+       vdso_test_clock(CLOCK_TAI);
 #endif
 
 #ifdef CLOCK_REALTIME_COARSE
-       ret += vdso_test_clock(CLOCK_REALTIME_COARSE);
+       vdso_test_clock(CLOCK_REALTIME_COARSE);
 #endif
 
 #ifdef CLOCK_MONOTONIC
-       ret += vdso_test_clock(CLOCK_MONOTONIC);
+       vdso_test_clock(CLOCK_MONOTONIC);
 #endif
 
 #ifdef CLOCK_MONOTONIC_RAW
-       ret += vdso_test_clock(CLOCK_MONOTONIC_RAW);
+       vdso_test_clock(CLOCK_MONOTONIC_RAW);
 #endif
 
 #ifdef CLOCK_MONOTONIC_COARSE
-       ret += vdso_test_clock(CLOCK_MONOTONIC_COARSE);
+       vdso_test_clock(CLOCK_MONOTONIC_COARSE);
 #endif
 
 #endif
 
-       ret += vdso_test_time();
-
-       if (ret > 0)
-               return KSFT_FAIL;
+       vdso_test_time();
 
-       return KSFT_PASS;
+       ksft_print_cnts();
+       return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
 }
index d3fd24f..2f49c9a 100644 (file)
@@ -1417,6 +1417,7 @@ static void userfaultfd_pagemap_test(unsigned int test_pgsize)
 static int userfaultfd_stress(void)
 {
        void *area;
+       char *tmp_area;
        unsigned long nr;
        struct uffdio_register uffdio_register;
        struct uffd_stats uffd_stats[nr_cpus];
@@ -1527,9 +1528,13 @@ static int userfaultfd_stress(void)
                                            count_verify[nr], nr);
 
                /* prepare next bounce */
-               swap(area_src, area_dst);
+               tmp_area = area_src;
+               area_src = area_dst;
+               area_dst = tmp_area;
 
-               swap(area_src_alias, area_dst_alias);
+               tmp_area = area_src_alias;
+               area_src_alias = area_dst_alias;
+               area_dst_alias = tmp_area;
 
                uffd_stats_report(uffd_stats, nr_cpus);
        }
index 232e958..b0b91d9 100755 (executable)
@@ -2,9 +2,6 @@
 # SPDX-License-Identifier: GPL-2.0
 TCID="zram.sh"
 
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
-
 . ./zram_lib.sh
 
 run_zram () {
@@ -18,14 +15,4 @@ echo ""
 
 check_prereqs
 
-# check zram module exists
-MODULE_PATH=/lib/modules/`uname -r`/kernel/drivers/block/zram/zram.ko
-if [ -f $MODULE_PATH ]; then
-       run_zram
-elif [ -b /dev/zram0 ]; then
-       run_zram
-else
-       echo "$TCID : No zram.ko module or /dev/zram0 device file not found"
-       echo "$TCID : CONFIG_ZRAM is not set"
-       exit $ksft_skip
-fi
+run_zram
index 114863d..8f4affe 100755 (executable)
@@ -33,9 +33,7 @@ zram_algs="lzo"
 
 zram_fill_fs()
 {
-       local mem_free0=$(free -m | awk 'NR==2 {print $4}')
-
-       for i in $(seq 0 $(($dev_num - 1))); do
+       for i in $(seq $dev_start $dev_end); do
                echo "fill zram$i..."
                local b=0
                while [ true ]; do
@@ -45,29 +43,17 @@ zram_fill_fs()
                        b=$(($b + 1))
                done
                echo "zram$i can be filled with '$b' KB"
-       done
 
-       local mem_free1=$(free -m | awk 'NR==2 {print $4}')
-       local used_mem=$(($mem_free0 - $mem_free1))
+               local mem_used_total=`awk '{print $3}' "/sys/block/zram$i/mm_stat"`
+               local v=$((100 * 1024 * $b / $mem_used_total))
+               if [ "$v" -lt 100 ]; then
+                        echo "FAIL compression ratio: 0.$v:1"
+                        ERR_CODE=-1
+                        return
+               fi
 
-       local total_size=0
-       for sm in $zram_sizes; do
-               local s=$(echo $sm | sed 's/M//')
-               total_size=$(($total_size + $s))
+               echo "zram compression ratio: $(echo "scale=2; $v / 100 " | bc):1: OK"
        done
-
-       echo "zram used ${used_mem}M, zram disk sizes ${total_size}M"
-
-       local v=$((100 * $total_size / $used_mem))
-
-       if [ "$v" -lt 100 ]; then
-               echo "FAIL compression ratio: 0.$v:1"
-               ERR_CODE=-1
-               zram_cleanup
-               return
-       fi
-
-       echo "zram compression ratio: $(echo "scale=2; $v / 100 " | bc):1: OK"
 }
 
 check_prereqs
@@ -81,7 +67,6 @@ zram_mount
 
 zram_fill_fs
 zram_cleanup
-zram_unload
 
 if [ $ERR_CODE -ne 0 ]; then
        echo "$TCID : [FAIL]"
index e83b404..2418b0c 100755 (executable)
@@ -36,7 +36,6 @@ zram_set_memlimit
 zram_makeswap
 zram_swapoff
 zram_cleanup
-zram_unload
 
 if [ $ERR_CODE -ne 0 ]; then
        echo "$TCID : [FAIL]"
index 6f872f2..21ec196 100755 (executable)
@@ -5,12 +5,17 @@
 # Author: Alexey Kodanev <alexey.kodanev@oracle.com>
 # Modified: Naresh Kamboju <naresh.kamboju@linaro.org>
 
-MODULE=0
 dev_makeswap=-1
 dev_mounted=-1
-
+dev_start=0
+dev_end=-1
+module_load=-1
+sys_control=-1
 # Kselftest framework requirement - SKIP code is 4.
 ksft_skip=4
+kernel_version=`uname -r | cut -d'.' -f1,2`
+kernel_major=${kernel_version%.*}
+kernel_minor=${kernel_version#*.}
 
 trap INT
 
@@ -25,68 +30,104 @@ check_prereqs()
        fi
 }
 
+kernel_gte()
+{
+       major=${1%.*}
+       minor=${1#*.}
+
+       if [ $kernel_major -gt $major ]; then
+               return 0
+       elif [[ $kernel_major -eq $major && $kernel_minor -ge $minor ]]; then
+               return 0
+       fi
+
+       return 1
+}
+
 zram_cleanup()
 {
        echo "zram cleanup"
        local i=
-       for i in $(seq 0 $dev_makeswap); do
+       for i in $(seq $dev_start $dev_makeswap); do
                swapoff /dev/zram$i
        done
 
-       for i in $(seq 0 $dev_mounted); do
+       for i in $(seq $dev_start $dev_mounted); do
                umount /dev/zram$i
        done
 
-       for i in $(seq 0 $(($dev_num - 1))); do
+       for i in $(seq $dev_start $dev_end); do
                echo 1 > /sys/block/zram${i}/reset
                rm -rf zram$i
        done
 
-}
+       if [ $sys_control -eq 1 ]; then
+               for i in $(seq $dev_start $dev_end); do
+                       echo $i > /sys/class/zram-control/hot_remove
+               done
+       fi
 
-zram_unload()
-{
-       if [ $MODULE -ne 0 ] ; then
-               echo "zram rmmod zram"
+       if [ $module_load -eq 1 ]; then
                rmmod zram > /dev/null 2>&1
        fi
 }
 
 zram_load()
 {
-       # check zram module exists
-       MODULE_PATH=/lib/modules/`uname -r`/kernel/drivers/block/zram/zram.ko
-       if [ -f $MODULE_PATH ]; then
-               MODULE=1
-               echo "create '$dev_num' zram device(s)"
-               modprobe zram num_devices=$dev_num
-               if [ $? -ne 0 ]; then
-                       echo "failed to insert zram module"
-                       exit 1
-               fi
-
-               dev_num_created=$(ls /dev/zram* | wc -w)
+       echo "create '$dev_num' zram device(s)"
+
+       # zram module loaded, new kernel
+       if [ -d "/sys/class/zram-control" ]; then
+               echo "zram modules already loaded, kernel supports" \
+                       "zram-control interface"
+               dev_start=$(ls /dev/zram* | wc -w)
+               dev_end=$(($dev_start + $dev_num - 1))
+               sys_control=1
+
+               for i in $(seq $dev_start $dev_end); do
+                       cat /sys/class/zram-control/hot_add > /dev/null
+               done
+
+               echo "all zram devices (/dev/zram$dev_start~$dev_end" \
+                       "successfully created"
+               return 0
+       fi
 
-               if [ "$dev_num_created" -ne "$dev_num" ]; then
-                       echo "unexpected num of devices: $dev_num_created"
-                       ERR_CODE=-1
+       # detect old kernel or built-in
+       modprobe zram num_devices=$dev_num
+       if [ ! -d "/sys/class/zram-control" ]; then
+               if grep -q '^zram' /proc/modules; then
+                       rmmod zram > /dev/null 2>&1
+                       if [ $? -ne 0 ]; then
+                               echo "zram module is being used on old kernel" \
+                                       "without zram-control interface"
+                               exit $ksft_skip
+                       fi
                else
-                       echo "zram load module successful"
+                       echo "test needs CONFIG_ZRAM=m on old kernel without" \
+                               "zram-control interface"
+                       exit $ksft_skip
                fi
-       elif [ -b /dev/zram0 ]; then
-               echo "/dev/zram0 device file found: OK"
-       else
-               echo "ERROR: No zram.ko module or no /dev/zram0 device found"
-               echo "$TCID : CONFIG_ZRAM is not set"
-               exit 1
+               modprobe zram num_devices=$dev_num
        fi
+
+       module_load=1
+       dev_end=$(($dev_num - 1))
+       echo "all zram devices (/dev/zram0~$dev_end) successfully created"
 }
 
 zram_max_streams()
 {
        echo "set max_comp_streams to zram device(s)"
 
-       local i=0
+       kernel_gte 4.7
+       if [ $? -eq 0 ]; then
+               echo "The device attribute max_comp_streams was"\
+                              "deprecated in 4.7"
+               return 0
+       fi
+
+       local i=$dev_start
        for max_s in $zram_max_streams; do
                local sys_path="/sys/block/zram${i}/max_comp_streams"
                echo $max_s > $sys_path || \
@@ -98,7 +139,7 @@ zram_max_streams()
                        echo "FAIL can't set max_streams '$max_s', get $max_stream"
 
                i=$(($i + 1))
-               echo "$sys_path = '$max_streams' ($i/$dev_num)"
+               echo "$sys_path = '$max_streams'"
        done
 
        echo "zram max streams: OK"
@@ -108,15 +149,16 @@ zram_compress_alg()
 {
        echo "test that we can set compression algorithm"
 
-       local algs=$(cat /sys/block/zram0/comp_algorithm)
+       local i=$dev_start
+       local algs=$(cat /sys/block/zram${i}/comp_algorithm)
        echo "supported algs: $algs"
-       local i=0
+
        for alg in $zram_algs; do
                local sys_path="/sys/block/zram${i}/comp_algorithm"
                echo "$alg" >   $sys_path || \
                        echo "FAIL can't set '$alg' to $sys_path"
                i=$(($i + 1))
-               echo "$sys_path = '$alg' ($i/$dev_num)"
+               echo "$sys_path = '$alg'"
        done
 
        echo "zram set compression algorithm: OK"
@@ -125,14 +167,14 @@ zram_compress_alg()
 zram_set_disksizes()
 {
        echo "set disk size to zram device(s)"
-       local i=0
+       local i=$dev_start
        for ds in $zram_sizes; do
                local sys_path="/sys/block/zram${i}/disksize"
                echo "$ds" >    $sys_path || \
                        echo "FAIL can't set '$ds' to $sys_path"
 
                i=$(($i + 1))
-               echo "$sys_path = '$ds' ($i/$dev_num)"
+               echo "$sys_path = '$ds'"
        done
 
        echo "zram set disksizes: OK"
@@ -142,14 +184,14 @@ zram_set_memlimit()
 {
        echo "set memory limit to zram device(s)"
 
-       local i=0
+       local i=$dev_start
        for ds in $zram_mem_limits; do
                local sys_path="/sys/block/zram${i}/mem_limit"
                echo "$ds" >    $sys_path || \
                        echo "FAIL can't set '$ds' to $sys_path"
 
                i=$(($i + 1))
-               echo "$sys_path = '$ds' ($i/$dev_num)"
+               echo "$sys_path = '$ds'"
        done
 
        echo "zram set memory limit: OK"
@@ -158,8 +200,8 @@ zram_set_memlimit()
 zram_makeswap()
 {
        echo "make swap with zram device(s)"
-       local i=0
-       for i in $(seq 0 $(($dev_num - 1))); do
+       local i=$dev_start
+       for i in $(seq $dev_start $dev_end); do
                mkswap /dev/zram$i > err.log 2>&1
                if [ $? -ne 0 ]; then
                        cat err.log
@@ -182,7 +224,7 @@ zram_makeswap()
 zram_swapoff()
 {
        local i=
-       for i in $(seq 0 $dev_makeswap); do
+       for i in $(seq $dev_start $dev_end); do
                swapoff /dev/zram$i > err.log 2>&1
                if [ $? -ne 0 ]; then
                        cat err.log
@@ -196,7 +238,7 @@ zram_swapoff()
 
 zram_makefs()
 {
-       local i=0
+       local i=$dev_start
        for fs in $zram_filesystems; do
                # if requested fs not supported default it to ext2
                which mkfs.$fs > /dev/null 2>&1 || fs=ext2
@@ -215,7 +257,7 @@ zram_makefs()
 zram_mount()
 {
        local i=0
-       for i in $(seq 0 $(($dev_num - 1))); do
+       for i in $(seq $dev_start $dev_end); do
                echo "mount /dev/zram$i"
                mkdir zram$i
                mount /dev/zram$i zram$i > /dev/null || \
index 87e0ec4..95e485f 100644 (file)
@@ -1,11 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0
 include ../scripts/Makefile.include
 
-all: latency
+all: latency rtla
 
-clean: latency_clean
+clean: latency_clean rtla_clean
 
-install: latency_install
+install: latency_install rtla_install
 
 latency:
        $(call descend,latency)
@@ -16,4 +16,14 @@ latency_install:
 latency_clean:
        $(call descend,latency,clean)
 
-.PHONY: all install clean latency latency_install latency_clean
+rtla:
+       $(call descend,rtla)
+
+rtla_install:
+       $(call descend,rtla,install)
+
+rtla_clean:
+       $(call descend,rtla,clean)
+
+.PHONY: all install clean latency latency_install latency_clean \
+       rtla rtla_install rtla_clean
index 2d52ff0..5a1eda6 100644 (file)
@@ -1,5 +1,6 @@
 NAME   :=      rtla
-VERSION        :=      0.5
+# Follow the kernel version
+VERSION :=     $(shell cat VERSION 2> /dev/null || make -sC ../../.. kernelversion)
 
 # From libtracefs:
 # Makefiles suck: This macro sets a default value of $(2) for the
@@ -59,7 +60,7 @@ endif
 .PHONY:        all
 all:   rtla
 
-rtla: $(OBJ) doc
+rtla: $(OBJ)
        $(CC) -o rtla $(LDFLAGS) $(OBJ) $(LIBS)
 
 static: $(OBJ)
@@ -85,6 +86,7 @@ clean: doc_clean
 
 tarball: clean
        rm -rf $(NAME)-$(VERSION) && mkdir $(NAME)-$(VERSION)
+       echo $(VERSION) > $(NAME)-$(VERSION)/VERSION
        cp -r $(DIRS) $(FILES) $(NAME)-$(VERSION)
        mkdir $(NAME)-$(VERSION)/Documentation/
        cp -rp $(SRCTREE)/../../../Documentation/tools/rtla/* $(NAME)-$(VERSION)/Documentation/
index 7b73d1e..5648f92 100644 (file)
@@ -750,6 +750,9 @@ void osnoise_put_context(struct osnoise_context *context)
  */
 void osnoise_destroy_tool(struct osnoise_tool *top)
 {
+       if (!top)
+               return;
+
        trace_instance_destroy(&top->trace);
 
        if (top->context)
index 180fcbe..1f0b7fc 100644 (file)
@@ -701,9 +701,9 @@ osnoise_hist_set_signals(struct osnoise_hist_params *params)
 int osnoise_hist_main(int argc, char *argv[])
 {
        struct osnoise_hist_params *params;
+       struct osnoise_tool *record = NULL;
+       struct osnoise_tool *tool = NULL;
        struct trace_instance *trace;
-       struct osnoise_tool *record;
-       struct osnoise_tool *tool;
        int return_value = 1;
        int retval;
 
@@ -792,9 +792,8 @@ int osnoise_hist_main(int argc, char *argv[])
 out_hist:
        osnoise_free_histogram(tool->data);
 out_destroy:
+       osnoise_destroy_tool(record);
        osnoise_destroy_tool(tool);
-       if (params->trace_output)
-               osnoise_destroy_tool(record);
        free(params);
 out_exit:
        exit(return_value);
index 332b2ac..c67dc28 100644 (file)
@@ -483,9 +483,9 @@ static void osnoise_top_set_signals(struct osnoise_top_params *params)
 int osnoise_top_main(int argc, char **argv)
 {
        struct osnoise_top_params *params;
+       struct osnoise_tool *record = NULL;
+       struct osnoise_tool *tool = NULL;
        struct trace_instance *trace;
-       struct osnoise_tool *record;
-       struct osnoise_tool *tool;
        int return_value = 1;
        int retval;
 
@@ -571,9 +571,8 @@ int osnoise_top_main(int argc, char **argv)
 
 out_top:
        osnoise_free_top(tool->data);
+       osnoise_destroy_tool(record);
        osnoise_destroy_tool(tool);
-       if (params->trace_output)
-               osnoise_destroy_tool(record);
 out_exit:
        exit(return_value);
 }
index 235f962..436a799 100644 (file)
@@ -729,9 +729,9 @@ timerlat_hist_set_signals(struct timerlat_hist_params *params)
 int timerlat_hist_main(int argc, char *argv[])
 {
        struct timerlat_hist_params *params;
+       struct osnoise_tool *record = NULL;
+       struct osnoise_tool *tool = NULL;
        struct trace_instance *trace;
-       struct osnoise_tool *record;
-       struct osnoise_tool *tool;
        int return_value = 1;
        int retval;
 
@@ -813,9 +813,8 @@ int timerlat_hist_main(int argc, char *argv[])
 
 out_hist:
        timerlat_free_histogram(tool->data);
+       osnoise_destroy_tool(record);
        osnoise_destroy_tool(tool);
-       if (params->trace_output)
-               osnoise_destroy_tool(record);
        free(params);
 out_exit:
        exit(return_value);
index 1ebd529..d4187f6 100644 (file)
@@ -521,9 +521,9 @@ timerlat_top_set_signals(struct timerlat_top_params *params)
 int timerlat_top_main(int argc, char *argv[])
 {
        struct timerlat_top_params *params;
+       struct osnoise_tool *record = NULL;
+       struct osnoise_tool *top = NULL;
        struct trace_instance *trace;
-       struct osnoise_tool *record;
-       struct osnoise_tool *top;
        int return_value = 1;
        int retval;
 
@@ -609,9 +609,8 @@ int timerlat_top_main(int argc, char *argv[])
 
 out_top:
        timerlat_free_top(top->data);
+       osnoise_destroy_tool(record);
        osnoise_destroy_tool(top);
-       if (params->trace_output)
-               osnoise_destroy_tool(record);
        free(params);
 out_exit:
        exit(return_value);
index 107a0c6..83de259 100644 (file)
@@ -20,14 +20,14 @@ int enable_tracer_by_name(struct tracefs_instance *inst, const char *tracer_name
 
        tracer = TRACEFS_TRACER_CUSTOM;
 
-       debug_msg("enabling %s tracer\n", tracer_name);
+       debug_msg("Enabling %s tracer\n", tracer_name);
 
        retval = tracefs_tracer_set(inst, tracer, tracer_name);
        if (retval < 0) {
                if (errno == ENODEV)
-                       err_msg("tracer %s not found!\n", tracer_name);
+                       err_msg("Tracer %s not found!\n", tracer_name);
 
-               err_msg("failed to enable the tracer %s\n", tracer_name);
+               err_msg("Failed to enable the %s tracer\n", tracer_name);
                return -1;
        }
 
@@ -44,7 +44,7 @@ void disable_tracer(struct tracefs_instance *inst)
 
        retval = tracefs_tracer_set(inst, t);
        if (retval < 0)
-               err_msg("oops, error disabling tracer\n");
+               err_msg("Oops, error disabling tracer\n");
 }
 
 /*
index 1c9f0ee..ffaf8ec 100644 (file)
@@ -77,11 +77,11 @@ void get_duration(time_t start_time, char *output, int output_size)
        time_t duration;
 
        duration = difftime(now, start_time);
-       tm_info = localtime(&duration);
+       tm_info = gmtime(&duration);
 
        snprintf(output, output_size, "%3d %02d:%02d:%02d",
                        tm_info->tm_yday,
-                       tm_info->tm_hour - 1,
+                       tm_info->tm_hour,
                        tm_info->tm_min,
                        tm_info->tm_sec);
 }
index 7be7468..83822c3 100644 (file)
@@ -28,6 +28,7 @@ no-header-test += linux/am437x-vpfe.h
 no-header-test += linux/android/binder.h
 no-header-test += linux/android/binderfs.h
 no-header-test += linux/coda.h
+no-header-test += linux/cyclades.h
 no-header-test += linux/errqueue.h
 no-header-test += linux/fsmap.h
 no-header-test += linux/hdlc/ioctl.h
index 2ad013b..59b1dd4 100644 (file)
@@ -463,8 +463,8 @@ bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin)
        idx = srcu_read_lock(&kvm->irq_srcu);
        gsi = kvm_irq_map_chip_pin(kvm, irqchip, pin);
        if (gsi != -1)
-               hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list,
-                                        link)
+               hlist_for_each_entry_srcu(kian, &kvm->irq_ack_notifier_list,
+                                         link, srcu_read_lock_held(&kvm->irq_srcu))
                        if (kian->gsi == gsi) {
                                srcu_read_unlock(&kvm->irq_srcu, idx);
                                return true;
@@ -480,8 +480,8 @@ void kvm_notify_acked_gsi(struct kvm *kvm, int gsi)
 {
        struct kvm_irq_ack_notifier *kian;
 
-       hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list,
-                                link)
+       hlist_for_each_entry_srcu(kian, &kvm->irq_ack_notifier_list,
+                                 link, srcu_read_lock_held(&kvm->irq_srcu))
                if (kian->gsi == gsi)
                        kian->irq_acked(kian);
 }
index 9a20f22..58d31da 100644 (file)
@@ -2248,7 +2248,6 @@ struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn
 
        return NULL;
 }
-EXPORT_SYMBOL_GPL(kvm_vcpu_gfn_to_memslot);
 
 bool kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn)
 {
@@ -2463,9 +2462,8 @@ static int kvm_try_get_pfn(kvm_pfn_t pfn)
 }
 
 static int hva_to_pfn_remapped(struct vm_area_struct *vma,
-                              unsigned long addr, bool *async,
-                              bool write_fault, bool *writable,
-                              kvm_pfn_t *p_pfn)
+                              unsigned long addr, bool write_fault,
+                              bool *writable, kvm_pfn_t *p_pfn)
 {
        kvm_pfn_t pfn;
        pte_t *ptep;
@@ -2575,7 +2573,7 @@ retry:
        if (vma == NULL)
                pfn = KVM_PFN_ERR_FAULT;
        else if (vma->vm_flags & (VM_IO | VM_PFNMAP)) {
-               r = hva_to_pfn_remapped(vma, addr, async, write_fault, writable, &pfn);
+               r = hva_to_pfn_remapped(vma, addr, write_fault, writable, &pfn);
                if (r == -EAGAIN)
                        goto retry;
                if (r < 0)