Merge tag 'block-5.6-2020-03-07' of git://git.kernel.dk/linux-block
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 7 Mar 2020 20:14:38 +0000 (14:14 -0600)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 7 Mar 2020 20:14:38 +0000 (14:14 -0600)
Pull block fixes from Jens Axboe:
 "Here are a few fixes that should go into this release. This contains:

   - Revert of a bad bcache patch from this merge window

   - Removed unused function (Daniel)

   - Fixup for the blktrace fix from Jan from this release (Cengiz)

   - Fix of deeper level bfqq overwrite in BFQ (Carlo)"

* tag 'block-5.6-2020-03-07' of git://git.kernel.dk/linux-block:
  block, bfq: fix overwrite of bfq_group pointer in bfq_find_set_group()
  blktrace: fix dereference after null check
  Revert "bcache: ignore pending signals when creating gc and allocator thread"
  block: Remove used kblockd_schedule_work_on()

449 files changed:
CREDITS
Documentation/admin-guide/acpi/fan_performance_states.rst
Documentation/admin-guide/bootconfig.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/dev-tools/kunit/usage.rst
Documentation/devicetree/bindings/arm/arm,scmi.txt
Documentation/devicetree/bindings/arm/arm,scpi.txt
Documentation/devicetree/bindings/arm/bcm/brcm,bcm63138.txt
Documentation/devicetree/bindings/arm/cpus.yaml
Documentation/devicetree/bindings/arm/fsl.yaml
Documentation/devicetree/bindings/arm/hisilicon/hi3519-sysctrl.txt
Documentation/devicetree/bindings/arm/msm/qcom,idle-state.txt
Documentation/devicetree/bindings/arm/omap/mpu.txt
Documentation/devicetree/bindings/arm/psci.yaml
Documentation/devicetree/bindings/arm/stm32/st,mlahb.yaml
Documentation/devicetree/bindings/bus/allwinner,sun8i-a23-rsb.yaml
Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-osc-clk.yaml
Documentation/devicetree/bindings/clock/allwinner,sun9i-a80-gt-clk.yaml
Documentation/devicetree/bindings/clock/qcom,gcc-apq8064.yaml
Documentation/devicetree/bindings/display/allwinner,sun4i-a10-tv-encoder.yaml
Documentation/devicetree/bindings/display/bridge/anx6345.yaml
Documentation/devicetree/bindings/display/panel/leadtek,ltk500hd1829.yaml
Documentation/devicetree/bindings/display/panel/xinpeng,xpp055c272.yaml
Documentation/devicetree/bindings/display/simple-framebuffer.yaml
Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt
Documentation/devicetree/bindings/dma/ti/k3-udma.yaml
Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml
Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml
Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml
Documentation/devicetree/bindings/input/touchscreen/goodix.yaml
Documentation/devicetree/bindings/input/twl4030-pwrbutton.txt
Documentation/devicetree/bindings/leds/common.yaml
Documentation/devicetree/bindings/leds/register-bit-led.txt
Documentation/devicetree/bindings/media/ti,cal.yaml
Documentation/devicetree/bindings/memory-controllers/ti/emif.txt
Documentation/devicetree/bindings/mfd/max77650.yaml
Documentation/devicetree/bindings/mfd/tps65910.txt
Documentation/devicetree/bindings/mfd/twl-family.txt [moved from Documentation/devicetree/bindings/mfd/twl-familly.txt with 100% similarity]
Documentation/devicetree/bindings/mfd/zii,rave-sp.txt
Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
Documentation/devicetree/bindings/mmc/mmc-controller.yaml
Documentation/devicetree/bindings/mtd/cadence-nand-controller.txt
Documentation/devicetree/bindings/net/brcm,bcm7445-switch-v4.0.txt
Documentation/devicetree/bindings/nvmem/nvmem.yaml
Documentation/devicetree/bindings/phy/allwinner,sun4i-a10-usb-phy.yaml
Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml
Documentation/devicetree/bindings/power/domain-idle-state.txt [deleted file]
Documentation/devicetree/bindings/power/domain-idle-state.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/power/power-domain.yaml
Documentation/devicetree/bindings/power/power_domain.txt
Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt
Documentation/devicetree/bindings/regulator/regulator.yaml
Documentation/devicetree/bindings/reset/st,stm32mp1-rcc.txt
Documentation/devicetree/bindings/sound/st,stm32-sai.txt
Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt
Documentation/devicetree/bindings/spi/st,stm32-spi.yaml
Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml
Documentation/devicetree/bindings/thermal/brcm,avs-ro-thermal.yaml
Documentation/devicetree/bindings/timer/allwinner,sun4i-a10-timer.yaml
Documentation/driver-api/dmaengine/client.rst
Documentation/hwmon/adm1177.rst
Documentation/kbuild/makefiles.rst
Documentation/networking/phy.rst
Documentation/power/index.rst
Documentation/sphinx/parallel-wrapper.sh
Documentation/virt/kvm/api.rst
Documentation/x86/index.rst
MAINTAINERS
Makefile
arch/Kconfig
arch/arm/include/asm/kvm_host.h
arch/arm64/include/asm/arch_gicv3.h
arch/arm64/include/asm/cache.h
arch/arm64/include/asm/cacheflush.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/io.h
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/kvm_hyp.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/include/asm/virt.h
arch/arm64/kvm/hyp/switch.c
arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c
arch/arm64/mm/context.c
arch/mips/boot/dts/ingenic/jz4740.dtsi
arch/mips/boot/dts/ingenic/jz4780.dtsi
arch/mips/boot/dts/ingenic/x1000.dtsi
arch/mips/include/asm/sync.h
arch/mips/kernel/vpe.c
arch/mips/vdso/Makefile
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/hw_breakpoint.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/mm/mem.c
arch/riscv/Kconfig
arch/riscv/Kconfig.socs
arch/riscv/Makefile
arch/riscv/boot/.gitignore
arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
arch/riscv/configs/defconfig
arch/riscv/configs/rv32_defconfig
arch/riscv/include/asm/csr.h
arch/riscv/include/asm/syscall.h
arch/riscv/kernel/entry.S
arch/riscv/kernel/head.S
arch/riscv/kernel/module.c
arch/riscv/kernel/ptrace.c
arch/riscv/kernel/traps.c
arch/riscv/mm/init.c
arch/riscv/mm/kasan_init.c
arch/s390/include/asm/pgtable.h
arch/s390/pci/pci.c
arch/x86/include/asm/io_bitmap.h
arch/x86/include/asm/kvm_emulate.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/vmx.h
arch/x86/include/asm/vmxfeatures.h
arch/x86/include/uapi/asm/kvm.h
arch/x86/kernel/cpu/common.c
arch/x86/kernel/kvm.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/process.c
arch/x86/kvm/Kconfig
arch/x86/kvm/Makefile
arch/x86/kvm/emulate.c
arch/x86/kvm/irq_comm.c
arch/x86/kvm/lapic.c
arch/x86/kvm/mmutrace.h
arch/x86/kvm/svm.c
arch/x86/kvm/vmx/capabilities.h
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/nested.h
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/vmx/vmx.h
arch/x86/kvm/x86.c
arch/x86/mm/dump_pagetables.c
arch/x86/platform/efi/efi_64.c
arch/x86/xen/enlighten_pv.c
drivers/acpi/acpi_watchdog.c
drivers/base/swnode.c
drivers/block/floppy.c
drivers/block/paride/pcd.c
drivers/block/xen-blkfront.c
drivers/cdrom/gdrom.c
drivers/cpufreq/cpufreq.c
drivers/devfreq/devfreq.c
drivers/dma-buf/dma-buf.c
drivers/dma/coh901318.c
drivers/dma/idxd/cdev.c
drivers/dma/idxd/sysfs.c
drivers/dma/imx-sdma.c
drivers/dma/tegra20-apb-dma.c
drivers/dma/ti/k3-udma.c
drivers/firmware/efi/efi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c
drivers/gpu/drm/amd/include/asic_reg/dce/dce_12_0_offset.h
drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
drivers/gpu/drm/amd/powerplay/renoir_ppt.c
drivers/gpu/drm/amd/powerplay/smu_v11_0.c
drivers/gpu/drm/amd/powerplay/smu_v12_0.c
drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
drivers/gpu/drm/drm_gem_shmem_helper.c
drivers/gpu/drm/exynos/exynos_drm_dsi.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h
drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/display/intel_display_power.c
drivers/gpu/drm/i915/display/intel_psr.c
drivers/gpu/drm/i915/display/intel_psr.h
drivers/gpu/drm/i915/gem/i915_gem_object.c
drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
drivers/gpu/drm/i915/gt/intel_gt_requests.c
drivers/gpu/drm/i915/gt/intel_workarounds.c
drivers/gpu/drm/i915/gvt/dmabuf.c
drivers/gpu/drm/i915/gvt/vgpu.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_pci.c
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/i915/i915_perf_types.h
drivers/gpu/drm/i915/i915_pmu.c
drivers/gpu/drm/i915/i915_pmu.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_request.c
drivers/gpu/drm/mediatek/mtk_drm_crtc.c
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
drivers/gpu/drm/mediatek/mtk_drm_plane.c
drivers/gpu/drm/panfrost/panfrost_mmu.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/sun4i/sun8i_mixer.c
drivers/gpu/drm/sun4i/sun8i_mixer.h
drivers/gpu/drm/sun4i/sun8i_vi_layer.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/virtio/virtgpu_object.c
drivers/hid/hid-alps.c
drivers/hid/hid-apple.c
drivers/hid/hid-bigbenff.c
drivers/hid/hid-core.c
drivers/hid/hid-hyperv.c
drivers/hid/hid-ite.c
drivers/hid/hid-logitech-hidpp.c
drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
drivers/hid/usbhid/hiddev.c
drivers/hwmon/adt7462.c
drivers/hwmon/pmbus/xdpe12284.c
drivers/i2c/busses/i2c-altera.c
drivers/i2c/busses/i2c-jz4780.c
drivers/ide/ide-gd.c
drivers/macintosh/therm_windtunnel.c
drivers/md/dm-bio-record.h
drivers/md/dm-cache-target.c
drivers/md/dm-integrity.c
drivers/md/dm-mpath.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-verity-target.c
drivers/md/dm-writecache.c
drivers/md/dm-zoned-target.c
drivers/md/dm.c
drivers/media/mc/mc-entity.c
drivers/media/platform/vicodec/codec-v4l2-fwht.c
drivers/media/usb/pulse8-cec/pulse8-cec.c
drivers/media/v4l2-core/v4l2-mem2mem.c
drivers/net/dsa/bcm_sf2.c
drivers/net/dsa/mv88e6xxx/global1.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
drivers/net/ethernet/broadcom/genet/bcmmii.c
drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
drivers/net/ethernet/huawei/hinic/hinic_hw_if.h
drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h
drivers/net/ethernet/huawei/hinic/hinic_main.c
drivers/net/ethernet/huawei/hinic/hinic_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
drivers/net/ethernet/mellanox/mlx5/core/lag.c
drivers/net/ethernet/mellanox/mlx5/core/lag.h
drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
drivers/net/ethernet/mellanox/mlxsw/pci_hw.h
drivers/net/ethernet/micrel/ks8851_mll.c
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h
drivers/net/ethernet/sfc/ptp.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/xilinx/ll_temac.h
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/phy/marvell.c
drivers/net/phy/mscc.c
drivers/net/phy/phy-c45.c
drivers/net/phy/phy_device.c
drivers/net/slip/slip.c
drivers/net/usb/qmi_wwan.c
drivers/pci/controller/pcie-brcmstb.c
drivers/perf/arm_pmu_acpi.c
drivers/perf/fsl_imx8_ddr_perf.c
drivers/platform/chrome/wilco_ec/properties.c
drivers/regulator/stm32-vrefbuf.c
drivers/s390/scsi/zfcp_fsf.h
drivers/s390/scsi/zfcp_sysfs.c
drivers/scsi/libfc/fc_disc.c
drivers/scsi/sd_zbc.c
drivers/scsi/sr.c
drivers/spi/atmel-quadspi.c
drivers/spi/spi-bcm63xx-hsspi.c
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-qup.c
drivers/spi/spi-zynqmp-gqspi.c
drivers/spi/spi.c
drivers/spi/spidev.c
drivers/staging/media/hantro/hantro_drv.c
drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
drivers/tee/amdtee/Kconfig
drivers/vhost/net.c
drivers/video/console/vgacon.c
drivers/watchdog/wdat_wdt.c
drivers/xen/xen-pciback/pciback.h
drivers/xen/xenbus/xenbus_comms.c
drivers/xen/xenbus/xenbus_probe.c
drivers/xen/xenbus/xenbus_probe_backend.c
drivers/xen/xenbus/xenbus_xs.c
fs/btrfs/inode.c
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/smb1ops.c
fs/cifs/smb2inode.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/ext4/super.c
fs/fat/inode.c
fs/fcntl.c
fs/io-wq.c
fs/io-wq.h
fs/io_uring.c
fs/jbd2/transaction.c
fs/locks.c
fs/zonefs/Kconfig
fs/zonefs/super.c
include/acpi/actypes.h
include/drm/drm_gem_shmem_helper.h
include/linux/bootconfig.h
include/linux/hid.h
include/linux/icmpv6.h
include/linux/kvm_host.h
include/linux/mm.h
include/linux/netfilter/ipset/ip_set.h
include/linux/platform_data/spi-omap2-mcspi.h
include/sound/soc.h
include/uapi/linux/dm-ioctl.h
include/xen/interface/io/tpmif.h
include/xen/xenbus.h
init/Kconfig
init/main.c
kernel/audit.c
kernel/auditfilter.c
kernel/exit.c
kernel/fork.c
kernel/power/snapshot.c
kernel/sched/fair.c
kernel/signal.c
kernel/trace/Kconfig
kernel/trace/synth_event_gen_test.c
kernel/trace/trace.c
kernel/trace/trace_events_hist.c
lib/bootconfig.c
lib/crypto/chacha20poly1305.c
mm/huge_memory.c
mm/memory.c
mm/memory_hotplug.c
mm/mprotect.c
mm/shmem.c
mm/z3fold.c
net/bridge/br_device.c
net/core/dev.c
net/core/devlink.c
net/ethtool/bitset.c
net/ethtool/bitset.h
net/ipv4/cipso_ipv4.c
net/ipv4/tcp_input.c
net/ipv6/ipv6_sockglue.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mptcp/protocol.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_hash_gen.h
net/netfilter/nft_set_pipapo.c
net/netfilter/xt_hashlimit.c
net/netlink/genetlink.c
net/sched/act_api.c
net/smc/af_smc.c
net/smc/smc_core.c
net/smc/smc_core.h
net/smc/smc_ib.c
net/unix/af_unix.c
net/vmw_vsock/af_vsock.c
net/vmw_vsock/hyperv_transport.c
net/vmw_vsock/virtio_transport_common.c
net/wireless/nl80211.c
net/wireless/reg.c
scripts/Makefile.lib
scripts/parse-maintainers.pl [changed mode: 0644->0755]
sound/mips/sgio2audio.c
sound/pci/hda/patch_realtek.c
sound/soc/codecs/Kconfig
sound/soc/codecs/pcm512x.c
sound/soc/codecs/rt1015.c
sound/soc/codecs/tas2562.c
sound/soc/intel/skylake/skl-debug.c
sound/soc/intel/skylake/skl-ssp-clk.c
sound/soc/meson/g12a-tohdmitx.c
sound/soc/soc-component.c
sound/soc/soc-compress.c
sound/soc/soc-dapm.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c
sound/soc/sof/ipc.c
sound/soc/stm/stm32_sai_sub.c
tools/arch/x86/include/asm/msr-index.h
tools/arch/x86/include/uapi/asm/kvm.h
tools/bootconfig/include/linux/printk.h
tools/bootconfig/main.c
tools/bootconfig/samples/bad-mixed-kv1.bconf [new file with mode: 0644]
tools/bootconfig/samples/bad-mixed-kv2.bconf [new file with mode: 0644]
tools/bootconfig/samples/bad-samekey.bconf [new file with mode: 0644]
tools/bootconfig/test-bootconfig.sh
tools/perf/Documentation/perf-config.txt
tools/perf/arch/arm/util/cs-etm.c
tools/perf/arch/arm64/util/arm-spe.c
tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
tools/perf/arch/x86/util/intel-bts.c
tools/perf/arch/x86/util/intel-pt.c
tools/perf/builtin-annotate.c
tools/perf/builtin-probe.c
tools/perf/builtin-report.c
tools/perf/builtin-top.c
tools/perf/include/bpf/pid_filter.h
tools/perf/include/bpf/stdio.h
tools/perf/include/bpf/unistd.h
tools/perf/tests/shell/lib/probe_vfs_getname.sh
tools/perf/ui/browsers/annotate.c
tools/perf/ui/gtk/annotate.c
tools/perf/util/annotate.c
tools/perf/util/annotate.h
tools/perf/util/auxtrace.c
tools/perf/util/auxtrace.h
tools/perf/util/config.c
tools/perf/util/config.h
tools/perf/util/probe-file.c
tools/testing/kunit/kunit.py
tools/testing/kunit/kunit_kernel.py
tools/testing/selftests/ftrace/Makefile
tools/testing/selftests/livepatch/Makefile
tools/testing/selftests/lkdtm/.gitignore [new file with mode: 0644]
tools/testing/selftests/net/mptcp/Makefile
tools/testing/selftests/netfilter/nft_concat_range.sh
tools/testing/selftests/pidfd/.gitignore
tools/testing/selftests/rseq/Makefile
tools/testing/selftests/rtc/Makefile
virt/kvm/arm/arm.c
virt/kvm/arm/trace.h

diff --git a/CREDITS b/CREDITS
index a97d328..032b599 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -567,6 +567,11 @@ D: Original author of Amiga FFS filesystem
 S: Orlando, Florida
 S: USA
 
+N: Paul Burton
+E: paulburton@kernel.org
+W: https://pburton.com
+D: MIPS maintainer 2018-2020
+
 N: Lennert Buytenhek
 E: kernel@wantstofly.org
 D: Original (2.4) rewrite of the ethernet bridging code
index 21d233c..98fe5c3 100644 (file)
@@ -18,7 +18,7 @@ may look as follows::
 
  $ ls -l /sys/bus/acpi/devices/INT3404:00/
  total 0
-...
+ ...
  -r--r--r-- 1 root root 4096 Dec 13 20:38 state0
  -r--r--r-- 1 root root 4096 Dec 13 20:38 state1
  -r--r--r-- 1 root root 4096 Dec 13 20:38 state10
@@ -38,7 +38,7 @@ where each of the "state*" files represents one performance state of the fan
 and contains a colon-separated list of 5 integer numbers (fields) with the
 following interpretation::
 
-control_percent:trip_point_index:speed_rpm:noise_level_mdb:power_mw
+  control_percent:trip_point_index:speed_rpm:noise_level_mdb:power_mw
 
 * ``control_percent``: The percent value to be used to set the fan speed to a
   specific level using the _FSL object (0-100).
index b342a67..cf2edcd 100644 (file)
@@ -62,6 +62,30 @@ Or more shorter, written as following::
 In both styles, same key words are automatically merged when parsing it
 at boot time. So you can append similar trees or key-values.
 
+Same-key Values
+---------------
+
+It is prohibited that two or more values or arrays share a same-key.
+For example,::
+
+ foo = bar, baz
+ foo = qux  # !ERROR! we can not re-define same key
+
+If you want to append the value to existing key as an array member,
+you can use ``+=`` operator. For example::
+
+ foo = bar, baz
+ foo += qux
+
+In this case, the key ``foo`` has ``bar``, ``baz`` and ``qux``.
+
+However, a sub-key and a value can not co-exist under a parent key.
+For example, following config is NOT allowed.::
+
+ foo = value1
+ foo.bar = value2 # !ERROR! subkey "bar" and value "value1" can NOT co-exist
+
+
 Comments
 --------
 
@@ -102,9 +126,13 @@ Boot Kernel With a Boot Config
 ==============================
 
 Since the boot configuration file is loaded with initrd, it will be added
-to the end of the initrd (initramfs) image file. The Linux kernel decodes
-the last part of the initrd image in memory to get the boot configuration
-data.
+to the end of the initrd (initramfs) image file with size, checksum and
+12-byte magic word as below.
+
+[initrd][bootconfig][size(u32)][checksum(u32)][#BOOTCONFIG\n]
+
+The Linux kernel decodes the last part of the initrd image in memory to
+get the boot configuration data.
 Because of this "piggyback" method, there is no need to change or
 update the boot loader and the kernel image itself.
 
index dbc22d6..c07815d 100644 (file)
                        dynamic table installation which will install SSDT
                        tables to /sys/firmware/acpi/tables/dynamic.
 
+       acpi_no_watchdog        [HW,ACPI,WDT]
+                       Ignore the ACPI-based watchdog interface (WDAT) and let
+                       a native driver control the watchdog device instead.
+
        acpi_rsdp=      [ACPI,EFI,KEXEC]
                        Pass the RSDP address to the kernel, mostly used
                        on machines running EFI runtime service to boot the
index 7cd56a1..607758a 100644 (file)
@@ -551,6 +551,7 @@ options to your ``.config``:
 Once the kernel is built and installed, a simple
 
 .. code-block:: bash
+
        modprobe example-test
 
 ...will run the tests.
index f493d69..dc102c4 100644 (file)
@@ -102,7 +102,7 @@ Required sub-node properties:
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
 [2] Documentation/devicetree/bindings/power/power-domain.yaml
 [3] Documentation/devicetree/bindings/thermal/thermal.txt
-[4] Documentation/devicetree/bindings/sram/sram.txt
+[4] Documentation/devicetree/bindings/sram/sram.yaml
 [5] Documentation/devicetree/bindings/reset/reset.txt
 
 Example:
index 7b83ef4..dd04d9d 100644 (file)
@@ -109,7 +109,7 @@ Required properties:
 [0] http://infocenter.arm.com/help/topic/com.arm.doc.dui0922b/index.html
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
 [2] Documentation/devicetree/bindings/thermal/thermal.txt
-[3] Documentation/devicetree/bindings/sram/sram.txt
+[3] Documentation/devicetree/bindings/sram/sram.yaml
 [4] Documentation/devicetree/bindings/power/power-domain.yaml
 
 Example:
index b82b6a0..8c7a490 100644 (file)
@@ -62,7 +62,7 @@ Timer node:
 
 Syscon reboot node:
 
-See Documentation/devicetree/bindings/power/reset/syscon-reboot.txt for the
+See Documentation/devicetree/bindings/power/reset/syscon-reboot.yaml for the
 detailed list of properties, the two values defined below are specific to the
 BCM6328-style timer:
 
index 7a9c3ce..0d5b610 100644 (file)
@@ -216,7 +216,7 @@ properties:
     $ref: '/schemas/types.yaml#/definitions/phandle-array'
     description: |
       List of phandles to idle state nodes supported
-      by this cpu (see ./idle-states.txt).
+      by this cpu (see ./idle-states.yaml).
 
   capacity-dmips-mhz:
     $ref: '/schemas/types.yaml#/definitions/uint32'
index a8e0b4a..0e17e1f 100644 (file)
@@ -160,7 +160,7 @@ properties:
         items:
           - enum:
               - armadeus,imx6dl-apf6      # APF6 (Solo) SoM
-              - armadeus,imx6dl-apf6dldev # APF6 (Solo) SoM on APF6Dev board
+              - armadeus,imx6dl-apf6dev   # APF6 (Solo) SoM on APF6Dev board
               - eckelmann,imx6dl-ci4x10
               - emtrion,emcon-mx6         # emCON-MX6S or emCON-MX6DL SoM
               - emtrion,emcon-mx6-avari   # emCON-MX6S or emCON-MX6DL SoM on Avari Base
index 115c5be..8defacc 100644 (file)
@@ -1,7 +1,7 @@
 * Hisilicon Hi3519 System Controller Block
 
 This bindings use the following binding:
-Documentation/devicetree/bindings/mfd/syscon.txt
+Documentation/devicetree/bindings/mfd/syscon.yaml
 
 Required properties:
 - compatible: "hisilicon,hi3519-sysctrl".
index 06df04c..6ce0b21 100644 (file)
@@ -81,4 +81,4 @@ Example:
                };
        };
 
-[1]. Documentation/devicetree/bindings/arm/idle-states.txt
+[1]. Documentation/devicetree/bindings/arm/idle-states.yaml
index f301e63..e41490e 100644 (file)
@@ -17,7 +17,7 @@ am335x and am437x only:
 - pm-sram: Phandles to ocmcram nodes to be used for power management.
           First should be type 'protect-exec' for the driver to use to copy
           and run PM functions, second should be regular pool to be used for
-          data region for code. See Documentation/devicetree/bindings/sram/sram.txt
+          data region for code. See Documentation/devicetree/bindings/sram/sram.yaml
           for more details.
 
 Examples:
index 8ef8542..5e66934 100644 (file)
@@ -100,13 +100,14 @@ properties:
       bindings in [1]) must specify this property.
 
       [1] Kernel documentation - ARM idle states bindings
-        Documentation/devicetree/bindings/arm/idle-states.txt
-
-  "#power-domain-cells":
-    description:
-      The number of cells in a PM domain specifier as per binding in [3].
-      Must be 0 as to represent a single PM domain.
+        Documentation/devicetree/bindings/arm/idle-states.yaml
 
+patternProperties:
+  "^power-domain-":
+    allOf:
+      - $ref: "../power/power-domain.yaml#"
+    type: object
+    description: |
       ARM systems can have multiple cores, sometimes in an hierarchical
       arrangement. This often, but not always, maps directly to the processor
       power topology of the system. Individual nodes in a topology have their
@@ -122,14 +123,8 @@ properties:
       helps to implement support for OSI mode and OS implementations may choose
       to mandate it.
 
-      [3] Documentation/devicetree/bindings/power/power_domain.txt
-      [4] Documentation/devicetree/bindings/power/domain-idle-state.txt
-
-  power-domains:
-    $ref: '/schemas/types.yaml#/definitions/phandle-array'
-    description:
-      List of phandles and PM domain specifiers, as defined by bindings of the
-      PM domain provider.
+      [3] Documentation/devicetree/bindings/power/power-domain.yaml
+      [4] Documentation/devicetree/bindings/power/domain-idle-state.yaml
 
 required:
   - compatible
@@ -199,7 +194,7 @@ examples:
 
       CPU0: cpu@0 {
         device_type = "cpu";
-        compatible = "arm,cortex-a53", "arm,armv8";
+        compatible = "arm,cortex-a53";
         reg = <0x0>;
         enable-method = "psci";
         power-domains = <&CPU_PD0>;
@@ -208,7 +203,7 @@ examples:
 
       CPU1: cpu@1 {
         device_type = "cpu";
-        compatible = "arm,cortex-a57", "arm,armv8";
+        compatible = "arm,cortex-a53";
         reg = <0x100>;
         enable-method = "psci";
         power-domains = <&CPU_PD1>;
@@ -224,6 +219,9 @@ examples:
           exit-latency-us = <10>;
           min-residency-us = <100>;
         };
+      };
+
+      domain-idle-states {
 
         CLUSTER_RET: cluster-retention {
           compatible = "domain-idle-state";
@@ -247,19 +245,19 @@ examples:
       compatible = "arm,psci-1.0";
       method = "smc";
 
-      CPU_PD0: cpu-pd0 {
+      CPU_PD0: power-domain-cpu0 {
         #power-domain-cells = <0>;
         domain-idle-states = <&CPU_PWRDN>;
         power-domains = <&CLUSTER_PD>;
       };
 
-      CPU_PD1: cpu-pd1 {
+      CPU_PD1: power-domain-cpu1 {
         #power-domain-cells = <0>;
         domain-idle-states =  <&CPU_PWRDN>;
         power-domains = <&CLUSTER_PD>;
       };
 
-      CLUSTER_PD: cluster-pd {
+      CLUSTER_PD: power-domain-cluster {
         #power-domain-cells = <0>;
         domain-idle-states = <&CLUSTER_RET>, <&CLUSTER_PWRDN>;
       };
index 68917bb..55f7938 100644 (file)
@@ -52,7 +52,7 @@ required:
 
 examples:
   - |
-    mlahb: ahb {
+    mlahb: ahb@38000000 {
       compatible = "st,mlahb", "simple-bus";
       #address-cells = <1>;
       #size-cells = <1>;
index 9fe11ce..8097361 100644 (file)
@@ -70,7 +70,6 @@ examples:
         #size-cells = <0>;
 
         pmic@3e3 {
-            compatible = "...";
             reg = <0x3e3>;
 
             /* ... */
index 69cfa4a..c604822 100644 (file)
@@ -40,7 +40,7 @@ additionalProperties: false
 
 examples:
   - |
-    osc24M: clk@01c20050 {
+    osc24M: clk@1c20050 {
         #clock-cells = <0>;
         compatible = "allwinner,sun4i-a10-osc-clk";
         reg = <0x01c20050 0x4>;
index 07f38de..43963c3 100644 (file)
@@ -41,7 +41,7 @@ additionalProperties: false
 
 examples:
   - |
-    clk@0600005c {
+    clk@600005c {
         #clock-cells = <0>;
         compatible = "allwinner,sun9i-a80-gt-clk";
         reg = <0x0600005c 0x4>;
index 17f8717..3647007 100644 (file)
@@ -42,7 +42,7 @@ properties:
       be part of GCC and hence the TSENS properties can also be part
       of the GCC/clock-controller node.
       For more details on the TSENS properties please refer
-      Documentation/devicetree/bindings/thermal/qcom-tsens.txt
+      Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
 
   nvmem-cell-names:
     minItems: 1
index 5d5d396..6009324 100644 (file)
@@ -49,11 +49,7 @@ examples:
         resets = <&tcon_ch0_clk 0>;
 
         port {
-            #address-cells = <1>;
-            #size-cells = <0>;
-
-            tve0_in_tcon0: endpoint@0 {
-                reg = <0>;
+            tve0_in_tcon0: endpoint {
                 remote-endpoint = <&tcon0_out_tve0>;
             };
         };
index 6d72b3d..c211038 100644 (file)
@@ -79,21 +79,15 @@ examples:
           #size-cells = <0>;
 
           anx6345_in: port@0 {
-            #address-cells = <1>;
-            #size-cells = <0>;
             reg = <0>;
-            anx6345_in_tcon0: endpoint@0 {
-              reg = <0>;
+            anx6345_in_tcon0: endpoint {
               remote-endpoint = <&tcon0_out_anx6345>;
             };
           };
 
           anx6345_out: port@1 {
-            #address-cells = <1>;
-            #size-cells = <0>;
             reg = <1>;
-            anx6345_out_panel: endpoint@0 {
-              reg = <0>;
+            anx6345_out_panel: endpoint {
               remote-endpoint = <&panel_in_edp>;
             };
           };
index 4ebcea7..a614644 100644 (file)
@@ -37,6 +37,8 @@ examples:
     dsi@ff450000 {
         #address-cells = <1>;
         #size-cells = <0>;
+        reg = <0xff450000 0x1000>;
+
         panel@0 {
             compatible = "leadtek,ltk500hd1829";
             reg = <0>;
index 186e5e1..22c91be 100644 (file)
@@ -37,6 +37,8 @@ examples:
     dsi@ff450000 {
         #address-cells = <1>;
         #size-cells = <0>;
+        reg = <0xff450000 0x1000>;
+
         panel@0 {
             compatible = "xinpeng,xpp055c272";
             reg = <0>;
index 678776b..1db608c 100644 (file)
@@ -174,10 +174,6 @@ examples:
       };
     };
 
-    soc@1c00000 {
-      lcdc0: lcdc@1c0c000 {
-        compatible = "allwinner,sun4i-a10-lcdc";
-      };
-    };
+    lcdc0: lcdc { };
 
 ...
index 7bf1bb4..aac617a 100644 (file)
@@ -37,7 +37,7 @@ Optional nodes:
    supports a single port with a single endpoint.
 
  - See also Documentation/devicetree/bindings/display/tilcdc/panel.txt and
-   Documentation/devicetree/bindings/display/tilcdc/tfp410.txt for connecting
+   Documentation/devicetree/bindings/display/bridge/ti,tfp410.txt for connecting
    tfp410 DVI encoder or lcd panel to lcdc
 
 [1] There is an errata about AM335x color wiring. For 16-bit color mode
index 8b5c346..34780d7 100644 (file)
@@ -143,7 +143,7 @@ examples:
             #size-cells = <2>;
             dma-coherent;
             dma-ranges;
-            ranges;
+            ranges = <0x0 0x30800000 0x0 0x30800000 0x0 0x05000000>;
 
             ti,sci-dev-id = <118>;
 
@@ -169,16 +169,4 @@ examples:
                 ti,sci-rm-range-rflow = <0x6>; /* GP RFLOW */
             };
         };
-
-        mcasp0: mcasp@02B00000 {
-            dmas = <&main_udmap 0xc400>, <&main_udmap 0x4400>;
-            dma-names = "tx", "rx";
-        };
-
-        crypto: crypto@4E00000 {
-            compatible = "ti,sa2ul-crypto";
-
-            dmas = <&main_udmap 0xc000>, <&main_udmap 0x4000>, <&main_udmap 0x4001>;
-            dma-names = "tx", "rx1", "rx2";
-        };
     };
index 4ea6a87..e8b99ad 100644 (file)
@@ -84,31 +84,31 @@ examples:
     gpu_opp_table: opp_table0 {
       compatible = "operating-points-v2";
 
-      opp@533000000 {
+      opp-533000000 {
         opp-hz = /bits/ 64 <533000000>;
         opp-microvolt = <1250000>;
       };
-      opp@450000000 {
+      opp-450000000 {
         opp-hz = /bits/ 64 <450000000>;
         opp-microvolt = <1150000>;
       };
-      opp@400000000 {
+      opp-400000000 {
         opp-hz = /bits/ 64 <400000000>;
         opp-microvolt = <1125000>;
       };
-      opp@350000000 {
+      opp-350000000 {
         opp-hz = /bits/ 64 <350000000>;
         opp-microvolt = <1075000>;
       };
-      opp@266000000 {
+      opp-266000000 {
         opp-hz = /bits/ 64 <266000000>;
         opp-microvolt = <1025000>;
       };
-      opp@160000000 {
+      opp-160000000 {
         opp-hz = /bits/ 64 <160000000>;
         opp-microvolt = <925000>;
       };
-      opp@100000000 {
+      opp-100000000 {
         opp-hz = /bits/ 64 <100000000>;
         opp-microvolt = <912500>;
       };
index 36f59b3..8d966f3 100644 (file)
@@ -138,31 +138,31 @@ examples:
     gpu_opp_table: opp_table0 {
       compatible = "operating-points-v2";
 
-      opp@533000000 {
+      opp-533000000 {
         opp-hz = /bits/ 64 <533000000>;
         opp-microvolt = <1250000>;
       };
-      opp@450000000 {
+      opp-450000000 {
         opp-hz = /bits/ 64 <450000000>;
         opp-microvolt = <1150000>;
       };
-      opp@400000000 {
+      opp-400000000 {
         opp-hz = /bits/ 64 <400000000>;
         opp-microvolt = <1125000>;
       };
-      opp@350000000 {
+      opp-350000000 {
         opp-hz = /bits/ 64 <350000000>;
         opp-microvolt = <1075000>;
       };
-      opp@266000000 {
+      opp-266000000 {
         opp-hz = /bits/ 64 <266000000>;
         opp-microvolt = <1025000>;
       };
-      opp@160000000 {
+      opp-160000000 {
         opp-hz = /bits/ 64 <160000000>;
         opp-microvolt = <925000>;
       };
-      opp@100000000 {
+      opp-100000000 {
         opp-hz = /bits/ 64 <100000000>;
         opp-microvolt = <912500>;
       };
index f46de17..cc3c8ea 100644 (file)
@@ -123,7 +123,7 @@ examples:
         samsung,syscon-phandle = <&pmu_system_controller>;
 
         /* NTC thermistor is a hwmon device */
-        ncp15wb473@0 {
+        ncp15wb473 {
             compatible = "murata,ncp15wb473";
             pullup-uv = <1800000>;
             pullup-ohm = <47000>;
index d7c3262..c99ed39 100644 (file)
@@ -62,7 +62,7 @@ required:
 
 examples:
 - |
-    i2c@00000000 {
+    i2c {
       #address-cells = <1>;
       #size-cells = <0>;
       gt928@5d {
index c864a46..f502121 100644 (file)
@@ -1,7 +1,7 @@
 Texas Instruments TWL family (twl4030) pwrbutton module
 
 This module is part of the TWL4030. For more details about the whole
-chip see Documentation/devicetree/bindings/mfd/twl-familly.txt.
+chip see Documentation/devicetree/bindings/mfd/twl-family.txt.
 
 This module provides a simple power button event via an Interrupt.
 
index d97d099..c60b994 100644 (file)
@@ -85,7 +85,7 @@ properties:
         # LED will act as a back-light, controlled by the framebuffer system
       - backlight
         # LED will turn on (but for leds-gpio see "default-state" property in
-        # Documentation/devicetree/bindings/leds/leds-gpio.txt)
+        # Documentation/devicetree/bindings/leds/leds-gpio.yaml)
       - default-on
         # LED "double" flashes at a load average based rate
       - heartbeat
index cf1ea40..c7af6f7 100644 (file)
@@ -5,7 +5,7 @@ where single bits in a certain register can turn on/off a
 single LED. The register bit LEDs appear as children to the
 syscon device, with the proper compatible string. For the
 syscon bindings see:
-Documentation/devicetree/bindings/mfd/syscon.txt
+Documentation/devicetree/bindings/mfd/syscon.yaml
 
 Each LED is represented as a sub-node of the syscon device. Each
 node's name represents the name of the corresponding LED.
index 1ea7841..5e06662 100644 (file)
@@ -177,7 +177,7 @@ examples:
         };
     };
 
-    i2c5: i2c@4807c000 {
+    i2c {
         clock-frequency = <400000>;
         #address-cells = <1>;
         #size-cells = <0>;
index 44d7146..63f674f 100644 (file)
@@ -32,7 +32,7 @@ Required only for "ti,emif-am3352" and "ti,emif-am4372":
 - sram                 : Phandles for generic sram driver nodes,
   first should be type 'protect-exec' for the driver to use to copy
   and run PM functions, second should be regular pool to be used for
-  data region for code. See Documentation/devicetree/bindings/sram/sram.txt
+  data region for code. See Documentation/devicetree/bindings/sram/sram.yaml
   for more details.
 
 Optional properties:
index 4a70f87..4803857 100644 (file)
@@ -97,14 +97,14 @@ examples:
             regulators {
                 compatible = "maxim,max77650-regulator";
 
-                max77650_ldo: regulator@0 {
+                max77650_ldo: regulator-ldo {
                     regulator-compatible = "ldo";
                     regulator-name = "max77650-ldo";
                     regulator-min-microvolt = <1350000>;
                     regulator-max-microvolt = <2937500>;
                 };
 
-                max77650_sbb0: regulator@1 {
+                max77650_sbb0: regulator-sbb0 {
                     regulator-compatible = "sbb0";
                     regulator-name = "max77650-sbb0";
                     regulator-min-microvolt = <800000>;
index 4f62143..a5ced46 100644 (file)
@@ -26,8 +26,8 @@ Required properties:
             ldo6, ldo7, ldo8
 
 - xxx-supply: Input voltage supply regulator.
-  These entries are require if regulators are enabled for a device. Missing of these
-  properties can cause the regulator registration fails.
+  These entries are required if regulators are enabled for a device. Missing these
+  properties can cause the regulator registration to fail.
   If some of input supply is powered through battery or always-on supply then
   also it is require to have these parameters with proper node handle of always
   on power supply.
index 088eff9..e0f901e 100644 (file)
@@ -20,7 +20,7 @@ RAVE SP consists of the following sub-devices:
 Device                          Description
 ------                          -----------
 rave-sp-wdt                    : Watchdog
-rave-sp-nvmem                  : Interface to onborad EEPROM
+rave-sp-nvmem                  : Interface to onboard EEPROM
 rave-sp-backlight              : Display backlight
 rave-sp-hwmon                  : Interface to onboard hardware sensors
 rave-sp-leds                   : Interface to onboard LEDs
index bb7e896..9134e9b 100644 (file)
@@ -26,7 +26,7 @@ For generic IOMMU bindings, see
 Documentation/devicetree/bindings/iommu/iommu.txt.
 
 For arm-smmu binding, see:
-Documentation/devicetree/bindings/iommu/arm,smmu.txt.
+Documentation/devicetree/bindings/iommu/arm,smmu.yaml.
 
 Required properties:
 
index 3c0df40..8fded83 100644 (file)
@@ -370,6 +370,7 @@ examples:
     mmc3: mmc@1c12000 {
         #address-cells = <1>;
         #size-cells = <0>;
+        reg = <0x1c12000 0x200>;
         pinctrl-names = "default";
         pinctrl-0 = <&mmc3_pins_a>;
         vmmc-supply = <&reg_vmmc3>;
index f3893c4..d2eada5 100644 (file)
@@ -27,7 +27,7 @@ Required properties of NAND chips:
   - reg: shall contain the native Chip Select ids from 0 to max supported by
     the cadence nand flash controller
 
-See Documentation/devicetree/bindings/mtd/nand.txt for more details on
+See Documentation/devicetree/bindings/mtd/nand-controller.yaml for more details on
 generic bindings.
 
 Example:
index 48a7f91..88b57b0 100644 (file)
@@ -45,7 +45,7 @@ Optional properties:
   switch queue
 
 - resets: a single phandle and reset identifier pair. See
-  Documentation/devicetree/binding/reset/reset.txt for details.
+  Documentation/devicetree/bindings/reset/reset.txt for details.
 
 - reset-names: If the "reset" property is specified, this property should have
   the value "switch" to denote the switch reset line.
index b43c6c6..6598022 100644 (file)
@@ -76,6 +76,8 @@ examples:
       qfprom: eeprom@700000 {
           #address-cells = <1>;
           #size-cells = <1>;
+          reg = <0x00700000 0x100000>;
+
           wp-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
 
           /* ... */
index 020ef9e..94ac236 100644 (file)
@@ -86,7 +86,7 @@ examples:
     #include <dt-bindings/clock/sun4i-a10-ccu.h>
     #include <dt-bindings/reset/sun4i-a10-ccu.h>
 
-    usbphy: phy@01c13400 {
+    usbphy: phy@1c13400 {
         #phy-cells = <1>;
         compatible = "allwinner,sun4i-a10-usb-phy";
         reg = <0x01c13400 0x10>, <0x01c14800 0x4>, <0x01c1c800 0x4>;
index bb690e2..135c7df 100644 (file)
@@ -17,7 +17,7 @@ description: |+
                     "aspeed,ast2400-scu", "syscon", "simple-mfd"
 
   Refer to the the bindings described in
-  Documentation/devicetree/bindings/mfd/syscon.txt
+  Documentation/devicetree/bindings/mfd/syscon.yaml
 
 properties:
   compatible:
index f7f5d57..824f7fd 100644 (file)
@@ -18,7 +18,7 @@ description: |+
                        "aspeed,g5-scu", "syscon", "simple-mfd"
 
   Refer to the the bindings described in
-  Documentation/devicetree/bindings/mfd/syscon.txt
+  Documentation/devicetree/bindings/mfd/syscon.yaml
 
 properties:
   compatible:
index 3749fa2..ac8d1c3 100644 (file)
@@ -17,7 +17,7 @@ description: |+
                 "aspeed,ast2600-scu", "syscon", "simple-mfd"
 
   Refer to the the bindings described in
-  Documentation/devicetree/bindings/mfd/syscon.txt
+  Documentation/devicetree/bindings/mfd/syscon.yaml
 
 properties:
   compatible:
index 754ea7a..ef4de32 100644 (file)
@@ -248,7 +248,7 @@ examples:
       };
 
     //Example 3 pin groups
-      pinctrl@60020000 {
+      pinctrl {
         usart1_pins_a: usart1-0 {
                 pins1 {
                         pinmux = <STM32_PINMUX('A', 9, AF7)>;
index aab70e8..d3098c9 100644 (file)
@@ -18,7 +18,7 @@ description: |+
                 "amlogic,meson-gx-hhi-sysctrl", "simple-mfd", "syscon"
 
   Refer to the the bindings described in
-  Documentation/devicetree/bindings/mfd/syscon.txt
+  Documentation/devicetree/bindings/mfd/syscon.yaml
 
 properties:
   compatible:
diff --git a/Documentation/devicetree/bindings/power/domain-idle-state.txt b/Documentation/devicetree/bindings/power/domain-idle-state.txt
deleted file mode 100644 (file)
index eefc7ed..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-PM Domain Idle State Node:
-
-A domain idle state node represents the state parameters that will be used to
-select the state when there are no active components in the domain.
-
-The state node has the following parameters -
-
-- compatible:
-       Usage: Required
-       Value type: <string>
-       Definition: Must be "domain-idle-state".
-
-- entry-latency-us
-       Usage: Required
-       Value type: <prop-encoded-array>
-       Definition: u32 value representing worst case latency in
-                   microseconds required to enter the idle state.
-                   The exit-latency-us duration may be guaranteed
-                   only after entry-latency-us has passed.
-
-- exit-latency-us
-       Usage: Required
-       Value type: <prop-encoded-array>
-       Definition: u32 value representing worst case latency
-                   in microseconds required to exit the idle state.
-
-- min-residency-us
-       Usage: Required
-       Value type: <prop-encoded-array>
-       Definition: u32 value representing minimum residency duration
-                   in microseconds after which the idle state will yield
-                   power benefits after overcoming the overhead in entering
-i                  the idle state.
diff --git a/Documentation/devicetree/bindings/power/domain-idle-state.yaml b/Documentation/devicetree/bindings/power/domain-idle-state.yaml
new file mode 100644 (file)
index 0000000..dfba1af
--- /dev/null
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/domain-idle-state.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PM Domain Idle States binding description
+
+maintainers:
+  - Ulf Hansson <ulf.hansson@linaro.org>
+
+description:
+  A domain idle state node represents the state parameters that will be used to
+  select the state when there are no active components in the PM domain.
+
+properties:
+  $nodename:
+    const: domain-idle-states
+
+patternProperties:
+  "^(cpu|cluster|domain)-":
+    type: object
+    description:
+      Each state node represents a domain idle state description.
+
+    properties:
+      compatible:
+        const: domain-idle-state
+
+      entry-latency-us:
+        description:
+          The worst case latency in microseconds required to enter the idle
+          state. Note that, the exit-latency-us duration may be guaranteed only
+          after the entry-latency-us has passed.
+
+      exit-latency-us:
+        description:
+          The worst case latency in microseconds required to exit the idle
+          state.
+
+      min-residency-us:
+        description:
+          The minimum residency duration in microseconds after which the idle
+          state will yield power benefits, after overcoming the overhead while
+          entering the idle state.
+
+    required:
+      - compatible
+      - entry-latency-us
+      - exit-latency-us
+      - min-residency-us
+
+examples:
+  - |
+
+    domain-idle-states {
+      domain_retention: domain-retention {
+        compatible = "domain-idle-state";
+        entry-latency-us = <20>;
+        exit-latency-us = <40>;
+        min-residency-us = <80>;
+      };
+    };
+...
index 455b573..6047aac 100644 (file)
@@ -25,22 +25,20 @@ description: |+
 
 properties:
   $nodename:
-    pattern: "^(power-controller|power-domain)(@.*)?$"
+    pattern: "^(power-controller|power-domain)([@-].*)?$"
 
   domain-idle-states:
     $ref: /schemas/types.yaml#/definitions/phandle-array
-    description:
-      A phandle of an idle-state that shall be soaked into a generic domain
-      power state. The idle state definitions are compatible with
-      domain-idle-state specified in
-      Documentation/devicetree/bindings/power/domain-idle-state.txt
-      phandles that are not compatible with domain-idle-state will be ignored.
-      The domain-idle-state property reflects the idle state of this PM domain
-      and not the idle states of the devices or sub-domains in the PM domain.
-      Devices and sub-domains have their own idle-states independent
-      of the parent domain's idle states. In the absence of this property,
-      the domain would be considered as capable of being powered-on
-      or powered-off.
+    description: |
+      Phandles of idle states that defines the available states for the
+      power-domain provider. The idle state definitions are compatible with the
+      domain-idle-state bindings, specified in ./domain-idle-state.yaml.
+
+      Note that, the domain-idle-state property reflects the idle states of this
+      PM domain and not the idle states of the devices or sub-domains in the PM
+      domain. Devices and sub-domains have their own idle states independent of
+      the parent domain's idle states. In the absence of this property, the
+      domain would be considered as capable of being powered-on or powered-off.
 
   operating-points-v2:
     $ref: /schemas/types.yaml#/definitions/phandle-array
index 5b09b2d..08497ef 100644 (file)
@@ -109,4 +109,4 @@ Example:
                required-opps = <&domain1_opp_1>;
        };
 
-[1]. Documentation/devicetree/bindings/power/domain-idle-state.txt
+[1]. Documentation/devicetree/bindings/power/domain-idle-state.yaml
index f5cdac8..8b00519 100644 (file)
@@ -161,7 +161,7 @@ The regulator node houses sub-nodes for each regulator within the device. Each
 sub-node is identified using the node's name, with valid values listed for each
 of the PMICs below.
 
-pm8005:
+pm8004:
        s2, s5
 
 pm8005:
index 92ff2e8..91a39a3 100644 (file)
@@ -191,7 +191,7 @@ patternProperties:
 
 examples:
   - |
-    xyzreg: regulator@0 {
+    xyzreg: regulator {
       regulator-min-microvolt = <1000000>;
       regulator-max-microvolt = <2500000>;
       regulator-always-on;
index b4edaf7..2880d5d 100644 (file)
@@ -3,4 +3,4 @@ STMicroelectronics STM32MP1 Peripheral Reset Controller
 
 The RCC IP is both a reset and a clock controller.
 
-Please see Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt
+Please see Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.yaml
index 944743d..c42b91e 100644 (file)
@@ -36,7 +36,7 @@ SAI subnodes required properties:
   - clock-names: Must contain "sai_ck".
        Must also contain "MCLK", if SAI shares a master clock,
        with a SAI set as MCLK clock provider.
-  - dmas: see Documentation/devicetree/bindings/dma/stm32-dma.txt
+  - dmas: see Documentation/devicetree/bindings/dma/st,stm32-dma.yaml
   - dma-names: identifier string for each DMA request line
        "tx": if sai sub-block is configured as playback DAI
        "rx": if sai sub-block is configured as capture DAI
index 33826f2..ca91017 100644 (file)
@@ -10,7 +10,7 @@ Required properties:
   - clock-names: must contain "kclk"
   - interrupts: cpu DAI interrupt line
   - dmas: DMA specifiers for audio data DMA and iec control flow DMA
-    See STM32 DMA bindings, Documentation/devicetree/bindings/dma/stm32-dma.txt
+    See STM32 DMA bindings, Documentation/devicetree/bindings/dma/st,stm32-dma.yaml
   - dma-names: two dmas have to be defined, "rx" and "rx-ctrl"
 
 Optional properties:
index f0d9796..e49ecbf 100644 (file)
@@ -49,7 +49,7 @@ properties:
   dmas:
     description: |
       DMA specifiers for tx and rx dma. DMA fifo mode must be used. See
-      the STM32 DMA bindings Documentation/devicetree/bindings/dma/stm32-dma.txt.
+      the STM32 DMA bindings Documentation/devicetree/bindings/dma/st,stm32-dma.yaml.
     items:
       - description: rx DMA channel
       - description: tx DMA channel
index 80bac7a..4b55094 100644 (file)
@@ -125,7 +125,7 @@ examples:
       #size-cells = <1>;
       ranges;
 
-      sram_a: sram@00000000 {
+      sram_a: sram@0 {
         compatible = "mmio-sram";
         reg = <0x00000000 0xc000>;
         #address-cells = <1>;
index d9fdf48..f3e68ed 100644 (file)
@@ -17,7 +17,7 @@ description: |+
                 "brcm,bcm2711-avs-monitor", "syscon", "simple-mfd"
 
   Refer to the the bindings described in
-  Documentation/devicetree/bindings/mfd/syscon.txt
+  Documentation/devicetree/bindings/mfd/syscon.yaml
 
 properties:
   compatible:
index 23e989e..d918cee 100644 (file)
@@ -87,7 +87,7 @@ additionalProperties: false
 
 examples:
   - |
-    timer {
+    timer@1c20c00 {
         compatible = "allwinner,sun4i-a10-timer";
         reg = <0x01c20c00 0x400>;
         interrupts = <22>,
index e5953e7..2104830 100644 (file)
@@ -151,8 +151,8 @@ The details of these operations are:
      Note that callbacks will always be invoked from the DMA
      engines tasklet, never from interrupt context.
 
-Optional: per descriptor metadata
----------------------------------
+  **Optional: per descriptor metadata**
+
   DMAengine provides two ways for metadata support.
 
   DESC_METADATA_CLIENT
@@ -199,12 +199,15 @@ Optional: per descriptor metadata
   DESC_METADATA_CLIENT
 
     - DMA_MEM_TO_DEV / DEV_MEM_TO_MEM:
+
       1. prepare the descriptor (dmaengine_prep_*)
          construct the metadata in the client's buffer
       2. use dmaengine_desc_attach_metadata() to attach the buffer to the
          descriptor
       3. submit the transfer
+
     - DMA_DEV_TO_MEM:
+
       1. prepare the descriptor (dmaengine_prep_*)
       2. use dmaengine_desc_attach_metadata() to attach the buffer to the
          descriptor
@@ -215,6 +218,7 @@ Optional: per descriptor metadata
   DESC_METADATA_ENGINE
 
     - DMA_MEM_TO_DEV / DEV_MEM_TO_MEM:
+
       1. prepare the descriptor (dmaengine_prep_*)
       2. use dmaengine_desc_get_metadata_ptr() to get the pointer to the
          engine's metadata area
@@ -222,7 +226,9 @@ Optional: per descriptor metadata
       4. use dmaengine_desc_set_metadata_len()  to tell the DMA engine the
          amount of data the client has placed into the metadata buffer
       5. submit the transfer
+
     - DMA_DEV_TO_MEM:
+
       1. prepare the descriptor (dmaengine_prep_*)
       2. submit the transfer
       3. on transfer completion, use dmaengine_desc_get_metadata_ptr() to get
@@ -278,8 +284,8 @@ Optional: per descriptor metadata
 
       void dma_async_issue_pending(struct dma_chan *chan);
 
-Further APIs:
--------------
+Further APIs
+------------
 
 1. Terminate APIs
 
index c81e0b4..471be1e 100644 (file)
@@ -20,8 +20,7 @@ Usage Notes
 -----------
 
 This driver does not auto-detect devices. You will have to instantiate the
-devices explicitly. Please see Documentation/i2c/instantiating-devices for
-details.
+devices explicitly. Please see :doc:`/i2c/instantiating-devices` for details.
 
 
 Sysfs entries
index 0e0eb2c..6bc126a 100644 (file)
@@ -765,7 +765,7 @@ is not sufficient this sometimes needs to be explicit.
        Example::
 
                #arch/x86/boot/Makefile
-               subdir- := compressed/
+               subdir- := compressed
 
 The above assignment instructs kbuild to descend down in the
 directory compressed/ when "make clean" is executed.
@@ -1379,9 +1379,6 @@ See subsequent chapter for the syntax of the Kbuild file.
        in arch/$(ARCH)/include/(uapi/)/asm, Kbuild will automatically generate
        a wrapper of the asm-generic one.
 
-       The convention is to list one subdir per line and
-       preferably in alphabetic order.
-
 8 Kbuild Variables
 ==================
 
index 1e4735c..2561060 100644 (file)
@@ -487,8 +487,9 @@ phy_register_fixup_for_id()::
 The stubs set one of the two matching criteria, and set the other one to
 match anything.
 
-When phy_register_fixup() or \*_for_uid()/\*_for_id() is called at module,
-unregister fixup and free allocate memory are required.
+When phy_register_fixup() or \*_for_uid()/\*_for_id() is called at module load
+time, the module needs to unregister the fixup and free allocated memory when
+it's unloaded.
 
 Call one of following function before unloading module::
 
index 002e427..ced8a80 100644 (file)
@@ -13,7 +13,6 @@ Power Management
     drivers-testing
     energy-model
     freezing-of-tasks
-    interface
     opp
     pci
     pm_qos_interface
index 7daf513..e54c44c 100644 (file)
@@ -30,4 +30,4 @@ if [ -n "$parallel" ] ; then
        parallel="-j$parallel"
 fi
 
-exec "$sphinx" "$parallel" "$@"
+exec "$sphinx" $parallel "$@"
index 97a72a5..ebd383f 100644 (file)
@@ -4611,35 +4611,38 @@ unpins the VPA pages and releases all the device pages that are used to
 track the secure pages by hypervisor.
 
 4.122 KVM_S390_NORMAL_RESET
+---------------------------
 
-Capability: KVM_CAP_S390_VCPU_RESETS
-Architectures: s390
-Type: vcpu ioctl
-Parameters: none
-Returns: 0
+:Capability: KVM_CAP_S390_VCPU_RESETS
+:Architectures: s390
+:Type: vcpu ioctl
+:Parameters: none
+:Returns: 0
 
 This ioctl resets VCPU registers and control structures according to
 the cpu reset definition in the POP (Principles Of Operation).
 
 4.123 KVM_S390_INITIAL_RESET
+----------------------------
 
-Capability: none
-Architectures: s390
-Type: vcpu ioctl
-Parameters: none
-Returns: 0
+:Capability: none
+:Architectures: s390
+:Type: vcpu ioctl
+:Parameters: none
+:Returns: 0
 
 This ioctl resets VCPU registers and control structures according to
 the initial cpu reset definition in the POP. However, the cpu is not
 put into ESA mode. This reset is a superset of the normal reset.
 
 4.124 KVM_S390_CLEAR_RESET
+--------------------------
 
-Capability: KVM_CAP_S390_VCPU_RESETS
-Architectures: s390
-Type: vcpu ioctl
-Parameters: none
-Returns: 0
+:Capability: KVM_CAP_S390_VCPU_RESETS
+:Architectures: s390
+:Type: vcpu ioctl
+:Parameters: none
+:Returns: 0
 
 This ioctl resets VCPU registers and control structures according to
 the clear cpu reset definition in the POP. However, the cpu is not put
index a8de2fb..265d9e9 100644 (file)
@@ -19,7 +19,6 @@ x86-specific Documentation
    tlb
    mtrr
    pat
-   intel_mpx
    intel-iommu
    intel_txt
    amd-memory-encryption
index fcd79fc..c93e493 100644 (file)
@@ -693,7 +693,7 @@ ALLWINNER CPUFREQ DRIVER
 M:     Yangtao Li <tiny.windzz@gmail.com>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/opp/sun50i-nvmem-cpufreq.txt
+F:     Documentation/devicetree/bindings/opp/allwinner,sun50i-h6-operating-points.yaml
 F:     drivers/cpufreq/sun50i-cpufreq-nvmem.c
 
 ALLWINNER CRYPTO DRIVERS
@@ -4017,7 +4017,7 @@ M:        Cheng-Yi Chiang <cychiang@chromium.org>
 S:     Maintained
 R:     Enric Balletbo i Serra <enric.balletbo@collabora.com>
 R:     Guenter Roeck <groeck@chromium.org>
-F:     Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt
+F:     Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml
 F:     sound/soc/codecs/cros_ec_codec.*
 
 CIRRUS LOGIC AUDIO CODEC DRIVERS
@@ -4475,7 +4475,7 @@ L:        linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/platform/sunxi/sun6i-csi/
-F:     Documentation/devicetree/bindings/media/sun6i-csi.txt
+F:     Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml
 
 CW1200 WLAN driver
 M:     Solomon Peachy <pizza@shaftnet.org>
@@ -5668,7 +5668,7 @@ L:        dri-devel@lists.freedesktop.org
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
 F:     drivers/gpu/drm/stm
-F:     Documentation/devicetree/bindings/display/st,stm32-ltdc.txt
+F:     Documentation/devicetree/bindings/display/st,stm32-ltdc.yaml
 
 DRM DRIVERS FOR TI LCDC
 M:     Jyri Sarha <jsarha@ti.com>
@@ -7738,7 +7738,7 @@ Hyper-V CORE AND DRIVERS
 M:     "K. Y. Srinivasan" <kys@microsoft.com>
 M:     Haiyang Zhang <haiyangz@microsoft.com>
 M:     Stephen Hemminger <sthemmin@microsoft.com>
-M:     Sasha Levin <sashal@kernel.org>
+M:     Wei Liu <wei.liu@kernel.org>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
 L:     linux-hyperv@vger.kernel.org
 S:     Supported
@@ -10164,7 +10164,7 @@ MAXBOTIX ULTRASONIC RANGER IIO DRIVER
 M:     Andreas Klinger <ak@it-klinger.de>
 L:     linux-iio@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.txt
+F:     Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.yaml
 F:     drivers/iio/proximity/mb1232.c
 
 MAXIM MAX77650 PMIC MFD DRIVER
@@ -10467,7 +10467,7 @@ M:      Hugues Fruchet <hugues.fruchet@st.com>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Supported
-F:     Documentation/devicetree/bindings/media/st,stm32-dcmi.txt
+F:     Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
 F:     drivers/media/platform/stm32/stm32-dcmi.c
 
 MEDIA DRIVERS FOR NVIDIA TEGRA - VDE
@@ -11115,14 +11115,12 @@ S:    Maintained
 F:     drivers/usb/image/microtek.*
 
 MIPS
-M:     Ralf Baechle <ralf@linux-mips.org>
-M:     Paul Burton <paulburton@kernel.org>
+M:     Thomas Bogendoerfer <tsbogend@alpha.franken.de>
 L:     linux-mips@vger.kernel.org
 W:     http://www.linux-mips.org/
-T:     git git://git.linux-mips.org/pub/scm/ralf/linux.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git
 Q:     http://patchwork.linux-mips.org/project/linux-mips/list/
-S:     Supported
+S:     Maintained
 F:     Documentation/devicetree/bindings/mips/
 F:     Documentation/mips/
 F:     arch/mips/
@@ -12741,7 +12739,7 @@ M:      Tom Joseph <tjoseph@cadence.com>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/pci/cdns,*.txt
-F:     drivers/pci/controller/pcie-cadence*
+F:     drivers/pci/controller/cadence/
 
 PCI DRIVER FOR FREESCALE LAYERSCAPE
 M:     Minghuan Lian <minghuan.Lian@nxp.com>
@@ -12954,7 +12952,6 @@ M:      Robert Richter <rrichter@marvell.com>
 L:     linux-pci@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
-F:     Documentation/devicetree/bindings/pci/pci-thunder-*
 F:     drivers/pci/controller/pci-thunder-*
 
 PCIE DRIVER FOR HISILICON
@@ -15924,7 +15921,7 @@ F:      drivers/*/stm32-*timer*
 F:     drivers/pwm/pwm-stm32*
 F:     include/linux/*/stm32-*tim*
 F:     Documentation/ABI/testing/*timer-stm32
-F:     Documentation/devicetree/bindings/*/stm32-*timer*
+F:     Documentation/devicetree/bindings/*/*stm32-*timer*
 F:     Documentation/devicetree/bindings/pwm/pwm-stm32*
 
 STMMAC ETHERNET DRIVER
index 0914049..86035d8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 6
 SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION = -rc4
 NAME = Kleptomaniac Octopus
 
 # *DOCUMENTATION*
@@ -68,6 +68,7 @@ unexport GREP_OPTIONS
 #
 # If KBUILD_VERBOSE equals 0 then the above command will be hidden.
 # If KBUILD_VERBOSE equals 1 then the above command is displayed.
+# If KBUILD_VERBOSE equals 2 then give the reason why each target is rebuilt.
 #
 # To put more focus on warnings, be less verbose as default
 # Use 'make V=1' to see the full commands
@@ -1238,7 +1239,7 @@ ifneq ($(dtstree),)
 %.dtb: include/config/kernel.release scripts_dtc
        $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
 
-PHONY += dtbs dtbs_install dt_binding_check
+PHONY += dtbs dtbs_install dtbs_check
 dtbs dtbs_check: include/config/kernel.release scripts_dtc
        $(Q)$(MAKE) $(build)=$(dtstree)
 
@@ -1258,6 +1259,7 @@ PHONY += scripts_dtc
 scripts_dtc: scripts_basic
        $(Q)$(MAKE) $(build)=scripts/dtc
 
+PHONY += dt_binding_check
 dt_binding_check: scripts_dtc
        $(Q)$(MAKE) $(build)=Documentation/devicetree/bindings
 
index 98de654..17fe351 100644 (file)
@@ -738,8 +738,9 @@ config HAVE_STACK_VALIDATION
 config HAVE_RELIABLE_STACKTRACE
        bool
        help
-         Architecture has a save_stack_trace_tsk_reliable() function which
-         only returns a stack trace if it can guarantee the trace is reliable.
+         Architecture has either save_stack_trace_tsk_reliable() or
+         arch_stack_walk_reliable() function which only returns a stack trace
+         if it can guarantee the trace is reliable.
 
 config HAVE_ARCH_HASH
        bool
index c3314b2..a827b4d 100644 (file)
@@ -392,9 +392,6 @@ static inline void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu) {}
 static inline void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu) {}
 static inline void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu) {}
 
-static inline void kvm_arm_vhe_guest_enter(void) {}
-static inline void kvm_arm_vhe_guest_exit(void) {}
-
 #define KVM_BP_HARDEN_UNKNOWN          -1
 #define KVM_BP_HARDEN_WA_NEEDED                0
 #define KVM_BP_HARDEN_NOT_REQUIRED     1
index 25fec4b..a358e97 100644 (file)
@@ -32,7 +32,7 @@ static inline void gic_write_eoir(u32 irq)
        isb();
 }
 
-static inline void gic_write_dir(u32 irq)
+static __always_inline void gic_write_dir(u32 irq)
 {
        write_sysreg_s(irq, SYS_ICC_DIR_EL1);
        isb();
index 806e9dc..a4d1b5f 100644 (file)
@@ -69,7 +69,7 @@ static inline int icache_is_aliasing(void)
        return test_bit(ICACHEF_ALIASING, &__icache_flags);
 }
 
-static inline int icache_is_vpipt(void)
+static __always_inline int icache_is_vpipt(void)
 {
        return test_bit(ICACHEF_VPIPT, &__icache_flags);
 }
index 665c78e..e6cca3d 100644 (file)
@@ -145,7 +145,7 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *);
 
-static inline void __flush_icache_all(void)
+static __always_inline void __flush_icache_all(void)
 {
        if (cpus_have_const_cap(ARM64_HAS_CACHE_DIC))
                return;
index 92ef953..2a746b9 100644 (file)
@@ -435,13 +435,13 @@ cpuid_feature_extract_signed_field(u64 features, int field)
        return cpuid_feature_extract_signed_field_width(features, field, 4);
 }
 
-static inline unsigned int __attribute_const__
+static __always_inline unsigned int __attribute_const__
 cpuid_feature_extract_unsigned_field_width(u64 features, int field, int width)
 {
        return (u64)(features << (64 - width - field)) >> (64 - width);
 }
 
-static inline unsigned int __attribute_const__
+static __always_inline unsigned int __attribute_const__
 cpuid_feature_extract_unsigned_field(u64 features, int field)
 {
        return cpuid_feature_extract_unsigned_field_width(features, field, 4);
@@ -564,7 +564,7 @@ static inline bool system_supports_mixed_endian(void)
        return val == 0x1;
 }
 
-static inline bool system_supports_fpsimd(void)
+static __always_inline bool system_supports_fpsimd(void)
 {
        return !cpus_have_const_cap(ARM64_HAS_NO_FPSIMD);
 }
@@ -575,13 +575,13 @@ static inline bool system_uses_ttbr0_pan(void)
                !cpus_have_const_cap(ARM64_HAS_PAN);
 }
 
-static inline bool system_supports_sve(void)
+static __always_inline bool system_supports_sve(void)
 {
        return IS_ENABLED(CONFIG_ARM64_SVE) &&
                cpus_have_const_cap(ARM64_SVE);
 }
 
-static inline bool system_supports_cnp(void)
+static __always_inline bool system_supports_cnp(void)
 {
        return IS_ENABLED(CONFIG_ARM64_CNP) &&
                cpus_have_const_cap(ARM64_HAS_CNP);
index 4e531f5..6facd13 100644 (file)
@@ -34,7 +34,7 @@ static inline void __raw_writew(u16 val, volatile void __iomem *addr)
 }
 
 #define __raw_writel __raw_writel
-static inline void __raw_writel(u32 val, volatile void __iomem *addr)
+static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
 {
        asm volatile("str %w0, [%1]" : : "rZ" (val), "r" (addr));
 }
@@ -69,7 +69,7 @@ static inline u16 __raw_readw(const volatile void __iomem *addr)
 }
 
 #define __raw_readl __raw_readl
-static inline u32 __raw_readl(const volatile void __iomem *addr)
+static __always_inline u32 __raw_readl(const volatile void __iomem *addr)
 {
        u32 val;
        asm volatile(ALTERNATIVE("ldr %w0, [%1]",
index 688c634..f658dda 100644 (file)
@@ -36,7 +36,7 @@ void kvm_inject_undef32(struct kvm_vcpu *vcpu);
 void kvm_inject_dabt32(struct kvm_vcpu *vcpu, unsigned long addr);
 void kvm_inject_pabt32(struct kvm_vcpu *vcpu, unsigned long addr);
 
-static inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
+static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
 {
        return !(vcpu->arch.hcr_el2 & HCR_RW);
 }
@@ -127,7 +127,7 @@ static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
        vcpu->arch.vsesr_el2 = vsesr;
 }
 
-static inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
+static __always_inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
 {
        return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pc;
 }
@@ -153,17 +153,17 @@ static inline void vcpu_write_elr_el1(const struct kvm_vcpu *vcpu, unsigned long
                *__vcpu_elr_el1(vcpu) = v;
 }
 
-static inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
+static __always_inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
 {
        return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pstate;
 }
 
-static inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
+static __always_inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
 {
        return !!(*vcpu_cpsr(vcpu) & PSR_MODE32_BIT);
 }
 
-static inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu)
 {
        if (vcpu_mode_is_32bit(vcpu))
                return kvm_condition_valid32(vcpu);
@@ -181,13 +181,13 @@ static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
  * coming from a read of ESR_EL2. Otherwise, it may give the wrong result on
  * AArch32 with banked registers.
  */
-static inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu,
+static __always_inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu,
                                         u8 reg_num)
 {
        return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)->regs.regs[reg_num];
 }
 
-static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
+static __always_inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
                                unsigned long val)
 {
        if (reg_num != 31)
@@ -264,12 +264,12 @@ static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
        return mode != PSR_MODE_EL0t;
 }
 
-static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
+static __always_inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
 {
        return vcpu->arch.fault.esr_el2;
 }
 
-static inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
+static __always_inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
 {
        u32 esr = kvm_vcpu_get_hsr(vcpu);
 
@@ -279,12 +279,12 @@ static inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
        return -1;
 }
 
-static inline unsigned long kvm_vcpu_get_hfar(const struct kvm_vcpu *vcpu)
+static __always_inline unsigned long kvm_vcpu_get_hfar(const struct kvm_vcpu *vcpu)
 {
        return vcpu->arch.fault.far_el2;
 }
 
-static inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu *vcpu)
+static __always_inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu *vcpu)
 {
        return ((phys_addr_t)vcpu->arch.fault.hpfar_el2 & HPFAR_MASK) << 8;
 }
@@ -299,7 +299,7 @@ static inline u32 kvm_vcpu_hvc_get_imm(const struct kvm_vcpu *vcpu)
        return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_xVC_IMM_MASK;
 }
 
-static inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu)
 {
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_ISV);
 }
@@ -319,17 +319,17 @@ static inline bool kvm_vcpu_dabt_issf(const struct kvm_vcpu *vcpu)
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SF);
 }
 
-static inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
+static __always_inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
 {
        return (kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SRT_MASK) >> ESR_ELx_SRT_SHIFT;
 }
 
-static inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
 {
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_S1PTW);
 }
 
-static inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
 {
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WNR) ||
                kvm_vcpu_dabt_iss1tw(vcpu); /* AF/DBM update */
@@ -340,18 +340,18 @@ static inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu)
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_CM);
 }
 
-static inline unsigned int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu)
+static __always_inline unsigned int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu)
 {
        return 1 << ((kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SAS) >> ESR_ELx_SAS_SHIFT);
 }
 
 /* This one is not specific to Data Abort */
-static inline bool kvm_vcpu_trap_il_is32bit(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_trap_il_is32bit(const struct kvm_vcpu *vcpu)
 {
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_IL);
 }
 
-static inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
+static __always_inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
 {
        return ESR_ELx_EC(kvm_vcpu_get_hsr(vcpu));
 }
@@ -361,17 +361,17 @@ static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
        return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW;
 }
 
-static inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
+static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
 {
        return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_FSC;
 }
 
-static inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu)
+static __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu)
 {
        return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_FSC_TYPE;
 }
 
-static inline bool kvm_vcpu_dabt_isextabt(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_dabt_isextabt(const struct kvm_vcpu *vcpu)
 {
        switch (kvm_vcpu_trap_get_fault(vcpu)) {
        case FSC_SEA:
@@ -390,7 +390,7 @@ static inline bool kvm_vcpu_dabt_isextabt(const struct kvm_vcpu *vcpu)
        }
 }
 
-static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
+static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
 {
        u32 esr = kvm_vcpu_get_hsr(vcpu);
        return ESR_ELx_SYS64_ISS_RT(esr);
@@ -504,7 +504,7 @@ static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu,
        return data;            /* Leave LE untouched */
 }
 
-static inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
+static __always_inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
 {
        if (vcpu_mode_is_32bit(vcpu))
                kvm_skip_instr32(vcpu, is_wide_instr);
@@ -519,7 +519,7 @@ static inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
  * Skip an instruction which has been emulated at hyp while most guest sysregs
  * are live.
  */
-static inline void __hyp_text __kvm_skip_instr(struct kvm_vcpu *vcpu)
+static __always_inline void __hyp_text __kvm_skip_instr(struct kvm_vcpu *vcpu)
 {
        *vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);
        vcpu->arch.ctxt.gp_regs.regs.pstate = read_sysreg_el2(SYS_SPSR);
index d87aa60..57fd46a 100644 (file)
@@ -626,38 +626,6 @@ static inline void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr) {}
 static inline void kvm_clr_pmu_events(u32 clr) {}
 #endif
 
-static inline void kvm_arm_vhe_guest_enter(void)
-{
-       local_daif_mask();
-
-       /*
-        * Having IRQs masked via PMR when entering the guest means the GIC
-        * will not signal the CPU of interrupts of lower priority, and the
-        * only way to get out will be via guest exceptions.
-        * Naturally, we want to avoid this.
-        *
-        * local_daif_mask() already sets GIC_PRIO_PSR_I_SET, we just need a
-        * dsb to ensure the redistributor is forwards EL2 IRQs to the CPU.
-        */
-       pmr_sync();
-}
-
-static inline void kvm_arm_vhe_guest_exit(void)
-{
-       /*
-        * local_daif_restore() takes care to properly restore PSTATE.DAIF
-        * and the GIC PMR if the host is using IRQ priorities.
-        */
-       local_daif_restore(DAIF_PROCCTX_NOIRQ);
-
-       /*
-        * When we exit from the guest we change a number of CPU configuration
-        * parameters, such as traps.  Make sure these changes take effect
-        * before running the host or additional guests.
-        */
-       isb();
-}
-
 #define KVM_BP_HARDEN_UNKNOWN          -1
 #define KVM_BP_HARDEN_WA_NEEDED                0
 #define KVM_BP_HARDEN_NOT_REQUIRED     1
index a3a6a2b..fe57f60 100644 (file)
 #define read_sysreg_el2(r)     read_sysreg_elx(r, _EL2, _EL1)
 #define write_sysreg_el2(v,r)  write_sysreg_elx(v, r, _EL2, _EL1)
 
+/*
+ * Without an __arch_swab32(), we fall back to ___constant_swab32(), but the
+ * static inline can allow the compiler to out-of-line this. KVM always wants
+ * the macro version as its always inlined.
+ */
+#define __kvm_swab32(x)        ___constant_swab32(x)
+
 int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
index 53d846f..7857628 100644 (file)
@@ -93,7 +93,7 @@ void kvm_update_va_mask(struct alt_instr *alt,
                        __le32 *origptr, __le32 *updptr, int nr_inst);
 void kvm_compute_layout(void);
 
-static inline unsigned long __kern_hyp_va(unsigned long v)
+static __always_inline unsigned long __kern_hyp_va(unsigned long v)
 {
        asm volatile(ALTERNATIVE_CB("and %0, %0, #1\n"
                                    "ror %0, %0, #1\n"
@@ -473,6 +473,7 @@ static inline int kvm_write_guest_lock(struct kvm *kvm, gpa_t gpa,
 extern void *__kvm_bp_vect_base;
 extern int __kvm_harden_el2_vector_slot;
 
+/*  This is only called on a VHE system */
 static inline void *kvm_get_hyp_vector(void)
 {
        struct bp_hardening_data *data = arm64_get_bp_hardening_data();
index 0958ed6..61fd267 100644 (file)
@@ -83,7 +83,7 @@ static inline bool is_kernel_in_hyp_mode(void)
        return read_sysreg(CurrentEL) == CurrentEL_EL2;
 }
 
-static inline bool has_vhe(void)
+static __always_inline bool has_vhe(void)
 {
        if (cpus_have_const_cap(ARM64_HAS_VIRT_HOST_EXTN))
                return true;
index dfe8dd1..925086b 100644 (file)
@@ -625,7 +625,7 @@ static void __hyp_text __pmu_switch_to_host(struct kvm_cpu_context *host_ctxt)
 }
 
 /* Switch to the guest for VHE systems running in EL2 */
-int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
+static int __kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpu_context *host_ctxt;
        struct kvm_cpu_context *guest_ctxt;
@@ -678,7 +678,42 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 
        return exit_code;
 }
-NOKPROBE_SYMBOL(kvm_vcpu_run_vhe);
+NOKPROBE_SYMBOL(__kvm_vcpu_run_vhe);
+
+int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
+{
+       int ret;
+
+       local_daif_mask();
+
+       /*
+        * Having IRQs masked via PMR when entering the guest means the GIC
+        * will not signal the CPU of interrupts of lower priority, and the
+        * only way to get out will be via guest exceptions.
+        * Naturally, we want to avoid this.
+        *
+        * local_daif_mask() already sets GIC_PRIO_PSR_I_SET, we just need a
+        * dsb to ensure the redistributor is forwards EL2 IRQs to the CPU.
+        */
+       pmr_sync();
+
+       ret = __kvm_vcpu_run_vhe(vcpu);
+
+       /*
+        * local_daif_restore() takes care to properly restore PSTATE.DAIF
+        * and the GIC PMR if the host is using IRQ priorities.
+        */
+       local_daif_restore(DAIF_PROCCTX_NOIRQ);
+
+       /*
+        * When we exit from the guest we change a number of CPU configuration
+        * parameters, such as traps.  Make sure these changes take effect
+        * before running the host or additional guests.
+        */
+       isb();
+
+       return ret;
+}
 
 /* Switch to the guest for legacy non-VHE systems */
 int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
index 29ee1fe..4f3a087 100644 (file)
@@ -69,14 +69,14 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
                u32 data = vcpu_get_reg(vcpu, rd);
                if (__is_be(vcpu)) {
                        /* guest pre-swabbed data, undo this for writel() */
-                       data = swab32(data);
+                       data = __kvm_swab32(data);
                }
                writel_relaxed(data, addr);
        } else {
                u32 data = readl_relaxed(addr);
                if (__is_be(vcpu)) {
                        /* guest expects swabbed data */
-                       data = swab32(data);
+                       data = __kvm_swab32(data);
                }
                vcpu_set_reg(vcpu, rd, data);
        }
index 8ef73e8..d89bb22 100644 (file)
@@ -260,14 +260,26 @@ asmlinkage void post_ttbr_update_workaround(void)
                        CONFIG_CAVIUM_ERRATUM_27456));
 }
 
-static int asids_init(void)
+static int asids_update_limit(void)
 {
-       asid_bits = get_cpu_asid_bits();
+       unsigned long num_available_asids = NUM_USER_ASIDS;
+
+       if (arm64_kernel_unmapped_at_el0())
+               num_available_asids /= 2;
        /*
         * Expect allocation after rollover to fail if we don't have at least
         * one more ASID than CPUs. ASID #0 is reserved for init_mm.
         */
-       WARN_ON(NUM_USER_ASIDS - 1 <= num_possible_cpus());
+       WARN_ON(num_available_asids - 1 <= num_possible_cpus());
+       pr_info("ASID allocator initialised with %lu entries\n",
+               num_available_asids);
+       return 0;
+}
+arch_initcall(asids_update_limit);
+
+static int asids_init(void)
+{
+       asid_bits = get_cpu_asid_bits();
        atomic64_set(&asid_generation, ASID_FIRST_VERSION);
        asid_map = kcalloc(BITS_TO_LONGS(NUM_USER_ASIDS), sizeof(*asid_map),
                           GFP_KERNEL);
@@ -282,8 +294,6 @@ static int asids_init(void)
         */
        if (IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0))
                set_kpti_asid_bits();
-
-       pr_info("ASID allocator initialised with %lu entries\n", NUM_USER_ASIDS);
        return 0;
 }
 early_initcall(asids_init);
index 5accda2..a3301ba 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <dt-bindings/clock/jz4740-cgu.h>
+#include <dt-bindings/clock/ingenic,tcu.h>
 
 / {
        #address-cells = <1>;
                #clock-cells = <1>;
        };
 
-       watchdog: watchdog@10002000 {
-               compatible = "ingenic,jz4740-watchdog";
-               reg = <0x10002000 0x10>;
-
-               clocks = <&cgu JZ4740_CLK_RTC>;
-               clock-names = "rtc";
-       };
-
        tcu: timer@10002000 {
                compatible = "ingenic,jz4740-tcu", "simple-mfd";
                reg = <0x10002000 0x1000>;
 
                interrupt-parent = <&intc>;
                interrupts = <23 22 21>;
+
+               watchdog: watchdog@0 {
+                       compatible = "ingenic,jz4740-watchdog";
+                       reg = <0x0 0xc>;
+
+                       clocks = <&tcu TCU_CLK_WDT>;
+                       clock-names = "wdt";
+               };
        };
 
        rtc_dev: rtc@10003000 {
index f928329..bb89653 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <dt-bindings/clock/jz4780-cgu.h>
+#include <dt-bindings/clock/ingenic,tcu.h>
 #include <dt-bindings/dma/jz4780-dma.h>
 
 / {
 
                interrupt-parent = <&intc>;
                interrupts = <27 26 25>;
+
+               watchdog: watchdog@0 {
+                       compatible = "ingenic,jz4780-watchdog";
+                       reg = <0x0 0xc>;
+
+                       clocks = <&tcu TCU_CLK_WDT>;
+                       clock-names = "wdt";
+               };
        };
 
        rtc_dev: rtc@10003000 {
                status = "disabled";
        };
 
-       watchdog: watchdog@10002000 {
-               compatible = "ingenic,jz4780-watchdog";
-               reg = <0x10002000 0x10>;
-
-               clocks = <&cgu JZ4780_CLK_RTCLK>;
-               clock-names = "rtc";
-       };
-
        nemc: nemc@13410000 {
                compatible = "ingenic,jz4780-nemc";
                reg = <0x13410000 0x10000>;
index 4994c69..147f7d5 100644 (file)
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <dt-bindings/clock/ingenic,tcu.h>
 #include <dt-bindings/clock/x1000-cgu.h>
 #include <dt-bindings/dma/x1000-dma.h>
 
@@ -72,7 +73,7 @@
                        compatible = "ingenic,x1000-watchdog", "ingenic,jz4780-watchdog";
                        reg = <0x0 0x10>;
 
-                       clocks = <&cgu X1000_CLK_RTCLK>;
+                       clocks = <&tcu TCU_CLK_WDT>;
                        clock-names = "wdt";
                };
        };
        i2c0: i2c-controller@10050000 {
                compatible = "ingenic,x1000-i2c";
                reg = <0x10050000 0x1000>;
-
                #address-cells = <1>;
                #size-cells = <0>;
 
        i2c1: i2c-controller@10051000 {
                compatible = "ingenic,x1000-i2c";
                reg = <0x10051000 0x1000>;
-
                #address-cells = <1>;
                #size-cells = <0>;
 
        i2c2: i2c-controller@10052000 {
                compatible = "ingenic,x1000-i2c";
                reg = <0x10052000 0x1000>;
-
                #address-cells = <1>;
                #size-cells = <0>;
 
index 7c6a109..aabd097 100644 (file)
  * effective barrier as noted by commit 6b07d38aaa52 ("MIPS: Octeon: Use
  * optimized memory barrier primitives."). Here we specify that the affected
  * sync instructions should be emitted twice.
+ * Note that this expression is evaluated by the assembler (not the compiler),
+ * and that the assembler evaluates '==' as 0 or -1, not 0 or 1.
  */
 #ifdef CONFIG_CPU_CAVIUM_OCTEON
-# define __SYNC_rpt(type)      (1 + (type == __SYNC_wmb))
+# define __SYNC_rpt(type)      (1 - (type == __SYNC_wmb))
 #else
 # define __SYNC_rpt(type)      1
 #endif
index 6176b9a..d0d832a 100644 (file)
@@ -134,7 +134,7 @@ void release_vpe(struct vpe *v)
 {
        list_del(&v->list);
        if (v->load_addr)
-               release_progmem(v);
+               release_progmem(v->load_addr);
        kfree(v);
 }
 
index aa89a41..d7fe840 100644 (file)
@@ -33,6 +33,7 @@ endif
 cflags-vdso := $(ccflags-vdso) \
        $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
        -O3 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \
+       -mrelax-pic-calls $(call cc-option, -mexplicit-relocs) \
        -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \
        $(call cc-option, -fno-asynchronous-unwind-tables) \
        $(call cc-option, -fno-stack-protector)
@@ -51,6 +52,8 @@ endif
 
 CFLAGS_REMOVE_vgettimeofday.o = -pg
 
+DISABLE_VDSO := n
+
 #
 # For the pre-R6 code in arch/mips/vdso/vdso.h for locating
 # the base address of VDSO, the linker will emit a R_MIPS_PC32
@@ -64,11 +67,24 @@ CFLAGS_REMOVE_vgettimeofday.o = -pg
 ifndef CONFIG_CPU_MIPSR6
   ifeq ($(call ld-ifversion, -lt, 225000000, y),y)
     $(warning MIPS VDSO requires binutils >= 2.25)
-    obj-vdso-y := $(filter-out vgettimeofday.o, $(obj-vdso-y))
-    ccflags-vdso += -DDISABLE_MIPS_VDSO
+    DISABLE_VDSO := y
   endif
 endif
 
+#
+# GCC (at least up to version 9.2) appears to emit function calls that make use
+# of the GOT when targeting microMIPS, which we can't use in the VDSO due to
+# the lack of relocations. As such, we disable the VDSO for microMIPS builds.
+#
+ifdef CONFIG_CPU_MICROMIPS
+  DISABLE_VDSO := y
+endif
+
+ifeq ($(DISABLE_VDSO),y)
+  obj-vdso-y := $(filter-out vgettimeofday.o, $(obj-vdso-y))
+  ccflags-vdso += -DDISABLE_MIPS_VDSO
+endif
+
 # VDSO linker flags.
 VDSO_LDFLAGS := \
        -Wl,-Bsymbolic -Wl,--no-undefined -Wl,-soname=linux-vdso.so.1 \
@@ -81,12 +97,18 @@ GCOV_PROFILE := n
 UBSAN_SANITIZE := n
 KCOV_INSTRUMENT := n
 
+# Check that we don't have PIC 'jalr t9' calls left
+quiet_cmd_vdso_mips_check = VDSOCHK $@
+      cmd_vdso_mips_check = if $(OBJDUMP) --disassemble $@ | egrep -h "jalr.*t9" > /dev/null; \
+                      then (echo >&2 "$@: PIC 'jalr t9' calls are not supported"; \
+                            rm -f $@; /bin/false); fi
+
 #
 # Shared build commands.
 #
 
 quiet_cmd_vdsold_and_vdso_check = LD      $@
-      cmd_vdsold_and_vdso_check = $(cmd_vdsold); $(cmd_vdso_check)
+      cmd_vdsold_and_vdso_check = $(cmd_vdsold); $(cmd_vdso_check); $(cmd_vdso_mips_check)
 
 quiet_cmd_vdsold = VDSO    $@
       cmd_vdsold = $(CC) $(c_flags) $(VDSO_LDFLAGS) \
index e745abc..245be4f 100644 (file)
@@ -2193,11 +2193,13 @@ static struct cpu_spec * __init setup_cpu_spec(unsigned long offset,
                 * oprofile_cpu_type already has a value, then we are
                 * possibly overriding a real PVR with a logical one,
                 * and, in that case, keep the current value for
-                * oprofile_cpu_type.
+                * oprofile_cpu_type. Futhermore, let's ensure that the
+                * fix for the PMAO bug is enabled on compatibility mode.
                 */
                if (old.oprofile_cpu_type != NULL) {
                        t->oprofile_cpu_type = old.oprofile_cpu_type;
                        t->oprofile_type = old.oprofile_type;
+                       t->cpu_features |= old.cpu_features & CPU_FTR_PMAO_BUG;
                }
        }
 
index 2462cd7..d085432 100644 (file)
@@ -331,11 +331,13 @@ int hw_breakpoint_handler(struct die_args *args)
        }
 
        info->type &= ~HW_BRK_TYPE_EXTRANEOUS_IRQ;
-       if (!dar_within_range(regs->dar, info))
-               info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
-
-       if (!IS_ENABLED(CONFIG_PPC_8xx) && !stepping_handler(regs, bp, info))
-               goto out;
+       if (IS_ENABLED(CONFIG_PPC_8xx)) {
+               if (!dar_within_range(regs->dar, info))
+                       info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
+       } else {
+               if (!stepping_handler(regs, bp, info))
+                       goto out;
+       }
 
        /*
         * As a policy, the callback is invoked in a 'trigger-after-execute'
index b4c89a1..a32d478 100644 (file)
@@ -303,6 +303,12 @@ SECTIONS
                *(.branch_lt)
        }
 
+#ifdef CONFIG_DEBUG_INFO_BTF
+       .BTF : AT(ADDR(.BTF) - LOAD_OFFSET) {
+               *(.BTF)
+       }
+#endif
+
        .opd : AT(ADDR(.opd) - LOAD_OFFSET) {
                __start_opd = .;
                KEEP(*(.opd))
index ef7b111..1c07d5a 100644 (file)
@@ -373,7 +373,9 @@ static inline bool flush_coherent_icache(unsigned long addr)
         */
        if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) {
                mb(); /* sync */
+               allow_read_from_user((const void __user *)addr, L1_CACHE_BYTES);
                icbi((void *)addr);
+               prevent_read_from_user((const void __user *)addr, L1_CACHE_BYTES);
                mb(); /* sync */
                isync();
                return true;
index 73f029e..1a3b5a5 100644 (file)
@@ -121,6 +121,7 @@ config ARCH_FLATMEM_ENABLE
 
 config ARCH_SPARSEMEM_ENABLE
        def_bool y
+       depends on MMU
        select SPARSEMEM_VMEMMAP_ENABLE
 
 config ARCH_SELECT_MEMORY_MODEL
index d325b67..3078b2d 100644 (file)
@@ -10,4 +10,28 @@ config SOC_SIFIVE
        help
          This enables support for SiFive SoC platform hardware.
 
+config SOC_VIRT
+       bool "QEMU Virt Machine"
+       select VIRTIO_PCI
+       select VIRTIO_BALLOON
+       select VIRTIO_MMIO
+       select VIRTIO_CONSOLE
+       select VIRTIO_NET
+       select NET_9P_VIRTIO
+       select VIRTIO_BLK
+       select SCSI_VIRTIO
+       select DRM_VIRTIO_GPU
+       select HW_RANDOM_VIRTIO
+       select RPMSG_CHAR
+       select RPMSG_VIRTIO
+       select CRYPTO_DEV_VIRTIO
+       select VIRTIO_INPUT
+       select POWER_RESET_SYSCON
+       select POWER_RESET_SYSCON_POWEROFF
+       select GOLDFISH
+       select RTC_DRV_GOLDFISH
+       select SIFIVE_PLIC
+       help
+         This enables support for QEMU Virt Machine.
+
 endmenu
index b9009a2..259cb53 100644 (file)
@@ -13,8 +13,10 @@ LDFLAGS_vmlinux :=
 ifeq ($(CONFIG_DYNAMIC_FTRACE),y)
        LDFLAGS_vmlinux := --no-relax
 endif
-KBUILD_AFLAGS_MODULE += -fPIC
-KBUILD_CFLAGS_MODULE += -fPIC
+
+ifeq ($(CONFIG_64BIT)$(CONFIG_CMODEL_MEDLOW),yy)
+KBUILD_CFLAGS_MODULE += -mcmodel=medany
+endif
 
 export BITS
 ifeq ($(CONFIG_ARCH_RV64I),y)
index 8dab0bb..8a45a37 100644 (file)
@@ -1,2 +1,4 @@
 Image
 Image.gz
+loader
+loader.lds
index 609198c..4a2729f 100644 (file)
@@ -2,6 +2,7 @@
 /* Copyright (c) 2018-2019 SiFive, Inc */
 
 #include "fu540-c000.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 
 /* Clock frequency (in Hz) of the PCB crystal for rtcclk */
 #define RTCCLK_FREQ            1000000
                clock-frequency = <RTCCLK_FREQ>;
                clock-output-names = "rtcclk";
        };
+       gpio-restart {
+               compatible = "gpio-restart";
+               gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
+       };
 };
 
 &uart0 {
index e2ff95c..c8f0842 100644 (file)
@@ -15,6 +15,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 CONFIG_BPF_SYSCALL=y
 CONFIG_SOC_SIFIVE=y
+CONFIG_SOC_VIRT=y
 CONFIG_SMP=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
@@ -30,7 +31,6 @@ CONFIG_IP_PNP_BOOTP=y
 CONFIG_IP_PNP_RARP=y
 CONFIG_NETLINK_DIAG=y
 CONFIG_NET_9P=y
-CONFIG_NET_9P_VIRTIO=y
 CONFIG_PCI=y
 CONFIG_PCIEPORTBUS=y
 CONFIG_PCI_HOST_GENERIC=y
@@ -38,15 +38,12 @@ CONFIG_PCIE_XILINX=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_BLK_DEV_LOOP=y
-CONFIG_VIRTIO_BLK=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_SCSI_VIRTIO=y
 CONFIG_ATA=y
 CONFIG_SATA_AHCI=y
 CONFIG_SATA_AHCI_PLATFORM=y
 CONFIG_NETDEVICES=y
-CONFIG_VIRTIO_NET=y
 CONFIG_MACB=y
 CONFIG_E1000E=y
 CONFIG_R8169=y
@@ -57,15 +54,13 @@ CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
 CONFIG_HVC_RISCV_SBI=y
-CONFIG_VIRTIO_CONSOLE=y
 CONFIG_HW_RANDOM=y
-CONFIG_HW_RANDOM_VIRTIO=y
 CONFIG_SPI=y
 CONFIG_SPI_SIFIVE=y
 # CONFIG_PTP_1588_CLOCK is not set
+CONFIG_POWER_RESET=y
 CONFIG_DRM=y
 CONFIG_DRM_RADEON=y
-CONFIG_DRM_VIRTIO_GPU=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
@@ -78,12 +73,7 @@ CONFIG_USB_STORAGE=y
 CONFIG_USB_UAS=y
 CONFIG_MMC=y
 CONFIG_MMC_SPI=y
-CONFIG_VIRTIO_PCI=y
-CONFIG_VIRTIO_BALLOON=y
-CONFIG_VIRTIO_INPUT=y
-CONFIG_VIRTIO_MMIO=y
-CONFIG_RPMSG_CHAR=y
-CONFIG_RPMSG_VIRTIO=y
+CONFIG_RTC_CLASS=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_AUTOFS4_FS=y
@@ -98,7 +88,6 @@ CONFIG_NFS_V4_2=y
 CONFIG_ROOT_NFS=y
 CONFIG_9P_FS=y
 CONFIG_CRYPTO_USER_API_HASH=y
-CONFIG_CRYPTO_DEV_VIRTIO=y
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_PAGEALLOC=y
index eb51940..a844920 100644 (file)
@@ -14,6 +14,7 @@ CONFIG_CHECKPOINT_RESTORE=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 CONFIG_BPF_SYSCALL=y
+CONFIG_SOC_VIRT=y
 CONFIG_ARCH_RV32I=y
 CONFIG_SMP=y
 CONFIG_MODULES=y
@@ -30,7 +31,6 @@ CONFIG_IP_PNP_BOOTP=y
 CONFIG_IP_PNP_RARP=y
 CONFIG_NETLINK_DIAG=y
 CONFIG_NET_9P=y
-CONFIG_NET_9P_VIRTIO=y
 CONFIG_PCI=y
 CONFIG_PCIEPORTBUS=y
 CONFIG_PCI_HOST_GENERIC=y
@@ -38,15 +38,12 @@ CONFIG_PCIE_XILINX=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_BLK_DEV_LOOP=y
-CONFIG_VIRTIO_BLK=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
-CONFIG_SCSI_VIRTIO=y
 CONFIG_ATA=y
 CONFIG_SATA_AHCI=y
 CONFIG_SATA_AHCI_PLATFORM=y
 CONFIG_NETDEVICES=y
-CONFIG_VIRTIO_NET=y
 CONFIG_MACB=y
 CONFIG_E1000E=y
 CONFIG_R8169=y
@@ -57,13 +54,11 @@ CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
 CONFIG_HVC_RISCV_SBI=y
-CONFIG_VIRTIO_CONSOLE=y
 CONFIG_HW_RANDOM=y
-CONFIG_HW_RANDOM_VIRTIO=y
 # CONFIG_PTP_1588_CLOCK is not set
+CONFIG_POWER_RESET=y
 CONFIG_DRM=y
 CONFIG_DRM_RADEON=y
-CONFIG_DRM_VIRTIO_GPU=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
@@ -74,13 +69,7 @@ CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_HCD_PLATFORM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_UAS=y
-CONFIG_VIRTIO_PCI=y
-CONFIG_VIRTIO_BALLOON=y
-CONFIG_VIRTIO_INPUT=y
-CONFIG_VIRTIO_MMIO=y
-CONFIG_RPMSG_CHAR=y
-CONFIG_RPMSG_VIRTIO=y
-CONFIG_SIFIVE_PLIC=y
+CONFIG_RTC_CLASS=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_AUTOFS4_FS=y
@@ -95,7 +84,6 @@ CONFIG_NFS_V4_2=y
 CONFIG_ROOT_NFS=y
 CONFIG_9P_FS=y
 CONFIG_CRYPTO_USER_API_HASH=y
-CONFIG_CRYPTO_DEV_VIRTIO=y
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_PAGEALLOC=y
index 435b655..8e18d2c 100644 (file)
 #define EXC_LOAD_PAGE_FAULT    13
 #define EXC_STORE_PAGE_FAULT   15
 
+/* PMP configuration */
+#define PMP_R                  0x01
+#define PMP_W                  0x02
+#define PMP_X                  0x04
+#define PMP_A                  0x18
+#define PMP_A_TOR              0x08
+#define PMP_A_NA4              0x10
+#define PMP_A_NAPOT            0x18
+#define PMP_L                  0x80
+
 /* symbolic CSR names: */
 #define CSR_CYCLE              0xc00
 #define CSR_TIME               0xc01
 #define CSR_MCAUSE             0x342
 #define CSR_MTVAL              0x343
 #define CSR_MIP                        0x344
+#define CSR_PMPCFG0            0x3a0
+#define CSR_PMPADDR0           0x3b0
 #define CSR_MHARTID            0xf14
 
 #ifdef CONFIG_RISCV_M_MODE
index 42347d0..49350c8 100644 (file)
@@ -28,13 +28,6 @@ static inline int syscall_get_nr(struct task_struct *task,
        return regs->a7;
 }
 
-static inline void syscall_set_nr(struct task_struct *task,
-                                 struct pt_regs *regs,
-                                 int sysno)
-{
-       regs->a7 = sysno;
-}
-
 static inline void syscall_rollback(struct task_struct *task,
                                    struct pt_regs *regs)
 {
index bad4d85..208702d 100644 (file)
@@ -229,19 +229,12 @@ check_syscall_nr:
        li t0, __NR_syscalls
        la s0, sys_ni_syscall
        /*
-        * The tracer can change syscall number to valid/invalid value.
-        * We use syscall_set_nr helper in syscall_trace_enter thus we
-        * cannot trust the current value in a7 and have to reload from
-        * the current task pt_regs.
-        */
-       REG_L a7, PT_A7(sp)
-       /*
         * Syscall number held in a7.
         * If syscall number is above allowed value, redirect to ni_syscall.
         */
        bge a7, t0, 1f
        /*
-        * Check if syscall is rejected by tracer or seccomp, i.e., a7 == -1.
+        * Check if syscall is rejected by tracer, i.e., a7 == -1.
         * If yes, we pretend it was executed.
         */
        li t1, -1
@@ -334,6 +327,7 @@ work_resched:
 handle_syscall_trace_enter:
        move a0, sp
        call do_syscall_trace_enter
+       move t0, a0
        REG_L a0, PT_A0(sp)
        REG_L a1, PT_A1(sp)
        REG_L a2, PT_A2(sp)
@@ -342,6 +336,7 @@ handle_syscall_trace_enter:
        REG_L a5, PT_A5(sp)
        REG_L a6, PT_A6(sp)
        REG_L a7, PT_A7(sp)
+       bnez t0, ret_from_syscall_rejected
        j check_syscall_nr
 handle_syscall_trace_exit:
        move a0, sp
index 271860f..85f2073 100644 (file)
@@ -58,6 +58,12 @@ _start_kernel:
        /* Reset all registers except ra, a0, a1 */
        call reset_regs
 
+       /* Setup a PMP to permit access to all of memory. */
+       li a0, -1
+       csrw CSR_PMPADDR0, a0
+       li a0, (PMP_A_NAPOT | PMP_R | PMP_W | PMP_X)
+       csrw CSR_PMPCFG0, a0
+
        /*
         * The hartid in a0 is expected later on, and we have no firmware
         * to hand it to us.
index b740185..8bbe5db 100644 (file)
@@ -8,6 +8,10 @@
 #include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/moduleloader.h>
+#include <linux/vmalloc.h>
+#include <linux/sizes.h>
+#include <asm/pgtable.h>
+#include <asm/sections.h>
 
 static int apply_r_riscv_32_rela(struct module *me, u32 *location, Elf_Addr v)
 {
@@ -386,3 +390,15 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
 
        return 0;
 }
+
+#if defined(CONFIG_MMU) && defined(CONFIG_64BIT)
+#define VMALLOC_MODULE_START \
+        max(PFN_ALIGN((unsigned long)&_end - SZ_2G), VMALLOC_START)
+void *module_alloc(unsigned long size)
+{
+       return __vmalloc_node_range(size, 1, VMALLOC_MODULE_START,
+                                   VMALLOC_END, GFP_KERNEL,
+                                   PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
+                                   __builtin_return_address(0));
+}
+#endif
index 4074642..444dc7b 100644 (file)
@@ -148,21 +148,19 @@ long arch_ptrace(struct task_struct *child, long request,
  * Allows PTRACE_SYSCALL to work.  These are called from entry.S in
  * {handle,ret_from}_syscall.
  */
-__visible void do_syscall_trace_enter(struct pt_regs *regs)
+__visible int do_syscall_trace_enter(struct pt_regs *regs)
 {
        if (test_thread_flag(TIF_SYSCALL_TRACE))
                if (tracehook_report_syscall_entry(regs))
-                       syscall_set_nr(current, regs, -1);
+                       return -1;
 
        /*
         * Do the secure computing after ptrace; failures should be fast.
         * If this fails we might have return value in a0 from seccomp
         * (via SECCOMP_RET_ERRNO/TRACE).
         */
-       if (secure_computing() == -1) {
-               syscall_set_nr(current, regs, -1);
-               return;
-       }
+       if (secure_computing() == -1)
+               return -1;
 
 #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
@@ -170,6 +168,7 @@ __visible void do_syscall_trace_enter(struct pt_regs *regs)
 #endif
 
        audit_syscall_entry(regs->a7, regs->a0, regs->a1, regs->a2, regs->a3);
+       return 0;
 }
 
 __visible void do_syscall_trace_exit(struct pt_regs *regs)
index f4cad51..ffb3d94 100644 (file)
@@ -156,6 +156,6 @@ void __init trap_init(void)
        csr_write(CSR_SCRATCH, 0);
        /* Set the exception vector address */
        csr_write(CSR_TVEC, &handle_exception);
-       /* Enable all interrupts */
-       csr_write(CSR_IE, -1);
+       /* Enable interrupts */
+       csr_write(CSR_IE, IE_SIE | IE_EIE);
 }
index 965a8cf..fab8559 100644 (file)
@@ -131,7 +131,7 @@ void __init setup_bootmem(void)
        for_each_memblock(memory, reg) {
                phys_addr_t end = reg->base + reg->size;
 
-               if (reg->base <= vmlinux_end && vmlinux_end <= end) {
+               if (reg->base <= vmlinux_start && vmlinux_end <= end) {
                        mem_size = min(reg->size, (phys_addr_t)-PAGE_OFFSET);
 
                        /*
index f0cc860..ec0ca90 100644 (file)
@@ -19,18 +19,20 @@ asmlinkage void __init kasan_early_init(void)
        for (i = 0; i < PTRS_PER_PTE; ++i)
                set_pte(kasan_early_shadow_pte + i,
                        mk_pte(virt_to_page(kasan_early_shadow_page),
-                       PAGE_KERNEL));
+                              PAGE_KERNEL));
 
        for (i = 0; i < PTRS_PER_PMD; ++i)
                set_pmd(kasan_early_shadow_pmd + i,
-                pfn_pmd(PFN_DOWN(__pa((uintptr_t)kasan_early_shadow_pte)),
-                       __pgprot(_PAGE_TABLE)));
+                       pfn_pmd(PFN_DOWN
+                               (__pa((uintptr_t) kasan_early_shadow_pte)),
+                               __pgprot(_PAGE_TABLE)));
 
        for (i = KASAN_SHADOW_START; i < KASAN_SHADOW_END;
             i += PGDIR_SIZE, ++pgd)
                set_pgd(pgd,
-                pfn_pgd(PFN_DOWN(__pa(((uintptr_t)kasan_early_shadow_pmd))),
-                       __pgprot(_PAGE_TABLE)));
+                       pfn_pgd(PFN_DOWN
+                               (__pa(((uintptr_t) kasan_early_shadow_pmd))),
+                               __pgprot(_PAGE_TABLE)));
 
        /* init for swapper_pg_dir */
        pgd = pgd_offset_k(KASAN_SHADOW_START);
@@ -38,37 +40,43 @@ asmlinkage void __init kasan_early_init(void)
        for (i = KASAN_SHADOW_START; i < KASAN_SHADOW_END;
             i += PGDIR_SIZE, ++pgd)
                set_pgd(pgd,
-                pfn_pgd(PFN_DOWN(__pa(((uintptr_t)kasan_early_shadow_pmd))),
-                       __pgprot(_PAGE_TABLE)));
+                       pfn_pgd(PFN_DOWN
+                               (__pa(((uintptr_t) kasan_early_shadow_pmd))),
+                               __pgprot(_PAGE_TABLE)));
 
        flush_tlb_all();
 }
 
 static void __init populate(void *start, void *end)
 {
-       unsigned long i;
+       unsigned long i, offset;
        unsigned long vaddr = (unsigned long)start & PAGE_MASK;
        unsigned long vend = PAGE_ALIGN((unsigned long)end);
        unsigned long n_pages = (vend - vaddr) / PAGE_SIZE;
+       unsigned long n_ptes =
+           ((n_pages + PTRS_PER_PTE) & -PTRS_PER_PTE) / PTRS_PER_PTE;
        unsigned long n_pmds =
-               (n_pages % PTRS_PER_PTE) ? n_pages / PTRS_PER_PTE + 1 :
-                                               n_pages / PTRS_PER_PTE;
+           ((n_ptes + PTRS_PER_PMD) & -PTRS_PER_PMD) / PTRS_PER_PMD;
+
+       pte_t *pte =
+           memblock_alloc(n_ptes * PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE);
+       pmd_t *pmd =
+           memblock_alloc(n_pmds * PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE);
        pgd_t *pgd = pgd_offset_k(vaddr);
-       pmd_t *pmd = memblock_alloc(n_pmds * sizeof(pmd_t), PAGE_SIZE);
-       pte_t *pte = memblock_alloc(n_pages * sizeof(pte_t), PAGE_SIZE);
 
        for (i = 0; i < n_pages; i++) {
                phys_addr_t phys = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE);
-
-               set_pte(pte + i, pfn_pte(PHYS_PFN(phys), PAGE_KERNEL));
+               set_pte(&pte[i], pfn_pte(PHYS_PFN(phys), PAGE_KERNEL));
        }
 
-       for (i = 0; i < n_pmds; ++pgd, i += PTRS_PER_PMD)
-               set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(((uintptr_t)(pmd + i)))),
+       for (i = 0, offset = 0; i < n_ptes; i++, offset += PTRS_PER_PTE)
+               set_pmd(&pmd[i],
+                       pfn_pmd(PFN_DOWN(__pa(&pte[offset])),
                                __pgprot(_PAGE_TABLE)));
 
-       for (i = 0; i < n_pages; ++pmd, i += PTRS_PER_PTE)
-               set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa((uintptr_t)(pte + i))),
+       for (i = 0, offset = 0; i < n_pmds; i++, offset += PTRS_PER_PMD)
+               set_pgd(&pgd[i],
+                       pfn_pgd(PFN_DOWN(__pa(&pmd[offset])),
                                __pgprot(_PAGE_TABLE)));
 
        flush_tlb_all();
@@ -81,7 +89,8 @@ void __init kasan_init(void)
        unsigned long i;
 
        kasan_populate_early_shadow((void *)KASAN_SHADOW_START,
-                       (void *)kasan_mem_to_shadow((void *)VMALLOC_END));
+                                   (void *)kasan_mem_to_shadow((void *)
+                                                               VMALLOC_END));
 
        for_each_memblock(memory, reg) {
                void *start = (void *)__va(reg->base);
@@ -90,14 +99,14 @@ void __init kasan_init(void)
                if (start >= end)
                        break;
 
-               populate(kasan_mem_to_shadow(start),
-                        kasan_mem_to_shadow(end));
+               populate(kasan_mem_to_shadow(start), kasan_mem_to_shadow(end));
        };
 
        for (i = 0; i < PTRS_PER_PTE; i++)
                set_pte(&kasan_early_shadow_pte[i],
                        mk_pte(virt_to_page(kasan_early_shadow_page),
-                       __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_ACCESSED)));
+                              __pgprot(_PAGE_PRESENT | _PAGE_READ |
+                                       _PAGE_ACCESSED)));
 
        memset(kasan_early_shadow_page, 0, PAGE_SIZE);
        init_task.kasan_depth = 0;
index 137a392..6d7c3b7 100644 (file)
@@ -752,6 +752,12 @@ static inline int pmd_write(pmd_t pmd)
        return (pmd_val(pmd) & _SEGMENT_ENTRY_WRITE) != 0;
 }
 
+#define pud_write pud_write
+static inline int pud_write(pud_t pud)
+{
+       return (pud_val(pud) & _REGION3_ENTRY_WRITE) != 0;
+}
+
 static inline int pmd_dirty(pmd_t pmd)
 {
        return (pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY) != 0;
index bc61ea1..60716d1 100644 (file)
@@ -424,7 +424,7 @@ static void zpci_map_resources(struct pci_dev *pdev)
 
                if (zpci_use_mio(zdev))
                        pdev->resource[i].start =
-                               (resource_size_t __force) zdev->bars[i].mio_wb;
+                               (resource_size_t __force) zdev->bars[i].mio_wt;
                else
                        pdev->resource[i].start = (resource_size_t __force)
                                pci_iomap_range_fh(pdev, i, 0, 0);
@@ -531,7 +531,7 @@ static int zpci_setup_bus_resources(struct zpci_dev *zdev,
                        flags |= IORESOURCE_MEM_64;
 
                if (zpci_use_mio(zdev))
-                       addr = (unsigned long) zdev->bars[i].mio_wb;
+                       addr = (unsigned long) zdev->bars[i].mio_wt;
                else
                        addr = ZPCI_ADDR(entry);
                size = 1UL << zdev->bars[i].size;
index 02c6ef8..07344d8 100644 (file)
@@ -19,7 +19,14 @@ struct task_struct;
 void io_bitmap_share(struct task_struct *tsk);
 void io_bitmap_exit(void);
 
-void tss_update_io_bitmap(void);
+void native_tss_update_io_bitmap(void);
+
+#ifdef CONFIG_PARAVIRT_XXL
+#include <asm/paravirt.h>
+#else
+#define tss_update_io_bitmap native_tss_update_io_bitmap
+#endif
+
 #else
 static inline void io_bitmap_share(struct task_struct *tsk) { }
 static inline void io_bitmap_exit(void) { }
index 03946eb..2a8f2bd 100644 (file)
@@ -292,6 +292,14 @@ enum x86emul_mode {
 #define X86EMUL_SMM_MASK             (1 << 6)
 #define X86EMUL_SMM_INSIDE_NMI_MASK  (1 << 7)
 
+/*
+ * fastop functions are declared as taking a never-defined fastop parameter,
+ * so they can't be called from C directly.
+ */
+struct fastop;
+
+typedef void (*fastop_t)(struct fastop *);
+
 struct x86_emulate_ctxt {
        const struct x86_emulate_ops *ops;
 
@@ -324,7 +332,10 @@ struct x86_emulate_ctxt {
        struct operand src;
        struct operand src2;
        struct operand dst;
-       int (*execute)(struct x86_emulate_ctxt *ctxt);
+       union {
+               int (*execute)(struct x86_emulate_ctxt *ctxt);
+               fastop_t fop;
+       };
        int (*check_perm)(struct x86_emulate_ctxt *ctxt);
        /*
         * The following six fields are cleared together,
index 40a0c0f..98959e8 100644 (file)
@@ -1122,6 +1122,7 @@ struct kvm_x86_ops {
        int (*handle_exit)(struct kvm_vcpu *vcpu,
                enum exit_fastpath_completion exit_fastpath);
        int (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
+       void (*update_emulated_instruction)(struct kvm_vcpu *vcpu);
        void (*set_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask);
        u32 (*get_interrupt_shadow)(struct kvm_vcpu *vcpu);
        void (*patch_hypercall)(struct kvm_vcpu *vcpu,
@@ -1146,7 +1147,7 @@ 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, hpa_t hpa);
-       void (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector);
+       int (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, 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);
index 86e7317..694d8da 100644 (file)
@@ -295,6 +295,13 @@ static inline void write_idt_entry(gate_desc *dt, int entry, const gate_desc *g)
        PVOP_VCALL3(cpu.write_idt_entry, dt, entry, g);
 }
 
+#ifdef CONFIG_X86_IOPL_IOPERM
+static inline void tss_update_io_bitmap(void)
+{
+       PVOP_VCALL0(cpu.update_io_bitmap);
+}
+#endif
+
 static inline void paravirt_activate_mm(struct mm_struct *prev,
                                        struct mm_struct *next)
 {
index 8481296..732f62e 100644 (file)
@@ -140,6 +140,10 @@ struct pv_cpu_ops {
 
        void (*load_sp0)(unsigned long sp0);
 
+#ifdef CONFIG_X86_IOPL_IOPERM
+       void (*update_io_bitmap)(void);
+#endif
+
        void (*wbinvd)(void);
 
        /* cpuid emulation, mostly so that caps bits can be disabled */
index 2a85287..8521af3 100644 (file)
@@ -72,7 +72,7 @@
 #define SECONDARY_EXEC_MODE_BASED_EPT_EXEC     VMCS_CONTROL_BIT(MODE_BASED_EPT_EXEC)
 #define SECONDARY_EXEC_PT_USE_GPA              VMCS_CONTROL_BIT(PT_USE_GPA)
 #define SECONDARY_EXEC_TSC_SCALING              VMCS_CONTROL_BIT(TSC_SCALING)
-#define SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE   0x04000000
+#define SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE   VMCS_CONTROL_BIT(USR_WAIT_PAUSE)
 
 #define PIN_BASED_EXT_INTR_MASK                 VMCS_CONTROL_BIT(INTR_EXITING)
 #define PIN_BASED_NMI_EXITING                   VMCS_CONTROL_BIT(NMI_EXITING)
index a50e4a0..9915990 100644 (file)
@@ -81,6 +81,7 @@
 #define VMX_FEATURE_MODE_BASED_EPT_EXEC        ( 2*32+ 22) /* "ept_mode_based_exec" Enable separate EPT EXEC bits for supervisor vs. user */
 #define VMX_FEATURE_PT_USE_GPA         ( 2*32+ 24) /* "" Processor Trace logs GPAs */
 #define VMX_FEATURE_TSC_SCALING                ( 2*32+ 25) /* Scale hardware TSC when read in guest */
+#define VMX_FEATURE_USR_WAIT_PAUSE     ( 2*32+ 26) /* Enable TPAUSE, UMONITOR, UMWAIT in guest */
 #define VMX_FEATURE_ENCLV_EXITING      ( 2*32+ 28) /* "" VM-Exit on ENCLV (leaf dependent) */
 
 #endif /* _ASM_X86_VMXFEATURES_H */
index 503d3f4..3f3f780 100644 (file)
@@ -390,6 +390,7 @@ struct kvm_sync_regs {
 #define KVM_STATE_NESTED_GUEST_MODE    0x00000001
 #define KVM_STATE_NESTED_RUN_PENDING   0x00000002
 #define KVM_STATE_NESTED_EVMCS         0x00000004
+#define KVM_STATE_NESTED_MTF_PENDING   0x00000008
 
 #define KVM_STATE_NESTED_SMM_GUEST_MODE        0x00000001
 #define KVM_STATE_NESTED_SMM_VMXON     0x00000002
index 52c9bfb..4cdb123 100644 (file)
@@ -445,7 +445,7 @@ static __always_inline void setup_pku(struct cpuinfo_x86 *c)
         * cpuid bit to be set.  We need to ensure that we
         * update that bit in this CPU's "cpu_info".
         */
-       get_cpu_cap(c);
+       set_cpu_cap(c, X86_FEATURE_OSPKE);
 }
 
 #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
index d817f25..6efe041 100644 (file)
@@ -425,7 +425,29 @@ static void __init sev_map_percpu_data(void)
        }
 }
 
+static bool pv_tlb_flush_supported(void)
+{
+       return (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH) &&
+               !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
+               kvm_para_has_feature(KVM_FEATURE_STEAL_TIME));
+}
+
+static DEFINE_PER_CPU(cpumask_var_t, __pv_cpu_mask);
+
 #ifdef CONFIG_SMP
+
+static bool pv_ipi_supported(void)
+{
+       return kvm_para_has_feature(KVM_FEATURE_PV_SEND_IPI);
+}
+
+static bool pv_sched_yield_supported(void)
+{
+       return (kvm_para_has_feature(KVM_FEATURE_PV_SCHED_YIELD) &&
+               !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
+           kvm_para_has_feature(KVM_FEATURE_STEAL_TIME));
+}
+
 #define KVM_IPI_CLUSTER_SIZE   (2 * BITS_PER_LONG)
 
 static void __send_ipi_mask(const struct cpumask *mask, int vector)
@@ -490,12 +512,12 @@ static void kvm_send_ipi_mask(const struct cpumask *mask, int vector)
 static void kvm_send_ipi_mask_allbutself(const struct cpumask *mask, int vector)
 {
        unsigned int this_cpu = smp_processor_id();
-       struct cpumask new_mask;
+       struct cpumask *new_mask = this_cpu_cpumask_var_ptr(__pv_cpu_mask);
        const struct cpumask *local_mask;
 
-       cpumask_copy(&new_mask, mask);
-       cpumask_clear_cpu(this_cpu, &new_mask);
-       local_mask = &new_mask;
+       cpumask_copy(new_mask, mask);
+       cpumask_clear_cpu(this_cpu, new_mask);
+       local_mask = new_mask;
        __send_ipi_mask(local_mask, vector);
 }
 
@@ -575,7 +597,6 @@ static void __init kvm_apf_trap_init(void)
        update_intr_gate(X86_TRAP_PF, async_page_fault);
 }
 
-static DEFINE_PER_CPU(cpumask_var_t, __pv_tlb_mask);
 
 static void kvm_flush_tlb_others(const struct cpumask *cpumask,
                        const struct flush_tlb_info *info)
@@ -583,7 +604,7 @@ static void kvm_flush_tlb_others(const struct cpumask *cpumask,
        u8 state;
        int cpu;
        struct kvm_steal_time *src;
-       struct cpumask *flushmask = this_cpu_cpumask_var_ptr(__pv_tlb_mask);
+       struct cpumask *flushmask = this_cpu_cpumask_var_ptr(__pv_cpu_mask);
 
        cpumask_copy(flushmask, cpumask);
        /*
@@ -619,11 +640,10 @@ static void __init kvm_guest_init(void)
                pv_ops.time.steal_clock = kvm_steal_clock;
        }
 
-       if (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH) &&
-           !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
-           kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) {
+       if (pv_tlb_flush_supported()) {
                pv_ops.mmu.flush_tlb_others = kvm_flush_tlb_others;
                pv_ops.mmu.tlb_remove_table = tlb_remove_table;
+               pr_info("KVM setup pv remote TLB flush\n");
        }
 
        if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))
@@ -632,9 +652,7 @@ static void __init kvm_guest_init(void)
 #ifdef CONFIG_SMP
        smp_ops.smp_prepare_cpus = kvm_smp_prepare_cpus;
        smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu;
-       if (kvm_para_has_feature(KVM_FEATURE_PV_SCHED_YIELD) &&
-           !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
-           kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) {
+       if (pv_sched_yield_supported()) {
                smp_ops.send_call_func_ipi = kvm_smp_send_call_func_ipi;
                pr_info("KVM setup pv sched yield\n");
        }
@@ -700,7 +718,7 @@ static uint32_t __init kvm_detect(void)
 static void __init kvm_apic_init(void)
 {
 #if defined(CONFIG_SMP)
-       if (kvm_para_has_feature(KVM_FEATURE_PV_SEND_IPI))
+       if (pv_ipi_supported())
                kvm_setup_pv_ipi();
 #endif
 }
@@ -732,26 +750,31 @@ static __init int activate_jump_labels(void)
 }
 arch_initcall(activate_jump_labels);
 
-static __init int kvm_setup_pv_tlb_flush(void)
+static __init int kvm_alloc_cpumask(void)
 {
        int cpu;
+       bool alloc = false;
 
        if (!kvm_para_available() || nopv)
                return 0;
 
-       if (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH) &&
-           !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
-           kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) {
+       if (pv_tlb_flush_supported())
+               alloc = true;
+
+#if defined(CONFIG_SMP)
+       if (pv_ipi_supported())
+               alloc = true;
+#endif
+
+       if (alloc)
                for_each_possible_cpu(cpu) {
-                       zalloc_cpumask_var_node(per_cpu_ptr(&__pv_tlb_mask, cpu),
+                       zalloc_cpumask_var_node(per_cpu_ptr(&__pv_cpu_mask, cpu),
                                GFP_KERNEL, cpu_to_node(cpu));
                }
-               pr_info("KVM setup pv remote TLB flush\n");
-       }
 
        return 0;
 }
-arch_initcall(kvm_setup_pv_tlb_flush);
+arch_initcall(kvm_alloc_cpumask);
 
 #ifdef CONFIG_PARAVIRT_SPINLOCKS
 
index 789f5e4..c131ba4 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/timer.h>
 #include <asm/special_insns.h>
 #include <asm/tlb.h>
+#include <asm/io_bitmap.h>
 
 /*
  * nop stub, which must not clobber anything *including the stack* to
@@ -341,6 +342,10 @@ struct paravirt_patch_template pv_ops = {
        .cpu.iret               = native_iret,
        .cpu.swapgs             = native_swapgs,
 
+#ifdef CONFIG_X86_IOPL_IOPERM
+       .cpu.update_io_bitmap   = native_tss_update_io_bitmap,
+#endif
+
        .cpu.start_context_switch       = paravirt_nop,
        .cpu.end_context_switch         = paravirt_nop,
 
index 839b524..3053c85 100644 (file)
@@ -374,7 +374,7 @@ static void tss_copy_io_bitmap(struct tss_struct *tss, struct io_bitmap *iobm)
 /**
  * tss_update_io_bitmap - Update I/O bitmap before exiting to usermode
  */
-void tss_update_io_bitmap(void)
+void native_tss_update_io_bitmap(void)
 {
        struct tss_struct *tss = this_cpu_ptr(&cpu_tss_rw);
        struct thread_struct *t = &current->thread;
index 991019d..1bb4927 100644 (file)
@@ -59,6 +59,19 @@ config KVM
 
          If unsure, say N.
 
+config KVM_WERROR
+       bool "Compile KVM with -Werror"
+       # KASAN may cause the build to fail due to larger frames
+       default y if X86_64 && !KASAN
+       # We use the dependency on !COMPILE_TEST to not be enabled
+       # blindly in allmodconfig or allyesconfig configurations
+       depends on (X86_64 && !KASAN) || !COMPILE_TEST
+       depends on EXPERT
+       help
+         Add -Werror to the build flags for (and only for) i915.ko.
+
+         If in doubt, say "N".
+
 config KVM_INTEL
        tristate "KVM for Intel (and compatible) processors support"
        depends on KVM && IA32_FEAT_CTL
index b19ef42..e553f0f 100644 (file)
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 ccflags-y += -Iarch/x86/kvm
+ccflags-$(CONFIG_KVM_WERROR) += -Werror
 
 KVM := ../../../virt/kvm
 
index ddbc619..dd19fb3 100644 (file)
 #define NR_FASTOP (ilog2(sizeof(ulong)) + 1)
 #define FASTOP_SIZE 8
 
-/*
- * fastop functions have a special calling convention:
- *
- * dst:    rax        (in/out)
- * src:    rdx        (in/out)
- * src2:   rcx        (in)
- * flags:  rflags     (in/out)
- * ex:     rsi        (in:fastop pointer, out:zero if exception)
- *
- * Moreover, they are all exactly FASTOP_SIZE bytes long, so functions for
- * different operand sizes can be reached by calculation, rather than a jump
- * table (which would be bigger than the code).
- *
- * fastop functions are declared as taking a never-defined fastop parameter,
- * so they can't be called from C directly.
- */
-
-struct fastop;
-
 struct opcode {
        u64 flags : 56;
        u64 intercept : 8;
@@ -311,8 +292,19 @@ static void invalidate_registers(struct x86_emulate_ctxt *ctxt)
 #define ON64(x)
 #endif
 
-typedef void (*fastop_t)(struct fastop *);
-
+/*
+ * fastop functions have a special calling convention:
+ *
+ * dst:    rax        (in/out)
+ * src:    rdx        (in/out)
+ * src2:   rcx        (in)
+ * flags:  rflags     (in/out)
+ * ex:     rsi        (in:fastop pointer, out:zero if exception)
+ *
+ * Moreover, they are all exactly FASTOP_SIZE bytes long, so functions for
+ * different operand sizes can be reached by calculation, rather than a jump
+ * table (which would be bigger than the code).
+ */
 static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop);
 
 #define __FOP_FUNC(name) \
@@ -5683,7 +5675,7 @@ special_insn:
 
        if (ctxt->execute) {
                if (ctxt->d & Fastop)
-                       rc = fastop(ctxt, (fastop_t)ctxt->execute);
+                       rc = fastop(ctxt, ctxt->fop);
                else
                        rc = ctxt->execute(ctxt);
                if (rc != X86EMUL_CONTINUE)
index 79afa0b..c47d2ac 100644 (file)
@@ -417,7 +417,7 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
 
                        kvm_set_msi_irq(vcpu->kvm, entry, &irq);
 
-                       if (irq.level &&
+                       if (irq.trig_mode &&
                            kvm_apic_match_dest(vcpu, NULL, APIC_DEST_NOSHORT,
                                                irq.dest_id, irq.dest_mode))
                                __set_bit(irq.vector, ioapic_handled_vectors);
index afcd30d..e3099c6 100644 (file)
@@ -627,9 +627,11 @@ static inline bool pv_eoi_enabled(struct kvm_vcpu *vcpu)
 static bool pv_eoi_get_pending(struct kvm_vcpu *vcpu)
 {
        u8 val;
-       if (pv_eoi_get_user(vcpu, &val) < 0)
+       if (pv_eoi_get_user(vcpu, &val) < 0) {
                printk(KERN_WARNING "Can't read EOI MSR value: 0x%llx\n",
                           (unsigned long long)vcpu->arch.pv_eoi.msr_val);
+               return false;
+       }
        return val & 0x1;
 }
 
@@ -1046,11 +1048,8 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                                                       apic->regs + APIC_TMR);
                }
 
-               if (vcpu->arch.apicv_active)
-                       kvm_x86_ops->deliver_posted_interrupt(vcpu, vector);
-               else {
+               if (kvm_x86_ops->deliver_posted_interrupt(vcpu, vector)) {
                        kvm_lapic_set_irr(vector, apic);
-
                        kvm_make_request(KVM_REQ_EVENT, vcpu);
                        kvm_vcpu_kick(vcpu);
                }
index 3c6522b..ffcd96f 100644 (file)
@@ -339,7 +339,7 @@ TRACE_EVENT(
                /* These depend on page entry type, so compute them now.  */
                __field(bool, r)
                __field(bool, x)
-               __field(u8, u)
+               __field(signed char, u)
        ),
 
        TP_fast_assign(
index bef0ba3..24c0b2b 100644 (file)
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
+#ifdef MODULE
 static const struct x86_cpu_id svm_cpu_id[] = {
        X86_FEATURE_MATCH(X86_FEATURE_SVM),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id);
+#endif
 
 #define IOPM_ALLOC_ORDER 2
 #define MSRPM_ALLOC_ORDER 1
@@ -1005,33 +1007,32 @@ static void svm_cpu_uninit(int cpu)
 static int svm_cpu_init(int cpu)
 {
        struct svm_cpu_data *sd;
-       int r;
 
        sd = kzalloc(sizeof(struct svm_cpu_data), GFP_KERNEL);
        if (!sd)
                return -ENOMEM;
        sd->cpu = cpu;
-       r = -ENOMEM;
        sd->save_area = alloc_page(GFP_KERNEL);
        if (!sd->save_area)
-               goto err_1;
+               goto free_cpu_data;
 
        if (svm_sev_enabled()) {
-               r = -ENOMEM;
                sd->sev_vmcbs = kmalloc_array(max_sev_asid + 1,
                                              sizeof(void *),
                                              GFP_KERNEL);
                if (!sd->sev_vmcbs)
-                       goto err_1;
+                       goto free_save_area;
        }
 
        per_cpu(svm_data, cpu) = sd;
 
        return 0;
 
-err_1:
+free_save_area:
+       __free_page(sd->save_area);
+free_cpu_data:
        kfree(sd);
-       return r;
+       return -ENOMEM;
 
 }
 
@@ -1350,6 +1351,24 @@ static __init void svm_adjust_mmio_mask(void)
        kvm_mmu_set_mmio_spte_mask(mask, mask, PT_WRITABLE_MASK | PT_USER_MASK);
 }
 
+static void svm_hardware_teardown(void)
+{
+       int cpu;
+
+       if (svm_sev_enabled()) {
+               bitmap_free(sev_asid_bitmap);
+               bitmap_free(sev_reclaim_asid_bitmap);
+
+               sev_flush_asids();
+       }
+
+       for_each_possible_cpu(cpu)
+               svm_cpu_uninit(cpu);
+
+       __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER);
+       iopm_base = 0;
+}
+
 static __init int svm_hardware_setup(void)
 {
        int cpu;
@@ -1463,29 +1482,10 @@ static __init int svm_hardware_setup(void)
        return 0;
 
 err:
-       __free_pages(iopm_pages, IOPM_ALLOC_ORDER);
-       iopm_base = 0;
+       svm_hardware_teardown();
        return r;
 }
 
-static __exit void svm_hardware_unsetup(void)
-{
-       int cpu;
-
-       if (svm_sev_enabled()) {
-               bitmap_free(sev_asid_bitmap);
-               bitmap_free(sev_reclaim_asid_bitmap);
-
-               sev_flush_asids();
-       }
-
-       for_each_possible_cpu(cpu)
-               svm_cpu_uninit(cpu);
-
-       __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER);
-       iopm_base = 0;
-}
-
 static void init_seg(struct vmcb_seg *seg)
 {
        seg->selector = 0;
@@ -2196,8 +2196,9 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 static int avic_init_vcpu(struct vcpu_svm *svm)
 {
        int ret;
+       struct kvm_vcpu *vcpu = &svm->vcpu;
 
-       if (!kvm_vcpu_apicv_active(&svm->vcpu))
+       if (!avic || !irqchip_in_kernel(vcpu->kvm))
                return 0;
 
        ret = avic_init_backing_page(&svm->vcpu);
@@ -5232,6 +5233,9 @@ static void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
        struct vmcb *vmcb = svm->vmcb;
        bool activated = kvm_vcpu_apicv_active(vcpu);
 
+       if (!avic)
+               return;
+
        if (activated) {
                /**
                 * During AVIC temporary deactivation, guest could update
@@ -5255,8 +5259,11 @@ static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
        return;
 }
 
-static void svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec)
+static int svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec)
 {
+       if (!vcpu->arch.apicv_active)
+               return -1;
+
        kvm_lapic_set_irr(vec, vcpu->arch.apic);
        smp_mb__after_atomic();
 
@@ -5268,6 +5275,8 @@ static void svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec)
                put_cpu();
        } else
                kvm_vcpu_wake_up(vcpu);
+
+       return 0;
 }
 
 static bool svm_dy_apicv_has_pending_interrupt(struct kvm_vcpu *vcpu)
@@ -7378,7 +7387,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
        .cpu_has_kvm_support = has_svm,
        .disabled_by_bios = is_disabled,
        .hardware_setup = svm_hardware_setup,
-       .hardware_unsetup = svm_hardware_unsetup,
+       .hardware_unsetup = svm_hardware_teardown,
        .check_processor_compatibility = svm_check_processor_compat,
        .hardware_enable = svm_hardware_enable,
        .hardware_disable = svm_hardware_disable,
@@ -7433,6 +7442,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
        .run = svm_vcpu_run,
        .handle_exit = handle_exit,
        .skip_emulated_instruction = skip_emulated_instruction,
+       .update_emulated_instruction = NULL,
        .set_interrupt_shadow = svm_set_interrupt_shadow,
        .get_interrupt_shadow = svm_get_interrupt_shadow,
        .patch_hypercall = svm_patch_hypercall,
index 283bdb7..f486e26 100644 (file)
@@ -12,6 +12,7 @@ extern bool __read_mostly enable_ept;
 extern bool __read_mostly enable_unrestricted_guest;
 extern bool __read_mostly enable_ept_ad_bits;
 extern bool __read_mostly enable_pml;
+extern bool __read_mostly enable_apicv;
 extern int __read_mostly pt_mode;
 
 #define PT_MODE_SYSTEM         0
index 3589cd3..e920d78 100644 (file)
@@ -3161,10 +3161,10 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
  * or KVM_SET_NESTED_STATE).  Otherwise it's called from vmlaunch/vmresume.
  *
  * Returns:
- *     NVMX_ENTRY_SUCCESS: Entered VMX non-root mode
- *     NVMX_ENTRY_VMFAIL:  Consistency check VMFail
- *     NVMX_ENTRY_VMEXIT:  Consistency check VMExit
- *     NVMX_ENTRY_KVM_INTERNAL_ERROR: KVM internal error
+ *     NVMX_VMENTRY_SUCCESS: Entered VMX non-root mode
+ *     NVMX_VMENTRY_VMFAIL:  Consistency check VMFail
+ *     NVMX_VMENTRY_VMEXIT:  Consistency check VMExit
+ *     NVMX_VMENTRY_KVM_INTERNAL_ERROR: KVM internal error
  */
 enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
                                                        bool from_vmentry)
@@ -3609,8 +3609,15 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr)
        unsigned long exit_qual;
        bool block_nested_events =
            vmx->nested.nested_run_pending || kvm_event_needs_reinjection(vcpu);
+       bool mtf_pending = vmx->nested.mtf_pending;
        struct kvm_lapic *apic = vcpu->arch.apic;
 
+       /*
+        * Clear the MTF state. If a higher priority VM-exit is delivered first,
+        * this state is discarded.
+        */
+       vmx->nested.mtf_pending = false;
+
        if (lapic_in_kernel(vcpu) &&
                test_bit(KVM_APIC_INIT, &apic->pending_events)) {
                if (block_nested_events)
@@ -3621,8 +3628,28 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr)
                return 0;
        }
 
+       /*
+        * Process any exceptions that are not debug traps before MTF.
+        */
+       if (vcpu->arch.exception.pending &&
+           !vmx_pending_dbg_trap(vcpu) &&
+           nested_vmx_check_exception(vcpu, &exit_qual)) {
+               if (block_nested_events)
+                       return -EBUSY;
+               nested_vmx_inject_exception_vmexit(vcpu, exit_qual);
+               return 0;
+       }
+
+       if (mtf_pending) {
+               if (block_nested_events)
+                       return -EBUSY;
+               nested_vmx_update_pending_dbg(vcpu);
+               nested_vmx_vmexit(vcpu, EXIT_REASON_MONITOR_TRAP_FLAG, 0, 0);
+               return 0;
+       }
+
        if (vcpu->arch.exception.pending &&
-               nested_vmx_check_exception(vcpu, &exit_qual)) {
+           nested_vmx_check_exception(vcpu, &exit_qual)) {
                if (block_nested_events)
                        return -EBUSY;
                nested_vmx_inject_exception_vmexit(vcpu, exit_qual);
@@ -5285,24 +5312,17 @@ fail:
        return 1;
 }
 
-
-static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
-                                      struct vmcs12 *vmcs12)
+/*
+ * Return true if an IO instruction with the specified port and size should cause
+ * a VM-exit into L1.
+ */
+bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port,
+                                int size)
 {
-       unsigned long exit_qualification;
+       struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
        gpa_t bitmap, last_bitmap;
-       unsigned int port;
-       int size;
        u8 b;
 
-       if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
-               return nested_cpu_has(vmcs12, CPU_BASED_UNCOND_IO_EXITING);
-
-       exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
-
-       port = exit_qualification >> 16;
-       size = (exit_qualification & 7) + 1;
-
        last_bitmap = (gpa_t)-1;
        b = -1;
 
@@ -5329,8 +5349,26 @@ static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
        return false;
 }
 
+static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
+                                      struct vmcs12 *vmcs12)
+{
+       unsigned long exit_qualification;
+       unsigned short port;
+       int size;
+
+       if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
+               return nested_cpu_has(vmcs12, CPU_BASED_UNCOND_IO_EXITING);
+
+       exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
+
+       port = exit_qualification >> 16;
+       size = (exit_qualification & 7) + 1;
+
+       return nested_vmx_check_io_bitmaps(vcpu, port, size);
+}
+
 /*
- * Return 1 if we should exit from L2 to L1 to handle an MSR access access,
+ * Return 1 if we should exit from L2 to L1 to handle an MSR access,
  * rather than handle it ourselves in L0. I.e., check whether L1 expressed
  * disinterest in the current event (read or write a specific MSR) by using an
  * MSR bitmap. This may be the case even when L0 doesn't use MSR bitmaps.
@@ -5712,6 +5750,9 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
 
                        if (vmx->nested.nested_run_pending)
                                kvm_state.flags |= KVM_STATE_NESTED_RUN_PENDING;
+
+                       if (vmx->nested.mtf_pending)
+                               kvm_state.flags |= KVM_STATE_NESTED_MTF_PENDING;
                }
        }
 
@@ -5892,6 +5933,9 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
        vmx->nested.nested_run_pending =
                !!(kvm_state->flags & KVM_STATE_NESTED_RUN_PENDING);
 
+       vmx->nested.mtf_pending =
+               !!(kvm_state->flags & KVM_STATE_NESTED_MTF_PENDING);
+
        ret = -EINVAL;
        if (nested_cpu_has_shadow_vmcs(vmcs12) &&
            vmcs12->vmcs_link_pointer != -1ull) {
@@ -5949,8 +5993,7 @@ void nested_vmx_set_vmcs_shadowing_bitmap(void)
  * bit in the high half is on if the corresponding bit in the control field
  * may be on. See also vmx_control_verify().
  */
-void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps,
-                               bool apicv)
+void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps)
 {
        /*
         * Note that as a general rule, the high half of the MSRs (bits in
@@ -5977,7 +6020,7 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps,
                PIN_BASED_EXT_INTR_MASK |
                PIN_BASED_NMI_EXITING |
                PIN_BASED_VIRTUAL_NMIS |
-               (apicv ? PIN_BASED_POSTED_INTR : 0);
+               (enable_apicv ? PIN_BASED_POSTED_INTR : 0);
        msrs->pinbased_ctls_high |=
                PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR |
                PIN_BASED_VMX_PREEMPTION_TIMER;
index fc874d4..9aeda46 100644 (file)
@@ -17,8 +17,7 @@ enum nvmx_vmentry_status {
 };
 
 void vmx_leave_nested(struct kvm_vcpu *vcpu);
-void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps,
-                               bool apicv);
+void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps);
 void nested_vmx_hardware_unsetup(void);
 __init int nested_vmx_hardware_setup(int (*exit_handlers[])(struct kvm_vcpu *));
 void nested_vmx_set_vmcs_shadowing_bitmap(void);
@@ -34,6 +33,8 @@ int vmx_get_vmx_msr(struct nested_vmx_msrs *msrs, u32 msr_index, u64 *pdata);
 int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
                        u32 vmx_instruction_info, bool wr, int len, gva_t *ret);
 void nested_vmx_pmu_entry_exit_ctls_update(struct kvm_vcpu *vcpu);
+bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port,
+                                int size);
 
 static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
 {
@@ -175,6 +176,11 @@ static inline bool nested_cpu_has_virtual_nmis(struct vmcs12 *vmcs12)
        return vmcs12->pin_based_vm_exec_control & PIN_BASED_VIRTUAL_NMIS;
 }
 
+static inline int nested_cpu_has_mtf(struct vmcs12 *vmcs12)
+{
+       return nested_cpu_has(vmcs12, CPU_BASED_MONITOR_TRAP_FLAG);
+}
+
 static inline int nested_cpu_has_ept(struct vmcs12 *vmcs12)
 {
        return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_EPT);
index 3be25ec..40b1e61 100644 (file)
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
+#ifdef MODULE
 static const struct x86_cpu_id vmx_cpu_id[] = {
        X86_FEATURE_MATCH(X86_FEATURE_VMX),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, vmx_cpu_id);
+#endif
 
 bool __read_mostly enable_vpid = 1;
 module_param_named(vpid, enable_vpid, bool, 0444);
@@ -95,7 +97,7 @@ module_param(emulate_invalid_guest_state, bool, S_IRUGO);
 static bool __read_mostly fasteoi = 1;
 module_param(fasteoi, bool, S_IRUGO);
 
-static bool __read_mostly enable_apicv = 1;
+bool __read_mostly enable_apicv = 1;
 module_param(enable_apicv, bool, S_IRUGO);
 
 /*
@@ -1175,6 +1177,10 @@ void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
                                           vmx->guest_msrs[i].mask);
 
        }
+
+       if (vmx->nested.need_vmcs12_to_shadow_sync)
+               nested_sync_vmcs12_to_shadow(vcpu);
+
        if (vmx->guest_state_loaded)
                return;
 
@@ -1599,6 +1605,40 @@ static int skip_emulated_instruction(struct kvm_vcpu *vcpu)
        return 1;
 }
 
+
+/*
+ * Recognizes a pending MTF VM-exit and records the nested state for later
+ * delivery.
+ */
+static void vmx_update_emulated_instruction(struct kvm_vcpu *vcpu)
+{
+       struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       if (!is_guest_mode(vcpu))
+               return;
+
+       /*
+        * Per the SDM, MTF takes priority over debug-trap exceptions besides
+        * T-bit traps. As instruction emulation is completed (i.e. at the
+        * instruction boundary), any #DB exception pending delivery must be a
+        * debug-trap. Record the pending MTF state to be delivered in
+        * vmx_check_nested_events().
+        */
+       if (nested_cpu_has_mtf(vmcs12) &&
+           (!vcpu->arch.exception.pending ||
+            vcpu->arch.exception.nr == DB_VECTOR))
+               vmx->nested.mtf_pending = true;
+       else
+               vmx->nested.mtf_pending = false;
+}
+
+static int vmx_skip_emulated_instruction(struct kvm_vcpu *vcpu)
+{
+       vmx_update_emulated_instruction(vcpu);
+       return skip_emulated_instruction(vcpu);
+}
+
 static void vmx_clear_hlt(struct kvm_vcpu *vcpu)
 {
        /*
@@ -3818,24 +3858,29 @@ static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
  * 2. If target vcpu isn't running(root mode), kick it to pick up the
  * interrupt from PIR in next vmentry.
  */
-static void vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
+static int vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        int r;
 
        r = vmx_deliver_nested_posted_interrupt(vcpu, vector);
        if (!r)
-               return;
+               return 0;
+
+       if (!vcpu->arch.apicv_active)
+               return -1;
 
        if (pi_test_and_set_pir(vector, &vmx->pi_desc))
-               return;
+               return 0;
 
        /* If a previous notification has sent the IPI, nothing to do.  */
        if (pi_test_and_set_on(&vmx->pi_desc))
-               return;
+               return 0;
 
        if (!kvm_vcpu_trigger_posted_interrupt(vcpu, false))
                kvm_vcpu_kick(vcpu);
+
+       return 0;
 }
 
 /*
@@ -6482,8 +6527,11 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
                vmcs_write32(PLE_WINDOW, vmx->ple_window);
        }
 
-       if (vmx->nested.need_vmcs12_to_shadow_sync)
-               nested_sync_vmcs12_to_shadow(vcpu);
+       /*
+        * We did this in prepare_switch_to_guest, because it needs to
+        * be within srcu_read_lock.
+        */
+       WARN_ON_ONCE(vmx->nested.need_vmcs12_to_shadow_sync);
 
        if (kvm_register_is_dirty(vcpu, VCPU_REGS_RSP))
                vmcs_writel(GUEST_RSP, vcpu->arch.regs[VCPU_REGS_RSP]);
@@ -6757,8 +6805,7 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
 
        if (nested)
                nested_vmx_setup_ctls_msrs(&vmx->nested.msrs,
-                                          vmx_capability.ept,
-                                          kvm_vcpu_apicv_active(vcpu));
+                                          vmx_capability.ept);
        else
                memset(&vmx->nested.msrs, 0, sizeof(vmx->nested.msrs));
 
@@ -6839,8 +6886,7 @@ static int __init vmx_check_processor_compat(void)
        if (setup_vmcs_config(&vmcs_conf, &vmx_cap) < 0)
                return -EIO;
        if (nested)
-               nested_vmx_setup_ctls_msrs(&vmcs_conf.nested, vmx_cap.ept,
-                                          enable_apicv);
+               nested_vmx_setup_ctls_msrs(&vmcs_conf.nested, vmx_cap.ept);
        if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) {
                printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n",
                                smp_processor_id());
@@ -7101,6 +7147,40 @@ static void vmx_request_immediate_exit(struct kvm_vcpu *vcpu)
        to_vmx(vcpu)->req_immediate_exit = true;
 }
 
+static int vmx_check_intercept_io(struct kvm_vcpu *vcpu,
+                                 struct x86_instruction_info *info)
+{
+       struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+       unsigned short port;
+       bool intercept;
+       int size;
+
+       if (info->intercept == x86_intercept_in ||
+           info->intercept == x86_intercept_ins) {
+               port = info->src_val;
+               size = info->dst_bytes;
+       } else {
+               port = info->dst_val;
+               size = info->src_bytes;
+       }
+
+       /*
+        * If the 'use IO bitmaps' VM-execution control is 0, IO instruction
+        * VM-exits depend on the 'unconditional IO exiting' VM-execution
+        * control.
+        *
+        * Otherwise, IO instruction VM-exits are controlled by the IO bitmaps.
+        */
+       if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
+               intercept = nested_cpu_has(vmcs12,
+                                          CPU_BASED_UNCOND_IO_EXITING);
+       else
+               intercept = nested_vmx_check_io_bitmaps(vcpu, port, size);
+
+       /* FIXME: produce nested vmexit and return X86EMUL_INTERCEPTED.  */
+       return intercept ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE;
+}
+
 static int vmx_check_intercept(struct kvm_vcpu *vcpu,
                               struct x86_instruction_info *info,
                               enum x86_intercept_stage stage)
@@ -7108,19 +7188,45 @@ static int vmx_check_intercept(struct kvm_vcpu *vcpu,
        struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
        struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
 
+       switch (info->intercept) {
        /*
         * RDPID causes #UD if disabled through secondary execution controls.
         * Because it is marked as EmulateOnUD, we need to intercept it here.
         */
-       if (info->intercept == x86_intercept_rdtscp &&
-           !nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDTSCP)) {
-               ctxt->exception.vector = UD_VECTOR;
-               ctxt->exception.error_code_valid = false;
-               return X86EMUL_PROPAGATE_FAULT;
-       }
+       case x86_intercept_rdtscp:
+               if (!nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDTSCP)) {
+                       ctxt->exception.vector = UD_VECTOR;
+                       ctxt->exception.error_code_valid = false;
+                       return X86EMUL_PROPAGATE_FAULT;
+               }
+               break;
+
+       case x86_intercept_in:
+       case x86_intercept_ins:
+       case x86_intercept_out:
+       case x86_intercept_outs:
+               return vmx_check_intercept_io(vcpu, info);
+
+       case x86_intercept_lgdt:
+       case x86_intercept_lidt:
+       case x86_intercept_lldt:
+       case x86_intercept_ltr:
+       case x86_intercept_sgdt:
+       case x86_intercept_sidt:
+       case x86_intercept_sldt:
+       case x86_intercept_str:
+               if (!nested_cpu_has2(vmcs12, SECONDARY_EXEC_DESC))
+                       return X86EMUL_CONTINUE;
+
+               /* FIXME: produce nested vmexit and return X86EMUL_INTERCEPTED.  */
+               break;
 
        /* TODO: check more intercepts... */
-       return X86EMUL_CONTINUE;
+       default:
+               break;
+       }
+
+       return X86EMUL_UNHANDLEABLE;
 }
 
 #ifdef CONFIG_X86_64
@@ -7702,7 +7808,7 @@ static __init int hardware_setup(void)
 
        if (nested) {
                nested_vmx_setup_ctls_msrs(&vmcs_config.nested,
-                                          vmx_capability.ept, enable_apicv);
+                                          vmx_capability.ept);
 
                r = nested_vmx_hardware_setup(kvm_vmx_exit_handlers);
                if (r)
@@ -7786,7 +7892,8 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
 
        .run = vmx_vcpu_run,
        .handle_exit = vmx_handle_exit,
-       .skip_emulated_instruction = skip_emulated_instruction,
+       .skip_emulated_instruction = vmx_skip_emulated_instruction,
+       .update_emulated_instruction = vmx_update_emulated_instruction,
        .set_interrupt_shadow = vmx_set_interrupt_shadow,
        .get_interrupt_shadow = vmx_get_interrupt_shadow,
        .patch_hypercall = vmx_patch_hypercall,
index 7f42cf3..e64da06 100644 (file)
@@ -150,6 +150,9 @@ struct nested_vmx {
        /* L2 must run next, and mustn't decide to exit to L1. */
        bool nested_run_pending;
 
+       /* Pending MTF VM-exit into L1.  */
+       bool mtf_pending;
+
        struct loaded_vmcs vmcs02;
 
        /*
index fb5d64e..5de2006 100644 (file)
@@ -6891,6 +6891,8 @@ restart:
                        kvm_rip_write(vcpu, ctxt->eip);
                        if (r && ctxt->tf)
                                r = kvm_vcpu_do_singlestep(vcpu);
+                       if (kvm_x86_ops->update_emulated_instruction)
+                               kvm_x86_ops->update_emulated_instruction(vcpu);
                        __kvm_set_rflags(vcpu, ctxt->eflags);
                }
 
@@ -7188,15 +7190,15 @@ static void kvm_timer_init(void)
 
        if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
 #ifdef CONFIG_CPU_FREQ
-               struct cpufreq_policy policy;
+               struct cpufreq_policy *policy;
                int cpu;
 
-               memset(&policy, 0, sizeof(policy));
                cpu = get_cpu();
-               cpufreq_get_policy(&policy, cpu);
-               if (policy.cpuinfo.max_freq)
-                       max_tsc_khz = policy.cpuinfo.max_freq;
+               policy = cpufreq_cpu_get(cpu);
+               if (policy && policy->cpuinfo.max_freq)
+                       max_tsc_khz = policy->cpuinfo.max_freq;
                put_cpu();
+               cpufreq_cpu_put(policy);
 #endif
                cpufreq_register_notifier(&kvmclock_cpufreq_notifier_block,
                                          CPUFREQ_TRANSITION_NOTIFIER);
@@ -7306,12 +7308,12 @@ int kvm_arch_init(void *opaque)
        }
 
        if (!ops->cpu_has_kvm_support()) {
-               printk(KERN_ERR "kvm: no hardware support\n");
+               pr_err_ratelimited("kvm: no hardware support\n");
                r = -EOPNOTSUPP;
                goto out;
        }
        if (ops->disabled_by_bios()) {
-               printk(KERN_ERR "kvm: disabled by bios\n");
+               pr_err_ratelimited("kvm: disabled by bios\n");
                r = -EOPNOTSUPP;
                goto out;
        }
index 64229da..69309cd 100644 (file)
@@ -363,13 +363,8 @@ static void ptdump_walk_pgd_level_core(struct seq_file *m,
 {
        const struct ptdump_range ptdump_ranges[] = {
 #ifdef CONFIG_X86_64
-
-#define normalize_addr_shift (64 - (__VIRTUAL_MASK_SHIFT + 1))
-#define normalize_addr(u) ((signed long)((u) << normalize_addr_shift) >> \
-                          normalize_addr_shift)
-
        {0, PTRS_PER_PGD * PGD_LEVEL_MULT / 2},
-       {normalize_addr(PTRS_PER_PGD * PGD_LEVEL_MULT / 2), ~0UL},
+       {GUARD_HOLE_END_ADDR, ~0UL},
 #else
        {0, ~0UL},
 #endif
index fa8506e..d19a2ed 100644 (file)
@@ -180,7 +180,7 @@ void efi_sync_low_kernel_mappings(void)
 static inline phys_addr_t
 virt_to_phys_or_null_size(void *va, unsigned long size)
 {
-       bool bad_size;
+       phys_addr_t pa;
 
        if (!va)
                return 0;
@@ -188,16 +188,13 @@ virt_to_phys_or_null_size(void *va, unsigned long size)
        if (virt_addr_valid(va))
                return virt_to_phys(va);
 
-       /*
-        * A fully aligned variable on the stack is guaranteed not to
-        * cross a page bounary. Try to catch strings on the stack by
-        * checking that 'size' is a power of two.
-        */
-       bad_size = size > PAGE_SIZE || !is_power_of_2(size);
+       pa = slow_virt_to_phys(va);
 
-       WARN_ON(!IS_ALIGNED((unsigned long)va, size) || bad_size);
+       /* check if the object crosses a page boundary */
+       if (WARN_ON((pa ^ (pa + size - 1)) & PAGE_MASK))
+               return 0;
 
-       return slow_virt_to_phys(va);
+       return pa;
 }
 
 #define virt_to_phys_or_null(addr)                             \
@@ -568,85 +565,25 @@ efi_thunk_set_virtual_address_map(unsigned long memory_map_size,
 
 static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc)
 {
-       efi_status_t status;
-       u32 phys_tm, phys_tc;
-       unsigned long flags;
-
-       spin_lock(&rtc_lock);
-       spin_lock_irqsave(&efi_runtime_lock, flags);
-
-       phys_tm = virt_to_phys_or_null(tm);
-       phys_tc = virt_to_phys_or_null(tc);
-
-       status = efi_thunk(get_time, phys_tm, phys_tc);
-
-       spin_unlock_irqrestore(&efi_runtime_lock, flags);
-       spin_unlock(&rtc_lock);
-
-       return status;
+       return EFI_UNSUPPORTED;
 }
 
 static efi_status_t efi_thunk_set_time(efi_time_t *tm)
 {
-       efi_status_t status;
-       u32 phys_tm;
-       unsigned long flags;
-
-       spin_lock(&rtc_lock);
-       spin_lock_irqsave(&efi_runtime_lock, flags);
-
-       phys_tm = virt_to_phys_or_null(tm);
-
-       status = efi_thunk(set_time, phys_tm);
-
-       spin_unlock_irqrestore(&efi_runtime_lock, flags);
-       spin_unlock(&rtc_lock);
-
-       return status;
+       return EFI_UNSUPPORTED;
 }
 
 static efi_status_t
 efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,
                          efi_time_t *tm)
 {
-       efi_status_t status;
-       u32 phys_enabled, phys_pending, phys_tm;
-       unsigned long flags;
-
-       spin_lock(&rtc_lock);
-       spin_lock_irqsave(&efi_runtime_lock, flags);
-
-       phys_enabled = virt_to_phys_or_null(enabled);
-       phys_pending = virt_to_phys_or_null(pending);
-       phys_tm = virt_to_phys_or_null(tm);
-
-       status = efi_thunk(get_wakeup_time, phys_enabled,
-                            phys_pending, phys_tm);
-
-       spin_unlock_irqrestore(&efi_runtime_lock, flags);
-       spin_unlock(&rtc_lock);
-
-       return status;
+       return EFI_UNSUPPORTED;
 }
 
 static efi_status_t
 efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
 {
-       efi_status_t status;
-       u32 phys_tm;
-       unsigned long flags;
-
-       spin_lock(&rtc_lock);
-       spin_lock_irqsave(&efi_runtime_lock, flags);
-
-       phys_tm = virt_to_phys_or_null(tm);
-
-       status = efi_thunk(set_wakeup_time, enabled, phys_tm);
-
-       spin_unlock_irqrestore(&efi_runtime_lock, flags);
-       spin_unlock(&rtc_lock);
-
-       return status;
+       return EFI_UNSUPPORTED;
 }
 
 static unsigned long efi_name_size(efi_char16_t *name)
@@ -658,6 +595,8 @@ static efi_status_t
 efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
                       u32 *attr, unsigned long *data_size, void *data)
 {
+       u8 buf[24] __aligned(8);
+       efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
        efi_status_t status;
        u32 phys_name, phys_vendor, phys_attr;
        u32 phys_data_size, phys_data;
@@ -665,14 +604,19 @@ efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
 
        spin_lock_irqsave(&efi_runtime_lock, flags);
 
+       *vnd = *vendor;
+
        phys_data_size = virt_to_phys_or_null(data_size);
-       phys_vendor = virt_to_phys_or_null(vendor);
+       phys_vendor = virt_to_phys_or_null(vnd);
        phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
        phys_attr = virt_to_phys_or_null(attr);
        phys_data = virt_to_phys_or_null_size(data, *data_size);
 
-       status = efi_thunk(get_variable, phys_name, phys_vendor,
-                          phys_attr, phys_data_size, phys_data);
+       if (!phys_name || (data && !phys_data))
+               status = EFI_INVALID_PARAMETER;
+       else
+               status = efi_thunk(get_variable, phys_name, phys_vendor,
+                                  phys_attr, phys_data_size, phys_data);
 
        spin_unlock_irqrestore(&efi_runtime_lock, flags);
 
@@ -683,19 +627,25 @@ static efi_status_t
 efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
                       u32 attr, unsigned long data_size, void *data)
 {
+       u8 buf[24] __aligned(8);
+       efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
        u32 phys_name, phys_vendor, phys_data;
        efi_status_t status;
        unsigned long flags;
 
        spin_lock_irqsave(&efi_runtime_lock, flags);
 
+       *vnd = *vendor;
+
        phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
-       phys_vendor = virt_to_phys_or_null(vendor);
+       phys_vendor = virt_to_phys_or_null(vnd);
        phys_data = virt_to_phys_or_null_size(data, data_size);
 
-       /* If data_size is > sizeof(u32) we've got problems */
-       status = efi_thunk(set_variable, phys_name, phys_vendor,
-                          attr, data_size, phys_data);
+       if (!phys_name || !phys_data)
+               status = EFI_INVALID_PARAMETER;
+       else
+               status = efi_thunk(set_variable, phys_name, phys_vendor,
+                                  attr, data_size, phys_data);
 
        spin_unlock_irqrestore(&efi_runtime_lock, flags);
 
@@ -707,6 +657,8 @@ efi_thunk_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
                                   u32 attr, unsigned long data_size,
                                   void *data)
 {
+       u8 buf[24] __aligned(8);
+       efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
        u32 phys_name, phys_vendor, phys_data;
        efi_status_t status;
        unsigned long flags;
@@ -714,13 +666,17 @@ efi_thunk_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
        if (!spin_trylock_irqsave(&efi_runtime_lock, flags))
                return EFI_NOT_READY;
 
+       *vnd = *vendor;
+
        phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
-       phys_vendor = virt_to_phys_or_null(vendor);
+       phys_vendor = virt_to_phys_or_null(vnd);
        phys_data = virt_to_phys_or_null_size(data, data_size);
 
-       /* If data_size is > sizeof(u32) we've got problems */
-       status = efi_thunk(set_variable, phys_name, phys_vendor,
-                          attr, data_size, phys_data);
+       if (!phys_name || !phys_data)
+               status = EFI_INVALID_PARAMETER;
+       else
+               status = efi_thunk(set_variable, phys_name, phys_vendor,
+                                  attr, data_size, phys_data);
 
        spin_unlock_irqrestore(&efi_runtime_lock, flags);
 
@@ -732,39 +688,36 @@ efi_thunk_get_next_variable(unsigned long *name_size,
                            efi_char16_t *name,
                            efi_guid_t *vendor)
 {
+       u8 buf[24] __aligned(8);
+       efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
        efi_status_t status;
        u32 phys_name_size, phys_name, phys_vendor;
        unsigned long flags;
 
        spin_lock_irqsave(&efi_runtime_lock, flags);
 
+       *vnd = *vendor;
+
        phys_name_size = virt_to_phys_or_null(name_size);
-       phys_vendor = virt_to_phys_or_null(vendor);
+       phys_vendor = virt_to_phys_or_null(vnd);
        phys_name = virt_to_phys_or_null_size(name, *name_size);
 
-       status = efi_thunk(get_next_variable, phys_name_size,
-                          phys_name, phys_vendor);
+       if (!phys_name)
+               status = EFI_INVALID_PARAMETER;
+       else
+               status = efi_thunk(get_next_variable, phys_name_size,
+                                  phys_name, phys_vendor);
 
        spin_unlock_irqrestore(&efi_runtime_lock, flags);
 
+       *vendor = *vnd;
        return status;
 }
 
 static efi_status_t
 efi_thunk_get_next_high_mono_count(u32 *count)
 {
-       efi_status_t status;
-       u32 phys_count;
-       unsigned long flags;
-
-       spin_lock_irqsave(&efi_runtime_lock, flags);
-
-       phys_count = virt_to_phys_or_null(count);
-       status = efi_thunk(get_next_high_mono_count, phys_count);
-
-       spin_unlock_irqrestore(&efi_runtime_lock, flags);
-
-       return status;
+       return EFI_UNSUPPORTED;
 }
 
 static void
index 7940912..507f4fb 100644 (file)
@@ -72,6 +72,9 @@
 #include <asm/mwait.h>
 #include <asm/pci_x86.h>
 #include <asm/cpu.h>
+#ifdef CONFIG_X86_IOPL_IOPERM
+#include <asm/io_bitmap.h>
+#endif
 
 #ifdef CONFIG_ACPI
 #include <linux/acpi.h>
@@ -837,6 +840,25 @@ static void xen_load_sp0(unsigned long sp0)
        this_cpu_write(cpu_tss_rw.x86_tss.sp0, sp0);
 }
 
+#ifdef CONFIG_X86_IOPL_IOPERM
+static void xen_update_io_bitmap(void)
+{
+       struct physdev_set_iobitmap iobitmap;
+       struct tss_struct *tss = this_cpu_ptr(&cpu_tss_rw);
+
+       native_tss_update_io_bitmap();
+
+       iobitmap.bitmap = (uint8_t *)(&tss->x86_tss) +
+                         tss->x86_tss.io_bitmap_base;
+       if (tss->x86_tss.io_bitmap_base == IO_BITMAP_OFFSET_INVALID)
+               iobitmap.nr_ports = 0;
+       else
+               iobitmap.nr_ports = IO_BITMAP_BITS;
+
+       HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &iobitmap);
+}
+#endif
+
 static void xen_io_delay(void)
 {
 }
@@ -1047,6 +1069,9 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
        .write_idt_entry = xen_write_idt_entry,
        .load_sp0 = xen_load_sp0,
 
+#ifdef CONFIG_X86_IOPL_IOPERM
+       .update_io_bitmap = xen_update_io_bitmap,
+#endif
        .io_delay = xen_io_delay,
 
        /* Xen takes care of %gs when switching to usermode for us */
index b5516b0..6e9ec6e 100644 (file)
@@ -55,12 +55,14 @@ static bool acpi_watchdog_uses_rtc(const struct acpi_table_wdat *wdat)
 }
 #endif
 
+static bool acpi_no_watchdog;
+
 static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void)
 {
        const struct acpi_table_wdat *wdat = NULL;
        acpi_status status;
 
-       if (acpi_disabled)
+       if (acpi_disabled || acpi_no_watchdog)
                return NULL;
 
        status = acpi_get_table(ACPI_SIG_WDAT, 0,
@@ -88,6 +90,14 @@ bool acpi_has_watchdog(void)
 }
 EXPORT_SYMBOL_GPL(acpi_has_watchdog);
 
+/* ACPI watchdog can be disabled on boot command line */
+static int __init disable_acpi_watchdog(char *str)
+{
+       acpi_no_watchdog = true;
+       return 1;
+}
+__setup("acpi_no_watchdog", disable_acpi_watchdog);
+
 void __init acpi_watchdog_init(void)
 {
        const struct acpi_wdat_entry *entries;
@@ -126,12 +136,11 @@ void __init acpi_watchdog_init(void)
                gas = &entries[i].register_region;
 
                res.start = gas->address;
+               res.end = res.start + ACPI_ACCESS_BYTE_WIDTH(gas->access_width) - 1;
                if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
                        res.flags = IORESOURCE_MEM;
-                       res.end = res.start + ALIGN(gas->access_width, 4) - 1;
                } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
                        res.flags = IORESOURCE_IO;
-                       res.end = res.start + gas->access_width - 1;
                } else {
                        pr_warn("Unsupported address space: %u\n",
                                gas->space_id);
index 0b081de..de8d354 100644 (file)
@@ -608,6 +608,13 @@ static void software_node_release(struct kobject *kobj)
 {
        struct swnode *swnode = kobj_to_swnode(kobj);
 
+       if (swnode->parent) {
+               ida_simple_remove(&swnode->parent->child_ids, swnode->id);
+               list_del(&swnode->entry);
+       } else {
+               ida_simple_remove(&swnode_root_ids, swnode->id);
+       }
+
        if (swnode->allocated) {
                property_entries_free(swnode->node->properties);
                kfree(swnode->node);
@@ -773,13 +780,6 @@ void fwnode_remove_software_node(struct fwnode_handle *fwnode)
        if (!swnode)
                return;
 
-       if (swnode->parent) {
-               ida_simple_remove(&swnode->parent->child_ids, swnode->id);
-               list_del(&swnode->entry);
-       } else {
-               ida_simple_remove(&swnode_root_ids, swnode->id);
-       }
-
        kobject_put(&swnode->kobj);
 }
 EXPORT_SYMBOL_GPL(fwnode_remove_software_node);
index cd3612e..8ef65c0 100644 (file)
@@ -853,14 +853,17 @@ static void reset_fdc_info(int mode)
 /* selects the fdc and drive, and enables the fdc's input/dma. */
 static void set_fdc(int drive)
 {
+       unsigned int new_fdc = fdc;
+
        if (drive >= 0 && drive < N_DRIVE) {
-               fdc = FDC(drive);
+               new_fdc = FDC(drive);
                current_drive = drive;
        }
-       if (fdc != 1 && fdc != 0) {
+       if (new_fdc >= N_FDC) {
                pr_info("bad fdc value\n");
                return;
        }
+       fdc = new_fdc;
        set_dor(fdc, ~0, 8);
 #if N_FDC > 1
        set_dor(1 - fdc, ~8, 0);
index 117cfc8..cda5cf9 100644 (file)
@@ -276,7 +276,7 @@ static const struct block_device_operations pcd_bdops = {
        .release        = pcd_block_release,
        .ioctl          = pcd_block_ioctl,
 #ifdef CONFIG_COMPAT
-       .ioctl          = blkdev_compat_ptr_ioctl,
+       .compat_ioctl   = blkdev_compat_ptr_ioctl,
 #endif
        .check_events   = pcd_block_check_events,
 };
index e2ad6bb..9df516a 100644 (file)
@@ -213,6 +213,7 @@ struct blkfront_info
        struct blk_mq_tag_set tag_set;
        struct blkfront_ring_info *rinfo;
        unsigned int nr_rings;
+       unsigned int rinfo_size;
        /* Save uncomplete reqs and bios for migration. */
        struct list_head requests;
        struct bio_list bio_list;
@@ -259,6 +260,18 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo);
 static void blkfront_gather_backend_features(struct blkfront_info *info);
 static int negotiate_mq(struct blkfront_info *info);
 
+#define for_each_rinfo(info, ptr, idx)                         \
+       for ((ptr) = (info)->rinfo, (idx) = 0;                  \
+            (idx) < (info)->nr_rings;                          \
+            (idx)++, (ptr) = (void *)(ptr) + (info)->rinfo_size)
+
+static inline struct blkfront_ring_info *
+get_rinfo(const struct blkfront_info *info, unsigned int i)
+{
+       BUG_ON(i >= info->nr_rings);
+       return (void *)info->rinfo + i * info->rinfo_size;
+}
+
 static int get_id_from_freelist(struct blkfront_ring_info *rinfo)
 {
        unsigned long free = rinfo->shadow_free;
@@ -883,8 +896,7 @@ static blk_status_t blkif_queue_rq(struct blk_mq_hw_ctx *hctx,
        struct blkfront_info *info = hctx->queue->queuedata;
        struct blkfront_ring_info *rinfo = NULL;
 
-       BUG_ON(info->nr_rings <= qid);
-       rinfo = &info->rinfo[qid];
+       rinfo = get_rinfo(info, qid);
        blk_mq_start_request(qd->rq);
        spin_lock_irqsave(&rinfo->ring_lock, flags);
        if (RING_FULL(&rinfo->ring))
@@ -1181,6 +1193,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
 static void xlvbd_release_gendisk(struct blkfront_info *info)
 {
        unsigned int minor, nr_minors, i;
+       struct blkfront_ring_info *rinfo;
 
        if (info->rq == NULL)
                return;
@@ -1188,9 +1201,7 @@ static void xlvbd_release_gendisk(struct blkfront_info *info)
        /* No more blkif_request(). */
        blk_mq_stop_hw_queues(info->rq);
 
-       for (i = 0; i < info->nr_rings; i++) {
-               struct blkfront_ring_info *rinfo = &info->rinfo[i];
-
+       for_each_rinfo(info, rinfo, i) {
                /* No more gnttab callback work. */
                gnttab_cancel_free_callback(&rinfo->callback);
 
@@ -1339,6 +1350,7 @@ free_shadow:
 static void blkif_free(struct blkfront_info *info, int suspend)
 {
        unsigned int i;
+       struct blkfront_ring_info *rinfo;
 
        /* Prevent new requests being issued until we fix things up. */
        info->connected = suspend ?
@@ -1347,8 +1359,8 @@ static void blkif_free(struct blkfront_info *info, int suspend)
        if (info->rq)
                blk_mq_stop_hw_queues(info->rq);
 
-       for (i = 0; i < info->nr_rings; i++)
-               blkif_free_ring(&info->rinfo[i]);
+       for_each_rinfo(info, rinfo, i)
+               blkif_free_ring(rinfo);
 
        kvfree(info->rinfo);
        info->rinfo = NULL;
@@ -1775,6 +1787,7 @@ static int talk_to_blkback(struct xenbus_device *dev,
        int err;
        unsigned int i, max_page_order;
        unsigned int ring_page_order;
+       struct blkfront_ring_info *rinfo;
 
        if (!info)
                return -ENODEV;
@@ -1788,9 +1801,7 @@ static int talk_to_blkback(struct xenbus_device *dev,
        if (err)
                goto destroy_blkring;
 
-       for (i = 0; i < info->nr_rings; i++) {
-               struct blkfront_ring_info *rinfo = &info->rinfo[i];
-
+       for_each_rinfo(info, rinfo, i) {
                /* Create shared ring, alloc event channel. */
                err = setup_blkring(dev, rinfo);
                if (err)
@@ -1815,7 +1826,7 @@ again:
 
        /* We already got the number of queues/rings in _probe */
        if (info->nr_rings == 1) {
-               err = write_per_ring_nodes(xbt, &info->rinfo[0], dev->nodename);
+               err = write_per_ring_nodes(xbt, info->rinfo, dev->nodename);
                if (err)
                        goto destroy_blkring;
        } else {
@@ -1837,10 +1848,10 @@ again:
                        goto abort_transaction;
                }
 
-               for (i = 0; i < info->nr_rings; i++) {
+               for_each_rinfo(info, rinfo, i) {
                        memset(path, 0, pathsize);
                        snprintf(path, pathsize, "%s/queue-%u", dev->nodename, i);
-                       err = write_per_ring_nodes(xbt, &info->rinfo[i], path);
+                       err = write_per_ring_nodes(xbt, rinfo, path);
                        if (err) {
                                kfree(path);
                                goto destroy_blkring;
@@ -1868,9 +1879,8 @@ again:
                goto destroy_blkring;
        }
 
-       for (i = 0; i < info->nr_rings; i++) {
+       for_each_rinfo(info, rinfo, i) {
                unsigned int j;
-               struct blkfront_ring_info *rinfo = &info->rinfo[i];
 
                for (j = 0; j < BLK_RING_SIZE(info); j++)
                        rinfo->shadow[j].req.u.rw.id = j + 1;
@@ -1900,6 +1910,7 @@ static int negotiate_mq(struct blkfront_info *info)
 {
        unsigned int backend_max_queues;
        unsigned int i;
+       struct blkfront_ring_info *rinfo;
 
        BUG_ON(info->nr_rings);
 
@@ -1911,20 +1922,16 @@ static int negotiate_mq(struct blkfront_info *info)
        if (!info->nr_rings)
                info->nr_rings = 1;
 
-       info->rinfo = kvcalloc(info->nr_rings,
-                              struct_size(info->rinfo, shadow,
-                                          BLK_RING_SIZE(info)),
-                              GFP_KERNEL);
+       info->rinfo_size = struct_size(info->rinfo, shadow,
+                                      BLK_RING_SIZE(info));
+       info->rinfo = kvcalloc(info->nr_rings, info->rinfo_size, GFP_KERNEL);
        if (!info->rinfo) {
                xenbus_dev_fatal(info->xbdev, -ENOMEM, "allocating ring_info structure");
                info->nr_rings = 0;
                return -ENOMEM;
        }
 
-       for (i = 0; i < info->nr_rings; i++) {
-               struct blkfront_ring_info *rinfo;
-
-               rinfo = &info->rinfo[i];
+       for_each_rinfo(info, rinfo, i) {
                INIT_LIST_HEAD(&rinfo->indirect_pages);
                INIT_LIST_HEAD(&rinfo->grants);
                rinfo->dev_info = info;
@@ -2017,6 +2024,7 @@ static int blkif_recover(struct blkfront_info *info)
        int rc;
        struct bio *bio;
        unsigned int segs;
+       struct blkfront_ring_info *rinfo;
 
        blkfront_gather_backend_features(info);
        /* Reset limits changed by blk_mq_update_nr_hw_queues(). */
@@ -2024,9 +2032,7 @@ static int blkif_recover(struct blkfront_info *info)
        segs = info->max_indirect_segments ? : BLKIF_MAX_SEGMENTS_PER_REQUEST;
        blk_queue_max_segments(info->rq, segs / GRANTS_PER_PSEG);
 
-       for (r_index = 0; r_index < info->nr_rings; r_index++) {
-               struct blkfront_ring_info *rinfo = &info->rinfo[r_index];
-
+       for_each_rinfo(info, rinfo, r_index) {
                rc = blkfront_setup_indirect(rinfo);
                if (rc)
                        return rc;
@@ -2036,10 +2042,7 @@ static int blkif_recover(struct blkfront_info *info)
        /* Now safe for us to use the shared ring */
        info->connected = BLKIF_STATE_CONNECTED;
 
-       for (r_index = 0; r_index < info->nr_rings; r_index++) {
-               struct blkfront_ring_info *rinfo;
-
-               rinfo = &info->rinfo[r_index];
+       for_each_rinfo(info, rinfo, r_index) {
                /* Kick any other new requests queued since we resumed */
                kick_pending_request_queues(rinfo);
        }
@@ -2072,13 +2075,13 @@ static int blkfront_resume(struct xenbus_device *dev)
        struct blkfront_info *info = dev_get_drvdata(&dev->dev);
        int err = 0;
        unsigned int i, j;
+       struct blkfront_ring_info *rinfo;
 
        dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
 
        bio_list_init(&info->bio_list);
        INIT_LIST_HEAD(&info->requests);
-       for (i = 0; i < info->nr_rings; i++) {
-               struct blkfront_ring_info *rinfo = &info->rinfo[i];
+       for_each_rinfo(info, rinfo, i) {
                struct bio_list merge_bio;
                struct blk_shadow *shadow = rinfo->shadow;
 
@@ -2337,6 +2340,7 @@ static void blkfront_connect(struct blkfront_info *info)
        unsigned int binfo;
        char *envp[] = { "RESIZE=1", NULL };
        int err, i;
+       struct blkfront_ring_info *rinfo;
 
        switch (info->connected) {
        case BLKIF_STATE_CONNECTED:
@@ -2394,8 +2398,8 @@ static void blkfront_connect(struct blkfront_info *info)
                                                    "physical-sector-size",
                                                    sector_size);
        blkfront_gather_backend_features(info);
-       for (i = 0; i < info->nr_rings; i++) {
-               err = blkfront_setup_indirect(&info->rinfo[i]);
+       for_each_rinfo(info, rinfo, i) {
+               err = blkfront_setup_indirect(rinfo);
                if (err) {
                        xenbus_dev_fatal(info->xbdev, err, "setup_indirect at %s",
                                         info->xbdev->otherend);
@@ -2416,8 +2420,8 @@ static void blkfront_connect(struct blkfront_info *info)
 
        /* Kick pending requests. */
        info->connected = BLKIF_STATE_CONNECTED;
-       for (i = 0; i < info->nr_rings; i++)
-               kick_pending_request_queues(&info->rinfo[i]);
+       for_each_rinfo(info, rinfo, i)
+               kick_pending_request_queues(rinfo);
 
        device_add_disk(&info->xbdev->dev, info->gd, NULL);
 
@@ -2652,9 +2656,9 @@ static void purge_persistent_grants(struct blkfront_info *info)
 {
        unsigned int i;
        unsigned long flags;
+       struct blkfront_ring_info *rinfo;
 
-       for (i = 0; i < info->nr_rings; i++) {
-               struct blkfront_ring_info *rinfo = &info->rinfo[i];
+       for_each_rinfo(info, rinfo, i) {
                struct grant *gnt_list_entry, *tmp;
 
                spin_lock_irqsave(&rinfo->ring_lock, flags);
index 886b263..c51292c 100644 (file)
@@ -519,7 +519,7 @@ static const struct block_device_operations gdrom_bdops = {
        .check_events           = gdrom_bdops_check_events,
        .ioctl                  = gdrom_bdops_ioctl,
 #ifdef CONFIG_COMPAT
-       .ioctl                  = blkdev_compat_ptr_ioctl,
+       .compat_ioctl           = blkdev_compat_ptr_ioctl,
 #endif
 };
 
index cbe6c94..808874b 100644 (file)
@@ -1076,9 +1076,17 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy)
                        pol = policy->last_policy;
                } else if (def_gov) {
                        pol = cpufreq_parse_policy(def_gov->name);
-               } else {
-                       return -ENODATA;
+                       /*
+                        * In case the default governor is neiter "performance"
+                        * nor "powersave", fall back to the initial policy
+                        * value set by the driver.
+                        */
+                       if (pol == CPUFREQ_POLICY_UNKNOWN)
+                               pol = policy->policy;
                }
+               if (pol != CPUFREQ_POLICY_PERFORMANCE &&
+                   pol != CPUFREQ_POLICY_POWERSAVE)
+                       return -ENODATA;
        }
 
        return cpufreq_set_policy(policy, gov, pol);
index cceee8b..7dcf209 100644 (file)
@@ -738,7 +738,6 @@ struct devfreq *devfreq_add_device(struct device *dev,
 {
        struct devfreq *devfreq;
        struct devfreq_governor *governor;
-       static atomic_t devfreq_no = ATOMIC_INIT(-1);
        int err = 0;
 
        if (!dev || !profile || !governor_name) {
@@ -800,8 +799,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
        devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
        atomic_set(&devfreq->suspend_count, 0);
 
-       dev_set_name(&devfreq->dev, "devfreq%d",
-                               atomic_inc_return(&devfreq_no));
+       dev_set_name(&devfreq->dev, "%s", dev_name(dev));
        err = device_register(&devfreq->dev);
        if (err) {
                mutex_unlock(&devfreq->lock);
index d409785..c343c7c 100644 (file)
@@ -108,6 +108,7 @@ static int dma_buf_release(struct inode *inode, struct file *file)
                dma_resv_fini(dmabuf->resv);
 
        module_put(dmabuf->owner);
+       kfree(dmabuf->name);
        kfree(dmabuf);
        return 0;
 }
index e51d836..1092d4c 100644 (file)
@@ -1947,8 +1947,6 @@ static void dma_tc_handle(struct coh901318_chan *cohc)
                return;
        }
 
-       spin_lock(&cohc->lock);
-
        /*
         * When we reach this point, at least one queue item
         * should have been moved over from cohc->queue to
@@ -1969,8 +1967,6 @@ static void dma_tc_handle(struct coh901318_chan *cohc)
        if (coh901318_queue_start(cohc) == NULL)
                cohc->busy = 0;
 
-       spin_unlock(&cohc->lock);
-
        /*
         * This tasklet will remove items from cohc->active
         * and thus terminates them.
index 1d73478..df47be6 100644 (file)
@@ -204,6 +204,7 @@ static int idxd_wq_cdev_dev_setup(struct idxd_wq *wq)
        minor = ida_simple_get(&cdev_ctx->minor_ida, 0, MINORMASK, GFP_KERNEL);
        if (minor < 0) {
                rc = minor;
+               kfree(dev);
                goto ida_err;
        }
 
@@ -212,7 +213,6 @@ static int idxd_wq_cdev_dev_setup(struct idxd_wq *wq)
        rc = device_register(dev);
        if (rc < 0) {
                dev_err(&idxd->pdev->dev, "device register failed\n");
-               put_device(dev);
                goto dev_reg_err;
        }
        idxd_cdev->minor = minor;
@@ -221,8 +221,8 @@ static int idxd_wq_cdev_dev_setup(struct idxd_wq *wq)
 
  dev_reg_err:
        ida_simple_remove(&cdev_ctx->minor_ida, MINOR(dev->devt));
+       put_device(dev);
  ida_err:
-       kfree(dev);
        idxd_cdev->dev = NULL;
        return rc;
 }
index 6d907fe..6ca6e52 100644 (file)
@@ -124,6 +124,7 @@ static int idxd_config_bus_probe(struct device *dev)
                rc = idxd_device_config(idxd);
                if (rc < 0) {
                        spin_unlock_irqrestore(&idxd->dev_lock, flags);
+                       module_put(THIS_MODULE);
                        dev_warn(dev, "Device config failed: %d\n", rc);
                        return rc;
                }
@@ -132,6 +133,7 @@ static int idxd_config_bus_probe(struct device *dev)
                rc = idxd_device_enable(idxd);
                if (rc < 0) {
                        spin_unlock_irqrestore(&idxd->dev_lock, flags);
+                       module_put(THIS_MODULE);
                        dev_warn(dev, "Device enable failed: %d\n", rc);
                        return rc;
                }
@@ -142,6 +144,7 @@ static int idxd_config_bus_probe(struct device *dev)
                rc = idxd_register_dma_device(idxd);
                if (rc < 0) {
                        spin_unlock_irqrestore(&idxd->dev_lock, flags);
+                       module_put(THIS_MODULE);
                        dev_dbg(dev, "Failed to register dmaengine device\n");
                        return rc;
                }
@@ -516,7 +519,7 @@ static ssize_t group_tokens_reserved_store(struct device *dev,
        if (val > idxd->max_tokens)
                return -EINVAL;
 
-       if (val > idxd->nr_tokens)
+       if (val > idxd->nr_tokens + group->tokens_reserved)
                return -EINVAL;
 
        group->tokens_reserved = val;
@@ -901,6 +904,20 @@ static ssize_t wq_size_show(struct device *dev, struct device_attribute *attr,
        return sprintf(buf, "%u\n", wq->size);
 }
 
+static int total_claimed_wq_size(struct idxd_device *idxd)
+{
+       int i;
+       int wq_size = 0;
+
+       for (i = 0; i < idxd->max_wqs; i++) {
+               struct idxd_wq *wq = &idxd->wqs[i];
+
+               wq_size += wq->size;
+       }
+
+       return wq_size;
+}
+
 static ssize_t wq_size_store(struct device *dev,
                             struct device_attribute *attr, const char *buf,
                             size_t count)
@@ -920,7 +937,7 @@ static ssize_t wq_size_store(struct device *dev,
        if (wq->state != IDXD_WQ_DISABLED)
                return -EPERM;
 
-       if (size > idxd->max_wq_size)
+       if (size + total_claimed_wq_size(idxd) - wq->size > idxd->max_wq_size)
                return -EINVAL;
 
        wq->size = size;
@@ -999,12 +1016,14 @@ static ssize_t wq_type_store(struct device *dev,
                return -EPERM;
 
        old_type = wq->type;
-       if (sysfs_streq(buf, idxd_wq_type_names[IDXD_WQT_KERNEL]))
+       if (sysfs_streq(buf, idxd_wq_type_names[IDXD_WQT_NONE]))
+               wq->type = IDXD_WQT_NONE;
+       else if (sysfs_streq(buf, idxd_wq_type_names[IDXD_WQT_KERNEL]))
                wq->type = IDXD_WQT_KERNEL;
        else if (sysfs_streq(buf, idxd_wq_type_names[IDXD_WQT_USER]))
                wq->type = IDXD_WQT_USER;
        else
-               wq->type = IDXD_WQT_NONE;
+               return -EINVAL;
 
        /* If we are changing queue type, clear the name */
        if (wq->type != old_type)
index 066b21a..4d4477d 100644 (file)
@@ -1331,13 +1331,14 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
 
        sdma_channel_synchronize(chan);
 
-       if (sdmac->event_id0)
+       if (sdmac->event_id0 >= 0)
                sdma_event_disable(sdmac, sdmac->event_id0);
        if (sdmac->event_id1)
                sdma_event_disable(sdmac, sdmac->event_id1);
 
        sdmac->event_id0 = 0;
        sdmac->event_id1 = 0;
+       sdmac->context_loaded = false;
 
        sdma_set_channel_priority(sdmac, 0);
 
@@ -1631,7 +1632,7 @@ static int sdma_config(struct dma_chan *chan,
        memcpy(&sdmac->slave_config, dmaengine_cfg, sizeof(*dmaengine_cfg));
 
        /* Set ENBLn earlier to make sure dma request triggered after that */
-       if (sdmac->event_id0) {
+       if (sdmac->event_id0 >= 0) {
                if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events)
                        return -EINVAL;
                sdma_event_enable(sdmac, sdmac->event_id0);
index 3a45079..4a750e2 100644 (file)
@@ -281,7 +281,7 @@ static struct tegra_dma_desc *tegra_dma_desc_get(
 
        /* Do not allocate if desc are waiting for ack */
        list_for_each_entry(dma_desc, &tdc->free_dma_desc, node) {
-               if (async_tx_test_ack(&dma_desc->txd)) {
+               if (async_tx_test_ack(&dma_desc->txd) && !dma_desc->cb_count) {
                        list_del(&dma_desc->node);
                        spin_unlock_irqrestore(&tdc->lock, flags);
                        dma_desc->txd.flags = 0;
@@ -756,10 +756,6 @@ static int tegra_dma_terminate_all(struct dma_chan *dc)
        bool was_busy;
 
        spin_lock_irqsave(&tdc->lock, flags);
-       if (list_empty(&tdc->pending_sg_req)) {
-               spin_unlock_irqrestore(&tdc->lock, flags);
-               return 0;
-       }
 
        if (!tdc->busy)
                goto skip_dma_stop;
index ea79c2d..0536866 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/delay.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
@@ -96,6 +97,24 @@ struct udma_match_data {
        u32 level_start_idx[];
 };
 
+struct udma_hwdesc {
+       size_t cppi5_desc_size;
+       void *cppi5_desc_vaddr;
+       dma_addr_t cppi5_desc_paddr;
+
+       /* TR descriptor internal pointers */
+       void *tr_req_base;
+       struct cppi5_tr_resp_t *tr_resp_base;
+};
+
+struct udma_rx_flush {
+       struct udma_hwdesc hwdescs[2];
+
+       size_t buffer_size;
+       void *buffer_vaddr;
+       dma_addr_t buffer_paddr;
+};
+
 struct udma_dev {
        struct dma_device ddev;
        struct device *dev;
@@ -112,6 +131,8 @@ struct udma_dev {
        struct list_head desc_to_purge;
        spinlock_t lock;
 
+       struct udma_rx_flush rx_flush;
+
        int tchan_cnt;
        int echan_cnt;
        int rchan_cnt;
@@ -130,16 +151,6 @@ struct udma_dev {
        u32 psil_base;
 };
 
-struct udma_hwdesc {
-       size_t cppi5_desc_size;
-       void *cppi5_desc_vaddr;
-       dma_addr_t cppi5_desc_paddr;
-
-       /* TR descriptor internal pointers */
-       void *tr_req_base;
-       struct cppi5_tr_resp_t *tr_resp_base;
-};
-
 struct udma_desc {
        struct virt_dma_desc vd;
 
@@ -169,7 +180,7 @@ enum udma_chan_state {
 
 struct udma_tx_drain {
        struct delayed_work work;
-       unsigned long jiffie;
+       ktime_t tstamp;
        u32 residue;
 };
 
@@ -502,7 +513,7 @@ static bool udma_is_chan_paused(struct udma_chan *uc)
 {
        u32 val, pause_mask;
 
-       switch (uc->desc->dir) {
+       switch (uc->config.dir) {
        case DMA_DEV_TO_MEM:
                val = udma_rchanrt_read(uc->rchan,
                                        UDMA_RCHAN_RT_PEER_RT_EN_REG);
@@ -551,12 +562,17 @@ static void udma_sync_for_device(struct udma_chan *uc, int idx)
        }
 }
 
+static inline dma_addr_t udma_get_rx_flush_hwdesc_paddr(struct udma_chan *uc)
+{
+       return uc->ud->rx_flush.hwdescs[uc->config.pkt_mode].cppi5_desc_paddr;
+}
+
 static int udma_push_to_ring(struct udma_chan *uc, int idx)
 {
        struct udma_desc *d = uc->desc;
-
        struct k3_ring *ring = NULL;
-       int ret = -EINVAL;
+       dma_addr_t paddr;
+       int ret;
 
        switch (uc->config.dir) {
        case DMA_DEV_TO_MEM:
@@ -567,21 +583,37 @@ static int udma_push_to_ring(struct udma_chan *uc, int idx)
                ring = uc->tchan->t_ring;
                break;
        default:
-               break;
+               return -EINVAL;
        }
 
-       if (ring) {
-               dma_addr_t desc_addr = udma_curr_cppi5_desc_paddr(d, idx);
+       /* RX flush packet: idx == -1 is only passed in case of DEV_TO_MEM */
+       if (idx == -1) {
+               paddr = udma_get_rx_flush_hwdesc_paddr(uc);
+       } else {
+               paddr = udma_curr_cppi5_desc_paddr(d, idx);
 
                wmb(); /* Ensure that writes are not moved over this point */
                udma_sync_for_device(uc, idx);
-               ret = k3_ringacc_ring_push(ring, &desc_addr);
-               uc->in_ring_cnt++;
        }
 
+       ret = k3_ringacc_ring_push(ring, &paddr);
+       if (!ret)
+               uc->in_ring_cnt++;
+
        return ret;
 }
 
+static bool udma_desc_is_rx_flush(struct udma_chan *uc, dma_addr_t addr)
+{
+       if (uc->config.dir != DMA_DEV_TO_MEM)
+               return false;
+
+       if (addr == udma_get_rx_flush_hwdesc_paddr(uc))
+               return true;
+
+       return false;
+}
+
 static int udma_pop_from_ring(struct udma_chan *uc, dma_addr_t *addr)
 {
        struct k3_ring *ring = NULL;
@@ -610,6 +642,10 @@ static int udma_pop_from_ring(struct udma_chan *uc, dma_addr_t *addr)
                if (cppi5_desc_is_tdcm(*addr))
                        return ret;
 
+               /* Check for flush descriptor */
+               if (udma_desc_is_rx_flush(uc, *addr))
+                       return -ENOENT;
+
                d = udma_udma_desc_from_paddr(uc, *addr);
 
                if (d)
@@ -890,6 +926,9 @@ static int udma_stop(struct udma_chan *uc)
 
        switch (uc->config.dir) {
        case DMA_DEV_TO_MEM:
+               if (!uc->cyclic && !uc->desc)
+                       udma_push_to_ring(uc, -1);
+
                udma_rchanrt_write(uc->rchan, UDMA_RCHAN_RT_PEER_RT_EN_REG,
                                   UDMA_PEER_RT_EN_ENABLE |
                                   UDMA_PEER_RT_EN_TEARDOWN);
@@ -946,9 +985,10 @@ static bool udma_is_desc_really_done(struct udma_chan *uc, struct udma_desc *d)
        peer_bcnt = udma_tchanrt_read(uc->tchan, UDMA_TCHAN_RT_PEER_BCNT_REG);
        bcnt = udma_tchanrt_read(uc->tchan, UDMA_TCHAN_RT_BCNT_REG);
 
+       /* Transfer is incomplete, store current residue and time stamp */
        if (peer_bcnt < bcnt) {
                uc->tx_drain.residue = bcnt - peer_bcnt;
-               uc->tx_drain.jiffie = jiffies;
+               uc->tx_drain.tstamp = ktime_get();
                return false;
        }
 
@@ -961,35 +1001,59 @@ static void udma_check_tx_completion(struct work_struct *work)
                                            tx_drain.work.work);
        bool desc_done = true;
        u32 residue_diff;
-       unsigned long jiffie_diff, delay;
+       ktime_t time_diff;
+       unsigned long delay;
+
+       while (1) {
+               if (uc->desc) {
+                       /* Get previous residue and time stamp */
+                       residue_diff = uc->tx_drain.residue;
+                       time_diff = uc->tx_drain.tstamp;
+                       /*
+                        * Get current residue and time stamp or see if
+                        * transfer is complete
+                        */
+                       desc_done = udma_is_desc_really_done(uc, uc->desc);
+               }
 
-       if (uc->desc) {
-               residue_diff = uc->tx_drain.residue;
-               jiffie_diff = uc->tx_drain.jiffie;
-               desc_done = udma_is_desc_really_done(uc, uc->desc);
-       }
-
-       if (!desc_done) {
-               jiffie_diff = uc->tx_drain.jiffie - jiffie_diff;
-               residue_diff -= uc->tx_drain.residue;
-               if (residue_diff) {
-                       /* Try to guess when we should check next time */
-                       residue_diff /= jiffie_diff;
-                       delay = uc->tx_drain.residue / residue_diff / 3;
-                       if (jiffies_to_msecs(delay) < 5)
-                               delay = 0;
-               } else {
-                       /* No progress, check again in 1 second  */
-                       delay = HZ;
+               if (!desc_done) {
+                       /*
+                        * Find the time delta and residue delta w.r.t
+                        * previous poll
+                        */
+                       time_diff = ktime_sub(uc->tx_drain.tstamp,
+                                             time_diff) + 1;
+                       residue_diff -= uc->tx_drain.residue;
+                       if (residue_diff) {
+                               /*
+                                * Try to guess when we should check
+                                * next time by calculating rate at
+                                * which data is being drained at the
+                                * peer device
+                                */
+                               delay = (time_diff / residue_diff) *
+                                       uc->tx_drain.residue;
+                       } else {
+                               /* No progress, check again in 1 second  */
+                               schedule_delayed_work(&uc->tx_drain.work, HZ);
+                               break;
+                       }
+
+                       usleep_range(ktime_to_us(delay),
+                                    ktime_to_us(delay) + 10);
+                       continue;
                }
 
-               schedule_delayed_work(&uc->tx_drain.work, delay);
-       } else if (uc->desc) {
-               struct udma_desc *d = uc->desc;
+               if (uc->desc) {
+                       struct udma_desc *d = uc->desc;
 
-               uc->bcnt += d->residue;
-               udma_start(uc);
-               vchan_cookie_complete(&d->vd);
+                       uc->bcnt += d->residue;
+                       udma_start(uc);
+                       vchan_cookie_complete(&d->vd);
+                       break;
+               }
+
+               break;
        }
 }
 
@@ -1033,29 +1097,27 @@ static irqreturn_t udma_ring_irq_handler(int irq, void *data)
                        goto out;
                }
 
-               if (uc->cyclic) {
-                       /* push the descriptor back to the ring */
-                       if (d == uc->desc) {
+               if (d == uc->desc) {
+                       /* active descriptor */
+                       if (uc->cyclic) {
                                udma_cyclic_packet_elapsed(uc);
                                vchan_cyclic_callback(&d->vd);
-                       }
-               } else {
-                       bool desc_done = false;
-
-                       if (d == uc->desc) {
-                               desc_done = udma_is_desc_really_done(uc, d);
-
-                               if (desc_done) {
+                       } else {
+                               if (udma_is_desc_really_done(uc, d)) {
                                        uc->bcnt += d->residue;
                                        udma_start(uc);
+                                       vchan_cookie_complete(&d->vd);
                                } else {
                                        schedule_delayed_work(&uc->tx_drain.work,
                                                              0);
                                }
                        }
-
-                       if (desc_done)
-                               vchan_cookie_complete(&d->vd);
+               } else {
+                       /*
+                        * terminated descriptor, mark the descriptor as
+                        * completed to update the channel's cookie marker
+                        */
+                       dma_cookie_complete(&d->vd.tx);
                }
        }
 out:
@@ -1965,36 +2027,81 @@ static struct udma_desc *udma_alloc_tr_desc(struct udma_chan *uc,
        return d;
 }
 
+/**
+ * udma_get_tr_counters - calculate TR counters for a given length
+ * @len: Length of the trasnfer
+ * @align_to: Preferred alignment
+ * @tr0_cnt0: First TR icnt0
+ * @tr0_cnt1: First TR icnt1
+ * @tr1_cnt0: Second (if used) TR icnt0
+ *
+ * For len < SZ_64K only one TR is enough, tr1_cnt0 is not updated
+ * For len >= SZ_64K two TRs are used in a simple way:
+ * First TR: SZ_64K-alignment blocks (tr0_cnt0, tr0_cnt1)
+ * Second TR: the remaining length (tr1_cnt0)
+ *
+ * Returns the number of TRs the length needs (1 or 2)
+ * -EINVAL if the length can not be supported
+ */
+static int udma_get_tr_counters(size_t len, unsigned long align_to,
+                               u16 *tr0_cnt0, u16 *tr0_cnt1, u16 *tr1_cnt0)
+{
+       if (len < SZ_64K) {
+               *tr0_cnt0 = len;
+               *tr0_cnt1 = 1;
+
+               return 1;
+       }
+
+       if (align_to > 3)
+               align_to = 3;
+
+realign:
+       *tr0_cnt0 = SZ_64K - BIT(align_to);
+       if (len / *tr0_cnt0 >= SZ_64K) {
+               if (align_to) {
+                       align_to--;
+                       goto realign;
+               }
+               return -EINVAL;
+       }
+
+       *tr0_cnt1 = len / *tr0_cnt0;
+       *tr1_cnt0 = len % *tr0_cnt0;
+
+       return 2;
+}
+
 static struct udma_desc *
 udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl,
                      unsigned int sglen, enum dma_transfer_direction dir,
                      unsigned long tx_flags, void *context)
 {
-       enum dma_slave_buswidth dev_width;
        struct scatterlist *sgent;
        struct udma_desc *d;
-       size_t tr_size;
        struct cppi5_tr_type1_t *tr_req = NULL;
+       u16 tr0_cnt0, tr0_cnt1, tr1_cnt0;
        unsigned int i;
-       u32 burst;
+       size_t tr_size;
+       int num_tr = 0;
+       int tr_idx = 0;
 
-       if (dir == DMA_DEV_TO_MEM) {
-               dev_width = uc->cfg.src_addr_width;
-               burst = uc->cfg.src_maxburst;
-       } else if (dir == DMA_MEM_TO_DEV) {
-               dev_width = uc->cfg.dst_addr_width;
-               burst = uc->cfg.dst_maxburst;
-       } else {
-               dev_err(uc->ud->dev, "%s: bad direction?\n", __func__);
+       if (!is_slave_direction(dir)) {
+               dev_err(uc->ud->dev, "Only slave cyclic is supported\n");
                return NULL;
        }
 
-       if (!burst)
-               burst = 1;
+       /* estimate the number of TRs we will need */
+       for_each_sg(sgl, sgent, sglen, i) {
+               if (sg_dma_len(sgent) < SZ_64K)
+                       num_tr++;
+               else
+                       num_tr += 2;
+       }
 
        /* Now allocate and setup the descriptor. */
        tr_size = sizeof(struct cppi5_tr_type1_t);
-       d = udma_alloc_tr_desc(uc, tr_size, sglen, dir);
+       d = udma_alloc_tr_desc(uc, tr_size, num_tr, dir);
        if (!d)
                return NULL;
 
@@ -2002,19 +2109,46 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl,
 
        tr_req = d->hwdesc[0].tr_req_base;
        for_each_sg(sgl, sgent, sglen, i) {
-               d->residue += sg_dma_len(sgent);
+               dma_addr_t sg_addr = sg_dma_address(sgent);
+
+               num_tr = udma_get_tr_counters(sg_dma_len(sgent), __ffs(sg_addr),
+                                             &tr0_cnt0, &tr0_cnt1, &tr1_cnt0);
+               if (num_tr < 0) {
+                       dev_err(uc->ud->dev, "size %u is not supported\n",
+                               sg_dma_len(sgent));
+                       udma_free_hwdesc(uc, d);
+                       kfree(d);
+                       return NULL;
+               }
 
                cppi5_tr_init(&tr_req[i].flags, CPPI5_TR_TYPE1, false, false,
                              CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
                cppi5_tr_csf_set(&tr_req[i].flags, CPPI5_TR_CSF_SUPR_EVT);
 
-               tr_req[i].addr = sg_dma_address(sgent);
-               tr_req[i].icnt0 = burst * dev_width;
-               tr_req[i].dim1 = burst * dev_width;
-               tr_req[i].icnt1 = sg_dma_len(sgent) / tr_req[i].icnt0;
+               tr_req[tr_idx].addr = sg_addr;
+               tr_req[tr_idx].icnt0 = tr0_cnt0;
+               tr_req[tr_idx].icnt1 = tr0_cnt1;
+               tr_req[tr_idx].dim1 = tr0_cnt0;
+               tr_idx++;
+
+               if (num_tr == 2) {
+                       cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1,
+                                     false, false,
+                                     CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
+                       cppi5_tr_csf_set(&tr_req[tr_idx].flags,
+                                        CPPI5_TR_CSF_SUPR_EVT);
+
+                       tr_req[tr_idx].addr = sg_addr + tr0_cnt1 * tr0_cnt0;
+                       tr_req[tr_idx].icnt0 = tr1_cnt0;
+                       tr_req[tr_idx].icnt1 = 1;
+                       tr_req[tr_idx].dim1 = tr1_cnt0;
+                       tr_idx++;
+               }
+
+               d->residue += sg_dma_len(sgent);
        }
 
-       cppi5_tr_csf_set(&tr_req[i - 1].flags, CPPI5_TR_CSF_EOP);
+       cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, CPPI5_TR_CSF_EOP);
 
        return d;
 }
@@ -2319,47 +2453,66 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr,
                        size_t buf_len, size_t period_len,
                        enum dma_transfer_direction dir, unsigned long flags)
 {
-       enum dma_slave_buswidth dev_width;
        struct udma_desc *d;
-       size_t tr_size;
+       size_t tr_size, period_addr;
        struct cppi5_tr_type1_t *tr_req;
-       unsigned int i;
        unsigned int periods = buf_len / period_len;
-       u32 burst;
+       u16 tr0_cnt0, tr0_cnt1, tr1_cnt0;
+       unsigned int i;
+       int num_tr;
 
-       if (dir == DMA_DEV_TO_MEM) {
-               dev_width = uc->cfg.src_addr_width;
-               burst = uc->cfg.src_maxburst;
-       } else if (dir == DMA_MEM_TO_DEV) {
-               dev_width = uc->cfg.dst_addr_width;
-               burst = uc->cfg.dst_maxburst;
-       } else {
-               dev_err(uc->ud->dev, "%s: bad direction?\n", __func__);
+       if (!is_slave_direction(dir)) {
+               dev_err(uc->ud->dev, "Only slave cyclic is supported\n");
                return NULL;
        }
 
-       if (!burst)
-               burst = 1;
+       num_tr = udma_get_tr_counters(period_len, __ffs(buf_addr), &tr0_cnt0,
+                                     &tr0_cnt1, &tr1_cnt0);
+       if (num_tr < 0) {
+               dev_err(uc->ud->dev, "size %zu is not supported\n",
+                       period_len);
+               return NULL;
+       }
 
        /* Now allocate and setup the descriptor. */
        tr_size = sizeof(struct cppi5_tr_type1_t);
-       d = udma_alloc_tr_desc(uc, tr_size, periods, dir);
+       d = udma_alloc_tr_desc(uc, tr_size, periods * num_tr, dir);
        if (!d)
                return NULL;
 
        tr_req = d->hwdesc[0].tr_req_base;
+       period_addr = buf_addr;
        for (i = 0; i < periods; i++) {
-               cppi5_tr_init(&tr_req[i].flags, CPPI5_TR_TYPE1, false, false,
-                             CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
+               int tr_idx = i * num_tr;
 
-               tr_req[i].addr = buf_addr + period_len * i;
-               tr_req[i].icnt0 = dev_width;
-               tr_req[i].icnt1 = period_len / dev_width;
-               tr_req[i].dim1 = dev_width;
+               cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, false,
+                             false, CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
+
+               tr_req[tr_idx].addr = period_addr;
+               tr_req[tr_idx].icnt0 = tr0_cnt0;
+               tr_req[tr_idx].icnt1 = tr0_cnt1;
+               tr_req[tr_idx].dim1 = tr0_cnt0;
+
+               if (num_tr == 2) {
+                       cppi5_tr_csf_set(&tr_req[tr_idx].flags,
+                                        CPPI5_TR_CSF_SUPR_EVT);
+                       tr_idx++;
+
+                       cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1,
+                                     false, false,
+                                     CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
+
+                       tr_req[tr_idx].addr = period_addr + tr0_cnt1 * tr0_cnt0;
+                       tr_req[tr_idx].icnt0 = tr1_cnt0;
+                       tr_req[tr_idx].icnt1 = 1;
+                       tr_req[tr_idx].dim1 = tr1_cnt0;
+               }
 
                if (!(flags & DMA_PREP_INTERRUPT))
-                       cppi5_tr_csf_set(&tr_req[i].flags,
+                       cppi5_tr_csf_set(&tr_req[tr_idx].flags,
                                         CPPI5_TR_CSF_SUPR_EVT);
+
+               period_addr += period_len;
        }
 
        return d;
@@ -2517,29 +2670,12 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
                return NULL;
        }
 
-       if (len < SZ_64K) {
-               num_tr = 1;
-               tr0_cnt0 = len;
-               tr0_cnt1 = 1;
-       } else {
-               unsigned long align_to = __ffs(src | dest);
-
-               if (align_to > 3)
-                       align_to = 3;
-               /*
-                * Keep simple: tr0: SZ_64K-alignment blocks,
-                *              tr1: the remaining
-                */
-               num_tr = 2;
-               tr0_cnt0 = (SZ_64K - BIT(align_to));
-               if (len / tr0_cnt0 >= SZ_64K) {
-                       dev_err(uc->ud->dev, "size %zu is not supported\n",
-                               len);
-                       return NULL;
-               }
-
-               tr0_cnt1 = len / tr0_cnt0;
-               tr1_cnt0 = len % tr0_cnt0;
+       num_tr = udma_get_tr_counters(len, __ffs(src | dest), &tr0_cnt0,
+                                     &tr0_cnt1, &tr1_cnt0);
+       if (num_tr < 0) {
+               dev_err(uc->ud->dev, "size %zu is not supported\n",
+                       len);
+               return NULL;
        }
 
        d = udma_alloc_tr_desc(uc, tr_size, num_tr, DMA_MEM_TO_MEM);
@@ -2631,6 +2767,9 @@ static enum dma_status udma_tx_status(struct dma_chan *chan,
 
        ret = dma_cookie_status(chan, cookie, txstate);
 
+       if (!udma_is_chan_running(uc))
+               ret = DMA_COMPLETE;
+
        if (ret == DMA_IN_PROGRESS && udma_is_chan_paused(uc))
                ret = DMA_PAUSED;
 
@@ -2697,11 +2836,8 @@ static int udma_pause(struct dma_chan *chan)
 {
        struct udma_chan *uc = to_udma_chan(chan);
 
-       if (!uc->desc)
-               return -EINVAL;
-
        /* pause the channel */
-       switch (uc->desc->dir) {
+       switch (uc->config.dir) {
        case DMA_DEV_TO_MEM:
                udma_rchanrt_update_bits(uc->rchan,
                                         UDMA_RCHAN_RT_PEER_RT_EN_REG,
@@ -2730,11 +2866,8 @@ static int udma_resume(struct dma_chan *chan)
 {
        struct udma_chan *uc = to_udma_chan(chan);
 
-       if (!uc->desc)
-               return -EINVAL;
-
        /* resume the channel */
-       switch (uc->desc->dir) {
+       switch (uc->config.dir) {
        case DMA_DEV_TO_MEM:
                udma_rchanrt_update_bits(uc->rchan,
                                         UDMA_RCHAN_RT_PEER_RT_EN_REG,
@@ -3248,6 +3381,98 @@ static int udma_setup_resources(struct udma_dev *ud)
        return ch_count;
 }
 
+static int udma_setup_rx_flush(struct udma_dev *ud)
+{
+       struct udma_rx_flush *rx_flush = &ud->rx_flush;
+       struct cppi5_desc_hdr_t *tr_desc;
+       struct cppi5_tr_type1_t *tr_req;
+       struct cppi5_host_desc_t *desc;
+       struct device *dev = ud->dev;
+       struct udma_hwdesc *hwdesc;
+       size_t tr_size;
+
+       /* Allocate 1K buffer for discarded data on RX channel teardown */
+       rx_flush->buffer_size = SZ_1K;
+       rx_flush->buffer_vaddr = devm_kzalloc(dev, rx_flush->buffer_size,
+                                             GFP_KERNEL);
+       if (!rx_flush->buffer_vaddr)
+               return -ENOMEM;
+
+       rx_flush->buffer_paddr = dma_map_single(dev, rx_flush->buffer_vaddr,
+                                               rx_flush->buffer_size,
+                                               DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, rx_flush->buffer_paddr))
+               return -ENOMEM;
+
+       /* Set up descriptor to be used for TR mode */
+       hwdesc = &rx_flush->hwdescs[0];
+       tr_size = sizeof(struct cppi5_tr_type1_t);
+       hwdesc->cppi5_desc_size = cppi5_trdesc_calc_size(tr_size, 1);
+       hwdesc->cppi5_desc_size = ALIGN(hwdesc->cppi5_desc_size,
+                                       ud->desc_align);
+
+       hwdesc->cppi5_desc_vaddr = devm_kzalloc(dev, hwdesc->cppi5_desc_size,
+                                               GFP_KERNEL);
+       if (!hwdesc->cppi5_desc_vaddr)
+               return -ENOMEM;
+
+       hwdesc->cppi5_desc_paddr = dma_map_single(dev, hwdesc->cppi5_desc_vaddr,
+                                                 hwdesc->cppi5_desc_size,
+                                                 DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, hwdesc->cppi5_desc_paddr))
+               return -ENOMEM;
+
+       /* Start of the TR req records */
+       hwdesc->tr_req_base = hwdesc->cppi5_desc_vaddr + tr_size;
+       /* Start address of the TR response array */
+       hwdesc->tr_resp_base = hwdesc->tr_req_base + tr_size;
+
+       tr_desc = hwdesc->cppi5_desc_vaddr;
+       cppi5_trdesc_init(tr_desc, 1, tr_size, 0, 0);
+       cppi5_desc_set_pktids(tr_desc, 0, CPPI5_INFO1_DESC_FLOWID_DEFAULT);
+       cppi5_desc_set_retpolicy(tr_desc, 0, 0);
+
+       tr_req = hwdesc->tr_req_base;
+       cppi5_tr_init(&tr_req->flags, CPPI5_TR_TYPE1, false, false,
+                     CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
+       cppi5_tr_csf_set(&tr_req->flags, CPPI5_TR_CSF_SUPR_EVT);
+
+       tr_req->addr = rx_flush->buffer_paddr;
+       tr_req->icnt0 = rx_flush->buffer_size;
+       tr_req->icnt1 = 1;
+
+       /* Set up descriptor to be used for packet mode */
+       hwdesc = &rx_flush->hwdescs[1];
+       hwdesc->cppi5_desc_size = ALIGN(sizeof(struct cppi5_host_desc_t) +
+                                       CPPI5_INFO0_HDESC_EPIB_SIZE +
+                                       CPPI5_INFO0_HDESC_PSDATA_MAX_SIZE,
+                                       ud->desc_align);
+
+       hwdesc->cppi5_desc_vaddr = devm_kzalloc(dev, hwdesc->cppi5_desc_size,
+                                               GFP_KERNEL);
+       if (!hwdesc->cppi5_desc_vaddr)
+               return -ENOMEM;
+
+       hwdesc->cppi5_desc_paddr = dma_map_single(dev, hwdesc->cppi5_desc_vaddr,
+                                                 hwdesc->cppi5_desc_size,
+                                                 DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, hwdesc->cppi5_desc_paddr))
+               return -ENOMEM;
+
+       desc = hwdesc->cppi5_desc_vaddr;
+       cppi5_hdesc_init(desc, 0, 0);
+       cppi5_desc_set_pktids(&desc->hdr, 0, CPPI5_INFO1_DESC_FLOWID_DEFAULT);
+       cppi5_desc_set_retpolicy(&desc->hdr, 0, 0);
+
+       cppi5_hdesc_attach_buf(desc,
+                              rx_flush->buffer_paddr, rx_flush->buffer_size,
+                              rx_flush->buffer_paddr, rx_flush->buffer_size);
+
+       dma_sync_single_for_device(dev, hwdesc->cppi5_desc_paddr,
+                                  hwdesc->cppi5_desc_size, DMA_TO_DEVICE);
+       return 0;
+}
+
 #define TI_UDMAC_BUSWIDTHS     (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
                                 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
                                 BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \
@@ -3361,6 +3586,10 @@ static int udma_probe(struct platform_device *pdev)
        if (ud->desc_align < dma_get_cache_alignment())
                ud->desc_align = dma_get_cache_alignment();
 
+       ret = udma_setup_rx_flush(ud);
+       if (ret)
+               return ret;
+
        for (i = 0; i < ud->tchan_cnt; i++) {
                struct udma_tchan *tchan = &ud->tchans[i];
 
index 621220a..21ea99f 100644 (file)
@@ -552,7 +552,7 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
 
                seed = early_memremap(efi.rng_seed, sizeof(*seed));
                if (seed != NULL) {
-                       size = seed->size;
+                       size = READ_ONCE(seed->size);
                        early_memunmap(seed, sizeof(*seed));
                } else {
                        pr_err("Could not map UEFI random seed!\n");
@@ -562,7 +562,7 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
                                              sizeof(*seed) + size);
                        if (seed != NULL) {
                                pr_notice("seeding entropy pool\n");
-                               add_bootloader_randomness(seed->bits, seed->size);
+                               add_bootloader_randomness(seed->bits, size);
                                early_memunmap(seed, sizeof(*seed) + size);
                        } else {
                                pr_err("Could not map UEFI random seed!\n");
index 94e2fd7..42f4feb 100644 (file)
@@ -1389,7 +1389,7 @@ amdgpu_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe,
 
 static struct drm_driver kms_driver = {
        .driver_features =
-           DRIVER_USE_AGP | DRIVER_ATOMIC |
+           DRIVER_ATOMIC |
            DRIVER_GEM |
            DRIVER_RENDER | DRIVER_MODESET | DRIVER_SYNCOBJ |
            DRIVER_SYNCOBJ_TIMELINE,
index d3c27a3..7546da0 100644 (file)
@@ -195,6 +195,7 @@ struct amdgpu_gmc {
        uint32_t                srbm_soft_reset;
        bool                    prt_warning;
        uint64_t                stolen_size;
+       uint32_t                sdpif_register;
        /* apertures */
        u64                     shared_aperture_start;
        u64                     shared_aperture_end;
index 22bbb36..0270259 100644 (file)
@@ -52,7 +52,7 @@
  * 1. Primary ring
  * 2. Async ring
  */
-#define GFX10_NUM_GFX_RINGS    2
+#define GFX10_NUM_GFX_RINGS_NV1X       1
 #define GFX10_MEC_HPD_SIZE     2048
 
 #define F32_CE_PROGRAM_RAM_SIZE                65536
@@ -1304,7 +1304,7 @@ static int gfx_v10_0_sw_init(void *handle)
        case CHIP_NAVI14:
        case CHIP_NAVI12:
                adev->gfx.me.num_me = 1;
-               adev->gfx.me.num_pipe_per_me = 2;
+               adev->gfx.me.num_pipe_per_me = 1;
                adev->gfx.me.num_queue_per_pipe = 1;
                adev->gfx.mec.num_mec = 2;
                adev->gfx.mec.num_pipe_per_mec = 4;
@@ -2710,18 +2710,20 @@ static int gfx_v10_0_cp_gfx_start(struct amdgpu_device *adev)
        amdgpu_ring_commit(ring);
 
        /* submit cs packet to copy state 0 to next available state */
-       ring = &adev->gfx.gfx_ring[1];
-       r = amdgpu_ring_alloc(ring, 2);
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to lock ring (%d).\n", r);
-               return r;
-       }
-
-       amdgpu_ring_write(ring, PACKET3(PACKET3_CLEAR_STATE, 0));
-       amdgpu_ring_write(ring, 0);
+       if (adev->gfx.num_gfx_rings > 1) {
+               /* maximum supported gfx ring is 2 */
+               ring = &adev->gfx.gfx_ring[1];
+               r = amdgpu_ring_alloc(ring, 2);
+               if (r) {
+                       DRM_ERROR("amdgpu: cp failed to lock ring (%d).\n", r);
+                       return r;
+               }
 
-       amdgpu_ring_commit(ring);
+               amdgpu_ring_write(ring, PACKET3(PACKET3_CLEAR_STATE, 0));
+               amdgpu_ring_write(ring, 0);
 
+               amdgpu_ring_commit(ring);
+       }
        return 0;
 }
 
@@ -2818,39 +2820,41 @@ static int gfx_v10_0_cp_gfx_resume(struct amdgpu_device *adev)
        mutex_unlock(&adev->srbm_mutex);
 
        /* Init gfx ring 1 for pipe 1 */
-       mutex_lock(&adev->srbm_mutex);
-       gfx_v10_0_cp_gfx_switch_pipe(adev, PIPE_ID1);
-       ring = &adev->gfx.gfx_ring[1];
-       rb_bufsz = order_base_2(ring->ring_size / 8);
-       tmp = REG_SET_FIELD(0, CP_RB1_CNTL, RB_BUFSZ, rb_bufsz);
-       tmp = REG_SET_FIELD(tmp, CP_RB1_CNTL, RB_BLKSZ, rb_bufsz - 2);
-       WREG32_SOC15(GC, 0, mmCP_RB1_CNTL, tmp);
-       /* Initialize the ring buffer's write pointers */
-       ring->wptr = 0;
-       WREG32_SOC15(GC, 0, mmCP_RB1_WPTR, lower_32_bits(ring->wptr));
-       WREG32_SOC15(GC, 0, mmCP_RB1_WPTR_HI, upper_32_bits(ring->wptr));
-       /* Set the wb address wether it's enabled or not */
-       rptr_addr = adev->wb.gpu_addr + (ring->rptr_offs * 4);
-       WREG32_SOC15(GC, 0, mmCP_RB1_RPTR_ADDR, lower_32_bits(rptr_addr));
-       WREG32_SOC15(GC, 0, mmCP_RB1_RPTR_ADDR_HI, upper_32_bits(rptr_addr) &
-               CP_RB1_RPTR_ADDR_HI__RB_RPTR_ADDR_HI_MASK);
-       wptr_gpu_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
-       WREG32_SOC15(GC, 0, mmCP_RB_WPTR_POLL_ADDR_LO,
-               lower_32_bits(wptr_gpu_addr));
-       WREG32_SOC15(GC, 0, mmCP_RB_WPTR_POLL_ADDR_HI,
-               upper_32_bits(wptr_gpu_addr));
-
-       mdelay(1);
-       WREG32_SOC15(GC, 0, mmCP_RB1_CNTL, tmp);
-
-       rb_addr = ring->gpu_addr >> 8;
-       WREG32_SOC15(GC, 0, mmCP_RB1_BASE, rb_addr);
-       WREG32_SOC15(GC, 0, mmCP_RB1_BASE_HI, upper_32_bits(rb_addr));
-       WREG32_SOC15(GC, 0, mmCP_RB1_ACTIVE, 1);
-
-       gfx_v10_0_cp_gfx_set_doorbell(adev, ring);
-       mutex_unlock(&adev->srbm_mutex);
-
+       if (adev->gfx.num_gfx_rings > 1) {
+               mutex_lock(&adev->srbm_mutex);
+               gfx_v10_0_cp_gfx_switch_pipe(adev, PIPE_ID1);
+               /* maximum supported gfx ring is 2 */
+               ring = &adev->gfx.gfx_ring[1];
+               rb_bufsz = order_base_2(ring->ring_size / 8);
+               tmp = REG_SET_FIELD(0, CP_RB1_CNTL, RB_BUFSZ, rb_bufsz);
+               tmp = REG_SET_FIELD(tmp, CP_RB1_CNTL, RB_BLKSZ, rb_bufsz - 2);
+               WREG32_SOC15(GC, 0, mmCP_RB1_CNTL, tmp);
+               /* Initialize the ring buffer's write pointers */
+               ring->wptr = 0;
+               WREG32_SOC15(GC, 0, mmCP_RB1_WPTR, lower_32_bits(ring->wptr));
+               WREG32_SOC15(GC, 0, mmCP_RB1_WPTR_HI, upper_32_bits(ring->wptr));
+               /* Set the wb address wether it's enabled or not */
+               rptr_addr = adev->wb.gpu_addr + (ring->rptr_offs * 4);
+               WREG32_SOC15(GC, 0, mmCP_RB1_RPTR_ADDR, lower_32_bits(rptr_addr));
+               WREG32_SOC15(GC, 0, mmCP_RB1_RPTR_ADDR_HI, upper_32_bits(rptr_addr) &
+                            CP_RB1_RPTR_ADDR_HI__RB_RPTR_ADDR_HI_MASK);
+               wptr_gpu_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
+               WREG32_SOC15(GC, 0, mmCP_RB_WPTR_POLL_ADDR_LO,
+                            lower_32_bits(wptr_gpu_addr));
+               WREG32_SOC15(GC, 0, mmCP_RB_WPTR_POLL_ADDR_HI,
+                            upper_32_bits(wptr_gpu_addr));
+
+               mdelay(1);
+               WREG32_SOC15(GC, 0, mmCP_RB1_CNTL, tmp);
+
+               rb_addr = ring->gpu_addr >> 8;
+               WREG32_SOC15(GC, 0, mmCP_RB1_BASE, rb_addr);
+               WREG32_SOC15(GC, 0, mmCP_RB1_BASE_HI, upper_32_bits(rb_addr));
+               WREG32_SOC15(GC, 0, mmCP_RB1_ACTIVE, 1);
+
+               gfx_v10_0_cp_gfx_set_doorbell(adev, ring);
+               mutex_unlock(&adev->srbm_mutex);
+       }
        /* Switch to pipe 0 */
        mutex_lock(&adev->srbm_mutex);
        gfx_v10_0_cp_gfx_switch_pipe(adev, PIPE_ID0);
@@ -3513,6 +3517,7 @@ static int gfx_v10_0_kcq_init_queue(struct amdgpu_ring *ring)
 
                /* reset ring buffer */
                ring->wptr = 0;
+               atomic64_set((atomic64_t *)&adev->wb.wb[ring->wptr_offs], 0);
                amdgpu_ring_clear_ring(ring);
        } else {
                amdgpu_ring_clear_ring(ring);
@@ -3966,7 +3971,8 @@ static int gfx_v10_0_early_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       adev->gfx.num_gfx_rings = GFX10_NUM_GFX_RINGS;
+       adev->gfx.num_gfx_rings = GFX10_NUM_GFX_RINGS_NV1X;
+
        adev->gfx.num_compute_rings = AMDGPU_MAX_COMPUTE_RINGS;
 
        gfx_v10_0_set_kiq_pm4_funcs(adev);
index 3afdbbd..889154a 100644 (file)
@@ -3663,6 +3663,7 @@ static int gfx_v9_0_kcq_init_queue(struct amdgpu_ring *ring)
 
                /* reset ring buffer */
                ring->wptr = 0;
+               atomic64_set((atomic64_t *)&adev->wb.wb[ring->wptr_offs], 0);
                amdgpu_ring_clear_ring(ring);
        } else {
                amdgpu_ring_clear_ring(ring);
index 90216ab..cc0c273 100644 (file)
@@ -1272,6 +1272,19 @@ static void gmc_v9_0_init_golden_registers(struct amdgpu_device *adev)
 }
 
 /**
+ * gmc_v9_0_restore_registers - restores regs
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * This restores register values, saved at suspend.
+ */
+static void gmc_v9_0_restore_registers(struct amdgpu_device *adev)
+{
+       if (adev->asic_type == CHIP_RAVEN)
+               WREG32(mmDCHUBBUB_SDPIF_MMIO_CNTRL_0, adev->gmc.sdpif_register);
+}
+
+/**
  * gmc_v9_0_gart_enable - gart enable
  *
  * @adev: amdgpu_device pointer
@@ -1377,6 +1390,20 @@ static int gmc_v9_0_hw_init(void *handle)
 }
 
 /**
+ * gmc_v9_0_save_registers - saves regs
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * This saves potential register values that should be
+ * restored upon resume
+ */
+static void gmc_v9_0_save_registers(struct amdgpu_device *adev)
+{
+       if (adev->asic_type == CHIP_RAVEN)
+               adev->gmc.sdpif_register = RREG32(mmDCHUBBUB_SDPIF_MMIO_CNTRL_0);
+}
+
+/**
  * gmc_v9_0_gart_disable - gart disable
  *
  * @adev: amdgpu_device pointer
@@ -1412,9 +1439,16 @@ static int gmc_v9_0_hw_fini(void *handle)
 
 static int gmc_v9_0_suspend(void *handle)
 {
+       int r;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       return gmc_v9_0_hw_fini(adev);
+       r = gmc_v9_0_hw_fini(adev);
+       if (r)
+               return r;
+
+       gmc_v9_0_save_registers(adev);
+
+       return 0;
 }
 
 static int gmc_v9_0_resume(void *handle)
@@ -1422,6 +1456,7 @@ static int gmc_v9_0_resume(void *handle)
        int r;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       gmc_v9_0_restore_registers(adev);
        r = gmc_v9_0_hw_init(adev);
        if (r)
                return r;
index e8f66fb..e997251 100644 (file)
@@ -1422,6 +1422,73 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend)
                drm_kms_helper_hotplug_event(dev);
 }
 
+static int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev)
+{
+       struct smu_context *smu = &adev->smu;
+       int ret = 0;
+
+       if (!is_support_sw_smu(adev))
+               return 0;
+
+       /* This interface is for dGPU Navi1x.Linux dc-pplib interface depends
+        * on window driver dc implementation.
+        * For Navi1x, clock settings of dcn watermarks are fixed. the settings
+        * should be passed to smu during boot up and resume from s3.
+        * boot up: dc calculate dcn watermark clock settings within dc_create,
+        * dcn20_resource_construct
+        * then call pplib functions below to pass the settings to smu:
+        * smu_set_watermarks_for_clock_ranges
+        * smu_set_watermarks_table
+        * navi10_set_watermarks_table
+        * smu_write_watermarks_table
+        *
+        * For Renoir, clock settings of dcn watermark are also fixed values.
+        * dc has implemented different flow for window driver:
+        * dc_hardware_init / dc_set_power_state
+        * dcn10_init_hw
+        * notify_wm_ranges
+        * set_wm_ranges
+        * -- Linux
+        * smu_set_watermarks_for_clock_ranges
+        * renoir_set_watermarks_table
+        * smu_write_watermarks_table
+        *
+        * For Linux,
+        * dc_hardware_init -> amdgpu_dm_init
+        * dc_set_power_state --> dm_resume
+        *
+        * therefore, this function apply to navi10/12/14 but not Renoir
+        * *
+        */
+       switch(adev->asic_type) {
+       case CHIP_NAVI10:
+       case CHIP_NAVI14:
+       case CHIP_NAVI12:
+               break;
+       default:
+               return 0;
+       }
+
+       mutex_lock(&smu->mutex);
+
+       /* pass data to smu controller */
+       if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
+                       !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
+               ret = smu_write_watermarks_table(smu);
+
+               if (ret) {
+                       mutex_unlock(&smu->mutex);
+                       DRM_ERROR("Failed to update WMTABLE!\n");
+                       return ret;
+               }
+               smu->watermarks_bitmap |= WATERMARKS_LOADED;
+       }
+
+       mutex_unlock(&smu->mutex);
+
+       return 0;
+}
+
 /**
  * dm_hw_init() - Initialize DC device
  * @handle: The base driver device containing the amdgpu_dm device.
@@ -1700,6 +1767,8 @@ static int dm_resume(void *handle)
 
        amdgpu_dm_irq_resume_late(adev);
 
+       amdgpu_dm_smu_write_watermarks_table(adev);
+
        return 0;
 }
 
index 5672f77..da73161 100644 (file)
@@ -451,6 +451,7 @@ static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
                                           aconnector->dc_sink);
                dc_sink_release(aconnector->dc_sink);
                aconnector->dc_sink = NULL;
+               aconnector->dc_link->cur_link_settings.lane_count = 0;
        }
 
        drm_connector_unregister(connector);
index f36a0d8..446ba0a 100644 (file)
@@ -840,8 +840,8 @@ static void hubbub1_det_request_size(
 
        hubbub1_get_blk256_size(&blk256_width, &blk256_height, bpe);
 
-       swath_bytes_horz_wc = height * blk256_height * bpe;
-       swath_bytes_vert_wc = width * blk256_width * bpe;
+       swath_bytes_horz_wc = width * blk256_height * bpe;
+       swath_bytes_vert_wc = height * blk256_width * bpe;
 
        *req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ?
                        false : /* full 256B request */
index b6f74bf..27bb8c1 100644 (file)
 #define mmCRTC4_CRTC_DRR_CONTROL                                                                       0x0f3e
 #define mmCRTC4_CRTC_DRR_CONTROL_BASE_IDX                                                              2
 
+#define mmDCHUBBUB_SDPIF_MMIO_CNTRL_0                                                                  0x395d
+#define mmDCHUBBUB_SDPIF_MMIO_CNTRL_0_BASE_IDX                                                         2
 
 // addressBlock: dce_dc_fmt4_dispdec
 // base address: 0x2000
index 99ad4dd..ad8e9b5 100644 (file)
@@ -222,7 +222,7 @@ int smu_set_soft_freq_range(struct smu_context *smu, enum smu_clk_type clk_type,
 {
        int ret = 0;
 
-       if (min <= 0 && max <= 0)
+       if (min < 0 && max < 0)
                return -EINVAL;
 
        if (!smu_clk_dpm_is_enabled(smu, clk_type))
index 861e641..568c041 100644 (file)
@@ -111,8 +111,8 @@ static struct smu_12_0_cmn2aisc_mapping renoir_clk_map[SMU_CLK_COUNT] = {
        CLK_MAP(GFXCLK, CLOCK_GFXCLK),
        CLK_MAP(SCLK,   CLOCK_GFXCLK),
        CLK_MAP(SOCCLK, CLOCK_SOCCLK),
-       CLK_MAP(UCLK, CLOCK_UMCCLK),
-       CLK_MAP(MCLK, CLOCK_UMCCLK),
+       CLK_MAP(UCLK, CLOCK_FCLK),
+       CLK_MAP(MCLK, CLOCK_FCLK),
 };
 
 static struct smu_12_0_cmn2aisc_mapping renoir_table_map[SMU_TABLE_COUNT] = {
@@ -280,7 +280,7 @@ static int renoir_print_clk_levels(struct smu_context *smu,
                break;
        case SMU_MCLK:
                count = NUM_MEMCLK_DPM_LEVELS;
-               cur_value = metrics.ClockFrequency[CLOCK_UMCCLK];
+               cur_value = metrics.ClockFrequency[CLOCK_FCLK];
                break;
        case SMU_DCEFCLK:
                count = NUM_DCFCLK_DPM_LEVELS;
index b06c057..c9e5ce1 100644 (file)
@@ -978,8 +978,12 @@ int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu)
        struct smu_11_0_max_sustainable_clocks *max_sustainable_clocks;
        int ret = 0;
 
-       max_sustainable_clocks = kzalloc(sizeof(struct smu_11_0_max_sustainable_clocks),
+       if (!smu->smu_table.max_sustainable_clocks)
+               max_sustainable_clocks = kzalloc(sizeof(struct smu_11_0_max_sustainable_clocks),
                                         GFP_KERNEL);
+       else
+               max_sustainable_clocks = smu->smu_table.max_sustainable_clocks;
+
        smu->smu_table.max_sustainable_clocks = (void *)max_sustainable_clocks;
 
        max_sustainable_clocks->uclock = smu->smu_table.boot_values.uclk / 100;
index 870e6db..518e659 100644 (file)
@@ -458,9 +458,6 @@ int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_
 {
        int ret = 0;
 
-       if (max < min)
-               return -EINVAL;
-
        switch (clk_type) {
        case SMU_GFXCLK:
        case SMU_SCLK:
index 56f55c5..2dfa2fd 100644 (file)
@@ -210,8 +210,7 @@ static int anx6345_dp_link_training(struct anx6345 *anx6345)
        if (err)
                return err;
 
-       dpcd[0] = drm_dp_max_link_rate(anx6345->dpcd);
-       dpcd[0] = drm_dp_link_rate_to_bw_code(dpcd[0]);
+       dpcd[0] = dp_bw;
        err = regmap_write(anx6345->map[I2C_IDX_DPTX],
                           SP_DP_MAIN_LINK_BW_SET_REG, dpcd[0]);
        if (err)
index a421a2e..df31e57 100644 (file)
@@ -254,11 +254,16 @@ static void *drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem)
        if (ret)
                goto err_zero_use;
 
-       if (obj->import_attach)
+       if (obj->import_attach) {
                shmem->vaddr = dma_buf_vmap(obj->import_attach->dmabuf);
-       else
+       } else {
+               pgprot_t prot = PAGE_KERNEL;
+
+               if (!shmem->map_cached)
+                       prot = pgprot_writecombine(prot);
                shmem->vaddr = vmap(shmem->pages, obj->size >> PAGE_SHIFT,
-                                   VM_MAP, pgprot_writecombine(PAGE_KERNEL));
+                                   VM_MAP, prot);
+       }
 
        if (!shmem->vaddr) {
                DRM_DEBUG_KMS("Failed to vmap pages\n");
@@ -540,8 +545,9 @@ int drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
        }
 
        vma->vm_flags |= VM_MIXEDMAP | VM_DONTEXPAND;
-       vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
-       vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
+       vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+       if (!shmem->map_cached)
+               vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
        vma->vm_ops = &drm_gem_shmem_vm_ops;
 
        return 0;
index 33628d8..a85365c 100644 (file)
@@ -1773,8 +1773,9 @@ static int exynos_dsi_probe(struct platform_device *pdev)
        ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dsi->supplies),
                                      dsi->supplies);
        if (ret) {
-               dev_info(dev, "failed to get regulators: %d\n", ret);
-               return -EPROBE_DEFER;
+               if (ret != -EPROBE_DEFER)
+                       dev_info(dev, "failed to get regulators: %d\n", ret);
+               return ret;
        }
 
        dsi->clks = devm_kcalloc(dev,
@@ -1787,9 +1788,10 @@ static int exynos_dsi_probe(struct platform_device *pdev)
                dsi->clks[i] = devm_clk_get(dev, clk_names[i]);
                if (IS_ERR(dsi->clks[i])) {
                        if (strcmp(clk_names[i], "sclk_mipi") == 0) {
-                               strcpy(clk_names[i], OLD_SCLK_MIPI_CLK_NAME);
-                               i--;
-                               continue;
+                               dsi->clks[i] = devm_clk_get(dev,
+                                                       OLD_SCLK_MIPI_CLK_NAME);
+                               if (!IS_ERR(dsi->clks[i]))
+                                       continue;
                        }
 
                        dev_info(dev, "failed to get the clock: %s\n",
index 9ff921f..f141916 100644 (file)
@@ -1805,18 +1805,10 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
 
        hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
 
-       if (PTR_ERR(hdata->reg_hdmi_en) != -ENODEV) {
+       if (PTR_ERR(hdata->reg_hdmi_en) != -ENODEV)
                if (IS_ERR(hdata->reg_hdmi_en))
                        return PTR_ERR(hdata->reg_hdmi_en);
 
-               ret = regulator_enable(hdata->reg_hdmi_en);
-               if (ret) {
-                       DRM_DEV_ERROR(dev,
-                                     "failed to enable hdmi-en regulator\n");
-                       return ret;
-               }
-       }
-
        return hdmi_bridge_init(hdata);
 }
 
@@ -2023,6 +2015,15 @@ static int hdmi_probe(struct platform_device *pdev)
                }
        }
 
+       if (!IS_ERR(hdata->reg_hdmi_en)) {
+               ret = regulator_enable(hdata->reg_hdmi_en);
+               if (ret) {
+                       DRM_DEV_ERROR(dev,
+                             "failed to enable hdmi-en regulator\n");
+                       goto err_hdmiphy;
+               }
+       }
+
        pm_runtime_enable(dev);
 
        audio_infoframe = &hdata->audio.infoframe;
@@ -2047,7 +2048,8 @@ err_unregister_audio:
 
 err_rpm_disable:
        pm_runtime_disable(dev);
-
+       if (!IS_ERR(hdata->reg_hdmi_en))
+               regulator_disable(hdata->reg_hdmi_en);
 err_hdmiphy:
        if (hdata->hdmiphy_port)
                put_device(&hdata->hdmiphy_port->dev);
index 0da8602..e2ac098 100644 (file)
@@ -83,7 +83,6 @@
 #define VSIZE_OFST                     20
 #define LDI_INT_EN                     0x741C
 #define FRAME_END_INT_EN_OFST          1
-#define UNDERFLOW_INT_EN_OFST          2
 #define LDI_CTRL                       0x7420
 #define BPP_OFST                       3
 #define DATA_GATE_EN                   BIT(2)
index 73cd28a..8600012 100644 (file)
@@ -46,7 +46,6 @@ struct ade_hw_ctx {
        struct clk *media_noc_clk;
        struct clk *ade_pix_clk;
        struct reset_control *reset;
-       struct work_struct display_reset_wq;
        bool power_on;
        int irq;
 
@@ -136,7 +135,6 @@ static void ade_init(struct ade_hw_ctx *ctx)
         */
        ade_update_bits(base + ADE_CTRL, FRM_END_START_OFST,
                        FRM_END_START_MASK, REG_EFFECTIVE_IN_ADEEN_FRMEND);
-       ade_update_bits(base + LDI_INT_EN, UNDERFLOW_INT_EN_OFST, MASK(1), 1);
 }
 
 static bool ade_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -304,17 +302,6 @@ static void ade_crtc_disable_vblank(struct drm_crtc *crtc)
                        MASK(1), 0);
 }
 
-static void drm_underflow_wq(struct work_struct *work)
-{
-       struct ade_hw_ctx *ctx = container_of(work, struct ade_hw_ctx,
-                                             display_reset_wq);
-       struct drm_device *drm_dev = ctx->crtc->dev;
-       struct drm_atomic_state *state;
-
-       state = drm_atomic_helper_suspend(drm_dev);
-       drm_atomic_helper_resume(drm_dev, state);
-}
-
 static irqreturn_t ade_irq_handler(int irq, void *data)
 {
        struct ade_hw_ctx *ctx = data;
@@ -331,12 +318,6 @@ static irqreturn_t ade_irq_handler(int irq, void *data)
                                MASK(1), 1);
                drm_crtc_handle_vblank(crtc);
        }
-       if (status & BIT(UNDERFLOW_INT_EN_OFST)) {
-               ade_update_bits(base + LDI_INT_CLR, UNDERFLOW_INT_EN_OFST,
-                               MASK(1), 1);
-               DRM_ERROR("LDI underflow!");
-               schedule_work(&ctx->display_reset_wq);
-       }
 
        return IRQ_HANDLED;
 }
@@ -919,7 +900,6 @@ static void *ade_hw_ctx_alloc(struct platform_device *pdev,
        if (ret)
                return ERR_PTR(-EIO);
 
-       INIT_WORK(&ctx->display_reset_wq, drm_underflow_wq);
        ctx->crtc = crtc;
 
        return ctx;
index b8c5f89..a1f2411 100644 (file)
@@ -294,7 +294,7 @@ extra-$(CONFIG_DRM_I915_WERROR) += \
                $(shell cd $(srctree)/$(src) && find * -name '*.h')))
 
 quiet_cmd_hdrtest = HDRTEST $(patsubst %.hdrtest,%.h,$@)
-      cmd_hdrtest = $(CC) $(c_flags) -S -o /dev/null -x c /dev/null -include $<; touch $@
+      cmd_hdrtest = $(CC) $(filter-out $(CFLAGS_GCOV), $(c_flags)) -S -o /dev/null -x c /dev/null -include $<; touch $@
 
 $(obj)/%.hdrtest: $(src)/%.h FORCE
        $(call if_changed_dep,hdrtest)
index 21561ac..46c40db 100644 (file)
@@ -4466,13 +4466,19 @@ static void icl_dbuf_disable(struct drm_i915_private *dev_priv)
 
 static void icl_mbus_init(struct drm_i915_private *dev_priv)
 {
-       u32 val;
+       u32 mask, val;
 
-       val = MBUS_ABOX_BT_CREDIT_POOL1(16) |
-             MBUS_ABOX_BT_CREDIT_POOL2(16) |
-             MBUS_ABOX_B_CREDIT(1) |
-             MBUS_ABOX_BW_CREDIT(1);
+       mask = MBUS_ABOX_BT_CREDIT_POOL1_MASK |
+               MBUS_ABOX_BT_CREDIT_POOL2_MASK |
+               MBUS_ABOX_B_CREDIT_MASK |
+               MBUS_ABOX_BW_CREDIT_MASK;
 
+       val = I915_READ(MBUS_ABOX_CTL);
+       val &= ~mask;
+       val |= MBUS_ABOX_BT_CREDIT_POOL1(16) |
+               MBUS_ABOX_BT_CREDIT_POOL2(16) |
+               MBUS_ABOX_B_CREDIT(1) |
+               MBUS_ABOX_BW_CREDIT(1);
        I915_WRITE(MBUS_ABOX_CTL, val);
 }
 
@@ -4968,8 +4974,21 @@ static void tgl_bw_buddy_init(struct drm_i915_private *dev_priv)
                I915_WRITE(BW_BUDDY1_CTL, BW_BUDDY_DISABLE);
                I915_WRITE(BW_BUDDY2_CTL, BW_BUDDY_DISABLE);
        } else {
+               u32 val;
+
                I915_WRITE(BW_BUDDY1_PAGE_MASK, table[i].page_mask);
                I915_WRITE(BW_BUDDY2_PAGE_MASK, table[i].page_mask);
+
+               /* Wa_22010178259:tgl */
+               val = I915_READ(BW_BUDDY1_CTL);
+               val &= ~BW_BUDDY_TLB_REQ_TIMER_MASK;
+               val |= REG_FIELD_PREP(BW_BUDDY_TLB_REQ_TIMER_MASK, 0x8);
+               I915_WRITE(BW_BUDDY1_CTL, val);
+
+               val = I915_READ(BW_BUDDY2_CTL);
+               val &= ~BW_BUDDY_TLB_REQ_TIMER_MASK;
+               val |= REG_FIELD_PREP(BW_BUDDY_TLB_REQ_TIMER_MASK, 0x8);
+               I915_WRITE(BW_BUDDY2_CTL, val);
        }
 }
 
index 89c9cf5..8302505 100644 (file)
@@ -852,10 +852,12 @@ void intel_psr_enable(struct intel_dp *intel_dp,
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
 
-       if (!crtc_state->has_psr)
+       if (!CAN_PSR(dev_priv) || dev_priv->psr.dp != intel_dp)
                return;
 
-       if (WARN_ON(!CAN_PSR(dev_priv)))
+       dev_priv->psr.force_mode_changed = false;
+
+       if (!crtc_state->has_psr)
                return;
 
        WARN_ON(dev_priv->drrs.dp);
@@ -1009,6 +1011,8 @@ void intel_psr_update(struct intel_dp *intel_dp,
        if (!CAN_PSR(dev_priv) || READ_ONCE(psr->dp) != intel_dp)
                return;
 
+       dev_priv->psr.force_mode_changed = false;
+
        mutex_lock(&dev_priv->psr.lock);
 
        enable = crtc_state->has_psr && psr_global_enabled(psr->debug);
@@ -1534,7 +1538,7 @@ void intel_psr_atomic_check(struct drm_connector *connector,
        struct drm_crtc_state *crtc_state;
 
        if (!CAN_PSR(dev_priv) || !new_state->crtc ||
-           dev_priv->psr.initially_probed)
+           !dev_priv->psr.force_mode_changed)
                return;
 
        intel_connector = to_intel_connector(connector);
@@ -1545,5 +1549,18 @@ void intel_psr_atomic_check(struct drm_connector *connector,
        crtc_state = drm_atomic_get_new_crtc_state(new_state->state,
                                                   new_state->crtc);
        crtc_state->mode_changed = true;
-       dev_priv->psr.initially_probed = true;
+}
+
+void intel_psr_set_force_mode_changed(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv;
+
+       if (!intel_dp)
+               return;
+
+       dev_priv = dp_to_i915(intel_dp);
+       if (!CAN_PSR(dev_priv) || intel_dp != dev_priv->psr.dp)
+               return;
+
+       dev_priv->psr.force_mode_changed = true;
 }
index c58a1d4..274fc6b 100644 (file)
@@ -40,5 +40,6 @@ bool intel_psr_enabled(struct intel_dp *intel_dp);
 void intel_psr_atomic_check(struct drm_connector *connector,
                            struct drm_connector_state *old_state,
                            struct drm_connector_state *new_state);
+void intel_psr_set_force_mode_changed(struct intel_dp *intel_dp);
 
 #endif /* __INTEL_PSR_H__ */
index 3598521..5da9f9e 100644 (file)
@@ -225,6 +225,7 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915,
 
                /* But keep the pointer alive for RCU-protected lookups */
                call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
+               cond_resched();
        }
        intel_runtime_pm_put(&i915->runtime_pm, wakeref);
 }
index f7e4b39..59b387a 100644 (file)
@@ -256,8 +256,7 @@ unsigned long i915_gem_shrink_all(struct drm_i915_private *i915)
        with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
                freed = i915_gem_shrink(i915, -1UL, NULL,
                                        I915_SHRINK_BOUND |
-                                       I915_SHRINK_UNBOUND |
-                                       I915_SHRINK_ACTIVE);
+                                       I915_SHRINK_UNBOUND);
        }
 
        return freed;
@@ -336,7 +335,6 @@ i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr)
        freed_pages = 0;
        with_intel_runtime_pm(&i915->runtime_pm, wakeref)
                freed_pages += i915_gem_shrink(i915, -1UL, NULL,
-                                              I915_SHRINK_ACTIVE |
                                               I915_SHRINK_BOUND |
                                               I915_SHRINK_UNBOUND |
                                               I915_SHRINK_WRITEBACK);
index ef7c74c..43912e9 100644 (file)
@@ -570,7 +570,7 @@ static bool assert_mmap_offset(struct drm_i915_private *i915,
 
        obj = i915_gem_object_create_internal(i915, size);
        if (IS_ERR(obj))
-               return PTR_ERR(obj);
+               return false;
 
        mmo = mmap_offset_attach(obj, I915_MMAP_OFFSET_GTT, NULL);
        i915_gem_object_put(obj);
index 8a5054f..24c99d0 100644 (file)
@@ -147,24 +147,32 @@ long intel_gt_retire_requests_timeout(struct intel_gt *gt, long timeout)
 
                        fence = i915_active_fence_get(&tl->last_request);
                        if (fence) {
+                               mutex_unlock(&tl->mutex);
+
                                timeout = dma_fence_wait_timeout(fence,
                                                                 interruptible,
                                                                 timeout);
                                dma_fence_put(fence);
+
+                               /* Retirement is best effort */
+                               if (!mutex_trylock(&tl->mutex)) {
+                                       active_count++;
+                                       goto out_active;
+                               }
                        }
                }
 
                if (!retire_requests(tl) || flush_submission(gt))
                        active_count++;
+               mutex_unlock(&tl->mutex);
 
-               spin_lock(&timelines->lock);
+out_active:    spin_lock(&timelines->lock);
 
-               /* Resume iteration after dropping lock */
+               /* Resume list iteration after reacquiring spinlock */
                list_safe_reset_next(tl, tn, link);
                if (atomic_dec_and_test(&tl->active_count))
                        list_del(&tl->link);
 
-               mutex_unlock(&tl->mutex);
 
                /* Defer the final release to after the spinlock */
                if (refcount_dec_and_test(&tl->kref.refcount)) {
index 4e292d4..173a7f2 100644 (file)
@@ -575,24 +575,19 @@ static void icl_ctx_workarounds_init(struct intel_engine_cs *engine,
 static void tgl_ctx_workarounds_init(struct intel_engine_cs *engine,
                                     struct i915_wa_list *wal)
 {
-       u32 val;
-
        /* Wa_1409142259:tgl */
        WA_SET_BIT_MASKED(GEN11_COMMON_SLICE_CHICKEN3,
                          GEN12_DISABLE_CPS_AWARE_COLOR_PIPE);
 
-       /* Wa_1604555607:tgl */
-       val = intel_uncore_read(engine->uncore, FF_MODE2);
-       val &= ~FF_MODE2_TDS_TIMER_MASK;
-       val |= FF_MODE2_TDS_TIMER_128;
        /*
-        * FIXME: FF_MODE2 register is not readable till TGL B0. We can
-        * enable verification of WA from the later steppings, which enables
-        * the read of FF_MODE2.
+        * Wa_1604555607:gen12 and Wa_1608008084:gen12
+        * FF_MODE2 register will return the wrong value when read. The default
+        * value for this register is zero for all fields and there are no bit
+        * masks. So instead of doing a RMW we should just write the TDS timer
+        * value for Wa_1604555607.
         */
-       wa_add(wal, FF_MODE2, FF_MODE2_TDS_TIMER_MASK, val,
-              IS_TGL_REVID(engine->i915, TGL_REVID_A0, TGL_REVID_A0) ? 0 :
-                           FF_MODE2_TDS_TIMER_MASK);
+       wa_add(wal, FF_MODE2, FF_MODE2_TDS_TIMER_MASK,
+              FF_MODE2_TDS_TIMER_128, 0);
 }
 
 static void
index 2477a1e..ae139f0 100644 (file)
@@ -151,12 +151,12 @@ static void dmabuf_gem_object_free(struct kref *kref)
                        dmabuf_obj = container_of(pos,
                                        struct intel_vgpu_dmabuf_obj, list);
                        if (dmabuf_obj == obj) {
+                               list_del(pos);
                                intel_gvt_hypervisor_put_vfio_device(vgpu);
                                idr_remove(&vgpu->object_idr,
                                           dmabuf_obj->dmabuf_id);
                                kfree(dmabuf_obj->info);
                                kfree(dmabuf_obj);
-                               list_del(pos);
                                break;
                        }
                }
index 85bd9bf..487af6e 100644 (file)
@@ -560,9 +560,9 @@ void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr,
 
                intel_vgpu_reset_mmio(vgpu, dmlr);
                populate_pvinfo_page(vgpu);
-               intel_vgpu_reset_display(vgpu);
 
                if (dmlr) {
+                       intel_vgpu_reset_display(vgpu);
                        intel_vgpu_reset_cfg_space(vgpu);
                        /* only reset the failsafe mode when dmlr reset */
                        vgpu->failsafe = false;
index f7385ab..8410330 100644 (file)
@@ -56,6 +56,7 @@
 #include "display/intel_hotplug.h"
 #include "display/intel_overlay.h"
 #include "display/intel_pipe_crc.h"
+#include "display/intel_psr.h"
 #include "display/intel_sprite.h"
 #include "display/intel_vga.h"
 
@@ -330,6 +331,8 @@ static int i915_driver_modeset_probe(struct drm_i915_private *i915)
 
        intel_init_ipc(i915);
 
+       intel_psr_set_force_mode_changed(i915->psr.dp);
+
        return 0;
 
 cleanup_gem:
index 077af22..810e3cc 100644 (file)
@@ -505,7 +505,7 @@ struct i915_psr {
        bool dc3co_enabled;
        u32 dc3co_exit_delay;
        struct delayed_work idle_work;
-       bool initially_probed;
+       bool force_mode_changed;
 };
 
 #define QUIRK_LVDS_SSC_DISABLE (1<<1)
index 83f0140..f631f6d 100644 (file)
@@ -437,7 +437,7 @@ static const struct intel_device_info snb_m_gt2_info = {
        .has_rc6 = 1, \
        .has_rc6p = 1, \
        .has_rps = true, \
-       .ppgtt_type = INTEL_PPGTT_FULL, \
+       .ppgtt_type = INTEL_PPGTT_ALIASING, \
        .ppgtt_size = 31, \
        IVB_PIPE_OFFSETS, \
        IVB_CURSOR_OFFSETS, \
@@ -494,7 +494,7 @@ static const struct intel_device_info vlv_info = {
        .has_rps = true,
        .display.has_gmch = 1,
        .display.has_hotplug = 1,
-       .ppgtt_type = INTEL_PPGTT_FULL,
+       .ppgtt_type = INTEL_PPGTT_ALIASING,
        .ppgtt_size = 31,
        .has_snoop = true,
        .has_coherent_ggtt = false,
index 0f556d8..3b6b913 100644 (file)
@@ -1954,9 +1954,10 @@ out:
        return i915_vma_get(oa_bo->vma);
 }
 
-static int emit_oa_config(struct i915_perf_stream *stream,
-                         struct i915_oa_config *oa_config,
-                         struct intel_context *ce)
+static struct i915_request *
+emit_oa_config(struct i915_perf_stream *stream,
+              struct i915_oa_config *oa_config,
+              struct intel_context *ce)
 {
        struct i915_request *rq;
        struct i915_vma *vma;
@@ -1964,7 +1965,7 @@ static int emit_oa_config(struct i915_perf_stream *stream,
 
        vma = get_oa_vma(stream, oa_config);
        if (IS_ERR(vma))
-               return PTR_ERR(vma);
+               return ERR_CAST(vma);
 
        err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL | PIN_HIGH);
        if (err)
@@ -1989,13 +1990,17 @@ static int emit_oa_config(struct i915_perf_stream *stream,
        err = rq->engine->emit_bb_start(rq,
                                        vma->node.start, 0,
                                        I915_DISPATCH_SECURE);
+       if (err)
+               goto err_add_request;
+
+       i915_request_get(rq);
 err_add_request:
        i915_request_add(rq);
 err_vma_unpin:
        i915_vma_unpin(vma);
 err_vma_put:
        i915_vma_put(vma);
-       return err;
+       return err ? ERR_PTR(err) : rq;
 }
 
 static struct intel_context *oa_context(struct i915_perf_stream *stream)
@@ -2003,7 +2008,8 @@ static struct intel_context *oa_context(struct i915_perf_stream *stream)
        return stream->pinned_ctx ?: stream->engine->kernel_context;
 }
 
-static int hsw_enable_metric_set(struct i915_perf_stream *stream)
+static struct i915_request *
+hsw_enable_metric_set(struct i915_perf_stream *stream)
 {
        struct intel_uncore *uncore = stream->uncore;
 
@@ -2406,7 +2412,8 @@ static int lrc_configure_all_contexts(struct i915_perf_stream *stream,
        return oa_configure_all_contexts(stream, regs, ARRAY_SIZE(regs));
 }
 
-static int gen8_enable_metric_set(struct i915_perf_stream *stream)
+static struct i915_request *
+gen8_enable_metric_set(struct i915_perf_stream *stream)
 {
        struct intel_uncore *uncore = stream->uncore;
        struct i915_oa_config *oa_config = stream->oa_config;
@@ -2448,7 +2455,7 @@ static int gen8_enable_metric_set(struct i915_perf_stream *stream)
         */
        ret = lrc_configure_all_contexts(stream, oa_config);
        if (ret)
-               return ret;
+               return ERR_PTR(ret);
 
        return emit_oa_config(stream, oa_config, oa_context(stream));
 }
@@ -2460,7 +2467,8 @@ static u32 oag_report_ctx_switches(const struct i915_perf_stream *stream)
                             0 : GEN12_OAG_OA_DEBUG_DISABLE_CTX_SWITCH_REPORTS);
 }
 
-static int gen12_enable_metric_set(struct i915_perf_stream *stream)
+static struct i915_request *
+gen12_enable_metric_set(struct i915_perf_stream *stream)
 {
        struct intel_uncore *uncore = stream->uncore;
        struct i915_oa_config *oa_config = stream->oa_config;
@@ -2491,7 +2499,7 @@ static int gen12_enable_metric_set(struct i915_perf_stream *stream)
         */
        ret = gen12_configure_all_contexts(stream, oa_config);
        if (ret)
-               return ret;
+               return ERR_PTR(ret);
 
        /*
         * For Gen12, performance counters are context
@@ -2501,7 +2509,7 @@ static int gen12_enable_metric_set(struct i915_perf_stream *stream)
        if (stream->ctx) {
                ret = gen12_configure_oar_context(stream, true);
                if (ret)
-                       return ret;
+                       return ERR_PTR(ret);
        }
 
        return emit_oa_config(stream, oa_config, oa_context(stream));
@@ -2696,6 +2704,20 @@ static const struct i915_perf_stream_ops i915_oa_stream_ops = {
        .read = i915_oa_read,
 };
 
+static int i915_perf_stream_enable_sync(struct i915_perf_stream *stream)
+{
+       struct i915_request *rq;
+
+       rq = stream->perf->ops.enable_metric_set(stream);
+       if (IS_ERR(rq))
+               return PTR_ERR(rq);
+
+       i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT);
+       i915_request_put(rq);
+
+       return 0;
+}
+
 /**
  * i915_oa_stream_init - validate combined props for OA stream and init
  * @stream: An i915 perf stream
@@ -2829,7 +2851,7 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
        stream->ops = &i915_oa_stream_ops;
        perf->exclusive_stream = stream;
 
-       ret = perf->ops.enable_metric_set(stream);
+       ret = i915_perf_stream_enable_sync(stream);
        if (ret) {
                DRM_DEBUG("Unable to enable metric set\n");
                goto err_enable;
@@ -3147,7 +3169,7 @@ static long i915_perf_config_locked(struct i915_perf_stream *stream,
                return -EINVAL;
 
        if (config != stream->oa_config) {
-               int err;
+               struct i915_request *rq;
 
                /*
                 * If OA is bound to a specific context, emit the
@@ -3158,11 +3180,13 @@ static long i915_perf_config_locked(struct i915_perf_stream *stream,
                 * When set globally, we use a low priority kernel context,
                 * so it will effectively take effect when idle.
                 */
-               err = emit_oa_config(stream, config, oa_context(stream));
-               if (err == 0)
+               rq = emit_oa_config(stream, config, oa_context(stream));
+               if (!IS_ERR(rq)) {
                        config = xchg(&stream->oa_config, config);
-               else
-                       ret = err;
+                       i915_request_put(rq);
+               } else {
+                       ret = PTR_ERR(rq);
+               }
        }
 
        i915_oa_config_put(config);
index 45e5814..a0e22f0 100644 (file)
@@ -339,7 +339,8 @@ struct i915_oa_ops {
         * counter reports being sampled. May apply system constraints such as
         * disabling EU clock gating as required.
         */
-       int (*enable_metric_set)(struct i915_perf_stream *stream);
+       struct i915_request *
+               (*enable_metric_set)(struct i915_perf_stream *stream);
 
        /**
         * @disable_metric_set: Remove system constraints associated with using
index ec02994..aa729d0 100644 (file)
@@ -822,11 +822,6 @@ static ssize_t i915_pmu_event_show(struct device *dev,
        return sprintf(buf, "config=0x%lx\n", eattr->val);
 }
 
-static struct attribute_group i915_pmu_events_attr_group = {
-       .name = "events",
-       /* Patch in attrs at runtime. */
-};
-
 static ssize_t
 i915_pmu_get_attr_cpumask(struct device *dev,
                          struct device_attribute *attr,
@@ -846,13 +841,6 @@ static const struct attribute_group i915_pmu_cpumask_attr_group = {
        .attrs = i915_cpumask_attrs,
 };
 
-static const struct attribute_group *i915_pmu_attr_groups[] = {
-       &i915_pmu_format_attr_group,
-       &i915_pmu_events_attr_group,
-       &i915_pmu_cpumask_attr_group,
-       NULL
-};
-
 #define __event(__config, __name, __unit) \
 { \
        .config = (__config), \
@@ -1026,23 +1014,23 @@ err_alloc:
 
 static void free_event_attributes(struct i915_pmu *pmu)
 {
-       struct attribute **attr_iter = i915_pmu_events_attr_group.attrs;
+       struct attribute **attr_iter = pmu->events_attr_group.attrs;
 
        for (; *attr_iter; attr_iter++)
                kfree((*attr_iter)->name);
 
-       kfree(i915_pmu_events_attr_group.attrs);
+       kfree(pmu->events_attr_group.attrs);
        kfree(pmu->i915_attr);
        kfree(pmu->pmu_attr);
 
-       i915_pmu_events_attr_group.attrs = NULL;
+       pmu->events_attr_group.attrs = NULL;
        pmu->i915_attr = NULL;
        pmu->pmu_attr = NULL;
 }
 
 static int i915_pmu_cpu_online(unsigned int cpu, struct hlist_node *node)
 {
-       struct i915_pmu *pmu = hlist_entry_safe(node, typeof(*pmu), node);
+       struct i915_pmu *pmu = hlist_entry_safe(node, typeof(*pmu), cpuhp.node);
 
        GEM_BUG_ON(!pmu->base.event_init);
 
@@ -1055,7 +1043,7 @@ static int i915_pmu_cpu_online(unsigned int cpu, struct hlist_node *node)
 
 static int i915_pmu_cpu_offline(unsigned int cpu, struct hlist_node *node)
 {
-       struct i915_pmu *pmu = hlist_entry_safe(node, typeof(*pmu), node);
+       struct i915_pmu *pmu = hlist_entry_safe(node, typeof(*pmu), cpuhp.node);
        unsigned int target;
 
        GEM_BUG_ON(!pmu->base.event_init);
@@ -1072,8 +1060,6 @@ static int i915_pmu_cpu_offline(unsigned int cpu, struct hlist_node *node)
        return 0;
 }
 
-static enum cpuhp_state cpuhp_slot = CPUHP_INVALID;
-
 static int i915_pmu_register_cpuhp_state(struct i915_pmu *pmu)
 {
        enum cpuhp_state slot;
@@ -1087,21 +1073,22 @@ static int i915_pmu_register_cpuhp_state(struct i915_pmu *pmu)
                return ret;
 
        slot = ret;
-       ret = cpuhp_state_add_instance(slot, &pmu->node);
+       ret = cpuhp_state_add_instance(slot, &pmu->cpuhp.node);
        if (ret) {
                cpuhp_remove_multi_state(slot);
                return ret;
        }
 
-       cpuhp_slot = slot;
+       pmu->cpuhp.slot = slot;
        return 0;
 }
 
 static void i915_pmu_unregister_cpuhp_state(struct i915_pmu *pmu)
 {
-       WARN_ON(cpuhp_slot == CPUHP_INVALID);
-       WARN_ON(cpuhp_state_remove_instance(cpuhp_slot, &pmu->node));
-       cpuhp_remove_multi_state(cpuhp_slot);
+       WARN_ON(pmu->cpuhp.slot == CPUHP_INVALID);
+       WARN_ON(cpuhp_state_remove_instance(pmu->cpuhp.slot, &pmu->cpuhp.node));
+       cpuhp_remove_multi_state(pmu->cpuhp.slot);
+       pmu->cpuhp.slot = CPUHP_INVALID;
 }
 
 static bool is_igp(struct drm_i915_private *i915)
@@ -1118,6 +1105,13 @@ static bool is_igp(struct drm_i915_private *i915)
 void i915_pmu_register(struct drm_i915_private *i915)
 {
        struct i915_pmu *pmu = &i915->pmu;
+       const struct attribute_group *attr_groups[] = {
+               &i915_pmu_format_attr_group,
+               &pmu->events_attr_group,
+               &i915_pmu_cpumask_attr_group,
+               NULL
+       };
+
        int ret = -ENOMEM;
 
        if (INTEL_GEN(i915) <= 2) {
@@ -1128,6 +1122,7 @@ void i915_pmu_register(struct drm_i915_private *i915)
        spin_lock_init(&pmu->lock);
        hrtimer_init(&pmu->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        pmu->timer.function = i915_sample;
+       pmu->cpuhp.slot = CPUHP_INVALID;
 
        if (!is_igp(i915)) {
                pmu->name = kasprintf(GFP_KERNEL,
@@ -1143,11 +1138,16 @@ void i915_pmu_register(struct drm_i915_private *i915)
        if (!pmu->name)
                goto err;
 
-       i915_pmu_events_attr_group.attrs = create_event_attributes(pmu);
-       if (!i915_pmu_events_attr_group.attrs)
+       pmu->events_attr_group.name = "events";
+       pmu->events_attr_group.attrs = create_event_attributes(pmu);
+       if (!pmu->events_attr_group.attrs)
                goto err_name;
 
-       pmu->base.attr_groups   = i915_pmu_attr_groups;
+       pmu->base.attr_groups = kmemdup(attr_groups, sizeof(attr_groups),
+                                       GFP_KERNEL);
+       if (!pmu->base.attr_groups)
+               goto err_attr;
+
        pmu->base.task_ctx_nr   = perf_invalid_context;
        pmu->base.event_init    = i915_pmu_event_init;
        pmu->base.add           = i915_pmu_event_add;
@@ -1159,7 +1159,7 @@ void i915_pmu_register(struct drm_i915_private *i915)
 
        ret = perf_pmu_register(&pmu->base, pmu->name, -1);
        if (ret)
-               goto err_attr;
+               goto err_groups;
 
        ret = i915_pmu_register_cpuhp_state(pmu);
        if (ret)
@@ -1169,6 +1169,8 @@ void i915_pmu_register(struct drm_i915_private *i915)
 
 err_unreg:
        perf_pmu_unregister(&pmu->base);
+err_groups:
+       kfree(pmu->base.attr_groups);
 err_attr:
        pmu->base.event_init = NULL;
        free_event_attributes(pmu);
@@ -1194,6 +1196,7 @@ void i915_pmu_unregister(struct drm_i915_private *i915)
 
        perf_pmu_unregister(&pmu->base);
        pmu->base.event_init = NULL;
+       kfree(pmu->base.attr_groups);
        if (!is_igp(i915))
                kfree(pmu->name);
        free_event_attributes(pmu);
index 6c1647c..f1d6cad 100644 (file)
@@ -39,9 +39,12 @@ struct i915_pmu_sample {
 
 struct i915_pmu {
        /**
-        * @node: List node for CPU hotplug handling.
+        * @cpuhp: Struct used for CPU hotplug handling.
         */
-       struct hlist_node node;
+       struct {
+               struct hlist_node node;
+               enum cpuhp_state slot;
+       } cpuhp;
        /**
         * @base: PMU base.
         */
@@ -105,6 +108,10 @@ struct i915_pmu {
         */
        ktime_t sleep_last;
        /**
+        * @events_attr_group: Device events attribute group.
+        */
+       struct attribute_group events_attr_group;
+       /**
         * @i915_attr: Memory block holding device attributes.
         */
        void *i915_attr;
index 6cc55c1..3575fd3 100644 (file)
@@ -7757,6 +7757,7 @@ enum {
 #define BW_BUDDY1_CTL                  _MMIO(0x45140)
 #define BW_BUDDY2_CTL                  _MMIO(0x45150)
 #define   BW_BUDDY_DISABLE             REG_BIT(31)
+#define   BW_BUDDY_TLB_REQ_TIMER_MASK  REG_GENMASK(21, 16)
 
 #define BW_BUDDY1_PAGE_MASK            _MMIO(0x45144)
 #define BW_BUDDY2_PAGE_MASK            _MMIO(0x45154)
index f56b046..dcaa85a 100644 (file)
@@ -275,7 +275,7 @@ bool i915_request_retire(struct i915_request *rq)
        spin_unlock_irq(&rq->lock);
 
        remove_from_client(rq);
-       list_del(&rq->link);
+       list_del_rcu(&rq->link);
 
        intel_context_exit(rq->context);
        intel_context_unpin(rq->context);
@@ -721,6 +721,8 @@ __i915_request_create(struct intel_context *ce, gfp_t gfp)
        rq->infix = rq->ring->emit; /* end of header; start of user payload */
 
        intel_context_mark_active(ce);
+       list_add_tail_rcu(&rq->link, &tl->requests);
+
        return rq;
 
 err_unwind:
@@ -777,13 +779,23 @@ i915_request_await_start(struct i915_request *rq, struct i915_request *signal)
        GEM_BUG_ON(i915_request_timeline(rq) ==
                   rcu_access_pointer(signal->timeline));
 
+       if (i915_request_started(signal))
+               return 0;
+
        fence = NULL;
        rcu_read_lock();
        spin_lock_irq(&signal->lock);
-       if (!i915_request_started(signal) &&
-           !list_is_first(&signal->link,
-                          &rcu_dereference(signal->timeline)->requests)) {
-               struct i915_request *prev = list_prev_entry(signal, link);
+       do {
+               struct list_head *pos = READ_ONCE(signal->link.prev);
+               struct i915_request *prev;
+
+               /* Confirm signal has not been retired, the link is valid */
+               if (unlikely(i915_request_started(signal)))
+                       break;
+
+               /* Is signal the earliest request on its timeline? */
+               if (pos == &rcu_dereference(signal->timeline)->requests)
+                       break;
 
                /*
                 * Peek at the request before us in the timeline. That
@@ -791,13 +803,18 @@ i915_request_await_start(struct i915_request *rq, struct i915_request *signal)
                 * after acquiring a reference to it, confirm that it is
                 * still part of the signaler's timeline.
                 */
-               if (i915_request_get_rcu(prev)) {
-                       if (list_next_entry(prev, link) == signal)
-                               fence = &prev->fence;
-                       else
-                               i915_request_put(prev);
+               prev = list_entry(pos, typeof(*prev), link);
+               if (!i915_request_get_rcu(prev))
+                       break;
+
+               /* After the strong barrier, confirm prev is still attached */
+               if (unlikely(READ_ONCE(prev->link.next) != &signal->link)) {
+                       i915_request_put(prev);
+                       break;
                }
-       }
+
+               fence = &prev->fence;
+       } while (0);
        spin_unlock_irq(&signal->lock);
        rcu_read_unlock();
        if (!fence)
@@ -1242,8 +1259,6 @@ __i915_request_add_to_timeline(struct i915_request *rq)
                                                         0);
        }
 
-       list_add_tail(&rq->link, &timeline->requests);
-
        /*
         * Make sure that no request gazumped us - if it was allocated after
         * our i915_request_alloc() and called __i915_request_add() before
index 0dfcd17..fe85e48 100644 (file)
@@ -486,6 +486,7 @@ static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc)
        }
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
        if (mtk_crtc->cmdq_client) {
+               mbox_flush(mtk_crtc->cmdq_client->chan, 2000);
                cmdq_handle = cmdq_pkt_create(mtk_crtc->cmdq_client, PAGE_SIZE);
                cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event);
                cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event);
@@ -636,10 +637,18 @@ static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = {
 
 static int mtk_drm_crtc_init(struct drm_device *drm,
                             struct mtk_drm_crtc *mtk_crtc,
-                            struct drm_plane *primary,
-                            struct drm_plane *cursor, unsigned int pipe)
+                            unsigned int pipe)
 {
-       int ret;
+       struct drm_plane *primary = NULL;
+       struct drm_plane *cursor = NULL;
+       int i, ret;
+
+       for (i = 0; i < mtk_crtc->layer_nr; i++) {
+               if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_PRIMARY)
+                       primary = &mtk_crtc->planes[i];
+               else if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_CURSOR)
+                       cursor = &mtk_crtc->planes[i];
+       }
 
        ret = drm_crtc_init_with_planes(drm, &mtk_crtc->base, primary, cursor,
                                        &mtk_crtc_funcs, NULL);
@@ -689,11 +698,12 @@ static int mtk_drm_crtc_num_comp_planes(struct mtk_drm_crtc *mtk_crtc,
 }
 
 static inline
-enum drm_plane_type mtk_drm_crtc_plane_type(unsigned int plane_idx)
+enum drm_plane_type mtk_drm_crtc_plane_type(unsigned int plane_idx,
+                                           unsigned int num_planes)
 {
        if (plane_idx == 0)
                return DRM_PLANE_TYPE_PRIMARY;
-       else if (plane_idx == 1)
+       else if (plane_idx == (num_planes - 1))
                return DRM_PLANE_TYPE_CURSOR;
        else
                return DRM_PLANE_TYPE_OVERLAY;
@@ -712,7 +722,8 @@ static int mtk_drm_crtc_init_comp_planes(struct drm_device *drm_dev,
                ret = mtk_plane_init(drm_dev,
                                &mtk_crtc->planes[mtk_crtc->layer_nr],
                                BIT(pipe),
-                               mtk_drm_crtc_plane_type(mtk_crtc->layer_nr),
+                               mtk_drm_crtc_plane_type(mtk_crtc->layer_nr,
+                                                       num_planes),
                                mtk_ddp_comp_supported_rotations(comp));
                if (ret)
                        return ret;
@@ -807,9 +818,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
                        return ret;
        }
 
-       ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, &mtk_crtc->planes[0],
-                               mtk_crtc->layer_nr > 1 ? &mtk_crtc->planes[1] :
-                               NULL, pipe);
+       ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, pipe);
        if (ret < 0)
                return ret;
 
@@ -828,7 +837,8 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
                        drm_crtc_index(&mtk_crtc->base));
                mtk_crtc->cmdq_client = NULL;
        }
-       ret = of_property_read_u32_index(dev->of_node, "mediatek,gce-events",
+       ret = of_property_read_u32_index(priv->mutex_node,
+                                        "mediatek,gce-events",
                                         drm_crtc_index(&mtk_crtc->base),
                                         &mtk_crtc->cmdq_event);
        if (ret)
index 1f5a112..57c88de 100644 (file)
@@ -471,6 +471,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
        /* Only DMA capable components need the LARB property */
        comp->larb_dev = NULL;
        if (type != MTK_DISP_OVL &&
+           type != MTK_DISP_OVL_2L &&
            type != MTK_DISP_RDMA &&
            type != MTK_DISP_WDMA)
                return 0;
index 914cc76..c2bd683 100644 (file)
@@ -80,6 +80,7 @@ static int mtk_plane_atomic_async_check(struct drm_plane *plane,
                                        struct drm_plane_state *state)
 {
        struct drm_crtc_state *crtc_state;
+       int ret;
 
        if (plane != state->crtc->cursor)
                return -EINVAL;
@@ -90,6 +91,11 @@ static int mtk_plane_atomic_async_check(struct drm_plane *plane,
        if (!plane->state->fb)
                return -EINVAL;
 
+       ret = mtk_drm_crtc_plane_check(state->crtc, plane,
+                                      to_mtk_plane_state(state));
+       if (ret)
+               return ret;
+
        if (state->state)
                crtc_state = drm_atomic_get_existing_crtc_state(state->state,
                                                                state->crtc);
@@ -115,6 +121,7 @@ static void mtk_plane_atomic_async_update(struct drm_plane *plane,
        plane->state->src_y = new_state->src_y;
        plane->state->src_h = new_state->src_h;
        plane->state->src_w = new_state->src_w;
+       swap(plane->state->fb, new_state->fb);
        state->pending.async_dirty = true;
 
        mtk_drm_crtc_async_update(new_state->crtc, plane, new_state);
index 3107b07..5d75f8c 100644 (file)
@@ -601,33 +601,27 @@ static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data)
                source_id = (fault_status >> 16);
 
                /* Page fault only */
-               if ((status & mask) == BIT(i)) {
-                       WARN_ON(exception_type < 0xC1 || exception_type > 0xC4);
-
+               ret = -1;
+               if ((status & mask) == BIT(i) && (exception_type & 0xF8) == 0xC0)
                        ret = panfrost_mmu_map_fault_addr(pfdev, i, addr);
-                       if (!ret) {
-                               mmu_write(pfdev, MMU_INT_CLEAR, BIT(i));
-                               status &= ~mask;
-                               continue;
-                       }
-               }
 
-               /* terminal fault, print info about the fault */
-               dev_err(pfdev->dev,
-                       "Unhandled Page fault in AS%d at VA 0x%016llX\n"
-                       "Reason: %s\n"
-                       "raw fault status: 0x%X\n"
-                       "decoded fault status: %s\n"
-                       "exception type 0x%X: %s\n"
-                       "access type 0x%X: %s\n"
-                       "source id 0x%X\n",
-                       i, addr,
-                       "TODO",
-                       fault_status,
-                       (fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"),
-                       exception_type, panfrost_exception_name(pfdev, exception_type),
-                       access_type, access_type_name(pfdev, fault_status),
-                       source_id);
+               if (ret)
+                       /* terminal fault, print info about the fault */
+                       dev_err(pfdev->dev,
+                               "Unhandled Page fault in AS%d at VA 0x%016llX\n"
+                               "Reason: %s\n"
+                               "raw fault status: 0x%X\n"
+                               "decoded fault status: %s\n"
+                               "exception type 0x%X: %s\n"
+                               "access type 0x%X: %s\n"
+                               "source id 0x%X\n",
+                               i, addr,
+                               "TODO",
+                               fault_status,
+                               (fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"),
+                               exception_type, panfrost_exception_name(pfdev, exception_type),
+                               access_type, access_type_name(pfdev, fault_status),
+                               source_id);
 
                mmu_write(pfdev, MMU_INT_CLEAR, mask);
 
index fd74e26..8696af1 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/vga_switcheroo.h>
 #include <linux/mmu_notifier.h>
 
+#include <drm/drm_agpsupport.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_fb_helper.h>
@@ -325,6 +326,7 @@ static int radeon_pci_probe(struct pci_dev *pdev,
                            const struct pci_device_id *ent)
 {
        unsigned long flags = 0;
+       struct drm_device *dev;
        int ret;
 
        if (!ent)
@@ -365,7 +367,44 @@ static int radeon_pci_probe(struct pci_dev *pdev,
        if (ret)
                return ret;
 
-       return drm_get_pci_dev(pdev, ent, &kms_driver);
+       dev = drm_dev_alloc(&kms_driver, &pdev->dev);
+       if (IS_ERR(dev))
+               return PTR_ERR(dev);
+
+       ret = pci_enable_device(pdev);
+       if (ret)
+               goto err_free;
+
+       dev->pdev = pdev;
+#ifdef __alpha__
+       dev->hose = pdev->sysdata;
+#endif
+
+       pci_set_drvdata(pdev, dev);
+
+       if (pci_find_capability(dev->pdev, PCI_CAP_ID_AGP))
+               dev->agp = drm_agp_init(dev);
+       if (dev->agp) {
+               dev->agp->agp_mtrr = arch_phys_wc_add(
+                       dev->agp->agp_info.aper_base,
+                       dev->agp->agp_info.aper_size *
+                       1024 * 1024);
+       }
+
+       ret = drm_dev_register(dev, ent->driver_data);
+       if (ret)
+               goto err_agp;
+
+       return 0;
+
+err_agp:
+       if (dev->agp)
+               arch_phys_wc_del(dev->agp->agp_mtrr);
+       kfree(dev->agp);
+       pci_disable_device(pdev);
+err_free:
+       drm_dev_put(dev);
+       return ret;
 }
 
 static void
@@ -575,7 +614,7 @@ radeon_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe,
 
 static struct drm_driver kms_driver = {
        .driver_features =
-           DRIVER_USE_AGP | DRIVER_GEM | DRIVER_RENDER,
+           DRIVER_GEM | DRIVER_RENDER,
        .load = radeon_driver_load_kms,
        .open = radeon_driver_open_kms,
        .postclose = radeon_driver_postclose_kms,
index d24f23a..dd2f19b 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/uaccess.h>
 #include <linux/vga_switcheroo.h>
 
+#include <drm/drm_agpsupport.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_file.h>
 #include <drm/drm_ioctl.h>
@@ -77,6 +78,11 @@ void radeon_driver_unload_kms(struct drm_device *dev)
        radeon_modeset_fini(rdev);
        radeon_device_fini(rdev);
 
+       if (dev->agp)
+               arch_phys_wc_del(dev->agp->agp_mtrr);
+       kfree(dev->agp);
+       dev->agp = NULL;
+
 done_free:
        kfree(rdev);
        dev->dev_private = NULL;
index 7c24f8f..4a64f7a 100644 (file)
@@ -107,48 +107,128 @@ static const struct de2_fmt_info de2_formats[] = {
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_XRGB4444,
+               .de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_ABGR4444,
                .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
                .rgb = true,
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_XBGR4444,
+               .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_RGBA4444,
                .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
                .rgb = true,
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_RGBX4444,
+               .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_BGRA4444,
                .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
                .rgb = true,
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_BGRX4444,
+               .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_ARGB1555,
                .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
                .rgb = true,
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_XRGB1555,
+               .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_ABGR1555,
                .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
                .rgb = true,
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_XBGR1555,
+               .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_RGBA5551,
                .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
                .rgb = true,
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_RGBX5551,
+               .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_BGRA5551,
                .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
                .rgb = true,
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_BGRX5551,
+               .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
+               .drm_fmt = DRM_FORMAT_ARGB2101010,
+               .de2_fmt = SUN8I_MIXER_FBFMT_ARGB2101010,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
+               .drm_fmt = DRM_FORMAT_ABGR2101010,
+               .de2_fmt = SUN8I_MIXER_FBFMT_ABGR2101010,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
+               .drm_fmt = DRM_FORMAT_RGBA1010102,
+               .de2_fmt = SUN8I_MIXER_FBFMT_RGBA1010102,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
+               .drm_fmt = DRM_FORMAT_BGRA1010102,
+               .de2_fmt = SUN8I_MIXER_FBFMT_BGRA1010102,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_UYVY,
                .de2_fmt = SUN8I_MIXER_FBFMT_UYVY,
                .rgb = false,
@@ -197,12 +277,6 @@ static const struct de2_fmt_info de2_formats[] = {
                .csc = SUN8I_CSC_MODE_YUV2RGB,
        },
        {
-               .drm_fmt = DRM_FORMAT_YUV444,
-               .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
-               .rgb = true,
-               .csc = SUN8I_CSC_MODE_YUV2RGB,
-       },
-       {
                .drm_fmt = DRM_FORMAT_YUV422,
                .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
                .rgb = false,
@@ -221,12 +295,6 @@ static const struct de2_fmt_info de2_formats[] = {
                .csc = SUN8I_CSC_MODE_YUV2RGB,
        },
        {
-               .drm_fmt = DRM_FORMAT_YVU444,
-               .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
-               .rgb = true,
-               .csc = SUN8I_CSC_MODE_YVU2RGB,
-       },
-       {
                .drm_fmt = DRM_FORMAT_YVU422,
                .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
                .rgb = false,
@@ -244,6 +312,18 @@ static const struct de2_fmt_info de2_formats[] = {
                .rgb = false,
                .csc = SUN8I_CSC_MODE_YVU2RGB,
        },
+       {
+               .drm_fmt = DRM_FORMAT_P010,
+               .de2_fmt = SUN8I_MIXER_FBFMT_P010_YUV,
+               .rgb = false,
+               .csc = SUN8I_CSC_MODE_YUV2RGB,
+       },
+       {
+               .drm_fmt = DRM_FORMAT_P210,
+               .de2_fmt = SUN8I_MIXER_FBFMT_P210_YUV,
+               .rgb = false,
+               .csc = SUN8I_CSC_MODE_YUV2RGB,
+       },
 };
 
 const struct de2_fmt_info *sun8i_mixer_format_info(u32 format)
index c6cc940..345b28b 100644 (file)
 #define SUN8I_MIXER_FBFMT_ABGR1555     17
 #define SUN8I_MIXER_FBFMT_RGBA5551     18
 #define SUN8I_MIXER_FBFMT_BGRA5551     19
+#define SUN8I_MIXER_FBFMT_ARGB2101010  20
+#define SUN8I_MIXER_FBFMT_ABGR2101010  21
+#define SUN8I_MIXER_FBFMT_RGBA1010102  22
+#define SUN8I_MIXER_FBFMT_BGRA1010102  23
 
 #define SUN8I_MIXER_FBFMT_YUYV         0
 #define SUN8I_MIXER_FBFMT_UYVY         1
 /* format 12 is semi-planar YUV411 UVUV */
 /* format 13 is semi-planar YUV411 VUVU */
 #define SUN8I_MIXER_FBFMT_YUV411       14
+/* format 15 doesn't exist */
+/* format 16 is P010 YVU */
+#define SUN8I_MIXER_FBFMT_P010_YUV     17
+/* format 18 is P210 YVU */
+#define SUN8I_MIXER_FBFMT_P210_YUV     19
+/* format 20 is packed YVU444 10-bit */
+/* format 21 is packed YUV444 10-bit */
 
 /*
  * Sub-engines listed bellow are unused for now. The EN registers are here only
index 42d445d..b8398ca 100644 (file)
@@ -398,24 +398,66 @@ static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
 };
 
 /*
- * While all RGB formats are supported, VI planes don't support
- * alpha blending, so there is no point having formats with alpha
- * channel if their opaque analog exist.
+ * While DE2 VI layer supports same RGB formats as UI layer, alpha
+ * channel is ignored. This structure lists all unique variants
+ * where alpha channel is replaced with "don't care" (X) channel.
  */
 static const u32 sun8i_vi_layer_formats[] = {
+       DRM_FORMAT_BGR565,
+       DRM_FORMAT_BGR888,
+       DRM_FORMAT_BGRX4444,
+       DRM_FORMAT_BGRX5551,
+       DRM_FORMAT_BGRX8888,
+       DRM_FORMAT_RGB565,
+       DRM_FORMAT_RGB888,
+       DRM_FORMAT_RGBX4444,
+       DRM_FORMAT_RGBX5551,
+       DRM_FORMAT_RGBX8888,
+       DRM_FORMAT_XBGR1555,
+       DRM_FORMAT_XBGR4444,
+       DRM_FORMAT_XBGR8888,
+       DRM_FORMAT_XRGB1555,
+       DRM_FORMAT_XRGB4444,
+       DRM_FORMAT_XRGB8888,
+
+       DRM_FORMAT_NV16,
+       DRM_FORMAT_NV12,
+       DRM_FORMAT_NV21,
+       DRM_FORMAT_NV61,
+       DRM_FORMAT_UYVY,
+       DRM_FORMAT_VYUY,
+       DRM_FORMAT_YUYV,
+       DRM_FORMAT_YVYU,
+       DRM_FORMAT_YUV411,
+       DRM_FORMAT_YUV420,
+       DRM_FORMAT_YUV422,
+       DRM_FORMAT_YVU411,
+       DRM_FORMAT_YVU420,
+       DRM_FORMAT_YVU422,
+};
+
+static const u32 sun8i_vi_layer_de3_formats[] = {
        DRM_FORMAT_ABGR1555,
+       DRM_FORMAT_ABGR2101010,
        DRM_FORMAT_ABGR4444,
+       DRM_FORMAT_ABGR8888,
        DRM_FORMAT_ARGB1555,
+       DRM_FORMAT_ARGB2101010,
        DRM_FORMAT_ARGB4444,
+       DRM_FORMAT_ARGB8888,
        DRM_FORMAT_BGR565,
        DRM_FORMAT_BGR888,
+       DRM_FORMAT_BGRA1010102,
        DRM_FORMAT_BGRA5551,
        DRM_FORMAT_BGRA4444,
+       DRM_FORMAT_BGRA8888,
        DRM_FORMAT_BGRX8888,
        DRM_FORMAT_RGB565,
        DRM_FORMAT_RGB888,
+       DRM_FORMAT_RGBA1010102,
        DRM_FORMAT_RGBA4444,
        DRM_FORMAT_RGBA5551,
+       DRM_FORMAT_RGBA8888,
        DRM_FORMAT_RGBX8888,
        DRM_FORMAT_XBGR8888,
        DRM_FORMAT_XRGB8888,
@@ -424,6 +466,8 @@ static const u32 sun8i_vi_layer_formats[] = {
        DRM_FORMAT_NV12,
        DRM_FORMAT_NV21,
        DRM_FORMAT_NV61,
+       DRM_FORMAT_P010,
+       DRM_FORMAT_P210,
        DRM_FORMAT_UYVY,
        DRM_FORMAT_VYUY,
        DRM_FORMAT_YUYV,
@@ -431,11 +475,9 @@ static const u32 sun8i_vi_layer_formats[] = {
        DRM_FORMAT_YUV411,
        DRM_FORMAT_YUV420,
        DRM_FORMAT_YUV422,
-       DRM_FORMAT_YUV444,
        DRM_FORMAT_YVU411,
        DRM_FORMAT_YVU420,
        DRM_FORMAT_YVU422,
-       DRM_FORMAT_YVU444,
 };
 
 struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
@@ -443,19 +485,27 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
                                               int index)
 {
        u32 supported_encodings, supported_ranges;
+       unsigned int plane_cnt, format_count;
        struct sun8i_vi_layer *layer;
-       unsigned int plane_cnt;
+       const u32 *formats;
        int ret;
 
        layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
        if (!layer)
                return ERR_PTR(-ENOMEM);
 
+       if (mixer->cfg->is_de3) {
+               formats = sun8i_vi_layer_de3_formats;
+               format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
+       } else {
+               formats = sun8i_vi_layer_formats;
+               format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
+       }
+
        /* possible crtcs are set later */
        ret = drm_universal_plane_init(drm, &layer->plane, 0,
                                       &sun8i_vi_layer_funcs,
-                                      sun8i_vi_layer_formats,
-                                      ARRAY_SIZE(sun8i_vi_layer_formats),
+                                      formats, format_count,
                                       NULL, DRM_PLANE_TYPE_OVERLAY, NULL);
        if (ret) {
                dev_err(drm->dev, "Couldn't initialize layer\n");
index 49ed557..953c82a 100644 (file)
@@ -515,6 +515,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
                fbo->base.base.resv = &fbo->base.base._resv;
 
        dma_resv_init(&fbo->base.base._resv);
+       fbo->base.base.dev = NULL;
        ret = dma_resv_trylock(&fbo->base.base._resv);
        WARN_ON(!ret);
 
index 017a9e0..3af7ec8 100644 (file)
@@ -42,8 +42,8 @@ static int virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
                 * "f91a9dd35715 Fix unlinking resources from hash
                 * table." (Feb 2019) fixes the bug.
                 */
-               static int handle;
-               handle++;
+               static atomic_t seqno = ATOMIC_INIT(0);
+               int handle = atomic_inc_return(&seqno);
                *resid = handle + 1;
        } else {
                int handle = ida_alloc(&vgdev->resource_ida, GFP_KERNEL);
@@ -99,6 +99,7 @@ struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev,
                return NULL;
 
        bo->base.base.funcs = &virtio_gpu_gem_funcs;
+       bo->base.map_cached = true;
        return &bo->base.base;
 }
 
index ae79a7c..fa70415 100644 (file)
@@ -730,7 +730,7 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
        if (data->has_sp) {
                input2 = input_allocate_device();
                if (!input2) {
-                       input_free_device(input2);
+                       ret = -ENOMEM;
                        goto exit;
                }
 
index 6ac8bec..d732d1d 100644 (file)
@@ -340,7 +340,8 @@ static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                unsigned long **bit, int *max)
 {
        if (usage->hid == (HID_UP_CUSTOM | 0x0003) ||
-                       usage->hid == (HID_UP_MSVENDOR | 0x0003)) {
+                       usage->hid == (HID_UP_MSVENDOR | 0x0003) ||
+                       usage->hid == (HID_UP_HPVENDOR2 | 0x0003)) {
                /* The fn key on Apple USB keyboards */
                set_bit(EV_REP, hi->input->evbit);
                hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN);
index 3f6abd1..db6da21 100644 (file)
@@ -174,6 +174,7 @@ static __u8 pid0902_rdesc_fixed[] = {
 struct bigben_device {
        struct hid_device *hid;
        struct hid_report *report;
+       bool removed;
        u8 led_state;         /* LED1 = 1 .. LED4 = 8 */
        u8 right_motor_on;    /* right motor off/on 0/1 */
        u8 left_motor_force;  /* left motor force 0-255 */
@@ -190,6 +191,9 @@ static void bigben_worker(struct work_struct *work)
                struct bigben_device, worker);
        struct hid_field *report_field = bigben->report->field[0];
 
+       if (bigben->removed)
+               return;
+
        if (bigben->work_led) {
                bigben->work_led = false;
                report_field->value[0] = 0x01; /* 1 = led message */
@@ -220,10 +224,16 @@ static void bigben_worker(struct work_struct *work)
 static int hid_bigben_play_effect(struct input_dev *dev, void *data,
                         struct ff_effect *effect)
 {
-       struct bigben_device *bigben = data;
+       struct hid_device *hid = input_get_drvdata(dev);
+       struct bigben_device *bigben = hid_get_drvdata(hid);
        u8 right_motor_on;
        u8 left_motor_force;
 
+       if (!bigben) {
+               hid_err(hid, "no device data\n");
+               return 0;
+       }
+
        if (effect->type != FF_RUMBLE)
                return 0;
 
@@ -298,8 +308,8 @@ static void bigben_remove(struct hid_device *hid)
 {
        struct bigben_device *bigben = hid_get_drvdata(hid);
 
+       bigben->removed = true;
        cancel_work_sync(&bigben->worker);
-       hid_hw_close(hid);
        hid_hw_stop(hid);
 }
 
@@ -319,6 +329,7 @@ static int bigben_probe(struct hid_device *hid,
                return -ENOMEM;
        hid_set_drvdata(hid, bigben);
        bigben->hid = hid;
+       bigben->removed = false;
 
        error = hid_parse(hid);
        if (error) {
@@ -341,10 +352,10 @@ static int bigben_probe(struct hid_device *hid,
 
        INIT_WORK(&bigben->worker, bigben_worker);
 
-       error = input_ff_create_memless(hidinput->input, bigben,
+       error = input_ff_create_memless(hidinput->input, NULL,
                hid_bigben_play_effect);
        if (error)
-               return error;
+               goto error_hw_stop;
 
        name_sz = strlen(dev_name(&hid->dev)) + strlen(":red:bigben#") + 1;
 
@@ -354,8 +365,10 @@ static int bigben_probe(struct hid_device *hid,
                        sizeof(struct led_classdev) + name_sz,
                        GFP_KERNEL
                );
-               if (!led)
-                       return -ENOMEM;
+               if (!led) {
+                       error = -ENOMEM;
+                       goto error_hw_stop;
+               }
                name = (void *)(&led[1]);
                snprintf(name, name_sz,
                        "%s:red:bigben%d",
@@ -369,7 +382,7 @@ static int bigben_probe(struct hid_device *hid,
                bigben->leds[n] = led;
                error = devm_led_classdev_register(&hid->dev, led);
                if (error)
-                       return error;
+                       goto error_hw_stop;
        }
 
        /* initial state: LED1 is on, no rumble effect */
@@ -383,6 +396,10 @@ static int bigben_probe(struct hid_device *hid,
        hid_info(hid, "LED and force feedback support for BigBen gamepad\n");
 
        return 0;
+
+error_hw_stop:
+       hid_hw_stop(hid);
+       return error;
 }
 
 static __u8 *bigben_report_fixup(struct hid_device *hid, __u8 *rdesc,
index 851fe54..359616e 100644 (file)
@@ -1741,7 +1741,9 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
 
        rsize = ((report->size - 1) >> 3) + 1;
 
-       if (rsize > HID_MAX_BUFFER_SIZE)
+       if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE)
+               rsize = HID_MAX_BUFFER_SIZE - 1;
+       else if (rsize > HID_MAX_BUFFER_SIZE)
                rsize = HID_MAX_BUFFER_SIZE;
 
        if (csize < rsize) {
index dddfca5..0b6ee1d 100644 (file)
@@ -193,8 +193,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
                goto cleanup;
 
        /* The pointer is not NULL when we resume from hibernation */
-       if (input_device->hid_desc != NULL)
-               kfree(input_device->hid_desc);
+       kfree(input_device->hid_desc);
        input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
 
        if (!input_device->hid_desc)
@@ -207,8 +206,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
        }
 
        /* The pointer is not NULL when we resume from hibernation */
-       if (input_device->report_desc != NULL)
-               kfree(input_device->report_desc);
+       kfree(input_device->report_desc);
        input_device->report_desc = kzalloc(input_device->report_desc_size,
                                          GFP_ATOMIC);
 
index c436e12..6c55682 100644 (file)
@@ -41,8 +41,9 @@ static const struct hid_device_id ite_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE8595) },
        { HID_USB_DEVICE(USB_VENDOR_ID_258A, USB_DEVICE_ID_258A_6A88) },
        /* ITE8595 USB kbd ctlr, with Synaptics touchpad connected to it. */
-       { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS,
-                        USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012) },
+       { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+                    USB_VENDOR_ID_SYNAPTICS,
+                    USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, ite_devices);
index 70e1cb9..094f4f1 100644 (file)
@@ -1256,36 +1256,35 @@ static int hidpp20_battery_map_status_voltage(u8 data[3], int *voltage,
 {
        int status;
 
-       long charge_sts = (long)data[2];
+       long flags = (long) data[2];
 
-       *level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
-       switch (data[2] & 0xe0) {
-       case 0x00:
-               status = POWER_SUPPLY_STATUS_CHARGING;
-               break;
-       case 0x20:
-               status = POWER_SUPPLY_STATUS_FULL;
-               *level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
-               break;
-       case 0x40:
+       if (flags & 0x80)
+               switch (flags & 0x07) {
+               case 0:
+                       status = POWER_SUPPLY_STATUS_CHARGING;
+                       break;
+               case 1:
+                       status = POWER_SUPPLY_STATUS_FULL;
+                       *level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+                       break;
+               case 2:
+                       status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                       break;
+               default:
+                       status = POWER_SUPPLY_STATUS_UNKNOWN;
+                       break;
+               }
+       else
                status = POWER_SUPPLY_STATUS_DISCHARGING;
-               break;
-       case 0xe0:
-               status = POWER_SUPPLY_STATUS_NOT_CHARGING;
-               break;
-       default:
-               status = POWER_SUPPLY_STATUS_UNKNOWN;
-       }
 
        *charge_type = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
-       if (test_bit(3, &charge_sts)) {
+       if (test_bit(3, &flags)) {
                *charge_type = POWER_SUPPLY_CHARGE_TYPE_FAST;
        }
-       if (test_bit(4, &charge_sts)) {
+       if (test_bit(4, &flags)) {
                *charge_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
        }
-
-       if (test_bit(5, &charge_sts)) {
+       if (test_bit(5, &flags)) {
                *level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
        }
 
index d31ea82..a66f080 100644 (file)
@@ -342,6 +342,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
                .driver_data = (void *)&sipodev_desc
        },
        {
+               .ident = "Trekstor SURFBOOK E11B",
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SURFBOOK E11B"),
+               },
+               .driver_data = (void *)&sipodev_desc
+       },
+       {
                .ident = "Direkt-Tek DTLAPY116-2",
                .matches = {
                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"),
index a970b80..4140dea 100644 (file)
@@ -932,9 +932,9 @@ void hiddev_disconnect(struct hid_device *hid)
        hiddev->exist = 0;
 
        if (hiddev->open) {
-               mutex_unlock(&hiddev->existancelock);
                hid_hw_close(hiddev->hid);
                wake_up_interruptible(&hiddev->wait);
+               mutex_unlock(&hiddev->existancelock);
        } else {
                mutex_unlock(&hiddev->existancelock);
                kfree(hiddev);
index 9632e2e..319a051 100644 (file)
@@ -413,7 +413,7 @@ static int ADT7462_REG_VOLT(struct adt7462_data *data, int which)
                        return 0x95;
                break;
        }
-       return -ENODEV;
+       return 0;
 }
 
 /* Provide labels for sysfs */
index ecd9b65..660556b 100644 (file)
 #define XDPE122_AMD_625MV              0x10 /* AMD mode 6.25mV */
 #define XDPE122_PAGE_NUM               2
 
+static int xdpe122_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+       long val;
+       s16 exponent;
+       s32 mantissa;
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VOUT_OV_FAULT_LIMIT:
+       case PMBUS_VOUT_UV_FAULT_LIMIT:
+               ret = pmbus_read_word_data(client, page, reg);
+               if (ret < 0)
+                       return ret;
+
+               /* Convert register value to LINEAR11 data. */
+               exponent = ((s16)ret) >> 11;
+               mantissa = ((s16)((ret & GENMASK(10, 0)) << 5)) >> 5;
+               val = mantissa * 1000L;
+               if (exponent >= 0)
+                       val <<= exponent;
+               else
+                       val >>= -exponent;
+
+               /* Convert data to VID register. */
+               switch (info->vrm_version[page]) {
+               case vr13:
+                       if (val >= 500)
+                               return 1 + DIV_ROUND_CLOSEST(val - 500, 10);
+                       return 0;
+               case vr12:
+                       if (val >= 250)
+                               return 1 + DIV_ROUND_CLOSEST(val - 250, 5);
+                       return 0;
+               case imvp9:
+                       if (val >= 200)
+                               return 1 + DIV_ROUND_CLOSEST(val - 200, 10);
+                       return 0;
+               case amd625mv:
+                       if (val >= 200 && val <= 1550)
+                               return DIV_ROUND_CLOSEST((1550 - val) * 100,
+                                                        625);
+                       return 0;
+               default:
+                       return -EINVAL;
+               }
+       default:
+               return -ENODATA;
+       }
+
+       return 0;
+}
+
 static int xdpe122_identify(struct i2c_client *client,
                            struct pmbus_driver_info *info)
 {
@@ -70,6 +123,7 @@ static struct pmbus_driver_info xdpe122_info = {
                PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
                PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
        .identify = xdpe122_identify,
+       .read_word_data = xdpe122_read_word_data,
 };
 
 static int xdpe122_probe(struct i2c_client *client,
index 5255d37..1de23b4 100644 (file)
@@ -171,7 +171,7 @@ static void altr_i2c_init(struct altr_i2c_dev *idev)
        /* SCL Low Time */
        writel(t_low, idev->base + ALTR_I2C_SCL_LOW);
        /* SDA Hold Time, 300ns */
-       writel(div_u64(300 * clk_mhz, 1000), idev->base + ALTR_I2C_SDA_HOLD);
+       writel(3 * clk_mhz / 10, idev->base + ALTR_I2C_SDA_HOLD);
 
        /* Mask all master interrupt bits */
        altr_i2c_int_enable(idev, ALTR_I2C_ALL_IRQ, false);
index 16a67a6..b426fc9 100644 (file)
 
 #define X1000_I2C_DC_STOP              BIT(9)
 
-static const char * const jz4780_i2c_abrt_src[] = {
-       "ABRT_7B_ADDR_NOACK",
-       "ABRT_10ADDR1_NOACK",
-       "ABRT_10ADDR2_NOACK",
-       "ABRT_XDATA_NOACK",
-       "ABRT_GCALL_NOACK",
-       "ABRT_GCALL_READ",
-       "ABRT_HS_ACKD",
-       "SBYTE_ACKDET",
-       "ABRT_HS_NORSTRT",
-       "SBYTE_NORSTRT",
-       "ABRT_10B_RD_NORSTRT",
-       "ABRT_MASTER_DIS",
-       "ARB_LOST",
-       "SLVFLUSH_TXFIFO",
-       "SLV_ARBLOST",
-       "SLVRD_INTX",
-};
-
 #define JZ4780_I2C_INTST_IGC           BIT(11)
 #define JZ4780_I2C_INTST_ISTT          BIT(10)
 #define JZ4780_I2C_INTST_ISTP          BIT(9)
@@ -576,21 +557,8 @@ done:
 
 static void jz4780_i2c_txabrt(struct jz4780_i2c *i2c, int src)
 {
-       int i;
-
-       dev_err(&i2c->adap.dev, "txabrt: 0x%08x\n", src);
-       dev_err(&i2c->adap.dev, "device addr=%x\n",
-               jz4780_i2c_readw(i2c, JZ4780_I2C_TAR));
-       dev_err(&i2c->adap.dev, "send cmd count:%d  %d\n",
-               i2c->cmd, i2c->cmd_buf[i2c->cmd]);
-       dev_err(&i2c->adap.dev, "receive data count:%d  %d\n",
-               i2c->cmd, i2c->data_buf[i2c->cmd]);
-
-       for (i = 0; i < 16; i++) {
-               if (src & BIT(i))
-                       dev_dbg(&i2c->adap.dev, "I2C TXABRT[%d]=%s\n",
-                               i, jz4780_i2c_abrt_src[i]);
-       }
+       dev_dbg(&i2c->adap.dev, "txabrt: 0x%08x, cmd: %d, send: %d, recv: %d\n",
+               src, i2c->cmd, i2c->cmd_buf[i2c->cmd], i2c->data_buf[i2c->cmd]);
 }
 
 static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c,
index 1bb99b5..05c2698 100644 (file)
@@ -361,7 +361,7 @@ static const struct block_device_operations ide_gd_ops = {
        .release                = ide_gd_release,
        .ioctl                  = ide_gd_ioctl,
 #ifdef CONFIG_COMPAT
-       .ioctl                  = ide_gd_compat_ioctl,
+       .compat_ioctl           = ide_gd_compat_ioctl,
 #endif
        .getgeo                 = ide_gd_getgeo,
        .check_events           = ide_gd_check_events,
index 8c74457..a0d87ed 100644 (file)
@@ -300,9 +300,11 @@ static int control_loop(void *dummy)
 /*     i2c probing and setup                                           */
 /************************************************************************/
 
-static int
-do_attach( struct i2c_adapter *adapter )
+static void do_attach(struct i2c_adapter *adapter)
 {
+       struct i2c_board_info info = { };
+       struct device_node *np;
+
        /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
        static const unsigned short scan_ds1775[] = {
                0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
@@ -313,25 +315,24 @@ do_attach( struct i2c_adapter *adapter )
                I2C_CLIENT_END
        };
 
-       if( strncmp(adapter->name, "uni-n", 5) )
-               return 0;
-
-       if( !x.running ) {
-               struct i2c_board_info info;
+       if (x.running || strncmp(adapter->name, "uni-n", 5))
+               return;
 
-               memset(&info, 0, sizeof(struct i2c_board_info));
-               strlcpy(info.type, "therm_ds1775", I2C_NAME_SIZE);
+       np = of_find_compatible_node(adapter->dev.of_node, NULL, "MAC,ds1775");
+       if (np) {
+               of_node_put(np);
+       } else {
+               strlcpy(info.type, "MAC,ds1775", I2C_NAME_SIZE);
                i2c_new_probed_device(adapter, &info, scan_ds1775, NULL);
+       }
 
-               strlcpy(info.type, "therm_adm1030", I2C_NAME_SIZE);
+       np = of_find_compatible_node(adapter->dev.of_node, NULL, "MAC,adm1030");
+       if (np) {
+               of_node_put(np);
+       } else {
+               strlcpy(info.type, "MAC,adm1030", I2C_NAME_SIZE);
                i2c_new_probed_device(adapter, &info, scan_adm1030, NULL);
-
-               if( x.thermostat && x.fan ) {
-                       x.running = 1;
-                       x.poll_task = kthread_run(control_loop, NULL, "g4fand");
-               }
        }
-       return 0;
 }
 
 static int
@@ -404,8 +405,8 @@ out:
 enum chip { ds1775, adm1030 };
 
 static const struct i2c_device_id therm_windtunnel_id[] = {
-       { "therm_ds1775", ds1775 },
-       { "therm_adm1030", adm1030 },
+       { "MAC,ds1775", ds1775 },
+       { "MAC,adm1030", adm1030 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, therm_windtunnel_id);
@@ -414,6 +415,7 @@ static int
 do_probe(struct i2c_client *cl, const struct i2c_device_id *id)
 {
        struct i2c_adapter *adapter = cl->adapter;
+       int ret = 0;
 
        if( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA
                                     | I2C_FUNC_SMBUS_WRITE_BYTE) )
@@ -421,11 +423,19 @@ do_probe(struct i2c_client *cl, const struct i2c_device_id *id)
 
        switch (id->driver_data) {
        case adm1030:
-               return attach_fan( cl );
+               ret = attach_fan(cl);
+               break;
        case ds1775:
-               return attach_thermostat(cl);
+               ret = attach_thermostat(cl);
+               break;
        }
-       return 0;
+
+       if (!x.running && x.thermostat && x.fan) {
+               x.running = 1;
+               x.poll_task = kthread_run(control_loop, NULL, "g4fand");
+       }
+
+       return ret;
 }
 
 static struct i2c_driver g4fan_driver = {
index c82578a..2ea0360 100644 (file)
 struct dm_bio_details {
        struct gendisk *bi_disk;
        u8 bi_partno;
+       int __bi_remaining;
        unsigned long bi_flags;
        struct bvec_iter bi_iter;
+       bio_end_io_t *bi_end_io;
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+       struct bio_integrity_payload *bi_integrity;
+#endif
 };
 
 static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio)
@@ -30,6 +35,11 @@ static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio)
        bd->bi_partno = bio->bi_partno;
        bd->bi_flags = bio->bi_flags;
        bd->bi_iter = bio->bi_iter;
+       bd->__bi_remaining = atomic_read(&bio->__bi_remaining);
+       bd->bi_end_io = bio->bi_end_io;
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+       bd->bi_integrity = bio_integrity(bio);
+#endif
 }
 
 static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio)
@@ -38,6 +48,11 @@ static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio)
        bio->bi_partno = bd->bi_partno;
        bio->bi_flags = bd->bi_flags;
        bio->bi_iter = bd->bi_iter;
+       atomic_set(&bio->__bi_remaining, bd->__bi_remaining);
+       bio->bi_end_io = bd->bi_end_io;
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+       bio->bi_integrity = bd->bi_integrity;
+#endif
 }
 
 #endif
index 2d32821..d3bb355 100644 (file)
@@ -2846,8 +2846,8 @@ static void cache_postsuspend(struct dm_target *ti)
        prevent_background_work(cache);
        BUG_ON(atomic_read(&cache->nr_io_migrations));
 
-       cancel_delayed_work(&cache->waker);
-       flush_workqueue(cache->wq);
+       cancel_delayed_work_sync(&cache->waker);
+       drain_workqueue(cache->wq);
        WARN_ON(cache->tracker.in_flight);
 
        /*
@@ -3492,7 +3492,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits)
 
 static struct target_type cache_target = {
        .name = "cache",
-       .version = {2, 1, 0},
+       .version = {2, 2, 0},
        .module = THIS_MODULE,
        .ctr = cache_ctr,
        .dtr = cache_dtr,
index b225b3e..2f03fec 100644 (file)
@@ -6,6 +6,8 @@
  * This file is released under the GPL.
  */
 
+#include "dm-bio-record.h"
+
 #include <linux/compiler.h>
 #include <linux/module.h>
 #include <linux/device-mapper.h>
@@ -201,17 +203,19 @@ struct dm_integrity_c {
        __u8 log2_blocks_per_bitmap_bit;
 
        unsigned char mode;
-       int suspending;
 
        int failed;
 
        struct crypto_shash *internal_hash;
 
+       struct dm_target *ti;
+
        /* these variables are locked with endio_wait.lock */
        struct rb_root in_progress;
        struct list_head wait_list;
        wait_queue_head_t endio_wait;
        struct workqueue_struct *wait_wq;
+       struct workqueue_struct *offload_wq;
 
        unsigned char commit_seq;
        commit_id_t commit_ids[N_COMMIT_IDS];
@@ -293,11 +297,7 @@ struct dm_integrity_io {
 
        struct completion *completion;
 
-       struct gendisk *orig_bi_disk;
-       u8 orig_bi_partno;
-       bio_end_io_t *orig_bi_end_io;
-       struct bio_integrity_payload *orig_bi_integrity;
-       struct bvec_iter orig_bi_iter;
+       struct dm_bio_details bio_details;
 };
 
 struct journal_completion {
@@ -1439,7 +1439,7 @@ static void dec_in_flight(struct dm_integrity_io *dio)
                        dio->range.logical_sector += dio->range.n_sectors;
                        bio_advance(bio, dio->range.n_sectors << SECTOR_SHIFT);
                        INIT_WORK(&dio->work, integrity_bio_wait);
-                       queue_work(ic->wait_wq, &dio->work);
+                       queue_work(ic->offload_wq, &dio->work);
                        return;
                }
                do_endio_flush(ic, dio);
@@ -1450,14 +1450,9 @@ static void integrity_end_io(struct bio *bio)
 {
        struct dm_integrity_io *dio = dm_per_bio_data(bio, sizeof(struct dm_integrity_io));
 
-       bio->bi_iter = dio->orig_bi_iter;
-       bio->bi_disk = dio->orig_bi_disk;
-       bio->bi_partno = dio->orig_bi_partno;
-       if (dio->orig_bi_integrity) {
-               bio->bi_integrity = dio->orig_bi_integrity;
+       dm_bio_restore(&dio->bio_details, bio);
+       if (bio->bi_integrity)
                bio->bi_opf |= REQ_INTEGRITY;
-       }
-       bio->bi_end_io = dio->orig_bi_end_io;
 
        if (dio->completion)
                complete(dio->completion);
@@ -1542,7 +1537,7 @@ static void integrity_metadata(struct work_struct *w)
                        }
                }
 
-               __bio_for_each_segment(bv, bio, iter, dio->orig_bi_iter) {
+               __bio_for_each_segment(bv, bio, iter, dio->bio_details.bi_iter) {
                        unsigned pos;
                        char *mem, *checksums_ptr;
 
@@ -1586,7 +1581,7 @@ again:
                if (likely(checksums != checksums_onstack))
                        kfree(checksums);
        } else {
-               struct bio_integrity_payload *bip = dio->orig_bi_integrity;
+               struct bio_integrity_payload *bip = dio->bio_details.bi_integrity;
 
                if (bip) {
                        struct bio_vec biv;
@@ -1865,7 +1860,7 @@ static void dm_integrity_map_continue(struct dm_integrity_io *dio, bool from_map
 
        if (need_sync_io && from_map) {
                INIT_WORK(&dio->work, integrity_bio_wait);
-               queue_work(ic->metadata_wq, &dio->work);
+               queue_work(ic->offload_wq, &dio->work);
                return;
        }
 
@@ -2005,20 +2000,13 @@ offload_to_thread:
        } else
                dio->completion = NULL;
 
-       dio->orig_bi_iter = bio->bi_iter;
-
-       dio->orig_bi_disk = bio->bi_disk;
-       dio->orig_bi_partno = bio->bi_partno;
+       dm_bio_record(&dio->bio_details, bio);
        bio_set_dev(bio, ic->dev->bdev);
-
-       dio->orig_bi_integrity = bio_integrity(bio);
        bio->bi_integrity = NULL;
        bio->bi_opf &= ~REQ_INTEGRITY;
-
-       dio->orig_bi_end_io = bio->bi_end_io;
        bio->bi_end_io = integrity_end_io;
-
        bio->bi_iter.bi_size = dio->range.n_sectors << SECTOR_SHIFT;
+
        generic_make_request(bio);
 
        if (need_sync_io) {
@@ -2315,7 +2303,7 @@ static void integrity_writer(struct work_struct *w)
        unsigned prev_free_sectors;
 
        /* the following test is not needed, but it tests the replay code */
-       if (READ_ONCE(ic->suspending) && !ic->meta_dev)
+       if (unlikely(dm_suspended(ic->ti)) && !ic->meta_dev)
                return;
 
        spin_lock_irq(&ic->endio_wait.lock);
@@ -2376,7 +2364,7 @@ static void integrity_recalc(struct work_struct *w)
 
 next_chunk:
 
-       if (unlikely(READ_ONCE(ic->suspending)))
+       if (unlikely(dm_suspended(ic->ti)))
                goto unlock_ret;
 
        range.logical_sector = le64_to_cpu(ic->sb->recalc_sector);
@@ -2501,7 +2489,7 @@ static void bitmap_block_work(struct work_struct *w)
                                    dio->range.n_sectors, BITMAP_OP_TEST_ALL_SET)) {
                        remove_range(ic, &dio->range);
                        INIT_WORK(&dio->work, integrity_bio_wait);
-                       queue_work(ic->wait_wq, &dio->work);
+                       queue_work(ic->offload_wq, &dio->work);
                } else {
                        block_bitmap_op(ic, ic->journal, dio->range.logical_sector,
                                        dio->range.n_sectors, BITMAP_OP_SET);
@@ -2524,7 +2512,7 @@ static void bitmap_block_work(struct work_struct *w)
 
                remove_range(ic, &dio->range);
                INIT_WORK(&dio->work, integrity_bio_wait);
-               queue_work(ic->wait_wq, &dio->work);
+               queue_work(ic->offload_wq, &dio->work);
        }
 
        queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, ic->bitmap_flush_interval);
@@ -2804,8 +2792,6 @@ static void dm_integrity_postsuspend(struct dm_target *ti)
 
        del_timer_sync(&ic->autocommit_timer);
 
-       WRITE_ONCE(ic->suspending, 1);
-
        if (ic->recalc_wq)
                drain_workqueue(ic->recalc_wq);
 
@@ -2834,8 +2820,6 @@ static void dm_integrity_postsuspend(struct dm_target *ti)
 #endif
        }
 
-       WRITE_ONCE(ic->suspending, 0);
-
        BUG_ON(!RB_EMPTY_ROOT(&ic->in_progress));
 
        ic->journal_uptodate = true;
@@ -2888,17 +2872,24 @@ static void dm_integrity_resume(struct dm_target *ti)
        } else {
                replay_journal(ic);
                if (ic->mode == 'B') {
-                       int mode;
                        ic->sb->flags |= cpu_to_le32(SB_FLAG_DIRTY_BITMAP);
                        ic->sb->log2_blocks_per_bitmap_bit = ic->log2_blocks_per_bitmap_bit;
                        r = sync_rw_sb(ic, REQ_OP_WRITE, REQ_FUA);
                        if (unlikely(r))
                                dm_integrity_io_error(ic, "writing superblock", r);
 
-                       mode = ic->recalculate_flag ? BITMAP_OP_SET : BITMAP_OP_CLEAR;
-                       block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, mode);
-                       block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, mode);
-                       block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, mode);
+                       block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR);
+                       block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR);
+                       block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR);
+                       if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) &&
+                           le64_to_cpu(ic->sb->recalc_sector) < ic->provided_data_sectors) {
+                               block_bitmap_op(ic, ic->journal, le64_to_cpu(ic->sb->recalc_sector),
+                                               ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET);
+                               block_bitmap_op(ic, ic->recalc_bitmap, le64_to_cpu(ic->sb->recalc_sector),
+                                               ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET);
+                               block_bitmap_op(ic, ic->may_write_bitmap, le64_to_cpu(ic->sb->recalc_sector),
+                                               ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET);
+                       }
                        rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC, 0,
                                           ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
                }
@@ -2967,7 +2958,7 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
                        DMEMIT(" meta_device:%s", ic->meta_dev->name);
                if (ic->sectors_per_block != 1)
                        DMEMIT(" block_size:%u", ic->sectors_per_block << SECTOR_SHIFT);
-               if (ic->recalculate_flag)
+               if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING))
                        DMEMIT(" recalculate");
                DMEMIT(" journal_sectors:%u", ic->initial_sectors - SB_SECTORS);
                DMEMIT(" interleave_sectors:%u", 1U << ic->sb->log2_interleave_sectors);
@@ -3623,6 +3614,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
        }
        ti->private = ic;
        ti->per_io_data_size = sizeof(struct dm_integrity_io);
+       ic->ti = ti;
 
        ic->in_progress = RB_ROOT;
        INIT_LIST_HEAD(&ic->wait_list);
@@ -3836,6 +3828,14 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                goto bad;
        }
 
+       ic->offload_wq = alloc_workqueue("dm-integrity-offload", WQ_MEM_RECLAIM,
+                                         METADATA_WORKQUEUE_MAX_ACTIVE);
+       if (!ic->offload_wq) {
+               ti->error = "Cannot allocate workqueue";
+               r = -ENOMEM;
+               goto bad;
+       }
+
        ic->commit_wq = alloc_workqueue("dm-integrity-commit", WQ_MEM_RECLAIM, 1);
        if (!ic->commit_wq) {
                ti->error = "Cannot allocate workqueue";
@@ -4140,6 +4140,8 @@ static void dm_integrity_dtr(struct dm_target *ti)
                destroy_workqueue(ic->metadata_wq);
        if (ic->wait_wq)
                destroy_workqueue(ic->wait_wq);
+       if (ic->offload_wq)
+               destroy_workqueue(ic->offload_wq);
        if (ic->commit_wq)
                destroy_workqueue(ic->commit_wq);
        if (ic->writer_wq)
@@ -4200,7 +4202,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
 
 static struct target_type integrity_target = {
        .name                   = "integrity",
-       .version                = {1, 4, 0},
+       .version                = {1, 5, 0},
        .module                 = THIS_MODULE,
        .features               = DM_TARGET_SINGLETON | DM_TARGET_INTEGRITY,
        .ctr                    = dm_integrity_ctr,
index 2bc18c9..58fd137 100644 (file)
@@ -2053,7 +2053,7 @@ static int multipath_busy(struct dm_target *ti)
  *---------------------------------------------------------------*/
 static struct target_type multipath_target = {
        .name = "multipath",
-       .version = {1, 13, 0},
+       .version = {1, 14, 0},
        .features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE |
                    DM_TARGET_PASSES_INTEGRITY,
        .module = THIS_MODULE,
index fc9947d..76b6b32 100644 (file)
@@ -960,9 +960,9 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
                        DMWARN("%s: __commit_transaction() failed, error = %d",
                               __func__, r);
        }
+       pmd_write_unlock(pmd);
        if (!pmd->fail_io)
                __destroy_persistent_data_objects(pmd);
-       pmd_write_unlock(pmd);
 
        kfree(pmd);
        return 0;
index 0d61e9c..eec9f25 100644 (file)
@@ -1221,7 +1221,7 @@ bad:
 
 static struct target_type verity_target = {
        .name           = "verity",
-       .version        = {1, 5, 0},
+       .version        = {1, 6, 0},
        .module         = THIS_MODULE,
        .ctr            = verity_ctr,
        .dtr            = verity_dtr,
index b9e27e3..a09bdc0 100644 (file)
@@ -625,6 +625,12 @@ static void writecache_add_to_freelist(struct dm_writecache *wc, struct wc_entry
        wc->freelist_size++;
 }
 
+static inline void writecache_verify_watermark(struct dm_writecache *wc)
+{
+       if (unlikely(wc->freelist_size + wc->writeback_size <= wc->freelist_high_watermark))
+               queue_work(wc->writeback_wq, &wc->writeback_work);
+}
+
 static struct wc_entry *writecache_pop_from_freelist(struct dm_writecache *wc, sector_t expected_sector)
 {
        struct wc_entry *e;
@@ -650,8 +656,8 @@ static struct wc_entry *writecache_pop_from_freelist(struct dm_writecache *wc, s
                list_del(&e->lru);
        }
        wc->freelist_size--;
-       if (unlikely(wc->freelist_size + wc->writeback_size <= wc->freelist_high_watermark))
-               queue_work(wc->writeback_wq, &wc->writeback_work);
+
+       writecache_verify_watermark(wc);
 
        return e;
 }
@@ -842,7 +848,7 @@ static void writecache_suspend(struct dm_target *ti)
        }
        wc_unlock(wc);
 
-       flush_workqueue(wc->writeback_wq);
+       drain_workqueue(wc->writeback_wq);
 
        wc_lock(wc);
        if (flush_on_suspend)
@@ -965,6 +971,8 @@ erase_this:
                writecache_commit_flushed(wc, false);
        }
 
+       writecache_verify_watermark(wc);
+
        wc_unlock(wc);
 }
 
@@ -2312,7 +2320,7 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
 
 static struct target_type writecache_target = {
        .name                   = "writecache",
-       .version                = {1, 1, 1},
+       .version                = {1, 2, 0},
        .module                 = THIS_MODULE,
        .ctr                    = writecache_ctr,
        .dtr                    = writecache_dtr,
index 70a1063..f4f83d3 100644 (file)
@@ -533,8 +533,9 @@ static int dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
 
        /* Get the BIO chunk work. If one is not active yet, create one */
        cw = radix_tree_lookup(&dmz->chunk_rxtree, chunk);
-       if (!cw) {
-
+       if (cw) {
+               dmz_get_chunk_work(cw);
+       } else {
                /* Create a new chunk work */
                cw = kmalloc(sizeof(struct dm_chunk_work), GFP_NOIO);
                if (unlikely(!cw)) {
@@ -543,7 +544,7 @@ static int dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
                }
 
                INIT_WORK(&cw->work, dmz_chunk_work);
-               refcount_set(&cw->refcount, 0);
+               refcount_set(&cw->refcount, 1);
                cw->target = dmz;
                cw->chunk = chunk;
                bio_list_init(&cw->bio_list);
@@ -556,7 +557,6 @@ static int dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
        }
 
        bio_list_add(&cw->bio_list, bio);
-       dmz_get_chunk_work(cw);
 
        dmz_reclaim_bio_acc(dmz->reclaim);
        if (queue_work(dmz->chunk_wq, &cw->work))
@@ -967,7 +967,7 @@ static int dmz_iterate_devices(struct dm_target *ti,
 
 static struct target_type dmz_type = {
        .name            = "zoned",
-       .version         = {1, 0, 0},
+       .version         = {1, 1, 0},
        .features        = DM_TARGET_SINGLETON | DM_TARGET_ZONED_HM,
        .module          = THIS_MODULE,
        .ctr             = dmz_ctr,
index b89f07e..0413018 100644 (file)
@@ -1788,7 +1788,8 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
                         * With request-based DM we only need to check the
                         * top-level queue for congestion.
                         */
-                       r = md->queue->backing_dev_info->wb.state & bdi_bits;
+                       struct backing_dev_info *bdi = md->queue->backing_dev_info;
+                       r = bdi->wb.congested->state & bdi_bits;
                } else {
                        map = dm_get_live_table_fast(md);
                        if (map)
@@ -1854,15 +1855,6 @@ static const struct dax_operations dm_dax_ops;
 
 static void dm_wq_work(struct work_struct *work);
 
-static void dm_init_normal_md_queue(struct mapped_device *md)
-{
-       /*
-        * Initialize aspects of queue that aren't relevant for blk-mq
-        */
-       md->queue->backing_dev_info->congested_data = md;
-       md->queue->backing_dev_info->congested_fn = dm_any_congested;
-}
-
 static void cleanup_mapped_device(struct mapped_device *md)
 {
        if (md->wq)
@@ -2249,6 +2241,12 @@ struct queue_limits *dm_get_queue_limits(struct mapped_device *md)
 }
 EXPORT_SYMBOL_GPL(dm_get_queue_limits);
 
+static void dm_init_congested_fn(struct mapped_device *md)
+{
+       md->queue->backing_dev_info->congested_data = md;
+       md->queue->backing_dev_info->congested_fn = dm_any_congested;
+}
+
 /*
  * Setup the DM device's queue based on md's type
  */
@@ -2265,11 +2263,12 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t)
                        DMERR("Cannot initialize queue for request-based dm-mq mapped device");
                        return r;
                }
+               dm_init_congested_fn(md);
                break;
        case DM_TYPE_BIO_BASED:
        case DM_TYPE_DAX_BIO_BASED:
        case DM_TYPE_NVME_BIO_BASED:
-               dm_init_normal_md_queue(md);
+               dm_init_congested_fn(md);
                break;
        case DM_TYPE_NONE:
                WARN_ON_ONCE(true);
@@ -2368,6 +2367,7 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
        map = dm_get_live_table(md, &srcu_idx);
        if (!dm_suspended_md(md)) {
                dm_table_presuspend_targets(map);
+               set_bit(DMF_SUSPENDED, &md->flags);
                dm_table_postsuspend_targets(map);
        }
        /* dm_put_live_table must be before msleep, otherwise deadlock is possible */
index 7c429ce..668770e 100644 (file)
@@ -639,9 +639,9 @@ int media_get_pad_index(struct media_entity *entity, bool is_sink,
                return -EINVAL;
 
        for (i = 0; i < entity->num_pads; i++) {
-               if (entity->pads[i].flags == MEDIA_PAD_FL_SINK)
+               if (entity->pads[i].flags & MEDIA_PAD_FL_SINK)
                        pad_is_sink = true;
-               else if (entity->pads[i].flags == MEDIA_PAD_FL_SOURCE)
+               else if (entity->pads[i].flags & MEDIA_PAD_FL_SOURCE)
                        pad_is_sink = false;
                else
                        continue;       /* This is an error! */
index 3c93d92..b6e39fb 100644 (file)
@@ -27,17 +27,17 @@ static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = {
        { V4L2_PIX_FMT_BGR24,   3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
        { V4L2_PIX_FMT_RGB24,   3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
        { V4L2_PIX_FMT_HSV24,   3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV},
-       { V4L2_PIX_FMT_BGR32,   4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
-       { V4L2_PIX_FMT_XBGR32,  4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+       { V4L2_PIX_FMT_BGR32,   4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
+       { V4L2_PIX_FMT_XBGR32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
        { V4L2_PIX_FMT_ABGR32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
-       { V4L2_PIX_FMT_RGB32,   4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
-       { V4L2_PIX_FMT_XRGB32,  4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+       { V4L2_PIX_FMT_RGB32,   4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
+       { V4L2_PIX_FMT_XRGB32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
        { V4L2_PIX_FMT_ARGB32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
-       { V4L2_PIX_FMT_BGRX32,  4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+       { V4L2_PIX_FMT_BGRX32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
        { V4L2_PIX_FMT_BGRA32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
-       { V4L2_PIX_FMT_RGBX32,  4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+       { V4L2_PIX_FMT_RGBX32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
        { V4L2_PIX_FMT_RGBA32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
-       { V4L2_PIX_FMT_HSV32,   4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV},
+       { V4L2_PIX_FMT_HSV32,   4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_HSV},
        { V4L2_PIX_FMT_GREY,    1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB},
 };
 
@@ -175,22 +175,14 @@ static int prepare_raw_frame(struct fwht_raw_frame *rf,
        case V4L2_PIX_FMT_RGB32:
        case V4L2_PIX_FMT_XRGB32:
        case V4L2_PIX_FMT_HSV32:
-               rf->cr = rf->luma + 1;
-               rf->cb = rf->cr + 2;
-               rf->luma += 2;
-               break;
-       case V4L2_PIX_FMT_BGR32:
-       case V4L2_PIX_FMT_XBGR32:
-               rf->cb = rf->luma;
-               rf->cr = rf->cb + 2;
-               rf->luma++;
-               break;
        case V4L2_PIX_FMT_ARGB32:
                rf->alpha = rf->luma;
                rf->cr = rf->luma + 1;
                rf->cb = rf->cr + 2;
                rf->luma += 2;
                break;
+       case V4L2_PIX_FMT_BGR32:
+       case V4L2_PIX_FMT_XBGR32:
        case V4L2_PIX_FMT_ABGR32:
                rf->cb = rf->luma;
                rf->cr = rf->cb + 2;
@@ -198,10 +190,6 @@ static int prepare_raw_frame(struct fwht_raw_frame *rf,
                rf->alpha = rf->cr + 1;
                break;
        case V4L2_PIX_FMT_BGRX32:
-               rf->cb = rf->luma + 1;
-               rf->cr = rf->cb + 2;
-               rf->luma += 2;
-               break;
        case V4L2_PIX_FMT_BGRA32:
                rf->alpha = rf->luma;
                rf->cb = rf->luma + 1;
@@ -209,10 +197,6 @@ static int prepare_raw_frame(struct fwht_raw_frame *rf,
                rf->luma += 2;
                break;
        case V4L2_PIX_FMT_RGBX32:
-               rf->cr = rf->luma;
-               rf->cb = rf->cr + 2;
-               rf->luma++;
-               break;
        case V4L2_PIX_FMT_RGBA32:
                rf->alpha = rf->luma + 3;
                rf->cr = rf->luma;
index afda438..0655aa9 100644 (file)
@@ -635,8 +635,6 @@ static void pulse8_cec_adap_free(struct cec_adapter *adap)
        cancel_delayed_work_sync(&pulse8->ping_eeprom_work);
        cancel_work_sync(&pulse8->irq_work);
        cancel_work_sync(&pulse8->tx_work);
-       serio_close(pulse8->serio);
-       serio_set_drvdata(pulse8->serio, NULL);
        kfree(pulse8);
 }
 
@@ -652,6 +650,9 @@ static void pulse8_disconnect(struct serio *serio)
        struct pulse8 *pulse8 = serio_get_drvdata(serio);
 
        cec_unregister_adapter(pulse8->adap);
+       pulse8->serio = NULL;
+       serio_set_drvdata(serio, NULL);
+       serio_close(serio);
 }
 
 static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio,
@@ -840,6 +841,8 @@ static int pulse8_connect(struct serio *serio, struct serio_driver *drv)
        serio_set_drvdata(serio, pulse8);
        INIT_WORK(&pulse8->irq_work, pulse8_irq_work_handler);
        INIT_WORK(&pulse8->tx_work, pulse8_tx_work_handler);
+       INIT_DELAYED_WORK(&pulse8->ping_eeprom_work,
+                         pulse8_ping_eeprom_work_handler);
        mutex_init(&pulse8->lock);
        spin_lock_init(&pulse8->msg_lock);
        pulse8->config_pending = false;
@@ -865,17 +868,16 @@ static int pulse8_connect(struct serio *serio, struct serio_driver *drv)
                pulse8->restoring_config = true;
        }
 
-       INIT_DELAYED_WORK(&pulse8->ping_eeprom_work,
-                         pulse8_ping_eeprom_work_handler);
        schedule_delayed_work(&pulse8->ping_eeprom_work, PING_PERIOD);
 
        return 0;
 
 close_serio:
+       pulse8->serio = NULL;
+       serio_set_drvdata(serio, NULL);
        serio_close(serio);
 delete_adap:
        cec_delete_adapter(pulse8->adap);
-       serio_set_drvdata(serio, NULL);
 free_device:
        kfree(pulse8);
        return err;
index 1afd9c6..cc34c5a 100644 (file)
@@ -880,12 +880,12 @@ int v4l2_m2m_register_media_controller(struct v4l2_m2m_dev *m2m_dev,
                goto err_rel_entity1;
 
        /* Connect the three entities */
-       ret = media_create_pad_link(m2m_dev->source, 0, &m2m_dev->proc, 1,
+       ret = media_create_pad_link(m2m_dev->source, 0, &m2m_dev->proc, 0,
                        MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
        if (ret)
                goto err_rel_entity2;
 
-       ret = media_create_pad_link(&m2m_dev->proc, 0, &m2m_dev->sink, 0,
+       ret = media_create_pad_link(&m2m_dev->proc, 1, &m2m_dev->sink, 0,
                        MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
        if (ret)
                goto err_rm_links0;
index d195554..b0f5280 100644 (file)
@@ -69,8 +69,7 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
                /* Force link status for IMP port */
                reg = core_readl(priv, offset);
                reg |= (MII_SW_OR | LINK_STS);
-               if (priv->type == BCM7278_DEVICE_ID)
-                       reg |= GMII_SPEED_UP_2G;
+               reg &= ~GMII_SPEED_UP_2G;
                core_writel(priv, reg, offset);
 
                /* Enable Broadcast, Multicast, Unicast forwarding to IMP port */
index b016cc2..ca3a7a7 100644 (file)
@@ -278,13 +278,13 @@ int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip,
        switch (direction) {
        case MV88E6XXX_EGRESS_DIR_INGRESS:
                dest_port_chip = &chip->ingress_dest_port;
-               reg &= MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK;
+               reg &= ~MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK;
                reg |= port <<
                       __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK);
                break;
        case MV88E6XXX_EGRESS_DIR_EGRESS:
                dest_port_chip = &chip->egress_dest_port;
-               reg &= MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK;
+               reg &= ~MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK;
                reg |= port <<
                       __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK);
                break;
index fd6e0e4..f9a8151 100644 (file)
@@ -11252,7 +11252,7 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp)
                }
        }
        if (test_and_clear_bit(BNXT_HWRM_PF_UNLOAD_SP_EVENT, &bp->sp_event))
-               netdev_info(bp->dev, "Receive PF driver unload event!");
+               netdev_info(bp->dev, "Receive PF driver unload event!\n");
 }
 
 #else
@@ -11759,7 +11759,7 @@ static int bnxt_pcie_dsn_get(struct bnxt *bp, u8 dsn[])
        u32 dw;
 
        if (!pos) {
-               netdev_info(bp->dev, "Unable do read adapter's DSN");
+               netdev_info(bp->dev, "Unable do read adapter's DSN\n");
                return -EOPNOTSUPP;
        }
 
index eec0168..d3c93cc 100644 (file)
@@ -641,14 +641,14 @@ static int bnxt_dl_params_register(struct bnxt *bp)
        rc = devlink_params_register(bp->dl, bnxt_dl_params,
                                     ARRAY_SIZE(bnxt_dl_params));
        if (rc) {
-               netdev_warn(bp->dev, "devlink_params_register failed. rc=%d",
+               netdev_warn(bp->dev, "devlink_params_register failed. rc=%d\n",
                            rc);
                return rc;
        }
        rc = devlink_port_params_register(&bp->dl_port, bnxt_dl_port_params,
                                          ARRAY_SIZE(bnxt_dl_port_params));
        if (rc) {
-               netdev_err(bp->dev, "devlink_port_params_register failed");
+               netdev_err(bp->dev, "devlink_port_params_register failed\n");
                devlink_params_unregister(bp->dl, bnxt_dl_params,
                                          ARRAY_SIZE(bnxt_dl_params));
                return rc;
@@ -679,7 +679,7 @@ int bnxt_dl_register(struct bnxt *bp)
        else
                dl = devlink_alloc(&bnxt_vf_dl_ops, sizeof(struct bnxt_dl));
        if (!dl) {
-               netdev_warn(bp->dev, "devlink_alloc failed");
+               netdev_warn(bp->dev, "devlink_alloc failed\n");
                return -ENOMEM;
        }
 
@@ -692,7 +692,7 @@ int bnxt_dl_register(struct bnxt *bp)
 
        rc = devlink_register(dl, &bp->pdev->dev);
        if (rc) {
-               netdev_warn(bp->dev, "devlink_register failed. rc=%d", rc);
+               netdev_warn(bp->dev, "devlink_register failed. rc=%d\n", rc);
                goto err_dl_free;
        }
 
@@ -704,7 +704,7 @@ int bnxt_dl_register(struct bnxt *bp)
                               sizeof(bp->dsn));
        rc = devlink_port_register(dl, &bp->dl_port, bp->pf.port_id);
        if (rc) {
-               netdev_err(bp->dev, "devlink_port_register failed");
+               netdev_err(bp->dev, "devlink_port_register failed\n");
                goto err_dl_unreg;
        }
 
index 6171fa8..e8fc167 100644 (file)
@@ -2028,7 +2028,7 @@ int bnxt_flash_package_from_file(struct net_device *dev, const char *filename,
        }
 
        if (fw->size > item_len) {
-               netdev_err(dev, "PKG insufficient update area in nvram: %lu",
+               netdev_err(dev, "PKG insufficient update area in nvram: %lu\n",
                           (unsigned long)fw->size);
                rc = -EFBIG;
        } else {
@@ -3338,7 +3338,7 @@ err:
        kfree(coredump.data);
        *dump_len += sizeof(struct bnxt_coredump_record);
        if (rc == -ENOBUFS)
-               netdev_err(bp->dev, "Firmware returned large coredump buffer");
+               netdev_err(bp->dev, "Firmware returned large coredump buffer\n");
        return rc;
 }
 
index 0cc6ec5..9bec256 100644 (file)
@@ -50,7 +50,7 @@ static u16 bnxt_flow_get_dst_fid(struct bnxt *pf_bp, struct net_device *dev)
 
        /* check if dev belongs to the same switch */
        if (!netdev_port_same_parent_id(pf_bp->dev, dev)) {
-               netdev_info(pf_bp->dev, "dev(ifindex=%d) not on same switch",
+               netdev_info(pf_bp->dev, "dev(ifindex=%d) not on same switch\n",
                            dev->ifindex);
                return BNXT_FID_INVALID;
        }
@@ -70,7 +70,7 @@ static int bnxt_tc_parse_redir(struct bnxt *bp,
        struct net_device *dev = act->dev;
 
        if (!dev) {
-               netdev_info(bp->dev, "no dev in mirred action");
+               netdev_info(bp->dev, "no dev in mirred action\n");
                return -EINVAL;
        }
 
@@ -106,7 +106,7 @@ static int bnxt_tc_parse_tunnel_set(struct bnxt *bp,
        const struct ip_tunnel_key *tun_key = &tun_info->key;
 
        if (ip_tunnel_info_af(tun_info) != AF_INET) {
-               netdev_info(bp->dev, "only IPv4 tunnel-encap is supported");
+               netdev_info(bp->dev, "only IPv4 tunnel-encap is supported\n");
                return -EOPNOTSUPP;
        }
 
@@ -295,7 +295,7 @@ static int bnxt_tc_parse_actions(struct bnxt *bp,
        int i, rc;
 
        if (!flow_action_has_entries(flow_action)) {
-               netdev_info(bp->dev, "no actions");
+               netdev_info(bp->dev, "no actions\n");
                return -EINVAL;
        }
 
@@ -370,7 +370,7 @@ static int bnxt_tc_parse_flow(struct bnxt *bp,
        /* KEY_CONTROL and KEY_BASIC are needed for forming a meaningful key */
        if ((dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL)) == 0 ||
            (dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_BASIC)) == 0) {
-               netdev_info(bp->dev, "cannot form TC key: used_keys = 0x%x",
+               netdev_info(bp->dev, "cannot form TC key: used_keys = 0x%x\n",
                            dissector->used_keys);
                return -EOPNOTSUPP;
        }
@@ -508,7 +508,7 @@ static int bnxt_hwrm_cfa_flow_free(struct bnxt *bp,
 
        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
-               netdev_info(bp->dev, "%s: Error rc=%d", __func__, rc);
+               netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
 
        return rc;
 }
@@ -841,7 +841,7 @@ static int hwrm_cfa_decap_filter_alloc(struct bnxt *bp,
                resp = bnxt_get_hwrm_resp_addr(bp, &req);
                *decap_filter_handle = resp->decap_filter_id;
        } else {
-               netdev_info(bp->dev, "%s: Error rc=%d", __func__, rc);
+               netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
        }
        mutex_unlock(&bp->hwrm_cmd_lock);
 
@@ -859,7 +859,7 @@ static int hwrm_cfa_decap_filter_free(struct bnxt *bp,
 
        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
-               netdev_info(bp->dev, "%s: Error rc=%d", __func__, rc);
+               netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
 
        return rc;
 }
@@ -906,7 +906,7 @@ static int hwrm_cfa_encap_record_alloc(struct bnxt *bp,
                resp = bnxt_get_hwrm_resp_addr(bp, &req);
                *encap_record_handle = resp->encap_record_id;
        } else {
-               netdev_info(bp->dev, "%s: Error rc=%d", __func__, rc);
+               netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
        }
        mutex_unlock(&bp->hwrm_cmd_lock);
 
@@ -924,7 +924,7 @@ static int hwrm_cfa_encap_record_free(struct bnxt *bp,
 
        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
-               netdev_info(bp->dev, "%s: Error rc=%d", __func__, rc);
+               netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
 
        return rc;
 }
@@ -943,7 +943,7 @@ static int bnxt_tc_put_l2_node(struct bnxt *bp,
                                             tc_info->l2_ht_params);
                if (rc)
                        netdev_err(bp->dev,
-                                  "Error: %s: rhashtable_remove_fast: %d",
+                                  "Error: %s: rhashtable_remove_fast: %d\n",
                                   __func__, rc);
                kfree_rcu(l2_node, rcu);
        }
@@ -972,7 +972,7 @@ bnxt_tc_get_l2_node(struct bnxt *bp, struct rhashtable *l2_table,
                if (rc) {
                        kfree_rcu(l2_node, rcu);
                        netdev_err(bp->dev,
-                                  "Error: %s: rhashtable_insert_fast: %d",
+                                  "Error: %s: rhashtable_insert_fast: %d\n",
                                   __func__, rc);
                        return NULL;
                }
@@ -1031,7 +1031,7 @@ static bool bnxt_tc_can_offload(struct bnxt *bp, struct bnxt_tc_flow *flow)
        if ((flow->flags & BNXT_TC_FLOW_FLAGS_PORTS) &&
            (flow->l4_key.ip_proto != IPPROTO_TCP &&
             flow->l4_key.ip_proto != IPPROTO_UDP)) {
-               netdev_info(bp->dev, "Cannot offload non-TCP/UDP (%d) ports",
+               netdev_info(bp->dev, "Cannot offload non-TCP/UDP (%d) ports\n",
                            flow->l4_key.ip_proto);
                return false;
        }
@@ -1088,7 +1088,7 @@ static int bnxt_tc_put_tunnel_node(struct bnxt *bp,
                rc =  rhashtable_remove_fast(tunnel_table, &tunnel_node->node,
                                             *ht_params);
                if (rc) {
-                       netdev_err(bp->dev, "rhashtable_remove_fast rc=%d", rc);
+                       netdev_err(bp->dev, "rhashtable_remove_fast rc=%d\n", rc);
                        rc = -1;
                }
                kfree_rcu(tunnel_node, rcu);
@@ -1129,7 +1129,7 @@ bnxt_tc_get_tunnel_node(struct bnxt *bp, struct rhashtable *tunnel_table,
        tunnel_node->refcount++;
        return tunnel_node;
 err:
-       netdev_info(bp->dev, "error rc=%d", rc);
+       netdev_info(bp->dev, "error rc=%d\n", rc);
        return NULL;
 }
 
@@ -1187,7 +1187,7 @@ static void bnxt_tc_put_decap_l2_node(struct bnxt *bp,
                                             &decap_l2_node->node,
                                             tc_info->decap_l2_ht_params);
                if (rc)
-                       netdev_err(bp->dev, "rhashtable_remove_fast rc=%d", rc);
+                       netdev_err(bp->dev, "rhashtable_remove_fast rc=%d\n", rc);
                kfree_rcu(decap_l2_node, rcu);
        }
 }
@@ -1227,7 +1227,7 @@ static int bnxt_tc_resolve_tunnel_hdrs(struct bnxt *bp,
 
        rt = ip_route_output_key(dev_net(real_dst_dev), &flow);
        if (IS_ERR(rt)) {
-               netdev_info(bp->dev, "no route to %pI4b", &flow.daddr);
+               netdev_info(bp->dev, "no route to %pI4b\n", &flow.daddr);
                return -EOPNOTSUPP;
        }
 
@@ -1241,7 +1241,7 @@ static int bnxt_tc_resolve_tunnel_hdrs(struct bnxt *bp,
 
                if (vlan->real_dev != real_dst_dev) {
                        netdev_info(bp->dev,
-                                   "dst_dev(%s) doesn't use PF-if(%s)",
+                                   "dst_dev(%s) doesn't use PF-if(%s)\n",
                                    netdev_name(dst_dev),
                                    netdev_name(real_dst_dev));
                        rc = -EOPNOTSUPP;
@@ -1253,7 +1253,7 @@ static int bnxt_tc_resolve_tunnel_hdrs(struct bnxt *bp,
 #endif
        } else if (dst_dev != real_dst_dev) {
                netdev_info(bp->dev,
-                           "dst_dev(%s) for %pI4b is not PF-if(%s)",
+                           "dst_dev(%s) for %pI4b is not PF-if(%s)\n",
                            netdev_name(dst_dev), &flow.daddr,
                            netdev_name(real_dst_dev));
                rc = -EOPNOTSUPP;
@@ -1262,7 +1262,7 @@ static int bnxt_tc_resolve_tunnel_hdrs(struct bnxt *bp,
 
        nbr = dst_neigh_lookup(&rt->dst, &flow.daddr);
        if (!nbr) {
-               netdev_info(bp->dev, "can't lookup neighbor for %pI4b",
+               netdev_info(bp->dev, "can't lookup neighbor for %pI4b\n",
                            &flow.daddr);
                rc = -EOPNOTSUPP;
                goto put_rt;
@@ -1472,7 +1472,7 @@ static int __bnxt_tc_del_flow(struct bnxt *bp,
        rc = rhashtable_remove_fast(&tc_info->flow_table, &flow_node->node,
                                    tc_info->flow_ht_params);
        if (rc)
-               netdev_err(bp->dev, "Error: %s: rhashtable_remove_fast rc=%d",
+               netdev_err(bp->dev, "Error: %s: rhashtable_remove_fast rc=%d\n",
                           __func__, rc);
 
        kfree_rcu(flow_node, rcu);
@@ -1587,7 +1587,7 @@ unlock:
 free_node:
        kfree_rcu(new_node, rcu);
 done:
-       netdev_err(bp->dev, "Error: %s: cookie=0x%lx error=%d",
+       netdev_err(bp->dev, "Error: %s: cookie=0x%lx error=%d\n",
                   __func__, tc_flow_cmd->cookie, rc);
        return rc;
 }
@@ -1700,7 +1700,7 @@ bnxt_hwrm_cfa_flow_stats_get(struct bnxt *bp, int num_flows,
                                                le64_to_cpu(resp_bytes[i]);
                }
        } else {
-               netdev_info(bp->dev, "error rc=%d", rc);
+               netdev_info(bp->dev, "error rc=%d\n", rc);
        }
        mutex_unlock(&bp->hwrm_cmd_lock);
 
@@ -1970,7 +1970,7 @@ static int bnxt_tc_indr_block_event(struct notifier_block *nb,
                                                   bp);
                if (rc)
                        netdev_info(bp->dev,
-                                   "Failed to register indirect blk: dev: %s",
+                                   "Failed to register indirect blk: dev: %s\n",
                                    netdev->name);
                break;
        case NETDEV_UNREGISTER:
index b010b34..6f2faf8 100644 (file)
@@ -43,7 +43,7 @@ static int hwrm_cfa_vfr_alloc(struct bnxt *bp, u16 vf_idx,
                netdev_dbg(bp->dev, "tx_cfa_action=0x%x, rx_cfa_code=0x%x",
                           *tx_cfa_action, *rx_cfa_code);
        } else {
-               netdev_info(bp->dev, "%s error rc=%d", __func__, rc);
+               netdev_info(bp->dev, "%s error rc=%d\n", __func__, rc);
        }
 
        mutex_unlock(&bp->hwrm_cmd_lock);
@@ -60,7 +60,7 @@ static int hwrm_cfa_vfr_free(struct bnxt *bp, u16 vf_idx)
 
        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
-               netdev_info(bp->dev, "%s error rc=%d", __func__, rc);
+               netdev_info(bp->dev, "%s error rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -465,7 +465,7 @@ static int bnxt_vf_reps_create(struct bnxt *bp)
        return 0;
 
 err:
-       netdev_info(bp->dev, "%s error=%d", __func__, rc);
+       netdev_info(bp->dev, "%s error=%d\n", __func__, rc);
        kfree(cfa_code_map);
        __bnxt_vf_reps_destroy(bp);
        return rc;
@@ -488,7 +488,7 @@ int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode,
 
        mutex_lock(&bp->sriov_lock);
        if (bp->eswitch_mode == mode) {
-               netdev_info(bp->dev, "already in %s eswitch mode",
+               netdev_info(bp->dev, "already in %s eswitch mode\n",
                            mode == DEVLINK_ESWITCH_MODE_LEGACY ?
                            "legacy" : "switchdev");
                rc = -EINVAL;
@@ -508,7 +508,7 @@ int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode,
                }
 
                if (pci_num_vf(bp->pdev) == 0) {
-                       netdev_info(bp->dev, "Enable VFs before setting switchdev mode");
+                       netdev_info(bp->dev, "Enable VFs before setting switchdev mode\n");
                        rc = -EPERM;
                        goto done;
                }
index 6392a25..1024494 100644 (file)
@@ -294,6 +294,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
         */
        if (priv->ext_phy) {
                reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
+               reg &= ~ID_MODE_DIS;
                reg |= id_mode_dis;
                if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv))
                        reg |= RGMII_MODE_EN_V123;
index 6f2cf56..79b3d53 100644 (file)
@@ -297,6 +297,7 @@ static int set_hw_ioctxt(struct hinic_hwdev *hwdev, unsigned int rq_depth,
        }
 
        hw_ioctxt.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
+       hw_ioctxt.ppf_idx = HINIC_HWIF_PPF_IDX(hwif);
 
        hw_ioctxt.set_cmdq_depth = HW_IOCTXT_SET_CMDQ_DEPTH_DEFAULT;
        hw_ioctxt.cmdq_depth = 0;
index b069045..66fd234 100644 (file)
@@ -151,8 +151,8 @@ struct hinic_cmd_hw_ioctxt {
 
        u8      lro_en;
        u8      rsvd3;
+       u8      ppf_idx;
        u8      rsvd4;
-       u8      rsvd5;
 
        u16     rq_depth;
        u16     rx_buf_sz_idx;
index 5177945..c7bb9ce 100644 (file)
 #define HINIC_HWIF_FUNC_IDX(hwif)       ((hwif)->attr.func_idx)
 #define HINIC_HWIF_PCI_INTF(hwif)       ((hwif)->attr.pci_intf_idx)
 #define HINIC_HWIF_PF_IDX(hwif)         ((hwif)->attr.pf_idx)
+#define HINIC_HWIF_PPF_IDX(hwif)        ((hwif)->attr.ppf_idx)
 
 #define HINIC_FUNC_TYPE(hwif)           ((hwif)->attr.func_type)
 #define HINIC_IS_PF(hwif)               (HINIC_FUNC_TYPE(hwif) == HINIC_PF)
index f4a339b..79091e1 100644 (file)
@@ -94,6 +94,7 @@ struct hinic_rq {
 
        struct hinic_wq         *wq;
 
+       struct cpumask          affinity_mask;
        u32                     irq;
        u16                     msix_entry;
 
index 02a14f5..1356097 100644 (file)
@@ -356,7 +356,8 @@ static void hinic_enable_rss(struct hinic_dev *nic_dev)
        if (!num_cpus)
                num_cpus = num_online_cpus();
 
-       nic_dev->num_qps = min_t(u16, nic_dev->max_qps, num_cpus);
+       nic_dev->num_qps = hinic_hwdev_num_qps(hwdev);
+       nic_dev->num_qps = min_t(u16, nic_dev->num_qps, num_cpus);
 
        nic_dev->rss_limit = nic_dev->num_qps;
        nic_dev->num_rss = nic_dev->num_qps;
index 56ea6d6..2695ad6 100644 (file)
@@ -475,7 +475,6 @@ static int rx_request_irq(struct hinic_rxq *rxq)
        struct hinic_hwdev *hwdev = nic_dev->hwdev;
        struct hinic_rq *rq = rxq->rq;
        struct hinic_qp *qp;
-       struct cpumask mask;
        int err;
 
        rx_add_napi(rxq);
@@ -492,8 +491,8 @@ static int rx_request_irq(struct hinic_rxq *rxq)
        }
 
        qp = container_of(rq, struct hinic_qp, rq);
-       cpumask_set_cpu(qp->q_id % num_online_cpus(), &mask);
-       return irq_set_affinity_hint(rq->irq, &mask);
+       cpumask_set_cpu(qp->q_id % num_online_cpus(), &rq->affinity_mask);
+       return irq_set_affinity_hint(rq->irq, &rq->affinity_mask);
 }
 
 static void rx_free_irq(struct hinic_rxq *rxq)
index 9669836..21de476 100644 (file)
@@ -5147,7 +5147,6 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv)
 
 static void mlx5e_nic_disable(struct mlx5e_priv *priv)
 {
-       struct net_device *netdev = priv->netdev;
        struct mlx5_core_dev *mdev = priv->mdev;
 
 #ifdef CONFIG_MLX5_CORE_EN_DCB
@@ -5168,7 +5167,7 @@ static void mlx5e_nic_disable(struct mlx5e_priv *priv)
                mlx5e_monitor_counter_cleanup(priv);
 
        mlx5e_disable_async_events(priv);
-       mlx5_lag_remove(mdev, netdev);
+       mlx5_lag_remove(mdev);
 }
 
 int mlx5e_update_nic_rx(struct mlx5e_priv *priv)
index 7b48cca..6ed307d 100644 (file)
@@ -1861,7 +1861,6 @@ static void mlx5e_uplink_rep_enable(struct mlx5e_priv *priv)
 
 static void mlx5e_uplink_rep_disable(struct mlx5e_priv *priv)
 {
-       struct net_device *netdev = priv->netdev;
        struct mlx5_core_dev *mdev = priv->mdev;
        struct mlx5e_rep_priv *rpriv = priv->ppriv;
 
@@ -1870,7 +1869,7 @@ static void mlx5e_uplink_rep_disable(struct mlx5e_priv *priv)
 #endif
        mlx5_notifier_unregister(mdev, &priv->events_nb);
        cancel_work_sync(&rpriv->uplink_priv.reoffload_flows_work);
-       mlx5_lag_remove(mdev, netdev);
+       mlx5_lag_remove(mdev);
 }
 
 static MLX5E_DEFINE_STATS_GRP(sw_rep, 0);
index b91eabc..8e19f6a 100644 (file)
@@ -464,9 +464,6 @@ static int mlx5_lag_netdev_event(struct notifier_block *this,
        struct mlx5_lag *ldev;
        int changed = 0;
 
-       if (!net_eq(dev_net(ndev), &init_net))
-               return NOTIFY_DONE;
-
        if ((event != NETDEV_CHANGEUPPER) && (event != NETDEV_CHANGELOWERSTATE))
                return NOTIFY_DONE;
 
@@ -586,8 +583,7 @@ void mlx5_lag_add(struct mlx5_core_dev *dev, struct net_device *netdev)
 
        if (!ldev->nb.notifier_call) {
                ldev->nb.notifier_call = mlx5_lag_netdev_event;
-               if (register_netdevice_notifier_dev_net(netdev, &ldev->nb,
-                                                       &ldev->nn)) {
+               if (register_netdevice_notifier_net(&init_net, &ldev->nb)) {
                        ldev->nb.notifier_call = NULL;
                        mlx5_core_err(dev, "Failed to register LAG netdev notifier\n");
                }
@@ -600,7 +596,7 @@ void mlx5_lag_add(struct mlx5_core_dev *dev, struct net_device *netdev)
 }
 
 /* Must be called with intf_mutex held */
-void mlx5_lag_remove(struct mlx5_core_dev *dev, struct net_device *netdev)
+void mlx5_lag_remove(struct mlx5_core_dev *dev)
 {
        struct mlx5_lag *ldev;
        int i;
@@ -620,8 +616,7 @@ void mlx5_lag_remove(struct mlx5_core_dev *dev, struct net_device *netdev)
 
        if (i == MLX5_MAX_PORTS) {
                if (ldev->nb.notifier_call)
-                       unregister_netdevice_notifier_dev_net(netdev, &ldev->nb,
-                                                             &ldev->nn);
+                       unregister_netdevice_notifier_net(&init_net, &ldev->nb);
                mlx5_lag_mp_cleanup(ldev);
                cancel_delayed_work_sync(&ldev->bond_work);
                mlx5_lag_dev_free(ldev);
index 316ab09..f1068aa 100644 (file)
@@ -44,7 +44,6 @@ struct mlx5_lag {
        struct workqueue_struct   *wq;
        struct delayed_work       bond_work;
        struct notifier_block     nb;
-       struct netdev_net_notifier      nn;
        struct lag_mp             lag_mp;
 };
 
index fcce9e0..da67b28 100644 (file)
@@ -157,7 +157,7 @@ int mlx5_query_qcam_reg(struct mlx5_core_dev *mdev, u32 *qcam,
                        u8 feature_group, u8 access_reg_group);
 
 void mlx5_lag_add(struct mlx5_core_dev *dev, struct net_device *netdev);
-void mlx5_lag_remove(struct mlx5_core_dev *dev, struct net_device *netdev);
+void mlx5_lag_remove(struct mlx5_core_dev *dev);
 
 int mlx5_irq_table_init(struct mlx5_core_dev *dev);
 void mlx5_irq_table_cleanup(struct mlx5_core_dev *dev);
index e0d7d2d..43fa8c8 100644 (file)
@@ -28,7 +28,7 @@
 #define MLXSW_PCI_SW_RESET                     0xF0010
 #define MLXSW_PCI_SW_RESET_RST_BIT             BIT(0)
 #define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS       900000
-#define MLXSW_PCI_SW_RESET_WAIT_MSECS          100
+#define MLXSW_PCI_SW_RESET_WAIT_MSECS          200
 #define MLXSW_PCI_FW_READY                     0xA1844
 #define MLXSW_PCI_FW_READY_MASK                        0xFFFF
 #define MLXSW_PCI_FW_READY_MAGIC               0x5E
index 1c9e70c..58579ba 100644 (file)
@@ -513,14 +513,17 @@ static irqreturn_t ks_irq(int irq, void *pw)
 {
        struct net_device *netdev = pw;
        struct ks_net *ks = netdev_priv(netdev);
+       unsigned long flags;
        u16 status;
 
+       spin_lock_irqsave(&ks->statelock, flags);
        /*this should be the first in IRQ handler */
        ks_save_cmd_reg(ks);
 
        status = ks_rdreg16(ks, KS_ISR);
        if (unlikely(!status)) {
                ks_restore_cmd_reg(ks);
+               spin_unlock_irqrestore(&ks->statelock, flags);
                return IRQ_NONE;
        }
 
@@ -546,6 +549,7 @@ static irqreturn_t ks_irq(int irq, void *pw)
                ks->netdev->stats.rx_over_errors++;
        /* this should be the last in IRQ handler*/
        ks_restore_cmd_reg(ks);
+       spin_unlock_irqrestore(&ks->statelock, flags);
        return IRQ_HANDLED;
 }
 
@@ -615,6 +619,7 @@ static int ks_net_stop(struct net_device *netdev)
 
        /* shutdown RX/TX QMU */
        ks_disable_qmu(ks);
+       ks_disable_int(ks);
 
        /* set powermode to soft power down to save power */
        ks_set_powermode(ks, PMECR_PM_SOFTDOWN);
@@ -671,10 +676,9 @@ static netdev_tx_t ks_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
        netdev_tx_t retv = NETDEV_TX_OK;
        struct ks_net *ks = netdev_priv(netdev);
+       unsigned long flags;
 
-       disable_irq(netdev->irq);
-       ks_disable_int(ks);
-       spin_lock(&ks->statelock);
+       spin_lock_irqsave(&ks->statelock, flags);
 
        /* Extra space are required:
        *  4 byte for alignment, 4 for status/length, 4 for CRC
@@ -688,9 +692,7 @@ static netdev_tx_t ks_start_xmit(struct sk_buff *skb, struct net_device *netdev)
                dev_kfree_skb(skb);
        } else
                retv = NETDEV_TX_BUSY;
-       spin_unlock(&ks->statelock);
-       ks_enable_int(ks);
-       enable_irq(netdev->irq);
+       spin_unlock_irqrestore(&ks->statelock, flags);
        return retv;
 }
 
index 06de595..fbf4cbc 100644 (file)
 #include "rmnet_vnd.h"
 #include "rmnet_private.h"
 
-/* Locking scheme -
- * The shared resource which needs to be protected is realdev->rx_handler_data.
- * For the writer path, this is using rtnl_lock(). The writer paths are
- * rmnet_newlink(), rmnet_dellink() and rmnet_force_unassociate_device(). These
- * paths are already called with rtnl_lock() acquired in. There is also an
- * ASSERT_RTNL() to ensure that we are calling with rtnl acquired. For
- * dereference here, we will need to use rtnl_dereference(). Dev list writing
- * needs to happen with rtnl_lock() acquired for netdev_master_upper_dev_link().
- * For the reader path, the real_dev->rx_handler_data is called in the TX / RX
- * path. We only need rcu_read_lock() for these scenarios. In these cases,
- * the rcu_read_lock() is held in __dev_queue_xmit() and
- * netif_receive_skb_internal(), so readers need to use rcu_dereference_rtnl()
- * to get the relevant information. For dev list reading, we again acquire
- * rcu_read_lock() in rmnet_dellink() for netdev_master_upper_dev_get_rcu().
- * We also use unregister_netdevice_many() to free all rmnet devices in
- * rmnet_force_unassociate_device() so we dont lose the rtnl_lock() and free in
- * same context.
- */
-
 /* Local Definitions and Declarations */
 
 static const struct nla_policy rmnet_policy[IFLA_RMNET_MAX + 1] = {
@@ -51,9 +32,10 @@ rmnet_get_port_rtnl(const struct net_device *real_dev)
        return rtnl_dereference(real_dev->rx_handler_data);
 }
 
-static int rmnet_unregister_real_device(struct net_device *real_dev,
-                                       struct rmnet_port *port)
+static int rmnet_unregister_real_device(struct net_device *real_dev)
 {
+       struct rmnet_port *port = rmnet_get_port_rtnl(real_dev);
+
        if (port->nr_rmnet_devs)
                return -EINVAL;
 
@@ -61,9 +43,6 @@ static int rmnet_unregister_real_device(struct net_device *real_dev,
 
        kfree(port);
 
-       /* release reference on real_dev */
-       dev_put(real_dev);
-
        netdev_dbg(real_dev, "Removed from rmnet\n");
        return 0;
 }
@@ -89,9 +68,6 @@ static int rmnet_register_real_device(struct net_device *real_dev)
                return -EBUSY;
        }
 
-       /* hold on to real dev for MAP data */
-       dev_hold(real_dev);
-
        for (entry = 0; entry < RMNET_MAX_LOGICAL_EP; entry++)
                INIT_HLIST_HEAD(&port->muxed_ep[entry]);
 
@@ -99,28 +75,33 @@ static int rmnet_register_real_device(struct net_device *real_dev)
        return 0;
 }
 
-static void rmnet_unregister_bridge(struct net_device *dev,
-                                   struct rmnet_port *port)
+static void rmnet_unregister_bridge(struct rmnet_port *port)
 {
-       struct rmnet_port *bridge_port;
-       struct net_device *bridge_dev;
+       struct net_device *bridge_dev, *real_dev, *rmnet_dev;
+       struct rmnet_port *real_port;
 
        if (port->rmnet_mode != RMNET_EPMODE_BRIDGE)
                return;
 
-       /* bridge slave handling */
+       rmnet_dev = port->rmnet_dev;
        if (!port->nr_rmnet_devs) {
-               bridge_dev = port->bridge_ep;
+               /* bridge device */
+               real_dev = port->bridge_ep;
+               bridge_dev = port->dev;
 
-               bridge_port = rmnet_get_port_rtnl(bridge_dev);
-               bridge_port->bridge_ep = NULL;
-               bridge_port->rmnet_mode = RMNET_EPMODE_VND;
+               real_port = rmnet_get_port_rtnl(real_dev);
+               real_port->bridge_ep = NULL;
+               real_port->rmnet_mode = RMNET_EPMODE_VND;
        } else {
+               /* real device */
                bridge_dev = port->bridge_ep;
 
-               bridge_port = rmnet_get_port_rtnl(bridge_dev);
-               rmnet_unregister_real_device(bridge_dev, bridge_port);
+               port->bridge_ep = NULL;
+               port->rmnet_mode = RMNET_EPMODE_VND;
        }
+
+       netdev_upper_dev_unlink(bridge_dev, rmnet_dev);
+       rmnet_unregister_real_device(bridge_dev);
 }
 
 static int rmnet_newlink(struct net *src_net, struct net_device *dev,
@@ -135,6 +116,11 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
        int err = 0;
        u16 mux_id;
 
+       if (!tb[IFLA_LINK]) {
+               NL_SET_ERR_MSG_MOD(extack, "link not specified");
+               return -EINVAL;
+       }
+
        real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
        if (!real_dev || !dev)
                return -ENODEV;
@@ -157,7 +143,12 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
        if (err)
                goto err1;
 
+       err = netdev_upper_dev_link(real_dev, dev, extack);
+       if (err < 0)
+               goto err2;
+
        port->rmnet_mode = mode;
+       port->rmnet_dev = dev;
 
        hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
 
@@ -173,8 +164,11 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 
        return 0;
 
+err2:
+       unregister_netdevice(dev);
+       rmnet_vnd_dellink(mux_id, port, ep);
 err1:
-       rmnet_unregister_real_device(real_dev, port);
+       rmnet_unregister_real_device(real_dev);
 err0:
        kfree(ep);
        return err;
@@ -183,77 +177,74 @@ err0:
 static void rmnet_dellink(struct net_device *dev, struct list_head *head)
 {
        struct rmnet_priv *priv = netdev_priv(dev);
-       struct net_device *real_dev;
+       struct net_device *real_dev, *bridge_dev;
+       struct rmnet_port *real_port, *bridge_port;
        struct rmnet_endpoint *ep;
-       struct rmnet_port *port;
-       u8 mux_id;
+       u8 mux_id = priv->mux_id;
 
        real_dev = priv->real_dev;
 
-       if (!real_dev || !rmnet_is_real_dev_registered(real_dev))
+       if (!rmnet_is_real_dev_registered(real_dev))
                return;
 
-       port = rmnet_get_port_rtnl(real_dev);
-
-       mux_id = rmnet_vnd_get_mux(dev);
+       real_port = rmnet_get_port_rtnl(real_dev);
+       bridge_dev = real_port->bridge_ep;
+       if (bridge_dev) {
+               bridge_port = rmnet_get_port_rtnl(bridge_dev);
+               rmnet_unregister_bridge(bridge_port);
+       }
 
-       ep = rmnet_get_endpoint(port, mux_id);
+       ep = rmnet_get_endpoint(real_port, mux_id);
        if (ep) {
                hlist_del_init_rcu(&ep->hlnode);
-               rmnet_unregister_bridge(dev, port);
-               rmnet_vnd_dellink(mux_id, port, ep);
+               rmnet_vnd_dellink(mux_id, real_port, ep);
                kfree(ep);
        }
-       rmnet_unregister_real_device(real_dev, port);
 
+       netdev_upper_dev_unlink(real_dev, dev);
+       rmnet_unregister_real_device(real_dev);
        unregister_netdevice_queue(dev, head);
 }
 
-static void rmnet_force_unassociate_device(struct net_device *dev)
+static void rmnet_force_unassociate_device(struct net_device *real_dev)
 {
-       struct net_device *real_dev = dev;
        struct hlist_node *tmp_ep;
        struct rmnet_endpoint *ep;
        struct rmnet_port *port;
        unsigned long bkt_ep;
        LIST_HEAD(list);
 
-       if (!rmnet_is_real_dev_registered(real_dev))
-               return;
-
-       ASSERT_RTNL();
-
-       port = rmnet_get_port_rtnl(dev);
-
-       rcu_read_lock();
-       rmnet_unregister_bridge(dev, port);
-
-       hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
-               unregister_netdevice_queue(ep->egress_dev, &list);
-               rmnet_vnd_dellink(ep->mux_id, port, ep);
+       port = rmnet_get_port_rtnl(real_dev);
 
-               hlist_del_init_rcu(&ep->hlnode);
-               kfree(ep);
+       if (port->nr_rmnet_devs) {
+               /* real device */
+               rmnet_unregister_bridge(port);
+               hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
+                       unregister_netdevice_queue(ep->egress_dev, &list);
+                       netdev_upper_dev_unlink(real_dev, ep->egress_dev);
+                       rmnet_vnd_dellink(ep->mux_id, port, ep);
+                       hlist_del_init_rcu(&ep->hlnode);
+                       kfree(ep);
+               }
+               rmnet_unregister_real_device(real_dev);
+               unregister_netdevice_many(&list);
+       } else {
+               rmnet_unregister_bridge(port);
        }
-
-       rcu_read_unlock();
-       unregister_netdevice_many(&list);
-
-       rmnet_unregister_real_device(real_dev, port);
 }
 
 static int rmnet_config_notify_cb(struct notifier_block *nb,
                                  unsigned long event, void *data)
 {
-       struct net_device *dev = netdev_notifier_info_to_dev(data);
+       struct net_device *real_dev = netdev_notifier_info_to_dev(data);
 
-       if (!dev)
+       if (!rmnet_is_real_dev_registered(real_dev))
                return NOTIFY_DONE;
 
        switch (event) {
        case NETDEV_UNREGISTER:
-               netdev_dbg(dev, "Kernel unregister\n");
-               rmnet_force_unassociate_device(dev);
+               netdev_dbg(real_dev, "Kernel unregister\n");
+               rmnet_force_unassociate_device(real_dev);
                break;
 
        default:
@@ -295,16 +286,18 @@ static int rmnet_changelink(struct net_device *dev, struct nlattr *tb[],
        if (!dev)
                return -ENODEV;
 
-       real_dev = __dev_get_by_index(dev_net(dev),
-                                     nla_get_u32(tb[IFLA_LINK]));
-
-       if (!real_dev || !rmnet_is_real_dev_registered(real_dev))
+       real_dev = priv->real_dev;
+       if (!rmnet_is_real_dev_registered(real_dev))
                return -ENODEV;
 
        port = rmnet_get_port_rtnl(real_dev);
 
        if (data[IFLA_RMNET_MUX_ID]) {
                mux_id = nla_get_u16(data[IFLA_RMNET_MUX_ID]);
+               if (rmnet_get_endpoint(port, mux_id)) {
+                       NL_SET_ERR_MSG_MOD(extack, "MUX ID already exists");
+                       return -EINVAL;
+               }
                ep = rmnet_get_endpoint(port, priv->mux_id);
                if (!ep)
                        return -ENODEV;
@@ -379,11 +372,10 @@ struct rtnl_link_ops rmnet_link_ops __read_mostly = {
        .fill_info      = rmnet_fill_info,
 };
 
-/* Needs either rcu_read_lock() or rtnl lock */
-struct rmnet_port *rmnet_get_port(struct net_device *real_dev)
+struct rmnet_port *rmnet_get_port_rcu(struct net_device *real_dev)
 {
        if (rmnet_is_real_dev_registered(real_dev))
-               return rcu_dereference_rtnl(real_dev->rx_handler_data);
+               return rcu_dereference_bh(real_dev->rx_handler_data);
        else
                return NULL;
 }
@@ -409,7 +401,7 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
        struct rmnet_port *port, *slave_port;
        int err;
 
-       port = rmnet_get_port(real_dev);
+       port = rmnet_get_port_rtnl(real_dev);
 
        /* If there is more than one rmnet dev attached, its probably being
         * used for muxing. Skip the briding in that case
@@ -417,6 +409,9 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
        if (port->nr_rmnet_devs > 1)
                return -EINVAL;
 
+       if (port->rmnet_mode != RMNET_EPMODE_VND)
+               return -EINVAL;
+
        if (rmnet_is_real_dev_registered(slave_dev))
                return -EBUSY;
 
@@ -424,9 +419,17 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
        if (err)
                return -EBUSY;
 
-       slave_port = rmnet_get_port(slave_dev);
+       err = netdev_master_upper_dev_link(slave_dev, rmnet_dev, NULL, NULL,
+                                          extack);
+       if (err) {
+               rmnet_unregister_real_device(slave_dev);
+               return err;
+       }
+
+       slave_port = rmnet_get_port_rtnl(slave_dev);
        slave_port->rmnet_mode = RMNET_EPMODE_BRIDGE;
        slave_port->bridge_ep = real_dev;
+       slave_port->rmnet_dev = rmnet_dev;
 
        port->rmnet_mode = RMNET_EPMODE_BRIDGE;
        port->bridge_ep = slave_dev;
@@ -438,16 +441,9 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
 int rmnet_del_bridge(struct net_device *rmnet_dev,
                     struct net_device *slave_dev)
 {
-       struct rmnet_priv *priv = netdev_priv(rmnet_dev);
-       struct net_device *real_dev = priv->real_dev;
-       struct rmnet_port *port, *slave_port;
+       struct rmnet_port *port = rmnet_get_port_rtnl(slave_dev);
 
-       port = rmnet_get_port(real_dev);
-       port->rmnet_mode = RMNET_EPMODE_VND;
-       port->bridge_ep = NULL;
-
-       slave_port = rmnet_get_port(slave_dev);
-       rmnet_unregister_real_device(slave_dev, slave_port);
+       rmnet_unregister_bridge(port);
 
        netdev_dbg(slave_dev, "removed from rmnet as slave\n");
        return 0;
@@ -473,8 +469,8 @@ static int __init rmnet_init(void)
 
 static void __exit rmnet_exit(void)
 {
-       unregister_netdevice_notifier(&rmnet_dev_notifier);
        rtnl_link_unregister(&rmnet_link_ops);
+       unregister_netdevice_notifier(&rmnet_dev_notifier);
 }
 
 module_init(rmnet_init)
index cd0a6bc..be51598 100644 (file)
@@ -28,6 +28,7 @@ struct rmnet_port {
        u8 rmnet_mode;
        struct hlist_head muxed_ep[RMNET_MAX_LOGICAL_EP];
        struct net_device *bridge_ep;
+       struct net_device *rmnet_dev;
 };
 
 extern struct rtnl_link_ops rmnet_link_ops;
@@ -65,7 +66,7 @@ struct rmnet_priv {
        struct rmnet_priv_stats stats;
 };
 
-struct rmnet_port *rmnet_get_port(struct net_device *real_dev);
+struct rmnet_port *rmnet_get_port_rcu(struct net_device *real_dev);
 struct rmnet_endpoint *rmnet_get_endpoint(struct rmnet_port *port, u8 mux_id);
 int rmnet_add_bridge(struct net_device *rmnet_dev,
                     struct net_device *slave_dev,
index 1b74bc1..29a7bfa 100644 (file)
@@ -159,6 +159,9 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
 static void
 rmnet_bridge_handler(struct sk_buff *skb, struct net_device *bridge_dev)
 {
+       if (skb_mac_header_was_set(skb))
+               skb_push(skb, skb->mac_len);
+
        if (bridge_dev) {
                skb->dev = bridge_dev;
                dev_queue_xmit(skb);
@@ -184,7 +187,7 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
                return RX_HANDLER_PASS;
 
        dev = skb->dev;
-       port = rmnet_get_port(dev);
+       port = rmnet_get_port_rcu(dev);
 
        switch (port->rmnet_mode) {
        case RMNET_EPMODE_VND:
@@ -217,7 +220,7 @@ void rmnet_egress_handler(struct sk_buff *skb)
        skb->dev = priv->real_dev;
        mux_id = priv->mux_id;
 
-       port = rmnet_get_port(skb->dev);
+       port = rmnet_get_port_rcu(skb->dev);
        if (!port)
                goto drop;
 
index 509dfc8..26ad40f 100644 (file)
@@ -266,14 +266,6 @@ int rmnet_vnd_dellink(u8 id, struct rmnet_port *port,
        return 0;
 }
 
-u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev)
-{
-       struct rmnet_priv *priv;
-
-       priv = netdev_priv(rmnet_dev);
-       return priv->mux_id;
-}
-
 int rmnet_vnd_do_flow_control(struct net_device *rmnet_dev, int enable)
 {
        netdev_dbg(rmnet_dev, "Setting VND TX queue state to %d\n", enable);
index 54cbaf3..14d77c7 100644 (file)
@@ -16,6 +16,5 @@ int rmnet_vnd_dellink(u8 id, struct rmnet_port *port,
                      struct rmnet_endpoint *ep);
 void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev);
 void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev);
-u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev);
 void rmnet_vnd_setup(struct net_device *dev);
 #endif /* _RMNET_VND_H_ */
index af15a73..59b4f16 100644 (file)
@@ -560,13 +560,45 @@ efx_ptp_mac_nic_to_ktime_correction(struct efx_nic *efx,
                                    u32 nic_major, u32 nic_minor,
                                    s32 correction)
 {
+       u32 sync_timestamp;
        ktime_t kt = { 0 };
+       s16 delta;
 
        if (!(nic_major & 0x80000000)) {
                WARN_ON_ONCE(nic_major >> 16);
-               /* Use the top bits from the latest sync event. */
-               nic_major &= 0xffff;
-               nic_major |= (last_sync_timestamp_major(efx) & 0xffff0000);
+
+               /* Medford provides 48 bits of timestamp, so we must get the top
+                * 16 bits from the timesync event state.
+                *
+                * We only have the lower 16 bits of the time now, but we do
+                * have a full resolution timestamp at some point in past. As
+                * long as the difference between the (real) now and the sync
+                * is less than 2^15, then we can reconstruct the difference
+                * between those two numbers using only the lower 16 bits of
+                * each.
+                *
+                * Put another way
+                *
+                * a - b = ((a mod k) - b) mod k
+                *
+                * when -k/2 < (a-b) < k/2. In our case k is 2^16. We know
+                * (a mod k) and b, so can calculate the delta, a - b.
+                *
+                */
+               sync_timestamp = last_sync_timestamp_major(efx);
+
+               /* Because delta is s16 this does an implicit mask down to
+                * 16 bits which is what we need, assuming
+                * MEDFORD_TX_SECS_EVENT_BITS is 16. delta is signed so that
+                * we can deal with the (unlikely) case of sync timestamps
+                * arriving from the future.
+                */
+               delta = nic_major - sync_timestamp;
+
+               /* Recover the fully specified time now, by applying the offset
+                * to the (fully specified) sync time.
+                */
+               nic_major = sync_timestamp + delta;
 
                kt = ptp->nic_to_kernel_time(nic_major, nic_minor,
                                             correction);
index 5836b21..7da18c9 100644 (file)
@@ -4405,6 +4405,8 @@ static void stmmac_init_fs(struct net_device *dev)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
 
+       rtnl_lock();
+
        /* Create per netdev entries */
        priv->dbgfs_dir = debugfs_create_dir(dev->name, stmmac_fs_dir);
 
@@ -4416,14 +4418,13 @@ static void stmmac_init_fs(struct net_device *dev)
        debugfs_create_file("dma_cap", 0444, priv->dbgfs_dir, dev,
                            &stmmac_dma_cap_fops);
 
-       register_netdevice_notifier(&stmmac_notifier);
+       rtnl_unlock();
 }
 
 static void stmmac_exit_fs(struct net_device *dev)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
 
-       unregister_netdevice_notifier(&stmmac_notifier);
        debugfs_remove_recursive(priv->dbgfs_dir);
 }
 #endif /* CONFIG_DEBUG_FS */
@@ -4940,14 +4941,14 @@ int stmmac_dvr_remove(struct device *dev)
 
        netdev_info(priv->dev, "%s: removing driver", __func__);
 
-#ifdef CONFIG_DEBUG_FS
-       stmmac_exit_fs(ndev);
-#endif
        stmmac_stop_all_dma(priv);
 
        stmmac_mac_set(priv, priv->ioaddr, false);
        netif_carrier_off(ndev);
        unregister_netdev(ndev);
+#ifdef CONFIG_DEBUG_FS
+       stmmac_exit_fs(ndev);
+#endif
        phylink_destroy(priv->phylink);
        if (priv->plat->stmmac_rst)
                reset_control_assert(priv->plat->stmmac_rst);
@@ -5166,6 +5167,7 @@ static int __init stmmac_init(void)
        /* Create debugfs main directory if it doesn't exist yet */
        if (!stmmac_fs_dir)
                stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL);
+       register_netdevice_notifier(&stmmac_notifier);
 #endif
 
        return 0;
@@ -5174,6 +5176,7 @@ static int __init stmmac_init(void)
 static void __exit stmmac_exit(void)
 {
 #ifdef CONFIG_DEBUG_FS
+       unregister_netdevice_notifier(&stmmac_notifier);
        debugfs_remove_recursive(stmmac_fs_dir);
 #endif
 }
index 276292b..53fb814 100644 (file)
@@ -375,10 +375,14 @@ struct temac_local {
        int tx_bd_next;
        int tx_bd_tail;
        int rx_bd_ci;
+       int rx_bd_tail;
 
        /* DMA channel control setup */
        u32 tx_chnl_ctrl;
        u32 rx_chnl_ctrl;
+       u8 coalesce_count_rx;
+
+       struct delayed_work restart_work;
 };
 
 /* Wrappers for temac_ior()/temac_iow() function pointers above */
index 6f11f52..9461ace 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/ip.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/workqueue.h>
 #include <linux/dma-mapping.h>
 #include <linux/processor.h>
 #include <linux/platform_data/xilinx-ll-temac.h>
@@ -367,6 +368,8 @@ static int temac_dma_bd_init(struct net_device *ndev)
                skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
                                              XTE_MAX_JUMBO_FRAME_SIZE,
                                              DMA_FROM_DEVICE);
+               if (dma_mapping_error(ndev->dev.parent, skb_dma_addr))
+                       goto out;
                lp->rx_bd_v[i].phys = cpu_to_be32(skb_dma_addr);
                lp->rx_bd_v[i].len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
                lp->rx_bd_v[i].app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
@@ -387,12 +390,13 @@ static int temac_dma_bd_init(struct net_device *ndev)
        lp->tx_bd_next = 0;
        lp->tx_bd_tail = 0;
        lp->rx_bd_ci = 0;
+       lp->rx_bd_tail = RX_BD_NUM - 1;
 
        /* Enable RX DMA transfers */
        wmb();
        lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
        lp->dma_out(lp, RX_TAILDESC_PTR,
-                      lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
+                      lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * lp->rx_bd_tail));
 
        /* Prepare for TX DMA transfer */
        lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
@@ -788,6 +792,9 @@ static void temac_start_xmit_done(struct net_device *ndev)
                stat = be32_to_cpu(cur_p->app0);
        }
 
+       /* Matches barrier in temac_start_xmit */
+       smp_mb();
+
        netif_wake_queue(ndev);
 }
 
@@ -830,9 +837,19 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
 
        if (temac_check_tx_bd_space(lp, num_frag + 1)) {
-               if (!netif_queue_stopped(ndev))
-                       netif_stop_queue(ndev);
-               return NETDEV_TX_BUSY;
+               if (netif_queue_stopped(ndev))
+                       return NETDEV_TX_BUSY;
+
+               netif_stop_queue(ndev);
+
+               /* Matches barrier in temac_start_xmit_done */
+               smp_mb();
+
+               /* Space might have just been freed - check again */
+               if (temac_check_tx_bd_space(lp, num_frag))
+                       return NETDEV_TX_BUSY;
+
+               netif_wake_queue(ndev);
        }
 
        cur_p->app0 = 0;
@@ -850,12 +867,16 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
                                      skb_headlen(skb), DMA_TO_DEVICE);
        cur_p->len = cpu_to_be32(skb_headlen(skb));
+       if (WARN_ON_ONCE(dma_mapping_error(ndev->dev.parent, skb_dma_addr))) {
+               dev_kfree_skb_any(skb);
+               ndev->stats.tx_dropped++;
+               return NETDEV_TX_OK;
+       }
        cur_p->phys = cpu_to_be32(skb_dma_addr);
        ptr_to_txbd((void *)skb, cur_p);
 
        for (ii = 0; ii < num_frag; ii++) {
-               lp->tx_bd_tail++;
-               if (lp->tx_bd_tail >= TX_BD_NUM)
+               if (++lp->tx_bd_tail >= TX_BD_NUM)
                        lp->tx_bd_tail = 0;
 
                cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
@@ -863,6 +884,27 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                              skb_frag_address(frag),
                                              skb_frag_size(frag),
                                              DMA_TO_DEVICE);
+               if (dma_mapping_error(ndev->dev.parent, skb_dma_addr)) {
+                       if (--lp->tx_bd_tail < 0)
+                               lp->tx_bd_tail = TX_BD_NUM - 1;
+                       cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
+                       while (--ii >= 0) {
+                               --frag;
+                               dma_unmap_single(ndev->dev.parent,
+                                                be32_to_cpu(cur_p->phys),
+                                                skb_frag_size(frag),
+                                                DMA_TO_DEVICE);
+                               if (--lp->tx_bd_tail < 0)
+                                       lp->tx_bd_tail = TX_BD_NUM - 1;
+                               cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
+                       }
+                       dma_unmap_single(ndev->dev.parent,
+                                        be32_to_cpu(cur_p->phys),
+                                        skb_headlen(skb), DMA_TO_DEVICE);
+                       dev_kfree_skb_any(skb);
+                       ndev->stats.tx_dropped++;
+                       return NETDEV_TX_OK;
+               }
                cur_p->phys = cpu_to_be32(skb_dma_addr);
                cur_p->len = cpu_to_be32(skb_frag_size(frag));
                cur_p->app0 = 0;
@@ -884,31 +926,56 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        return NETDEV_TX_OK;
 }
 
+static int ll_temac_recv_buffers_available(struct temac_local *lp)
+{
+       int available;
+
+       if (!lp->rx_skb[lp->rx_bd_ci])
+               return 0;
+       available = 1 + lp->rx_bd_tail - lp->rx_bd_ci;
+       if (available <= 0)
+               available += RX_BD_NUM;
+       return available;
+}
 
 static void ll_temac_recv(struct net_device *ndev)
 {
        struct temac_local *lp = netdev_priv(ndev);
-       struct sk_buff *skb, *new_skb;
-       unsigned int bdstat;
-       struct cdmac_bd *cur_p;
-       dma_addr_t tail_p, skb_dma_addr;
-       int length;
        unsigned long flags;
+       int rx_bd;
+       bool update_tail = false;
 
        spin_lock_irqsave(&lp->rx_lock, flags);
 
-       tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
-       cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
-
-       bdstat = be32_to_cpu(cur_p->app0);
-       while ((bdstat & STS_CTRL_APP0_CMPLT)) {
+       /* Process all received buffers, passing them on network
+        * stack.  After this, the buffer descriptors will be in an
+        * un-allocated stage, where no skb is allocated for it, and
+        * they are therefore not available for TEMAC/DMA.
+        */
+       do {
+               struct cdmac_bd *bd = &lp->rx_bd_v[lp->rx_bd_ci];
+               struct sk_buff *skb = lp->rx_skb[lp->rx_bd_ci];
+               unsigned int bdstat = be32_to_cpu(bd->app0);
+               int length;
+
+               /* While this should not normally happen, we can end
+                * here when GFP_ATOMIC allocations fail, and we
+                * therefore have un-allocated buffers.
+                */
+               if (!skb)
+                       break;
 
-               skb = lp->rx_skb[lp->rx_bd_ci];
-               length = be32_to_cpu(cur_p->app4) & 0x3FFF;
+               /* Loop over all completed buffer descriptors */
+               if (!(bdstat & STS_CTRL_APP0_CMPLT))
+                       break;
 
-               dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
+               dma_unmap_single(ndev->dev.parent, be32_to_cpu(bd->phys),
                                 XTE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE);
+               /* The buffer is not valid for DMA anymore */
+               bd->phys = 0;
+               bd->len = 0;
 
+               length = be32_to_cpu(bd->app4) & 0x3FFF;
                skb_put(skb, length);
                skb->protocol = eth_type_trans(skb, ndev);
                skb_checksum_none_assert(skb);
@@ -923,43 +990,102 @@ static void ll_temac_recv(struct net_device *ndev)
                         * (back) for proper IP checksum byte order
                         * (be16).
                         */
-                       skb->csum = htons(be32_to_cpu(cur_p->app3) & 0xFFFF);
+                       skb->csum = htons(be32_to_cpu(bd->app3) & 0xFFFF);
                        skb->ip_summed = CHECKSUM_COMPLETE;
                }
 
                if (!skb_defer_rx_timestamp(skb))
                        netif_rx(skb);
+               /* The skb buffer is now owned by network stack above */
+               lp->rx_skb[lp->rx_bd_ci] = NULL;
 
                ndev->stats.rx_packets++;
                ndev->stats.rx_bytes += length;
 
-               new_skb = netdev_alloc_skb_ip_align(ndev,
-                                               XTE_MAX_JUMBO_FRAME_SIZE);
-               if (!new_skb) {
-                       spin_unlock_irqrestore(&lp->rx_lock, flags);
-                       return;
+               rx_bd = lp->rx_bd_ci;
+               if (++lp->rx_bd_ci >= RX_BD_NUM)
+                       lp->rx_bd_ci = 0;
+       } while (rx_bd != lp->rx_bd_tail);
+
+       /* DMA operations will halt when the last buffer descriptor is
+        * processed (ie. the one pointed to by RX_TAILDESC_PTR).
+        * When that happens, no more interrupt events will be
+        * generated.  No IRQ_COAL or IRQ_DLY, and not even an
+        * IRQ_ERR.  To avoid stalling, we schedule a delayed work
+        * when there is a potential risk of that happening.  The work
+        * will call this function, and thus re-schedule itself until
+        * enough buffers are available again.
+        */
+       if (ll_temac_recv_buffers_available(lp) < lp->coalesce_count_rx)
+               schedule_delayed_work(&lp->restart_work, HZ / 1000);
+
+       /* Allocate new buffers for those buffer descriptors that were
+        * passed to network stack.  Note that GFP_ATOMIC allocations
+        * can fail (e.g. when a larger burst of GFP_ATOMIC
+        * allocations occurs), so while we try to allocate all
+        * buffers in the same interrupt where they were processed, we
+        * continue with what we could get in case of allocation
+        * failure.  Allocation of remaining buffers will be retried
+        * in following calls.
+        */
+       while (1) {
+               struct sk_buff *skb;
+               struct cdmac_bd *bd;
+               dma_addr_t skb_dma_addr;
+
+               rx_bd = lp->rx_bd_tail + 1;
+               if (rx_bd >= RX_BD_NUM)
+                       rx_bd = 0;
+               bd = &lp->rx_bd_v[rx_bd];
+
+               if (bd->phys)
+                       break;  /* All skb's allocated */
+
+               skb = netdev_alloc_skb_ip_align(ndev, XTE_MAX_JUMBO_FRAME_SIZE);
+               if (!skb) {
+                       dev_warn(&ndev->dev, "skb alloc failed\n");
+                       break;
                }
 
-               cur_p->app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
-               skb_dma_addr = dma_map_single(ndev->dev.parent, new_skb->data,
+               skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
                                              XTE_MAX_JUMBO_FRAME_SIZE,
                                              DMA_FROM_DEVICE);
-               cur_p->phys = cpu_to_be32(skb_dma_addr);
-               cur_p->len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
-               lp->rx_skb[lp->rx_bd_ci] = new_skb;
+               if (WARN_ON_ONCE(dma_mapping_error(ndev->dev.parent,
+                                                  skb_dma_addr))) {
+                       dev_kfree_skb_any(skb);
+                       break;
+               }
 
-               lp->rx_bd_ci++;
-               if (lp->rx_bd_ci >= RX_BD_NUM)
-                       lp->rx_bd_ci = 0;
+               bd->phys = cpu_to_be32(skb_dma_addr);
+               bd->len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
+               bd->app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
+               lp->rx_skb[rx_bd] = skb;
 
-               cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
-               bdstat = be32_to_cpu(cur_p->app0);
+               lp->rx_bd_tail = rx_bd;
+               update_tail = true;
+       }
+
+       /* Move tail pointer when buffers have been allocated */
+       if (update_tail) {
+               lp->dma_out(lp, RX_TAILDESC_PTR,
+                       lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_tail);
        }
-       lp->dma_out(lp, RX_TAILDESC_PTR, tail_p);
 
        spin_unlock_irqrestore(&lp->rx_lock, flags);
 }
 
+/* Function scheduled to ensure a restart in case of DMA halt
+ * condition caused by running out of buffer descriptors.
+ */
+static void ll_temac_restart_work_func(struct work_struct *work)
+{
+       struct temac_local *lp = container_of(work, struct temac_local,
+                                             restart_work.work);
+       struct net_device *ndev = lp->ndev;
+
+       ll_temac_recv(ndev);
+}
+
 static irqreturn_t ll_temac_tx_irq(int irq, void *_ndev)
 {
        struct net_device *ndev = _ndev;
@@ -1052,6 +1178,8 @@ static int temac_stop(struct net_device *ndev)
 
        dev_dbg(&ndev->dev, "temac_close()\n");
 
+       cancel_delayed_work_sync(&lp->restart_work);
+
        free_irq(lp->tx_irq, ndev);
        free_irq(lp->rx_irq, ndev);
 
@@ -1173,6 +1301,7 @@ static int temac_probe(struct platform_device *pdev)
        lp->dev = &pdev->dev;
        lp->options = XTE_OPTION_DEFAULTS;
        spin_lock_init(&lp->rx_lock);
+       INIT_DELAYED_WORK(&lp->restart_work, ll_temac_restart_work_func);
 
        /* Setup mutex for synchronization of indirect register access */
        if (pdata) {
@@ -1279,6 +1408,7 @@ static int temac_probe(struct platform_device *pdev)
                 */
                lp->tx_chnl_ctrl = 0x10220000;
                lp->rx_chnl_ctrl = 0xff070000;
+               lp->coalesce_count_rx = 0x07;
 
                /* Finished with the DMA node; drop the reference */
                of_node_put(dma_np);
@@ -1310,11 +1440,14 @@ static int temac_probe(struct platform_device *pdev)
                                (pdata->tx_irq_count << 16);
                else
                        lp->tx_chnl_ctrl = 0x10220000;
-               if (pdata->rx_irq_timeout || pdata->rx_irq_count)
+               if (pdata->rx_irq_timeout || pdata->rx_irq_count) {
                        lp->rx_chnl_ctrl = (pdata->rx_irq_timeout << 24) |
                                (pdata->rx_irq_count << 16);
-               else
+                       lp->coalesce_count_rx = pdata->rx_irq_count;
+               } else {
                        lp->rx_chnl_ctrl = 0xff070000;
+                       lp->coalesce_count_rx = 0x07;
+               }
        }
 
        /* Error handle returned DMA RX and TX interrupts */
index ae3f308..1b320bc 100644 (file)
@@ -99,7 +99,7 @@ static struct netvsc_device *alloc_net_device(void)
 
        init_waitqueue_head(&net_device->wait_drain);
        net_device->destroy = false;
-       net_device->tx_disable = false;
+       net_device->tx_disable = true;
 
        net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT;
        net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT;
index 65e12cb..2c0a24c 100644 (file)
@@ -1068,6 +1068,7 @@ static int netvsc_attach(struct net_device *ndev,
        }
 
        /* In any case device is now ready */
+       nvdev->tx_disable = false;
        netif_device_attach(ndev);
 
        /* Note: enable and attach happen when sub-channels setup */
@@ -2476,6 +2477,8 @@ static int netvsc_probe(struct hv_device *dev,
        else
                net->max_mtu = ETH_DATA_LEN;
 
+       nvdev->tx_disable = false;
+
        ret = register_netdevice(net);
        if (ret != 0) {
                pr_err("Unable to register netdev.\n");
index 28e33ec..9a8bada 100644 (file)
@@ -1306,6 +1306,9 @@ static int marvell_read_status_page_an(struct phy_device *phydev,
                }
        }
 
+       if (!(status & MII_M1011_PHY_STATUS_RESOLVED))
+               return 0;
+
        if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
                phydev->duplex = DUPLEX_FULL;
        else
@@ -1365,6 +1368,8 @@ static int marvell_read_status_page(struct phy_device *phydev, int page)
        linkmode_zero(phydev->lp_advertising);
        phydev->pause = 0;
        phydev->asym_pause = 0;
+       phydev->speed = SPEED_UNKNOWN;
+       phydev->duplex = DUPLEX_UNKNOWN;
 
        if (phydev->autoneg == AUTONEG_ENABLE)
                err = marvell_read_status_page_an(phydev, fiber, status);
index 937ac7d..f686f40 100644 (file)
@@ -345,11 +345,11 @@ enum macsec_bank {
                                BIT(VSC8531_FORCE_LED_OFF) | \
                                BIT(VSC8531_FORCE_LED_ON))
 
-#define MSCC_VSC8584_REVB_INT8051_FW           "mscc_vsc8584_revb_int8051_fb48.bin"
+#define MSCC_VSC8584_REVB_INT8051_FW           "microchip/mscc_vsc8584_revb_int8051_fb48.bin"
 #define MSCC_VSC8584_REVB_INT8051_FW_START_ADDR        0xe800
 #define MSCC_VSC8584_REVB_INT8051_FW_CRC       0xfb48
 
-#define MSCC_VSC8574_REVB_INT8051_FW           "mscc_vsc8574_revb_int8051_29e8.bin"
+#define MSCC_VSC8574_REVB_INT8051_FW           "microchip/mscc_vsc8574_revb_int8051_29e8.bin"
 #define MSCC_VSC8574_REVB_INT8051_FW_START_ADDR        0x4000
 #define MSCC_VSC8574_REVB_INT8051_FW_CRC       0x29e8
 
index a1caeee..dd2e23f 100644 (file)
@@ -167,7 +167,7 @@ EXPORT_SYMBOL_GPL(genphy_c45_restart_aneg);
  */
 int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart)
 {
-       int ret = 0;
+       int ret;
 
        if (!restart) {
                /* Configure and restart aneg if it wasn't set before */
@@ -180,9 +180,9 @@ int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart)
        }
 
        if (restart)
-               ret = genphy_c45_restart_aneg(phydev);
+               return genphy_c45_restart_aneg(phydev);
 
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(genphy_c45_check_and_restart_aneg);
 
index 6a5056e..c8b0c34 100644 (file)
@@ -247,7 +247,7 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
         * MDIO bus driver and clock gated at this point.
         */
        if (!netdev)
-               return !phydev->suspended;
+               goto out;
 
        if (netdev->wol_enabled)
                return false;
@@ -267,7 +267,8 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
        if (device_may_wakeup(&netdev->dev))
                return false;
 
-       return true;
+out:
+       return !phydev->suspended;
 }
 
 static int mdio_bus_phy_suspend(struct device *dev)
@@ -1792,7 +1793,7 @@ EXPORT_SYMBOL(genphy_restart_aneg);
  */
 int genphy_check_and_restart_aneg(struct phy_device *phydev, bool restart)
 {
-       int ret = 0;
+       int ret;
 
        if (!restart) {
                /* Advertisement hasn't changed, but maybe aneg was never on to
@@ -1807,9 +1808,9 @@ int genphy_check_and_restart_aneg(struct phy_device *phydev, bool restart)
        }
 
        if (restart)
-               ret = genphy_restart_aneg(phydev);
+               return genphy_restart_aneg(phydev);
 
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(genphy_check_and_restart_aneg);
 
index 6f4d7ba..babb018 100644 (file)
@@ -863,7 +863,10 @@ err_free_chan:
        tty->disc_data = NULL;
        clear_bit(SLF_INUSE, &sl->flags);
        sl_free_netdev(sl->dev);
+       /* do not call free_netdev before rtnl_unlock */
+       rtnl_unlock();
        free_netdev(sl->dev);
+       return err;
 
 err_exit:
        rtnl_unlock();
index 3b7a3b8..5754bb6 100644 (file)
@@ -337,6 +337,9 @@ static void qmi_wwan_netdev_setup(struct net_device *net)
                netdev_dbg(net, "mode: raw IP\n");
        } else if (!net->header_ops) { /* don't bother if already set */
                ether_setup(net);
+               /* Restoring min/max mtu values set originally by usbnet */
+               net->min_mtu = 0;
+               net->max_mtu = ETH_MAX_MTU;
                clear_bit(EVENT_NO_IP_ALIGN, &dev->flags);
                netdev_dbg(net, "mode: Ethernet\n");
        }
index d20aabc..3a10e67 100644 (file)
@@ -670,7 +670,7 @@ static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie,
         *   outbound memory @ 3GB). So instead it will  start at the 1x
         *   multiple of its size
         */
-       if (!*rc_bar2_size || *rc_bar2_offset % *rc_bar2_size ||
+       if (!*rc_bar2_size || (*rc_bar2_offset & (*rc_bar2_size - 1)) ||
            (*rc_bar2_offset < SZ_4G && *rc_bar2_offset > SZ_2G)) {
                dev_err(dev, "Invalid rc_bar2_offset/size: size 0x%llx, off 0x%llx\n",
                        *rc_bar2_size, *rc_bar2_offset);
index acce878..f5c7a84 100644 (file)
@@ -24,8 +24,6 @@ static int arm_pmu_acpi_register_irq(int cpu)
        int gsi, trigger;
 
        gicc = acpi_cpu_get_madt_gicc(cpu);
-       if (WARN_ON(!gicc))
-               return -EINVAL;
 
        gsi = gicc->performance_interrupt;
 
@@ -64,11 +62,10 @@ static void arm_pmu_acpi_unregister_irq(int cpu)
        int gsi;
 
        gicc = acpi_cpu_get_madt_gicc(cpu);
-       if (!gicc)
-               return;
 
        gsi = gicc->performance_interrupt;
-       acpi_unregister_gsi(gsi);
+       if (gsi)
+               acpi_unregister_gsi(gsi);
 }
 
 #if IS_ENABLED(CONFIG_ARM_SPE_PMU)
index 95dca2c..90884d1 100644 (file)
@@ -388,9 +388,10 @@ static void ddr_perf_counter_enable(struct ddr_pmu *pmu, int config,
 
        if (enable) {
                /*
-                * must disable first, then enable again
-                * otherwise, cycle counter will not work
-                * if previous state is enabled.
+                * cycle counter is special which should firstly write 0 then
+                * write 1 into CLEAR bit to clear it. Other counters only
+                * need write 0 into CLEAR bit and it turns out to be 1 by
+                * hardware. Below enable flow is harmless for all counters.
                 */
                writel(0, pmu->base + reg);
                val = CNTL_EN | CNTL_CLEAR;
@@ -398,7 +399,8 @@ static void ddr_perf_counter_enable(struct ddr_pmu *pmu, int config,
                writel(val, pmu->base + reg);
        } else {
                /* Disable counter */
-               writel(0, pmu->base + reg);
+               val = readl_relaxed(pmu->base + reg) & CNTL_EN_MASK;
+               writel(val, pmu->base + reg);
        }
 }
 
index e69682c..62f2761 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <linux/platform_data/wilco-ec.h>
 #include <linux/string.h>
-#include <linux/unaligned/le_memmove.h>
+#include <asm/unaligned.h>
 
 /* Operation code; what the EC should do with the property */
 enum ec_property_op {
index bdfaf7e..992bc18 100644 (file)
@@ -88,7 +88,7 @@ static int stm32_vrefbuf_disable(struct regulator_dev *rdev)
        }
 
        val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
-       val = (val & ~STM32_ENVR) | STM32_HIZ;
+       val &= ~STM32_ENVR;
        writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
 
        pm_runtime_mark_last_busy(priv->dev);
@@ -175,6 +175,7 @@ static const struct regulator_desc stm32_vrefbuf_regu = {
        .volt_table = stm32_vrefbuf_voltages,
        .n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages),
        .ops = &stm32_vrefbuf_volt_ops,
+       .off_on_delay = 1000,
        .type = REGULATOR_VOLTAGE,
        .owner = THIS_MODULE,
 };
index 2b1e4da..4bfb79f 100644 (file)
@@ -410,7 +410,7 @@ struct fsf_qtcb_bottom_port {
        u8 cb_util;
        u8 a_util;
        u8 res2;
-       u16 temperature;
+       s16 temperature;
        u16 vcc;
        u16 tx_bias;
        u16 tx_power;
index 494b9fe..a711a0d 100644 (file)
@@ -800,7 +800,7 @@ static ZFCP_DEV_ATTR(adapter_diag, b2b_credit, 0400,
        static ZFCP_DEV_ATTR(adapter_diag_sfp, _name, 0400,                    \
                             zfcp_sysfs_adapter_diag_sfp_##_name##_show, NULL)
 
-ZFCP_DEFINE_DIAG_SFP_ATTR(temperature, temperature, 5, "%hu");
+ZFCP_DEFINE_DIAG_SFP_ATTR(temperature, temperature, 6, "%hd");
 ZFCP_DEFINE_DIAG_SFP_ATTR(vcc, vcc, 5, "%hu");
 ZFCP_DEFINE_DIAG_SFP_ATTR(tx_bias, tx_bias, 5, "%hu");
 ZFCP_DEFINE_DIAG_SFP_ATTR(tx_power, tx_power, 5, "%hu");
index 9c5f7c9..2b865c6 100644 (file)
@@ -628,6 +628,8 @@ redisc:
        }
 out:
        kref_put(&rdata->kref, fc_rport_destroy);
+       if (!IS_ERR(fp))
+               fc_frame_free(fp);
 }
 
 /**
index e4282bc..f45c22b 100644 (file)
@@ -161,6 +161,7 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
                        unsigned int nr_zones, report_zones_cb cb, void *data)
 {
        struct scsi_disk *sdkp = scsi_disk(disk);
+       sector_t capacity = logical_to_sectors(sdkp->device, sdkp->capacity);
        unsigned int nr, i;
        unsigned char *buf;
        size_t offset, buflen = 0;
@@ -171,11 +172,15 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
                /* Not a zoned device */
                return -EOPNOTSUPP;
 
+       if (!capacity)
+               /* Device gone or invalid */
+               return -ENODEV;
+
        buf = sd_zbc_alloc_report_buffer(sdkp, nr_zones, &buflen);
        if (!buf)
                return -ENOMEM;
 
-       while (zone_idx < nr_zones && sector < get_capacity(disk)) {
+       while (zone_idx < nr_zones && sector < capacity) {
                ret = sd_zbc_do_report_zones(sdkp, buf, buflen,
                                sectors_to_logical(sdkp->device, sector), true);
                if (ret)
index 0fbb8fe..e4240e4 100644 (file)
@@ -688,7 +688,7 @@ static const struct block_device_operations sr_bdops =
        .release        = sr_block_release,
        .ioctl          = sr_block_ioctl,
 #ifdef CONFIG_COMPAT
-       .ioctl          = sr_block_compat_ioctl,
+       .compat_ioctl   = sr_block_compat_ioctl,
 #endif
        .check_events   = sr_block_check_events,
        .revalidate_disk = sr_block_revalidate_disk,
index fd8007e..13def7f 100644 (file)
@@ -149,6 +149,7 @@ struct atmel_qspi {
        struct clk              *qspick;
        struct platform_device  *pdev;
        const struct atmel_qspi_caps *caps;
+       resource_size_t         mmap_size;
        u32                     pending;
        u32                     mr;
        u32                     scr;
@@ -329,6 +330,14 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
        u32 sr, offset;
        int err;
 
+       /*
+        * Check if the address exceeds the MMIO window size. An improvement
+        * would be to add support for regular SPI mode and fall back to it
+        * when the flash memories overrun the controller's memory space.
+        */
+       if (op->addr.val + op->data.nbytes > aq->mmap_size)
+               return -ENOTSUPP;
+
        err = atmel_qspi_set_cfg(aq, op, &offset);
        if (err)
                return err;
@@ -480,6 +489,8 @@ static int atmel_qspi_probe(struct platform_device *pdev)
                goto exit;
        }
 
+       aq->mmap_size = resource_size(res);
+
        /* Get the peripheral clock */
        aq->pclk = devm_clk_get(&pdev->dev, "pclk");
        if (IS_ERR(aq->pclk))
index 7327309..6c23530 100644 (file)
@@ -366,7 +366,6 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
                        goto out_disable_clk;
 
                rate = clk_get_rate(pll_clk);
-               clk_disable_unprepare(pll_clk);
                if (!rate) {
                        ret = -EINVAL;
                        goto out_disable_pll_clk;
index 7e2292c..e9e2567 100644 (file)
@@ -130,6 +130,7 @@ struct omap2_mcspi {
        int                     fifo_depth;
        bool                    slave_aborted;
        unsigned int            pin_dir:1;
+       size_t                  max_xfer_len;
 };
 
 struct omap2_mcspi_cs {
@@ -974,20 +975,12 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
  * Note that we currently allow DMA only if we get a channel
  * for both rx and tx. Otherwise we'll do PIO for both rx and tx.
  */
-static int omap2_mcspi_request_dma(struct spi_device *spi)
+static int omap2_mcspi_request_dma(struct omap2_mcspi *mcspi,
+                                  struct omap2_mcspi_dma *mcspi_dma)
 {
-       struct spi_master       *master = spi->master;
-       struct omap2_mcspi      *mcspi;
-       struct omap2_mcspi_dma  *mcspi_dma;
        int ret = 0;
 
-       mcspi = spi_master_get_devdata(master);
-       mcspi_dma = mcspi->dma_channels + spi->chip_select;
-
-       init_completion(&mcspi_dma->dma_rx_completion);
-       init_completion(&mcspi_dma->dma_tx_completion);
-
-       mcspi_dma->dma_rx = dma_request_chan(&master->dev,
+       mcspi_dma->dma_rx = dma_request_chan(mcspi->dev,
                                             mcspi_dma->dma_rx_ch_name);
        if (IS_ERR(mcspi_dma->dma_rx)) {
                ret = PTR_ERR(mcspi_dma->dma_rx);
@@ -995,7 +988,7 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
                goto no_dma;
        }
 
-       mcspi_dma->dma_tx = dma_request_chan(&master->dev,
+       mcspi_dma->dma_tx = dma_request_chan(mcspi->dev,
                                             mcspi_dma->dma_tx_ch_name);
        if (IS_ERR(mcspi_dma->dma_tx)) {
                ret = PTR_ERR(mcspi_dma->dma_tx);
@@ -1004,20 +997,40 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
                mcspi_dma->dma_rx = NULL;
        }
 
+       init_completion(&mcspi_dma->dma_rx_completion);
+       init_completion(&mcspi_dma->dma_tx_completion);
+
 no_dma:
        return ret;
 }
 
+static void omap2_mcspi_release_dma(struct spi_master *master)
+{
+       struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+       struct omap2_mcspi_dma  *mcspi_dma;
+       int i;
+
+       for (i = 0; i < master->num_chipselect; i++) {
+               mcspi_dma = &mcspi->dma_channels[i];
+
+               if (mcspi_dma->dma_rx) {
+                       dma_release_channel(mcspi_dma->dma_rx);
+                       mcspi_dma->dma_rx = NULL;
+               }
+               if (mcspi_dma->dma_tx) {
+                       dma_release_channel(mcspi_dma->dma_tx);
+                       mcspi_dma->dma_tx = NULL;
+               }
+       }
+}
+
 static int omap2_mcspi_setup(struct spi_device *spi)
 {
        int                     ret;
        struct omap2_mcspi      *mcspi = spi_master_get_devdata(spi->master);
        struct omap2_mcspi_regs *ctx = &mcspi->ctx;
-       struct omap2_mcspi_dma  *mcspi_dma;
        struct omap2_mcspi_cs   *cs = spi->controller_state;
 
-       mcspi_dma = &mcspi->dma_channels[spi->chip_select];
-
        if (!cs) {
                cs = kzalloc(sizeof *cs, GFP_KERNEL);
                if (!cs)
@@ -1042,13 +1055,6 @@ static int omap2_mcspi_setup(struct spi_device *spi)
                }
        }
 
-       if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) {
-               ret = omap2_mcspi_request_dma(spi);
-               if (ret)
-                       dev_warn(&spi->dev, "not using DMA for McSPI (%d)\n",
-                                ret);
-       }
-
        ret = pm_runtime_get_sync(mcspi->dev);
        if (ret < 0) {
                pm_runtime_put_noidle(mcspi->dev);
@@ -1065,12 +1071,8 @@ static int omap2_mcspi_setup(struct spi_device *spi)
 
 static void omap2_mcspi_cleanup(struct spi_device *spi)
 {
-       struct omap2_mcspi      *mcspi;
-       struct omap2_mcspi_dma  *mcspi_dma;
        struct omap2_mcspi_cs   *cs;
 
-       mcspi = spi_master_get_devdata(spi->master);
-
        if (spi->controller_state) {
                /* Unlink controller state from context save list */
                cs = spi->controller_state;
@@ -1079,19 +1081,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
                kfree(cs);
        }
 
-       if (spi->chip_select < spi->master->num_chipselect) {
-               mcspi_dma = &mcspi->dma_channels[spi->chip_select];
-
-               if (mcspi_dma->dma_rx) {
-                       dma_release_channel(mcspi_dma->dma_rx);
-                       mcspi_dma->dma_rx = NULL;
-               }
-               if (mcspi_dma->dma_tx) {
-                       dma_release_channel(mcspi_dma->dma_tx);
-                       mcspi_dma->dma_tx = NULL;
-               }
-       }
-
        if (gpio_is_valid(spi->cs_gpio))
                gpio_free(spi->cs_gpio);
 }
@@ -1302,9 +1291,24 @@ static bool omap2_mcspi_can_dma(struct spi_master *master,
        if (spi_controller_is_slave(master))
                return true;
 
+       master->dma_rx = mcspi_dma->dma_rx;
+       master->dma_tx = mcspi_dma->dma_tx;
+
        return (xfer->len >= DMA_MIN_BYTES);
 }
 
+static size_t omap2_mcspi_max_xfer_size(struct spi_device *spi)
+{
+       struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
+       struct omap2_mcspi_dma *mcspi_dma =
+               &mcspi->dma_channels[spi->chip_select];
+
+       if (mcspi->max_xfer_len && mcspi_dma->dma_rx)
+               return mcspi->max_xfer_len;
+
+       return SIZE_MAX;
+}
+
 static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi)
 {
        struct spi_master       *master = mcspi->master;
@@ -1373,6 +1377,11 @@ static struct omap2_mcspi_platform_config omap4_pdata = {
        .regs_offset = OMAP4_MCSPI_REG_OFFSET,
 };
 
+static struct omap2_mcspi_platform_config am654_pdata = {
+       .regs_offset = OMAP4_MCSPI_REG_OFFSET,
+       .max_xfer_len = SZ_4K - 1,
+};
+
 static const struct of_device_id omap_mcspi_of_match[] = {
        {
                .compatible = "ti,omap2-mcspi",
@@ -1382,6 +1391,10 @@ static const struct of_device_id omap_mcspi_of_match[] = {
                .compatible = "ti,omap4-mcspi",
                .data = &omap4_pdata,
        },
+       {
+               .compatible = "ti,am654-mcspi",
+               .data = &am654_pdata,
+       },
        { },
 };
 MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
@@ -1439,6 +1452,10 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
                mcspi->pin_dir = pdata->pin_dir;
        }
        regs_offset = pdata->regs_offset;
+       if (pdata->max_xfer_len) {
+               mcspi->max_xfer_len = pdata->max_xfer_len;
+               master->max_transfer_size = omap2_mcspi_max_xfer_size;
+       }
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        mcspi->base = devm_ioremap_resource(&pdev->dev, r);
@@ -1464,6 +1481,11 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
        for (i = 0; i < master->num_chipselect; i++) {
                sprintf(mcspi->dma_channels[i].dma_rx_ch_name, "rx%d", i);
                sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i);
+
+               status = omap2_mcspi_request_dma(mcspi,
+                                                &mcspi->dma_channels[i]);
+               if (status == -EPROBE_DEFER)
+                       goto free_master;
        }
 
        status = platform_get_irq(pdev, 0);
@@ -1501,6 +1523,7 @@ disable_pm:
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 free_master:
+       omap2_mcspi_release_dma(master);
        spi_master_put(master);
        return status;
 }
@@ -1510,6 +1533,8 @@ static int omap2_mcspi_remove(struct platform_device *pdev)
        struct spi_master *master = platform_get_drvdata(pdev);
        struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
 
+       omap2_mcspi_release_dma(master);
+
        pm_runtime_dont_use_autosuspend(mcspi->dev);
        pm_runtime_put_sync(mcspi->dev);
        pm_runtime_disable(&pdev->dev);
index 4c7a71f..2e31815 100644 (file)
@@ -70,6 +70,10 @@ MODULE_ALIAS("platform:pxa2xx-spi");
 #define LPSS_CAPS_CS_EN_SHIFT                  9
 #define LPSS_CAPS_CS_EN_MASK                   (0xf << LPSS_CAPS_CS_EN_SHIFT)
 
+#define LPSS_PRIV_CLOCK_GATE 0x38
+#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK 0x3
+#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON 0x3
+
 struct lpss_config {
        /* LPSS offset from drv_data->ioaddr */
        unsigned offset;
@@ -86,6 +90,8 @@ struct lpss_config {
        unsigned cs_sel_shift;
        unsigned cs_sel_mask;
        unsigned cs_num;
+       /* Quirks */
+       unsigned cs_clk_stays_gated : 1;
 };
 
 /* Keep these sorted with enum pxa_ssp_type */
@@ -156,6 +162,7 @@ static const struct lpss_config lpss_platforms[] = {
                .tx_threshold_hi = 56,
                .cs_sel_shift = 8,
                .cs_sel_mask = 3 << 8,
+               .cs_clk_stays_gated = true,
        },
 };
 
@@ -383,6 +390,22 @@ static void lpss_ssp_cs_control(struct spi_device *spi, bool enable)
        else
                value |= LPSS_CS_CONTROL_CS_HIGH;
        __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
+       if (config->cs_clk_stays_gated) {
+               u32 clkgate;
+
+               /*
+                * Changing CS alone when dynamic clock gating is on won't
+                * actually flip CS at that time. This ruins SPI transfers
+                * that specify delays, or have no data. Toggle the clock mode
+                * to force on briefly to poke the CS pin to move.
+                */
+               clkgate = __lpss_ssp_read_priv(drv_data, LPSS_PRIV_CLOCK_GATE);
+               value = (clkgate & ~LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK) |
+                       LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON;
+
+               __lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, value);
+               __lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, clkgate);
+       }
 }
 
 static void cs_assert(struct spi_device *spi)
index dd3434a..a364b99 100644 (file)
@@ -1217,6 +1217,11 @@ static int spi_qup_suspend(struct device *device)
        struct spi_qup *controller = spi_master_get_devdata(master);
        int ret;
 
+       if (pm_runtime_suspended(device)) {
+               ret = spi_qup_pm_resume_runtime(device);
+               if (ret)
+                       return ret;
+       }
        ret = spi_master_suspend(master);
        if (ret)
                return ret;
@@ -1225,10 +1230,8 @@ static int spi_qup_suspend(struct device *device)
        if (ret)
                return ret;
 
-       if (!pm_runtime_suspended(device)) {
-               clk_disable_unprepare(controller->cclk);
-               clk_disable_unprepare(controller->iclk);
-       }
+       clk_disable_unprepare(controller->cclk);
+       clk_disable_unprepare(controller->iclk);
        return 0;
 }
 
index 60c4de4..7412a30 100644 (file)
@@ -401,9 +401,6 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high)
 
        zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, genfifoentry);
 
-       /* Dummy generic FIFO entry */
-       zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, 0x0);
-
        /* Manually start the generic FIFO command */
        zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
                        zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) |
index 38b4c78..755221b 100644 (file)
@@ -2639,7 +2639,7 @@ int spi_register_controller(struct spi_controller *ctlr)
                if (ctlr->use_gpio_descriptors) {
                        status = spi_get_gpio_descs(ctlr);
                        if (status)
-                               return status;
+                               goto free_bus_id;
                        /*
                         * A controller using GPIO descriptors always
                         * supports SPI_CS_HIGH if need be.
@@ -2649,7 +2649,7 @@ int spi_register_controller(struct spi_controller *ctlr)
                        /* Legacy code path for GPIOs from DT */
                        status = of_spi_get_gpio_numbers(ctlr);
                        if (status)
-                               return status;
+                               goto free_bus_id;
                }
        }
 
@@ -2657,17 +2657,14 @@ int spi_register_controller(struct spi_controller *ctlr)
         * Even if it's just one always-selected device, there must
         * be at least one chipselect.
         */
-       if (!ctlr->num_chipselect)
-               return -EINVAL;
+       if (!ctlr->num_chipselect) {
+               status = -EINVAL;
+               goto free_bus_id;
+       }
 
        status = device_add(&ctlr->dev);
-       if (status < 0) {
-               /* free bus id */
-               mutex_lock(&board_lock);
-               idr_remove(&spi_master_idr, ctlr->bus_num);
-               mutex_unlock(&board_lock);
-               goto done;
-       }
+       if (status < 0)
+               goto free_bus_id;
        dev_dbg(dev, "registered %s %s\n",
                        spi_controller_is_slave(ctlr) ? "slave" : "master",
                        dev_name(&ctlr->dev));
@@ -2683,11 +2680,7 @@ int spi_register_controller(struct spi_controller *ctlr)
                status = spi_controller_initialize_queue(ctlr);
                if (status) {
                        device_del(&ctlr->dev);
-                       /* free bus id */
-                       mutex_lock(&board_lock);
-                       idr_remove(&spi_master_idr, ctlr->bus_num);
-                       mutex_unlock(&board_lock);
-                       goto done;
+                       goto free_bus_id;
                }
        }
        /* add statistics */
@@ -2702,7 +2695,12 @@ int spi_register_controller(struct spi_controller *ctlr)
        /* Register devices from the device tree and ACPI */
        of_register_spi_devices(ctlr);
        acpi_register_spi_devices(ctlr);
-done:
+       return status;
+
+free_bus_id:
+       mutex_lock(&board_lock);
+       idr_remove(&spi_master_idr, ctlr->bus_num);
+       mutex_unlock(&board_lock);
        return status;
 }
 EXPORT_SYMBOL_GPL(spi_register_controller);
index 1e217e3..2ab6e78 100644 (file)
@@ -396,6 +396,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                else
                        retval = get_user(tmp, (u32 __user *)arg);
                if (retval == 0) {
+                       struct spi_controller *ctlr = spi->controller;
                        u32     save = spi->mode;
 
                        if (tmp & ~SPI_MODE_MASK) {
@@ -403,6 +404,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                                break;
                        }
 
+                       if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods &&
+                           ctlr->cs_gpiods[spi->chip_select])
+                               tmp |= SPI_CS_HIGH;
+
                        tmp |= spi->mode & ~SPI_MODE_MASK;
                        spi->mode = (u16)tmp;
                        retval = spi_setup(spi);
index 97c615a..c988353 100644 (file)
@@ -558,13 +558,13 @@ static int hantro_attach_func(struct hantro_dev *vpu,
                goto err_rel_entity1;
 
        /* Connect the three entities */
-       ret = media_create_pad_link(&func->vdev.entity, 0, &func->proc, 1,
+       ret = media_create_pad_link(&func->vdev.entity, 0, &func->proc, 0,
                                    MEDIA_LNK_FL_IMMUTABLE |
                                    MEDIA_LNK_FL_ENABLED);
        if (ret)
                goto err_rel_entity2;
 
-       ret = media_create_pad_link(&func->proc, 0, &func->sink, 0,
+       ret = media_create_pad_link(&func->proc, 1, &func->sink, 0,
                                    MEDIA_LNK_FL_IMMUTABLE |
                                    MEDIA_LNK_FL_ENABLED);
        if (ret)
index 26de676..081d58a 100644 (file)
@@ -93,5 +93,5 @@ Some properties are recognized either by SPI and SDIO versions:
    Must contains 64 hexadecimal digits. Not supported in current version.
 
 WFx driver also supports `mac-address` and `local-mac-address` as described in
-Documentation/devicetree/binding/net/ethernet.txt
+Documentation/devicetree/bindings/net/ethernet.txt
 
index 4e32b64..191f971 100644 (file)
@@ -3,6 +3,6 @@
 config AMDTEE
        tristate "AMD-TEE"
        default m
-       depends on CRYPTO_DEV_SP_PSP
+       depends on CRYPTO_DEV_SP_PSP && CRYPTO_DEV_CCP_DD
        help
          This implements AMD's Trusted Execution Environment (TEE) driver.
index e158159..18e205e 100644 (file)
@@ -1414,10 +1414,6 @@ static int vhost_net_release(struct inode *inode, struct file *f)
 
 static struct socket *get_raw_socket(int fd)
 {
-       struct {
-               struct sockaddr_ll sa;
-               char  buf[MAX_ADDR_LEN];
-       } uaddr;
        int r;
        struct socket *sock = sockfd_lookup(fd, &r);
 
@@ -1430,11 +1426,7 @@ static struct socket *get_raw_socket(int fd)
                goto err;
        }
 
-       r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa, 0);
-       if (r < 0)
-               goto err;
-
-       if (uaddr.sa.sll_family != AF_PACKET) {
+       if (sock->sk->sk_family != AF_PACKET) {
                r = -EPFNOSUPPORT;
                goto err;
        }
index de7b838..998b0de 100644 (file)
@@ -1316,6 +1316,9 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font)
 static int vgacon_resize(struct vc_data *c, unsigned int width,
                         unsigned int height, unsigned int user)
 {
+       if ((width << 1) * height > vga_vram_size)
+               return -EINVAL;
+
        if (width % 2 || width > screen_info.orig_video_cols ||
            height > (screen_info.orig_video_lines * vga_default_font_height)/
            c->vc_font.height)
index b069349..3065dd6 100644 (file)
@@ -54,6 +54,13 @@ module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
+#define WDAT_DEFAULT_TIMEOUT   30
+
+static int timeout = WDAT_DEFAULT_TIMEOUT;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="
+                __MODULE_STRING(WDAT_DEFAULT_TIMEOUT) ")");
+
 static int wdat_wdt_read(struct wdat_wdt *wdat,
         const struct wdat_instruction *instr, u32 *value)
 {
@@ -389,7 +396,7 @@ static int wdat_wdt_probe(struct platform_device *pdev)
 
                memset(&r, 0, sizeof(r));
                r.start = gas->address;
-               r.end = r.start + gas->access_width - 1;
+               r.end = r.start + ACPI_ACCESS_BYTE_WIDTH(gas->access_width) - 1;
                if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
                        r.flags = IORESOURCE_MEM;
                } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
@@ -438,6 +445,22 @@ static int wdat_wdt_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, wdat);
 
+       /*
+        * Set initial timeout so that userspace has time to configure the
+        * watchdog properly after it has opened the device. In some cases
+        * the BIOS default is too short and causes immediate reboot.
+        */
+       if (timeout * 1000 < wdat->wdd.min_hw_heartbeat_ms ||
+           timeout * 1000 > wdat->wdd.max_hw_heartbeat_ms) {
+               dev_warn(dev, "Invalid timeout %d given, using %d\n",
+                        timeout, WDAT_DEFAULT_TIMEOUT);
+               timeout = WDAT_DEFAULT_TIMEOUT;
+       }
+
+       ret = wdat_wdt_set_timeout(&wdat->wdd, timeout);
+       if (ret)
+               return ret;
+
        watchdog_set_nowayout(&wdat->wdd, nowayout);
        return devm_watchdog_register_device(dev, &wdat->wdd);
 }
index ce1077e..7c95516 100644 (file)
@@ -52,7 +52,7 @@ struct xen_pcibk_dev_data {
        unsigned int ack_intr:1; /* .. and ACK-ing */
        unsigned long handled;
        unsigned int irq; /* Saved in case device transitions to MSI/MSI-X */
-       char irq_name[0]; /* xen-pcibk[000:04:00.0] */
+       char irq_name[]; /* xen-pcibk[000:04:00.0] */
 };
 
 /* Used by XenBus and xen_pcibk_ops.c */
index d239fc3..eb5151f 100644 (file)
@@ -313,6 +313,8 @@ static int process_msg(void)
                        req->msg.type = state.msg.type;
                        req->msg.len = state.msg.len;
                        req->body = state.body;
+                       /* write body, then update state */
+                       virt_wmb();
                        req->state = xb_req_state_got_reply;
                        req->cb(req);
                } else
@@ -395,6 +397,8 @@ static int process_writes(void)
        if (state.req->state == xb_req_state_aborted)
                kfree(state.req);
        else {
+               /* write err, then update state */
+               virt_wmb();
                state.req->state = xb_req_state_got_reply;
                wake_up(&state.req->wq);
        }
index 66975da..8c4d05b 100644 (file)
@@ -239,9 +239,9 @@ int xenbus_dev_probe(struct device *_dev)
                goto fail;
        }
 
-       spin_lock(&dev->reclaim_lock);
+       down(&dev->reclaim_sem);
        err = drv->probe(dev, id);
-       spin_unlock(&dev->reclaim_lock);
+       up(&dev->reclaim_sem);
        if (err)
                goto fail_put;
 
@@ -271,9 +271,9 @@ int xenbus_dev_remove(struct device *_dev)
        free_otherend_watch(dev);
 
        if (drv->remove) {
-               spin_lock(&dev->reclaim_lock);
+               down(&dev->reclaim_sem);
                drv->remove(dev);
-               spin_unlock(&dev->reclaim_lock);
+               up(&dev->reclaim_sem);
        }
 
        module_put(drv->driver.owner);
@@ -473,7 +473,7 @@ int xenbus_probe_node(struct xen_bus_type *bus,
                goto fail;
 
        dev_set_name(&xendev->dev, "%s", devname);
-       spin_lock_init(&xendev->reclaim_lock);
+       sema_init(&xendev->reclaim_sem, 1);
 
        /* Register with generic device framework. */
        err = device_register(&xendev->dev);
index 791f6fe..9b2fbe6 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/mm.h>
 #include <linux/notifier.h>
 #include <linux/export.h>
+#include <linux/semaphore.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -257,10 +258,10 @@ static int backend_reclaim_memory(struct device *dev, void *data)
        drv = to_xenbus_driver(dev->driver);
        if (drv && drv->reclaim_memory) {
                xdev = to_xenbus_device(dev);
-               if (!spin_trylock(&xdev->reclaim_lock))
+               if (down_trylock(&xdev->reclaim_sem))
                        return 0;
                drv->reclaim_memory(xdev);
-               spin_unlock(&xdev->reclaim_lock);
+               up(&xdev->reclaim_sem);
        }
        return 0;
 }
index ddc18da..3a06eb6 100644 (file)
@@ -191,8 +191,11 @@ static bool xenbus_ok(void)
 
 static bool test_reply(struct xb_req_data *req)
 {
-       if (req->state == xb_req_state_got_reply || !xenbus_ok())
+       if (req->state == xb_req_state_got_reply || !xenbus_ok()) {
+               /* read req->state before all other fields */
+               virt_rmb();
                return true;
+       }
 
        /* Make sure to reread req->state each time. */
        barrier();
@@ -202,7 +205,7 @@ static bool test_reply(struct xb_req_data *req)
 
 static void *read_reply(struct xb_req_data *req)
 {
-       while (req->state != xb_req_state_got_reply) {
+       do {
                wait_event(req->wq, test_reply(req));
 
                if (!xenbus_ok())
@@ -216,7 +219,7 @@ static void *read_reply(struct xb_req_data *req)
                if (req->err)
                        return ERR_PTR(req->err);
 
-       }
+       } while (req->state != xb_req_state_got_reply);
 
        return req->body;
 }
index 1ccb3f8..27076eb 100644 (file)
@@ -7783,6 +7783,7 @@ static inline blk_status_t btrfs_lookup_and_bind_dio_csum(struct inode *inode,
 {
        struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
        struct btrfs_io_bio *orig_io_bio = btrfs_io_bio(dip->orig_bio);
+       u16 csum_size;
        blk_status_t ret;
 
        /*
@@ -7802,7 +7803,8 @@ static inline blk_status_t btrfs_lookup_and_bind_dio_csum(struct inode *inode,
 
        file_offset -= dip->logical_offset;
        file_offset >>= inode->i_sb->s_blocksize_bits;
-       io_bio->csum = (u8 *)(((u32 *)orig_io_bio->csum) + file_offset);
+       csum_size = btrfs_super_csum_size(btrfs_sb(inode->i_sb)->super_copy);
+       io_bio->csum = orig_io_bio->csum + csum_size * file_offset;
 
        return 0;
 }
index 606f26d..cc3ada1 100644 (file)
@@ -324,6 +324,8 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
        if (full_path == NULL)
                goto cdda_exit;
 
+       convert_delimiter(full_path, '\\');
+
        cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
 
        if (!cifs_sb_master_tlink(cifs_sb)) {
index 46ebaf3..fa77fe5 100644 (file)
@@ -530,6 +530,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
 
        if (tcon->seal)
                seq_puts(s, ",seal");
+       else if (tcon->ses->server->ignore_signature)
+               seq_puts(s, ",signloosely");
        if (tcon->nocase)
                seq_puts(s, ",nocase");
        if (tcon->local_lease)
index de82cfa..0d95636 100644 (file)
@@ -1281,6 +1281,7 @@ struct cifs_fid {
        __u64 volatile_fid;     /* volatile file id for smb2 */
        __u8 lease_key[SMB2_LEASE_KEY_SIZE];    /* lease key for smb2 */
        __u8 create_guid[16];
+       __u32 access;
        struct cifs_pending_open *pending_open;
        unsigned int epoch;
 #ifdef CONFIG_CIFS_DEBUG2
@@ -1741,6 +1742,12 @@ static inline bool is_retryable_error(int error)
        return false;
 }
 
+
+/* cifs_get_writable_file() flags */
+#define FIND_WR_ANY         0
+#define FIND_WR_FSUID_ONLY  1
+#define FIND_WR_WITH_DELETE 2
+
 #define   MID_FREE 0
 #define   MID_REQUEST_ALLOCATED 1
 #define   MID_REQUEST_SUBMITTED 2
index 89eaaf4..e5cb681 100644 (file)
@@ -134,11 +134,12 @@ extern bool backup_cred(struct cifs_sb_info *);
 extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
 extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
                            unsigned int bytes_written);
-extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
+extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, int);
 extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
-                                 bool fsuid_only,
+                                 int flags,
                                  struct cifsFileInfo **ret_file);
 extern int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
+                                 int flags,
                                  struct cifsFileInfo **ret_file);
 extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
 extern int cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
index 3c89569..6f6fb36 100644 (file)
@@ -1492,6 +1492,7 @@ openRetry:
        *oplock = rsp->OplockLevel;
        /* cifs fid stays in le */
        oparms->fid->netfid = rsp->Fid;
+       oparms->fid->access = desired_access;
 
        /* Let caller know file was created so we can set the mode. */
        /* Do we care about the CreateAction in any other cases? */
@@ -2115,7 +2116,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
                wdata2->tailsz = tailsz;
                wdata2->bytes = cur_len;
 
-               rc = cifs_get_writable_file(CIFS_I(inode), false,
+               rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY,
                                            &wdata2->cfile);
                if (!wdata2->cfile) {
                        cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n",
index bc9516a..3b942ec 100644 (file)
@@ -1958,7 +1958,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
 
 /* Return -EBADF if no handle is found and general rc otherwise */
 int
-cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
+cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags,
                       struct cifsFileInfo **ret_file)
 {
        struct cifsFileInfo *open_file, *inv_file = NULL;
@@ -1966,7 +1966,8 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
        bool any_available = false;
        int rc = -EBADF;
        unsigned int refind = 0;
-
+       bool fsuid_only = flags & FIND_WR_FSUID_ONLY;
+       bool with_delete = flags & FIND_WR_WITH_DELETE;
        *ret_file = NULL;
 
        /*
@@ -1998,6 +1999,8 @@ refind_writable:
                        continue;
                if (fsuid_only && !uid_eq(open_file->uid, current_fsuid()))
                        continue;
+               if (with_delete && !(open_file->fid.access & DELETE))
+                       continue;
                if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
                        if (!open_file->invalidHandle) {
                                /* found a good writable file */
@@ -2045,12 +2048,12 @@ refind_writable:
 }
 
 struct cifsFileInfo *
-find_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only)
+find_writable_file(struct cifsInodeInfo *cifs_inode, int flags)
 {
        struct cifsFileInfo *cfile;
        int rc;
 
-       rc = cifs_get_writable_file(cifs_inode, fsuid_only, &cfile);
+       rc = cifs_get_writable_file(cifs_inode, flags, &cfile);
        if (rc)
                cifs_dbg(FYI, "couldn't find writable handle rc=%d", rc);
 
@@ -2059,6 +2062,7 @@ find_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only)
 
 int
 cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
+                      int flags,
                       struct cifsFileInfo **ret_file)
 {
        struct list_head *tmp;
@@ -2085,7 +2089,7 @@ cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
                kfree(full_path);
                cinode = CIFS_I(d_inode(cfile->dentry));
                spin_unlock(&tcon->open_file_lock);
-               return cifs_get_writable_file(cinode, 0, ret_file);
+               return cifs_get_writable_file(cinode, flags, ret_file);
        }
 
        spin_unlock(&tcon->open_file_lock);
@@ -2162,7 +2166,8 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
        if (mapping->host->i_size - offset < (loff_t)to)
                to = (unsigned)(mapping->host->i_size - offset);
 
-       rc = cifs_get_writable_file(CIFS_I(mapping->host), false, &open_file);
+       rc = cifs_get_writable_file(CIFS_I(mapping->host), FIND_WR_ANY,
+                                   &open_file);
        if (!rc) {
                bytes_written = cifs_write(open_file, open_file->pid,
                                           write_data, to - from, &offset);
@@ -2355,7 +2360,7 @@ retry:
                if (cfile)
                        cifsFileInfo_put(cfile);
 
-               rc = cifs_get_writable_file(CIFS_I(inode), false, &cfile);
+               rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY, &cfile);
 
                /* in case of an error store it to return later */
                if (rc)
index b5e6635..1e8a4b1 100644 (file)
@@ -653,8 +653,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
                 */
                if ((fattr->cf_nlink < 1) && !tcon->unix_ext &&
                    !info->DeletePending) {
-                       cifs_dbg(1, "bogus file nlink value %u\n",
-                               fattr->cf_nlink);
+                       cifs_dbg(VFS, "bogus file nlink value %u\n",
+                                fattr->cf_nlink);
                        fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
                }
        }
@@ -2073,6 +2073,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
        struct inode *inode = d_inode(dentry);
        struct super_block *sb = dentry->d_sb;
        char *full_path = NULL;
+       int count = 0;
 
        if (inode == NULL)
                return -ENOENT;
@@ -2094,15 +2095,18 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
                 full_path, inode, inode->i_count.counter,
                 dentry, cifs_get_time(dentry), jiffies);
 
+again:
        if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
                rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
        else
                rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
                                         xid, NULL);
-
+       if (rc == -EAGAIN && count++ < 10)
+               goto again;
 out:
        kfree(full_path);
        free_xid(xid);
+
        return rc;
 }
 
@@ -2278,7 +2282,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
         * writebehind data than the SMB timeout for the SetPathInfo
         * request would allow
         */
-       open_file = find_writable_file(cifsInode, true);
+       open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
        if (open_file) {
                tcon = tlink_tcon(open_file->tlink);
                server = tcon->ses->server;
@@ -2428,7 +2432,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
                args->ctime = NO_CHANGE_64;
 
        args->device = 0;
-       open_file = find_writable_file(cifsInode, true);
+       open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
        if (open_file) {
                u16 nfid = open_file->fid.netfid;
                u32 npid = open_file->pid;
@@ -2531,7 +2535,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
        rc = 0;
 
        if (attrs->ia_valid & ATTR_MTIME) {
-               rc = cifs_get_writable_file(cifsInode, false, &wfile);
+               rc = cifs_get_writable_file(cifsInode, FIND_WR_ANY, &wfile);
                if (!rc) {
                        tcon = tlink_tcon(wfile->tlink);
                        rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid);
index eb994e3..b130efa 100644 (file)
@@ -766,7 +766,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
        struct cifs_tcon *tcon;
 
        /* if the file is already open for write, just use that fileid */
-       open_file = find_writable_file(cinode, true);
+       open_file = find_writable_file(cinode, FIND_WR_FSUID_ONLY);
        if (open_file) {
                fid.netfid = open_file->fid.netfid;
                netpid = open_file->pid;
index 1cf2075..a8c301a 100644 (file)
@@ -521,7 +521,7 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
        cifs_i = CIFS_I(inode);
        dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
        data.Attributes = cpu_to_le32(dosattrs);
-       cifs_get_writable_path(tcon, name, &cfile);
+       cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
        tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
                                 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
                                 CREATE_NOT_FILE, ACL_NO_MODE,
@@ -577,7 +577,7 @@ smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
 {
        struct cifsFileInfo *cfile;
 
-       cifs_get_writable_path(tcon, from_name, &cfile);
+       cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
 
        return smb2_set_path_attr(xid, tcon, from_name, to_name,
                                  cifs_sb, DELETE, SMB2_OP_RENAME, cfile);
index e47190c..c31e84e 100644 (file)
@@ -1364,6 +1364,7 @@ smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
 
        cfile->fid.persistent_fid = fid->persistent_fid;
        cfile->fid.volatile_fid = fid->volatile_fid;
+       cfile->fid.access = fid->access;
 #ifdef CONFIG_CIFS_DEBUG2
        cfile->fid.mid = fid->mid;
 #endif /* CIFS_DEBUG2 */
@@ -3327,7 +3328,7 @@ static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, loff_t offs
         * some servers (Windows2016) will not reflect recent writes in
         * QUERY_ALLOCATED_RANGES until SMB2_flush is called.
         */
-       wrcfile = find_writable_file(cifsi, false);
+       wrcfile = find_writable_file(cifsi, FIND_WR_ANY);
        if (wrcfile) {
                filemap_write_and_wait(inode->i_mapping);
                smb2_flush_file(xid, tcon, &wrcfile->fid);
index 1234f9c..28c0be5 100644 (file)
@@ -2771,6 +2771,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        atomic_inc(&tcon->num_remote_opens);
        oparms->fid->persistent_fid = rsp->PersistentFileId;
        oparms->fid->volatile_fid = rsp->VolatileFileId;
+       oparms->fid->access = oparms->desired_access;
 #ifdef CONFIG_CIFS_DEBUG2
        oparms->fid->mid = le64_to_cpu(rsp->sync_hdr.MessageId);
 #endif /* CIFS_DEBUG2 */
index ff1b764..0c7c4ad 100644 (file)
@@ -2391,7 +2391,7 @@ int ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct flex_groups **old_groups, **new_groups;
-       int size, i;
+       int size, i, j;
 
        if (!sbi->s_log_groups_per_flex)
                return 0;
@@ -2412,8 +2412,8 @@ int ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup)
                                         sizeof(struct flex_groups)),
                                         GFP_KERNEL);
                if (!new_groups[i]) {
-                       for (i--; i >= sbi->s_flex_groups_allocated; i--)
-                               kvfree(new_groups[i]);
+                       for (j = sbi->s_flex_groups_allocated; j < i; j++)
+                               kvfree(new_groups[j]);
                        kvfree(new_groups);
                        ext4_msg(sb, KERN_ERR,
                                 "not enough memory for %d flex groups", size);
index 594b05a..71946da 100644 (file)
@@ -750,6 +750,13 @@ static struct inode *fat_alloc_inode(struct super_block *sb)
                return NULL;
 
        init_rwsem(&ei->truncate_lock);
+       /* Zeroing to allow iput() even if partial initialized inode. */
+       ei->mmu_private = 0;
+       ei->i_start = 0;
+       ei->i_logstart = 0;
+       ei->i_attrs = 0;
+       ei->i_pos = 0;
+
        return &ei->vfs_inode;
 }
 
@@ -1374,16 +1381,6 @@ out:
        return 0;
 }
 
-static void fat_dummy_inode_init(struct inode *inode)
-{
-       /* Initialize this dummy inode to work as no-op. */
-       MSDOS_I(inode)->mmu_private = 0;
-       MSDOS_I(inode)->i_start = 0;
-       MSDOS_I(inode)->i_logstart = 0;
-       MSDOS_I(inode)->i_attrs = 0;
-       MSDOS_I(inode)->i_pos = 0;
-}
-
 static int fat_read_root(struct inode *inode)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
@@ -1844,13 +1841,11 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
        fat_inode = new_inode(sb);
        if (!fat_inode)
                goto out_fail;
-       fat_dummy_inode_init(fat_inode);
        sbi->fat_inode = fat_inode;
 
        fsinfo_inode = new_inode(sb);
        if (!fsinfo_inode)
                goto out_fail;
-       fat_dummy_inode_init(fsinfo_inode);
        fsinfo_inode->i_ino = MSDOS_FSINFO_INO;
        sbi->fsinfo_inode = fsinfo_inode;
        insert_inode_hash(fsinfo_inode);
index 9bc1675..2e4c0fa 100644 (file)
@@ -735,8 +735,9 @@ static void send_sigio_to_task(struct task_struct *p,
                return;
 
        switch (signum) {
-               kernel_siginfo_t si;
-               default:
+               default: {
+                       kernel_siginfo_t si;
+
                        /* Queue a rt signal with the appropriate fd as its
                           value.  We use SI_SIGIO as the source, not 
                           SI_KERNEL, since kernel signals always get 
@@ -769,6 +770,7 @@ static void send_sigio_to_task(struct task_struct *p,
                        si.si_fd    = fd;
                        if (!do_send_sig_info(signum, &si, p, type))
                                break;
+               }
                /* fall-through - fall back on the old plain SIGIO signal */
                case 0:
                        do_send_sig_info(SIGIO, SEND_SIG_PRIV, p, type);
index 0a5ab1a..bf8ed1b 100644 (file)
@@ -535,42 +535,23 @@ next:
        } while (1);
 }
 
-static inline void io_worker_spin_for_work(struct io_wqe *wqe)
-{
-       int i = 0;
-
-       while (++i < 1000) {
-               if (io_wqe_run_queue(wqe))
-                       break;
-               if (need_resched())
-                       break;
-               cpu_relax();
-       }
-}
-
 static int io_wqe_worker(void *data)
 {
        struct io_worker *worker = data;
        struct io_wqe *wqe = worker->wqe;
        struct io_wq *wq = wqe->wq;
-       bool did_work;
 
        io_worker_start(wqe, worker);
 
-       did_work = false;
        while (!test_bit(IO_WQ_BIT_EXIT, &wq->state)) {
                set_current_state(TASK_INTERRUPTIBLE);
 loop:
-               if (did_work)
-                       io_worker_spin_for_work(wqe);
                spin_lock_irq(&wqe->lock);
                if (io_wqe_run_queue(wqe)) {
                        __set_current_state(TASK_RUNNING);
                        io_worker_handle_work(worker);
-                       did_work = true;
                        goto loop;
                }
-               did_work = false;
                /* drops the lock on success, retry */
                if (__io_worker_idle(wqe, worker)) {
                        __release(&wqe->lock);
index ccc7d84..33baba4 100644 (file)
@@ -79,16 +79,10 @@ struct io_wq_work {
        pid_t task_pid;
 };
 
-#define INIT_IO_WORK(work, _func)                      \
-       do {                                            \
-               (work)->list.next = NULL;               \
-               (work)->func = _func;                   \
-               (work)->files = NULL;                   \
-               (work)->mm = NULL;                      \
-               (work)->creds = NULL;                   \
-               (work)->fs = NULL;                      \
-               (work)->flags = 0;                      \
-       } while (0)                                     \
+#define INIT_IO_WORK(work, _func)                              \
+       do {                                                    \
+               *(work) = (struct io_wq_work){ .func = _func }; \
+       } while (0)                                             \
 
 typedef void (get_work_fn)(struct io_wq_work *);
 typedef void (put_work_fn)(struct io_wq_work *);
index de650df..6a595c1 100644 (file)
@@ -183,17 +183,12 @@ struct fixed_file_table {
        struct file             **files;
 };
 
-enum {
-       FFD_F_ATOMIC,
-};
-
 struct fixed_file_data {
        struct fixed_file_table         *table;
        struct io_ring_ctx              *ctx;
 
        struct percpu_ref               refs;
        struct llist_head               put_llist;
-       unsigned long                   state;
        struct work_struct              ref_work;
        struct completion               done;
 };
@@ -1483,10 +1478,10 @@ static void io_free_req(struct io_kiocb *req)
 __attribute__((nonnull))
 static void io_put_req_find_next(struct io_kiocb *req, struct io_kiocb **nxtptr)
 {
-       io_req_find_next(req, nxtptr);
-
-       if (refcount_dec_and_test(&req->refs))
+       if (refcount_dec_and_test(&req->refs)) {
+               io_req_find_next(req, nxtptr);
                __io_free_req(req);
+       }
 }
 
 static void io_put_req(struct io_kiocb *req)
@@ -1821,6 +1816,10 @@ static void io_iopoll_req_issued(struct io_kiocb *req)
                list_add(&req->list, &ctx->poll_list);
        else
                list_add_tail(&req->list, &ctx->poll_list);
+
+       if ((ctx->flags & IORING_SETUP_SQPOLL) &&
+           wq_has_sleeper(&ctx->sqo_wait))
+               wake_up(&ctx->sqo_wait);
 }
 
 static void io_file_put(struct io_submit_state *state)
@@ -2071,7 +2070,7 @@ static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
                ssize_t ret;
                ret = import_single_range(rw, buf, sqe_len, *iovec, iter);
                *iovec = NULL;
-               return ret;
+               return ret < 0 ? ret : sqe_len;
        }
 
        if (req->io) {
@@ -3002,6 +3001,11 @@ static int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        sr->msg = u64_to_user_ptr(READ_ONCE(sqe->addr));
        sr->len = READ_ONCE(sqe->len);
 
+#ifdef CONFIG_COMPAT
+       if (req->ctx->compat)
+               sr->msg_flags |= MSG_CMSG_COMPAT;
+#endif
+
        if (!io || req->opcode == IORING_OP_SEND)
                return 0;
        /* iovec is already imported */
@@ -3154,6 +3158,11 @@ static int io_recvmsg_prep(struct io_kiocb *req,
        sr->msg = u64_to_user_ptr(READ_ONCE(sqe->addr));
        sr->len = READ_ONCE(sqe->len);
 
+#ifdef CONFIG_COMPAT
+       if (req->ctx->compat)
+               sr->msg_flags |= MSG_CMSG_COMPAT;
+#endif
+
        if (!io || req->opcode == IORING_OP_RECV)
                return 0;
        /* iovec is already imported */
@@ -4705,11 +4714,21 @@ static void __io_queue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
        struct io_kiocb *linked_timeout;
        struct io_kiocb *nxt = NULL;
+       const struct cred *old_creds = NULL;
        int ret;
 
 again:
        linked_timeout = io_prep_linked_timeout(req);
 
+       if (req->work.creds && req->work.creds != current_cred()) {
+               if (old_creds)
+                       revert_creds(old_creds);
+               if (old_creds == req->work.creds)
+                       old_creds = NULL; /* restored original creds */
+               else
+                       old_creds = override_creds(req->work.creds);
+       }
+
        ret = io_issue_sqe(req, sqe, &nxt, true);
 
        /*
@@ -4735,7 +4754,7 @@ punt:
 
 err:
        /* drop submission reference */
-       io_put_req(req);
+       io_put_req_find_next(req, &nxt);
 
        if (linked_timeout) {
                if (!ret)
@@ -4759,6 +4778,8 @@ done_req:
                        goto punt;
                goto again;
        }
+       if (old_creds)
+               revert_creds(old_creds);
 }
 
 static void io_queue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe)
@@ -4803,7 +4824,6 @@ static inline void io_queue_link_head(struct io_kiocb *req)
 static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                          struct io_submit_state *state, struct io_kiocb **link)
 {
-       const struct cred *old_creds = NULL;
        struct io_ring_ctx *ctx = req->ctx;
        unsigned int sqe_flags;
        int ret, id;
@@ -4818,14 +4838,12 @@ static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
 
        id = READ_ONCE(sqe->personality);
        if (id) {
-               const struct cred *personality_creds;
-
-               personality_creds = idr_find(&ctx->personality_idr, id);
-               if (unlikely(!personality_creds)) {
+               req->work.creds = idr_find(&ctx->personality_idr, id);
+               if (unlikely(!req->work.creds)) {
                        ret = -EINVAL;
                        goto err_req;
                }
-               old_creds = override_creds(personality_creds);
+               get_cred(req->work.creds);
        }
 
        /* same numerical values with corresponding REQ_F_*, safe to copy */
@@ -4837,8 +4855,6 @@ static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
 err_req:
                io_cqring_add_event(req, ret);
                io_double_put_req(req);
-               if (old_creds)
-                       revert_creds(old_creds);
                return false;
        }
 
@@ -4899,8 +4915,6 @@ err_req:
                }
        }
 
-       if (old_creds)
-               revert_creds(old_creds);
        return true;
 }
 
@@ -5081,9 +5095,8 @@ static int io_sq_thread(void *data)
        const struct cred *old_cred;
        mm_segment_t old_fs;
        DEFINE_WAIT(wait);
-       unsigned inflight;
        unsigned long timeout;
-       int ret;
+       int ret = 0;
 
        complete(&ctx->completions[1]);
 
@@ -5091,39 +5104,19 @@ static int io_sq_thread(void *data)
        set_fs(USER_DS);
        old_cred = override_creds(ctx->creds);
 
-       ret = timeout = inflight = 0;
+       timeout = jiffies + ctx->sq_thread_idle;
        while (!kthread_should_park()) {
                unsigned int to_submit;
 
-               if (inflight) {
+               if (!list_empty(&ctx->poll_list)) {
                        unsigned nr_events = 0;
 
-                       if (ctx->flags & IORING_SETUP_IOPOLL) {
-                               /*
-                                * inflight is the count of the maximum possible
-                                * entries we submitted, but it can be smaller
-                                * if we dropped some of them. If we don't have
-                                * poll entries available, then we know that we
-                                * have nothing left to poll for. Reset the
-                                * inflight count to zero in that case.
-                                */
-                               mutex_lock(&ctx->uring_lock);
-                               if (!list_empty(&ctx->poll_list))
-                                       io_iopoll_getevents(ctx, &nr_events, 0);
-                               else
-                                       inflight = 0;
-                               mutex_unlock(&ctx->uring_lock);
-                       } else {
-                               /*
-                                * Normal IO, just pretend everything completed.
-                                * We don't have to poll completions for that.
-                                */
-                               nr_events = inflight;
-                       }
-
-                       inflight -= nr_events;
-                       if (!inflight)
+                       mutex_lock(&ctx->uring_lock);
+                       if (!list_empty(&ctx->poll_list))
+                               io_iopoll_getevents(ctx, &nr_events, 0);
+                       else
                                timeout = jiffies + ctx->sq_thread_idle;
+                       mutex_unlock(&ctx->uring_lock);
                }
 
                to_submit = io_sqring_entries(ctx);
@@ -5152,7 +5145,7 @@ static int io_sq_thread(void *data)
                         * more IO, we should wait for the application to
                         * reap events and wake us up.
                         */
-                       if (inflight ||
+                       if (!list_empty(&ctx->poll_list) ||
                            (!time_after(jiffies, timeout) && ret != -EBUSY &&
                            !percpu_ref_is_dying(&ctx->refs))) {
                                cond_resched();
@@ -5162,6 +5155,19 @@ static int io_sq_thread(void *data)
                        prepare_to_wait(&ctx->sqo_wait, &wait,
                                                TASK_INTERRUPTIBLE);
 
+                       /*
+                        * While doing polled IO, before going to sleep, we need
+                        * to check if there are new reqs added to poll_list, it
+                        * is because reqs may have been punted to io worker and
+                        * will be added to poll_list later, hence check the
+                        * poll_list again.
+                        */
+                       if ((ctx->flags & IORING_SETUP_IOPOLL) &&
+                           !list_empty_careful(&ctx->poll_list)) {
+                               finish_wait(&ctx->sqo_wait, &wait);
+                               continue;
+                       }
+
                        /* Tell userspace we may need a wakeup call */
                        ctx->rings->sq_flags |= IORING_SQ_NEED_WAKEUP;
                        /* make sure to read SQ tail after writing flags */
@@ -5189,8 +5195,7 @@ static int io_sq_thread(void *data)
                mutex_lock(&ctx->uring_lock);
                ret = io_submit_sqes(ctx, to_submit, NULL, -1, &cur_mm, true);
                mutex_unlock(&ctx->uring_lock);
-               if (ret > 0)
-                       inflight += ret;
+               timeout = jiffies + ctx->sq_thread_idle;
        }
 
        set_fs(old_fs);
@@ -5595,7 +5600,6 @@ static void io_ring_file_ref_switch(struct work_struct *work)
 
        data = container_of(work, struct fixed_file_data, ref_work);
        io_ring_file_ref_flush(data);
-       percpu_ref_get(&data->refs);
        percpu_ref_switch_to_percpu(&data->refs);
 }
 
@@ -5771,8 +5775,13 @@ static void io_atomic_switch(struct percpu_ref *ref)
 {
        struct fixed_file_data *data;
 
+       /*
+        * Juggle reference to ensure we hit zero, if needed, so we can
+        * switch back to percpu mode
+        */
        data = container_of(ref, struct fixed_file_data, refs);
-       clear_bit(FFD_F_ATOMIC, &data->state);
+       percpu_ref_put(&data->refs);
+       percpu_ref_get(&data->refs);
 }
 
 static bool io_queue_file_removal(struct fixed_file_data *data,
@@ -5795,11 +5804,7 @@ static bool io_queue_file_removal(struct fixed_file_data *data,
        llist_add(&pfile->llist, &data->put_llist);
 
        if (pfile == &pfile_stack) {
-               if (!test_and_set_bit(FFD_F_ATOMIC, &data->state)) {
-                       percpu_ref_put(&data->refs);
-                       percpu_ref_switch_to_atomic(&data->refs,
-                                                       io_atomic_switch);
-               }
+               percpu_ref_switch_to_atomic(&data->refs, io_atomic_switch);
                wait_for_completion(&done);
                flush_work(&data->ref_work);
                return false;
@@ -5873,10 +5878,8 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
                up->offset++;
        }
 
-       if (ref_switch && !test_and_set_bit(FFD_F_ATOMIC, &data->state)) {
-               percpu_ref_put(&data->refs);
+       if (ref_switch)
                percpu_ref_switch_to_atomic(&data->refs, io_atomic_switch);
-       }
 
        return done ? done : err;
 }
@@ -6334,6 +6337,7 @@ static void io_ring_ctx_free(struct io_ring_ctx *ctx)
        io_sqe_buffer_unregister(ctx);
        io_sqe_files_unregister(ctx);
        io_eventfd_unregister(ctx);
+       idr_destroy(&ctx->personality_idr);
 
 #if defined(CONFIG_UNIX)
        if (ctx->ring_sock) {
@@ -6647,6 +6651,7 @@ out_fput:
        return submitted ? submitted : ret;
 }
 
+#ifdef CONFIG_PROC_FS
 static int io_uring_show_cred(int id, void *p, void *data)
 {
        const struct cred *cred = p;
@@ -6720,6 +6725,7 @@ static void io_uring_show_fdinfo(struct seq_file *m, struct file *f)
                percpu_ref_put(&ctx->refs);
        }
 }
+#endif
 
 static const struct file_operations io_uring_fops = {
        .release        = io_uring_release,
@@ -6731,7 +6737,9 @@ static const struct file_operations io_uring_fops = {
 #endif
        .poll           = io_uring_poll,
        .fasync         = io_uring_fasync,
+#ifdef CONFIG_PROC_FS
        .show_fdinfo    = io_uring_show_fdinfo,
+#endif
 };
 
 static int io_allocate_scq_urings(struct io_ring_ctx *ctx,
index d181948..3dccc23 100644 (file)
@@ -1150,8 +1150,8 @@ static bool jbd2_write_access_granted(handle_t *handle, struct buffer_head *bh,
        /* For undo access buffer must have data copied */
        if (undo && !jh->b_committed_data)
                goto out;
-       if (jh->b_transaction != handle->h_transaction &&
-           jh->b_next_transaction != handle->h_transaction)
+       if (READ_ONCE(jh->b_transaction) != handle->h_transaction &&
+           READ_ONCE(jh->b_next_transaction) != handle->h_transaction)
                goto out;
        /*
         * There are two reasons for the barrier here:
@@ -2569,8 +2569,8 @@ bool __jbd2_journal_refile_buffer(struct journal_head *jh)
         * our jh reference and thus __jbd2_journal_file_buffer() must not
         * take a new one.
         */
-       jh->b_transaction = jh->b_next_transaction;
-       jh->b_next_transaction = NULL;
+       WRITE_ONCE(jh->b_transaction, jh->b_next_transaction);
+       WRITE_ONCE(jh->b_next_transaction, NULL);
        if (buffer_freed(bh))
                jlist = BJ_Forget;
        else if (jh->b_modified)
index 44b6da0..426b55d 100644 (file)
@@ -753,20 +753,6 @@ int locks_delete_block(struct file_lock *waiter)
 {
        int status = -ENOENT;
 
-       /*
-        * If fl_blocker is NULL, it won't be set again as this thread
-        * "owns" the lock and is the only one that might try to claim
-        * the lock.  So it is safe to test fl_blocker locklessly.
-        * Also if fl_blocker is NULL, this waiter is not listed on
-        * fl_blocked_requests for some lock, so no other request can
-        * be added to the list of fl_blocked_requests for this
-        * request.  So if fl_blocker is NULL, it is safe to
-        * locklessly check if fl_blocked_requests is empty.  If both
-        * of these checks succeed, there is no need to take the lock.
-        */
-       if (waiter->fl_blocker == NULL &&
-           list_empty(&waiter->fl_blocked_requests))
-               return status;
        spin_lock(&blocked_lock_lock);
        if (waiter->fl_blocker)
                status = 0;
index fb87ad3..ef2697b 100644 (file)
@@ -2,6 +2,7 @@ config ZONEFS_FS
        tristate "zonefs filesystem support"
        depends on BLOCK
        depends on BLK_DEV_ZONED
+       select FS_IOMAP
        help
          zonefs is a simple file system which exposes zones of a zoned block
          device (e.g. host-managed or host-aware SMR disk drives) as files.
index 8bc6ef8..69aee3d 100644 (file)
@@ -601,13 +601,13 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
        ssize_t ret;
 
        /*
-        * For async direct IOs to sequential zone files, ignore IOCB_NOWAIT
+        * For async direct IOs to sequential zone files, refuse IOCB_NOWAIT
         * as this can cause write reordering (e.g. the first aio gets EAGAIN
         * on the inode lock but the second goes through but is now unaligned).
         */
-       if (zi->i_ztype == ZONEFS_ZTYPE_SEQ && !is_sync_kiocb(iocb)
-           && (iocb->ki_flags & IOCB_NOWAIT))
-               iocb->ki_flags &= ~IOCB_NOWAIT;
+       if (zi->i_ztype == ZONEFS_ZTYPE_SEQ && !is_sync_kiocb(iocb) &&
+           (iocb->ki_flags & IOCB_NOWAIT))
+               return -EOPNOTSUPP;
 
        if (iocb->ki_flags & IOCB_NOWAIT) {
                if (!inode_trylock(inode))
index a2583c2..4defed5 100644 (file)
@@ -532,11 +532,12 @@ typedef u64 acpi_integer;
         strnlen (a, ACPI_NAMESEG_SIZE) == ACPI_NAMESEG_SIZE)
 
 /*
- * Algorithm to obtain access bit width.
+ * Algorithm to obtain access bit or byte width.
  * Can be used with access_width of struct acpi_generic_address and access_size of
  * struct acpi_resource_generic_register.
  */
 #define ACPI_ACCESS_BIT_WIDTH(size)     (1 << ((size) + 2))
+#define ACPI_ACCESS_BYTE_WIDTH(size)    (1 << ((size) - 1))
 
 /*******************************************************************************
  *
index e34a7b7..294b293 100644 (file)
@@ -96,6 +96,11 @@ struct drm_gem_shmem_object {
         * The address are un-mapped when the count reaches zero.
         */
        unsigned int vmap_use_count;
+
+       /**
+        * @map_cached: map object cached (instead of using writecombine).
+        */
+       bool map_cached;
 };
 
 #define to_drm_gem_shmem_obj(obj) \
index 7e18c93..d11e183 100644 (file)
@@ -10,6 +10,9 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 
+#define BOOTCONFIG_MAGIC       "#BOOTCONFIG\n"
+#define BOOTCONFIG_MAGIC_LEN   12
+
 /* XBC tree node */
 struct xbc_node {
        u16 next;
index cd41f20..875f711 100644 (file)
@@ -492,7 +492,7 @@ struct hid_report_enum {
 };
 
 #define HID_MIN_BUFFER_SIZE    64              /* make sure there is at least a packet size of space */
-#define HID_MAX_BUFFER_SIZE    4096            /* 4kb */
+#define HID_MAX_BUFFER_SIZE    8192            /* 8kb */
 #define HID_CONTROL_FIFO_SIZE  256             /* to init devices with >100 reports */
 #define HID_OUTPUT_FIFO_SIZE   64
 
index 93338fd..33d3796 100644 (file)
@@ -22,19 +22,23 @@ extern int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn);
 int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
                               unsigned int data_len);
 
+#if IS_ENABLED(CONFIG_NF_NAT)
+void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info);
+#else
+#define icmpv6_ndo_send icmpv6_send
+#endif
+
 #else
 
 static inline void icmpv6_send(struct sk_buff *skb,
                               u8 type, u8 code, __u32 info)
 {
-
 }
-#endif
 
-#if IS_ENABLED(CONFIG_NF_NAT)
-void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info);
-#else
-#define icmpv6_ndo_send icmpv6_send
+static inline void icmpv6_ndo_send(struct sk_buff *skb,
+                                  u8 type, u8 code, __u32 info)
+{
+}
 #endif
 
 extern int                             icmpv6_init(void);
index e89eb67..bcb9b2a 100644 (file)
@@ -889,6 +889,8 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu);
 bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu);
 int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu);
 bool kvm_arch_dy_runnable(struct kvm_vcpu *vcpu);
+int kvm_arch_post_init_vm(struct kvm *kvm);
+void kvm_arch_pre_destroy_vm(struct kvm *kvm);
 
 #ifndef __KVM_HAVE_ARCH_VM_ALLOC
 /*
@@ -1342,7 +1344,7 @@ static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val)
 #endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */
 
 struct kvm_vcpu *kvm_get_running_vcpu(void);
-struct kvm_vcpu __percpu **kvm_get_running_vcpus(void);
+struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void);
 
 #ifdef CONFIG_HAVE_KVM_IRQ_BYPASS
 bool kvm_arch_has_irq_bypass(void);
index 52269e5..c54fb96 100644 (file)
@@ -2715,6 +2715,10 @@ static inline bool debug_pagealloc_enabled_static(void)
 #if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_ARCH_HAS_SET_DIRECT_MAP)
 extern void __kernel_map_pages(struct page *page, int numpages, int enable);
 
+/*
+ * When called in DEBUG_PAGEALLOC context, the call should most likely be
+ * guarded by debug_pagealloc_enabled() or debug_pagealloc_enabled_static()
+ */
 static inline void
 kernel_map_pages(struct page *page, int numpages, int enable)
 {
index 908d38d..5448c8b 100644 (file)
@@ -121,6 +121,7 @@ struct ip_set_ext {
        u32 timeout;
        u8 packets_op;
        u8 bytes_op;
+       bool target;
 };
 
 struct ip_set;
@@ -187,6 +188,14 @@ struct ip_set_type_variant {
        /* Return true if "b" set is the same as "a"
         * according to the create set parameters */
        bool (*same_set)(const struct ip_set *a, const struct ip_set *b);
+       /* Region-locking is used */
+       bool region_lock;
+};
+
+struct ip_set_region {
+       spinlock_t lock;        /* Region lock */
+       size_t ext_size;        /* Size of the dynamic extensions */
+       u32 elements;           /* Number of elements vs timeout */
 };
 
 /* The core set type structure */
@@ -501,7 +510,7 @@ ip_set_init_skbinfo(struct ip_set_skbinfo *skbinfo,
 }
 
 #define IP_SET_INIT_KEXT(skb, opt, set)                        \
-       { .bytes = (skb)->len, .packets = 1,            \
+       { .bytes = (skb)->len, .packets = 1, .target = true,\
          .timeout = ip_set_adt_opt_timeout(opt, set) }
 
 #define IP_SET_INIT_UEXT(set)                          \
index 0bf9fdd..3b400b1 100644 (file)
@@ -11,6 +11,7 @@ struct omap2_mcspi_platform_config {
        unsigned short  num_cs;
        unsigned int regs_offset;
        unsigned int pin_dir:1;
+       size_t max_xfer_len;
 };
 
 struct omap2_mcspi_device_config {
index f0e4f36..8a22666 100644 (file)
@@ -1157,7 +1157,7 @@ struct snd_soc_pcm_runtime {
             ((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \
             (i)++)
 #define for_each_rtd_codec_dai_rollback(rtd, i, dai)           \
-       for (; ((--i) >= 0) && ((dai) = rtd->codec_dais[i]);)
+       for (; (--(i) >= 0) && ((dai) = rtd->codec_dais[i]);)
 
 void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd);
 
index 2df8cec..6622912 100644 (file)
@@ -272,9 +272,9 @@ enum {
 #define DM_DEV_SET_GEOMETRY    _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR       4
-#define DM_VERSION_MINOR       41
+#define DM_VERSION_MINOR       42
 #define DM_VERSION_PATCHLEVEL  0
-#define DM_VERSION_EXTRA       "-ioctl (2019-09-16)"
+#define DM_VERSION_EXTRA       "-ioctl (2020-02-27)"
 
 /* Status bits */
 #define DM_READONLY_FLAG       (1 << 0) /* In/Out */
index 28e7dcd..f8aa8ba 100644 (file)
@@ -46,7 +46,7 @@ struct vtpm_shared_page {
        uint8_t pad;
 
        uint8_t nr_extra_pages;  /* extra pages for long packets; may be zero */
-       uint32_t extra_pages[0]; /* grant IDs; length in nr_extra_pages */
+       uint32_t extra_pages[]; /* grant IDs; length in nr_extra_pages */
 };
 
 #endif
index 89a8895..850a43b 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/completion.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/semaphore.h>
 #include <xen/interface/xen.h>
 #include <xen/interface/grant_table.h>
 #include <xen/interface/io/xenbus.h>
@@ -76,7 +77,7 @@ struct xenbus_device {
        enum xenbus_state state;
        struct completion down;
        struct work_struct work;
-       spinlock_t reclaim_lock;
+       struct semaphore reclaim_sem;
 };
 
 static inline struct xenbus_device *to_xenbus_device(struct device *dev)
index 452bc18..20a6ac3 100644 (file)
@@ -1226,13 +1226,12 @@ endif
 
 config BOOT_CONFIG
        bool "Boot config support"
-       depends on BLK_DEV_INITRD
-       default y
+       select BLK_DEV_INITRD
        help
          Extra boot config allows system admin to pass a config file as
          complemental extension of kernel cmdline when booting.
          The boot config file must be attached at the end of initramfs
-         with checksum and size.
+         with checksum, size and magic word.
          See <file:Documentation/admin-guide/bootconfig.rst> for details.
 
          If unsure, say Y.
index f95b014..ee4947a 100644 (file)
@@ -268,7 +268,6 @@ static int __init xbc_snprint_cmdline(char *buf, size_t size,
 {
        struct xbc_node *knode, *vnode;
        char *end = buf + size;
-       char c = '\"';
        const char *val;
        int ret;
 
@@ -279,25 +278,20 @@ static int __init xbc_snprint_cmdline(char *buf, size_t size,
                        return ret;
 
                vnode = xbc_node_get_child(knode);
-               ret = snprintf(buf, rest(buf, end), "%s%c", xbc_namebuf,
-                               vnode ? '=' : ' ');
-               if (ret < 0)
-                       return ret;
-               buf += ret;
-               if (!vnode)
+               if (!vnode) {
+                       ret = snprintf(buf, rest(buf, end), "%s ", xbc_namebuf);
+                       if (ret < 0)
+                               return ret;
+                       buf += ret;
                        continue;
-
-               c = '\"';
+               }
                xbc_array_for_each_value(vnode, val) {
-                       ret = snprintf(buf, rest(buf, end), "%c%s", c, val);
+                       ret = snprintf(buf, rest(buf, end), "%s=\"%s\" ",
+                                      xbc_namebuf, val);
                        if (ret < 0)
                                return ret;
                        buf += ret;
-                       c = ',';
                }
-               if (rest(buf, end) > 2)
-                       strcpy(buf, "\" ");
-               buf += 2;
        }
 
        return buf - (end - size);
@@ -335,7 +329,7 @@ static char * __init xbc_make_cmdline(const char *key)
        return new_cmdline;
 }
 
-u32 boot_config_checksum(unsigned char *p, u32 size)
+static u32 boot_config_checksum(unsigned char *p, u32 size)
 {
        u32 ret = 0;
 
@@ -374,7 +368,11 @@ static void __init setup_boot_config(const char *cmdline)
        if (!initrd_end)
                goto not_found;
 
-       hdr = (u32 *)(initrd_end - 8);
+       data = (char *)initrd_end - BOOTCONFIG_MAGIC_LEN;
+       if (memcmp(data, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN))
+               goto not_found;
+
+       hdr = (u32 *)(data - 8);
        size = hdr[0];
        csum = hdr[1];
 
@@ -418,6 +416,14 @@ not_found:
 }
 #else
 #define setup_boot_config(cmdline)     do { } while (0)
+
+static int __init warn_bootconfig(char *str)
+{
+       pr_warn("WARNING: 'bootconfig' found on the kernel command line but CONFIG_BOOTCONFIG is not set.\n");
+       return 0;
+}
+early_param("bootconfig", warn_bootconfig);
+
 #endif
 
 /* Change NUL term back to "=", to make "param" the whole string. */
index 17b0d52..9ddfe2a 100644 (file)
@@ -1101,13 +1101,11 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature
        audit_log_end(ab);
 }
 
-static int audit_set_feature(struct sk_buff *skb)
+static int audit_set_feature(struct audit_features *uaf)
 {
-       struct audit_features *uaf;
        int i;
 
        BUILD_BUG_ON(AUDIT_LAST_FEATURE + 1 > ARRAY_SIZE(audit_feature_names));
-       uaf = nlmsg_data(nlmsg_hdr(skb));
 
        /* if there is ever a version 2 we should handle that here */
 
@@ -1175,6 +1173,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
        u32                     seq;
        void                    *data;
+       int                     data_len;
        int                     err;
        struct audit_buffer     *ab;
        u16                     msg_type = nlh->nlmsg_type;
@@ -1188,6 +1187,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 
        seq  = nlh->nlmsg_seq;
        data = nlmsg_data(nlh);
+       data_len = nlmsg_len(nlh);
 
        switch (msg_type) {
        case AUDIT_GET: {
@@ -1211,7 +1211,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                struct audit_status     s;
                memset(&s, 0, sizeof(s));
                /* guard against past and future API changes */
-               memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh)));
+               memcpy(&s, data, min_t(size_t, sizeof(s), data_len));
                if (s.mask & AUDIT_STATUS_ENABLED) {
                        err = audit_set_enabled(s.enabled);
                        if (err < 0)
@@ -1315,7 +1315,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        return err;
                break;
        case AUDIT_SET_FEATURE:
-               err = audit_set_feature(skb);
+               if (data_len < sizeof(struct audit_features))
+                       return -EINVAL;
+               err = audit_set_feature(data);
                if (err)
                        return err;
                break;
@@ -1327,6 +1329,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 
                err = audit_filter(msg_type, AUDIT_FILTER_USER);
                if (err == 1) { /* match or error */
+                       char *str = data;
+
                        err = 0;
                        if (msg_type == AUDIT_USER_TTY) {
                                err = tty_audit_push();
@@ -1334,26 +1338,24 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                        break;
                        }
                        audit_log_user_recv_msg(&ab, msg_type);
-                       if (msg_type != AUDIT_USER_TTY)
+                       if (msg_type != AUDIT_USER_TTY) {
+                               /* ensure NULL termination */
+                               str[data_len - 1] = '\0';
                                audit_log_format(ab, " msg='%.*s'",
                                                 AUDIT_MESSAGE_TEXT_MAX,
-                                                (char *)data);
-                       else {
-                               int size;
-
+                                                str);
+                       } else {
                                audit_log_format(ab, " data=");
-                               size = nlmsg_len(nlh);
-                               if (size > 0 &&
-                                   ((unsigned char *)data)[size - 1] == '\0')
-                                       size--;
-                               audit_log_n_untrustedstring(ab, data, size);
+                               if (data_len > 0 && str[data_len - 1] == '\0')
+                                       data_len--;
+                               audit_log_n_untrustedstring(ab, str, data_len);
                        }
                        audit_log_end(ab);
                }
                break;
        case AUDIT_ADD_RULE:
        case AUDIT_DEL_RULE:
-               if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
+               if (data_len < sizeof(struct audit_rule_data))
                        return -EINVAL;
                if (audit_enabled == AUDIT_LOCKED) {
                        audit_log_common_recv_msg(audit_context(), &ab,
@@ -1365,7 +1367,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        audit_log_end(ab);
                        return -EPERM;
                }
-               err = audit_rule_change(msg_type, seq, data, nlmsg_len(nlh));
+               err = audit_rule_change(msg_type, seq, data, data_len);
                break;
        case AUDIT_LIST_RULES:
                err = audit_list_rules_send(skb, seq);
@@ -1380,7 +1382,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        case AUDIT_MAKE_EQUIV: {
                void *bufp = data;
                u32 sizes[2];
-               size_t msglen = nlmsg_len(nlh);
+               size_t msglen = data_len;
                char *old, *new;
 
                err = -EINVAL;
@@ -1456,7 +1458,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 
                memset(&s, 0, sizeof(s));
                /* guard against past and future API changes */
-               memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh)));
+               memcpy(&s, data, min_t(size_t, sizeof(s), data_len));
                /* check if new data is valid */
                if ((s.enabled != 0 && s.enabled != 1) ||
                    (s.log_passwd != 0 && s.log_passwd != 1))
index b0126e9..026e34d 100644 (file)
@@ -456,6 +456,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
        bufp = data->buf;
        for (i = 0; i < data->field_count; i++) {
                struct audit_field *f = &entry->rule.fields[i];
+               u32 f_val;
 
                err = -EINVAL;
 
@@ -464,12 +465,12 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                        goto exit_free;
 
                f->type = data->fields[i];
-               f->val = data->values[i];
+               f_val = data->values[i];
 
                /* Support legacy tests for a valid loginuid */
-               if ((f->type == AUDIT_LOGINUID) && (f->val == AUDIT_UID_UNSET)) {
+               if ((f->type == AUDIT_LOGINUID) && (f_val == AUDIT_UID_UNSET)) {
                        f->type = AUDIT_LOGINUID_SET;
-                       f->val = 0;
+                       f_val = 0;
                        entry->rule.pflags |= AUDIT_LOGINUID_LEGACY;
                }
 
@@ -485,7 +486,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                case AUDIT_SUID:
                case AUDIT_FSUID:
                case AUDIT_OBJ_UID:
-                       f->uid = make_kuid(current_user_ns(), f->val);
+                       f->uid = make_kuid(current_user_ns(), f_val);
                        if (!uid_valid(f->uid))
                                goto exit_free;
                        break;
@@ -494,11 +495,12 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                case AUDIT_SGID:
                case AUDIT_FSGID:
                case AUDIT_OBJ_GID:
-                       f->gid = make_kgid(current_user_ns(), f->val);
+                       f->gid = make_kgid(current_user_ns(), f_val);
                        if (!gid_valid(f->gid))
                                goto exit_free;
                        break;
                case AUDIT_ARCH:
+                       f->val = f_val;
                        entry->rule.arch_f = f;
                        break;
                case AUDIT_SUBJ_USER:
@@ -511,11 +513,13 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                case AUDIT_OBJ_TYPE:
                case AUDIT_OBJ_LEV_LOW:
                case AUDIT_OBJ_LEV_HIGH:
-                       str = audit_unpack_string(&bufp, &remain, f->val);
-                       if (IS_ERR(str))
+                       str = audit_unpack_string(&bufp, &remain, f_val);
+                       if (IS_ERR(str)) {
+                               err = PTR_ERR(str);
                                goto exit_free;
-                       entry->rule.buflen += f->val;
-
+                       }
+                       entry->rule.buflen += f_val;
+                       f->lsm_str = str;
                        err = security_audit_rule_init(f->type, f->op, str,
                                                       (void **)&f->lsm_rule);
                        /* Keep currently invalid fields around in case they
@@ -524,68 +528,71 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                                pr_warn("audit rule for LSM \'%s\' is invalid\n",
                                        str);
                                err = 0;
-                       }
-                       if (err) {
-                               kfree(str);
+                       } else if (err)
                                goto exit_free;
-                       } else
-                               f->lsm_str = str;
                        break;
                case AUDIT_WATCH:
-                       str = audit_unpack_string(&bufp, &remain, f->val);
-                       if (IS_ERR(str))
+                       str = audit_unpack_string(&bufp, &remain, f_val);
+                       if (IS_ERR(str)) {
+                               err = PTR_ERR(str);
                                goto exit_free;
-                       entry->rule.buflen += f->val;
-
-                       err = audit_to_watch(&entry->rule, str, f->val, f->op);
+                       }
+                       err = audit_to_watch(&entry->rule, str, f_val, f->op);
                        if (err) {
                                kfree(str);
                                goto exit_free;
                        }
+                       entry->rule.buflen += f_val;
                        break;
                case AUDIT_DIR:
-                       str = audit_unpack_string(&bufp, &remain, f->val);
-                       if (IS_ERR(str))
+                       str = audit_unpack_string(&bufp, &remain, f_val);
+                       if (IS_ERR(str)) {
+                               err = PTR_ERR(str);
                                goto exit_free;
-                       entry->rule.buflen += f->val;
-
+                       }
                        err = audit_make_tree(&entry->rule, str, f->op);
                        kfree(str);
                        if (err)
                                goto exit_free;
+                       entry->rule.buflen += f_val;
                        break;
                case AUDIT_INODE:
+                       f->val = f_val;
                        err = audit_to_inode(&entry->rule, f);
                        if (err)
                                goto exit_free;
                        break;
                case AUDIT_FILTERKEY:
-                       if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN)
+                       if (entry->rule.filterkey || f_val > AUDIT_MAX_KEY_LEN)
                                goto exit_free;
-                       str = audit_unpack_string(&bufp, &remain, f->val);
-                       if (IS_ERR(str))
+                       str = audit_unpack_string(&bufp, &remain, f_val);
+                       if (IS_ERR(str)) {
+                               err = PTR_ERR(str);
                                goto exit_free;
-                       entry->rule.buflen += f->val;
+                       }
+                       entry->rule.buflen += f_val;
                        entry->rule.filterkey = str;
                        break;
                case AUDIT_EXE:
-                       if (entry->rule.exe || f->val > PATH_MAX)
+                       if (entry->rule.exe || f_val > PATH_MAX)
                                goto exit_free;
-                       str = audit_unpack_string(&bufp, &remain, f->val);
+                       str = audit_unpack_string(&bufp, &remain, f_val);
                        if (IS_ERR(str)) {
                                err = PTR_ERR(str);
                                goto exit_free;
                        }
-                       entry->rule.buflen += f->val;
-
-                       audit_mark = audit_alloc_mark(&entry->rule, str, f->val);
+                       audit_mark = audit_alloc_mark(&entry->rule, str, f_val);
                        if (IS_ERR(audit_mark)) {
                                kfree(str);
                                err = PTR_ERR(audit_mark);
                                goto exit_free;
                        }
+                       entry->rule.buflen += f_val;
                        entry->rule.exe = audit_mark;
                        break;
+               default:
+                       f->val = f_val;
+                       break;
                }
        }
 
index 2833ffb..0b81b26 100644 (file)
@@ -619,8 +619,8 @@ static void forget_original_parent(struct task_struct *father,
        reaper = find_new_reaper(father, reaper);
        list_for_each_entry(p, &father->children, sibling) {
                for_each_thread(p, t) {
-                       t->real_parent = reaper;
-                       BUG_ON((!t->ptrace) != (t->parent == father));
+                       RCU_INIT_POINTER(t->real_parent, reaper);
+                       BUG_ON((!t->ptrace) != (rcu_access_pointer(t->parent) == father));
                        if (likely(!t->ptrace))
                                t->parent = t->real_parent;
                        if (t->pdeath_signal)
index 60a1295..8642530 100644 (file)
@@ -1508,7 +1508,7 @@ static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
                return 0;
        }
        sig = kmem_cache_alloc(sighand_cachep, GFP_KERNEL);
-       rcu_assign_pointer(tsk->sighand, sig);
+       RCU_INIT_POINTER(tsk->sighand, sig);
        if (!sig)
                return -ENOMEM;
 
index ddade80..d82b7b8 100644 (file)
@@ -1681,7 +1681,7 @@ static unsigned long minimum_image_size(unsigned long saveable)
  * hibernation for allocations made while saving the image and for device
  * drivers, in case they need to allocate memory from their hibernation
  * callbacks (these two numbers are given by PAGES_FOR_IO (which is a rough
- * estimate) and reserverd_size divided by PAGE_SIZE (which is tunable through
+ * estimate) and reserved_size divided by PAGE_SIZE (which is tunable through
  * /sys/power/reserved_size, respectively).  To make this happen, we compute the
  * total number of available page frames and allocate at least
  *
index 3c8a379..c1217bf 100644 (file)
@@ -8337,6 +8337,8 @@ static inline void update_sg_wakeup_stats(struct sched_domain *sd,
 
        sgs->group_capacity = group->sgc->capacity;
 
+       sgs->group_weight = group->group_weight;
+
        sgs->group_type = group_classify(sd->imbalance_pct, group, sgs);
 
        /*
index 9ad8dea..5b23963 100644 (file)
@@ -413,27 +413,32 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi
 {
        struct sigqueue *q = NULL;
        struct user_struct *user;
+       int sigpending;
 
        /*
         * Protect access to @t credentials. This can go away when all
         * callers hold rcu read lock.
+        *
+        * NOTE! A pending signal will hold on to the user refcount,
+        * and we get/put the refcount only when the sigpending count
+        * changes from/to zero.
         */
        rcu_read_lock();
-       user = get_uid(__task_cred(t)->user);
-       atomic_inc(&user->sigpending);
+       user = __task_cred(t)->user;
+       sigpending = atomic_inc_return(&user->sigpending);
+       if (sigpending == 1)
+               get_uid(user);
        rcu_read_unlock();
 
-       if (override_rlimit ||
-           atomic_read(&user->sigpending) <=
-                       task_rlimit(t, RLIMIT_SIGPENDING)) {
+       if (override_rlimit || likely(sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {
                q = kmem_cache_alloc(sigqueue_cachep, flags);
        } else {
                print_dropped_signal(sig);
        }
 
        if (unlikely(q == NULL)) {
-               atomic_dec(&user->sigpending);
-               free_uid(user);
+               if (atomic_dec_and_test(&user->sigpending))
+                       free_uid(user);
        } else {
                INIT_LIST_HEAD(&q->list);
                q->flags = 0;
@@ -447,8 +452,8 @@ static void __sigqueue_free(struct sigqueue *q)
 {
        if (q->flags & SIGQUEUE_PREALLOC)
                return;
-       atomic_dec(&q->user->sigpending);
-       free_uid(q->user);
+       if (atomic_dec_and_test(&q->user->sigpending))
+               free_uid(q->user);
        kmem_cache_free(sigqueue_cachep, q);
 }
 
index 91e8851..402eef8 100644 (file)
@@ -143,8 +143,8 @@ if FTRACE
 
 config BOOTTIME_TRACING
        bool "Boot-time Tracing support"
-       depends on BOOT_CONFIG && TRACING
-       default y
+       depends on TRACING
+       select BOOT_CONFIG
        help
          Enable developer to setup ftrace subsystem via supplemental
          kernel cmdline at boot time for debugging (tracing) driver
index 4aefe00..7d56d62 100644 (file)
@@ -111,11 +111,11 @@ static int __init test_gen_synth_cmd(void)
        /* Create some bogus values just for testing */
 
        vals[0] = 777;                  /* next_pid_field */
-       vals[1] = (u64)"hula hoops";    /* next_comm_field */
+       vals[1] = (u64)(long)"hula hoops";      /* next_comm_field */
        vals[2] = 1000000;              /* ts_ns */
        vals[3] = 1000;                 /* ts_ms */
-       vals[4] = smp_processor_id();   /* cpu */
-       vals[5] = (u64)"thneed";        /* my_string_field */
+       vals[4] = raw_smp_processor_id(); /* cpu */
+       vals[5] = (u64)(long)"thneed";  /* my_string_field */
        vals[6] = 598;                  /* my_int_field */
 
        /* Now generate a gen_synth_test event */
@@ -218,11 +218,11 @@ static int __init test_empty_synth_event(void)
        /* Create some bogus values just for testing */
 
        vals[0] = 777;                  /* next_pid_field */
-       vals[1] = (u64)"tiddlywinks";   /* next_comm_field */
+       vals[1] = (u64)(long)"tiddlywinks";     /* next_comm_field */
        vals[2] = 1000000;              /* ts_ns */
        vals[3] = 1000;                 /* ts_ms */
-       vals[4] = smp_processor_id();   /* cpu */
-       vals[5] = (u64)"thneed_2.0";    /* my_string_field */
+       vals[4] = raw_smp_processor_id(); /* cpu */
+       vals[5] = (u64)(long)"thneed_2.0";      /* my_string_field */
        vals[6] = 399;                  /* my_int_field */
 
        /* Now trace an empty_synth_test event */
@@ -290,11 +290,11 @@ static int __init test_create_synth_event(void)
        /* Create some bogus values just for testing */
 
        vals[0] = 777;                  /* next_pid_field */
-       vals[1] = (u64)"tiddlywinks";   /* next_comm_field */
+       vals[1] = (u64)(long)"tiddlywinks";     /* next_comm_field */
        vals[2] = 1000000;              /* ts_ns */
        vals[3] = 1000;                 /* ts_ms */
-       vals[4] = smp_processor_id();   /* cpu */
-       vals[5] = (u64)"thneed";        /* my_string_field */
+       vals[4] = raw_smp_processor_id(); /* cpu */
+       vals[5] = (u64)(long)"thneed";  /* my_string_field */
        vals[6] = 398;                  /* my_int_field */
 
        /* Now generate a create_synth_test event */
@@ -330,7 +330,7 @@ static int __init test_add_next_synth_val(void)
                goto out;
 
        /* next_comm_field */
-       ret = synth_event_add_next_val((u64)"slinky", &trace_state);
+       ret = synth_event_add_next_val((u64)(long)"slinky", &trace_state);
        if (ret)
                goto out;
 
@@ -345,12 +345,12 @@ static int __init test_add_next_synth_val(void)
                goto out;
 
        /* cpu */
-       ret = synth_event_add_next_val(smp_processor_id(), &trace_state);
+       ret = synth_event_add_next_val(raw_smp_processor_id(), &trace_state);
        if (ret)
                goto out;
 
        /* my_string_field */
-       ret = synth_event_add_next_val((u64)"thneed_2.01", &trace_state);
+       ret = synth_event_add_next_val((u64)(long)"thneed_2.01", &trace_state);
        if (ret)
                goto out;
 
@@ -388,7 +388,7 @@ static int __init test_add_synth_val(void)
        if (ret)
                goto out;
 
-       ret = synth_event_add_val("cpu", smp_processor_id(), &trace_state);
+       ret = synth_event_add_val("cpu", raw_smp_processor_id(), &trace_state);
        if (ret)
                goto out;
 
@@ -396,12 +396,12 @@ static int __init test_add_synth_val(void)
        if (ret)
                goto out;
 
-       ret = synth_event_add_val("next_comm_field", (u64)"silly putty",
+       ret = synth_event_add_val("next_comm_field", (u64)(long)"silly putty",
                                  &trace_state);
        if (ret)
                goto out;
 
-       ret = synth_event_add_val("my_string_field", (u64)"thneed_9",
+       ret = synth_event_add_val("my_string_field", (u64)(long)"thneed_9",
                                  &trace_state);
        if (ret)
                goto out;
@@ -423,13 +423,13 @@ static int __init test_trace_synth_event(void)
 
        /* Trace some bogus values just for testing */
        ret = synth_event_trace(create_synth_test, 7,   /* number of values */
-                               444,                    /* next_pid_field */
-                               (u64)"clackers",        /* next_comm_field */
-                               1000000,                /* ts_ns */
-                               1000,                   /* ts_ms */
-                               smp_processor_id(),     /* cpu */
-                               (u64)"Thneed",          /* my_string_field */
-                               999);                   /* my_int_field */
+                               (u64)444,               /* next_pid_field */
+                               (u64)(long)"clackers",  /* next_comm_field */
+                               (u64)1000000,           /* ts_ns */
+                               (u64)1000,              /* ts_ms */
+                               (u64)raw_smp_processor_id(), /* cpu */
+                               (u64)(long)"Thneed",    /* my_string_field */
+                               (u64)999);              /* my_int_field */
        return ret;
 }
 
index c797a15..6b11e4e 100644 (file)
@@ -1837,6 +1837,7 @@ static __init int init_trace_selftests(void)
 
        pr_info("Running postponed tracer tests:\n");
 
+       tracing_selftest_running = true;
        list_for_each_entry_safe(p, n, &postponed_selftests, list) {
                /* This loop can take minutes when sanitizers are enabled, so
                 * lets make sure we allow RCU processing.
@@ -1859,6 +1860,7 @@ static __init int init_trace_selftests(void)
                list_del(&p->list);
                kfree(p);
        }
+       tracing_selftest_running = false;
 
  out:
        mutex_unlock(&trace_types_lock);
index 483b3fd..5f6834a 100644 (file)
@@ -821,6 +821,29 @@ static const char *synth_field_fmt(char *type)
        return fmt;
 }
 
+static void print_synth_event_num_val(struct trace_seq *s,
+                                     char *print_fmt, char *name,
+                                     int size, u64 val, char *space)
+{
+       switch (size) {
+       case 1:
+               trace_seq_printf(s, print_fmt, name, (u8)val, space);
+               break;
+
+       case 2:
+               trace_seq_printf(s, print_fmt, name, (u16)val, space);
+               break;
+
+       case 4:
+               trace_seq_printf(s, print_fmt, name, (u32)val, space);
+               break;
+
+       default:
+               trace_seq_printf(s, print_fmt, name, val, space);
+               break;
+       }
+}
+
 static enum print_line_t print_synth_event(struct trace_iterator *iter,
                                           int flags,
                                           struct trace_event *event)
@@ -859,10 +882,13 @@ static enum print_line_t print_synth_event(struct trace_iterator *iter,
                } else {
                        struct trace_print_flags __flags[] = {
                            __def_gfpflag_names, {-1, NULL} };
+                       char *space = (i == se->n_fields - 1 ? "" : " ");
 
-                       trace_seq_printf(s, print_fmt, se->fields[i]->name,
-                                        entry->fields[n_u64],
-                                        i == se->n_fields - 1 ? "" : " ");
+                       print_synth_event_num_val(s, print_fmt,
+                                                 se->fields[i]->name,
+                                                 se->fields[i]->size,
+                                                 entry->fields[n_u64],
+                                                 space);
 
                        if (strcmp(se->fields[i]->type, "gfp_t") == 0) {
                                trace_seq_puts(s, " (");
@@ -1805,6 +1831,8 @@ __synth_event_trace_start(struct trace_event_file *file,
        int entry_size, fields_size = 0;
        int ret = 0;
 
+       memset(trace_state, '\0', sizeof(*trace_state));
+
        /*
         * Normal event tracing doesn't get called at all unless the
         * ENABLED bit is set (which attaches the probe thus allowing
@@ -1885,6 +1913,11 @@ int synth_event_trace(struct trace_event_file *file, unsigned int n_vals, ...)
                return ret;
        }
 
+       if (n_vals != state.event->n_fields) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        va_start(args, n_vals);
        for (i = 0, n_u64 = 0; i < state.event->n_fields; i++) {
                u64 val;
@@ -1898,12 +1931,30 @@ int synth_event_trace(struct trace_event_file *file, unsigned int n_vals, ...)
                        strscpy(str_field, str_val, STR_VAR_LEN_MAX);
                        n_u64 += STR_VAR_LEN_MAX / sizeof(u64);
                } else {
-                       state.entry->fields[n_u64] = val;
+                       struct synth_field *field = state.event->fields[i];
+
+                       switch (field->size) {
+                       case 1:
+                               *(u8 *)&state.entry->fields[n_u64] = (u8)val;
+                               break;
+
+                       case 2:
+                               *(u16 *)&state.entry->fields[n_u64] = (u16)val;
+                               break;
+
+                       case 4:
+                               *(u32 *)&state.entry->fields[n_u64] = (u32)val;
+                               break;
+
+                       default:
+                               state.entry->fields[n_u64] = val;
+                               break;
+                       }
                        n_u64++;
                }
        }
        va_end(args);
-
+out:
        __synth_event_trace_end(&state);
 
        return ret;
@@ -1942,6 +1993,11 @@ int synth_event_trace_array(struct trace_event_file *file, u64 *vals,
                return ret;
        }
 
+       if (n_vals != state.event->n_fields) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        for (i = 0, n_u64 = 0; i < state.event->n_fields; i++) {
                if (state.event->fields[i]->is_string) {
                        char *str_val = (char *)(long)vals[i];
@@ -1950,11 +2006,30 @@ int synth_event_trace_array(struct trace_event_file *file, u64 *vals,
                        strscpy(str_field, str_val, STR_VAR_LEN_MAX);
                        n_u64 += STR_VAR_LEN_MAX / sizeof(u64);
                } else {
-                       state.entry->fields[n_u64] = vals[i];
+                       struct synth_field *field = state.event->fields[i];
+                       u64 val = vals[i];
+
+                       switch (field->size) {
+                       case 1:
+                               *(u8 *)&state.entry->fields[n_u64] = (u8)val;
+                               break;
+
+                       case 2:
+                               *(u16 *)&state.entry->fields[n_u64] = (u16)val;
+                               break;
+
+                       case 4:
+                               *(u32 *)&state.entry->fields[n_u64] = (u32)val;
+                               break;
+
+                       default:
+                               state.entry->fields[n_u64] = val;
+                               break;
+                       }
                        n_u64++;
                }
        }
-
+out:
        __synth_event_trace_end(&state);
 
        return ret;
@@ -1997,8 +2072,6 @@ int synth_event_trace_start(struct trace_event_file *file,
        if (!trace_state)
                return -EINVAL;
 
-       memset(trace_state, '\0', sizeof(*trace_state));
-
        ret = __synth_event_trace_start(file, trace_state);
        if (ret == -ENOENT)
                ret = 0; /* just disabled, not really an error */
@@ -2069,8 +2142,25 @@ static int __synth_event_add_val(const char *field_name, u64 val,
 
                str_field = (char *)&entry->fields[field->offset];
                strscpy(str_field, str_val, STR_VAR_LEN_MAX);
-       } else
-               entry->fields[field->offset] = val;
+       } else {
+               switch (field->size) {
+               case 1:
+                       *(u8 *)&trace_state->entry->fields[field->offset] = (u8)val;
+                       break;
+
+               case 2:
+                       *(u16 *)&trace_state->entry->fields[field->offset] = (u16)val;
+                       break;
+
+               case 4:
+                       *(u32 *)&trace_state->entry->fields[field->offset] = (u32)val;
+                       break;
+
+               default:
+                       trace_state->entry->fields[field->offset] = val;
+                       break;
+               }
+       }
  out:
        return ret;
 }
index 3ea601a..ec3ce7f 100644 (file)
@@ -533,7 +533,7 @@ struct xbc_node *find_match_node(struct xbc_node *node, char *k)
 
 static int __init __xbc_add_key(char *k)
 {
-       struct xbc_node *node;
+       struct xbc_node *node, *child;
 
        if (!xbc_valid_keyword(k))
                return xbc_parse_error("Invalid keyword", k);
@@ -543,8 +543,12 @@ static int __init __xbc_add_key(char *k)
 
        if (!last_parent)       /* the first level */
                node = find_match_node(xbc_nodes, k);
-       else
-               node = find_match_node(xbc_node_get_child(last_parent), k);
+       else {
+               child = xbc_node_get_child(last_parent);
+               if (child && xbc_node_is_value(child))
+                       return xbc_parse_error("Subkey is mixed with value", k);
+               node = find_match_node(child, k);
+       }
 
        if (node)
                last_parent = node;
@@ -574,10 +578,10 @@ static int __init __xbc_parse_keys(char *k)
        return __xbc_add_key(k);
 }
 
-static int __init xbc_parse_kv(char **k, char *v)
+static int __init xbc_parse_kv(char **k, char *v, int op)
 {
        struct xbc_node *prev_parent = last_parent;
-       struct xbc_node *node;
+       struct xbc_node *child;
        char *next;
        int c, ret;
 
@@ -585,12 +589,19 @@ static int __init xbc_parse_kv(char **k, char *v)
        if (ret)
                return ret;
 
+       child = xbc_node_get_child(last_parent);
+       if (child) {
+               if (xbc_node_is_key(child))
+                       return xbc_parse_error("Value is mixed with subkey", v);
+               else if (op == '=')
+                       return xbc_parse_error("Value is redefined", v);
+       }
+
        c = __xbc_parse_value(&v, &next);
        if (c < 0)
                return c;
 
-       node = xbc_add_sibling(v, XBC_VALUE);
-       if (!node)
+       if (!xbc_add_sibling(v, XBC_VALUE))
                return -ENOMEM;
 
        if (c == ',') { /* Array */
@@ -763,7 +774,7 @@ int __init xbc_init(char *buf)
 
        p = buf;
        do {
-               q = strpbrk(p, "{}=;\n#");
+               q = strpbrk(p, "{}=+;\n#");
                if (!q) {
                        p = skip_spaces(p);
                        if (*p != '\0')
@@ -774,8 +785,15 @@ int __init xbc_init(char *buf)
                c = *q;
                *q++ = '\0';
                switch (c) {
+               case '+':
+                       if (*q++ != '=') {
+                               ret = xbc_parse_error("Wrong '+' operator",
+                                                       q - 2);
+                               break;
+                       }
+                       /* Fall through */
                case '=':
-                       ret = xbc_parse_kv(&p, q);
+                       ret = xbc_parse_kv(&p, q, c);
                        break;
                case '{':
                        ret = xbc_open_brace(&p, q);
index 6d83caf..ad0699c 100644 (file)
@@ -235,6 +235,9 @@ bool chacha20poly1305_crypt_sg_inplace(struct scatterlist *src,
                __le64 lens[2];
        } b __aligned(16);
 
+       if (WARN_ON(src_len > INT_MAX))
+               return false;
+
        chacha_load_key(b.k, key);
 
        b.iv[0] = 0;
index b08b199..24ad53b 100644 (file)
@@ -3043,8 +3043,7 @@ void set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
                return;
 
        flush_cache_range(vma, address, address + HPAGE_PMD_SIZE);
-       pmdval = *pvmw->pmd;
-       pmdp_invalidate(vma, address, pvmw->pmd);
+       pmdval = pmdp_invalidate(vma, address, pvmw->pmd);
        if (pmd_dirty(pmdval))
                set_page_dirty(page);
        entry = make_migration_entry(page, pmd_write(pmdval));
index 0bccc62..e8bfdf0 100644 (file)
@@ -2257,7 +2257,7 @@ static inline bool cow_user_page(struct page *dst, struct page *src,
        bool ret;
        void *kaddr;
        void __user *uaddr;
-       bool force_mkyoung;
+       bool locked = false;
        struct vm_area_struct *vma = vmf->vma;
        struct mm_struct *mm = vma->vm_mm;
        unsigned long addr = vmf->address;
@@ -2282,11 +2282,11 @@ static inline bool cow_user_page(struct page *dst, struct page *src,
         * On architectures with software "accessed" bits, we would
         * take a double page fault, so mark it accessed here.
         */
-       force_mkyoung = arch_faults_on_old_pte() && !pte_young(vmf->orig_pte);
-       if (force_mkyoung) {
+       if (arch_faults_on_old_pte() && !pte_young(vmf->orig_pte)) {
                pte_t entry;
 
                vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl);
+               locked = true;
                if (!likely(pte_same(*vmf->pte, vmf->orig_pte))) {
                        /*
                         * Other thread has already handled the fault
@@ -2310,18 +2310,37 @@ static inline bool cow_user_page(struct page *dst, struct page *src,
         * zeroes.
         */
        if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) {
+               if (locked)
+                       goto warn;
+
+               /* Re-validate under PTL if the page is still mapped */
+               vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl);
+               locked = true;
+               if (!likely(pte_same(*vmf->pte, vmf->orig_pte))) {
+                       /* The PTE changed under us. Retry page fault. */
+                       ret = false;
+                       goto pte_unlock;
+               }
+
                /*
-                * Give a warn in case there can be some obscure
-                * use-case
+                * The same page can be mapped back since last copy attampt.
+                * Try to copy again under PTL.
                 */
-               WARN_ON_ONCE(1);
-               clear_page(kaddr);
+               if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) {
+                       /*
+                        * Give a warn in case there can be some obscure
+                        * use-case
+                        */
+warn:
+                       WARN_ON_ONCE(1);
+                       clear_page(kaddr);
+               }
        }
 
        ret = true;
 
 pte_unlock:
-       if (force_mkyoung)
+       if (locked)
                pte_unmap_unlock(vmf->pte, vmf->ptl);
        kunmap_atomic(kaddr);
        flush_dcache_page(dst);
index 0a54ffa..19389cd 100644 (file)
@@ -574,7 +574,13 @@ EXPORT_SYMBOL_GPL(restore_online_page_callback);
 
 void generic_online_page(struct page *page, unsigned int order)
 {
-       kernel_map_pages(page, 1 << order, 1);
+       /*
+        * Freeing the page with debug_pagealloc enabled will try to unmap it,
+        * so we should map it first. This is better than introducing a special
+        * case in page freeing fast path.
+        */
+       if (debug_pagealloc_enabled_static())
+               kernel_map_pages(page, 1 << order, 1);
        __free_pages_core(page, order);
        totalram_pages_add(1UL << order);
 #ifdef CONFIG_HIGHMEM
index 7a8e84f..311c0da 100644 (file)
@@ -161,6 +161,31 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
        return pages;
 }
 
+/*
+ * Used when setting automatic NUMA hinting protection where it is
+ * critical that a numa hinting PMD is not confused with a bad PMD.
+ */
+static inline int pmd_none_or_clear_bad_unless_trans_huge(pmd_t *pmd)
+{
+       pmd_t pmdval = pmd_read_atomic(pmd);
+
+       /* See pmd_none_or_trans_huge_or_clear_bad for info on barrier */
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+       barrier();
+#endif
+
+       if (pmd_none(pmdval))
+               return 1;
+       if (pmd_trans_huge(pmdval))
+               return 0;
+       if (unlikely(pmd_bad(pmdval))) {
+               pmd_clear_bad(pmd);
+               return 1;
+       }
+
+       return 0;
+}
+
 static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
                pud_t *pud, unsigned long addr, unsigned long end,
                pgprot_t newprot, int dirty_accountable, int prot_numa)
@@ -178,8 +203,17 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
                unsigned long this_pages;
 
                next = pmd_addr_end(addr, end);
-               if (!is_swap_pmd(*pmd) && !pmd_trans_huge(*pmd) && !pmd_devmap(*pmd)
-                               && pmd_none_or_clear_bad(pmd))
+
+               /*
+                * Automatic NUMA balancing walks the tables with mmap_sem
+                * held for read. It's possible a parallel update to occur
+                * between pmd_trans_huge() and a pmd_none_or_clear_bad()
+                * check leading to a false positive and clearing.
+                * Hence, it's necessary to atomically read the PMD value
+                * for all the checks.
+                */
+               if (!is_swap_pmd(*pmd) && !pmd_devmap(*pmd) &&
+                    pmd_none_or_clear_bad_unless_trans_huge(pmd))
                        goto next;
 
                /* invoke the mmu notifier if the pmd is populated */
index c8f7540..aad3ba7 100644 (file)
@@ -3386,8 +3386,6 @@ static const struct constant_table shmem_param_enums_huge[] = {
        {"always",      SHMEM_HUGE_ALWAYS },
        {"within_size", SHMEM_HUGE_WITHIN_SIZE },
        {"advise",      SHMEM_HUGE_ADVISE },
-       {"deny",        SHMEM_HUGE_DENY },
-       {"force",       SHMEM_HUGE_FORCE },
        {}
 };
 
index 43754d8..42f31c4 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/workqueue.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
-#include <linux/rwlock.h>
 #include <linux/zpool.h>
 #include <linux/magic.h>
 
index dc3d2c1..0e3dbc5 100644 (file)
@@ -34,7 +34,6 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        const struct nf_br_ops *nf_ops;
        u8 state = BR_STATE_FORWARDING;
        const unsigned char *dest;
-       struct ethhdr *eth;
        u16 vid = 0;
 
        rcu_read_lock();
@@ -54,15 +53,14 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        BR_INPUT_SKB_CB(skb)->frag_max_size = 0;
 
        skb_reset_mac_header(skb);
-       eth = eth_hdr(skb);
        skb_pull(skb, ETH_HLEN);
 
        if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid, &state))
                goto out;
 
        if (IS_ENABLED(CONFIG_INET) &&
-           (eth->h_proto == htons(ETH_P_ARP) ||
-            eth->h_proto == htons(ETH_P_RARP)) &&
+           (eth_hdr(skb)->h_proto == htons(ETH_P_ARP) ||
+            eth_hdr(skb)->h_proto == htons(ETH_P_RARP)) &&
            br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) {
                br_do_proxy_suppress_arp(skb, br, vid, NULL);
        } else if (IS_ENABLED(CONFIG_IPV6) &&
index e10bd68..c6c985f 100644 (file)
@@ -3076,6 +3076,8 @@ static u16 skb_tx_hash(const struct net_device *dev,
 
        if (skb_rx_queue_recorded(skb)) {
                hash = skb_get_rx_queue(skb);
+               if (hash >= qoffset)
+                       hash -= qoffset;
                while (unlikely(hash >= qcount))
                        hash -= qcount;
                return hash + qoffset;
index 549ee56..5e22080 100644 (file)
@@ -2103,11 +2103,11 @@ err_action_values_put:
 
 static struct devlink_dpipe_table *
 devlink_dpipe_table_find(struct list_head *dpipe_tables,
-                        const char *table_name)
+                        const char *table_name, struct devlink *devlink)
 {
        struct devlink_dpipe_table *table;
-
-       list_for_each_entry_rcu(table, dpipe_tables, list) {
+       list_for_each_entry_rcu(table, dpipe_tables, list,
+                               lockdep_is_held(&devlink->lock)) {
                if (!strcmp(table->name, table_name))
                        return table;
        }
@@ -2226,7 +2226,7 @@ static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
 
        table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
        table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
-                                        table_name);
+                                        table_name, devlink);
        if (!table)
                return -EINVAL;
 
@@ -2382,7 +2382,7 @@ static int devlink_dpipe_table_counters_set(struct devlink *devlink,
        struct devlink_dpipe_table *table;
 
        table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
-                                        table_name);
+                                        table_name, devlink);
        if (!table)
                return -EINVAL;
 
@@ -6854,7 +6854,7 @@ bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
 
        rcu_read_lock();
        table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
-                                        table_name);
+                                        table_name, devlink);
        enabled = false;
        if (table)
                enabled = table->counters_enabled;
@@ -6878,26 +6878,34 @@ int devlink_dpipe_table_register(struct devlink *devlink,
                                 void *priv, bool counter_control_extern)
 {
        struct devlink_dpipe_table *table;
-
-       if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name))
-               return -EEXIST;
+       int err = 0;
 
        if (WARN_ON(!table_ops->size_get))
                return -EINVAL;
 
+       mutex_lock(&devlink->lock);
+
+       if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
+                                    devlink)) {
+               err = -EEXIST;
+               goto unlock;
+       }
+
        table = kzalloc(sizeof(*table), GFP_KERNEL);
-       if (!table)
-               return -ENOMEM;
+       if (!table) {
+               err = -ENOMEM;
+               goto unlock;
+       }
 
        table->name = table_name;
        table->table_ops = table_ops;
        table->priv = priv;
        table->counter_control_extern = counter_control_extern;
 
-       mutex_lock(&devlink->lock);
        list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
+unlock:
        mutex_unlock(&devlink->lock);
-       return 0;
+       return err;
 }
 EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
 
@@ -6914,7 +6922,7 @@ void devlink_dpipe_table_unregister(struct devlink *devlink,
 
        mutex_lock(&devlink->lock);
        table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
-                                        table_name);
+                                        table_name, devlink);
        if (!table)
                goto unlock;
        list_del_rcu(&table->list);
@@ -7071,7 +7079,7 @@ int devlink_dpipe_table_resource_set(struct devlink *devlink,
 
        mutex_lock(&devlink->lock);
        table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
-                                        table_name);
+                                        table_name, devlink);
        if (!table) {
                err = -EINVAL;
                goto out;
index 8977fe1..ef91975 100644 (file)
@@ -305,7 +305,8 @@ nla_put_failure:
 static const struct nla_policy bitset_policy[ETHTOOL_A_BITSET_MAX + 1] = {
        [ETHTOOL_A_BITSET_UNSPEC]       = { .type = NLA_REJECT },
        [ETHTOOL_A_BITSET_NOMASK]       = { .type = NLA_FLAG },
-       [ETHTOOL_A_BITSET_SIZE]         = { .type = NLA_U32 },
+       [ETHTOOL_A_BITSET_SIZE]         = NLA_POLICY_MAX(NLA_U32,
+                                                        ETHNL_MAX_BITSET_SIZE),
        [ETHTOOL_A_BITSET_BITS]         = { .type = NLA_NESTED },
        [ETHTOOL_A_BITSET_VALUE]        = { .type = NLA_BINARY },
        [ETHTOOL_A_BITSET_MASK]         = { .type = NLA_BINARY },
index b8247e3..b849f9d 100644 (file)
@@ -3,6 +3,8 @@
 #ifndef _NET_ETHTOOL_BITSET_H
 #define _NET_ETHTOOL_BITSET_H
 
+#define ETHNL_MAX_BITSET_SIZE S16_MAX
+
 typedef const char (*const ethnl_string_array_t)[ETH_GSTRING_LEN];
 
 int ethnl_bitset_is_compact(const struct nlattr *bitset, bool *compact);
index 3768822..0bd10a1 100644 (file)
@@ -1724,6 +1724,7 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
 {
        unsigned char optbuf[sizeof(struct ip_options) + 40];
        struct ip_options *opt = (struct ip_options *)optbuf;
+       int res;
 
        if (ip_hdr(skb)->protocol == IPPROTO_ICMP || error != -EACCES)
                return;
@@ -1735,7 +1736,11 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
 
        memset(opt, 0, sizeof(struct ip_options));
        opt->optlen = ip_hdr(skb)->ihl*4 - sizeof(struct iphdr);
-       if (__ip_options_compile(dev_net(skb->dev), opt, skb, NULL))
+       rcu_read_lock();
+       res = __ip_options_compile(dev_net(skb->dev), opt, skb, NULL);
+       rcu_read_unlock();
+
+       if (res)
                return;
 
        if (gateway)
index 316ebdf..6b6b570 100644 (file)
@@ -6124,7 +6124,11 @@ static void tcp_rcv_synrecv_state_fastopen(struct sock *sk)
 {
        struct request_sock *req;
 
-       tcp_try_undo_loss(sk, false);
+       /* If we are still handling the SYNACK RTO, see if timestamp ECR allows
+        * undo. If peer SACKs triggered fast recovery, we can't undo here.
+        */
+       if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss)
+               tcp_try_undo_loss(sk, false);
 
        /* Reset rtx states to prevent spurious retransmits_timed_out() */
        tcp_sk(sk)->retrans_stamp = 0;
index 79fc012..debdaeb 100644 (file)
@@ -183,9 +183,15 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                                        retv = -EBUSY;
                                        break;
                                }
-                       } else if (sk->sk_protocol != IPPROTO_TCP)
+                       } else if (sk->sk_protocol == IPPROTO_TCP) {
+                               if (sk->sk_prot != &tcpv6_prot) {
+                                       retv = -EBUSY;
+                                       break;
+                               }
                                break;
-
+                       } else {
+                               break;
+                       }
                        if (sk->sk_state != TCP_ESTABLISHED) {
                                retv = -ENOTCONN;
                                break;
index e041af2..88d7a69 100644 (file)
@@ -2959,7 +2959,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
            (auth_transaction == 2 &&
             ifmgd->auth_data->expected_transaction == 2)) {
                if (!ieee80211_mark_sta_auth(sdata, bssid))
-                       goto out_err;
+                       return; /* ignore frame -- wait for timeout */
        } else if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE &&
                   auth_transaction == 2) {
                sdata_info(sdata, "SAE peer confirmed\n");
@@ -2967,10 +2967,6 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
        }
 
        cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
-       return;
- out_err:
-       mutex_unlock(&sdata->local->sta_mtx);
-       /* ignore frame -- wait for timeout */
 }
 
 #define case_WLAN(type) \
index 0e05ff0..0ba98ad 100644 (file)
@@ -4114,7 +4114,7 @@ void __ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata)
 
        lockdep_assert_held(&local->sta_mtx);
 
-       list_for_each_entry_rcu(sta, &local->sta_list, list) {
+       list_for_each_entry(sta, &local->sta_list, list) {
                if (sdata != sta->sdata &&
                    (!sta->sdata->bss || sta->sdata->bss != sdata->bss))
                        continue;
index e9aa680..3c19a8e 100644 (file)
@@ -543,6 +543,11 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
        }
 }
 
+static unsigned int mptcp_sync_mss(struct sock *sk, u32 pmtu)
+{
+       return 0;
+}
+
 static int __mptcp_init_sock(struct sock *sk)
 {
        struct mptcp_sock *msk = mptcp_sk(sk);
@@ -551,6 +556,7 @@ static int __mptcp_init_sock(struct sock *sk)
        __set_bit(MPTCP_SEND_SPACE, &msk->flags);
 
        msk->first = NULL;
+       inet_csk(sk)->icsk_sync_mss = mptcp_sync_mss;
 
        return 0;
 }
index 69c107f..8dd1758 100644 (file)
@@ -723,6 +723,20 @@ ip_set_rcu_get(struct net *net, ip_set_id_t index)
        return set;
 }
 
+static inline void
+ip_set_lock(struct ip_set *set)
+{
+       if (!set->variant->region_lock)
+               spin_lock_bh(&set->lock);
+}
+
+static inline void
+ip_set_unlock(struct ip_set *set)
+{
+       if (!set->variant->region_lock)
+               spin_unlock_bh(&set->lock);
+}
+
 int
 ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
            const struct xt_action_param *par, struct ip_set_adt_opt *opt)
@@ -744,9 +758,9 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
        if (ret == -EAGAIN) {
                /* Type requests element to be completed */
                pr_debug("element must be completed, ADD is triggered\n");
-               spin_lock_bh(&set->lock);
+               ip_set_lock(set);
                set->variant->kadt(set, skb, par, IPSET_ADD, opt);
-               spin_unlock_bh(&set->lock);
+               ip_set_unlock(set);
                ret = 1;
        } else {
                /* --return-nomatch: invert matched element */
@@ -775,9 +789,9 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
            !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
                return -IPSET_ERR_TYPE_MISMATCH;
 
-       spin_lock_bh(&set->lock);
+       ip_set_lock(set);
        ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
-       spin_unlock_bh(&set->lock);
+       ip_set_unlock(set);
 
        return ret;
 }
@@ -797,9 +811,9 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
            !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
                return -IPSET_ERR_TYPE_MISMATCH;
 
-       spin_lock_bh(&set->lock);
+       ip_set_lock(set);
        ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
-       spin_unlock_bh(&set->lock);
+       ip_set_unlock(set);
 
        return ret;
 }
@@ -1264,9 +1278,9 @@ ip_set_flush_set(struct ip_set *set)
 {
        pr_debug("set: %s\n",  set->name);
 
-       spin_lock_bh(&set->lock);
+       ip_set_lock(set);
        set->variant->flush(set);
-       spin_unlock_bh(&set->lock);
+       ip_set_unlock(set);
 }
 
 static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb,
@@ -1713,9 +1727,9 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
        bool eexist = flags & IPSET_FLAG_EXIST, retried = false;
 
        do {
-               spin_lock_bh(&set->lock);
+               ip_set_lock(set);
                ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
-               spin_unlock_bh(&set->lock);
+               ip_set_unlock(set);
                retried = true;
        } while (ret == -EAGAIN &&
                 set->variant->resize &&
index 7480ce5..e52d7b7 100644 (file)
@@ -7,13 +7,21 @@
 #include <linux/rcupdate.h>
 #include <linux/jhash.h>
 #include <linux/types.h>
+#include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/ipset/ip_set.h>
 
-#define __ipset_dereference_protected(p, c)    rcu_dereference_protected(p, c)
-#define ipset_dereference_protected(p, set) \
-       __ipset_dereference_protected(p, lockdep_is_held(&(set)->lock))
-
-#define rcu_dereference_bh_nfnl(p)     rcu_dereference_bh_check(p, 1)
+#define __ipset_dereference(p)         \
+       rcu_dereference_protected(p, 1)
+#define ipset_dereference_nfnl(p)      \
+       rcu_dereference_protected(p,    \
+               lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET))
+#define ipset_dereference_set(p, set)  \
+       rcu_dereference_protected(p,    \
+               lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET) || \
+               lockdep_is_held(&(set)->lock))
+#define ipset_dereference_bh_nfnl(p)   \
+       rcu_dereference_bh_check(p,     \
+               lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET))
 
 /* Hashing which uses arrays to resolve clashing. The hash table is resized
  * (doubled) when searching becomes too long.
@@ -72,11 +80,35 @@ struct hbucket {
                __aligned(__alignof__(u64));
 };
 
+/* Region size for locking == 2^HTABLE_REGION_BITS */
+#define HTABLE_REGION_BITS     10
+#define ahash_numof_locks(htable_bits)         \
+       ((htable_bits) < HTABLE_REGION_BITS ? 1 \
+               : jhash_size((htable_bits) - HTABLE_REGION_BITS))
+#define ahash_sizeof_regions(htable_bits)              \
+       (ahash_numof_locks(htable_bits) * sizeof(struct ip_set_region))
+#define ahash_region(n, htable_bits)           \
+       ((n) % ahash_numof_locks(htable_bits))
+#define ahash_bucket_start(h,  htable_bits)    \
+       ((htable_bits) < HTABLE_REGION_BITS ? 0 \
+               : (h) * jhash_size(HTABLE_REGION_BITS))
+#define ahash_bucket_end(h,  htable_bits)      \
+       ((htable_bits) < HTABLE_REGION_BITS ? jhash_size(htable_bits)   \
+               : ((h) + 1) * jhash_size(HTABLE_REGION_BITS))
+
+struct htable_gc {
+       struct delayed_work dwork;
+       struct ip_set *set;     /* Set the gc belongs to */
+       u32 region;             /* Last gc run position */
+};
+
 /* The hash table: the table size stored here in order to make resizing easy */
 struct htable {
        atomic_t ref;           /* References for resizing */
-       atomic_t uref;          /* References for dumping */
+       atomic_t uref;          /* References for dumping and gc */
        u8 htable_bits;         /* size of hash table == 2^htable_bits */
+       u32 maxelem;            /* Maxelem per region */
+       struct ip_set_region *hregion;  /* Region locks and ext sizes */
        struct hbucket __rcu *bucket[0]; /* hashtable buckets */
 };
 
@@ -162,6 +194,10 @@ htable_bits(u32 hashsize)
 #define NLEN                   0
 #endif /* IP_SET_HASH_WITH_NETS */
 
+#define SET_ELEM_EXPIRED(set, d)       \
+       (SET_WITH_TIMEOUT(set) &&       \
+        ip_set_timeout_expired(ext_timeout(d, set)))
+
 #endif /* _IP_SET_HASH_GEN_H */
 
 #ifndef MTYPE
@@ -205,10 +241,12 @@ htable_bits(u32 hashsize)
 #undef mtype_test_cidrs
 #undef mtype_test
 #undef mtype_uref
-#undef mtype_expire
 #undef mtype_resize
+#undef mtype_ext_size
+#undef mtype_resize_ad
 #undef mtype_head
 #undef mtype_list
+#undef mtype_gc_do
 #undef mtype_gc
 #undef mtype_gc_init
 #undef mtype_variant
@@ -247,10 +285,12 @@ htable_bits(u32 hashsize)
 #define mtype_test_cidrs       IPSET_TOKEN(MTYPE, _test_cidrs)
 #define mtype_test             IPSET_TOKEN(MTYPE, _test)
 #define mtype_uref             IPSET_TOKEN(MTYPE, _uref)
-#define mtype_expire           IPSET_TOKEN(MTYPE, _expire)
 #define mtype_resize           IPSET_TOKEN(MTYPE, _resize)
+#define mtype_ext_size         IPSET_TOKEN(MTYPE, _ext_size)
+#define mtype_resize_ad                IPSET_TOKEN(MTYPE, _resize_ad)
 #define mtype_head             IPSET_TOKEN(MTYPE, _head)
 #define mtype_list             IPSET_TOKEN(MTYPE, _list)
+#define mtype_gc_do            IPSET_TOKEN(MTYPE, _gc_do)
 #define mtype_gc               IPSET_TOKEN(MTYPE, _gc)
 #define mtype_gc_init          IPSET_TOKEN(MTYPE, _gc_init)
 #define mtype_variant          IPSET_TOKEN(MTYPE, _variant)
@@ -275,8 +315,7 @@ htable_bits(u32 hashsize)
 /* The generic hash structure */
 struct htype {
        struct htable __rcu *table; /* the hash table */
-       struct timer_list gc;   /* garbage collection when timeout enabled */
-       struct ip_set *set;     /* attached to this ip_set */
+       struct htable_gc gc;    /* gc workqueue */
        u32 maxelem;            /* max elements in the hash */
        u32 initval;            /* random jhash init value */
 #ifdef IP_SET_HASH_WITH_MARKMASK
@@ -288,21 +327,33 @@ struct htype {
 #ifdef IP_SET_HASH_WITH_NETMASK
        u8 netmask;             /* netmask value for subnets to store */
 #endif
+       struct list_head ad;    /* Resize add|del backlist */
        struct mtype_elem next; /* temporary storage for uadd */
 #ifdef IP_SET_HASH_WITH_NETS
        struct net_prefixes nets[NLEN]; /* book-keeping of prefixes */
 #endif
 };
 
+/* ADD|DEL entries saved during resize */
+struct mtype_resize_ad {
+       struct list_head list;
+       enum ipset_adt ad;      /* ADD|DEL element */
+       struct mtype_elem d;    /* Element value */
+       struct ip_set_ext ext;  /* Extensions for ADD */
+       struct ip_set_ext mext; /* Target extensions for ADD */
+       u32 flags;              /* Flags for ADD */
+};
+
 #ifdef IP_SET_HASH_WITH_NETS
 /* Network cidr size book keeping when the hash stores different
  * sized networks. cidr == real cidr + 1 to support /0.
  */
 static void
-mtype_add_cidr(struct htype *h, u8 cidr, u8 n)
+mtype_add_cidr(struct ip_set *set, struct htype *h, u8 cidr, u8 n)
 {
        int i, j;
 
+       spin_lock_bh(&set->lock);
        /* Add in increasing prefix order, so larger cidr first */
        for (i = 0, j = -1; i < NLEN && h->nets[i].cidr[n]; i++) {
                if (j != -1) {
@@ -311,7 +362,7 @@ mtype_add_cidr(struct htype *h, u8 cidr, u8 n)
                        j = i;
                } else if (h->nets[i].cidr[n] == cidr) {
                        h->nets[CIDR_POS(cidr)].nets[n]++;
-                       return;
+                       goto unlock;
                }
        }
        if (j != -1) {
@@ -320,24 +371,29 @@ mtype_add_cidr(struct htype *h, u8 cidr, u8 n)
        }
        h->nets[i].cidr[n] = cidr;
        h->nets[CIDR_POS(cidr)].nets[n] = 1;
+unlock:
+       spin_unlock_bh(&set->lock);
 }
 
 static void
-mtype_del_cidr(struct htype *h, u8 cidr, u8 n)
+mtype_del_cidr(struct ip_set *set, struct htype *h, u8 cidr, u8 n)
 {
        u8 i, j, net_end = NLEN - 1;
 
+       spin_lock_bh(&set->lock);
        for (i = 0; i < NLEN; i++) {
                if (h->nets[i].cidr[n] != cidr)
                        continue;
                h->nets[CIDR_POS(cidr)].nets[n]--;
                if (h->nets[CIDR_POS(cidr)].nets[n] > 0)
-                       return;
+                       goto unlock;
                for (j = i; j < net_end && h->nets[j].cidr[n]; j++)
                        h->nets[j].cidr[n] = h->nets[j + 1].cidr[n];
                h->nets[j].cidr[n] = 0;
-               return;
+               goto unlock;
        }
+unlock:
+       spin_unlock_bh(&set->lock);
 }
 #endif
 
@@ -345,7 +401,7 @@ mtype_del_cidr(struct htype *h, u8 cidr, u8 n)
 static size_t
 mtype_ahash_memsize(const struct htype *h, const struct htable *t)
 {
-       return sizeof(*h) + sizeof(*t);
+       return sizeof(*h) + sizeof(*t) + ahash_sizeof_regions(t->htable_bits);
 }
 
 /* Get the ith element from the array block n */
@@ -369,24 +425,29 @@ mtype_flush(struct ip_set *set)
        struct htype *h = set->data;
        struct htable *t;
        struct hbucket *n;
-       u32 i;
-
-       t = ipset_dereference_protected(h->table, set);
-       for (i = 0; i < jhash_size(t->htable_bits); i++) {
-               n = __ipset_dereference_protected(hbucket(t, i), 1);
-               if (!n)
-                       continue;
-               if (set->extensions & IPSET_EXT_DESTROY)
-                       mtype_ext_cleanup(set, n);
-               /* FIXME: use slab cache */
-               rcu_assign_pointer(hbucket(t, i), NULL);
-               kfree_rcu(n, rcu);
+       u32 r, i;
+
+       t = ipset_dereference_nfnl(h->table);
+       for (r = 0; r < ahash_numof_locks(t->htable_bits); r++) {
+               spin_lock_bh(&t->hregion[r].lock);
+               for (i = ahash_bucket_start(r, t->htable_bits);
+                    i < ahash_bucket_end(r, t->htable_bits); i++) {
+                       n = __ipset_dereference(hbucket(t, i));
+                       if (!n)
+                               continue;
+                       if (set->extensions & IPSET_EXT_DESTROY)
+                               mtype_ext_cleanup(set, n);
+                       /* FIXME: use slab cache */
+                       rcu_assign_pointer(hbucket(t, i), NULL);
+                       kfree_rcu(n, rcu);
+               }
+               t->hregion[r].ext_size = 0;
+               t->hregion[r].elements = 0;
+               spin_unlock_bh(&t->hregion[r].lock);
        }
 #ifdef IP_SET_HASH_WITH_NETS
        memset(h->nets, 0, sizeof(h->nets));
 #endif
-       set->elements = 0;
-       set->ext_size = 0;
 }
 
 /* Destroy the hashtable part of the set */
@@ -397,7 +458,7 @@ mtype_ahash_destroy(struct ip_set *set, struct htable *t, bool ext_destroy)
        u32 i;
 
        for (i = 0; i < jhash_size(t->htable_bits); i++) {
-               n = __ipset_dereference_protected(hbucket(t, i), 1);
+               n = __ipset_dereference(hbucket(t, i));
                if (!n)
                        continue;
                if (set->extensions & IPSET_EXT_DESTROY && ext_destroy)
@@ -406,6 +467,7 @@ mtype_ahash_destroy(struct ip_set *set, struct htable *t, bool ext_destroy)
                kfree(n);
        }
 
+       ip_set_free(t->hregion);
        ip_set_free(t);
 }
 
@@ -414,28 +476,21 @@ static void
 mtype_destroy(struct ip_set *set)
 {
        struct htype *h = set->data;
+       struct list_head *l, *lt;
 
        if (SET_WITH_TIMEOUT(set))
-               del_timer_sync(&h->gc);
+               cancel_delayed_work_sync(&h->gc.dwork);
 
-       mtype_ahash_destroy(set,
-                           __ipset_dereference_protected(h->table, 1), true);
+       mtype_ahash_destroy(set, ipset_dereference_nfnl(h->table), true);
+       list_for_each_safe(l, lt, &h->ad) {
+               list_del(l);
+               kfree(l);
+       }
        kfree(h);
 
        set->data = NULL;
 }
 
-static void
-mtype_gc_init(struct ip_set *set, void (*gc)(struct timer_list *t))
-{
-       struct htype *h = set->data;
-
-       timer_setup(&h->gc, gc, 0);
-       mod_timer(&h->gc, jiffies + IPSET_GC_PERIOD(set->timeout) * HZ);
-       pr_debug("gc initialized, run in every %u\n",
-                IPSET_GC_PERIOD(set->timeout));
-}
-
 static bool
 mtype_same_set(const struct ip_set *a, const struct ip_set *b)
 {
@@ -454,11 +509,9 @@ mtype_same_set(const struct ip_set *a, const struct ip_set *b)
               a->extensions == b->extensions;
 }
 
-/* Delete expired elements from the hashtable */
 static void
-mtype_expire(struct ip_set *set, struct htype *h)
+mtype_gc_do(struct ip_set *set, struct htype *h, struct htable *t, u32 r)
 {
-       struct htable *t;
        struct hbucket *n, *tmp;
        struct mtype_elem *data;
        u32 i, j, d;
@@ -466,10 +519,12 @@ mtype_expire(struct ip_set *set, struct htype *h)
 #ifdef IP_SET_HASH_WITH_NETS
        u8 k;
 #endif
+       u8 htable_bits = t->htable_bits;
 
-       t = ipset_dereference_protected(h->table, set);
-       for (i = 0; i < jhash_size(t->htable_bits); i++) {
-               n = __ipset_dereference_protected(hbucket(t, i), 1);
+       spin_lock_bh(&t->hregion[r].lock);
+       for (i = ahash_bucket_start(r, htable_bits);
+            i < ahash_bucket_end(r, htable_bits); i++) {
+               n = __ipset_dereference(hbucket(t, i));
                if (!n)
                        continue;
                for (j = 0, d = 0; j < n->pos; j++) {
@@ -485,58 +540,100 @@ mtype_expire(struct ip_set *set, struct htype *h)
                        smp_mb__after_atomic();
 #ifdef IP_SET_HASH_WITH_NETS
                        for (k = 0; k < IPSET_NET_COUNT; k++)
-                               mtype_del_cidr(h,
+                               mtype_del_cidr(set, h,
                                        NCIDR_PUT(DCIDR_GET(data->cidr, k)),
                                        k);
 #endif
+                       t->hregion[r].elements--;
                        ip_set_ext_destroy(set, data);
-                       set->elements--;
                        d++;
                }
                if (d >= AHASH_INIT_SIZE) {
                        if (d >= n->size) {
+                               t->hregion[r].ext_size -=
+                                       ext_size(n->size, dsize);
                                rcu_assign_pointer(hbucket(t, i), NULL);
                                kfree_rcu(n, rcu);
                                continue;
                        }
                        tmp = kzalloc(sizeof(*tmp) +
-                                     (n->size - AHASH_INIT_SIZE) * dsize,
-                                     GFP_ATOMIC);
+                               (n->size - AHASH_INIT_SIZE) * dsize,
+                               GFP_ATOMIC);
                        if (!tmp)
-                               /* Still try to delete expired elements */
+                               /* Still try to delete expired elements. */
                                continue;
                        tmp->size = n->size - AHASH_INIT_SIZE;
                        for (j = 0, d = 0; j < n->pos; j++) {
                                if (!test_bit(j, n->used))
                                        continue;
                                data = ahash_data(n, j, dsize);
-                               memcpy(tmp->value + d * dsize, data, dsize);
+                               memcpy(tmp->value + d * dsize,
+                                      data, dsize);
                                set_bit(d, tmp->used);
                                d++;
                        }
                        tmp->pos = d;
-                       set->ext_size -= ext_size(AHASH_INIT_SIZE, dsize);
+                       t->hregion[r].ext_size -=
+                               ext_size(AHASH_INIT_SIZE, dsize);
                        rcu_assign_pointer(hbucket(t, i), tmp);
                        kfree_rcu(n, rcu);
                }
        }
+       spin_unlock_bh(&t->hregion[r].lock);
 }
 
 static void
-mtype_gc(struct timer_list *t)
+mtype_gc(struct work_struct *work)
 {
-       struct htype *h = from_timer(h, t, gc);
-       struct ip_set *set = h->set;
+       struct htable_gc *gc;
+       struct ip_set *set;
+       struct htype *h;
+       struct htable *t;
+       u32 r, numof_locks;
+       unsigned int next_run;
+
+       gc = container_of(work, struct htable_gc, dwork.work);
+       set = gc->set;
+       h = set->data;
 
-       pr_debug("called\n");
        spin_lock_bh(&set->lock);
-       mtype_expire(set, h);
+       t = ipset_dereference_set(h->table, set);
+       atomic_inc(&t->uref);
+       numof_locks = ahash_numof_locks(t->htable_bits);
+       r = gc->region++;
+       if (r >= numof_locks) {
+               r = gc->region = 0;
+       }
+       next_run = (IPSET_GC_PERIOD(set->timeout) * HZ) / numof_locks;
+       if (next_run < HZ/10)
+               next_run = HZ/10;
        spin_unlock_bh(&set->lock);
 
-       h->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
-       add_timer(&h->gc);
+       mtype_gc_do(set, h, t, r);
+
+       if (atomic_dec_and_test(&t->uref) && atomic_read(&t->ref)) {
+               pr_debug("Table destroy after resize by expire: %p\n", t);
+               mtype_ahash_destroy(set, t, false);
+       }
+
+       queue_delayed_work(system_power_efficient_wq, &gc->dwork, next_run);
+
+}
+
+static void
+mtype_gc_init(struct htable_gc *gc)
+{
+       INIT_DEFERRABLE_WORK(&gc->dwork, mtype_gc);
+       queue_delayed_work(system_power_efficient_wq, &gc->dwork, HZ);
 }
 
+static int
+mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+         struct ip_set_ext *mext, u32 flags);
+static int
+mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+         struct ip_set_ext *mext, u32 flags);
+
 /* Resize a hash: create a new hash table with doubling the hashsize
  * and inserting the elements to it. Repeat until we succeed or
  * fail due to memory pressures.
@@ -547,7 +644,7 @@ mtype_resize(struct ip_set *set, bool retried)
        struct htype *h = set->data;
        struct htable *t, *orig;
        u8 htable_bits;
-       size_t extsize, dsize = set->dsize;
+       size_t dsize = set->dsize;
 #ifdef IP_SET_HASH_WITH_NETS
        u8 flags;
        struct mtype_elem *tmp;
@@ -555,7 +652,9 @@ mtype_resize(struct ip_set *set, bool retried)
        struct mtype_elem *data;
        struct mtype_elem *d;
        struct hbucket *n, *m;
-       u32 i, j, key;
+       struct list_head *l, *lt;
+       struct mtype_resize_ad *x;
+       u32 i, j, r, nr, key;
        int ret;
 
 #ifdef IP_SET_HASH_WITH_NETS
@@ -563,10 +662,8 @@ mtype_resize(struct ip_set *set, bool retried)
        if (!tmp)
                return -ENOMEM;
 #endif
-       rcu_read_lock_bh();
-       orig = rcu_dereference_bh_nfnl(h->table);
+       orig = ipset_dereference_bh_nfnl(h->table);
        htable_bits = orig->htable_bits;
-       rcu_read_unlock_bh();
 
 retry:
        ret = 0;
@@ -583,88 +680,124 @@ retry:
                ret = -ENOMEM;
                goto out;
        }
+       t->hregion = ip_set_alloc(ahash_sizeof_regions(htable_bits));
+       if (!t->hregion) {
+               kfree(t);
+               ret = -ENOMEM;
+               goto out;
+       }
        t->htable_bits = htable_bits;
+       t->maxelem = h->maxelem / ahash_numof_locks(htable_bits);
+       for (i = 0; i < ahash_numof_locks(htable_bits); i++)
+               spin_lock_init(&t->hregion[i].lock);
 
-       spin_lock_bh(&set->lock);
-       orig = __ipset_dereference_protected(h->table, 1);
-       /* There can't be another parallel resizing, but dumping is possible */
+       /* There can't be another parallel resizing,
+        * but dumping, gc, kernel side add/del are possible
+        */
+       orig = ipset_dereference_bh_nfnl(h->table);
        atomic_set(&orig->ref, 1);
        atomic_inc(&orig->uref);
-       extsize = 0;
        pr_debug("attempt to resize set %s from %u to %u, t %p\n",
                 set->name, orig->htable_bits, htable_bits, orig);
-       for (i = 0; i < jhash_size(orig->htable_bits); i++) {
-               n = __ipset_dereference_protected(hbucket(orig, i), 1);
-               if (!n)
-                       continue;
-               for (j = 0; j < n->pos; j++) {
-                       if (!test_bit(j, n->used))
+       for (r = 0; r < ahash_numof_locks(orig->htable_bits); r++) {
+               /* Expire may replace a hbucket with another one */
+               rcu_read_lock_bh();
+               for (i = ahash_bucket_start(r, orig->htable_bits);
+                    i < ahash_bucket_end(r, orig->htable_bits); i++) {
+                       n = __ipset_dereference(hbucket(orig, i));
+                       if (!n)
                                continue;
-                       data = ahash_data(n, j, dsize);
+                       for (j = 0; j < n->pos; j++) {
+                               if (!test_bit(j, n->used))
+                                       continue;
+                               data = ahash_data(n, j, dsize);
+                               if (SET_ELEM_EXPIRED(set, data))
+                                       continue;
 #ifdef IP_SET_HASH_WITH_NETS
-                       /* We have readers running parallel with us,
-                        * so the live data cannot be modified.
-                        */
-                       flags = 0;
-                       memcpy(tmp, data, dsize);
-                       data = tmp;
-                       mtype_data_reset_flags(data, &flags);
+                               /* We have readers running parallel with us,
+                                * so the live data cannot be modified.
+                                */
+                               flags = 0;
+                               memcpy(tmp, data, dsize);
+                               data = tmp;
+                               mtype_data_reset_flags(data, &flags);
 #endif
-                       key = HKEY(data, h->initval, htable_bits);
-                       m = __ipset_dereference_protected(hbucket(t, key), 1);
-                       if (!m) {
-                               m = kzalloc(sizeof(*m) +
+                               key = HKEY(data, h->initval, htable_bits);
+                               m = __ipset_dereference(hbucket(t, key));
+                               nr = ahash_region(key, htable_bits);
+                               if (!m) {
+                                       m = kzalloc(sizeof(*m) +
                                            AHASH_INIT_SIZE * dsize,
                                            GFP_ATOMIC);
-                               if (!m) {
-                                       ret = -ENOMEM;
-                                       goto cleanup;
-                               }
-                               m->size = AHASH_INIT_SIZE;
-                               extsize += ext_size(AHASH_INIT_SIZE, dsize);
-                               RCU_INIT_POINTER(hbucket(t, key), m);
-                       } else if (m->pos >= m->size) {
-                               struct hbucket *ht;
-
-                               if (m->size >= AHASH_MAX(h)) {
-                                       ret = -EAGAIN;
-                               } else {
-                                       ht = kzalloc(sizeof(*ht) +
+                                       if (!m) {
+                                               ret = -ENOMEM;
+                                               goto cleanup;
+                                       }
+                                       m->size = AHASH_INIT_SIZE;
+                                       t->hregion[nr].ext_size +=
+                                               ext_size(AHASH_INIT_SIZE,
+                                                        dsize);
+                                       RCU_INIT_POINTER(hbucket(t, key), m);
+                               } else if (m->pos >= m->size) {
+                                       struct hbucket *ht;
+
+                                       if (m->size >= AHASH_MAX(h)) {
+                                               ret = -EAGAIN;
+                                       } else {
+                                               ht = kzalloc(sizeof(*ht) +
                                                (m->size + AHASH_INIT_SIZE)
                                                * dsize,
                                                GFP_ATOMIC);
-                                       if (!ht)
-                                               ret = -ENOMEM;
+                                               if (!ht)
+                                                       ret = -ENOMEM;
+                                       }
+                                       if (ret < 0)
+                                               goto cleanup;
+                                       memcpy(ht, m, sizeof(struct hbucket) +
+                                              m->size * dsize);
+                                       ht->size = m->size + AHASH_INIT_SIZE;
+                                       t->hregion[nr].ext_size +=
+                                               ext_size(AHASH_INIT_SIZE,
+                                                        dsize);
+                                       kfree(m);
+                                       m = ht;
+                                       RCU_INIT_POINTER(hbucket(t, key), ht);
                                }
-                               if (ret < 0)
-                                       goto cleanup;
-                               memcpy(ht, m, sizeof(struct hbucket) +
-                                             m->size * dsize);
-                               ht->size = m->size + AHASH_INIT_SIZE;
-                               extsize += ext_size(AHASH_INIT_SIZE, dsize);
-                               kfree(m);
-                               m = ht;
-                               RCU_INIT_POINTER(hbucket(t, key), ht);
-                       }
-                       d = ahash_data(m, m->pos, dsize);
-                       memcpy(d, data, dsize);
-                       set_bit(m->pos++, m->used);
+                               d = ahash_data(m, m->pos, dsize);
+                               memcpy(d, data, dsize);
+                               set_bit(m->pos++, m->used);
+                               t->hregion[nr].elements++;
 #ifdef IP_SET_HASH_WITH_NETS
-                       mtype_data_reset_flags(d, &flags);
+                               mtype_data_reset_flags(d, &flags);
 #endif
+                       }
                }
+               rcu_read_unlock_bh();
        }
-       rcu_assign_pointer(h->table, t);
-       set->ext_size = extsize;
 
-       spin_unlock_bh(&set->lock);
+       /* There can't be any other writer. */
+       rcu_assign_pointer(h->table, t);
 
        /* Give time to other readers of the set */
        synchronize_rcu();
 
        pr_debug("set %s resized from %u (%p) to %u (%p)\n", set->name,
                 orig->htable_bits, orig, t->htable_bits, t);
-       /* If there's nobody else dumping the table, destroy it */
+       /* Add/delete elements processed by the SET target during resize.
+        * Kernel-side add cannot trigger a resize and userspace actions
+        * are serialized by the mutex.
+        */
+       list_for_each_safe(l, lt, &h->ad) {
+               x = list_entry(l, struct mtype_resize_ad, list);
+               if (x->ad == IPSET_ADD) {
+                       mtype_add(set, &x->d, &x->ext, &x->mext, x->flags);
+               } else {
+                       mtype_del(set, &x->d, NULL, NULL, 0);
+               }
+               list_del(l);
+               kfree(l);
+       }
+       /* If there's nobody else using the table, destroy it */
        if (atomic_dec_and_test(&orig->uref)) {
                pr_debug("Table destroy by resize %p\n", orig);
                mtype_ahash_destroy(set, orig, false);
@@ -677,15 +810,44 @@ out:
        return ret;
 
 cleanup:
+       rcu_read_unlock_bh();
        atomic_set(&orig->ref, 0);
        atomic_dec(&orig->uref);
-       spin_unlock_bh(&set->lock);
        mtype_ahash_destroy(set, t, false);
        if (ret == -EAGAIN)
                goto retry;
        goto out;
 }
 
+/* Get the current number of elements and ext_size in the set  */
+static void
+mtype_ext_size(struct ip_set *set, u32 *elements, size_t *ext_size)
+{
+       struct htype *h = set->data;
+       const struct htable *t;
+       u32 i, j, r;
+       struct hbucket *n;
+       struct mtype_elem *data;
+
+       t = rcu_dereference_bh(h->table);
+       for (r = 0; r < ahash_numof_locks(t->htable_bits); r++) {
+               for (i = ahash_bucket_start(r, t->htable_bits);
+                    i < ahash_bucket_end(r, t->htable_bits); i++) {
+                       n = rcu_dereference_bh(hbucket(t, i));
+                       if (!n)
+                               continue;
+                       for (j = 0; j < n->pos; j++) {
+                               if (!test_bit(j, n->used))
+                                       continue;
+                               data = ahash_data(n, j, set->dsize);
+                               if (!SET_ELEM_EXPIRED(set, data))
+                                       (*elements)++;
+                       }
+               }
+               *ext_size += t->hregion[r].ext_size;
+       }
+}
+
 /* Add an element to a hash and update the internal counters when succeeded,
  * otherwise report the proper error code.
  */
@@ -698,32 +860,49 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
        const struct mtype_elem *d = value;
        struct mtype_elem *data;
        struct hbucket *n, *old = ERR_PTR(-ENOENT);
-       int i, j = -1;
+       int i, j = -1, ret;
        bool flag_exist = flags & IPSET_FLAG_EXIST;
        bool deleted = false, forceadd = false, reuse = false;
-       u32 key, multi = 0;
+       u32 r, key, multi = 0, elements, maxelem;
 
-       if (set->elements >= h->maxelem) {
-               if (SET_WITH_TIMEOUT(set))
-                       /* FIXME: when set is full, we slow down here */
-                       mtype_expire(set, h);
-               if (set->elements >= h->maxelem && SET_WITH_FORCEADD(set))
+       rcu_read_lock_bh();
+       t = rcu_dereference_bh(h->table);
+       key = HKEY(value, h->initval, t->htable_bits);
+       r = ahash_region(key, t->htable_bits);
+       atomic_inc(&t->uref);
+       elements = t->hregion[r].elements;
+       maxelem = t->maxelem;
+       if (elements >= maxelem) {
+               u32 e;
+               if (SET_WITH_TIMEOUT(set)) {
+                       rcu_read_unlock_bh();
+                       mtype_gc_do(set, h, t, r);
+                       rcu_read_lock_bh();
+               }
+               maxelem = h->maxelem;
+               elements = 0;
+               for (e = 0; e < ahash_numof_locks(t->htable_bits); e++)
+                       elements += t->hregion[e].elements;
+               if (elements >= maxelem && SET_WITH_FORCEADD(set))
                        forceadd = true;
        }
+       rcu_read_unlock_bh();
 
-       t = ipset_dereference_protected(h->table, set);
-       key = HKEY(value, h->initval, t->htable_bits);
-       n = __ipset_dereference_protected(hbucket(t, key), 1);
+       spin_lock_bh(&t->hregion[r].lock);
+       n = rcu_dereference_bh(hbucket(t, key));
        if (!n) {
-               if (forceadd || set->elements >= h->maxelem)
+               if (forceadd || elements >= maxelem)
                        goto set_full;
                old = NULL;
                n = kzalloc(sizeof(*n) + AHASH_INIT_SIZE * set->dsize,
                            GFP_ATOMIC);
-               if (!n)
-                       return -ENOMEM;
+               if (!n) {
+                       ret = -ENOMEM;
+                       goto unlock;
+               }
                n->size = AHASH_INIT_SIZE;
-               set->ext_size += ext_size(AHASH_INIT_SIZE, set->dsize);
+               t->hregion[r].ext_size +=
+                       ext_size(AHASH_INIT_SIZE, set->dsize);
                goto copy_elem;
        }
        for (i = 0; i < n->pos; i++) {
@@ -737,38 +916,37 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
                }
                data = ahash_data(n, i, set->dsize);
                if (mtype_data_equal(data, d, &multi)) {
-                       if (flag_exist ||
-                           (SET_WITH_TIMEOUT(set) &&
-                            ip_set_timeout_expired(ext_timeout(data, set)))) {
+                       if (flag_exist || SET_ELEM_EXPIRED(set, data)) {
                                /* Just the extensions could be overwritten */
                                j = i;
                                goto overwrite_extensions;
                        }
-                       return -IPSET_ERR_EXIST;
+                       ret = -IPSET_ERR_EXIST;
+                       goto unlock;
                }
                /* Reuse first timed out entry */
-               if (SET_WITH_TIMEOUT(set) &&
-                   ip_set_timeout_expired(ext_timeout(data, set)) &&
-                   j == -1) {
+               if (SET_ELEM_EXPIRED(set, data) && j == -1) {
                        j = i;
                        reuse = true;
                }
        }
        if (reuse || forceadd) {
+               if (j == -1)
+                       j = 0;
                data = ahash_data(n, j, set->dsize);
                if (!deleted) {
 #ifdef IP_SET_HASH_WITH_NETS
                        for (i = 0; i < IPSET_NET_COUNT; i++)
-                               mtype_del_cidr(h,
+                               mtype_del_cidr(set, h,
                                        NCIDR_PUT(DCIDR_GET(data->cidr, i)),
                                        i);
 #endif
                        ip_set_ext_destroy(set, data);
-                       set->elements--;
+                       t->hregion[r].elements--;
                }
                goto copy_data;
        }
-       if (set->elements >= h->maxelem)
+       if (elements >= maxelem)
                goto set_full;
        /* Create a new slot */
        if (n->pos >= n->size) {
@@ -776,28 +954,32 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
                if (n->size >= AHASH_MAX(h)) {
                        /* Trigger rehashing */
                        mtype_data_next(&h->next, d);
-                       return -EAGAIN;
+                       ret = -EAGAIN;
+                       goto resize;
                }
                old = n;
                n = kzalloc(sizeof(*n) +
                            (old->size + AHASH_INIT_SIZE) * set->dsize,
                            GFP_ATOMIC);
-               if (!n)
-                       return -ENOMEM;
+               if (!n) {
+                       ret = -ENOMEM;
+                       goto unlock;
+               }
                memcpy(n, old, sizeof(struct hbucket) +
                       old->size * set->dsize);
                n->size = old->size + AHASH_INIT_SIZE;
-               set->ext_size += ext_size(AHASH_INIT_SIZE, set->dsize);
+               t->hregion[r].ext_size +=
+                       ext_size(AHASH_INIT_SIZE, set->dsize);
        }
 
 copy_elem:
        j = n->pos++;
        data = ahash_data(n, j, set->dsize);
 copy_data:
-       set->elements++;
+       t->hregion[r].elements++;
 #ifdef IP_SET_HASH_WITH_NETS
        for (i = 0; i < IPSET_NET_COUNT; i++)
-               mtype_add_cidr(h, NCIDR_PUT(DCIDR_GET(d->cidr, i)), i);
+               mtype_add_cidr(set, h, NCIDR_PUT(DCIDR_GET(d->cidr, i)), i);
 #endif
        memcpy(data, d, sizeof(struct mtype_elem));
 overwrite_extensions:
@@ -820,13 +1002,41 @@ overwrite_extensions:
                if (old)
                        kfree_rcu(old, rcu);
        }
+       ret = 0;
+resize:
+       spin_unlock_bh(&t->hregion[r].lock);
+       if (atomic_read(&t->ref) && ext->target) {
+               /* Resize is in process and kernel side add, save values */
+               struct mtype_resize_ad *x;
+
+               x = kzalloc(sizeof(struct mtype_resize_ad), GFP_ATOMIC);
+               if (!x)
+                       /* Don't bother */
+                       goto out;
+               x->ad = IPSET_ADD;
+               memcpy(&x->d, value, sizeof(struct mtype_elem));
+               memcpy(&x->ext, ext, sizeof(struct ip_set_ext));
+               memcpy(&x->mext, mext, sizeof(struct ip_set_ext));
+               x->flags = flags;
+               spin_lock_bh(&set->lock);
+               list_add_tail(&x->list, &h->ad);
+               spin_unlock_bh(&set->lock);
+       }
+       goto out;
 
-       return 0;
 set_full:
        if (net_ratelimit())
                pr_warn("Set %s is full, maxelem %u reached\n",
-                       set->name, h->maxelem);
-       return -IPSET_ERR_HASH_FULL;
+                       set->name, maxelem);
+       ret = -IPSET_ERR_HASH_FULL;
+unlock:
+       spin_unlock_bh(&t->hregion[r].lock);
+out:
+       if (atomic_dec_and_test(&t->uref) && atomic_read(&t->ref)) {
+               pr_debug("Table destroy after resize by add: %p\n", t);
+               mtype_ahash_destroy(set, t, false);
+       }
+       return ret;
 }
 
 /* Delete an element from the hash and free up space if possible.
@@ -840,13 +1050,23 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
        const struct mtype_elem *d = value;
        struct mtype_elem *data;
        struct hbucket *n;
-       int i, j, k, ret = -IPSET_ERR_EXIST;
+       struct mtype_resize_ad *x = NULL;
+       int i, j, k, r, ret = -IPSET_ERR_EXIST;
        u32 key, multi = 0;
        size_t dsize = set->dsize;
 
-       t = ipset_dereference_protected(h->table, set);
+       /* Userspace add and resize is excluded by the mutex.
+        * Kernespace add does not trigger resize.
+        */
+       rcu_read_lock_bh();
+       t = rcu_dereference_bh(h->table);
        key = HKEY(value, h->initval, t->htable_bits);
-       n = __ipset_dereference_protected(hbucket(t, key), 1);
+       r = ahash_region(key, t->htable_bits);
+       atomic_inc(&t->uref);
+       rcu_read_unlock_bh();
+
+       spin_lock_bh(&t->hregion[r].lock);
+       n = rcu_dereference_bh(hbucket(t, key));
        if (!n)
                goto out;
        for (i = 0, k = 0; i < n->pos; i++) {
@@ -857,8 +1077,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
                data = ahash_data(n, i, dsize);
                if (!mtype_data_equal(data, d, &multi))
                        continue;
-               if (SET_WITH_TIMEOUT(set) &&
-                   ip_set_timeout_expired(ext_timeout(data, set)))
+               if (SET_ELEM_EXPIRED(set, data))
                        goto out;
 
                ret = 0;
@@ -866,20 +1085,33 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
                smp_mb__after_atomic();
                if (i + 1 == n->pos)
                        n->pos--;
-               set->elements--;
+               t->hregion[r].elements--;
 #ifdef IP_SET_HASH_WITH_NETS
                for (j = 0; j < IPSET_NET_COUNT; j++)
-                       mtype_del_cidr(h, NCIDR_PUT(DCIDR_GET(d->cidr, j)),
-                                      j);
+                       mtype_del_cidr(set, h,
+                                      NCIDR_PUT(DCIDR_GET(d->cidr, j)), j);
 #endif
                ip_set_ext_destroy(set, data);
 
+               if (atomic_read(&t->ref) && ext->target) {
+                       /* Resize is in process and kernel side del,
+                        * save values
+                        */
+                       x = kzalloc(sizeof(struct mtype_resize_ad),
+                                   GFP_ATOMIC);
+                       if (x) {
+                               x->ad = IPSET_DEL;
+                               memcpy(&x->d, value,
+                                      sizeof(struct mtype_elem));
+                               x->flags = flags;
+                       }
+               }
                for (; i < n->pos; i++) {
                        if (!test_bit(i, n->used))
                                k++;
                }
                if (n->pos == 0 && k == 0) {
-                       set->ext_size -= ext_size(n->size, dsize);
+                       t->hregion[r].ext_size -= ext_size(n->size, dsize);
                        rcu_assign_pointer(hbucket(t, key), NULL);
                        kfree_rcu(n, rcu);
                } else if (k >= AHASH_INIT_SIZE) {
@@ -898,7 +1130,8 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
                                k++;
                        }
                        tmp->pos = k;
-                       set->ext_size -= ext_size(AHASH_INIT_SIZE, dsize);
+                       t->hregion[r].ext_size -=
+                               ext_size(AHASH_INIT_SIZE, dsize);
                        rcu_assign_pointer(hbucket(t, key), tmp);
                        kfree_rcu(n, rcu);
                }
@@ -906,6 +1139,16 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
        }
 
 out:
+       spin_unlock_bh(&t->hregion[r].lock);
+       if (x) {
+               spin_lock_bh(&set->lock);
+               list_add(&x->list, &h->ad);
+               spin_unlock_bh(&set->lock);
+       }
+       if (atomic_dec_and_test(&t->uref) && atomic_read(&t->ref)) {
+               pr_debug("Table destroy after resize by del: %p\n", t);
+               mtype_ahash_destroy(set, t, false);
+       }
        return ret;
 }
 
@@ -991,6 +1234,7 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
        int i, ret = 0;
        u32 key, multi = 0;
 
+       rcu_read_lock_bh();
        t = rcu_dereference_bh(h->table);
 #ifdef IP_SET_HASH_WITH_NETS
        /* If we test an IP address and not a network address,
@@ -1022,6 +1266,7 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
                        goto out;
        }
 out:
+       rcu_read_unlock_bh();
        return ret;
 }
 
@@ -1033,23 +1278,14 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
        const struct htable *t;
        struct nlattr *nested;
        size_t memsize;
+       u32 elements = 0;
+       size_t ext_size = 0;
        u8 htable_bits;
 
-       /* If any members have expired, set->elements will be wrong
-        * mytype_expire function will update it with the right count.
-        * we do not hold set->lock here, so grab it first.
-        * set->elements can still be incorrect in the case of a huge set,
-        * because elements might time out during the listing.
-        */
-       if (SET_WITH_TIMEOUT(set)) {
-               spin_lock_bh(&set->lock);
-               mtype_expire(set, h);
-               spin_unlock_bh(&set->lock);
-       }
-
        rcu_read_lock_bh();
-       t = rcu_dereference_bh_nfnl(h->table);
-       memsize = mtype_ahash_memsize(h, t) + set->ext_size;
+       t = rcu_dereference_bh(h->table);
+       mtype_ext_size(set, &elements, &ext_size);
+       memsize = mtype_ahash_memsize(h, t) + ext_size + set->ext_size;
        htable_bits = t->htable_bits;
        rcu_read_unlock_bh();
 
@@ -1071,7 +1307,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
 #endif
        if (nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref)) ||
            nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)) ||
-           nla_put_net32(skb, IPSET_ATTR_ELEMENTS, htonl(set->elements)))
+           nla_put_net32(skb, IPSET_ATTR_ELEMENTS, htonl(elements)))
                goto nla_put_failure;
        if (unlikely(ip_set_put_flags(skb, set)))
                goto nla_put_failure;
@@ -1091,15 +1327,15 @@ mtype_uref(struct ip_set *set, struct netlink_callback *cb, bool start)
 
        if (start) {
                rcu_read_lock_bh();
-               t = rcu_dereference_bh_nfnl(h->table);
+               t = ipset_dereference_bh_nfnl(h->table);
                atomic_inc(&t->uref);
                cb->args[IPSET_CB_PRIVATE] = (unsigned long)t;
                rcu_read_unlock_bh();
        } else if (cb->args[IPSET_CB_PRIVATE]) {
                t = (struct htable *)cb->args[IPSET_CB_PRIVATE];
                if (atomic_dec_and_test(&t->uref) && atomic_read(&t->ref)) {
-                       /* Resizing didn't destroy the hash table */
-                       pr_debug("Table destroy by dump: %p\n", t);
+                       pr_debug("Table destroy after resize "
+                                " by dump: %p\n", t);
                        mtype_ahash_destroy(set, t, false);
                }
                cb->args[IPSET_CB_PRIVATE] = 0;
@@ -1141,8 +1377,7 @@ mtype_list(const struct ip_set *set,
                        if (!test_bit(i, n->used))
                                continue;
                        e = ahash_data(n, i, set->dsize);
-                       if (SET_WITH_TIMEOUT(set) &&
-                           ip_set_timeout_expired(ext_timeout(e, set)))
+                       if (SET_ELEM_EXPIRED(set, e))
                                continue;
                        pr_debug("list hash %lu hbucket %p i %u, data %p\n",
                                 cb->args[IPSET_CB_ARG0], n, i, e);
@@ -1208,6 +1443,7 @@ static const struct ip_set_type_variant mtype_variant = {
        .uref   = mtype_uref,
        .resize = mtype_resize,
        .same_set = mtype_same_set,
+       .region_lock = true,
 };
 
 #ifdef IP_SET_EMIT_CREATE
@@ -1226,6 +1462,7 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
        size_t hsize;
        struct htype *h;
        struct htable *t;
+       u32 i;
 
        pr_debug("Create set %s with family %s\n",
                 set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6");
@@ -1294,6 +1531,15 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
                kfree(h);
                return -ENOMEM;
        }
+       t->hregion = ip_set_alloc(ahash_sizeof_regions(hbits));
+       if (!t->hregion) {
+               kfree(t);
+               kfree(h);
+               return -ENOMEM;
+       }
+       h->gc.set = set;
+       for (i = 0; i < ahash_numof_locks(hbits); i++)
+               spin_lock_init(&t->hregion[i].lock);
        h->maxelem = maxelem;
 #ifdef IP_SET_HASH_WITH_NETMASK
        h->netmask = netmask;
@@ -1304,9 +1550,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
        get_random_bytes(&h->initval, sizeof(h->initval));
 
        t->htable_bits = hbits;
+       t->maxelem = h->maxelem / ahash_numof_locks(hbits);
        RCU_INIT_POINTER(h->table, t);
 
-       h->set = set;
+       INIT_LIST_HEAD(&h->ad);
        set->data = h;
 #ifndef IP_SET_PROTO_UNDEF
        if (set->family == NFPROTO_IPV4) {
@@ -1329,12 +1576,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
 #ifndef IP_SET_PROTO_UNDEF
                if (set->family == NFPROTO_IPV4)
 #endif
-                       IPSET_TOKEN(HTYPE, 4_gc_init)(set,
-                               IPSET_TOKEN(HTYPE, 4_gc));
+                       IPSET_TOKEN(HTYPE, 4_gc_init)(&h->gc);
 #ifndef IP_SET_PROTO_UNDEF
                else
-                       IPSET_TOKEN(HTYPE, 6_gc_init)(set,
-                               IPSET_TOKEN(HTYPE, 6_gc));
+                       IPSET_TOKEN(HTYPE, 6_gc_init)(&h->gc);
 #endif
        }
        pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
index feac855..4fc0c92 100644 (file)
@@ -1766,11 +1766,13 @@ static bool pipapo_match_field(struct nft_pipapo_field *f,
 static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
                              const struct nft_set_elem *elem)
 {
-       const u8 *data = (const u8 *)elem->key.val.data;
        struct nft_pipapo *priv = nft_set_priv(set);
        struct nft_pipapo_match *m = priv->clone;
+       struct nft_pipapo_elem *e = elem->priv;
        int rules_f0, first_rule = 0;
-       struct nft_pipapo_elem *e;
+       const u8 *data;
+
+       data = (const u8 *)nft_set_ext_key(&e->ext);
 
        e = pipapo_get(net, set, data, 0);
        if (IS_ERR(e))
index 7a2c4b8..8c835ad 100644 (file)
@@ -402,15 +402,6 @@ static void htable_remove_proc_entry(struct xt_hashlimit_htable *hinfo)
                remove_proc_entry(hinfo->name, parent);
 }
 
-static void htable_destroy(struct xt_hashlimit_htable *hinfo)
-{
-       cancel_delayed_work_sync(&hinfo->gc_work);
-       htable_remove_proc_entry(hinfo);
-       htable_selective_cleanup(hinfo, true);
-       kfree(hinfo->name);
-       vfree(hinfo);
-}
-
 static struct xt_hashlimit_htable *htable_find_get(struct net *net,
                                                   const char *name,
                                                   u_int8_t family)
@@ -432,8 +423,13 @@ static void htable_put(struct xt_hashlimit_htable *hinfo)
 {
        if (refcount_dec_and_mutex_lock(&hinfo->use, &hashlimit_mutex)) {
                hlist_del(&hinfo->node);
+               htable_remove_proc_entry(hinfo);
                mutex_unlock(&hashlimit_mutex);
-               htable_destroy(hinfo);
+
+               cancel_delayed_work_sync(&hinfo->gc_work);
+               htable_selective_cleanup(hinfo, true);
+               kfree(hinfo->name);
+               vfree(hinfo);
        }
 }
 
index 0522b2b..9f357aa 100644 (file)
@@ -497,8 +497,9 @@ genl_family_rcv_msg_attrs_parse(const struct genl_family *family,
 
        err = __nlmsg_parse(nlh, hdrlen, attrbuf, family->maxattr,
                            family->policy, validate, extack);
-       if (err && parallel) {
-               kfree(attrbuf);
+       if (err) {
+               if (parallel)
+                       kfree(attrbuf);
                return ERR_PTR(err);
        }
        return attrbuf;
index 90a31b1..8c466a7 100644 (file)
@@ -186,6 +186,7 @@ static size_t tcf_action_shared_attrs_size(const struct tc_action *act)
                + nla_total_size(IFNAMSIZ) /* TCA_ACT_KIND */
                + cookie_len /* TCA_ACT_COOKIE */
                + nla_total_size(0) /* TCA_ACT_STATS nested */
+               + nla_total_size(sizeof(struct nla_bitfield32)) /* TCA_ACT_FLAGS */
                /* TCA_STATS_BASIC */
                + nla_total_size_64bit(sizeof(struct gnet_stats_basic))
                /* TCA_STATS_PKT64 */
index 90988a5..6fd44bd 100644 (file)
@@ -512,15 +512,18 @@ static int smc_connect_decline_fallback(struct smc_sock *smc, int reason_code)
 static int smc_connect_abort(struct smc_sock *smc, int reason_code,
                             int local_contact)
 {
+       bool is_smcd = smc->conn.lgr->is_smcd;
+
        if (local_contact == SMC_FIRST_CONTACT)
-               smc_lgr_forget(smc->conn.lgr);
-       if (smc->conn.lgr->is_smcd)
+               smc_lgr_cleanup_early(&smc->conn);
+       else
+               smc_conn_free(&smc->conn);
+       if (is_smcd)
                /* there is only one lgr role for SMC-D; use server lock */
                mutex_unlock(&smc_server_lgr_pending);
        else
                mutex_unlock(&smc_client_lgr_pending);
 
-       smc_conn_free(&smc->conn);
        smc->connect_nonblock = 0;
        return reason_code;
 }
@@ -1091,7 +1094,6 @@ static void smc_listen_out_err(struct smc_sock *new_smc)
        if (newsmcsk->sk_state == SMC_INIT)
                sock_put(&new_smc->sk); /* passive closing */
        newsmcsk->sk_state = SMC_CLOSED;
-       smc_conn_free(&new_smc->conn);
 
        smc_listen_out(new_smc);
 }
@@ -1102,12 +1104,13 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code,
 {
        /* RDMA setup failed, switch back to TCP */
        if (local_contact == SMC_FIRST_CONTACT)
-               smc_lgr_forget(new_smc->conn.lgr);
+               smc_lgr_cleanup_early(&new_smc->conn);
+       else
+               smc_conn_free(&new_smc->conn);
        if (reason_code < 0) { /* error, no fallback possible */
                smc_listen_out_err(new_smc);
                return;
        }
-       smc_conn_free(&new_smc->conn);
        smc_switch_to_fallback(new_smc);
        new_smc->fallback_rsn = reason_code;
        if (reason_code && reason_code != SMC_CLC_DECL_PEERDECL) {
@@ -1170,16 +1173,18 @@ static int smc_listen_ism_init(struct smc_sock *new_smc,
                            new_smc->conn.lgr->vlan_id,
                            new_smc->conn.lgr->smcd)) {
                if (ini->cln_first_contact == SMC_FIRST_CONTACT)
-                       smc_lgr_forget(new_smc->conn.lgr);
-               smc_conn_free(&new_smc->conn);
+                       smc_lgr_cleanup_early(&new_smc->conn);
+               else
+                       smc_conn_free(&new_smc->conn);
                return SMC_CLC_DECL_SMCDNOTALK;
        }
 
        /* Create send and receive buffers */
        if (smc_buf_create(new_smc, true)) {
                if (ini->cln_first_contact == SMC_FIRST_CONTACT)
-                       smc_lgr_forget(new_smc->conn.lgr);
-               smc_conn_free(&new_smc->conn);
+                       smc_lgr_cleanup_early(&new_smc->conn);
+               else
+                       smc_conn_free(&new_smc->conn);
                return SMC_CLC_DECL_MEM;
        }
 
index 2249de5..5b085ef 100644 (file)
@@ -162,6 +162,18 @@ static void smc_lgr_unregister_conn(struct smc_connection *conn)
        conn->lgr = NULL;
 }
 
+void smc_lgr_cleanup_early(struct smc_connection *conn)
+{
+       struct smc_link_group *lgr = conn->lgr;
+
+       if (!lgr)
+               return;
+
+       smc_conn_free(conn);
+       smc_lgr_forget(lgr);
+       smc_lgr_schedule_free_work_fast(lgr);
+}
+
 /* Send delete link, either as client to request the initiation
  * of the DELETE LINK sequence from server; or as server to
  * initiate the delete processing. See smc_llc_rx_delete_link().
index c472e12..234ae25 100644 (file)
@@ -296,6 +296,7 @@ struct smc_clc_msg_accept_confirm;
 struct smc_clc_msg_local;
 
 void smc_lgr_forget(struct smc_link_group *lgr);
+void smc_lgr_cleanup_early(struct smc_connection *conn);
 void smc_lgr_terminate(struct smc_link_group *lgr, bool soft);
 void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport);
 void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid,
@@ -316,7 +317,6 @@ int smc_vlan_by_tcpsk(struct socket *clcsock, struct smc_init_info *ini);
 
 void smc_conn_free(struct smc_connection *conn);
 int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini);
-void smcd_conn_free(struct smc_connection *conn);
 void smc_lgr_schedule_free_work_fast(struct smc_link_group *lgr);
 int smc_core_init(void);
 void smc_core_exit(void);
index 5486326..d6ba186 100644 (file)
@@ -573,6 +573,8 @@ static void smc_ib_remove_dev(struct ib_device *ibdev, void *client_data)
        struct smc_ib_device *smcibdev;
 
        smcibdev = ib_get_client_data(ibdev, &smc_ib_client);
+       if (!smcibdev || smcibdev->ibdev != ibdev)
+               return;
        ib_set_client_data(ibdev, &smc_ib_client, NULL);
        spin_lock(&smc_ib_devices.lock);
        list_del_init(&smcibdev->list); /* remove from smc_ib_devices */
index 62c12cb..68debcb 100644 (file)
@@ -682,6 +682,7 @@ static int unix_set_peek_off(struct sock *sk, int val)
        return 0;
 }
 
+#ifdef CONFIG_PROC_FS
 static void unix_show_fdinfo(struct seq_file *m, struct socket *sock)
 {
        struct sock *sk = sock->sk;
@@ -692,6 +693,9 @@ static void unix_show_fdinfo(struct seq_file *m, struct socket *sock)
                seq_printf(m, "scm_fds: %u\n", READ_ONCE(u->scm_stat.nr_fds));
        }
 }
+#else
+#define unix_show_fdinfo NULL
+#endif
 
 static const struct proto_ops unix_stream_ops = {
        .family =       PF_UNIX,
index 9c5b2a9..a5f2870 100644 (file)
@@ -451,6 +451,12 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
                if (vsk->transport == new_transport)
                        return 0;
 
+               /* transport->release() must be called with sock lock acquired.
+                * This path can only be taken during vsock_stream_connect(),
+                * where we have already held the sock lock.
+                * In the other cases, this function is called on a new socket
+                * which is not assigned to any transport.
+                */
                vsk->transport->release(vsk);
                vsock_deassign_transport(vsk);
        }
@@ -753,20 +759,18 @@ static void __vsock_release(struct sock *sk, int level)
                vsk = vsock_sk(sk);
                pending = NULL; /* Compiler warning. */
 
-               /* The release call is supposed to use lock_sock_nested()
-                * rather than lock_sock(), if a sock lock should be acquired.
-                */
-               if (vsk->transport)
-                       vsk->transport->release(vsk);
-               else if (sk->sk_type == SOCK_STREAM)
-                       vsock_remove_sock(vsk);
-
                /* When "level" is SINGLE_DEPTH_NESTING, use the nested
                 * version to avoid the warning "possible recursive locking
                 * detected". When "level" is 0, lock_sock_nested(sk, level)
                 * is the same as lock_sock(sk).
                 */
                lock_sock_nested(sk, level);
+
+               if (vsk->transport)
+                       vsk->transport->release(vsk);
+               else if (sk->sk_type == SOCK_STREAM)
+                       vsock_remove_sock(vsk);
+
                sock_orphan(sk);
                sk->sk_shutdown = SHUTDOWN_MASK;
 
index 3492c02..630b851 100644 (file)
@@ -526,12 +526,9 @@ static bool hvs_close_lock_held(struct vsock_sock *vsk)
 
 static void hvs_release(struct vsock_sock *vsk)
 {
-       struct sock *sk = sk_vsock(vsk);
        bool remove_sock;
 
-       lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
        remove_sock = hvs_close_lock_held(vsk);
-       release_sock(sk);
        if (remove_sock)
                vsock_remove_sock(vsk);
 }
index d9f0c9c..f3c4bab 100644 (file)
@@ -829,7 +829,6 @@ void virtio_transport_release(struct vsock_sock *vsk)
        struct sock *sk = &vsk->sk;
        bool remove_sock = true;
 
-       lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
        if (sk->sk_type == SOCK_STREAM)
                remove_sock = virtio_transport_close(vsk);
 
@@ -837,7 +836,6 @@ void virtio_transport_release(struct vsock_sock *vsk)
                list_del(&pkt->list);
                virtio_transport_free_pkt(pkt);
        }
-       release_sock(sk);
 
        if (remove_sock)
                vsock_remove_sock(vsk);
index cedf17d..5b19e9f 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/netlink.h>
 #include <linux/nospec.h>
 #include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
 #include <net/net_namespace.h>
 #include <net/genetlink.h>
 #include <net/cfg80211.h>
@@ -4800,8 +4801,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
                err = nl80211_parse_he_obss_pd(
                                        info->attrs[NL80211_ATTR_HE_OBSS_PD],
                                        &params.he_obss_pd);
-               if (err)
-                       return err;
+               goto out;
        }
 
        nl80211_calculate_ap_params(&params);
@@ -4823,6 +4823,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        }
        wdev_unlock(wdev);
 
+out:
        kfree(params.acl);
 
        return err;
index fff9a74..1a8218f 100644 (file)
@@ -2276,7 +2276,7 @@ static void handle_channel_custom(struct wiphy *wiphy,
                        break;
        }
 
-       if (IS_ERR(reg_rule)) {
+       if (IS_ERR_OR_NULL(reg_rule)) {
                pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n",
                         chan->center_freq);
                if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
index bae6254..752ff0a 100644 (file)
@@ -300,15 +300,15 @@ DT_BINDING_DIR := Documentation/devicetree/bindings
 DT_TMP_SCHEMA := $(objtree)/$(DT_BINDING_DIR)/processed-schema.yaml
 
 quiet_cmd_dtb_check =  CHECK   $@
-      cmd_dtb_check =  $(DT_CHECKER) -u $(srctree)/$(DT_BINDING_DIR) -p $(DT_TMP_SCHEMA) $@ ;
+      cmd_dtb_check =  $(DT_CHECKER) -u $(srctree)/$(DT_BINDING_DIR) -p $(DT_TMP_SCHEMA) $@
 
-define rule_dtc_dt_yaml
+define rule_dtc
        $(call cmd_and_fixdep,dtc,yaml)
        $(call cmd,dtb_check)
 endef
 
 $(obj)/%.dt.yaml: $(src)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE
-       $(call if_changed_rule,dtc_dt_yaml)
+       $(call if_changed_rule,dtc)
 
 dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
 
old mode 100644 (file)
new mode 100755 (executable)
index 9f60a50..5bf1ea1 100644 (file)
@@ -649,8 +649,6 @@ snd_sgio2audio_pcm_pointer(struct snd_pcm_substream *substream)
 static const struct snd_pcm_ops snd_sgio2audio_playback1_ops = {
        .open =        snd_sgio2audio_playback1_open,
        .close =       snd_sgio2audio_pcm_close,
-       .hw_params =   snd_sgio2audio_pcm_hw_params,
-       .hw_free =     snd_sgio2audio_pcm_hw_free,
        .prepare =     snd_sgio2audio_pcm_prepare,
        .trigger =     snd_sgio2audio_pcm_trigger,
        .pointer =     snd_sgio2audio_pcm_pointer,
@@ -659,8 +657,6 @@ static const struct snd_pcm_ops snd_sgio2audio_playback1_ops = {
 static const struct snd_pcm_ops snd_sgio2audio_playback2_ops = {
        .open =        snd_sgio2audio_playback2_open,
        .close =       snd_sgio2audio_pcm_close,
-       .hw_params =   snd_sgio2audio_pcm_hw_params,
-       .hw_free =     snd_sgio2audio_pcm_hw_free,
        .prepare =     snd_sgio2audio_pcm_prepare,
        .trigger =     snd_sgio2audio_pcm_trigger,
        .pointer =     snd_sgio2audio_pcm_pointer,
@@ -669,8 +665,6 @@ static const struct snd_pcm_ops snd_sgio2audio_playback2_ops = {
 static const struct snd_pcm_ops snd_sgio2audio_capture_ops = {
        .open =        snd_sgio2audio_capture_open,
        .close =       snd_sgio2audio_pcm_close,
-       .hw_params =   snd_sgio2audio_pcm_hw_params,
-       .hw_free =     snd_sgio2audio_pcm_hw_free,
        .prepare =     snd_sgio2audio_pcm_prepare,
        .trigger =     snd_sgio2audio_pcm_trigger,
        .pointer =     snd_sgio2audio_pcm_pointer,
index 477589e..0ac06ff 100644 (file)
@@ -2447,6 +2447,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
        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_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950),
@@ -5920,7 +5921,8 @@ enum {
        ALC289_FIXUP_DUAL_SPK,
        ALC294_FIXUP_SPK2_TO_DAC1,
        ALC294_FIXUP_ASUS_DUAL_SPK,
-
+       ALC285_FIXUP_THINKPAD_HEADSET_JACK,
+       ALC294_FIXUP_ASUS_HPE,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -6684,6 +6686,8 @@ static const struct hda_fixup alc269_fixups[] = {
        [ALC285_FIXUP_SPEAKER2_TO_DAC1] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc285_fixup_speaker2_to_dac1,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
        },
        [ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = {
                .type = HDA_FIXUP_PINS,
@@ -7040,7 +7044,23 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC294_FIXUP_SPK2_TO_DAC1
        },
-
+       [ALC285_FIXUP_THINKPAD_HEADSET_JACK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_jack,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_SPEAKER2_TO_DAC1
+       },
+       [ALC294_FIXUP_ASUS_HPE] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Set EAPD high */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x0f },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x7774 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -7115,6 +7135,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0935, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
        SND_PCI_QUIRK(0x1028, 0x097e, "Dell Precision", ALC289_FIXUP_DUAL_SPK),
        SND_PCI_QUIRK(0x1028, 0x097d, "Dell Precision", ALC289_FIXUP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x098d, "Dell Precision", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x09bf, "Dell Precision", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -7204,6 +7226,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK),
        SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x19ce, "ASUS B9450FA", ALC294_FIXUP_ASUS_HPE),
        SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
        SND_PCI_QUIRK(0x1043, 0x1a30, "ASUS X705UD", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
@@ -7274,8 +7297,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Yoga 7th", ALC285_FIXUP_SPEAKER2_TO_DAC1),
-       SND_PCI_QUIRK(0x17aa, 0x2293, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_SPEAKER2_TO_DAC1),
+       SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Yoga 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
+       SND_PCI_QUIRK(0x17aa, 0x2293, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
        SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
index 7e90f5d..ea91243 100644 (file)
@@ -1406,7 +1406,7 @@ config SND_SOC_WM8737
        depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8741
-       tristate "Wolfson Microelectronics WM8737 DAC"
+       tristate "Wolfson Microelectronics WM8741 DAC"
        depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8750
index 861210f..4cbef9a 100644 (file)
@@ -1564,13 +1564,15 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
        }
 
        pcm512x->sclk = devm_clk_get(dev, NULL);
-       if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER)
-               return -EPROBE_DEFER;
+       if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) {
+               ret = -EPROBE_DEFER;
+               goto err;
+       }
        if (!IS_ERR(pcm512x->sclk)) {
                ret = clk_prepare_enable(pcm512x->sclk);
                if (ret != 0) {
                        dev_err(dev, "Failed to enable SCLK: %d\n", ret);
-                       return ret;
+                       goto err;
                }
        }
 
index 6d490e2..66eb55b 100644 (file)
@@ -664,7 +664,7 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream,
        snd_soc_component_update_bits(component, RT1015_TDM_MASTER,
                RT1015_I2S_DL_MASK, val_len);
        snd_soc_component_update_bits(component, RT1015_CLK2,
-               RT1015_FS_PD_MASK, pre_div);
+               RT1015_FS_PD_MASK, pre_div << RT1015_FS_PD_SFT);
 
        return 0;
 }
@@ -857,6 +857,7 @@ struct snd_soc_dai_driver rt1015_dai[] = {
                        .rates = RT1015_STEREO_RATES,
                        .formats = RT1015_FORMATS,
                },
+               .ops = &rt1015_aif_dai_ops,
        }
 };
 
index 729acd8..be52886 100644 (file)
@@ -215,7 +215,8 @@ static int tas2562_set_bitwidth(struct tas2562_data *tas2562, int bitwidth)
                break;
 
        default:
-               dev_info(tas2562->dev, "Not supported params format\n");
+               dev_info(tas2562->dev, "Unsupported bitwidth format\n");
+               return -EINVAL;
        }
 
        ret = snd_soc_component_update_bits(tas2562->component,
@@ -251,7 +252,7 @@ static int tas2562_hw_params(struct snd_pcm_substream *substream,
 
        ret = tas2562_set_samplerate(tas2562, params_rate(params));
        if (ret)
-               dev_err(tas2562->dev, "set bitwidth failed, %d\n", ret);
+               dev_err(tas2562->dev, "set sample rate failed, %d\n", ret);
 
        return ret;
 }
index 3466675..a15aa2f 100644 (file)
@@ -34,8 +34,8 @@ static ssize_t skl_print_pins(struct skl_module_pin *m_pin, char *buf,
        int i;
        ssize_t ret = 0;
 
-       for (i = 0; i < max_pin; i++)
-               ret += snprintf(buf + size, MOD_BUF - size,
+       for (i = 0; i < max_pin; i++) {
+               ret += scnprintf(buf + size, MOD_BUF - size,
                                "%s %d\n\tModule %d\n\tInstance %d\n\t"
                                "In-used %s\n\tType %s\n"
                                "\tState %d\n\tIndex %d\n",
@@ -45,13 +45,15 @@ static ssize_t skl_print_pins(struct skl_module_pin *m_pin, char *buf,
                                m_pin[i].in_use ? "Used" : "Unused",
                                m_pin[i].is_dynamic ? "Dynamic" : "Static",
                                m_pin[i].pin_state, i);
+               size += ret;
+       }
        return ret;
 }
 
 static ssize_t skl_print_fmt(struct skl_module_fmt *fmt, char *buf,
                                        ssize_t size, bool direction)
 {
-       return snprintf(buf + size, MOD_BUF - size,
+       return scnprintf(buf + size, MOD_BUF - size,
                        "%s\n\tCh %d\n\tFreq %d\n\tBit depth %d\n\t"
                        "Valid bit depth %d\n\tCh config %#x\n\tInterleaving %d\n\t"
                        "Sample Type %d\n\tCh Map %#x\n",
@@ -75,16 +77,16 @@ static ssize_t module_read(struct file *file, char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
-       ret = snprintf(buf, MOD_BUF, "Module:\n\tUUID %pUL\n\tModule id %d\n"
+       ret = scnprintf(buf, MOD_BUF, "Module:\n\tUUID %pUL\n\tModule id %d\n"
                        "\tInstance id %d\n\tPvt_id %d\n", mconfig->guid,
                        mconfig->id.module_id, mconfig->id.instance_id,
                        mconfig->id.pvt_id);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "Resources:\n\tCPC %#x\n\tIBS %#x\n\tOBS %#x\t\n",
                        res->cpc, res->ibs, res->obs);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "Module data:\n\tCore %d\n\tIn queue %d\n\t"
                        "Out queue %d\n\tType %s\n",
                        mconfig->core_id, mconfig->max_in_queue,
@@ -94,38 +96,38 @@ static ssize_t module_read(struct file *file, char __user *user_buf,
        ret += skl_print_fmt(mconfig->in_fmt, buf, ret, true);
        ret += skl_print_fmt(mconfig->out_fmt, buf, ret, false);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "Fixup:\n\tParams %#x\n\tConverter %#x\n",
                        mconfig->params_fixup, mconfig->converter);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "Module Gateway:\n\tType %#x\n\tVbus %#x\n\tHW conn %#x\n\tSlot %#x\n",
                        mconfig->dev_type, mconfig->vbus_id,
                        mconfig->hw_conn_type, mconfig->time_slot);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "Pipeline:\n\tID %d\n\tPriority %d\n\tConn Type %d\n\t"
                        "Pages %#x\n", mconfig->pipe->ppl_id,
                        mconfig->pipe->pipe_priority, mconfig->pipe->conn_type,
                        mconfig->pipe->memory_pages);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "\tParams:\n\t\tHost DMA %d\n\t\tLink DMA %d\n",
                        mconfig->pipe->p_params->host_dma_id,
                        mconfig->pipe->p_params->link_dma_id);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "\tPCM params:\n\t\tCh %d\n\t\tFreq %d\n\t\tFormat %d\n",
                        mconfig->pipe->p_params->ch,
                        mconfig->pipe->p_params->s_freq,
                        mconfig->pipe->p_params->s_fmt);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "\tLink %#x\n\tStream %#x\n",
                        mconfig->pipe->p_params->linktype,
                        mconfig->pipe->p_params->stream);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "\tState %d\n\tPassthru %s\n",
                        mconfig->pipe->state,
                        mconfig->pipe->passthru ? "true" : "false");
@@ -135,7 +137,7 @@ static ssize_t module_read(struct file *file, char __user *user_buf,
        ret += skl_print_pins(mconfig->m_out_pin, buf,
                        mconfig->max_out_queue, ret, false);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "Other:\n\tDomain %d\n\tHomogeneous Input %s\n\t"
                        "Homogeneous Output %s\n\tIn Queue Mask %d\n\t"
                        "Out Queue Mask %d\n\tDMA ID %d\n\tMem Pages %d\n\t"
@@ -191,7 +193,7 @@ static ssize_t fw_softreg_read(struct file *file, char __user *user_buf,
                __ioread32_copy(d->fw_read_buff, fw_reg_addr, w0_stat_sz >> 2);
 
        for (offset = 0; offset < FW_REG_SIZE; offset += 16) {
-               ret += snprintf(tmp + ret, FW_REG_BUF - ret, "%#.4x: ", offset);
+               ret += scnprintf(tmp + ret, FW_REG_BUF - ret, "%#.4x: ", offset);
                hex_dump_to_buffer(d->fw_read_buff + offset, 16, 16, 4,
                                   tmp + ret, FW_REG_BUF - ret, 0);
                ret += strlen(tmp + ret);
index 1c0e522..bd43885 100644 (file)
@@ -384,9 +384,11 @@ static int skl_clk_dev_probe(struct platform_device *pdev)
                                &clks[i], clk_pdata, i);
 
                if (IS_ERR(data->clk[data->avail_clk_cnt])) {
-                       ret = PTR_ERR(data->clk[data->avail_clk_cnt++]);
+                       ret = PTR_ERR(data->clk[data->avail_clk_cnt]);
                        goto err_unreg_skl_clk;
                }
+
+               data->avail_clk_cnt++;
        }
 
        platform_set_drvdata(pdev, data);
index 9cfbd34..8a0db28 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <sound/pcm_params.h>
 #include <linux/regmap.h>
+#include <linux/reset.h>
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
 
@@ -378,6 +379,11 @@ static int g12a_tohdmitx_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        void __iomem *regs;
        struct regmap *map;
+       int ret;
+
+       ret = device_reset(dev);
+       if (ret)
+               return ret;
 
        regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(regs))
index 14e175c..785a038 100644 (file)
@@ -451,7 +451,7 @@ int snd_soc_pcm_component_sync_stop(struct snd_pcm_substream *substream)
        int i, ret;
 
        for_each_rtd_components(rtd, i, component) {
-               if (component->driver->ioctl) {
+               if (component->driver->sync_stop) {
                        ret = component->driver->sync_stop(component,
                                                           substream);
                        if (ret < 0)
index 223cd04..392a1c5 100644 (file)
@@ -299,7 +299,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
        for_each_dpcm_be(fe, stream, dpcm)
                dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
 
-       snd_soc_dapm_stream_stop(fe, stream);
+       dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
 
        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
index 9b13056..9fb54e6 100644 (file)
@@ -4772,7 +4772,7 @@ static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
                        continue;
                if (w->power) {
                        dapm_seq_insert(w, &down_list, false);
-                       w->power = 0;
+                       w->new_power = 0;
                        powerdown = 1;
                }
        }
index ff1b7c7..2c59b36 100644 (file)
@@ -2006,7 +2006,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
        soc_pcm_close(substream);
 
        /* run the stream event for each BE */
-       snd_soc_dapm_stream_stop(fe, stream);
+       dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
 
        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
        dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
@@ -3171,16 +3171,16 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
        unsigned long flags;
 
        /* FE state */
-       offset += snprintf(buf + offset, size - offset,
+       offset += scnprintf(buf + offset, size - offset,
                        "[%s - %s]\n", fe->dai_link->name,
                        stream ? "Capture" : "Playback");
 
-       offset += snprintf(buf + offset, size - offset, "State: %s\n",
+       offset += scnprintf(buf + offset, size - offset, "State: %s\n",
                        dpcm_state_string(fe->dpcm[stream].state));
 
        if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
            (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
-               offset += snprintf(buf + offset, size - offset,
+               offset += scnprintf(buf + offset, size - offset,
                                "Hardware Params: "
                                "Format = %s, Channels = %d, Rate = %d\n",
                                snd_pcm_format_name(params_format(params)),
@@ -3188,10 +3188,10 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
                                params_rate(params));
 
        /* BEs state */
-       offset += snprintf(buf + offset, size - offset, "Backends:\n");
+       offset += scnprintf(buf + offset, size - offset, "Backends:\n");
 
        if (list_empty(&fe->dpcm[stream].be_clients)) {
-               offset += snprintf(buf + offset, size - offset,
+               offset += scnprintf(buf + offset, size - offset,
                                " No active DSP links\n");
                goto out;
        }
@@ -3201,16 +3201,16 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
                struct snd_soc_pcm_runtime *be = dpcm->be;
                params = &dpcm->hw_params;
 
-               offset += snprintf(buf + offset, size - offset,
+               offset += scnprintf(buf + offset, size - offset,
                                "- %s\n", be->dai_link->name);
 
-               offset += snprintf(buf + offset, size - offset,
+               offset += scnprintf(buf + offset, size - offset,
                                "   State: %s\n",
                                dpcm_state_string(be->dpcm[stream].state));
 
                if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
                    (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
-                       offset += snprintf(buf + offset, size - offset,
+                       offset += scnprintf(buf + offset, size - offset,
                                "   Hardware Params: "
                                "Format = %s, Channels = %d, Rate = %d\n",
                                snd_pcm_format_name(params_format(params)),
index d2ee6ad..575da6a 100644 (file)
@@ -2377,8 +2377,11 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg,
                }
 
                ret = soc_tplg_link_config(tplg, _link);
-               if (ret < 0)
+               if (ret < 0) {
+                       if (!abi_match)
+                               kfree(_link);
                        return ret;
+               }
 
                /* offset by version-specific struct size and
                 * real priv data size
@@ -2542,7 +2545,7 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg,
 {
        struct snd_soc_tplg_manifest *manifest, *_manifest;
        bool abi_match;
-       int err;
+       int ret = 0;
 
        if (tplg->pass != SOC_TPLG_PASS_MANIFEST)
                return 0;
@@ -2555,19 +2558,19 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg,
                _manifest = manifest;
        } else {
                abi_match = false;
-               err = manifest_new_ver(tplg, manifest, &_manifest);
-               if (err < 0)
-                       return err;
+               ret = manifest_new_ver(tplg, manifest, &_manifest);
+               if (ret < 0)
+                       return ret;
        }
 
        /* pass control to component driver for optional further init */
        if (tplg->comp && tplg->ops && tplg->ops->manifest)
-               return tplg->ops->manifest(tplg->comp, tplg->index, _manifest);
+               ret = tplg->ops->manifest(tplg->comp, tplg->index, _manifest);
 
        if (!abi_match) /* free the duplicated one */
                kfree(_manifest);
 
-       return 0;
+       return ret;
 }
 
 /* validate header magic, size and type */
index b63fc52..78aa1da 100644 (file)
@@ -499,7 +499,7 @@ int snd_sof_ipc_stream_posn(struct snd_soc_component *scomp,
 
        /* send IPC to the DSP */
        err = sof_ipc_tx_message(sdev->ipc,
-                                stream.hdr.cmd, &stream, sizeof(stream), &posn,
+                                stream.hdr.cmd, &stream, sizeof(stream), posn,
                                 sizeof(*posn));
        if (err < 0) {
                dev_err(sdev->dev, "error: failed to get stream %d position\n",
index 30bcd5d..10eb4b8 100644 (file)
@@ -1543,20 +1543,20 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = devm_snd_soc_register_component(&pdev->dev, &stm32_component,
-                                             &sai->cpu_dai_drv, 1);
+       ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register pcm dma\n");
+               return ret;
+       }
+
+       ret = snd_soc_register_component(&pdev->dev, &stm32_component,
+                                        &sai->cpu_dai_drv, 1);
        if (ret)
                return ret;
 
        if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
                conf = &stm32_sai_pcm_config_spdif;
 
-       ret = devm_snd_dmaengine_pcm_register(&pdev->dev, conf, 0);
-       if (ret) {
-               dev_err(&pdev->dev, "Could not register pcm dma\n");
-               return ret;
-       }
-
        return 0;
 }
 
@@ -1565,6 +1565,8 @@ static int stm32_sai_sub_remove(struct platform_device *pdev)
        struct stm32_sai_sub_data *sai = dev_get_drvdata(&pdev->dev);
 
        clk_unprepare(sai->pdata->pclk);
+       snd_dmaengine_pcm_unregister(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        return 0;
 }
index ebe1685..d5e517d 100644 (file)
 #define MSR_K7_HWCR                    0xc0010015
 #define MSR_K7_HWCR_SMMLOCK_BIT                0
 #define MSR_K7_HWCR_SMMLOCK            BIT_ULL(MSR_K7_HWCR_SMMLOCK_BIT)
+#define MSR_K7_HWCR_IRPERF_EN_BIT      30
+#define MSR_K7_HWCR_IRPERF_EN          BIT_ULL(MSR_K7_HWCR_IRPERF_EN_BIT)
 #define MSR_K7_FID_VID_CTL             0xc0010041
 #define MSR_K7_FID_VID_STATUS          0xc0010042
 
index 503d3f4..3f3f780 100644 (file)
@@ -390,6 +390,7 @@ struct kvm_sync_regs {
 #define KVM_STATE_NESTED_GUEST_MODE    0x00000001
 #define KVM_STATE_NESTED_RUN_PENDING   0x00000002
 #define KVM_STATE_NESTED_EVMCS         0x00000004
+#define KVM_STATE_NESTED_MTF_PENDING   0x00000008
 
 #define KVM_STATE_NESTED_SMM_GUEST_MODE        0x00000001
 #define KVM_STATE_NESTED_SMM_VMXON     0x00000002
index e978a63..036e667 100644 (file)
@@ -4,10 +4,7 @@
 
 #include <stdio.h>
 
-/* controllable printf */
-extern int pr_output;
-#define printk(fmt, ...)       \
-       (pr_output ? printf(fmt, ##__VA_ARGS__) : 0)
+#define printk(fmt, ...) printf(fmt, ##__VA_ARGS__)
 
 #define pr_err printk
 #define pr_warn        printk
index e18eeb0..a9b9781 100644 (file)
@@ -14,8 +14,6 @@
 #include <linux/kernel.h>
 #include <linux/bootconfig.h>
 
-int pr_output = 1;
-
 static int xbc_show_array(struct xbc_node *node)
 {
        const char *val;
@@ -131,15 +129,26 @@ int load_xbc_from_initrd(int fd, char **buf)
        struct stat stat;
        int ret;
        u32 size = 0, csum = 0, rcsum;
+       char magic[BOOTCONFIG_MAGIC_LEN];
 
        ret = fstat(fd, &stat);
        if (ret < 0)
                return -errno;
 
-       if (stat.st_size < 8)
+       if (stat.st_size < 8 + BOOTCONFIG_MAGIC_LEN)
+               return 0;
+
+       if (lseek(fd, -BOOTCONFIG_MAGIC_LEN, SEEK_END) < 0) {
+               pr_err("Failed to lseek: %d\n", -errno);
+               return -errno;
+       }
+       if (read(fd, magic, BOOTCONFIG_MAGIC_LEN) < 0)
+               return -errno;
+       /* Check the bootconfig magic bytes */
+       if (memcmp(magic, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN) != 0)
                return 0;
 
-       if (lseek(fd, -8, SEEK_END) < 0) {
+       if (lseek(fd, -(8 + BOOTCONFIG_MAGIC_LEN), SEEK_END) < 0) {
                pr_err("Failed to lseek: %d\n", -errno);
                return -errno;
        }
@@ -150,11 +159,14 @@ int load_xbc_from_initrd(int fd, char **buf)
        if (read(fd, &csum, sizeof(u32)) < 0)
                return -errno;
 
-       /* Wrong size, maybe no boot config here */
-       if (stat.st_size < size + 8)
-               return 0;
+       /* Wrong size error  */
+       if (stat.st_size < size + 8 + BOOTCONFIG_MAGIC_LEN) {
+               pr_err("bootconfig size is too big\n");
+               return -E2BIG;
+       }
 
-       if (lseek(fd, stat.st_size - 8 - size, SEEK_SET) < 0) {
+       if (lseek(fd, stat.st_size - (size + 8 + BOOTCONFIG_MAGIC_LEN),
+                 SEEK_SET) < 0) {
                pr_err("Failed to lseek: %d\n", -errno);
                return -errno;
        }
@@ -163,17 +175,17 @@ int load_xbc_from_initrd(int fd, char **buf)
        if (ret < 0)
                return ret;
 
-       /* Wrong Checksum, maybe no boot config here */
+       /* Wrong Checksum */
        rcsum = checksum((unsigned char *)*buf, size);
        if (csum != rcsum) {
                pr_err("checksum error: %d != %d\n", csum, rcsum);
-               return 0;
+               return -EINVAL;
        }
 
        ret = xbc_init(*buf);
-       /* Wrong data, maybe no boot config here */
+       /* Wrong data */
        if (ret < 0)
-               return 0;
+               return ret;
 
        return size;
 }
@@ -213,20 +225,15 @@ int delete_xbc(const char *path)
                return -errno;
        }
 
-       /*
-        * Suppress error messages in xbc_init() because it can be just a
-        * data which concidentally matches the size and checksum footer.
-        */
-       pr_output = 0;
        size = load_xbc_from_initrd(fd, &buf);
-       pr_output = 1;
        if (size < 0) {
                ret = size;
                pr_err("Failed to load a boot config from initrd: %d\n", ret);
        } else if (size > 0) {
                ret = fstat(fd, &stat);
                if (!ret)
-                       ret = ftruncate(fd, stat.st_size - size - 8);
+                       ret = ftruncate(fd, stat.st_size
+                                       - size - 8 - BOOTCONFIG_MAGIC_LEN);
                if (ret)
                        ret = -errno;
        } /* Ignore if there is no boot config in initrd */
@@ -295,6 +302,12 @@ int apply_xbc(const char *path, const char *xbc_path)
                pr_err("Failed to apply a boot config: %d\n", ret);
                return ret;
        }
+       /* Write a magic word of the bootconfig */
+       ret = write(fd, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN);
+       if (ret < 0) {
+               pr_err("Failed to apply a boot config magic: %d\n", ret);
+               return ret;
+       }
        close(fd);
        free(data);
 
diff --git a/tools/bootconfig/samples/bad-mixed-kv1.bconf b/tools/bootconfig/samples/bad-mixed-kv1.bconf
new file mode 100644 (file)
index 0000000..1761547
--- /dev/null
@@ -0,0 +1,3 @@
+# value -> subkey pattern
+key = value
+key.subkey = another-value
diff --git a/tools/bootconfig/samples/bad-mixed-kv2.bconf b/tools/bootconfig/samples/bad-mixed-kv2.bconf
new file mode 100644 (file)
index 0000000..6b32e0c
--- /dev/null
@@ -0,0 +1,3 @@
+# subkey -> value pattern
+key.subkey = value
+key = another-value
diff --git a/tools/bootconfig/samples/bad-samekey.bconf b/tools/bootconfig/samples/bad-samekey.bconf
new file mode 100644 (file)
index 0000000..e8d983a
--- /dev/null
@@ -0,0 +1,6 @@
+# Same key value is not allowed
+key {
+       foo = value
+       bar = value2
+}
+key.foo = value
index 1de06de..1411f4c 100755 (executable)
@@ -9,7 +9,7 @@ TEMPCONF=`mktemp temp-XXXX.bconf`
 NG=0
 
 cleanup() {
-  rm -f $INITRD $TEMPCONF
+  rm -f $INITRD $TEMPCONF $OUTFILE
   exit $NG
 }
 
@@ -49,7 +49,7 @@ xpass $BOOTCONF -a $TEMPCONF $INITRD
 new_size=$(stat -c %s $INITRD)
 
 echo "File size check"
-xpass test $new_size -eq $(expr $bconf_size + $initrd_size + 9)
+xpass test $new_size -eq $(expr $bconf_size + $initrd_size + 9 + 12)
 
 echo "Apply command repeat test"
 xpass $BOOTCONF -a $TEMPCONF $INITRD
@@ -71,7 +71,6 @@ printf " \0\0\0 \0\0\0" >> $INITRD
 $BOOTCONF -a $TEMPCONF $INITRD > $OUTFILE 2>&1
 xfail grep -i "failed" $OUTFILE
 xfail grep -i "error" $OUTFILE
-rm $OUTFILE
 
 echo "Max node number check"
 
@@ -96,6 +95,19 @@ truncate -s 32764 $TEMPCONF
 echo "\"" >> $TEMPCONF # add 2 bytes + terminal ('\"\n\0')
 xpass $BOOTCONF -a $TEMPCONF $INITRD
 
+echo "Adding same-key values"
+cat > $TEMPCONF << EOF
+key = bar, baz
+key += qux
+EOF
+echo > $INITRD
+
+xpass $BOOTCONF -a $TEMPCONF $INITRD
+$BOOTCONF $INITRD > $OUTFILE
+xpass grep -q "bar" $OUTFILE
+xpass grep -q "baz" $OUTFILE
+xpass grep -q "qux" $OUTFILE
+
 echo "=== expected failure cases ==="
 for i in samples/bad-* ; do
   xfail $BOOTCONF -a $i $INITRD
index c4dd23c..8ead555 100644 (file)
@@ -239,7 +239,6 @@ buildid.*::
                set buildid.dir to /dev/null. The default is $HOME/.debug
 
 annotate.*::
-       These options work only for TUI.
        These are in control of addresses, jump function, source code
        in lines of assembly code from a specific program.
 
@@ -269,6 +268,8 @@ annotate.*::
                â”‚        mov    (%rdi),%rdx
                â”‚              return n;
 
+               This option works with tui, stdio2 browsers.
+
         annotate.use_offset::
                Basing on a first address of a loaded function, offset can be used.
                Instead of using original addresses of assembly code,
@@ -287,6 +288,8 @@ annotate.*::
 
                             368:│  mov    0x8(%r14),%rdi
 
+               This option works with tui, stdio2 browsers.
+
        annotate.jump_arrows::
                There can be jump instruction among assembly code.
                Depending on a boolean value of jump_arrows,
@@ -306,6 +309,8 @@ annotate.*::
                â”‚1330:   mov    %r15,%r10
                â”‚1333:   cmp    %r15,%r14
 
+               This option works with tui browser.
+
         annotate.show_linenr::
                When showing source code if this option is 'true',
                line numbers are printed as below.
@@ -325,6 +330,8 @@ annotate.*::
                â”‚                     array++;
                â”‚             }
 
+               This option works with tui, stdio2 browsers.
+
         annotate.show_nr_jumps::
                Let's see a part of assembly code.
 
@@ -335,6 +342,8 @@ annotate.*::
 
                â”‚1 1382:   movb   $0x1,-0x270(%rbp)
 
+               This option works with tui, stdio2 browsers.
+
         annotate.show_total_period::
                To compare two records on an instruction base, with this option
                provided, display total number of samples that belong to a line
@@ -348,11 +357,30 @@ annotate.*::
 
                99.93 â”‚      mov    %eax,%eax
 
+               This option works with tui, stdio2, stdio browsers.
+
+       annotate.show_nr_samples::
+               By default perf annotate shows percentage of samples. This option
+               can be used to print absolute number of samples. Ex, when set as
+               false:
+
+               Percent│
+                74.03 â”‚      mov    %fs:0x28,%rax
+
+               When set as true:
+
+               Samples│
+                    6 â”‚      mov    %fs:0x28,%rax
+
+               This option works with tui, stdio2, stdio browsers.
+
        annotate.offset_level::
                Default is '1', meaning just jump targets will have offsets show right beside
                the instruction. When set to '2' 'call' instructions will also have its offsets
                shown, 3 or higher will show offsets for all instructions.
 
+               This option works with tui, stdio2 browsers.
+
 hist.*::
        hist.percentage::
                This option control the way to calculate overhead of filtered entries -
@@ -490,6 +518,12 @@ top.*::
                column by default.
                The default is 'true'.
 
+       top.call-graph::
+               This is identical to 'call-graph.record-mode', except it is
+               applicable only for 'top' subcommand. This option ONLY setup
+               the unwind method. To enable 'perf top' to actually use it,
+               the command line option -g must be specified.
+
 man.*::
        man.viewer::
                This option can assign a tool to view manual pages when 'help'
@@ -517,6 +551,16 @@ record.*::
                But if this option is 'no-cache', it will not update the build-id cache.
                'skip' skips post-processing and does not update the cache.
 
+       record.call-graph::
+               This is identical to 'call-graph.record-mode', except it is
+               applicable only for 'record' subcommand. This option ONLY setup
+               the unwind method. To enable 'perf record' to actually use it,
+               the command line option -g must be specified.
+
+       record.aio::
+               Use 'n' control blocks in asynchronous (Posix AIO) trace writing
+               mode ('n' default: 1, max: 4).
+
 diff.*::
        diff.order::
                This option sets the number of columns to sort the result.
@@ -566,6 +610,11 @@ trace.*::
                "libbeauty", the default, to use the same argument beautifiers used in the
                strace-like sys_enter+sys_exit lines.
 
+ftrace.*::
+       ftrace.tracer::
+               Can be used to select the default tracer. Possible values are
+               'function' and 'function_graph'.
+
 llvm.*::
        llvm.clang-path::
                Path to clang. If omit, search it from $PATH.
@@ -610,6 +659,29 @@ scripts.*::
        The script gets the same options passed as a full perf script,
        in particular -i perfdata file, --cpu, --tid
 
+convert.*::
+
+       convert.queue-size::
+               Limit the size of ordered_events queue, so we could control
+               allocation size of perf data files without proper finished
+               round events.
+
+intel-pt.*::
+
+       intel-pt.cache-divisor::
+
+       intel-pt.mispred-all::
+               If set, Intel PT decoder will set the mispred flag on all
+               branches.
+
+auxtrace.*::
+
+       auxtrace.dumpdir::
+               s390 only. The directory to save the auxiliary trace buffer
+               can be changed using this option. Ex, auxtrace.dumpdir=/tmp.
+               If the directory does not exist or has the wrong file type,
+               the current directory is used.
+
 SEE ALSO
 --------
 linkperf:perf[1]
index 2898cfd..941f814 100644 (file)
@@ -858,21 +858,6 @@ static void cs_etm_recording_free(struct auxtrace_record *itr)
        free(ptr);
 }
 
-static int cs_etm_read_finish(struct auxtrace_record *itr, int idx)
-{
-       struct cs_etm_recording *ptr =
-                       container_of(itr, struct cs_etm_recording, itr);
-       struct evsel *evsel;
-
-       evlist__for_each_entry(ptr->evlist, evsel) {
-               if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
-                       return perf_evlist__enable_event_idx(ptr->evlist,
-                                                            evsel, idx);
-       }
-
-       return -EINVAL;
-}
-
 struct auxtrace_record *cs_etm_record_init(int *err)
 {
        struct perf_pmu *cs_etm_pmu;
@@ -892,6 +877,7 @@ struct auxtrace_record *cs_etm_record_init(int *err)
        }
 
        ptr->cs_etm_pmu                 = cs_etm_pmu;
+       ptr->itr.pmu                    = cs_etm_pmu;
        ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options;
        ptr->itr.recording_options      = cs_etm_recording_options;
        ptr->itr.info_priv_size         = cs_etm_info_priv_size;
@@ -901,7 +887,7 @@ struct auxtrace_record *cs_etm_record_init(int *err)
        ptr->itr.snapshot_finish        = cs_etm_snapshot_finish;
        ptr->itr.reference              = cs_etm_reference;
        ptr->itr.free                   = cs_etm_recording_free;
-       ptr->itr.read_finish            = cs_etm_read_finish;
+       ptr->itr.read_finish            = auxtrace_record__read_finish;
 
        *err = 0;
        return &ptr->itr;
index eba6541..8d6821d 100644 (file)
@@ -158,20 +158,6 @@ static void arm_spe_recording_free(struct auxtrace_record *itr)
        free(sper);
 }
 
-static int arm_spe_read_finish(struct auxtrace_record *itr, int idx)
-{
-       struct arm_spe_recording *sper =
-                       container_of(itr, struct arm_spe_recording, itr);
-       struct evsel *evsel;
-
-       evlist__for_each_entry(sper->evlist, evsel) {
-               if (evsel->core.attr.type == sper->arm_spe_pmu->type)
-                       return perf_evlist__enable_event_idx(sper->evlist,
-                                                            evsel, idx);
-       }
-       return -EINVAL;
-}
-
 struct auxtrace_record *arm_spe_recording_init(int *err,
                                               struct perf_pmu *arm_spe_pmu)
 {
@@ -189,12 +175,13 @@ struct auxtrace_record *arm_spe_recording_init(int *err,
        }
 
        sper->arm_spe_pmu = arm_spe_pmu;
+       sper->itr.pmu = arm_spe_pmu;
        sper->itr.recording_options = arm_spe_recording_options;
        sper->itr.info_priv_size = arm_spe_info_priv_size;
        sper->itr.info_fill = arm_spe_info_fill;
        sper->itr.free = arm_spe_recording_free;
        sper->itr.reference = arm_spe_reference;
-       sper->itr.read_finish = arm_spe_read_finish;
+       sper->itr.read_finish = auxtrace_record__read_finish;
        sper->itr.alignment = 0;
 
        *err = 0;
index 43f736e..35b61bf 100644 (file)
 433    common  fspick                          sys_fspick
 434    common  pidfd_open                      sys_pidfd_open
 435    nospu   clone3                          ppc_clone3
+437    common  openat2                         sys_openat2
+438    common  pidfd_getfd                     sys_pidfd_getfd
index 27d9e21..26cee10 100644 (file)
@@ -413,20 +413,6 @@ out_err:
        return err;
 }
 
-static int intel_bts_read_finish(struct auxtrace_record *itr, int idx)
-{
-       struct intel_bts_recording *btsr =
-                       container_of(itr, struct intel_bts_recording, itr);
-       struct evsel *evsel;
-
-       evlist__for_each_entry(btsr->evlist, evsel) {
-               if (evsel->core.attr.type == btsr->intel_bts_pmu->type)
-                       return perf_evlist__enable_event_idx(btsr->evlist,
-                                                            evsel, idx);
-       }
-       return -EINVAL;
-}
-
 struct auxtrace_record *intel_bts_recording_init(int *err)
 {
        struct perf_pmu *intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME);
@@ -447,6 +433,7 @@ struct auxtrace_record *intel_bts_recording_init(int *err)
        }
 
        btsr->intel_bts_pmu = intel_bts_pmu;
+       btsr->itr.pmu = intel_bts_pmu;
        btsr->itr.recording_options = intel_bts_recording_options;
        btsr->itr.info_priv_size = intel_bts_info_priv_size;
        btsr->itr.info_fill = intel_bts_info_fill;
@@ -456,7 +443,7 @@ struct auxtrace_record *intel_bts_recording_init(int *err)
        btsr->itr.find_snapshot = intel_bts_find_snapshot;
        btsr->itr.parse_snapshot_options = intel_bts_parse_snapshot_options;
        btsr->itr.reference = intel_bts_reference;
-       btsr->itr.read_finish = intel_bts_read_finish;
+       btsr->itr.read_finish = auxtrace_record__read_finish;
        btsr->itr.alignment = sizeof(struct branch);
        return &btsr->itr;
 }
index 20df442..7eea4fd 100644 (file)
@@ -1166,20 +1166,6 @@ static u64 intel_pt_reference(struct auxtrace_record *itr __maybe_unused)
        return rdtsc();
 }
 
-static int intel_pt_read_finish(struct auxtrace_record *itr, int idx)
-{
-       struct intel_pt_recording *ptr =
-                       container_of(itr, struct intel_pt_recording, itr);
-       struct evsel *evsel;
-
-       evlist__for_each_entry(ptr->evlist, evsel) {
-               if (evsel->core.attr.type == ptr->intel_pt_pmu->type)
-                       return perf_evlist__enable_event_idx(ptr->evlist, evsel,
-                                                            idx);
-       }
-       return -EINVAL;
-}
-
 struct auxtrace_record *intel_pt_recording_init(int *err)
 {
        struct perf_pmu *intel_pt_pmu = perf_pmu__find(INTEL_PT_PMU_NAME);
@@ -1200,6 +1186,7 @@ struct auxtrace_record *intel_pt_recording_init(int *err)
        }
 
        ptr->intel_pt_pmu = intel_pt_pmu;
+       ptr->itr.pmu = intel_pt_pmu;
        ptr->itr.recording_options = intel_pt_recording_options;
        ptr->itr.info_priv_size = intel_pt_info_priv_size;
        ptr->itr.info_fill = intel_pt_info_fill;
@@ -1209,7 +1196,7 @@ struct auxtrace_record *intel_pt_recording_init(int *err)
        ptr->itr.find_snapshot = intel_pt_find_snapshot;
        ptr->itr.parse_snapshot_options = intel_pt_parse_snapshot_options;
        ptr->itr.reference = intel_pt_reference;
-       ptr->itr.read_finish = intel_pt_read_finish;
+       ptr->itr.read_finish = auxtrace_record__read_finish;
        /*
         * Decoding starts at a PSB packet. Minimum PSB period is 2K so 4K
         * should give at least 1 PSB per sample.
index ff61795..6c0a041 100644 (file)
@@ -566,6 +566,8 @@ int cmd_annotate(int argc, const char **argv)
        if (ret < 0)
                return ret;
 
+       annotation_config__init(&annotate.opts);
+
        argc = parse_options(argc, argv, options, annotate_usage, 0);
        if (argc) {
                /*
@@ -605,8 +607,6 @@ int cmd_annotate(int argc, const char **argv)
        if (ret < 0)
                goto out_delete;
 
-       annotation_config__init();
-
        symbol_conf.try_vmlinux_path = true;
 
        ret = symbol__init(&annotate.session->header.env);
index 26bc592..70548df 100644 (file)
@@ -449,7 +449,8 @@ static int perf_del_probe_events(struct strfilter *filter)
                ret = probe_file__del_strlist(kfd, klist);
                if (ret < 0)
                        goto error;
-       }
+       } else if (ret == -ENOMEM)
+               goto error;
 
        ret2 = probe_file__get_events(ufd, filter, ulist);
        if (ret2 == 0) {
@@ -459,7 +460,8 @@ static int perf_del_probe_events(struct strfilter *filter)
                ret2 = probe_file__del_strlist(ufd, ulist);
                if (ret2 < 0)
                        goto error;
-       }
+       } else if (ret2 == -ENOMEM)
+               goto error;
 
        if (ret == -ENOENT && ret2 == -ENOENT)
                pr_warning("\"%s\" does not hit any event.\n", str);
index 9483b3f..72a12b6 100644 (file)
@@ -1507,7 +1507,7 @@ repeat:
                        symbol_conf.priv_size += sizeof(u32);
                        symbol_conf.sort_by_name = true;
                }
-               annotation_config__init();
+               annotation_config__init(&report.annotation_opts);
        }
 
        if (symbol__init(&session->header.env) < 0)
index 8affcab..f6dd1a6 100644 (file)
@@ -143,7 +143,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
                return err;
        }
 
-       err = symbol__annotate(&he->ms, evsel, 0, &top->annotation_opts, NULL);
+       err = symbol__annotate(&he->ms, evsel, &top->annotation_opts, NULL);
        if (err == 0) {
                top->sym_filter_entry = he;
        } else {
@@ -1683,7 +1683,7 @@ int cmd_top(int argc, const char **argv)
        if (status < 0)
                goto out_delete_evlist;
 
-       annotation_config__init();
+       annotation_config__init(&top.annotation_opts);
 
        symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
        status = symbol__init(NULL);
index 607189a..6e61c4b 100644 (file)
@@ -3,7 +3,7 @@
 #ifndef _PERF_BPF_PID_FILTER_
 #define _PERF_BPF_PID_FILTER_
 
-#include <bpf/bpf.h>
+#include <bpf.h>
 
 #define pid_filter(name) pid_map(name, bool)
 
index 7ca6fa5..316af5b 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 
-#include <bpf/bpf.h>
+#include <bpf.h>
 
 struct bpf_map SEC("maps") __bpf_stdout__ = {
        .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
index d1a35b6..ca7877f 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: LGPL-2.1
 
-#include <bpf/bpf.h>
+#include <bpf.h>
 
 static int (*bpf_get_current_pid_tgid)(void) = (void *)BPF_FUNC_get_current_pid_tgid;
 
index 7cb99b4..c2cc42d 100644 (file)
@@ -14,7 +14,7 @@ add_probe_vfs_getname() {
        if [ $had_vfs_getname -eq 1 ] ; then
                line=$(perf probe -L getname_flags 2>&1 | egrep 'result.*=.*filename;' | sed -r 's/[[:space:]]+([[:digit:]]+)[[:space:]]+result->uptr.*/\1/')
                perf probe -q       "vfs_getname=getname_flags:${line} pathname=result->name:string" || \
-               perf probe $verbose "vfs_getname=getname_flags:${line} pathname=filename:string"
+               perf probe $verbose "vfs_getname=getname_flags:${line} pathname=filename:ustring"
        fi
 }
 
index badbddb..9023267 100644 (file)
@@ -754,10 +754,9 @@ static int annotate_browser__run(struct annotate_browser *browser,
                "?             Search string backwards\n");
                        continue;
                case 'r':
-                       {
-                               script_browse(NULL, NULL);
-                               continue;
-                       }
+                       script_browse(NULL, NULL);
+                       annotate_browser__show(&browser->b, title, help);
+                       continue;
                case 'k':
                        notes->options->show_linenr = !notes->options->show_linenr;
                        break;
@@ -834,13 +833,13 @@ show_sup_ins:
                        map_symbol__annotation_dump(ms, evsel, browser->opts);
                        continue;
                case 't':
-                       if (notes->options->show_total_period) {
-                               notes->options->show_total_period = false;
-                               notes->options->show_nr_samples = true;
-                       } else if (notes->options->show_nr_samples)
-                               notes->options->show_nr_samples = false;
+                       if (symbol_conf.show_total_period) {
+                               symbol_conf.show_total_period = false;
+                               symbol_conf.show_nr_samples = true;
+                       } else if (symbol_conf.show_nr_samples)
+                               symbol_conf.show_nr_samples = false;
                        else
-                               notes->options->show_total_period = true;
+                               symbol_conf.show_total_period = true;
                        annotation__update_column_widths(notes);
                        continue;
                case 'c':
index 22cc240..35f9641 100644 (file)
@@ -174,7 +174,7 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel,
        if (ms->map->dso->annotate_warned)
                return -1;
 
-       err = symbol__annotate(ms, evsel, 0, &annotation__default_options, NULL);
+       err = symbol__annotate(ms, evsel, &annotation__default_options, NULL);
        if (err) {
                char msg[BUFSIZ];
                symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
index ca73fb7..0ea95be 100644 (file)
@@ -1143,93 +1143,70 @@ out:
 }
 
 struct annotate_args {
-       size_t                   privsize;
-       struct arch             *arch;
-       struct map_symbol        ms;
-       struct evsel    *evsel;
+       struct arch               *arch;
+       struct map_symbol         ms;
+       struct evsel              *evsel;
        struct annotation_options *options;
-       s64                      offset;
-       char                    *line;
-       int                      line_nr;
+       s64                       offset;
+       char                      *line;
+       int                       line_nr;
 };
 
-static void annotation_line__delete(struct annotation_line *al)
+static void annotation_line__init(struct annotation_line *al,
+                                 struct annotate_args *args,
+                                 int nr)
 {
-       void *ptr = (void *) al - al->privsize;
+       al->offset = args->offset;
+       al->line = strdup(args->line);
+       al->line_nr = args->line_nr;
+       al->data_nr = nr;
+}
 
+static void annotation_line__exit(struct annotation_line *al)
+{
        free_srcline(al->path);
        zfree(&al->line);
-       free(ptr);
 }
 
-/*
- * Allocating the annotation line data with following
- * structure:
- *
- *    --------------------------------------
- *    private space | struct annotation_line
- *    --------------------------------------
- *
- * Size of the private space is stored in 'struct annotation_line'.
- *
- */
-static struct annotation_line *
-annotation_line__new(struct annotate_args *args, size_t privsize)
+static size_t disasm_line_size(int nr)
 {
        struct annotation_line *al;
-       struct evsel *evsel = args->evsel;
-       size_t size = privsize + sizeof(*al);
-       int nr = 1;
-
-       if (perf_evsel__is_group_event(evsel))
-               nr = evsel->core.nr_members;
 
-       size += sizeof(al->data[0]) * nr;
-
-       al = zalloc(size);
-       if (al) {
-               al = (void *) al + privsize;
-               al->privsize   = privsize;
-               al->offset     = args->offset;
-               al->line       = strdup(args->line);
-               al->line_nr    = args->line_nr;
-               al->data_nr    = nr;
-       }
-
-       return al;
+       return (sizeof(struct disasm_line) + (sizeof(al->data[0]) * nr));
 }
 
 /*
  * Allocating the disasm annotation line data with
  * following structure:
  *
- *    ------------------------------------------------------------
- *    privsize space | struct disasm_line | struct annotation_line
- *    ------------------------------------------------------------
+ *    -------------------------------------------
+ *    struct disasm_line | struct annotation_line
+ *    -------------------------------------------
  *
  * We have 'struct annotation_line' member as last member
  * of 'struct disasm_line' to have an easy access.
- *
  */
 static struct disasm_line *disasm_line__new(struct annotate_args *args)
 {
        struct disasm_line *dl = NULL;
-       struct annotation_line *al;
-       size_t privsize = args->privsize + offsetof(struct disasm_line, al);
+       int nr = 1;
 
-       al = annotation_line__new(args, privsize);
-       if (al != NULL) {
-               dl = disasm_line(al);
+       if (perf_evsel__is_group_event(args->evsel))
+               nr = args->evsel->core.nr_members;
 
-               if (dl->al.line == NULL)
-                       goto out_delete;
+       dl = zalloc(disasm_line_size(nr));
+       if (!dl)
+               return NULL;
 
-               if (args->offset != -1) {
-                       if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0)
-                               goto out_free_line;
+       annotation_line__init(&dl->al, args, nr);
+       if (dl->al.line == NULL)
+               goto out_delete;
 
-                       disasm_line__init_ins(dl, args->arch, &args->ms);
-               }
+       if (args->offset != -1) {
+               if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0)
+                       goto out_free_line;
+
+               disasm_line__init_ins(dl, args->arch, &args->ms);
        }
 
        return dl;
@@ -1248,7 +1225,8 @@ void disasm_line__free(struct disasm_line *dl)
        else
                ins__delete(&dl->ops);
        zfree(&dl->ins.name);
-       annotation_line__delete(&dl->al);
+       annotation_line__exit(&dl->al);
+       free(dl);
 }
 
 int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name)
@@ -2149,13 +2127,12 @@ void symbol__calc_percent(struct symbol *sym, struct evsel *evsel)
        annotation__calc_percent(notes, evsel, symbol__size(sym));
 }
 
-int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, size_t privsize,
+int symbol__annotate(struct map_symbol *ms, struct evsel *evsel,
                     struct annotation_options *options, struct arch **parch)
 {
        struct symbol *sym = ms->sym;
        struct annotation *notes = symbol__annotation(sym);
        struct annotate_args args = {
-               .privsize       = privsize,
                .evsel          = evsel,
                .options        = options,
        };
@@ -2644,6 +2621,8 @@ void annotation__set_offsets(struct annotation *notes, s64 size)
        struct annotation_line *al;
 
        notes->max_line_len = 0;
+       notes->nr_entries = 0;
+       notes->nr_asm_entries = 0;
 
        list_for_each_entry(al, &notes->src->source, node) {
                size_t line_len = strlen(al->line);
@@ -2790,7 +2769,7 @@ int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel,
        struct symbol *sym = ms->sym;
        struct rb_root source_line = RB_ROOT;
 
-       if (symbol__annotate(ms, evsel, 0, opts, NULL) < 0)
+       if (symbol__annotate(ms, evsel, opts, NULL) < 0)
                return -1;
 
        symbol__calc_percent(sym, evsel);
@@ -2915,9 +2894,9 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
                        percent = annotation_data__percent(&al->data[i], percent_type);
 
                        obj__set_percent_color(obj, percent, current_entry);
-                       if (notes->options->show_total_period) {
+                       if (symbol_conf.show_total_period) {
                                obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period);
-                       } else if (notes->options->show_nr_samples) {
+                       } else if (symbol_conf.show_nr_samples) {
                                obj__printf(obj, "%6" PRIu64 " ",
                                                   al->data[i].he.nr_samples);
                        } else {
@@ -2931,8 +2910,8 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
                        obj__printf(obj, "%-*s", pcnt_width, " ");
                else {
                        obj__printf(obj, "%-*s", pcnt_width,
-                                          notes->options->show_total_period ? "Period" :
-                                          notes->options->show_nr_samples ? "Samples" : "Percent");
+                                          symbol_conf.show_total_period ? "Period" :
+                                          symbol_conf.show_nr_samples ? "Samples" : "Percent");
                }
        }
 
@@ -3070,7 +3049,7 @@ int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel,
        if (perf_evsel__is_group_event(evsel))
                nr_pcnt = evsel->core.nr_members;
 
-       err = symbol__annotate(ms, evsel, 0, options, parch);
+       err = symbol__annotate(ms, evsel, options, parch);
        if (err)
                goto out_free_offsets;
 
@@ -3094,69 +3073,46 @@ out_free_offsets:
        return err;
 }
 
-#define ANNOTATION__CFG(n) \
-       { .name = #n, .value = &annotation__default_options.n, }
-
-/*
- * Keep the entries sorted, they are bsearch'ed
- */
-static struct annotation_config {
-       const char *name;
-       void *value;
-} annotation__configs[] = {
-       ANNOTATION__CFG(hide_src_code),
-       ANNOTATION__CFG(jump_arrows),
-       ANNOTATION__CFG(offset_level),
-       ANNOTATION__CFG(show_linenr),
-       ANNOTATION__CFG(show_nr_jumps),
-       ANNOTATION__CFG(show_nr_samples),
-       ANNOTATION__CFG(show_total_period),
-       ANNOTATION__CFG(use_offset),
-};
-
-#undef ANNOTATION__CFG
-
-static int annotation_config__cmp(const void *name, const void *cfgp)
-{
-       const struct annotation_config *cfg = cfgp;
-
-       return strcmp(name, cfg->name);
-}
-
-static int annotation__config(const char *var, const char *value,
-                           void *data __maybe_unused)
+static int annotation__config(const char *var, const char *value, void *data)
 {
-       struct annotation_config *cfg;
-       const char *name;
+       struct annotation_options *opt = data;
 
        if (!strstarts(var, "annotate."))
                return 0;
 
-       name = var + 9;
-       cfg = bsearch(name, annotation__configs, ARRAY_SIZE(annotation__configs),
-                     sizeof(struct annotation_config), annotation_config__cmp);
-
-       if (cfg == NULL)
-               pr_debug("%s variable unknown, ignoring...", var);
-       else if (strcmp(var, "annotate.offset_level") == 0) {
-               perf_config_int(cfg->value, name, value);
-
-               if (*(int *)cfg->value > ANNOTATION__MAX_OFFSET_LEVEL)
-                       *(int *)cfg->value = ANNOTATION__MAX_OFFSET_LEVEL;
-               else if (*(int *)cfg->value < ANNOTATION__MIN_OFFSET_LEVEL)
-                       *(int *)cfg->value = ANNOTATION__MIN_OFFSET_LEVEL;
+       if (!strcmp(var, "annotate.offset_level")) {
+               perf_config_u8(&opt->offset_level, "offset_level", value);
+
+               if (opt->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
+                       opt->offset_level = ANNOTATION__MAX_OFFSET_LEVEL;
+               else if (opt->offset_level < ANNOTATION__MIN_OFFSET_LEVEL)
+                       opt->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
+       } else if (!strcmp(var, "annotate.hide_src_code")) {
+               opt->hide_src_code = perf_config_bool("hide_src_code", value);
+       } else if (!strcmp(var, "annotate.jump_arrows")) {
+               opt->jump_arrows = perf_config_bool("jump_arrows", value);
+       } else if (!strcmp(var, "annotate.show_linenr")) {
+               opt->show_linenr = perf_config_bool("show_linenr", value);
+       } else if (!strcmp(var, "annotate.show_nr_jumps")) {
+               opt->show_nr_jumps = perf_config_bool("show_nr_jumps", value);
+       } else if (!strcmp(var, "annotate.show_nr_samples")) {
+               symbol_conf.show_nr_samples = perf_config_bool("show_nr_samples",
+                                                               value);
+       } else if (!strcmp(var, "annotate.show_total_period")) {
+               symbol_conf.show_total_period = perf_config_bool("show_total_period",
+                                                               value);
+       } else if (!strcmp(var, "annotate.use_offset")) {
+               opt->use_offset = perf_config_bool("use_offset", value);
        } else {
-               *(bool *)cfg->value = perf_config_bool(name, value);
+               pr_debug("%s variable unknown, ignoring...", var);
        }
+
        return 0;
 }
 
-void annotation_config__init(void)
+void annotation_config__init(struct annotation_options *opt)
 {
-       perf_config(annotation__config, NULL);
-
-       annotation__default_options.show_total_period = symbol_conf.show_total_period;
-       annotation__default_options.show_nr_samples   = symbol_conf.show_nr_samples;
+       perf_config(annotation__config, opt);
 }
 
 static unsigned int parse_percent_type(char *str1, char *str2)
index 455403e..0012586 100644 (file)
@@ -83,8 +83,6 @@ struct annotation_options {
             full_path,
             show_linenr,
             show_nr_jumps,
-            show_nr_samples,
-            show_total_period,
             show_minmax_cycle,
             show_asm_raw,
             annotate_src;
@@ -141,7 +139,6 @@ struct annotation_line {
        u64                      cycles;
        u64                      cycles_max;
        u64                      cycles_min;
-       size_t                   privsize;
        char                    *path;
        u32                      idx;
        int                      idx_asm;
@@ -309,7 +306,7 @@ static inline int annotation__cycles_width(struct annotation *notes)
 
 static inline int annotation__pcnt_width(struct annotation *notes)
 {
-       return (notes->options->show_total_period ? 12 : 7) * notes->nr_events;
+       return (symbol_conf.show_total_period ? 12 : 7) * notes->nr_events;
 }
 
 static inline bool annotation_line__filter(struct annotation_line *al, struct annotation *notes)
@@ -352,7 +349,7 @@ struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists);
 void symbol__annotate_zero_histograms(struct symbol *sym);
 
 int symbol__annotate(struct map_symbol *ms,
-                    struct evsel *evsel, size_t privsize,
+                    struct evsel *evsel,
                     struct annotation_options *options,
                     struct arch **parch);
 int symbol__annotate2(struct map_symbol *ms,
@@ -413,7 +410,7 @@ static inline int symbol__tui_annotate(struct map_symbol *ms __maybe_unused,
 }
 #endif
 
-void annotation_config__init(void);
+void annotation_config__init(struct annotation_options *opt);
 
 int annotate_parse_percent_type(const struct option *opt, const char *_str,
                                int unset);
index eb087e7..3571ce7 100644 (file)
@@ -629,8 +629,10 @@ int auxtrace_record__options(struct auxtrace_record *itr,
                             struct evlist *evlist,
                             struct record_opts *opts)
 {
-       if (itr)
+       if (itr) {
+               itr->evlist = evlist;
                return itr->recording_options(itr, evlist, opts);
+       }
        return 0;
 }
 
@@ -664,6 +666,24 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
        return -EINVAL;
 }
 
+int auxtrace_record__read_finish(struct auxtrace_record *itr, int idx)
+{
+       struct evsel *evsel;
+
+       if (!itr->evlist || !itr->pmu)
+               return -EINVAL;
+
+       evlist__for_each_entry(itr->evlist, evsel) {
+               if (evsel->core.attr.type == itr->pmu->type) {
+                       if (evsel->disabled)
+                               return 0;
+                       return perf_evlist__enable_event_idx(itr->evlist, evsel,
+                                                            idx);
+               }
+       }
+       return -EINVAL;
+}
+
 /*
  * Event record size is 16-bit which results in a maximum size of about 64KiB.
  * Allow about 4KiB for the rest of the sample record, to give a maximum
index 749d72c..e58ef16 100644 (file)
@@ -29,6 +29,7 @@ struct record_opts;
 struct perf_record_auxtrace_error;
 struct perf_record_auxtrace_info;
 struct events_stats;
+struct perf_pmu;
 
 enum auxtrace_error_type {
        PERF_AUXTRACE_ERROR_ITRACE  = 1,
@@ -322,6 +323,8 @@ struct auxtrace_mmap_params {
  * @read_finish: called after reading from an auxtrace mmap
  * @alignment: alignment (if any) for AUX area data
  * @default_aux_sample_size: default sample size for --aux sample option
+ * @pmu: associated pmu
+ * @evlist: selected events list
  */
 struct auxtrace_record {
        int (*recording_options)(struct auxtrace_record *itr,
@@ -346,6 +349,8 @@ struct auxtrace_record {
        int (*read_finish)(struct auxtrace_record *itr, int idx);
        unsigned int alignment;
        unsigned int default_aux_sample_size;
+       struct perf_pmu *pmu;
+       struct evlist *evlist;
 };
 
 /**
@@ -537,6 +542,7 @@ int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx,
                                   struct auxtrace_mmap *mm,
                                   unsigned char *data, u64 *head, u64 *old);
 u64 auxtrace_record__reference(struct auxtrace_record *itr);
+int auxtrace_record__read_finish(struct auxtrace_record *itr, int idx);
 
 int auxtrace_index__auxtrace_event(struct list_head *head, union perf_event *event,
                                   off_t file_offset);
index 0bc9c4d..ef38eba 100644 (file)
@@ -374,6 +374,18 @@ int perf_config_int(int *dest, const char *name, const char *value)
        return 0;
 }
 
+int perf_config_u8(u8 *dest, const char *name, const char *value)
+{
+       long ret = 0;
+
+       if (!perf_parse_long(value, &ret)) {
+               bad_config(name);
+               return -1;
+       }
+       *dest = ret;
+       return 0;
+}
+
 static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
 {
        int ret;
index bd0a589..c10b66d 100644 (file)
@@ -29,6 +29,7 @@ typedef int (*config_fn_t)(const char *, const char *, void *);
 int perf_default_config(const char *, const char *, void *);
 int perf_config(config_fn_t fn, void *);
 int perf_config_int(int *dest, const char *, const char *);
+int perf_config_u8(u8 *dest, const char *name, const char *value);
 int perf_config_u64(u64 *dest, const char *, const char *);
 int perf_config_bool(const char *, const char *);
 int config_error_nonbool(const char *);
index 5003ba4..0f5fda1 100644 (file)
@@ -301,10 +301,15 @@ int probe_file__get_events(int fd, struct strfilter *filter,
                p = strchr(ent->s, ':');
                if ((p && strfilter__compare(filter, p + 1)) ||
                    strfilter__compare(filter, ent->s)) {
-                       strlist__add(plist, ent->s);
+                       ret = strlist__add(plist, ent->s);
+                       if (ret == -ENOMEM) {
+                               pr_err("strlist__add failed with -ENOMEM\n");
+                               goto out;
+                       }
                        ret = 0;
                }
        }
+out:
        strlist__delete(namelist);
 
        return ret;
@@ -511,7 +516,11 @@ static int probe_cache__load(struct probe_cache *pcache)
                                ret = -EINVAL;
                                goto out;
                        }
-                       strlist__add(entry->tevlist, buf);
+                       ret = strlist__add(entry->tevlist, buf);
+                       if (ret == -ENOMEM) {
+                               pr_err("strlist__add failed with -ENOMEM\n");
+                               goto out;
+                       }
                }
        }
 out:
@@ -672,7 +681,12 @@ int probe_cache__add_entry(struct probe_cache *pcache,
                command = synthesize_probe_trace_command(&tevs[i]);
                if (!command)
                        goto out_err;
-               strlist__add(entry->tevlist, command);
+               ret = strlist__add(entry->tevlist, command);
+               if (ret == -ENOMEM) {
+                       pr_err("strlist__add failed with -ENOMEM\n");
+                       goto out_err;
+               }
+
                free(command);
        }
        list_add_tail(&entry->node, &pcache->entries);
@@ -853,9 +867,15 @@ int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
                        break;
                }
 
-               strlist__add(entry->tevlist, buf);
+               ret = strlist__add(entry->tevlist, buf);
+
                free(buf);
                entry = NULL;
+
+               if (ret == -ENOMEM) {
+                       pr_err("strlist__add failed with -ENOMEM\n");
+                       break;
+               }
        }
        if (entry) {
                list_del_init(&entry->node);
index e59eb9e..180ad1e 100755 (executable)
@@ -24,6 +24,8 @@ KunitResult = namedtuple('KunitResult', ['status','result'])
 
 KunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs', 'build_dir', 'defconfig'])
 
+KernelDirectoryPath = sys.argv[0].split('tools/testing/kunit/')[0]
+
 class KunitStatus(Enum):
        SUCCESS = auto()
        CONFIG_FAILURE = auto()
@@ -35,6 +37,13 @@ def create_default_kunitconfig():
                shutil.copyfile('arch/um/configs/kunit_defconfig',
                                kunit_kernel.kunitconfig_path)
 
+def get_kernel_root_path():
+       parts = sys.argv[0] if not __file__ else __file__
+       parts = os.path.realpath(parts).split('tools/testing/kunit')
+       if len(parts) != 2:
+               sys.exit(1)
+       return parts[0]
+
 def run_tests(linux: kunit_kernel.LinuxSourceTree,
              request: KunitRequest) -> KunitResult:
        config_start = time.time()
@@ -114,6 +123,9 @@ def main(argv, linux=None):
        cli_args = parser.parse_args(argv)
 
        if cli_args.subcommand == 'run':
+               if get_kernel_root_path():
+                       os.chdir(get_kernel_root_path())
+
                if cli_args.build_dir:
                        if not os.path.exists(cli_args.build_dir):
                                os.mkdir(cli_args.build_dir)
index cc5d844..d99ae75 100644 (file)
@@ -93,6 +93,20 @@ class LinuxSourceTree(object):
                        return False
                return True
 
+       def validate_config(self, build_dir):
+               kconfig_path = get_kconfig_path(build_dir)
+               validated_kconfig = kunit_config.Kconfig()
+               validated_kconfig.read_from_file(kconfig_path)
+               if not self._kconfig.is_subset_of(validated_kconfig):
+                       invalid = self._kconfig.entries() - validated_kconfig.entries()
+                       message = 'Provided Kconfig is not contained in validated .config. Following fields found in kunitconfig, ' \
+                                         'but not in .config: %s' % (
+                                       ', '.join([str(e) for e in invalid])
+                       )
+                       logging.error(message)
+                       return False
+               return True
+
        def build_config(self, build_dir):
                kconfig_path = get_kconfig_path(build_dir)
                if build_dir and not os.path.exists(build_dir):
@@ -103,12 +117,7 @@ class LinuxSourceTree(object):
                except ConfigError as e:
                        logging.error(e)
                        return False
-               validated_kconfig = kunit_config.Kconfig()
-               validated_kconfig.read_from_file(kconfig_path)
-               if not self._kconfig.is_subset_of(validated_kconfig):
-                       logging.error('Provided Kconfig is not contained in validated .config!')
-                       return False
-               return True
+               return self.validate_config(build_dir)
 
        def build_reconfig(self, build_dir):
                """Creates a new .config if it is not a subset of the .kunitconfig."""
@@ -133,12 +142,7 @@ class LinuxSourceTree(object):
                except (ConfigError, BuildError) as e:
                        logging.error(e)
                        return False
-               used_kconfig = kunit_config.Kconfig()
-               used_kconfig.read_from_file(get_kconfig_path(build_dir))
-               if not self._kconfig.is_subset_of(used_kconfig):
-                       logging.error('Provided Kconfig is not contained in final config!')
-                       return False
-               return True
+               return self.validate_config(build_dir)
 
        def run_kernel(self, args=[], timeout=None, build_dir=''):
                args.extend(['mem=256M'])
index cd1f5b3..d6e106f 100644 (file)
@@ -2,7 +2,7 @@
 all:
 
 TEST_PROGS := ftracetest
-TEST_FILES := test.d
+TEST_FILES := test.d settings
 EXTRA_CLEAN := $(OUTPUT)/logs/*
 
 include ../lib.mk
index 3876d8d..1acc9e1 100644 (file)
@@ -8,4 +8,6 @@ TEST_PROGS := \
        test-state.sh \
        test-ftrace.sh
 
+TEST_FILES := settings
+
 include ../lib.mk
diff --git a/tools/testing/selftests/lkdtm/.gitignore b/tools/testing/selftests/lkdtm/.gitignore
new file mode 100644 (file)
index 0000000..f262126
--- /dev/null
@@ -0,0 +1,2 @@
+*.sh
+!run.sh
index 93de520..ba450e6 100644 (file)
@@ -8,6 +8,8 @@ TEST_PROGS := mptcp_connect.sh
 
 TEST_GEN_FILES = mptcp_connect
 
+TEST_FILES := settings
+
 EXTRA_CLEAN := *.pcap
 
 include ../../lib.mk
index aca21dd..5a4938d 100755 (executable)
 KSELFTEST_SKIP=4
 
 # Available test groups:
+# - reported_issues: check for issues that were reported in the past
 # - correctness: check that packets match given entries, and only those
 # - concurrency: attempt races between insertion, deletion and lookup
 # - timeout: check that packets match entries until they expire
 # - performance: estimate matching rate, compare with rbtree and hash baselines
-TESTS="correctness concurrency timeout"
+TESTS="reported_issues correctness concurrency timeout"
 [ "${quicktest}" != "1" ] && TESTS="${TESTS} performance"
 
 # Set types, defined by TYPE_ variables below
@@ -25,6 +26,9 @@ TYPES="net_port port_net net6_port port_proto net6_port_mac net6_port_mac_proto
        net_port_net net_mac net_mac_icmp net6_mac_icmp net6_port_net6_port
        net_port_mac_proto_net"
 
+# Reported bugs, also described by TYPE_ variables below
+BUGS="flush_remove_add"
+
 # List of possible paths to pktgen script from kernel tree for performance tests
 PKTGEN_SCRIPT_PATHS="
        ../../../samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
@@ -327,6 +331,12 @@ flood_spec ip daddr . tcp dport . meta l4proto . ip saddr
 perf_duration  0
 "
 
+# Definition of tests for bugs reported in the past:
+# display      display text for test report
+TYPE_flush_remove_add="
+display                Add two elements, flush, re-add
+"
+
 # Set template for all tests, types and rules are filled in depending on test
 set_template='
 flush ruleset
@@ -440,6 +450,8 @@ setup_set() {
 
 # Check that at least one of the needed tools is available
 check_tools() {
+       [ -z "${tools}" ] && return 0
+
        __tools=
        for tool in ${tools}; do
                if [ "${tool}" = "nc" ] && [ "${proto}" = "udp6" ] && \
@@ -1025,7 +1037,7 @@ format_noconcat() {
 add() {
        if ! nft add element inet filter test "${1}"; then
                err "Failed to add ${1} given ruleset:"
-               err "$(nft list ruleset -a)"
+               err "$(nft -a list ruleset)"
                return 1
        fi
 }
@@ -1045,7 +1057,7 @@ add_perf() {
 add_perf_norange() {
        if ! nft add element netdev perf norange "${1}"; then
                err "Failed to add ${1} given ruleset:"
-               err "$(nft list ruleset -a)"
+               err "$(nft -a list ruleset)"
                return 1
        fi
 }
@@ -1054,7 +1066,7 @@ add_perf_norange() {
 add_perf_noconcat() {
        if ! nft add element netdev perf noconcat "${1}"; then
                err "Failed to add ${1} given ruleset:"
-               err "$(nft list ruleset -a)"
+               err "$(nft -a list ruleset)"
                return 1
        fi
 }
@@ -1063,7 +1075,7 @@ add_perf_noconcat() {
 del() {
        if ! nft delete element inet filter test "${1}"; then
                err "Failed to delete ${1} given ruleset:"
-               err "$(nft list ruleset -a)"
+               err "$(nft -a list ruleset)"
                return 1
        fi
 }
@@ -1134,7 +1146,7 @@ send_match() {
                err "  $(for f in ${src}; do
                         eval format_\$f "${2}"; printf ' '; done)"
                err "should have matched ruleset:"
-               err "$(nft list ruleset -a)"
+               err "$(nft -a list ruleset)"
                return 1
        fi
        nft reset counter inet filter test >/dev/null
@@ -1160,7 +1172,7 @@ send_nomatch() {
                err "  $(for f in ${src}; do
                         eval format_\$f "${2}"; printf ' '; done)"
                err "should not have matched ruleset:"
-               err "$(nft list ruleset -a)"
+               err "$(nft -a list ruleset)"
                return 1
        fi
 }
@@ -1430,6 +1442,23 @@ test_performance() {
        kill "${perf_pid}"
 }
 
+test_bug_flush_remove_add() {
+       set_cmd='{ set s { type ipv4_addr . inet_service; flags interval; }; }'
+       elem1='{ 10.0.0.1 . 22-25, 10.0.0.1 . 10-20 }'
+       elem2='{ 10.0.0.1 . 10-20, 10.0.0.1 . 22-25 }'
+       for i in `seq 1 100`; do
+               nft add table t ${set_cmd}      || return ${KSELFTEST_SKIP}
+               nft add element t s ${elem1}    2>/dev/null || return 1
+               nft flush set t s               2>/dev/null || return 1
+               nft add element t s ${elem2}    2>/dev/null || return 1
+       done
+       nft flush ruleset
+}
+
+test_reported_issues() {
+       eval test_bug_"${subtest}"
+}
+
 # Run everything in a separate network namespace
 [ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; }
 tmp="$(mktemp)"
@@ -1438,9 +1467,15 @@ trap cleanup EXIT
 # Entry point for test runs
 passed=0
 for name in ${TESTS}; do
-       printf "TEST: %s\n" "${name}"
-       for type in ${TYPES}; do
-               eval desc=\$TYPE_"${type}"
+       printf "TEST: %s\n" "$(echo ${name} | tr '_' ' ')"
+       if [ "${name}" = "reported_issues" ]; then
+               SUBTESTS="${BUGS}"
+       else
+               SUBTESTS="${TYPES}"
+       fi
+
+       for subtest in ${SUBTESTS}; do
+               eval desc=\$TYPE_"${subtest}"
                IFS='
 '
                for __line in ${desc}; do
index 3a779c0..39559d7 100644 (file)
@@ -2,4 +2,5 @@ pidfd_open_test
 pidfd_poll_test
 pidfd_test
 pidfd_wait
+pidfd_fdinfo_test
 pidfd_getfd_test
index d646953..2af9d39 100644 (file)
@@ -4,7 +4,7 @@ ifneq ($(shell $(CC) --version 2>&1 | head -n 1 | grep clang),)
 CLANG_FLAGS += -no-integrated-as
 endif
 
-CFLAGS += -O2 -Wall -g -I./ -I../../../../usr/include/ -L./ -Wl,-rpath=./ \
+CFLAGS += -O2 -Wall -g -I./ -I../../../../usr/include/ -L$(OUTPUT) -Wl,-rpath=./ \
          $(CLANG_FLAGS)
 LDLIBS += -lpthread
 
@@ -19,6 +19,8 @@ TEST_GEN_PROGS_EXTENDED = librseq.so
 
 TEST_PROGS = run_param_test.sh
 
+TEST_FILES := settings
+
 include ../lib.mk
 
 $(OUTPUT)/librseq.so: rseq.c rseq.h rseq-*.h
index 2d93d65..55198ec 100644 (file)
@@ -6,4 +6,6 @@ TEST_GEN_PROGS = rtctest
 
 TEST_GEN_PROGS_EXTENDED = setdate
 
+TEST_FILES := settings
+
 include ../lib.mk
index d65a0fa..eda7b62 100644 (file)
@@ -742,9 +742,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                guest_enter_irqoff();
 
                if (has_vhe()) {
-                       kvm_arm_vhe_guest_enter();
                        ret = kvm_vcpu_run_vhe(vcpu);
-                       kvm_arm_vhe_guest_exit();
                } else {
                        ret = kvm_call_hyp_ret(__kvm_vcpu_run_nvhe, vcpu);
                }
index 204d210..cc94ccc 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <kvm/arm_arch_timer.h>
 #include <linux/tracepoint.h>
+#include <asm/kvm_arm.h>
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM kvm