Merge branch 'for-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 5 Aug 2021 19:00:00 +0000 (12:00 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 5 Aug 2021 19:00:00 +0000 (12:00 -0700)
Pull ucounts fix from Eric Biederman:
 "Fix a subtle locking versus reference counting bug in the ucount
  changes, found by syzbot"

* 'for-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
  ucounts: Fix race condition between alloc_ucounts and put_ucounts

292 files changed:
Documentation/virt/kvm/api.rst
MAINTAINERS
Makefile
arch/alpha/Kconfig
arch/alpha/boot/bootp.c
arch/alpha/boot/bootpz.c
arch/alpha/boot/misc.c
arch/alpha/configs/defconfig
arch/alpha/include/asm/compiler.h
arch/alpha/include/asm/syscall.h
arch/alpha/kernel/osf_sys.c
arch/alpha/kernel/perf_event.c
arch/alpha/kernel/process.c
arch/alpha/kernel/setup.c
arch/alpha/kernel/smp.c
arch/alpha/kernel/sys_nautilus.c
arch/alpha/kernel/traps.c
arch/alpha/math-emu/math.c
arch/arm/Kconfig
arch/arm/mach-davinci/Kconfig
arch/arm/mach-rpc/riscpc.c
arch/arm/net/bpf_jit_32.c
arch/arm64/boot/dts/freescale/imx8mp.dtsi
arch/arm64/kvm/mmu.c
arch/arm64/net/bpf_jit_comp.c
arch/h8300/Kconfig.cpu
arch/ia64/Kconfig
arch/m68k/Kconfig
arch/m68k/coldfire/m525x.c
arch/mips/Kconfig
arch/mips/net/ebpf_jit.c
arch/parisc/Kconfig
arch/powerpc/Kconfig
arch/powerpc/kernel/vdso64/Makefile
arch/powerpc/net/bpf_jit_comp32.c
arch/powerpc/net/bpf_jit_comp64.c
arch/powerpc/platforms/pseries/setup.c
arch/riscv/net/bpf_jit_comp32.c
arch/riscv/net/bpf_jit_comp64.c
arch/s390/boot/compressed/Makefile
arch/s390/boot/compressed/clz_ctz.c [new file with mode: 0644]
arch/s390/configs/debug_defconfig
arch/s390/configs/defconfig
arch/s390/include/asm/kvm_host.h
arch/s390/kernel/vdso32/vdso32.lds.S
arch/s390/kernel/vdso64/vdso64.lds.S
arch/s390/kvm/diag.c
arch/s390/kvm/kvm-s390.c
arch/s390/net/bpf_jit_comp.c
arch/sh/Kconfig
arch/sparc/Kconfig
arch/sparc/net/bpf_jit_comp_64.c
arch/x86/Kconfig
arch/x86/kvm/hyperv.c
arch/x86/kvm/ioapic.c
arch/x86/kvm/ioapic.h
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/svm/avic.c
arch/x86/kvm/svm/nested.c
arch/x86/kvm/svm/sev.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/svm/svm.h
arch/x86/kvm/svm/svm_onhyperv.h
arch/x86/kvm/trace.h
arch/x86/kvm/x86.c
arch/x86/net/bpf_jit_comp.c
arch/x86/net/bpf_jit_comp32.c
arch/xtensa/Kconfig
block/blk-iocost.c
block/blk-mq-sched.c
block/genhd.c
drivers/acpi/dptf/dptf_pch_fivr.c
drivers/acpi/resource.c
drivers/acpi/x86/s2idle.c
drivers/ata/libata-sff.c
drivers/block/loop.c
drivers/clk/clk-devres.c
drivers/clk/clk-stm32f4.c
drivers/clk/hisilicon/Kconfig
drivers/clk/qcom/clk-smd-rpm.c
drivers/clk/tegra/clk-sdmmc-mux.c
drivers/gpio/gpio-mpc8xxx.c
drivers/gpio/gpio-tqmx86.c
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c
drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c
drivers/gpu/drm/i915/display/intel_bios.c
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/intel_device_info.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
drivers/gpu/drm/msm/dp/dp_catalog.c
drivers/gpu/drm/msm/dp/dp_ctrl.c
drivers/gpu/drm/msm/dp/dp_display.c
drivers/gpu/drm/msm/msm_iommu.c
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/ttm/ttm_device.c
drivers/gpu/drm/ttm/ttm_module.c
drivers/hid/Kconfig
drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
drivers/hid/hid-apple.c
drivers/hid/hid-asus.c
drivers/hid/hid-ft260.c
drivers/hid/intel-ish-hid/ishtp-hid-client.c
drivers/hid/intel-ish-hid/ishtp-hid.h
drivers/hid/intel-ish-hid/ishtp/bus.c
drivers/hid/usbhid/Kconfig
drivers/hid/wacom_wac.c
drivers/infiniband/hw/bnxt_re/main.c
drivers/infiniband/hw/bnxt_re/qplib_res.c
drivers/infiniband/hw/bnxt_re/qplib_res.h
drivers/infiniband/hw/irdma/ctrl.c
drivers/infiniband/hw/irdma/hw.c
drivers/infiniband/hw/irdma/main.c
drivers/infiniband/hw/irdma/type.h
drivers/infiniband/hw/irdma/uk.c
drivers/infiniband/hw/irdma/verbs.c
drivers/infiniband/sw/rxe/rxe_mr.c
drivers/media/common/videobuf2/videobuf2-core.c
drivers/media/platform/atmel/Kconfig
drivers/media/platform/atmel/Makefile
drivers/media/platform/atmel/atmel-isc-base.c
drivers/media/usb/dvb-usb-v2/rtl28xxu.c
drivers/net/can/spi/hi311x.c
drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
drivers/net/can/usb/ems_usb.c
drivers/net/can/usb/esd_usb2.c
drivers/net/can/usb/mcba_usb.c
drivers/net/can/usb/peak_usb/pcan_usb.c
drivers/net/can/usb/usb_8dev.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h
drivers/net/ethernet/dec/tulip/winbond-840.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.h
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_txrx.h
drivers/net/ethernet/marvell/octeontx2/af/cgx.c
drivers/net/ethernet/marvell/octeontx2/af/npc.h
drivers/net/ethernet/marvell/octeontx2/af/rvu.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx5/core/dev.c
drivers/net/ethernet/mellanox/mlx5/core/en/params.c
drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
drivers/net/ethernet/mellanox/mlx5/core/en/trap.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
drivers/net/ethernet/mellanox/mlx5/core/health.c
drivers/net/ethernet/pensando/ionic/ionic_lif.c
drivers/net/ethernet/pensando/ionic/ionic_lif.h
drivers/net/ethernet/pensando/ionic/ionic_phc.c
drivers/net/ethernet/pensando/ionic/ionic_txrx.c
drivers/net/ethernet/qlogic/qede/qede_filter.c
drivers/net/ethernet/qlogic/qla3xxx.c
drivers/net/ethernet/sis/sis900.c
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
drivers/net/ethernet/sun/niu.c
drivers/net/phy/broadcom.c
drivers/net/wireless/virt_wifi.c
drivers/net/wwan/wwan_core.c
drivers/nfc/nfcsim.c
drivers/nfc/s3fwrn5/firmware.c
drivers/pcmcia/i82092.c
drivers/platform/x86/amd-pmc.c
drivers/platform/x86/gigabyte-wmi.c
drivers/platform/x86/intel-hid.c
drivers/platform/x86/think-lmi.c
drivers/platform/x86/think-lmi.h
drivers/platform/x86/wireless-hotkey.c
drivers/scsi/arm/acornscsi.c
drivers/scsi/arm/fas216.c
drivers/scsi/device_handler/scsi_dh_rdac.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvfc.h
drivers/scsi/megaraid/megaraid_mm.c
drivers/scsi/pm8001/pm8001_sas.c
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/sr.c
fs/Kconfig.binfmt
fs/Makefile
fs/binfmt_em86.c [deleted file]
fs/block_dev.c
fs/btrfs/compression.c
fs/btrfs/disk-io.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/cifs/file.c
fs/cifs/fs_context.c
fs/cifs/smb2ops.c
fs/ext2/dir.c
fs/ext2/ext2.h
fs/ext2/namei.c
fs/internal.h
fs/io_uring.c
fs/ocfs2/file.c
fs/pipe.c
fs/reiserfs/stree.c
fs/reiserfs/super.c
fs/xfs/libxfs/xfs_log_format.h
fs/xfs/xfs_buf_item_recover.c
fs/xfs/xfs_inode_item_recover.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_log_priv.h
fs/xfs/xfs_trace.h
include/linux/bpf_types.h
include/linux/bpf_verifier.h
include/linux/filter.h
include/linux/fs_context.h
include/linux/intel-ish-client-if.h
include/linux/skmsg.h
include/net/llc_pdu.h
include/net/sctp/structs.h
include/uapi/linux/idxd.h
include/uapi/rdma/irdma-abi.h
kernel/bpf/core.c
kernel/bpf/disasm.c
kernel/bpf/verifier.c
kernel/cgroup/cgroup-v1.c
kernel/trace/trace.c
kernel/trace/trace_events_hist.c
kernel/trace/trace_hwlat.c
kernel/workqueue.c
lib/Kconfig
lib/Kconfig.debug
mm/memcontrol.c
mm/migrate.c
mm/slab.h
mm/slub.c
net/can/j1939/transport.c
net/can/raw.c
net/core/devlink.c
net/core/flow_dissector.c
net/core/skmsg.c
net/ipv4/ip_tunnel.c
net/ipv6/ip6_output.c
net/llc/af_llc.c
net/llc/llc_s_ac.c
net/mac80211/cfg.c
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/tx.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_flow_table_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink_hook.c
net/netfilter/nft_last.c
net/netfilter/nft_nat.c
net/qrtr/qrtr.c
net/sctp/input.c
net/sctp/ipv6.c
net/sctp/sm_statefuns.c
net/sctp/transport.c
net/tipc/crypto.c
net/tipc/socket.c
net/unix/af_unix.c
net/wireless/nl80211.c
net/wireless/scan.c
scripts/recordmcount.pl
scripts/tracing/draw_functrace.py
tools/perf/util/cs-etm.c
tools/perf/util/map.c
tools/perf/util/pmu.c
tools/testing/selftests/bpf/verifier/value_ptr_arith.c
tools/testing/selftests/kvm/.gitignore
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/aarch64/get-reg-list.c
tools/testing/selftests/kvm/access_tracking_perf_test.c [new file with mode: 0644]
tools/testing/selftests/kvm/dirty_log_perf_test.c
tools/testing/selftests/kvm/include/x86_64/hyperv.h
tools/testing/selftests/kvm/steal_time.c
tools/testing/selftests/kvm/x86_64/hyperv_clock.c
tools/testing/selftests/kvm/x86_64/hyperv_features.c
virt/kvm/kvm_main.c

index c7b165c..dae68e6 100644 (file)
@@ -855,7 +855,7 @@ in-kernel irqchip (GIC), and for in-kernel irqchip can tell the GIC to
 use PPIs designated for specific cpus.  The irq field is interpreted
 like this::
 
 bits:  |  31 ... 28  | 27 ... 24 | 23  ... 16 | 15 ... 0 |
 bits:  |  31 ... 28  | 27 ... 24 | 23  ... 16 | 15 ... 0 |
   field: | vcpu2_index | irq_type  | vcpu_index |  irq_id  |
 
 The irq_type field has the following values:
@@ -2149,10 +2149,10 @@ prior to calling the KVM_RUN ioctl.
 Errors:
 
   ======   ============================================================
 ENOENT Â Â no such register
 EINVAL Â Â invalid register ID, or no such register or used with VMs in
 ENOENT   no such register
 EINVAL   invalid register ID, or no such register or used with VMs in
            protected virtualization mode on s390
 EPERM Â Â Â (arm64) register access not allowed before vcpu finalization
 EPERM    (arm64) register access not allowed before vcpu finalization
   ======   ============================================================
 
 (These error codes are indicative only: do not rely on a specific error
@@ -2590,10 +2590,10 @@ following id bit patterns::
 Errors include:
 
   ======== ============================================================
 ENOENT Â Â no such register
 EINVAL Â Â invalid register ID, or no such register or used with VMs in
 ENOENT   no such register
 EINVAL   invalid register ID, or no such register or used with VMs in
            protected virtualization mode on s390
 EPERM Â Â Â (arm64) register access not allowed before vcpu finalization
 EPERM    (arm64) register access not allowed before vcpu finalization
   ======== ============================================================
 
 (These error codes are indicative only: do not rely on a specific error
@@ -3112,13 +3112,13 @@ current state.  "addr" is ignored.
 Errors:
 
   ======     =================================================================
 EINVAL  Â Â Â the target is unknown, or the combination of features is invalid.
 ENOENT  Â Â Â a features bit specified is unknown.
 EINVAL     the target is unknown, or the combination of features is invalid.
 ENOENT     a features bit specified is unknown.
   ======     =================================================================
 
 This tells KVM what type of CPU to present to the guest, and what
-optional features it should have. Â This will cause a reset of the cpu
-registers to their initial values. Â If this is not called, KVM_RUN will
+optional features it should have.  This will cause a reset of the cpu
+registers to their initial values.  If this is not called, KVM_RUN will
 return ENOEXEC for that vcpu.
 
 The initial values are defined as:
@@ -3239,8 +3239,8 @@ VCPU matching underlying host.
 Errors:
 
   =====      ==============================================================
 E2BIG  Â Â Â Â the reg index list is too big to fit in the array specified by
            the user (the number required will be written into n).
 E2BIG      the reg index list is too big to fit in the array specified by
            the user (the number required will be written into n).
   =====      ==============================================================
 
 ::
@@ -3288,7 +3288,7 @@ specific device.
 ARM/arm64 divides the id field into two parts, a device id and an
 address type id specific to the individual device::
 
 bits:  | 63        ...       32 | 31    ...    16 | 15    ...    0 |
 bits:  | 63        ...       32 | 31    ...    16 | 15    ...    0 |
   field: |        0x00000000      |     device id   |  addr type id  |
 
 ARM/arm64 currently only require this when using the in-kernel GIC
@@ -7049,7 +7049,7 @@ In combination with KVM_CAP_X86_USER_SPACE_MSR, this allows user space to
 trap and emulate MSRs that are outside of the scope of KVM as well as
 limit the attack surface on KVM's MSR emulation code.
 
-8.28 KVM_CAP_ENFORCE_PV_CPUID
+8.28 KVM_CAP_ENFORCE_PV_FEATURE_CPUID
 -----------------------------
 
 Architectures: x86
index 19135a9..c9467d2 100644 (file)
@@ -7858,9 +7858,9 @@ S:        Maintained
 F:     drivers/input/touchscreen/goodix.c
 
 GOOGLE ETHERNET DRIVERS
-M:     Catherine Sullivan <csully@google.com>
-R:     Sagi Shahar <sagis@google.com>
-R:     Jon Olson <jonolson@google.com>
+M:     Jeroen de Borst <jeroendb@google.com>
+R:     Catherine Sullivan <csully@google.com>
+R:     David Awogbemila <awogbemila@google.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     Documentation/networking/device_drivers/ethernet/google/gve.rst
@@ -11327,6 +11327,12 @@ W:     https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/radio/radio-maxiradio*
 
+MCAB MICROCHIP CAN BUS ANALYZER TOOL DRIVER
+R:     Yasushi SHOJI <yashi@spacecubics.com>
+L:     linux-can@vger.kernel.org
+S:     Maintained
+F:     drivers/net/can/usb/mcba_usb.c
+
 MCAN MMIO DEVICE DRIVER
 M:     Chandrasekar Ramakrishnan <rcsekar@samsung.com>
 L:     linux-can@vger.kernel.org
@@ -15468,6 +15474,8 @@ M:      Pan, Xinhui <Xinhui.Pan@amd.com>
 L:     amd-gfx@lists.freedesktop.org
 S:     Supported
 T:     git https://gitlab.freedesktop.org/agd5f/linux.git
+B:     https://gitlab.freedesktop.org/drm/amd/-/issues
+C:     irc://irc.oftc.net/radeon
 F:     drivers/gpu/drm/amd/
 F:     drivers/gpu/drm/radeon/
 F:     include/uapi/drm/amdgpu_drm.h
index 6b555f6..b6ee64d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 14
 SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION = -rc4
 NAME = Opossums on Parade
 
 # *DOCUMENTATION*
@@ -546,7 +546,6 @@ export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \
 PHONY += scripts_basic
 scripts_basic:
        $(Q)$(MAKE) $(build)=scripts/basic
-       $(Q)rm -f .tmp_quiet_recordmcount
 
 PHONY += outputmakefile
 ifdef building_out_of_srctree
index 77d3280..6c50877 100644 (file)
@@ -14,7 +14,6 @@ config ALPHA
        select PCI_SYSCALL if PCI
        select HAVE_AOUT
        select HAVE_ASM_MODVERSIONS
-       select HAVE_IDE
        select HAVE_PCSPKR_PLATFORM
        select HAVE_PERF_EVENTS
        select NEED_DMA_MAP_STATE
@@ -532,7 +531,7 @@ config SMP
          will run faster if you say N here.
 
          See also the SMP-HOWTO available at
-         <http://www.tldp.org/docs.html#howto>.
+         <https://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
 
index 00266e6..b4faba2 100644 (file)
@@ -23,7 +23,7 @@
 #include "ksize.h"
 
 extern unsigned long switch_to_osf_pal(unsigned long nr,
-       struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
+       struct pcb_struct *pcb_va, struct pcb_struct *pcb_pa,
        unsigned long *vptb);
 
 extern void move_stack(unsigned long new_stack);
index 43af718..90a2b34 100644 (file)
@@ -200,7 +200,7 @@ extern char _end;
        START_ADDR      KSEG address of the entry point of kernel code.
 
        ZERO_PGE        KSEG address of page full of zeroes, but 
-                       upon entry to kerne cvan be expected
+                       upon entry to kernel, it can be expected
                        to hold the parameter list and possible
                        INTRD information.
 
index d651922..325d4dd 100644 (file)
@@ -30,7 +30,7 @@ extern long srm_printk(const char *, ...)
      __attribute__ ((format (printf, 1, 2)));
 
 /*
- * gzip delarations
+ * gzip declarations
  */
 #define OF(args)  args
 #define STATIC static
index dd2dd9f..7f1ca30 100644 (file)
@@ -70,3 +70,4 @@ CONFIG_DEBUG_INFO=y
 CONFIG_ALPHA_LEGACY_START_ADDRESS=y
 CONFIG_MATHEMU=y
 CONFIG_CRYPTO_HMAC=y
+CONFIG_DEVTMPFS=y
index 5159ba2..ae64595 100644 (file)
@@ -4,15 +4,4 @@
 
 #include <uapi/asm/compiler.h>
 
-/* Some idiots over in <linux/compiler.h> thought inline should imply
-   always_inline.  This breaks stuff.  We'll include this file whenever
-   we run into such problems.  */
-
-#include <linux/compiler.h>
-#undef inline
-#undef __inline__
-#undef __inline
-#undef __always_inline
-#define __always_inline                inline __attribute__((always_inline))
-
 #endif /* __ALPHA_COMPILER_H */
index 11c688c..f21baba 100644 (file)
@@ -9,4 +9,10 @@ static inline int syscall_get_arch(struct task_struct *task)
        return AUDIT_ARCH_ALPHA;
 }
 
+static inline long syscall_get_return_value(struct task_struct *task,
+                                           struct pt_regs *regs)
+{
+       return regs->r0;
+}
+
 #endif /* _ASM_ALPHA_SYSCALL_H */
index d5367a1..d31167e 100644 (file)
@@ -834,7 +834,7 @@ SYSCALL_DEFINE5(osf_setsysinfo, unsigned long, op, void __user *, buffer,
                        return -EFAULT;
                state = &current_thread_info()->ieee_state;
 
-               /* Update softare trap enable bits.  */
+               /* Update software trap enable bits.  */
                *state = (*state & ~IEEE_SW_MASK) | (swcr & IEEE_SW_MASK);
 
                /* Update the real fpcr.  */
@@ -854,7 +854,7 @@ SYSCALL_DEFINE5(osf_setsysinfo, unsigned long, op, void __user *, buffer,
                state = &current_thread_info()->ieee_state;
                exc &= IEEE_STATUS_MASK;
 
-               /* Update softare trap enable bits.  */
+               /* Update software trap enable bits.  */
                swcr = (*state & IEEE_SW_MASK) | exc;
                *state |= exc;
 
index e7a59d9..efcf732 100644 (file)
@@ -574,7 +574,7 @@ static void alpha_pmu_start(struct perf_event *event, int flags)
  * Check that CPU performance counters are supported.
  * - currently support EV67 and later CPUs.
  * - actually some later revisions of the EV6 have the same PMC model as the
- *     EV67 but we don't do suffiently deep CPU detection to detect them.
+ *     EV67 but we don't do sufficiently deep CPU detection to detect them.
  *     Bad luck to the very few people who might have one, I guess.
  */
 static int supported_cpu(void)
index ef0c08e..a5123ea 100644 (file)
@@ -256,7 +256,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
                childstack->r26 = (unsigned long) ret_from_kernel_thread;
                childstack->r9 = usp;   /* function */
                childstack->r10 = kthread_arg;
-               childregs->hae = alpha_mv.hae_cache,
+               childregs->hae = alpha_mv.hae_cache;
                childti->pcb.usp = 0;
                return 0;
        }
index 7d56c21..b4fbbba 100644 (file)
@@ -319,18 +319,19 @@ setup_memory(void *kernel_end)
                       i, cluster->usage, cluster->start_pfn,
                       cluster->start_pfn + cluster->numpages);
 
-               /* Bit 0 is console/PALcode reserved.  Bit 1 is
-                  non-volatile memory -- we might want to mark
-                  this for later.  */
-               if (cluster->usage & 3)
-                       continue;
-
                end = cluster->start_pfn + cluster->numpages;
                if (end > max_low_pfn)
                        max_low_pfn = end;
 
                memblock_add(PFN_PHYS(cluster->start_pfn),
                             cluster->numpages << PAGE_SHIFT);
+
+               /* Bit 0 is console/PALcode reserved.  Bit 1 is
+                  non-volatile memory -- we might want to mark
+                  this for later.  */
+               if (cluster->usage & 3)
+                       memblock_reserve(PFN_PHYS(cluster->start_pfn),
+                                        cluster->numpages << PAGE_SHIFT);
        }
 
        /*
index 4b2575f..cb64e47 100644 (file)
@@ -582,7 +582,7 @@ void
 smp_send_stop(void)
 {
        cpumask_t to_whom;
-       cpumask_copy(&to_whom, cpu_possible_mask);
+       cpumask_copy(&to_whom, cpu_online_mask);
        cpumask_clear_cpu(smp_processor_id(), &to_whom);
 #ifdef DEBUG_IPI_MSG
        if (hard_smp_processor_id() != boot_cpu_id)
index 53adf43..96fd6ff 100644 (file)
@@ -212,7 +212,7 @@ nautilus_init_pci(void)
 
        /* Use default IO. */
        pci_add_resource(&bridge->windows, &ioport_resource);
-       /* Irongate PCI memory aperture, calculate requred size before
+       /* Irongate PCI memory aperture, calculate required size before
           setting it up. */
        pci_add_resource(&bridge->windows, &irongate_mem);
 
index 921d4b6..5398f98 100644 (file)
@@ -730,7 +730,7 @@ do_entUnaUser(void __user * va, unsigned long opcode,
        long error;
 
        /* Check the UAC bits to decide what the user wants us to do
-          with the unaliged access.  */
+          with the unaligned access.  */
 
        if (!(current_thread_info()->status & TS_UAC_NOPRINT)) {
                if (__ratelimit(&ratelimit)) {
index d568cd9..f7cef66 100644 (file)
@@ -65,7 +65,7 @@ static long (*save_emul) (unsigned long pc);
 long do_alpha_fp_emul_imprecise(struct pt_regs *, unsigned long);
 long do_alpha_fp_emul(unsigned long);
 
-int init_module(void)
+static int alpha_fp_emul_init_module(void)
 {
        save_emul_imprecise = alpha_fp_emul_imprecise;
        save_emul = alpha_fp_emul;
@@ -73,12 +73,14 @@ int init_module(void)
        alpha_fp_emul = do_alpha_fp_emul;
        return 0;
 }
+module_init(alpha_fp_emul_init_module);
 
-void cleanup_module(void)
+static void alpha_fp_emul_cleanup_module(void)
 {
        alpha_fp_emul_imprecise = save_emul_imprecise;
        alpha_fp_emul = save_emul;
 }
+module_exit(alpha_fp_emul_cleanup_module);
 
 #undef  alpha_fp_emul_imprecise
 #define alpha_fp_emul_imprecise                do_alpha_fp_emul_imprecise
@@ -401,3 +403,5 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
 egress:
        return si_code;
 }
+
+EXPORT_SYMBOL(__udiv_qrnnd);
index 82f908f..2fb7012 100644 (file)
@@ -95,7 +95,6 @@ config ARM
        select HAVE_FUNCTION_TRACER if !XIP_KERNEL
        select HAVE_GCC_PLUGINS
        select HAVE_HW_BREAKPOINT if PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)
-       select HAVE_IDE if PCI || ISA || PCMCIA
        select HAVE_IRQ_TIME_ACCOUNTING
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_LZ4
@@ -361,7 +360,6 @@ config ARCH_FOOTBRIDGE
        bool "FootBridge"
        select CPU_SA110
        select FOOTBRIDGE
-       select HAVE_IDE
        select NEED_MACH_IO_H if !MMU
        select NEED_MACH_MEMORY_H
        help
@@ -430,7 +428,6 @@ config ARCH_PXA
        select GENERIC_IRQ_MULTI_HANDLER
        select GPIO_PXA
        select GPIOLIB
-       select HAVE_IDE
        select IRQ_DOMAIN
        select PLAT_PXA
        select SPARSE_IRQ
@@ -446,7 +443,6 @@ config ARCH_RPC
        select ARM_HAS_SG_CHAIN
        select CPU_SA110
        select FIQ
-       select HAVE_IDE
        select HAVE_PATA_PLATFORM
        select ISA_DMA_API
        select LEGACY_TIMER_TICK
@@ -469,7 +465,6 @@ config ARCH_SA1100
        select CPU_SA1100
        select GENERIC_IRQ_MULTI_HANDLER
        select GPIOLIB
-       select HAVE_IDE
        select IRQ_DOMAIN
        select ISA
        select NEED_MACH_MEMORY_H
@@ -505,7 +500,6 @@ config ARCH_OMAP1
        select GENERIC_IRQ_CHIP
        select GENERIC_IRQ_MULTI_HANDLER
        select GPIOLIB
-       select HAVE_IDE
        select HAVE_LEGACY_CLK
        select IRQ_DOMAIN
        select NEED_MACH_IO_H if PCCARD
index de11030..1d3aef8 100644 (file)
@@ -9,7 +9,6 @@ menuconfig ARCH_DAVINCI
        select PM_GENERIC_DOMAINS_OF if PM && OF
        select REGMAP_MMIO
        select RESET_CONTROLLER
-       select HAVE_IDE
        select PINCTRL_SINGLE
 
 if ARCH_DAVINCI
index d23970b..f70fb9c 100644 (file)
@@ -49,6 +49,7 @@ static int __init parse_tag_acorn(const struct tag *tag)
                fallthrough;    /* ??? */
        case 256:
                vram_size += PAGE_SIZE * 256;
+               break;
        default:
                break;
        }
index 897634d..a951276 100644 (file)
@@ -1602,6 +1602,9 @@ exit:
                rn = arm_bpf_get_reg32(src_lo, tmp2[1], ctx);
                emit_ldx_r(dst, rn, off, ctx, BPF_SIZE(code));
                break;
+       /* speculation barrier */
+       case BPF_ST | BPF_NOSPEC:
+               break;
        /* ST: *(size *)(dst + off) = imm */
        case BPF_ST | BPF_MEM | BPF_W:
        case BPF_ST | BPF_MEM | BPF_H:
index ca38d0d..f4eaab3 100644 (file)
                        };
 
                        flexcan1: can@308c0000 {
-                               compatible = "fsl,imx8mp-flexcan", "fsl,imx6q-flexcan";
+                               compatible = "fsl,imx8mp-flexcan";
                                reg = <0x308c0000 0x10000>;
                                interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
                        };
 
                        flexcan2: can@308d0000 {
-                               compatible = "fsl,imx8mp-flexcan", "fsl,imx6q-flexcan";
+                               compatible = "fsl,imx8mp-flexcan";
                                reg = <0x308d0000 0x10000>;
                                interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
index 3155c9e..0625bf2 100644 (file)
@@ -947,7 +947,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
                vma_shift = get_vma_page_shift(vma, hva);
        }
 
-       shared = (vma->vm_flags & VM_PFNMAP);
+       shared = (vma->vm_flags & VM_SHARED);
 
        switch (vma_shift) {
 #ifndef __PAGETABLE_PMD_FOLDED
index dccf98a..41c23f4 100644 (file)
@@ -823,6 +823,19 @@ emit_cond_jmp:
                        return ret;
                break;
 
+       /* speculation barrier */
+       case BPF_ST | BPF_NOSPEC:
+               /*
+                * Nothing required here.
+                *
+                * In case of arm64, we rely on the firmware mitigation of
+                * Speculative Store Bypass as controlled via the ssbd kernel
+                * parameter. Whenever the mitigation is enabled, it works
+                * for all of the kernel code with no need to provide any
+                * additional instructions.
+                */
+               break;
+
        /* ST: *(size *)(dst + off) = imm */
        case BPF_ST | BPF_MEM | BPF_W:
        case BPF_ST | BPF_MEM | BPF_H:
index b5e14d5..c30baa0 100644 (file)
@@ -44,7 +44,6 @@ config H8300_H8MAX
        bool "H8MAX"
        select H83069
        select RAMKERNEL
-       select HAVE_IDE
        help
          H8MAX Evaluation Board Support
          More Information. (Japanese Only)
index cf425c2..4993c7a 100644 (file)
@@ -25,7 +25,6 @@ config IA64
        select HAVE_ASM_MODVERSIONS
        select HAVE_UNSTABLE_SCHED_CLOCK
        select HAVE_EXIT_THREAD
-       select HAVE_IDE
        select HAVE_KPROBES
        select HAVE_KRETPROBES
        select HAVE_FTRACE_MCOUNT_RECORD
index 96989ad..d632a1d 100644 (file)
@@ -23,7 +23,6 @@ config M68K
        select HAVE_DEBUG_BUGVERBOSE
        select HAVE_EFFICIENT_UNALIGNED_ACCESS if !CPU_HAS_NO_UNALIGNED
        select HAVE_FUTEX_CMPXCHG if MMU && FUTEX
-       select HAVE_IDE
        select HAVE_MOD_ARCH_SPECIFIC
        select HAVE_UID16
        select MMU_GATHER_NO_RANGE if MMU
index 2c4d2ca..4853751 100644 (file)
@@ -26,7 +26,7 @@ DEFINE_CLK(pll, "pll.0", MCF_CLK);
 DEFINE_CLK(sys, "sys.0", MCF_BUSCLK);
 
 static struct clk_lookup m525x_clk_lookup[] = {
-       CLKDEV_INIT(NULL, "pll.0", &pll),
+       CLKDEV_INIT(NULL, "pll.0", &clk_pll),
        CLKDEV_INIT(NULL, "sys.0", &clk_sys),
        CLKDEV_INIT("mcftmr.0", NULL, &clk_sys),
        CLKDEV_INIT("mcftmr.1", NULL, &clk_sys),
index cee6087..6dfb27d 100644 (file)
@@ -71,7 +71,6 @@ config MIPS
        select HAVE_FUNCTION_TRACER
        select HAVE_GCC_PLUGINS
        select HAVE_GENERIC_VDSO
-       select HAVE_IDE
        select HAVE_IOREMAP_PROT
        select HAVE_IRQ_EXIT_ON_IRQ_STACK
        select HAVE_IRQ_TIME_ACCOUNTING
index 939dd06..3a73e93 100644 (file)
@@ -1355,6 +1355,9 @@ jeq_common:
                }
                break;
 
+       case BPF_ST | BPF_NOSPEC: /* speculation barrier */
+               break;
+
        case BPF_ST | BPF_B | BPF_MEM:
        case BPF_ST | BPF_H | BPF_MEM:
        case BPF_ST | BPF_W | BPF_MEM:
index bde9907..4f8c1fb 100644 (file)
@@ -3,7 +3,6 @@ config PARISC
        def_bool y
        select ARCH_32BIT_OFF_T if !64BIT
        select ARCH_MIGHT_HAVE_PC_PARPORT
-       select HAVE_IDE
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_SYSCALL_TRACEPOINTS
index d01e340..663766f 100644 (file)
@@ -220,7 +220,6 @@ config PPC
        select HAVE_HARDLOCKUP_DETECTOR_ARCH    if PPC_BOOK3S_64 && SMP
        select HAVE_HARDLOCKUP_DETECTOR_PERF    if PERF_EVENTS && HAVE_PERF_EVENTS_NMI && !HAVE_HARDLOCKUP_DETECTOR_ARCH
        select HAVE_HW_BREAKPOINT               if PERF_EVENTS && (PPC_BOOK3S || PPC_8xx)
-       select HAVE_IDE
        select HAVE_IOREMAP_PROT
        select HAVE_IRQ_EXIT_ON_IRQ_STACK
        select HAVE_IRQ_TIME_ACCOUNTING
index 2813e3f..3c5baaa 100644 (file)
@@ -27,6 +27,13 @@ KASAN_SANITIZE := n
 
 ccflags-y := -shared -fno-common -fno-builtin -nostdlib \
        -Wl,-soname=linux-vdso64.so.1 -Wl,--hash-style=both
+
+# Go prior to 1.16.x assumes r30 is not clobbered by any VDSO code. That used to be true
+# by accident when the VDSO was hand-written asm code, but may not be now that the VDSO is
+# compiler generated. To avoid breaking Go tell GCC not to use r30. Impact on code
+# generation is minimal, it will just use r29 instead.
+ccflags-y += $(call cc-option, -ffixed-r30)
+
 asflags-y := -D__VDSO64__ -s
 
 targets += vdso64.lds
index 34bb158..beb12cb 100644 (file)
@@ -738,6 +738,12 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
                        break;
 
                /*
+                * BPF_ST NOSPEC (speculation barrier)
+                */
+               case BPF_ST | BPF_NOSPEC:
+                       break;
+
+               /*
                 * BPF_ST(X)
                 */
                case BPF_STX | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = src */
index de85958..b87a63d 100644 (file)
@@ -628,6 +628,12 @@ emit_clear:
                        break;
 
                /*
+                * BPF_ST NOSPEC (speculation barrier)
+                */
+               case BPF_ST | BPF_NOSPEC:
+                       break;
+
+               /*
                 * BPF_ST(X)
                 */
                case BPF_STX | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = src */
index 631a0d5..6b08866 100644 (file)
@@ -77,7 +77,7 @@
 #include "../../../../drivers/pci/pci.h"
 
 DEFINE_STATIC_KEY_FALSE(shared_processor);
-EXPORT_SYMBOL_GPL(shared_processor);
+EXPORT_SYMBOL(shared_processor);
 
 int CMO_PrPSP = -1;
 int CMO_SecPSP = -1;
index 81de865..e649742 100644 (file)
@@ -1251,6 +1251,10 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
                        return -1;
                break;
 
+       /* speculation barrier */
+       case BPF_ST | BPF_NOSPEC:
+               break;
+
        case BPF_ST | BPF_MEM | BPF_B:
        case BPF_ST | BPF_MEM | BPF_H:
        case BPF_ST | BPF_MEM | BPF_W:
index 87e3bf5..3af4131 100644 (file)
@@ -939,6 +939,10 @@ out_be:
                emit_ld(rd, 0, RV_REG_T1, ctx);
                break;
 
+       /* speculation barrier */
+       case BPF_ST | BPF_NOSPEC:
+               break;
+
        /* ST: *(size *)(dst + off) = imm */
        case BPF_ST | BPF_MEM | BPF_B:
                emit_imm(RV_REG_T1, imm, ctx);
index 660c799..e30d3fd 100644 (file)
@@ -11,6 +11,7 @@ UBSAN_SANITIZE := n
 KASAN_SANITIZE := n
 
 obj-y  := $(if $(CONFIG_KERNEL_UNCOMPRESSED),,decompressor.o) info.o
+obj-$(CONFIG_KERNEL_ZSTD) += clz_ctz.o
 obj-all := $(obj-y) piggy.o syms.o
 targets        := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2
 targets += vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo vmlinux.bin.lz4
diff --git a/arch/s390/boot/compressed/clz_ctz.c b/arch/s390/boot/compressed/clz_ctz.c
new file mode 100644 (file)
index 0000000..c3ebf24
--- /dev/null
@@ -0,0 +1,2 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "../../../../lib/clz_ctz.c"
index 7de253f..b881840 100644 (file)
@@ -335,7 +335,7 @@ CONFIG_L2TP_DEBUGFS=m
 CONFIG_L2TP_V3=y
 CONFIG_L2TP_IP=m
 CONFIG_L2TP_ETH=m
-CONFIG_BRIDGE=m
+CONFIG_BRIDGE=y
 CONFIG_BRIDGE_MRP=y
 CONFIG_VLAN_8021Q=m
 CONFIG_VLAN_8021Q_GVRP=y
index b671642..1667a3c 100644 (file)
@@ -325,7 +325,7 @@ CONFIG_L2TP_DEBUGFS=m
 CONFIG_L2TP_V3=y
 CONFIG_L2TP_IP=m
 CONFIG_L2TP_ETH=m
-CONFIG_BRIDGE=m
+CONFIG_BRIDGE=y
 CONFIG_BRIDGE_MRP=y
 CONFIG_VLAN_8021Q=m
 CONFIG_VLAN_8021Q_GVRP=y
index 9b4473f..161a9e1 100644 (file)
@@ -445,15 +445,15 @@ struct kvm_vcpu_stat {
        u64 instruction_sigp_init_cpu_reset;
        u64 instruction_sigp_cpu_reset;
        u64 instruction_sigp_unknown;
-       u64 diagnose_10;
-       u64 diagnose_44;
-       u64 diagnose_9c;
-       u64 diagnose_9c_ignored;
-       u64 diagnose_9c_forward;
-       u64 diagnose_258;
-       u64 diagnose_308;
-       u64 diagnose_500;
-       u64 diagnose_other;
+       u64 instruction_diagnose_10;
+       u64 instruction_diagnose_44;
+       u64 instruction_diagnose_9c;
+       u64 diag_9c_ignored;
+       u64 diag_9c_forward;
+       u64 instruction_diagnose_258;
+       u64 instruction_diagnose_308;
+       u64 instruction_diagnose_500;
+       u64 instruction_diagnose_other;
        u64 pfault_sync;
 };
 
index bff50b6..edf5ff1 100644 (file)
@@ -51,6 +51,7 @@ SECTIONS
 
        .rela.dyn ALIGN(8) : { *(.rela.dyn) }
        .got ALIGN(8)   : { *(.got .toc) }
+       .got.plt ALIGN(8) : { *(.got.plt) }
 
        _end = .;
        PROVIDE(end = .);
index d4fb336..4461ea1 100644 (file)
@@ -51,6 +51,7 @@ SECTIONS
 
        .rela.dyn ALIGN(8) : { *(.rela.dyn) }
        .got ALIGN(8)   : { *(.got .toc) }
+       .got.plt ALIGN(8) : { *(.got.plt) }
 
        _end = .;
        PROVIDE(end = .);
index 02c146f..807fa9d 100644 (file)
@@ -24,7 +24,7 @@ static int diag_release_pages(struct kvm_vcpu *vcpu)
 
        start = vcpu->run->s.regs.gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4];
        end = vcpu->run->s.regs.gprs[vcpu->arch.sie_block->ipa & 0xf] + PAGE_SIZE;
-       vcpu->stat.diagnose_10++;
+       vcpu->stat.instruction_diagnose_10++;
 
        if (start & ~PAGE_MASK || end & ~PAGE_MASK || start >= end
            || start < 2 * PAGE_SIZE)
@@ -74,7 +74,7 @@ static int __diag_page_ref_service(struct kvm_vcpu *vcpu)
 
        VCPU_EVENT(vcpu, 3, "diag page reference parameter block at 0x%llx",
                   vcpu->run->s.regs.gprs[rx]);
-       vcpu->stat.diagnose_258++;
+       vcpu->stat.instruction_diagnose_258++;
        if (vcpu->run->s.regs.gprs[rx] & 7)
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
        rc = read_guest(vcpu, vcpu->run->s.regs.gprs[rx], rx, &parm, sizeof(parm));
@@ -145,7 +145,7 @@ static int __diag_page_ref_service(struct kvm_vcpu *vcpu)
 static int __diag_time_slice_end(struct kvm_vcpu *vcpu)
 {
        VCPU_EVENT(vcpu, 5, "%s", "diag time slice end");
-       vcpu->stat.diagnose_44++;
+       vcpu->stat.instruction_diagnose_44++;
        kvm_vcpu_on_spin(vcpu, true);
        return 0;
 }
@@ -169,7 +169,7 @@ static int __diag_time_slice_end_directed(struct kvm_vcpu *vcpu)
        int tid;
 
        tid = vcpu->run->s.regs.gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4];
-       vcpu->stat.diagnose_9c++;
+       vcpu->stat.instruction_diagnose_9c++;
 
        /* yield to self */
        if (tid == vcpu->vcpu_id)
@@ -192,7 +192,7 @@ static int __diag_time_slice_end_directed(struct kvm_vcpu *vcpu)
                VCPU_EVENT(vcpu, 5,
                           "diag time slice end directed to %d: yield forwarded",
                           tid);
-               vcpu->stat.diagnose_9c_forward++;
+               vcpu->stat.diag_9c_forward++;
                return 0;
        }
 
@@ -203,7 +203,7 @@ static int __diag_time_slice_end_directed(struct kvm_vcpu *vcpu)
        return 0;
 no_yield:
        VCPU_EVENT(vcpu, 5, "diag time slice end directed to %d: ignored", tid);
-       vcpu->stat.diagnose_9c_ignored++;
+       vcpu->stat.diag_9c_ignored++;
        return 0;
 }
 
@@ -213,7 +213,7 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
        unsigned long subcode = vcpu->run->s.regs.gprs[reg] & 0xffff;
 
        VCPU_EVENT(vcpu, 3, "diag ipl functions, subcode %lx", subcode);
-       vcpu->stat.diagnose_308++;
+       vcpu->stat.instruction_diagnose_308++;
        switch (subcode) {
        case 3:
                vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR;
@@ -245,7 +245,7 @@ static int __diag_virtio_hypercall(struct kvm_vcpu *vcpu)
 {
        int ret;
 
-       vcpu->stat.diagnose_500++;
+       vcpu->stat.instruction_diagnose_500++;
        /* No virtio-ccw notification? Get out quickly. */
        if (!vcpu->kvm->arch.css_support ||
            (vcpu->run->s.regs.gprs[1] != KVM_S390_VIRTIO_CCW_NOTIFY))
@@ -299,7 +299,7 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu)
        case 0x500:
                return __diag_virtio_hypercall(vcpu);
        default:
-               vcpu->stat.diagnose_other++;
+               vcpu->stat.instruction_diagnose_other++;
                return -EOPNOTSUPP;
        }
 }
index b655a7d..4527ac7 100644 (file)
@@ -163,15 +163,15 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
        STATS_DESC_COUNTER(VCPU, instruction_sigp_init_cpu_reset),
        STATS_DESC_COUNTER(VCPU, instruction_sigp_cpu_reset),
        STATS_DESC_COUNTER(VCPU, instruction_sigp_unknown),
-       STATS_DESC_COUNTER(VCPU, diagnose_10),
-       STATS_DESC_COUNTER(VCPU, diagnose_44),
-       STATS_DESC_COUNTER(VCPU, diagnose_9c),
-       STATS_DESC_COUNTER(VCPU, diagnose_9c_ignored),
-       STATS_DESC_COUNTER(VCPU, diagnose_9c_forward),
-       STATS_DESC_COUNTER(VCPU, diagnose_258),
-       STATS_DESC_COUNTER(VCPU, diagnose_308),
-       STATS_DESC_COUNTER(VCPU, diagnose_500),
-       STATS_DESC_COUNTER(VCPU, diagnose_other),
+       STATS_DESC_COUNTER(VCPU, instruction_diagnose_10),
+       STATS_DESC_COUNTER(VCPU, instruction_diagnose_44),
+       STATS_DESC_COUNTER(VCPU, instruction_diagnose_9c),
+       STATS_DESC_COUNTER(VCPU, diag_9c_ignored),
+       STATS_DESC_COUNTER(VCPU, diag_9c_forward),
+       STATS_DESC_COUNTER(VCPU, instruction_diagnose_258),
+       STATS_DESC_COUNTER(VCPU, instruction_diagnose_308),
+       STATS_DESC_COUNTER(VCPU, instruction_diagnose_500),
+       STATS_DESC_COUNTER(VCPU, instruction_diagnose_other),
        STATS_DESC_COUNTER(VCPU, pfault_sync)
 };
 static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) ==
index 2ae419f..8841926 100644 (file)
@@ -1154,6 +1154,11 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
                }
                break;
        /*
+        * BPF_NOSPEC (speculation barrier)
+        */
+       case BPF_ST | BPF_NOSPEC:
+               break;
+       /*
         * BPF_ST(X)
         */
        case BPF_STX | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = src_reg */
index 45a0549..b683b69 100644 (file)
@@ -39,7 +39,6 @@ config SUPERH
        select HAVE_FUTEX_CMPXCHG if FUTEX
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_HW_BREAKPOINT
-       select HAVE_IDE if HAS_IOPORT_MAP
        select HAVE_IOREMAP_PROT if MMU && !X2TLB
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_GZIP
index c5fa793..f0c0f95 100644 (file)
@@ -19,7 +19,6 @@ config SPARC
        select OF
        select OF_PROMTREE
        select HAVE_ASM_MODVERSIONS
-       select HAVE_IDE
        select HAVE_ARCH_KGDB if !SMP || SPARC64
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARCH_SECCOMP if SPARC64
index 4b8d3c6..9a2f20c 100644 (file)
@@ -1287,6 +1287,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
                        return 1;
                break;
        }
+       /* speculation barrier */
+       case BPF_ST | BPF_NOSPEC:
+               break;
        /* ST: *(size *)(dst + off) = imm */
        case BPF_ST | BPF_MEM | BPF_W:
        case BPF_ST | BPF_MEM | BPF_H:
index 4927065..88fb922 100644 (file)
@@ -202,7 +202,6 @@ config X86
        select HAVE_FUNCTION_TRACER
        select HAVE_GCC_PLUGINS
        select HAVE_HW_BREAKPOINT
-       select HAVE_IDE
        select HAVE_IOREMAP_PROT
        select HAVE_IRQ_EXIT_ON_IRQ_STACK       if X86_64
        select HAVE_IRQ_TIME_ACCOUNTING
index b07592c..0b38f94 100644 (file)
@@ -2016,6 +2016,7 @@ static void kvm_hv_hypercall_set_result(struct kvm_vcpu *vcpu, u64 result)
 
 static int kvm_hv_hypercall_complete(struct kvm_vcpu *vcpu, u64 result)
 {
+       trace_kvm_hv_hypercall_done(result);
        kvm_hv_hypercall_set_result(vcpu, result);
        ++vcpu->stat.hypercalls;
        return kvm_skip_emulated_instruction(vcpu);
@@ -2139,6 +2140,7 @@ static bool hv_check_hypercall_access(struct kvm_vcpu_hv *hv_vcpu, u16 code)
 
 int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
 {
+       struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
        struct kvm_hv_hcall hc;
        u64 ret = HV_STATUS_SUCCESS;
 
@@ -2173,17 +2175,25 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
        hc.rep_idx = (hc.param >> HV_HYPERCALL_REP_START_OFFSET) & 0xfff;
        hc.rep = !!(hc.rep_cnt || hc.rep_idx);
 
-       if (hc.fast && is_xmm_fast_hypercall(&hc))
-               kvm_hv_hypercall_read_xmm(&hc);
-
        trace_kvm_hv_hypercall(hc.code, hc.fast, hc.rep_cnt, hc.rep_idx,
                               hc.ingpa, hc.outgpa);
 
-       if (unlikely(!hv_check_hypercall_access(to_hv_vcpu(vcpu), hc.code))) {
+       if (unlikely(!hv_check_hypercall_access(hv_vcpu, hc.code))) {
                ret = HV_STATUS_ACCESS_DENIED;
                goto hypercall_complete;
        }
 
+       if (hc.fast && is_xmm_fast_hypercall(&hc)) {
+               if (unlikely(hv_vcpu->enforce_cpuid &&
+                            !(hv_vcpu->cpuid_cache.features_edx &
+                              HV_X64_HYPERCALL_XMM_INPUT_AVAILABLE))) {
+                       kvm_queue_exception(vcpu, UD_VECTOR);
+                       return 1;
+               }
+
+               kvm_hv_hypercall_read_xmm(&hc);
+       }
+
        switch (hc.code) {
        case HVCALL_NOTIFY_LONG_SPIN_WAIT:
                if (unlikely(hc.rep)) {
index 698969e..ff005fe 100644 (file)
@@ -96,7 +96,7 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
 static void rtc_irq_eoi_tracking_reset(struct kvm_ioapic *ioapic)
 {
        ioapic->rtc_status.pending_eoi = 0;
-       bitmap_zero(ioapic->rtc_status.dest_map.map, KVM_MAX_VCPU_ID);
+       bitmap_zero(ioapic->rtc_status.dest_map.map, KVM_MAX_VCPU_ID + 1);
 }
 
 static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic);
index 6604017..11e4065 100644 (file)
@@ -43,13 +43,13 @@ struct kvm_vcpu;
 
 struct dest_map {
        /* vcpu bitmap where IRQ has been sent */
-       DECLARE_BITMAP(map, KVM_MAX_VCPU_ID);
+       DECLARE_BITMAP(map, KVM_MAX_VCPU_ID + 1);
 
        /*
         * Vector sent to a given vcpu, only valid when
         * the vcpu's bit in map is set
         */
-       u8 vectors[KVM_MAX_VCPU_ID];
+       u8 vectors[KVM_MAX_VCPU_ID + 1];
 };
 
 
index 66f7f5b..c4f4fa2 100644 (file)
@@ -1644,7 +1644,7 @@ static int is_empty_shadow_page(u64 *spt)
  * aggregate version in order to make the slab shrinker
  * faster
  */
-static inline void kvm_mod_used_mmu_pages(struct kvm *kvm, unsigned long nr)
+static inline void kvm_mod_used_mmu_pages(struct kvm *kvm, long nr)
 {
        kvm->arch.n_used_mmu_pages += nr;
        percpu_counter_add(&kvm_total_used_mmu_pages, nr);
index 1d01da6..a8ad78a 100644 (file)
@@ -646,7 +646,7 @@ out:
 void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
-       struct vmcb *vmcb = svm->vmcb;
+       struct vmcb *vmcb = svm->vmcb01.ptr;
        bool activated = kvm_vcpu_apicv_active(vcpu);
 
        if (!enable_apicv)
index 3bd09c5..61738ff 100644 (file)
@@ -515,7 +515,7 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm)
         * Also covers avic_vapic_bar, avic_backing_page, avic_logical_id,
         * avic_physical_id.
         */
-       WARN_ON(svm->vmcb01.ptr->control.int_ctl & AVIC_ENABLE_MASK);
+       WARN_ON(kvm_apicv_activated(svm->vcpu.kvm));
 
        /* Copied from vmcb01.  msrpm_base can be overwritten later.  */
        svm->vmcb->control.nested_ctl = svm->vmcb01.ptr->control.nested_ctl;
@@ -702,8 +702,8 @@ out:
 }
 
 /* Copy state save area fields which are handled by VMRUN */
-void svm_copy_vmrun_state(struct vmcb_save_area *from_save,
-                         struct vmcb_save_area *to_save)
+void svm_copy_vmrun_state(struct vmcb_save_area *to_save,
+                         struct vmcb_save_area *from_save)
 {
        to_save->es = from_save->es;
        to_save->cs = from_save->cs;
@@ -722,7 +722,7 @@ void svm_copy_vmrun_state(struct vmcb_save_area *from_save,
        to_save->cpl = 0;
 }
 
-void nested_svm_vmloadsave(struct vmcb *from_vmcb, struct vmcb *to_vmcb)
+void svm_copy_vmloadsave_state(struct vmcb *to_vmcb, struct vmcb *from_vmcb)
 {
        to_vmcb->save.fs = from_vmcb->save.fs;
        to_vmcb->save.gs = from_vmcb->save.gs;
@@ -1385,7 +1385,7 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
 
        svm->nested.vmcb12_gpa = kvm_state->hdr.svm.vmcb_pa;
 
-       svm_copy_vmrun_state(save, &svm->vmcb01.ptr->save);
+       svm_copy_vmrun_state(&svm->vmcb01.ptr->save, save);
        nested_load_control_from_vmcb12(svm, ctl);
 
        svm_switch_vmcb(svm, &svm->nested.vmcb02);
index 6710d9e..7fbce34 100644 (file)
@@ -64,6 +64,7 @@ static DEFINE_MUTEX(sev_bitmap_lock);
 unsigned int max_sev_asid;
 static unsigned int min_sev_asid;
 static unsigned long sev_me_mask;
+static unsigned int nr_asids;
 static unsigned long *sev_asid_bitmap;
 static unsigned long *sev_reclaim_asid_bitmap;
 
@@ -78,11 +79,11 @@ struct enc_region {
 /* Called with the sev_bitmap_lock held, or on shutdown  */
 static int sev_flush_asids(int min_asid, int max_asid)
 {
-       int ret, pos, error = 0;
+       int ret, asid, error = 0;
 
        /* Check if there are any ASIDs to reclaim before performing a flush */
-       pos = find_next_bit(sev_reclaim_asid_bitmap, max_asid, min_asid);
-       if (pos >= max_asid)
+       asid = find_next_bit(sev_reclaim_asid_bitmap, nr_asids, min_asid);
+       if (asid > max_asid)
                return -EBUSY;
 
        /*
@@ -115,15 +116,15 @@ static bool __sev_recycle_asids(int min_asid, int max_asid)
 
        /* The flush process will flush all reclaimable SEV and SEV-ES ASIDs */
        bitmap_xor(sev_asid_bitmap, sev_asid_bitmap, sev_reclaim_asid_bitmap,
-                  max_sev_asid);
-       bitmap_zero(sev_reclaim_asid_bitmap, max_sev_asid);
+                  nr_asids);
+       bitmap_zero(sev_reclaim_asid_bitmap, nr_asids);
 
        return true;
 }
 
 static int sev_asid_new(struct kvm_sev_info *sev)
 {
-       int pos, min_asid, max_asid, ret;
+       int asid, min_asid, max_asid, ret;
        bool retry = true;
        enum misc_res_type type;
 
@@ -143,11 +144,11 @@ static int sev_asid_new(struct kvm_sev_info *sev)
         * SEV-enabled guests must use asid from min_sev_asid to max_sev_asid.
         * SEV-ES-enabled guest can use from 1 to min_sev_asid - 1.
         */
-       min_asid = sev->es_active ? 0 : min_sev_asid - 1;
+       min_asid = sev->es_active ? 1 : min_sev_asid;
        max_asid = sev->es_active ? min_sev_asid - 1 : max_sev_asid;
 again:
-       pos = find_next_zero_bit(sev_asid_bitmap, max_sev_asid, min_asid);
-       if (pos >= max_asid) {
+       asid = find_next_zero_bit(sev_asid_bitmap, max_asid + 1, min_asid);
+       if (asid > max_asid) {
                if (retry && __sev_recycle_asids(min_asid, max_asid)) {
                        retry = false;
                        goto again;
@@ -157,11 +158,11 @@ again:
                goto e_uncharge;
        }
 
-       __set_bit(pos, sev_asid_bitmap);
+       __set_bit(asid, sev_asid_bitmap);
 
        mutex_unlock(&sev_bitmap_lock);
 
-       return pos + 1;
+       return asid;
 e_uncharge:
        misc_cg_uncharge(type, sev->misc_cg, 1);
        put_misc_cg(sev->misc_cg);
@@ -179,17 +180,16 @@ static int sev_get_asid(struct kvm *kvm)
 static void sev_asid_free(struct kvm_sev_info *sev)
 {
        struct svm_cpu_data *sd;
-       int cpu, pos;
+       int cpu;
        enum misc_res_type type;
 
        mutex_lock(&sev_bitmap_lock);
 
-       pos = sev->asid - 1;
-       __set_bit(pos, sev_reclaim_asid_bitmap);
+       __set_bit(sev->asid, sev_reclaim_asid_bitmap);
 
        for_each_possible_cpu(cpu) {
                sd = per_cpu(svm_data, cpu);
-               sd->sev_vmcbs[pos] = NULL;
+               sd->sev_vmcbs[sev->asid] = NULL;
        }
 
        mutex_unlock(&sev_bitmap_lock);
@@ -1857,12 +1857,17 @@ void __init sev_hardware_setup(void)
        min_sev_asid = edx;
        sev_me_mask = 1UL << (ebx & 0x3f);
 
-       /* Initialize SEV ASID bitmaps */
-       sev_asid_bitmap = bitmap_zalloc(max_sev_asid, GFP_KERNEL);
+       /*
+        * Initialize SEV ASID bitmaps. Allocate space for ASID 0 in the bitmap,
+        * even though it's never used, so that the bitmap is indexed by the
+        * actual ASID.
+        */
+       nr_asids = max_sev_asid + 1;
+       sev_asid_bitmap = bitmap_zalloc(nr_asids, GFP_KERNEL);
        if (!sev_asid_bitmap)
                goto out;
 
-       sev_reclaim_asid_bitmap = bitmap_zalloc(max_sev_asid, GFP_KERNEL);
+       sev_reclaim_asid_bitmap = bitmap_zalloc(nr_asids, GFP_KERNEL);
        if (!sev_reclaim_asid_bitmap) {
                bitmap_free(sev_asid_bitmap);
                sev_asid_bitmap = NULL;
@@ -1907,7 +1912,7 @@ void sev_hardware_teardown(void)
                return;
 
        /* No need to take sev_bitmap_lock, all VMs have been destroyed. */
-       sev_flush_asids(0, max_sev_asid);
+       sev_flush_asids(1, max_sev_asid);
 
        bitmap_free(sev_asid_bitmap);
        bitmap_free(sev_reclaim_asid_bitmap);
@@ -1921,7 +1926,7 @@ int sev_cpu_init(struct svm_cpu_data *sd)
        if (!sev_enabled)
                return 0;
 
-       sd->sev_vmcbs = kcalloc(max_sev_asid + 1, sizeof(void *), GFP_KERNEL);
+       sd->sev_vmcbs = kcalloc(nr_asids, sizeof(void *), GFP_KERNEL);
        if (!sd->sev_vmcbs)
                return -ENOMEM;
 
index 664d20f..e8ccab5 100644 (file)
@@ -1406,8 +1406,6 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)
                goto error_free_vmsa_page;
        }
 
-       svm_vcpu_init_msrpm(vcpu, svm->msrpm);
-
        svm->vmcb01.ptr = page_address(vmcb01_page);
        svm->vmcb01.pa = __sme_set(page_to_pfn(vmcb01_page) << PAGE_SHIFT);
 
@@ -1419,6 +1417,8 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)
        svm_switch_vmcb(svm, &svm->vmcb01);
        init_vmcb(vcpu);
 
+       svm_vcpu_init_msrpm(vcpu, svm->msrpm);
+
        svm_init_osvw(vcpu);
        vcpu->arch.microcode_version = 0x01000065;
 
@@ -1568,8 +1568,11 @@ static void svm_set_vintr(struct vcpu_svm *svm)
 {
        struct vmcb_control_area *control;
 
-       /* The following fields are ignored when AVIC is enabled */
-       WARN_ON(kvm_vcpu_apicv_active(&svm->vcpu));
+       /*
+        * The following fields are ignored when AVIC is enabled
+        */
+       WARN_ON(kvm_apicv_activated(svm->vcpu.kvm));
+
        svm_set_intercept(svm, INTERCEPT_VINTR);
 
        /*
@@ -2147,11 +2150,12 @@ static int vmload_vmsave_interception(struct kvm_vcpu *vcpu, bool vmload)
        ret = kvm_skip_emulated_instruction(vcpu);
 
        if (vmload) {
-               nested_svm_vmloadsave(vmcb12, svm->vmcb);
+               svm_copy_vmloadsave_state(svm->vmcb, vmcb12);
                svm->sysenter_eip_hi = 0;
                svm->sysenter_esp_hi = 0;
-       } else
-               nested_svm_vmloadsave(svm->vmcb, vmcb12);
+       } else {
+               svm_copy_vmloadsave_state(vmcb12, svm->vmcb);
+       }
 
        kvm_vcpu_unmap(vcpu, &map, true);
 
@@ -4344,8 +4348,8 @@ static int svm_enter_smm(struct kvm_vcpu *vcpu, char *smstate)
 
                BUILD_BUG_ON(offsetof(struct vmcb, save) != 0x400);
 
-               svm_copy_vmrun_state(&svm->vmcb01.ptr->save,
-                                    map_save.hva + 0x400);
+               svm_copy_vmrun_state(map_save.hva + 0x400,
+                                    &svm->vmcb01.ptr->save);
 
                kvm_vcpu_unmap(vcpu, &map_save, true);
        }
@@ -4393,8 +4397,8 @@ static int svm_leave_smm(struct kvm_vcpu *vcpu, const char *smstate)
                                         &map_save) == -EINVAL)
                                return 1;
 
-                       svm_copy_vmrun_state(map_save.hva + 0x400,
-                                            &svm->vmcb01.ptr->save);
+                       svm_copy_vmrun_state(&svm->vmcb01.ptr->save,
+                                            map_save.hva + 0x400);
 
                        kvm_vcpu_unmap(vcpu, &map_save, true);
                }
index 7e20907..bd0fe94 100644 (file)
@@ -464,9 +464,9 @@ void svm_leave_nested(struct vcpu_svm *svm);
 void svm_free_nested(struct vcpu_svm *svm);
 int svm_allocate_nested(struct vcpu_svm *svm);
 int nested_svm_vmrun(struct kvm_vcpu *vcpu);
-void svm_copy_vmrun_state(struct vmcb_save_area *from_save,
-                         struct vmcb_save_area *to_save);
-void nested_svm_vmloadsave(struct vmcb *from_vmcb, struct vmcb *to_vmcb);
+void svm_copy_vmrun_state(struct vmcb_save_area *to_save,
+                         struct vmcb_save_area *from_save);
+void svm_copy_vmloadsave_state(struct vmcb *to_vmcb, struct vmcb *from_vmcb);
 int nested_svm_vmexit(struct vcpu_svm *svm);
 
 static inline int nested_svm_simple_vmexit(struct vcpu_svm *svm, u32 exit_code)
index 9b9a55a..c53b8bf 100644 (file)
@@ -89,7 +89,7 @@ static inline void svm_hv_vmcb_dirty_nested_enlightenments(
         * as we mark it dirty unconditionally towards end of vcpu
         * init phase.
         */
-       if (vmcb && vmcb_is_clean(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS) &&
+       if (vmcb_is_clean(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS) &&
            hve->hv_enlightenments_control.msr_bitmap)
                vmcb_mark_dirty(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS);
 }
index b484141..03ebe36 100644 (file)
@@ -92,6 +92,21 @@ TRACE_EVENT(kvm_hv_hypercall,
                  __entry->outgpa)
 );
 
+TRACE_EVENT(kvm_hv_hypercall_done,
+       TP_PROTO(u64 result),
+       TP_ARGS(result),
+
+       TP_STRUCT__entry(
+               __field(__u64, result)
+       ),
+
+       TP_fast_assign(
+               __entry->result = result;
+       ),
+
+       TP_printk("result 0x%llx", __entry->result)
+);
+
 /*
  * Tracepoint for Xen hypercall.
  */
index a4fd106..e5d5c5e 100644 (file)
@@ -3407,7 +3407,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                        return 1;
                break;
        case MSR_KVM_ASYNC_PF_ACK:
-               if (!guest_pv_has(vcpu, KVM_FEATURE_ASYNC_PF))
+               if (!guest_pv_has(vcpu, KVM_FEATURE_ASYNC_PF_INT))
                        return 1;
                if (data & 0x1) {
                        vcpu->arch.apf.pageready_pending = false;
@@ -3746,7 +3746,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                msr_info->data = vcpu->arch.apf.msr_int_val;
                break;
        case MSR_KVM_ASYNC_PF_ACK:
-               if (!guest_pv_has(vcpu, KVM_FEATURE_ASYNC_PF))
+               if (!guest_pv_has(vcpu, KVM_FEATURE_ASYNC_PF_INT))
                        return 1;
 
                msr_info->data = 0;
@@ -4358,8 +4358,17 @@ static int kvm_cpu_accept_dm_intr(struct kvm_vcpu *vcpu)
 
 static int kvm_vcpu_ready_for_interrupt_injection(struct kvm_vcpu *vcpu)
 {
-       return kvm_arch_interrupt_allowed(vcpu) &&
-               kvm_cpu_accept_dm_intr(vcpu);
+       /*
+        * Do not cause an interrupt window exit if an exception
+        * is pending or an event needs reinjection; userspace
+        * might want to inject the interrupt manually using KVM_SET_REGS
+        * or KVM_SET_SREGS.  For that to work, we must be at an
+        * instruction boundary and with no events half-injected.
+        */
+       return (kvm_arch_interrupt_allowed(vcpu) &&
+               kvm_cpu_accept_dm_intr(vcpu) &&
+               !kvm_event_needs_reinjection(vcpu) &&
+               !vcpu->arch.exception.pending);
 }
 
 static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
index 4b95145..16d76f8 100644 (file)
@@ -1219,6 +1219,13 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
                        }
                        break;
 
+                       /* speculation barrier */
+               case BPF_ST | BPF_NOSPEC:
+                       if (boot_cpu_has(X86_FEATURE_XMM2))
+                               /* Emit 'lfence' */
+                               EMIT3(0x0F, 0xAE, 0xE8);
+                       break;
+
                        /* ST: *(u8*)(dst_reg + off) = imm */
                case BPF_ST | BPF_MEM | BPF_B:
                        if (is_ereg(dst_reg))
index 3da88de..3bfda5f 100644 (file)
@@ -1886,6 +1886,12 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
                        i++;
                        break;
                }
+               /* speculation barrier */
+               case BPF_ST | BPF_NOSPEC:
+                       if (boot_cpu_has(X86_FEATURE_XMM2))
+                               /* Emit 'lfence' */
+                               EMIT3(0x0F, 0xAE, 0xE8);
+                       break;
                /* ST: *(u8*)(dst_reg + off) = imm */
                case BPF_ST | BPF_MEM | BPF_H:
                case BPF_ST | BPF_MEM | BPF_B:
index 2332b21..3878880 100644 (file)
@@ -327,7 +327,6 @@ config XTENSA_PLATFORM_ISS
 
 config XTENSA_PLATFORM_XT2000
        bool "XT2000"
-       select HAVE_IDE
        help
          XT2000 is the name of Tensilica's feature-rich emulation platform.
          This hardware is capable of running a full Linux distribution.
index c2d6bc8..5fac375 100644 (file)
@@ -1440,16 +1440,17 @@ static int iocg_wake_fn(struct wait_queue_entry *wq_entry, unsigned mode,
                return -1;
 
        iocg_commit_bio(ctx->iocg, wait->bio, wait->abs_cost, cost);
+       wait->committed = true;
 
        /*
         * autoremove_wake_function() removes the wait entry only when it
-        * actually changed the task state.  We want the wait always
-        * removed.  Remove explicitly and use default_wake_function().
+        * actually changed the task state. We want the wait always removed.
+        * Remove explicitly and use default_wake_function(). Note that the
+        * order of operations is important as finish_wait() tests whether
+        * @wq_entry is removed without grabbing the lock.
         */
-       list_del_init(&wq_entry->entry);
-       wait->committed = true;
-
        default_wake_function(wq_entry, mode, flags, key);
+       list_del_init_careful(&wq_entry->entry);
        return 0;
 }
 
index c838d81..0f006ca 100644 (file)
@@ -515,17 +515,6 @@ void blk_mq_sched_insert_requests(struct blk_mq_hw_ctx *hctx,
        percpu_ref_put(&q->q_usage_counter);
 }
 
-static void blk_mq_sched_free_tags(struct blk_mq_tag_set *set,
-                                  struct blk_mq_hw_ctx *hctx,
-                                  unsigned int hctx_idx)
-{
-       if (hctx->sched_tags) {
-               blk_mq_free_rqs(set, hctx->sched_tags, hctx_idx);
-               blk_mq_free_rq_map(hctx->sched_tags, set->flags);
-               hctx->sched_tags = NULL;
-       }
-}
-
 static int blk_mq_sched_alloc_tags(struct request_queue *q,
                                   struct blk_mq_hw_ctx *hctx,
                                   unsigned int hctx_idx)
@@ -539,8 +528,10 @@ static int blk_mq_sched_alloc_tags(struct request_queue *q,
                return -ENOMEM;
 
        ret = blk_mq_alloc_rqs(set, hctx->sched_tags, hctx_idx, q->nr_requests);
-       if (ret)
-               blk_mq_sched_free_tags(set, hctx, hctx_idx);
+       if (ret) {
+               blk_mq_free_rq_map(hctx->sched_tags, set->flags);
+               hctx->sched_tags = NULL;
+       }
 
        return ret;
 }
index af4d2ab..298ee78 100644 (file)
@@ -1079,10 +1079,9 @@ static void disk_release(struct device *dev)
        disk_release_events(disk);
        kfree(disk->random);
        xa_destroy(&disk->part_tbl);
-       bdput(disk->part0);
        if (test_bit(GD_QUEUE_REF, &disk->state) && disk->queue)
                blk_put_queue(disk->queue);
-       kfree(disk);
+       bdput(disk->part0);     /* frees the disk */
 }
 struct class block_class = {
        .name           = "block",
index 5fca182..550b908 100644 (file)
@@ -9,6 +9,42 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
+struct pch_fivr_resp {
+       u64 status;
+       u64 result;
+};
+
+static int pch_fivr_read(acpi_handle handle, char *method, struct pch_fivr_resp *fivr_resp)
+{
+       struct acpi_buffer resp = { sizeof(struct pch_fivr_resp), fivr_resp};
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_buffer format = { sizeof("NN"), "NN" };
+       union acpi_object *obj;
+       acpi_status status;
+       int ret = -EFAULT;
+
+       status = acpi_evaluate_object(handle, method, NULL, &buffer);
+       if (ACPI_FAILURE(status))
+               return ret;
+
+       obj = buffer.pointer;
+       if (!obj || obj->type != ACPI_TYPE_PACKAGE)
+               goto release_buffer;
+
+       status = acpi_extract_package(obj, &format, &resp);
+       if (ACPI_FAILURE(status))
+               goto release_buffer;
+
+       if (fivr_resp->status)
+               goto release_buffer;
+
+       ret = 0;
+
+release_buffer:
+       kfree(buffer.pointer);
+       return ret;
+}
+
 /*
  * Presentation of attributes which are defined for INT1045
  * They are:
@@ -23,15 +59,14 @@ static ssize_t name##_show(struct device *dev,\
                           char *buf)\
 {\
        struct acpi_device *acpi_dev = dev_get_drvdata(dev);\
-       unsigned long long val;\
-       acpi_status status;\
+       struct pch_fivr_resp fivr_resp;\
+       int status;\
 \
-       status = acpi_evaluate_integer(acpi_dev->handle, #method,\
-                                      NULL, &val);\
-       if (ACPI_SUCCESS(status))\
-               return sprintf(buf, "%d\n", (int)val);\
-       else\
-               return -EINVAL;\
+       status = pch_fivr_read(acpi_dev->handle, #method, &fivr_resp);\
+       if (status)\
+               return status;\
+\
+       return sprintf(buf, "%llu\n", fivr_resp.result);\
 }
 
 #define PCH_FIVR_STORE(name, method) \
index dc01fb5..ee78a21 100644 (file)
@@ -423,13 +423,6 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi,
        }
 }
 
-static bool irq_is_legacy(struct acpi_resource_irq *irq)
-{
-       return irq->triggering == ACPI_EDGE_SENSITIVE &&
-               irq->polarity == ACPI_ACTIVE_HIGH &&
-               irq->shareable == ACPI_EXCLUSIVE;
-}
-
 /**
  * acpi_dev_resource_interrupt - Extract ACPI interrupt resource information.
  * @ares: Input ACPI resource object.
@@ -468,7 +461,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
                }
                acpi_dev_get_irqresource(res, irq->interrupts[index],
                                         irq->triggering, irq->polarity,
-                                        irq->shareable, irq_is_legacy(irq));
+                                        irq->shareable, true);
                break;
        case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
                ext_irq = &ares->data.extended_irq;
index 1c50780..fbdbef0 100644 (file)
@@ -378,19 +378,25 @@ static int lps0_device_attach(struct acpi_device *adev,
                 * AMDI0006:
                 * - should use rev_id 0x0
                 * - function mask = 0x3: Should use Microsoft method
+                * AMDI0007:
+                * - Should use rev_id 0x2
+                * - Should only use AMD method
                 */
                const char *hid = acpi_device_hid(adev);
-               rev_id = 0;
+               rev_id = strcmp(hid, "AMDI0007") ? 0 : 2;
                lps0_dsm_func_mask = validate_dsm(adev->handle,
                                        ACPI_LPS0_DSM_UUID_AMD, rev_id, &lps0_dsm_guid);
                lps0_dsm_func_mask_microsoft = validate_dsm(adev->handle,
-                                       ACPI_LPS0_DSM_UUID_MICROSOFT, rev_id,
+                                       ACPI_LPS0_DSM_UUID_MICROSOFT, 0,
                                        &lps0_dsm_guid_microsoft);
                if (lps0_dsm_func_mask > 0x3 && (!strcmp(hid, "AMD0004") ||
                                                 !strcmp(hid, "AMDI0005"))) {
                        lps0_dsm_func_mask = (lps0_dsm_func_mask << 1) | 0x1;
                        acpi_handle_debug(adev->handle, "_DSM UUID %s: Adjusted function mask: 0x%x\n",
                                          ACPI_LPS0_DSM_UUID_AMD, lps0_dsm_func_mask);
+               } else if (lps0_dsm_func_mask_microsoft > 0 && !strcmp(hid, "AMDI0007")) {
+                       lps0_dsm_func_mask_microsoft = -EINVAL;
+                       acpi_handle_debug(adev->handle, "_DSM Using AMD method\n");
                }
        } else {
                rev_id = 1;
index ae7189d..b71ea4a 100644 (file)
@@ -637,6 +637,20 @@ unsigned int ata_sff_data_xfer32(struct ata_queued_cmd *qc, unsigned char *buf,
 }
 EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
 
+static void ata_pio_xfer(struct ata_queued_cmd *qc, struct page *page,
+               unsigned int offset, size_t xfer_size)
+{
+       bool do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+       unsigned char *buf;
+
+       buf = kmap_atomic(page);
+       qc->ap->ops->sff_data_xfer(qc, buf + offset, xfer_size, do_write);
+       kunmap_atomic(buf);
+
+       if (!do_write && !PageSlab(page))
+               flush_dcache_page(page);
+}
+
 /**
  *     ata_pio_sector - Transfer a sector of data.
  *     @qc: Command on going
@@ -648,11 +662,9 @@ EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
  */
 static void ata_pio_sector(struct ata_queued_cmd *qc)
 {
-       int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
        struct ata_port *ap = qc->ap;
        struct page *page;
        unsigned int offset;
-       unsigned char *buf;
 
        if (!qc->cursg) {
                qc->curbytes = qc->nbytes;
@@ -670,13 +682,20 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
 
        DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
 
-       /* do the actual data transfer */
-       buf = kmap_atomic(page);
-       ap->ops->sff_data_xfer(qc, buf + offset, qc->sect_size, do_write);
-       kunmap_atomic(buf);
+       /*
+        * Split the transfer when it splits a page boundary.  Note that the
+        * split still has to be dword aligned like all ATA data transfers.
+        */
+       WARN_ON_ONCE(offset % 4);
+       if (offset + qc->sect_size > PAGE_SIZE) {
+               unsigned int split_len = PAGE_SIZE - offset;
 
-       if (!do_write && !PageSlab(page))
-               flush_dcache_page(page);
+               ata_pio_xfer(qc, page, offset, split_len);
+               ata_pio_xfer(qc, nth_page(page, 1), 0,
+                            qc->sect_size - split_len);
+       } else {
+               ata_pio_xfer(qc, page, offset, qc->sect_size);
+       }
 
        qc->curbytes += qc->sect_size;
        qc->cursg_ofs += qc->sect_size;
index f37b9e3..f0cdff0 100644 (file)
 
 static DEFINE_IDR(loop_index_idr);
 static DEFINE_MUTEX(loop_ctl_mutex);
+static DEFINE_MUTEX(loop_validate_mutex);
+
+/**
+ * loop_global_lock_killable() - take locks for safe loop_validate_file() test
+ *
+ * @lo: struct loop_device
+ * @global: true if @lo is about to bind another "struct loop_device", false otherwise
+ *
+ * Returns 0 on success, -EINTR otherwise.
+ *
+ * Since loop_validate_file() traverses on other "struct loop_device" if
+ * is_loop_device() is true, we need a global lock for serializing concurrent
+ * loop_configure()/loop_change_fd()/__loop_clr_fd() calls.
+ */
+static int loop_global_lock_killable(struct loop_device *lo, bool global)
+{
+       int err;
+
+       if (global) {
+               err = mutex_lock_killable(&loop_validate_mutex);
+               if (err)
+                       return err;
+       }
+       err = mutex_lock_killable(&lo->lo_mutex);
+       if (err && global)
+               mutex_unlock(&loop_validate_mutex);
+       return err;
+}
+
+/**
+ * loop_global_unlock() - release locks taken by loop_global_lock_killable()
+ *
+ * @lo: struct loop_device
+ * @global: true if @lo was about to bind another "struct loop_device", false otherwise
+ */
+static void loop_global_unlock(struct loop_device *lo, bool global)
+{
+       mutex_unlock(&lo->lo_mutex);
+       if (global)
+               mutex_unlock(&loop_validate_mutex);
+}
 
 static int max_part;
 static int part_shift;
@@ -672,13 +713,15 @@ static int loop_validate_file(struct file *file, struct block_device *bdev)
        while (is_loop_device(f)) {
                struct loop_device *l;
 
+               lockdep_assert_held(&loop_validate_mutex);
                if (f->f_mapping->host->i_rdev == bdev->bd_dev)
                        return -EBADF;
 
                l = I_BDEV(f->f_mapping->host)->bd_disk->private_data;
-               if (l->lo_state != Lo_bound) {
+               if (l->lo_state != Lo_bound)
                        return -EINVAL;
-               }
+               /* Order wrt setting lo->lo_backing_file in loop_configure(). */
+               rmb();
                f = l->lo_backing_file;
        }
        if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
@@ -697,13 +740,18 @@ static int loop_validate_file(struct file *file, struct block_device *bdev)
 static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
                          unsigned int arg)
 {
-       struct file     *file = NULL, *old_file;
-       int             error;
-       bool            partscan;
+       struct file *file = fget(arg);
+       struct file *old_file;
+       int error;
+       bool partscan;
+       bool is_loop;
 
-       error = mutex_lock_killable(&lo->lo_mutex);
+       if (!file)
+               return -EBADF;
+       is_loop = is_loop_device(file);
+       error = loop_global_lock_killable(lo, is_loop);
        if (error)
-               return error;
+               goto out_putf;
        error = -ENXIO;
        if (lo->lo_state != Lo_bound)
                goto out_err;
@@ -713,11 +761,6 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
        if (!(lo->lo_flags & LO_FLAGS_READ_ONLY))
                goto out_err;
 
-       error = -EBADF;
-       file = fget(arg);
-       if (!file)
-               goto out_err;
-
        error = loop_validate_file(file, bdev);
        if (error)
                goto out_err;
@@ -740,7 +783,16 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
        loop_update_dio(lo);
        blk_mq_unfreeze_queue(lo->lo_queue);
        partscan = lo->lo_flags & LO_FLAGS_PARTSCAN;
-       mutex_unlock(&lo->lo_mutex);
+       loop_global_unlock(lo, is_loop);
+
+       /*
+        * Flush loop_validate_file() before fput(), for l->lo_backing_file
+        * might be pointing at old_file which might be the last reference.
+        */
+       if (!is_loop) {
+               mutex_lock(&loop_validate_mutex);
+               mutex_unlock(&loop_validate_mutex);
+       }
        /*
         * We must drop file reference outside of lo_mutex as dropping
         * the file ref can take open_mutex which creates circular locking
@@ -752,9 +804,9 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
        return 0;
 
 out_err:
-       mutex_unlock(&lo->lo_mutex);
-       if (file)
-               fput(file);
+       loop_global_unlock(lo, is_loop);
+out_putf:
+       fput(file);
        return error;
 }
 
@@ -1136,22 +1188,22 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
                          struct block_device *bdev,
                          const struct loop_config *config)
 {
-       struct file     *file;
-       struct inode    *inode;
+       struct file *file = fget(config->fd);
+       struct inode *inode;
        struct address_space *mapping;
-       int             error;
-       loff_t          size;
-       bool            partscan;
-       unsigned short  bsize;
+       int error;
+       loff_t size;
+       bool partscan;
+       unsigned short bsize;
+       bool is_loop;
+
+       if (!file)
+               return -EBADF;
+       is_loop = is_loop_device(file);
 
        /* This is safe, since we have a reference from open(). */
        __module_get(THIS_MODULE);
 
-       error = -EBADF;
-       file = fget(config->fd);
-       if (!file)
-               goto out;
-
        /*
         * If we don't hold exclusive handle for the device, upgrade to it
         * here to avoid changing device under exclusive owner.
@@ -1162,7 +1214,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
                        goto out_putf;
        }
 
-       error = mutex_lock_killable(&lo->lo_mutex);
+       error = loop_global_lock_killable(lo, is_loop);
        if (error)
                goto out_bdev;
 
@@ -1242,6 +1294,9 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
        size = get_loop_size(lo, file);
        loop_set_size(lo, size);
 
+       /* Order wrt reading lo_state in loop_validate_file(). */
+       wmb();
+
        lo->lo_state = Lo_bound;
        if (part_shift)
                lo->lo_flags |= LO_FLAGS_PARTSCAN;
@@ -1253,7 +1308,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
         * put /dev/loopXX inode. Later in __loop_clr_fd() we bdput(bdev).
         */
        bdgrab(bdev);
-       mutex_unlock(&lo->lo_mutex);
+       loop_global_unlock(lo, is_loop);
        if (partscan)
                loop_reread_partitions(lo);
        if (!(mode & FMODE_EXCL))
@@ -1261,13 +1316,12 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
        return 0;
 
 out_unlock:
-       mutex_unlock(&lo->lo_mutex);
+       loop_global_unlock(lo, is_loop);
 out_bdev:
        if (!(mode & FMODE_EXCL))
                bd_abort_claiming(bdev, loop_configure);
 out_putf:
        fput(file);
-out:
        /* This is safe: open() is still holding a reference. */
        module_put(THIS_MODULE);
        return error;
@@ -1283,6 +1337,18 @@ static int __loop_clr_fd(struct loop_device *lo, bool release)
        int lo_number;
        struct loop_worker *pos, *worker;
 
+       /*
+        * Flush loop_configure() and loop_change_fd(). It is acceptable for
+        * loop_validate_file() to succeed, for actual clear operation has not
+        * started yet.
+        */
+       mutex_lock(&loop_validate_mutex);
+       mutex_unlock(&loop_validate_mutex);
+       /*
+        * loop_validate_file() now fails because l->lo_state != Lo_bound
+        * became visible.
+        */
+
        mutex_lock(&lo->lo_mutex);
        if (WARN_ON_ONCE(lo->lo_state != Lo_rundown)) {
                err = -ENXIO;
index be16076..f9d5b73 100644 (file)
@@ -92,13 +92,20 @@ int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
 }
 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional);
 
+static void devm_clk_bulk_release_all(struct device *dev, void *res)
+{
+       struct clk_bulk_devres *devres = res;
+
+       clk_bulk_put_all(devres->num_clks, devres->clks);
+}
+
 int __must_check devm_clk_bulk_get_all(struct device *dev,
                                       struct clk_bulk_data **clks)
 {
        struct clk_bulk_devres *devres;
        int ret;
 
-       devres = devres_alloc(devm_clk_bulk_release,
+       devres = devres_alloc(devm_clk_bulk_release_all,
                              sizeof(*devres), GFP_KERNEL);
        if (!devres)
                return -ENOMEM;
index 18117ce..5c75e3d 100644 (file)
@@ -526,7 +526,7 @@ struct stm32f4_pll {
 
 struct stm32f4_pll_post_div_data {
        int idx;
-       u8 pll_num;
+       int pll_idx;
        const char *name;
        const char *parent;
        u8 flag;
@@ -557,13 +557,13 @@ static const struct clk_div_table post_divr_table[] = {
 
 #define MAX_POST_DIV 3
 static const struct stm32f4_pll_post_div_data  post_div_data[MAX_POST_DIV] = {
-       { CLK_I2SQ_PDIV, PLL_I2S, "plli2s-q-div", "plli2s-q",
+       { CLK_I2SQ_PDIV, PLL_VCO_I2S, "plli2s-q-div", "plli2s-q",
                CLK_SET_RATE_PARENT, STM32F4_RCC_DCKCFGR, 0, 5, 0, NULL},
 
-       { CLK_SAIQ_PDIV, PLL_SAI, "pllsai-q-div", "pllsai-q",
+       { CLK_SAIQ_PDIV, PLL_VCO_SAI, "pllsai-q-div", "pllsai-q",
                CLK_SET_RATE_PARENT, STM32F4_RCC_DCKCFGR, 8, 5, 0, NULL },
 
-       { NO_IDX, PLL_SAI, "pllsai-r-div", "pllsai-r", CLK_SET_RATE_PARENT,
+       { NO_IDX, PLL_VCO_SAI, "pllsai-r-div", "pllsai-r", CLK_SET_RATE_PARENT,
                STM32F4_RCC_DCKCFGR, 16, 2, 0, post_divr_table },
 };
 
@@ -1774,7 +1774,7 @@ static void __init stm32f4_rcc_init(struct device_node *np)
                                post_div->width,
                                post_div->flag_div,
                                post_div->div_table,
-                               clks[post_div->pll_num],
+                               clks[post_div->pll_idx],
                                &stm32f4_clk_lock);
 
                if (post_div->idx != NO_IDX)
index 5ecc37a..c1ec75a 100644 (file)
@@ -18,6 +18,7 @@ config COMMON_CLK_HI3519
 config COMMON_CLK_HI3559A
        bool "Hi3559A Clock Driver"
        depends on ARCH_HISI || COMPILE_TEST
+       select RESET_HISI
        default ARCH_HISI
        help
          Build the clock driver for hi3559a.
index 800b2fe..b2c142f 100644 (file)
@@ -467,7 +467,7 @@ DEFINE_CLK_SMD_RPM(msm8936, sysmmnoc_clk, sysmmnoc_a_clk, QCOM_SMD_RPM_BUS_CLK,
 
 static struct clk_smd_rpm *msm8936_clks[] = {
        [RPM_SMD_PCNOC_CLK]             = &msm8916_pcnoc_clk,
-       [RPM_SMD_PCNOC_A_CLK]           = &msm8916_pcnoc_clk,
+       [RPM_SMD_PCNOC_A_CLK]           = &msm8916_pcnoc_a_clk,
        [RPM_SMD_SNOC_CLK]              = &msm8916_snoc_clk,
        [RPM_SMD_SNOC_A_CLK]            = &msm8916_snoc_a_clk,
        [RPM_SMD_BIMC_CLK]              = &msm8916_bimc_clk,
index 316912d..4f2c330 100644 (file)
@@ -194,6 +194,15 @@ static void clk_sdmmc_mux_disable(struct clk_hw *hw)
        gate_ops->disable(gate_hw);
 }
 
+static void clk_sdmmc_mux_disable_unused(struct clk_hw *hw)
+{
+       struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw);
+       const struct clk_ops *gate_ops = sdmmc_mux->gate_ops;
+       struct clk_hw *gate_hw = &sdmmc_mux->gate.hw;
+
+       gate_ops->disable_unused(gate_hw);
+}
+
 static void clk_sdmmc_mux_restore_context(struct clk_hw *hw)
 {
        struct clk_hw *parent = clk_hw_get_parent(hw);
@@ -218,6 +227,7 @@ static const struct clk_ops tegra_clk_sdmmc_mux_ops = {
        .is_enabled = clk_sdmmc_mux_is_enabled,
        .enable = clk_sdmmc_mux_enable,
        .disable = clk_sdmmc_mux_disable,
+       .disable_unused = clk_sdmmc_mux_disable_unused,
        .restore_context = clk_sdmmc_mux_restore_context,
 };
 
index 4b9157a..50b321a 100644 (file)
@@ -405,7 +405,7 @@ static int mpc8xxx_probe(struct platform_device *pdev)
 
        ret = devm_request_irq(&pdev->dev, mpc8xxx_gc->irqn,
                               mpc8xxx_gpio_irq_cascade,
-                              IRQF_SHARED, "gpio-cascade",
+                              IRQF_NO_THREAD | IRQF_SHARED, "gpio-cascade",
                               mpc8xxx_gc);
        if (ret) {
                dev_err(&pdev->dev,
index 5022e0a..0f5d17f 100644 (file)
@@ -238,8 +238,8 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
        struct resource *res;
        int ret, irq;
 
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
+       irq = platform_get_irq_optional(pdev, 0);
+       if (irq < 0 && irq != -ENXIO)
                return irq;
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -278,7 +278,7 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
 
        pm_runtime_enable(&pdev->dev);
 
-       if (irq) {
+       if (irq > 0) {
                struct irq_chip *irq_chip = &gpio->irq_chip;
                u8 irq_status;
 
index 84a1b4b..6cc0d4f 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/power_supply.h>
 #include <linux/pm_runtime.h>
+#include <linux/suspend.h>
 #include <acpi/video.h>
 #include <acpi/actbl.h>
 
@@ -1042,7 +1043,7 @@ bool amdgpu_acpi_is_s0ix_supported(struct amdgpu_device *adev)
 #if defined(CONFIG_AMD_PMC) || defined(CONFIG_AMD_PMC_MODULE)
        if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) {
                if (adev->flags & AMD_IS_APU)
-                       return true;
+                       return pm_suspend_target_state == PM_SUSPEND_TO_IDLE;
        }
 #endif
        return false;
index d303e88..f3fd5ec 100644 (file)
@@ -3504,13 +3504,13 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        r = amdgpu_device_get_job_timeout_settings(adev);
        if (r) {
                dev_err(adev->dev, "invalid lockup_timeout parameter syntax\n");
-               goto failed_unmap;
+               return r;
        }
 
        /* early init functions */
        r = amdgpu_device_ip_early_init(adev);
        if (r)
-               goto failed_unmap;
+               return r;
 
        /* doorbell bar mapping and doorbell index init*/
        amdgpu_device_doorbell_init(adev);
@@ -3736,10 +3736,6 @@ release_ras_con:
 failed:
        amdgpu_vf_error_trans_all(adev);
 
-failed_unmap:
-       iounmap(adev->rmmio);
-       adev->rmmio = NULL;
-
        return r;
 }
 
index 618e5b6..536d41f 100644 (file)
@@ -67,7 +67,7 @@ static int psp_v12_0_init_microcode(struct psp_context *psp)
 
        err = psp_init_asd_microcode(psp, chip_name);
        if (err)
-               goto out;
+               return err;
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name);
        err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev);
@@ -80,7 +80,7 @@ static int psp_v12_0_init_microcode(struct psp_context *psp)
        } else {
                err = amdgpu_ucode_validate(adev->psp.ta_fw);
                if (err)
-                       goto out2;
+                       goto out;
 
                ta_hdr = (const struct ta_firmware_header_v1_0 *)
                                 adev->psp.ta_fw->data;
@@ -105,10 +105,9 @@ static int psp_v12_0_init_microcode(struct psp_context *psp)
 
        return 0;
 
-out2:
+out:
        release_firmware(adev->psp.ta_fw);
        adev->psp.ta_fw = NULL;
-out:
        if (err) {
                dev_err(adev->dev,
                        "psp v12.0: Failed to load firmware \"%s\"\n",
index d3a2a5f..b53f49a 100644 (file)
@@ -2429,9 +2429,9 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
        max_cll = conn_base->hdr_sink_metadata.hdmi_type1.max_cll;
        min_cll = conn_base->hdr_sink_metadata.hdmi_type1.min_cll;
 
-       if (caps->ext_caps->bits.oled == 1 ||
+       if (caps->ext_caps->bits.oled == 1 /*||
            caps->ext_caps->bits.sdr_aux_backlight_control == 1 ||
-           caps->ext_caps->bits.hdr_aux_backlight_control == 1)
+           caps->ext_caps->bits.hdr_aux_backlight_control == 1*/)
                caps->aux_support = true;
 
        if (amdgpu_backlight == 0)
index 6e0c5c6..a5331b9 100644 (file)
@@ -197,7 +197,7 @@ void dcn20_update_clocks_update_dentist(struct clk_mgr_internal *clk_mgr, struct
 
        REG_UPDATE(DENTIST_DISPCLK_CNTL,
                        DENTIST_DISPCLK_WDIVIDER, dispclk_wdivider);
-//     REG_WAIT(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, 1, 5, 100);
+       REG_WAIT(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, 1, 50, 1000);
        REG_UPDATE(DENTIST_DISPCLK_CNTL,
                        DENTIST_DPPCLK_WDIVIDER, dppclk_wdivider);
        REG_WAIT(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_CHG_DONE, 1, 5, 100);
index f3d98e3..bf0a198 100644 (file)
@@ -109,6 +109,7 @@ struct _vcs_dpi_ip_params_st dcn2_1_ip = {
        .max_page_table_levels = 4,
        .pte_chunk_size_kbytes = 2,
        .meta_chunk_size_kbytes = 2,
+       .min_meta_chunk_size_bytes = 256,
        .writeback_chunk_size_kbytes = 2,
        .line_buffer_size_bits = 789504,
        .is_line_buffer_bpp_fixed = 0,
index d25a7d3..6655bb9 100644 (file)
@@ -841,6 +841,9 @@ static bool CalculatePrefetchSchedule(
        else
                *DestinationLinesForPrefetch = dst_y_prefetch_equ;
 
+       // Limit to prevent overflow in DST_Y_PREFETCH register
+       *DestinationLinesForPrefetch = dml_min(*DestinationLinesForPrefetch, 63.75);
+
        dml_print("DML: VStartup: %d\n", VStartup);
        dml_print("DML: TCalc: %f\n", TCalc);
        dml_print("DML: TWait: %f\n", TWait);
index 5b6922e..aa667fa 100644 (file)
@@ -2166,7 +2166,8 @@ static void
 init_vbt_missing_defaults(struct drm_i915_private *i915)
 {
        enum port port;
-       int ports = PORT_A | PORT_B | PORT_C | PORT_D | PORT_E | PORT_F;
+       int ports = BIT(PORT_A) | BIT(PORT_B) | BIT(PORT_C) |
+                   BIT(PORT_D) | BIT(PORT_E) | BIT(PORT_F);
 
        if (!HAS_DDI(i915) && !IS_CHERRYVIEW(i915))
                return;
index 3bad4e0..2d5d217 100644 (file)
@@ -11361,13 +11361,19 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv)
                intel_ddi_init(dev_priv, PORT_B);
                intel_ddi_init(dev_priv, PORT_C);
                vlv_dsi_init(dev_priv);
-       } else if (DISPLAY_VER(dev_priv) >= 9) {
+       } else if (DISPLAY_VER(dev_priv) == 10) {
                intel_ddi_init(dev_priv, PORT_A);
                intel_ddi_init(dev_priv, PORT_B);
                intel_ddi_init(dev_priv, PORT_C);
                intel_ddi_init(dev_priv, PORT_D);
                intel_ddi_init(dev_priv, PORT_E);
                intel_ddi_init(dev_priv, PORT_F);
+       } else if (DISPLAY_VER(dev_priv) >= 9) {
+               intel_ddi_init(dev_priv, PORT_A);
+               intel_ddi_init(dev_priv, PORT_B);
+               intel_ddi_init(dev_priv, PORT_C);
+               intel_ddi_init(dev_priv, PORT_D);
+               intel_ddi_init(dev_priv, PORT_E);
        } else if (HAS_DDI(dev_priv)) {
                u32 found;
 
index 7eaa92f..e0a10f3 100644 (file)
@@ -325,7 +325,7 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv)
                        info->pipe_mask &= ~BIT(PIPE_C);
                        info->cpu_transcoder_mask &= ~BIT(TRANSCODER_C);
                }
-       } else if (HAS_DISPLAY(dev_priv) && GRAPHICS_VER(dev_priv) >= 9) {
+       } else if (HAS_DISPLAY(dev_priv) && DISPLAY_VER(dev_priv) >= 9) {
                u32 dfsm = intel_de_read(dev_priv, SKL_DFSM);
 
                if (dfsm & SKL_DFSM_PIPE_A_DISABLE) {
@@ -340,7 +340,8 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv)
                        info->pipe_mask &= ~BIT(PIPE_C);
                        info->cpu_transcoder_mask &= ~BIT(TRANSCODER_C);
                }
-               if (GRAPHICS_VER(dev_priv) >= 12 &&
+
+               if (DISPLAY_VER(dev_priv) >= 12 &&
                    (dfsm & TGL_DFSM_PIPE_D_DISABLE)) {
                        info->pipe_mask &= ~BIT(PIPE_D);
                        info->cpu_transcoder_mask &= ~BIT(TRANSCODER_D);
@@ -352,10 +353,10 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv)
                if (dfsm & SKL_DFSM_DISPLAY_PM_DISABLE)
                        info->display.has_fbc = 0;
 
-               if (GRAPHICS_VER(dev_priv) >= 11 && (dfsm & ICL_DFSM_DMC_DISABLE))
+               if (DISPLAY_VER(dev_priv) >= 11 && (dfsm & ICL_DFSM_DMC_DISABLE))
                        info->display.has_dmc = 0;
 
-               if (GRAPHICS_VER(dev_priv) >= 10 &&
+               if (DISPLAY_VER(dev_priv) >= 10 &&
                    (dfsm & CNL_DFSM_DISPLAY_DSC_DISABLE))
                        info->display.has_dsc = 0;
        }
index d01c4c9..704dace 100644 (file)
@@ -296,7 +296,7 @@ static const struct dpu_mdp_cfg sc7180_mdp[] = {
 static const struct dpu_mdp_cfg sm8250_mdp[] = {
        {
        .name = "top_0", .id = MDP_TOP,
-       .base = 0x0, .len = 0x45C,
+       .base = 0x0, .len = 0x494,
        .features = 0,
        .highest_bank_bit = 0x3, /* TODO: 2 for LP_DDR4 */
        .clk_ctrls[DPU_CLK_CTRL_VIG0] = {
index ca96e35..c0423e7 100644 (file)
@@ -771,6 +771,7 @@ int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog)
        dp_write_link(catalog, REG_DP_HSYNC_VSYNC_WIDTH_POLARITY,
                                dp_catalog->width_blanking);
        dp_write_link(catalog, REG_DP_ACTIVE_HOR_VER, dp_catalog->dp_active);
+       dp_write_p0(catalog, MMSS_DP_INTF_CONFIG, 0);
        return 0;
 }
 
index ee221d8..eaddfd7 100644 (file)
@@ -1526,7 +1526,7 @@ static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl)
         * running. Add the global reset just before disabling the
         * link clocks and core clocks.
         */
-       ret = dp_ctrl_off(&ctrl->dp_ctrl);
+       ret = dp_ctrl_off_link_stream(&ctrl->dp_ctrl);
        if (ret) {
                DRM_ERROR("failed to disable DP controller\n");
                return ret;
index 051c1be..867388a 100644 (file)
@@ -219,6 +219,7 @@ static int dp_display_bind(struct device *dev, struct device *master,
                goto end;
        }
 
+       dp->aux->drm_dev = drm;
        rc = dp_aux_register(dp->aux);
        if (rc) {
                DRM_ERROR("DRM DP AUX register failed\n");
@@ -1311,6 +1312,10 @@ static int dp_pm_resume(struct device *dev)
        else
                dp->dp_display.is_connected = false;
 
+       dp_display_handle_plugged_change(g_dp_display,
+                               dp->dp_display.is_connected);
+
+
        mutex_unlock(&dp->event_mutex);
 
        return 0;
index eed2a76..bcaddbb 100644 (file)
@@ -142,6 +142,9 @@ static const struct iommu_flush_ops null_tlb_ops = {
        .tlb_add_page = msm_iommu_tlb_add_page,
 };
 
+static int msm_fault_handler(struct iommu_domain *domain, struct device *dev,
+               unsigned long iova, int flags, void *arg);
+
 struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent)
 {
        struct adreno_smmu_priv *adreno_smmu = dev_get_drvdata(parent->dev);
@@ -157,6 +160,13 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent)
        if (!ttbr1_cfg)
                return ERR_PTR(-ENODEV);
 
+       /*
+        * Defer setting the fault handler until we have a valid adreno_smmu
+        * to avoid accidentially installing a GPU specific fault handler for
+        * the display's iommu
+        */
+       iommu_set_fault_handler(iommu->domain, msm_fault_handler, iommu);
+
        pagetable = kzalloc(sizeof(*pagetable), GFP_KERNEL);
        if (!pagetable)
                return ERR_PTR(-ENOMEM);
@@ -300,7 +310,6 @@ struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain)
 
        iommu->domain = domain;
        msm_mmu_init(&iommu->base, dev, &funcs, MSM_MMU_IOMMU);
-       iommu_set_fault_handler(domain, msm_fault_handler, iommu);
 
        atomic_set(&iommu->pagetables, 0);
 
index 21939d4..1b80290 100644 (file)
@@ -4166,7 +4166,7 @@ static const struct drm_display_mode yes_optoelectronics_ytc700tlag_05_201c_mode
 static const struct panel_desc yes_optoelectronics_ytc700tlag_05_201c = {
        .modes = &yes_optoelectronics_ytc700tlag_05_201c_mode,
        .num_modes = 1,
-       .bpc = 6,
+       .bpc = 8,
        .size = {
                .width = 154,
                .height = 90,
index 519deea..74e3b46 100644 (file)
@@ -44,6 +44,8 @@ static unsigned ttm_glob_use_count;
 struct ttm_global ttm_glob;
 EXPORT_SYMBOL(ttm_glob);
 
+struct dentry *ttm_debugfs_root;
+
 static void ttm_global_release(void)
 {
        struct ttm_global *glob = &ttm_glob;
@@ -53,6 +55,7 @@ static void ttm_global_release(void)
                goto out;
 
        ttm_pool_mgr_fini();
+       debugfs_remove(ttm_debugfs_root);
 
        __free_page(glob->dummy_read_page);
        memset(glob, 0, sizeof(*glob));
@@ -73,6 +76,13 @@ static int ttm_global_init(void)
 
        si_meminfo(&si);
 
+       ttm_debugfs_root = debugfs_create_dir("ttm", NULL);
+       if (IS_ERR(ttm_debugfs_root)) {
+               ret = PTR_ERR(ttm_debugfs_root);
+               ttm_debugfs_root = NULL;
+               goto out;
+       }
+
        /* Limit the number of pages in the pool to about 50% of the total
         * system memory.
         */
@@ -100,6 +110,8 @@ static int ttm_global_init(void)
        debugfs_create_atomic_t("buffer_objects", 0444, ttm_debugfs_root,
                                &glob->bo_count);
 out:
+       if (ret && ttm_debugfs_root)
+               debugfs_remove(ttm_debugfs_root);
        if (ret)
                --ttm_glob_use_count;
        mutex_unlock(&ttm_global_mutex);
index 997c458..7fcdef2 100644 (file)
@@ -72,22 +72,6 @@ pgprot_t ttm_prot_from_caching(enum ttm_caching caching, pgprot_t tmp)
        return tmp;
 }
 
-struct dentry *ttm_debugfs_root;
-
-static int __init ttm_init(void)
-{
-       ttm_debugfs_root = debugfs_create_dir("ttm", NULL);
-       return 0;
-}
-
-static void __exit ttm_exit(void)
-{
-       debugfs_remove(ttm_debugfs_root);
-}
-
-module_init(ttm_init);
-module_exit(ttm_exit);
-
 MODULE_AUTHOR("Thomas Hellstrom, Jerome Glisse");
 MODULE_DESCRIPTION("TTM memory manager subsystem (for DRM device)");
 MODULE_LICENSE("GPL and additional rights");
index 1605549..76937f7 100644 (file)
@@ -576,7 +576,7 @@ config HID_LOGITECH_HIDPP
        depends on HID_LOGITECH
        select POWER_SUPPLY
        help
-       Support for Logitech devices relyingon the HID++ Logitech specification
+       Support for Logitech devices relying on the HID++ Logitech specification
 
        Say Y if you want support for Logitech devices relying on the HID++
        specification. Such devices are the various Logitech Touchpads (T650,
index 96e2577..8d68796 100644 (file)
@@ -58,7 +58,7 @@ static void amd_stop_sensor_v2(struct amd_mp2_dev *privdata, u16 sensor_idx)
        cmd_base.cmd_v2.sensor_id = sensor_idx;
        cmd_base.cmd_v2.length  = 16;
 
-       writeq(0x0, privdata->mmio + AMD_C2P_MSG2);
+       writeq(0x0, privdata->mmio + AMD_C2P_MSG1);
        writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
 }
 
index 6b8f0d0..dc6bd42 100644 (file)
@@ -501,6 +501,8 @@ static const struct hid_device_id apple_devices[] = {
                        APPLE_RDESC_JIS },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI),
                .driver_data = APPLE_HAS_FN },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI),
+               .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO),
                .driver_data = APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO),
index fca8fc7..fb807c8 100644 (file)
@@ -485,9 +485,6 @@ static void asus_kbd_backlight_set(struct led_classdev *led_cdev,
 {
        struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
                                                 cdev);
-       if (led->brightness == brightness)
-               return;
-
        led->brightness = brightness;
        schedule_work(&led->work);
 }
index f43a840..4ef1c3b 100644 (file)
@@ -742,7 +742,7 @@ static int ft260_is_interface_enabled(struct hid_device *hdev)
        int ret;
 
        ret = ft260_get_system_config(hdev, &cfg);
-       if (ret)
+       if (ret < 0)
                return ret;
 
        ft260_dbg("interface:  0x%02x\n", interface);
@@ -754,23 +754,16 @@ static int ft260_is_interface_enabled(struct hid_device *hdev)
        switch (cfg.chip_mode) {
        case FT260_MODE_ALL:
        case FT260_MODE_BOTH:
-               if (interface == 1) {
+               if (interface == 1)
                        hid_info(hdev, "uart interface is not supported\n");
-                       return 0;
-               }
-               ret = 1;
+               else
+                       ret = 1;
                break;
        case FT260_MODE_UART:
-               if (interface == 0) {
-                       hid_info(hdev, "uart is unsupported on interface 0\n");
-                       ret = 0;
-               }
+               hid_info(hdev, "uart interface is not supported\n");
                break;
        case FT260_MODE_I2C:
-               if (interface == 1) {
-                       hid_info(hdev, "i2c is unsupported on interface 1\n");
-                       ret = 0;
-               }
+               ret = 1;
                break;
        }
        return ret;
@@ -785,7 +778,7 @@ static int ft260_byte_show(struct hid_device *hdev, int id, u8 *cfg, int len,
        if (ret < 0)
                return ret;
 
-       return scnprintf(buf, PAGE_SIZE, "%hi\n", *field);
+       return scnprintf(buf, PAGE_SIZE, "%d\n", *field);
 }
 
 static int ft260_word_show(struct hid_device *hdev, int id, u8 *cfg, int len,
@@ -797,7 +790,7 @@ static int ft260_word_show(struct hid_device *hdev, int id, u8 *cfg, int len,
        if (ret < 0)
                return ret;
 
-       return scnprintf(buf, PAGE_SIZE, "%hi\n", le16_to_cpu(*field));
+       return scnprintf(buf, PAGE_SIZE, "%d\n", le16_to_cpu(*field));
 }
 
 #define FT260_ATTR_SHOW(name, reptype, id, type, func)                        \
@@ -1004,11 +997,9 @@ err_hid_stop:
 
 static void ft260_remove(struct hid_device *hdev)
 {
-       int ret;
        struct ft260_device *dev = hid_get_drvdata(hdev);
 
-       ret = ft260_is_interface_enabled(hdev);
-       if (ret <= 0)
+       if (!dev)
                return;
 
        sysfs_remove_group(&hdev->dev.kobj, &ft260_attr_group);
index 6b1fa97..91bf4d0 100644 (file)
@@ -784,6 +784,17 @@ static void hid_ishtp_cl_reset_handler(struct work_struct *work)
        }
 }
 
+static void hid_ishtp_cl_resume_handler(struct work_struct *work)
+{
+       struct ishtp_cl_data *client_data = container_of(work, struct ishtp_cl_data, resume_work);
+       struct ishtp_cl *hid_ishtp_cl = client_data->hid_ishtp_cl;
+
+       if (ishtp_wait_resume(ishtp_get_ishtp_device(hid_ishtp_cl))) {
+               client_data->suspended = false;
+               wake_up_interruptible(&client_data->ishtp_resume_wait);
+       }
+}
+
 ishtp_print_log ishtp_hid_print_trace;
 
 /**
@@ -822,6 +833,8 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
        init_waitqueue_head(&client_data->ishtp_resume_wait);
 
        INIT_WORK(&client_data->work, hid_ishtp_cl_reset_handler);
+       INIT_WORK(&client_data->resume_work, hid_ishtp_cl_resume_handler);
+
 
        ishtp_hid_print_trace = ishtp_trace_callback(cl_device);
 
@@ -921,7 +934,7 @@ static int hid_ishtp_cl_resume(struct device *device)
 
        hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
                        hid_ishtp_cl);
-       client_data->suspended = false;
+       schedule_work(&client_data->resume_work);
        return 0;
 }
 
index f88443a..6a5cc11 100644 (file)
@@ -135,6 +135,7 @@ struct ishtp_cl_data {
        int multi_packet_cnt;
 
        struct work_struct work;
+       struct work_struct resume_work;
        struct ishtp_cl_device *cl_device;
 };
 
index f0802b0..aa2c516 100644 (file)
@@ -314,13 +314,6 @@ static int ishtp_cl_device_resume(struct device *dev)
        if (!device)
                return 0;
 
-       /*
-        * When ISH needs hard reset, it is done asynchrnously, hence bus
-        * resume will  be called before full ISH resume
-        */
-       if (device->ishtp_dev->resume_flag)
-               return 0;
-
        driver = to_ishtp_cl_driver(dev->driver);
        if (driver && driver->driver.pm) {
                if (driver->driver.pm->resume)
@@ -850,6 +843,28 @@ struct device *ishtp_device(struct ishtp_cl_device *device)
 EXPORT_SYMBOL(ishtp_device);
 
 /**
+ * ishtp_wait_resume() - Wait for IPC resume
+ *
+ * Wait for IPC resume
+ *
+ * Return: resume complete or not
+ */
+bool ishtp_wait_resume(struct ishtp_device *dev)
+{
+       /* 50ms to get resume response */
+       #define WAIT_FOR_RESUME_ACK_MS          50
+
+       /* Waiting to get resume response */
+       if (dev->resume_flag)
+               wait_event_interruptible_timeout(dev->resume_wait,
+                                                !dev->resume_flag,
+                                                msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS));
+
+       return (!dev->resume_flag);
+}
+EXPORT_SYMBOL_GPL(ishtp_wait_resume);
+
+/**
  * ishtp_get_pci_device() - Return PCI device dev pointer
  * This interface is used to return PCI device pointer
  * from ishtp_cl_device instance.
index dcf3a23..7c2032f 100644 (file)
@@ -38,7 +38,7 @@ config USB_HIDDEV
        help
          Say Y here if you want to support HID devices (from the USB
          specification standpoint) that aren't strictly user interface
-         devices, like monitor controls and Uninterruptable Power Supplies.
+         devices, like monitor controls and Uninterruptible Power Supplies.
 
          This module supports these devices separately using a separate
          event interface on /dev/usb/hiddevX (char 180:96 to 180:111).
index 81d7d12..81ba642 100644 (file)
@@ -2548,6 +2548,9 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
                int slot;
 
                slot = input_mt_get_slot_by_key(input, hid_data->id);
+               if (slot < 0)
+                       return;
+
                input_mt_slot(input, slot);
                input_mt_report_slot_state(input, MT_TOOL_FINGER, prox);
        }
@@ -3831,7 +3834,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
                    wacom_wac->shared->touch->product == 0xF6) {
                        input_dev->evbit[0] |= BIT_MASK(EV_SW);
                        __set_bit(SW_MUTE_DEVICE, input_dev->swbit);
-                       wacom_wac->shared->has_mute_touch_switch = true;
+                       wacom_wac->has_mute_touch_switch = true;
                }
                fallthrough;
 
index d567402..a8688a9 100644 (file)
@@ -120,6 +120,7 @@ static int bnxt_re_setup_chip_ctx(struct bnxt_re_dev *rdev, u8 wqe_mode)
        if (!chip_ctx)
                return -ENOMEM;
        chip_ctx->chip_num = bp->chip_num;
+       chip_ctx->hw_stats_size = bp->hw_ring_stats_size;
 
        rdev->chip_ctx = chip_ctx;
        /* rest members to follow eventually */
@@ -550,6 +551,7 @@ static int bnxt_re_net_stats_ctx_alloc(struct bnxt_re_dev *rdev,
                                       dma_addr_t dma_map,
                                       u32 *fw_stats_ctx_id)
 {
+       struct bnxt_qplib_chip_ctx *chip_ctx = rdev->chip_ctx;
        struct hwrm_stat_ctx_alloc_output resp = {0};
        struct hwrm_stat_ctx_alloc_input req = {0};
        struct bnxt_en_dev *en_dev = rdev->en_dev;
@@ -566,7 +568,7 @@ static int bnxt_re_net_stats_ctx_alloc(struct bnxt_re_dev *rdev,
        bnxt_re_init_hwrm_hdr(rdev, (void *)&req, HWRM_STAT_CTX_ALLOC, -1, -1);
        req.update_period_ms = cpu_to_le32(1000);
        req.stats_dma_addr = cpu_to_le64(dma_map);
-       req.stats_dma_length = cpu_to_le16(sizeof(struct ctx_hw_stats_ext));
+       req.stats_dma_length = cpu_to_le16(chip_ctx->hw_stats_size);
        req.stat_ctx_flags = STAT_CTX_ALLOC_REQ_STAT_CTX_FLAGS_ROCE;
        bnxt_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp,
                            sizeof(resp), DFLT_HWRM_CMD_TIMEOUT);
index 17f0701..44282a8 100644 (file)
@@ -56,6 +56,7 @@
 static void bnxt_qplib_free_stats_ctx(struct pci_dev *pdev,
                                      struct bnxt_qplib_stats *stats);
 static int bnxt_qplib_alloc_stats_ctx(struct pci_dev *pdev,
+                                     struct bnxt_qplib_chip_ctx *cctx,
                                      struct bnxt_qplib_stats *stats);
 
 /* PBL */
@@ -559,7 +560,7 @@ int bnxt_qplib_alloc_ctx(struct bnxt_qplib_res *res,
                goto fail;
 stats_alloc:
        /* Stats */
-       rc = bnxt_qplib_alloc_stats_ctx(res->pdev, &ctx->stats);
+       rc = bnxt_qplib_alloc_stats_ctx(res->pdev, res->cctx, &ctx->stats);
        if (rc)
                goto fail;
 
@@ -889,15 +890,12 @@ static void bnxt_qplib_free_stats_ctx(struct pci_dev *pdev,
 }
 
 static int bnxt_qplib_alloc_stats_ctx(struct pci_dev *pdev,
+                                     struct bnxt_qplib_chip_ctx *cctx,
                                      struct bnxt_qplib_stats *stats)
 {
        memset(stats, 0, sizeof(*stats));
        stats->fw_id = -1;
-       /* 128 byte aligned context memory is required only for 57500.
-        * However making this unconditional, it does not harm previous
-        * generation.
-        */
-       stats->size = ALIGN(sizeof(struct ctx_hw_stats), 128);
+       stats->size = cctx->hw_stats_size;
        stats->dma = dma_alloc_coherent(&pdev->dev, stats->size,
                                        &stats->dma_map, GFP_KERNEL);
        if (!stats->dma) {
index c291f49..9103150 100644 (file)
@@ -54,6 +54,7 @@ struct bnxt_qplib_chip_ctx {
        u16     chip_num;
        u8      chip_rev;
        u8      chip_metal;
+       u16     hw_stats_size;
        struct bnxt_qplib_drv_modes modes;
 };
 
index b1023a7..f1e5515 100644 (file)
@@ -2845,7 +2845,7 @@ static u64 irdma_sc_decode_fpm_commit(struct irdma_sc_dev *dev, __le64 *buf,
  * parses fpm commit info and copy base value
  * of hmc objects in hmc_info
  */
-static enum irdma_status_code
+static void
 irdma_sc_parse_fpm_commit_buf(struct irdma_sc_dev *dev, __le64 *buf,
                              struct irdma_hmc_obj_info *info, u32 *sd)
 {
@@ -2915,7 +2915,6 @@ irdma_sc_parse_fpm_commit_buf(struct irdma_sc_dev *dev, __le64 *buf,
        else
                *sd = (u32)(size >> 21);
 
-       return 0;
 }
 
 /**
@@ -4187,11 +4186,9 @@ enum irdma_status_code irdma_sc_get_next_aeqe(struct irdma_sc_aeq *aeq,
  * @dev: sc device struct
  * @count: allocate count
  */
-enum irdma_status_code irdma_sc_repost_aeq_entries(struct irdma_sc_dev *dev, u32 count)
+void irdma_sc_repost_aeq_entries(struct irdma_sc_dev *dev, u32 count)
 {
        writel(count, dev->hw_regs[IRDMA_AEQALLOC]);
-
-       return 0;
 }
 
 /**
@@ -4434,9 +4431,9 @@ static enum irdma_status_code irdma_sc_cfg_iw_fpm(struct irdma_sc_dev *dev,
        ret_code = irdma_sc_commit_fpm_val(dev->cqp, 0, hmc_info->hmc_fn_id,
                                           &commit_fpm_mem, true, wait_type);
        if (!ret_code)
-               ret_code = irdma_sc_parse_fpm_commit_buf(dev, dev->fpm_commit_buf,
-                                                        hmc_info->hmc_obj,
-                                                        &hmc_info->sd_table.sd_cnt);
+               irdma_sc_parse_fpm_commit_buf(dev, dev->fpm_commit_buf,
+                                             hmc_info->hmc_obj,
+                                             &hmc_info->sd_table.sd_cnt);
        print_hex_dump_debug("HMC: COMMIT FPM BUFFER", DUMP_PREFIX_OFFSET, 16,
                             8, commit_fpm_mem.va, IRDMA_COMMIT_FPM_BUF_SIZE,
                             false);
index 7afb8a6..00de5ee 100644 (file)
@@ -1920,7 +1920,7 @@ enum irdma_status_code irdma_ctrl_init_hw(struct irdma_pci_f *rf)
  * irdma_set_hw_rsrc - set hw memory resources.
  * @rf: RDMA PCI function
  */
-static u32 irdma_set_hw_rsrc(struct irdma_pci_f *rf)
+static void irdma_set_hw_rsrc(struct irdma_pci_f *rf)
 {
        rf->allocated_qps = (void *)(rf->mem_rsrc +
                   (sizeof(struct irdma_arp_entry) * rf->arp_table_size));
@@ -1937,8 +1937,6 @@ static u32 irdma_set_hw_rsrc(struct irdma_pci_f *rf)
        spin_lock_init(&rf->arp_lock);
        spin_lock_init(&rf->qptable_lock);
        spin_lock_init(&rf->qh_list_lock);
-
-       return 0;
 }
 
 /**
@@ -2000,9 +1998,7 @@ u32 irdma_initialize_hw_rsrc(struct irdma_pci_f *rf)
 
        rf->arp_table = (struct irdma_arp_entry *)rf->mem_rsrc;
 
-       ret = irdma_set_hw_rsrc(rf);
-       if (ret)
-               goto set_hw_rsrc_fail;
+       irdma_set_hw_rsrc(rf);
 
        set_bit(0, rf->allocated_mrs);
        set_bit(0, rf->allocated_qps);
@@ -2025,9 +2021,6 @@ u32 irdma_initialize_hw_rsrc(struct irdma_pci_f *rf)
 
        return 0;
 
-set_hw_rsrc_fail:
-       kfree(rf->mem_rsrc);
-       rf->mem_rsrc = NULL;
 mem_rsrc_kzalloc_fail:
        kfree(rf->allocated_ws_nodes);
        rf->allocated_ws_nodes = NULL;
index ea59432..51a4135 100644 (file)
@@ -215,10 +215,10 @@ static void irdma_remove(struct auxiliary_device *aux_dev)
        pr_debug("INIT: Gen2 PF[%d] device remove success\n", PCI_FUNC(pf->pdev->devfn));
 }
 
-static void irdma_fill_device_info(struct irdma_device *iwdev, struct ice_pf *pf)
+static void irdma_fill_device_info(struct irdma_device *iwdev, struct ice_pf *pf,
+                                  struct ice_vsi *vsi)
 {
        struct irdma_pci_f *rf = iwdev->rf;
-       struct ice_vsi *vsi = ice_get_main_vsi(pf);
 
        rf->cdev = pf;
        rf->gen_ops.register_qset = irdma_lan_register_qset;
@@ -253,12 +253,15 @@ static int irdma_probe(struct auxiliary_device *aux_dev, const struct auxiliary_
                                                            struct iidc_auxiliary_dev,
                                                            adev);
        struct ice_pf *pf = iidc_adev->pf;
+       struct ice_vsi *vsi = ice_get_main_vsi(pf);
        struct iidc_qos_params qos_info = {};
        struct irdma_device *iwdev;
        struct irdma_pci_f *rf;
        struct irdma_l2params l2params = {};
        int err;
 
+       if (!vsi)
+               return -EIO;
        iwdev = ib_alloc_device(irdma_device, ibdev);
        if (!iwdev)
                return -ENOMEM;
@@ -268,7 +271,7 @@ static int irdma_probe(struct auxiliary_device *aux_dev, const struct auxiliary_
                return -ENOMEM;
        }
 
-       irdma_fill_device_info(iwdev, pf);
+       irdma_fill_device_info(iwdev, pf, vsi);
        rf = iwdev->rf;
 
        if (irdma_ctrl_init_hw(rf)) {
index 7387b83..874bc25 100644 (file)
@@ -1222,8 +1222,7 @@ enum irdma_status_code irdma_sc_aeq_init(struct irdma_sc_aeq *aeq,
                                         struct irdma_aeq_init_info *info);
 enum irdma_status_code irdma_sc_get_next_aeqe(struct irdma_sc_aeq *aeq,
                                              struct irdma_aeqe_info *info);
-enum irdma_status_code irdma_sc_repost_aeq_entries(struct irdma_sc_dev *dev,
-                                                  u32 count);
+void irdma_sc_repost_aeq_entries(struct irdma_sc_dev *dev, u32 count);
 
 void irdma_sc_pd_init(struct irdma_sc_dev *dev, struct irdma_sc_pd *pd, u32 pd_id,
                      int abi_ver);
index a6d52c2..5fb92de 100644 (file)
@@ -931,7 +931,7 @@ enum irdma_status_code irdma_uk_mw_bind(struct irdma_qp_uk *qp,
 enum irdma_status_code irdma_uk_post_receive(struct irdma_qp_uk *qp,
                                             struct irdma_post_rq_info *info)
 {
-       u32 total_size = 0, wqe_idx, i, byte_off;
+       u32 wqe_idx, i, byte_off;
        u32 addl_frag_cnt;
        __le64 *wqe;
        u64 hdr;
@@ -939,9 +939,6 @@ enum irdma_status_code irdma_uk_post_receive(struct irdma_qp_uk *qp,
        if (qp->max_rq_frag_cnt < info->num_sges)
                return IRDMA_ERR_INVALID_FRAG_COUNT;
 
-       for (i = 0; i < info->num_sges; i++)
-               total_size += info->sg_list[i].len;
-
        wqe = irdma_qp_get_next_recv_wqe(qp, &wqe_idx);
        if (!wqe)
                return IRDMA_ERR_QP_TOOMANY_WRS_POSTED;
index 9712f69..717147e 100644 (file)
@@ -557,7 +557,7 @@ static int irdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
  * @iwqp: qp ptr
  * @init_info: initialize info to return
  */
-static int irdma_setup_virt_qp(struct irdma_device *iwdev,
+static void irdma_setup_virt_qp(struct irdma_device *iwdev,
                               struct irdma_qp *iwqp,
                               struct irdma_qp_init_info *init_info)
 {
@@ -574,8 +574,6 @@ static int irdma_setup_virt_qp(struct irdma_device *iwdev,
                init_info->sq_pa = qpmr->sq_pbl.addr;
                init_info->rq_pa = qpmr->rq_pbl.addr;
        }
-
-       return 0;
 }
 
 /**
@@ -914,7 +912,7 @@ static struct ib_qp *irdma_create_qp(struct ib_pd *ibpd,
                        }
                }
                init_info.qp_uk_init_info.abi_ver = iwpd->sc_pd.abi_ver;
-               err_code = irdma_setup_virt_qp(iwdev, iwqp, &init_info);
+               irdma_setup_virt_qp(iwdev, iwqp, &init_info);
        } else {
                init_info.qp_uk_init_info.abi_ver = IRDMA_ABI_VER;
                err_code = irdma_setup_kmode_qp(iwdev, iwqp, &init_info, init_attr);
index 6aabcb4..be4bcb4 100644 (file)
@@ -113,13 +113,14 @@ int rxe_mr_init_user(struct rxe_pd *pd, u64 start, u64 length, u64 iova,
        int                     num_buf;
        void                    *vaddr;
        int err;
+       int i;
 
        umem = ib_umem_get(pd->ibpd.device, start, length, access);
        if (IS_ERR(umem)) {
-               pr_warn("err %d from rxe_umem_get\n",
-                       (int)PTR_ERR(umem));
+               pr_warn("%s: Unable to pin memory region err = %d\n",
+                       __func__, (int)PTR_ERR(umem));
                err = PTR_ERR(umem);
-               goto err1;
+               goto err_out;
        }
 
        mr->umem = umem;
@@ -129,9 +130,9 @@ int rxe_mr_init_user(struct rxe_pd *pd, u64 start, u64 length, u64 iova,
 
        err = rxe_mr_alloc(mr, num_buf);
        if (err) {
-               pr_warn("err %d from rxe_mr_alloc\n", err);
-               ib_umem_release(umem);
-               goto err1;
+               pr_warn("%s: Unable to allocate memory for map\n",
+                               __func__);
+               goto err_release_umem;
        }
 
        mr->page_shift = PAGE_SHIFT;
@@ -151,10 +152,10 @@ int rxe_mr_init_user(struct rxe_pd *pd, u64 start, u64 length, u64 iova,
 
                        vaddr = page_address(sg_page_iter_page(&sg_iter));
                        if (!vaddr) {
-                               pr_warn("null vaddr\n");
-                               ib_umem_release(umem);
+                               pr_warn("%s: Unable to get virtual address\n",
+                                               __func__);
                                err = -ENOMEM;
-                               goto err1;
+                               goto err_cleanup_map;
                        }
 
                        buf->addr = (uintptr_t)vaddr;
@@ -177,7 +178,13 @@ int rxe_mr_init_user(struct rxe_pd *pd, u64 start, u64 length, u64 iova,
 
        return 0;
 
-err1:
+err_cleanup_map:
+       for (i = 0; i < mr->num_map; i++)
+               kfree(mr->map[i]);
+       kfree(mr->map);
+err_release_umem:
+       ib_umem_release(umem);
+err_out:
        return err;
 }
 
index 02281d1..508ac29 100644 (file)
@@ -1573,6 +1573,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
                  struct media_request *req)
 {
        struct vb2_buffer *vb;
+       enum vb2_buffer_state orig_state;
        int ret;
 
        if (q->error) {
@@ -1673,6 +1674,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
         * Add to the queued buffers list, a buffer will stay on it until
         * dequeued in dqbuf.
         */
+       orig_state = vb->state;
        list_add_tail(&vb->queued_entry, &q->queued_list);
        q->queued_count++;
        q->waiting_for_buffers = false;
@@ -1703,8 +1705,17 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
        if (q->streaming && !q->start_streaming_called &&
            q->queued_count >= q->min_buffers_needed) {
                ret = vb2_start_streaming(q);
-               if (ret)
+               if (ret) {
+                       /*
+                        * Since vb2_core_qbuf will return with an error,
+                        * we should return it to state DEQUEUED since
+                        * the error indicates that the buffer wasn't queued.
+                        */
+                       list_del(&vb->queued_entry);
+                       q->queued_count--;
+                       vb->state = orig_state;
                        return ret;
+               }
        }
 
        dprintk(q, 2, "qbuf of buffer %d succeeded\n", vb->index);
index 99b5121..dda2f27 100644 (file)
@@ -8,6 +8,7 @@ config VIDEO_ATMEL_ISC
        select VIDEOBUF2_DMA_CONTIG
        select REGMAP_MMIO
        select V4L2_FWNODE
+       select VIDEO_ATMEL_ISC_BASE
        help
           This module makes the ATMEL Image Sensor Controller available
           as a v4l2 device.
@@ -19,10 +20,17 @@ config VIDEO_ATMEL_XISC
        select VIDEOBUF2_DMA_CONTIG
        select REGMAP_MMIO
        select V4L2_FWNODE
+       select VIDEO_ATMEL_ISC_BASE
        help
           This module makes the ATMEL eXtended Image Sensor Controller
           available as a v4l2 device.
 
+config VIDEO_ATMEL_ISC_BASE
+       tristate
+       default n
+       help
+         ATMEL ISC and XISC common code base.
+
 config VIDEO_ATMEL_ISI
        tristate "ATMEL Image Sensor Interface (ISI) support"
        depends on VIDEO_V4L2 && OF
index c5c0155..46d264a 100644 (file)
@@ -1,7 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0-only
-atmel-isc-objs = atmel-sama5d2-isc.o atmel-isc-base.o
-atmel-xisc-objs = atmel-sama7g5-isc.o atmel-isc-base.o
+atmel-isc-objs = atmel-sama5d2-isc.o
+atmel-xisc-objs = atmel-sama7g5-isc.o
 
 obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o
+obj-$(CONFIG_VIDEO_ATMEL_ISC_BASE) += atmel-isc-base.o
 obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o
 obj-$(CONFIG_VIDEO_ATMEL_XISC) += atmel-xisc.o
index 19daa49..136ab7c 100644 (file)
@@ -378,6 +378,7 @@ int isc_clk_init(struct isc_device *isc)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(isc_clk_init);
 
 void isc_clk_cleanup(struct isc_device *isc)
 {
@@ -392,6 +393,7 @@ void isc_clk_cleanup(struct isc_device *isc)
                        clk_unregister(isc_clk->clk);
        }
 }
+EXPORT_SYMBOL_GPL(isc_clk_cleanup);
 
 static int isc_queue_setup(struct vb2_queue *vq,
                            unsigned int *nbuffers, unsigned int *nplanes,
@@ -1578,6 +1580,7 @@ irqreturn_t isc_interrupt(int irq, void *dev_id)
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(isc_interrupt);
 
 static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
 {
@@ -2212,6 +2215,7 @@ const struct v4l2_async_notifier_operations isc_async_ops = {
        .unbind = isc_async_unbind,
        .complete = isc_async_complete,
 };
+EXPORT_SYMBOL_GPL(isc_async_ops);
 
 void isc_subdev_cleanup(struct isc_device *isc)
 {
@@ -2224,6 +2228,7 @@ void isc_subdev_cleanup(struct isc_device *isc)
 
        INIT_LIST_HEAD(&isc->subdev_entities);
 }
+EXPORT_SYMBOL_GPL(isc_subdev_cleanup);
 
 int isc_pipeline_init(struct isc_device *isc)
 {
@@ -2264,6 +2269,7 @@ int isc_pipeline_init(struct isc_device *isc)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(isc_pipeline_init);
 
 /* regmap configuration */
 #define ATMEL_ISC_REG_MAX    0xd5c
@@ -2273,4 +2279,9 @@ const struct regmap_config isc_regmap_config = {
        .val_bits       = 32,
        .max_register   = ATMEL_ISC_REG_MAX,
 };
+EXPORT_SYMBOL_GPL(isc_regmap_config);
 
+MODULE_AUTHOR("Songjun Wu");
+MODULE_AUTHOR("Eugen Hristev");
+MODULE_DESCRIPTION("Atmel ISC common code base");
+MODULE_LICENSE("GPL v2");
index 8370573..795a012 100644 (file)
@@ -37,7 +37,16 @@ static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
        } else {
                /* read */
                requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
-               pipe = usb_rcvctrlpipe(d->udev, 0);
+
+               /*
+                * Zero-length transfers must use usb_sndctrlpipe() and
+                * rtl28xxu_identify_state() uses a zero-length i2c read
+                * command to determine the chip type.
+                */
+               if (req->size)
+                       pipe = usb_rcvctrlpipe(d->udev, 0);
+               else
+                       pipe = usb_sndctrlpipe(d->udev, 0);
        }
 
        ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value,
@@ -612,9 +621,8 @@ static int rtl28xxu_read_config(struct dvb_usb_device *d)
 static int rtl28xxu_identify_state(struct dvb_usb_device *d, const char **name)
 {
        struct rtl28xxu_dev *dev = d_to_priv(d);
-       u8 buf[1];
        int ret;
-       struct rtl28xxu_req req_demod_i2c = {0x0020, CMD_I2C_DA_RD, 1, buf};
+       struct rtl28xxu_req req_demod_i2c = {0x0020, CMD_I2C_DA_RD, 0, NULL};
 
        dev_dbg(&d->intf->dev, "\n");
 
index dd17b8c..89d9c98 100644 (file)
@@ -218,7 +218,7 @@ static int hi3110_spi_trans(struct spi_device *spi, int len)
        return ret;
 }
 
-static u8 hi3110_cmd(struct spi_device *spi, u8 command)
+static int hi3110_cmd(struct spi_device *spi, u8 command)
 {
        struct hi3110_priv *priv = spi_get_drvdata(spi);
 
index 47c3f40..9ae4807 100644 (file)
@@ -2300,6 +2300,7 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
                   err, priv->regs_status.intf);
        mcp251xfd_dump(priv);
        mcp251xfd_chip_interrupts_disable(priv);
+       mcp251xfd_timestamp_stop(priv);
 
        return handled;
 }
index 0a37af4..2b5302e 100644 (file)
@@ -255,6 +255,8 @@ struct ems_usb {
        unsigned int free_slots; /* remember number of available slots */
 
        struct ems_cpc_msg active_params; /* active controller parameters */
+       void *rxbuf[MAX_RX_URBS];
+       dma_addr_t rxbuf_dma[MAX_RX_URBS];
 };
 
 static void ems_usb_read_interrupt_callback(struct urb *urb)
@@ -587,6 +589,7 @@ static int ems_usb_start(struct ems_usb *dev)
        for (i = 0; i < MAX_RX_URBS; i++) {
                struct urb *urb = NULL;
                u8 *buf = NULL;
+               dma_addr_t buf_dma;
 
                /* create a URB, and a buffer for it */
                urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -596,7 +599,7 @@ static int ems_usb_start(struct ems_usb *dev)
                }
 
                buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,
-                                        &urb->transfer_dma);
+                                        &buf_dma);
                if (!buf) {
                        netdev_err(netdev, "No memory left for USB buffer\n");
                        usb_free_urb(urb);
@@ -604,6 +607,8 @@ static int ems_usb_start(struct ems_usb *dev)
                        break;
                }
 
+               urb->transfer_dma = buf_dma;
+
                usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 2),
                                  buf, RX_BUFFER_SIZE,
                                  ems_usb_read_bulk_callback, dev);
@@ -619,6 +624,9 @@ static int ems_usb_start(struct ems_usb *dev)
                        break;
                }
 
+               dev->rxbuf[i] = buf;
+               dev->rxbuf_dma[i] = buf_dma;
+
                /* Drop reference, USB core will take care of freeing it */
                usb_free_urb(urb);
        }
@@ -684,6 +692,10 @@ static void unlink_all_urbs(struct ems_usb *dev)
 
        usb_kill_anchored_urbs(&dev->rx_submitted);
 
+       for (i = 0; i < MAX_RX_URBS; ++i)
+               usb_free_coherent(dev->udev, RX_BUFFER_SIZE,
+                                 dev->rxbuf[i], dev->rxbuf_dma[i]);
+
        usb_kill_anchored_urbs(&dev->tx_submitted);
        atomic_set(&dev->active_tx_urbs, 0);
 
index 65b58f8..66fa8b0 100644 (file)
@@ -195,6 +195,8 @@ struct esd_usb2 {
        int net_count;
        u32 version;
        int rxinitdone;
+       void *rxbuf[MAX_RX_URBS];
+       dma_addr_t rxbuf_dma[MAX_RX_URBS];
 };
 
 struct esd_usb2_net_priv {
@@ -545,6 +547,7 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
        for (i = 0; i < MAX_RX_URBS; i++) {
                struct urb *urb = NULL;
                u8 *buf = NULL;
+               dma_addr_t buf_dma;
 
                /* create a URB, and a buffer for it */
                urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -554,7 +557,7 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
                }
 
                buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,
-                                        &urb->transfer_dma);
+                                        &buf_dma);
                if (!buf) {
                        dev_warn(dev->udev->dev.parent,
                                 "No memory left for USB buffer\n");
@@ -562,6 +565,8 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
                        goto freeurb;
                }
 
+               urb->transfer_dma = buf_dma;
+
                usb_fill_bulk_urb(urb, dev->udev,
                                  usb_rcvbulkpipe(dev->udev, 1),
                                  buf, RX_BUFFER_SIZE,
@@ -574,8 +579,12 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
                        usb_unanchor_urb(urb);
                        usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
                                          urb->transfer_dma);
+                       goto freeurb;
                }
 
+               dev->rxbuf[i] = buf;
+               dev->rxbuf_dma[i] = buf_dma;
+
 freeurb:
                /* Drop reference, USB core will take care of freeing it */
                usb_free_urb(urb);
@@ -663,6 +672,11 @@ static void unlink_all_urbs(struct esd_usb2 *dev)
        int i, j;
 
        usb_kill_anchored_urbs(&dev->rx_submitted);
+
+       for (i = 0; i < MAX_RX_URBS; ++i)
+               usb_free_coherent(dev->udev, RX_BUFFER_SIZE,
+                                 dev->rxbuf[i], dev->rxbuf_dma[i]);
+
        for (i = 0; i < dev->net_count; i++) {
                priv = dev->nets[i];
                if (priv) {
index a45865b..a1a154c 100644 (file)
@@ -653,6 +653,8 @@ static int mcba_usb_start(struct mcba_priv *priv)
                        break;
                }
 
+               urb->transfer_dma = buf_dma;
+
                usb_fill_bulk_urb(urb, priv->udev,
                                  usb_rcvbulkpipe(priv->udev, MCBA_USB_EP_IN),
                                  buf, MCBA_USB_RX_BUFF_SIZE,
index 1d6f772..899a3d2 100644 (file)
 #define PCAN_USB_BERR_MASK     (PCAN_USB_ERR_RXERR | PCAN_USB_ERR_TXERR)
 
 /* identify bus event packets with rx/tx error counters */
-#define PCAN_USB_ERR_CNT               0x80
+#define PCAN_USB_ERR_CNT_DEC           0x00    /* counters are decreasing */
+#define PCAN_USB_ERR_CNT_INC           0x80    /* counters are increasing */
 
 /* private to PCAN-USB adapter */
 struct pcan_usb {
@@ -608,11 +609,12 @@ static int pcan_usb_handle_bus_evt(struct pcan_usb_msg_context *mc, u8 ir)
 
        /* acccording to the content of the packet */
        switch (ir) {
-       case PCAN_USB_ERR_CNT:
+       case PCAN_USB_ERR_CNT_DEC:
+       case PCAN_USB_ERR_CNT_INC:
 
                /* save rx/tx error counters from in the device context */
-               pdev->bec.rxerr = mc->ptr[0];
-               pdev->bec.txerr = mc->ptr[1];
+               pdev->bec.rxerr = mc->ptr[1];
+               pdev->bec.txerr = mc->ptr[2];
                break;
 
        default:
index b6e7ef0..d1b83bd 100644 (file)
@@ -137,7 +137,8 @@ struct usb_8dev_priv {
        u8 *cmd_msg_buffer;
 
        struct mutex usb_8dev_cmd_lock;
-
+       void *rxbuf[MAX_RX_URBS];
+       dma_addr_t rxbuf_dma[MAX_RX_URBS];
 };
 
 /* tx frame */
@@ -733,6 +734,7 @@ static int usb_8dev_start(struct usb_8dev_priv *priv)
        for (i = 0; i < MAX_RX_URBS; i++) {
                struct urb *urb = NULL;
                u8 *buf;
+               dma_addr_t buf_dma;
 
                /* create a URB, and a buffer for it */
                urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -742,7 +744,7 @@ static int usb_8dev_start(struct usb_8dev_priv *priv)
                }
 
                buf = usb_alloc_coherent(priv->udev, RX_BUFFER_SIZE, GFP_KERNEL,
-                                        &urb->transfer_dma);
+                                        &buf_dma);
                if (!buf) {
                        netdev_err(netdev, "No memory left for USB buffer\n");
                        usb_free_urb(urb);
@@ -750,6 +752,8 @@ static int usb_8dev_start(struct usb_8dev_priv *priv)
                        break;
                }
 
+               urb->transfer_dma = buf_dma;
+
                usb_fill_bulk_urb(urb, priv->udev,
                                  usb_rcvbulkpipe(priv->udev,
                                                  USB_8DEV_ENDP_DATA_RX),
@@ -767,6 +771,9 @@ static int usb_8dev_start(struct usb_8dev_priv *priv)
                        break;
                }
 
+               priv->rxbuf[i] = buf;
+               priv->rxbuf_dma[i] = buf_dma;
+
                /* Drop reference, USB core will take care of freeing it */
                usb_free_urb(urb);
        }
@@ -836,6 +843,10 @@ static void unlink_all_urbs(struct usb_8dev_priv *priv)
 
        usb_kill_anchored_urbs(&priv->rx_submitted);
 
+       for (i = 0; i < MAX_RX_URBS; ++i)
+               usb_free_coherent(priv->udev, RX_BUFFER_SIZE,
+                                 priv->rxbuf[i], priv->rxbuf_dma[i]);
+
        usb_kill_anchored_urbs(&priv->tx_submitted);
        atomic_set(&priv->active_tx_urbs, 0);
 
index beb4157..272b053 100644 (file)
@@ -2155,7 +2155,7 @@ static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip,
        int i, err;
 
        if (!vid)
-               return -EOPNOTSUPP;
+               return 0;
 
        err = mv88e6xxx_vtu_get(chip, vid, &vlan);
        if (err)
index 4db162c..8960658 100644 (file)
@@ -12131,9 +12131,8 @@ static void bnxt_fw_reset_task(struct work_struct *work)
                /* Make sure fw_reset_state is 0 before clearing the flag */
                smp_mb__before_atomic();
                clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
-               bnxt_ulp_start(bp, rc);
-               if (!rc)
-                       bnxt_reenable_sriov(bp);
+               bnxt_ulp_start(bp, 0);
+               bnxt_reenable_sriov(bp);
                bnxt_vf_reps_alloc(bp);
                bnxt_vf_reps_open(bp);
                bnxt_dl_health_recovery_done(bp);
index 9089e7f..ec381c2 100644 (file)
@@ -353,6 +353,12 @@ static long bnxt_ptp_ts_aux_work(struct ptp_clock_info *ptp_info)
 
        bnxt_ptp_get_current_time(bp);
        ptp->next_period = now + HZ;
+       if (time_after_eq(now, ptp->next_overflow_check)) {
+               spin_lock_bh(&ptp->ptp_lock);
+               timecounter_read(&ptp->tc);
+               spin_unlock_bh(&ptp->ptp_lock);
+               ptp->next_overflow_check = now + BNXT_PHC_OVERFLOW_PERIOD;
+       }
        return HZ;
 }
 
@@ -423,6 +429,7 @@ int bnxt_ptp_init(struct bnxt *bp)
        ptp->cc.shift = 0;
        ptp->cc.mult = 1;
 
+       ptp->next_overflow_check = jiffies + BNXT_PHC_OVERFLOW_PERIOD;
        timecounter_init(&ptp->tc, &ptp->cc, ktime_to_ns(ktime_get_real()));
 
        ptp->ptp_info = bnxt_ptp_caps;
index 4135ea3..254ba7b 100644 (file)
@@ -32,6 +32,10 @@ struct bnxt_ptp_cfg {
        u64                     current_time;
        u64                     old_time;
        unsigned long           next_period;
+       unsigned long           next_overflow_check;
+       /* 48-bit PHC overflows in 78 hours.  Check overflow every 19 hours. */
+       #define BNXT_PHC_OVERFLOW_PERIOD        (19 * 3600 * HZ)
+
        u16                     tx_seqid;
        struct bnxt             *bp;
        atomic_t                tx_avail;
index f6ff1f7..1876f15 100644 (file)
@@ -357,7 +357,7 @@ static int w840_probe1(struct pci_dev *pdev, const struct pci_device_id *ent)
        int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
        void __iomem *ioaddr;
 
-       i = pci_enable_device(pdev);
+       i = pcim_enable_device(pdev);
        if (i) return i;
 
        pci_set_master(pdev);
@@ -379,7 +379,7 @@ static int w840_probe1(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        ioaddr = pci_iomap(pdev, TULIP_BAR, netdev_res_size);
        if (!ioaddr)
-               goto err_out_free_res;
+               goto err_out_netdev;
 
        for (i = 0; i < 3; i++)
                ((__le16 *)dev->dev_addr)[i] = cpu_to_le16(eeprom_read(ioaddr, i));
@@ -458,8 +458,6 @@ static int w840_probe1(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 err_out_cleardev:
        pci_iounmap(pdev, ioaddr);
-err_out_free_res:
-       pci_release_regions(pdev);
 err_out_netdev:
        free_netdev (dev);
        return -ENODEV;
@@ -1526,7 +1524,6 @@ static void w840_remove1(struct pci_dev *pdev)
        if (dev) {
                struct netdev_private *np = netdev_priv(dev);
                unregister_netdev(dev);
-               pci_release_regions(pdev);
                pci_iounmap(pdev, np->base_addr);
                free_netdev(dev);
        }
index 3b1f845..befa9bc 100644 (file)
@@ -5,9 +5,27 @@
 #include "hclge_main.h"
 #include "hnae3.h"
 
+static int hclge_ptp_get_cycle(struct hclge_dev *hdev)
+{
+       struct hclge_ptp *ptp = hdev->ptp;
+
+       ptp->cycle.quo = readl(hdev->ptp->io_base + HCLGE_PTP_CYCLE_QUO_REG) &
+                        HCLGE_PTP_CYCLE_QUO_MASK;
+       ptp->cycle.numer = readl(hdev->ptp->io_base + HCLGE_PTP_CYCLE_NUM_REG);
+       ptp->cycle.den = readl(hdev->ptp->io_base + HCLGE_PTP_CYCLE_DEN_REG);
+
+       if (ptp->cycle.den == 0) {
+               dev_err(&hdev->pdev->dev, "invalid ptp cycle denominator!\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int hclge_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
 {
        struct hclge_dev *hdev = hclge_ptp_get_hdev(ptp);
+       struct hclge_ptp_cycle *cycle = &hdev->ptp->cycle;
        u64 adj_val, adj_base, diff;
        unsigned long flags;
        bool is_neg = false;
@@ -18,7 +36,7 @@ static int hclge_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
                is_neg = true;
        }
 
-       adj_base = HCLGE_PTP_CYCLE_ADJ_BASE * HCLGE_PTP_CYCLE_ADJ_UNIT;
+       adj_base = (u64)cycle->quo * (u64)cycle->den + (u64)cycle->numer;
        adj_val = adj_base * ppb;
        diff = div_u64(adj_val, 1000000000ULL);
 
@@ -29,16 +47,16 @@ static int hclge_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
 
        /* This clock cycle is defined by three part: quotient, numerator
         * and denominator. For example, 2.5ns, the quotient is 2,
-        * denominator is fixed to HCLGE_PTP_CYCLE_ADJ_UNIT, and numerator
-        * is 0.5 * HCLGE_PTP_CYCLE_ADJ_UNIT.
+        * denominator is fixed to ptp->cycle.den, and numerator
+        * is 0.5 * ptp->cycle.den.
         */
-       quo = div_u64_rem(adj_val, HCLGE_PTP_CYCLE_ADJ_UNIT, &numerator);
+       quo = div_u64_rem(adj_val, cycle->den, &numerator);
 
        spin_lock_irqsave(&hdev->ptp->lock, flags);
-       writel(quo, hdev->ptp->io_base + HCLGE_PTP_CYCLE_QUO_REG);
+       writel(quo & HCLGE_PTP_CYCLE_QUO_MASK,
+              hdev->ptp->io_base + HCLGE_PTP_CYCLE_QUO_REG);
        writel(numerator, hdev->ptp->io_base + HCLGE_PTP_CYCLE_NUM_REG);
-       writel(HCLGE_PTP_CYCLE_ADJ_UNIT,
-              hdev->ptp->io_base + HCLGE_PTP_CYCLE_DEN_REG);
+       writel(cycle->den, hdev->ptp->io_base + HCLGE_PTP_CYCLE_DEN_REG);
        writel(HCLGE_PTP_CYCLE_ADJ_EN,
               hdev->ptp->io_base + HCLGE_PTP_CYCLE_CFG_REG);
        spin_unlock_irqrestore(&hdev->ptp->lock, flags);
@@ -475,6 +493,10 @@ int hclge_ptp_init(struct hclge_dev *hdev)
                ret = hclge_ptp_create_clock(hdev);
                if (ret)
                        return ret;
+
+               ret = hclge_ptp_get_cycle(hdev);
+               if (ret)
+                       return ret;
        }
 
        ret = hclge_ptp_int_en(hdev, true);
index 5a202b7..dbf5f4c 100644 (file)
@@ -29,6 +29,7 @@
 #define HCLGE_PTP_TIME_ADJ_REG         0x60
 #define HCLGE_PTP_TIME_ADJ_EN          BIT(0)
 #define HCLGE_PTP_CYCLE_QUO_REG                0x64
+#define HCLGE_PTP_CYCLE_QUO_MASK       GENMASK(7, 0)
 #define HCLGE_PTP_CYCLE_DEN_REG                0x68
 #define HCLGE_PTP_CYCLE_NUM_REG                0x6C
 #define HCLGE_PTP_CYCLE_CFG_REG                0x70
@@ -37,9 +38,7 @@
 #define HCLGE_PTP_CUR_TIME_SEC_L_REG   0x78
 #define HCLGE_PTP_CUR_TIME_NSEC_REG    0x7C
 
-#define HCLGE_PTP_CYCLE_ADJ_BASE       2
 #define HCLGE_PTP_CYCLE_ADJ_MAX                500000000
-#define HCLGE_PTP_CYCLE_ADJ_UNIT       100000000
 #define HCLGE_PTP_SEC_H_OFFSET         32u
 #define HCLGE_PTP_SEC_L_MASK           GENMASK(31, 0)
 
 #define HCLGE_PTP_FLAG_TX_EN           1
 #define HCLGE_PTP_FLAG_RX_EN           2
 
+struct hclge_ptp_cycle {
+       u32 quo;
+       u32 numer;
+       u32 den;
+};
+
 struct hclge_ptp {
        struct hclge_dev *hdev;
        struct ptp_clock *clock;
@@ -58,6 +63,7 @@ struct hclge_ptp {
        spinlock_t lock;        /* protects ptp registers */
        u32 ptp_cfg;
        u32 last_tx_seqid;
+       struct hclge_ptp_cycle cycle;
        unsigned long tx_start;
        unsigned long tx_cnt;
        unsigned long tx_skipped;
index 3e822ba..2c9e4ee 100644 (file)
@@ -980,7 +980,7 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
        default:
                /* if we got here and link is up something bad is afoot */
                netdev_info(netdev,
-                           "WARNING: Link is up but PHY type 0x%x is not recognized.\n",
+                           "WARNING: Link is up but PHY type 0x%x is not recognized, or incorrect cable is in use\n",
                            hw_link_info->phy_type);
        }
 
@@ -5294,6 +5294,10 @@ flags_complete:
                                        dev_warn(&pf->pdev->dev,
                                                 "Device configuration forbids SW from starting the LLDP agent.\n");
                                        return -EINVAL;
+                               case I40E_AQ_RC_EAGAIN:
+                                       dev_warn(&pf->pdev->dev,
+                                                "Stop FW LLDP agent command is still being processed, please try again in a second.\n");
+                                       return -EBUSY;
                                default:
                                        dev_warn(&pf->pdev->dev,
                                                 "Starting FW LLDP agent failed: error: %s, %s\n",
index 861e59a..1d1f527 100644 (file)
@@ -4454,11 +4454,10 @@ int i40e_control_wait_tx_q(int seid, struct i40e_pf *pf, int pf_q,
 }
 
 /**
- * i40e_vsi_control_tx - Start or stop a VSI's rings
+ * i40e_vsi_enable_tx - Start a VSI's rings
  * @vsi: the VSI being configured
- * @enable: start or stop the rings
  **/
-static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
+static int i40e_vsi_enable_tx(struct i40e_vsi *vsi)
 {
        struct i40e_pf *pf = vsi->back;
        int i, pf_q, ret = 0;
@@ -4467,7 +4466,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
        for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
                ret = i40e_control_wait_tx_q(vsi->seid, pf,
                                             pf_q,
-                                            false /*is xdp*/, enable);
+                                            false /*is xdp*/, true);
                if (ret)
                        break;
 
@@ -4476,7 +4475,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
 
                ret = i40e_control_wait_tx_q(vsi->seid, pf,
                                             pf_q + vsi->alloc_queue_pairs,
-                                            true /*is xdp*/, enable);
+                                            true /*is xdp*/, true);
                if (ret)
                        break;
        }
@@ -4574,32 +4573,25 @@ int i40e_control_wait_rx_q(struct i40e_pf *pf, int pf_q, bool enable)
 }
 
 /**
- * i40e_vsi_control_rx - Start or stop a VSI's rings
+ * i40e_vsi_enable_rx - Start a VSI's rings
  * @vsi: the VSI being configured
- * @enable: start or stop the rings
  **/
-static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
+static int i40e_vsi_enable_rx(struct i40e_vsi *vsi)
 {
        struct i40e_pf *pf = vsi->back;
        int i, pf_q, ret = 0;
 
        pf_q = vsi->base_queue;
        for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
-               ret = i40e_control_wait_rx_q(pf, pf_q, enable);
+               ret = i40e_control_wait_rx_q(pf, pf_q, true);
                if (ret) {
                        dev_info(&pf->pdev->dev,
-                                "VSI seid %d Rx ring %d %sable timeout\n",
-                                vsi->seid, pf_q, (enable ? "en" : "dis"));
+                                "VSI seid %d Rx ring %d enable timeout\n",
+                                vsi->seid, pf_q);
                        break;
                }
        }
 
-       /* Due to HW errata, on Rx disable only, the register can indicate done
-        * before it really is. Needs 50ms to be sure
-        */
-       if (!enable)
-               mdelay(50);
-
        return ret;
 }
 
@@ -4612,29 +4604,47 @@ int i40e_vsi_start_rings(struct i40e_vsi *vsi)
        int ret = 0;
 
        /* do rx first for enable and last for disable */
-       ret = i40e_vsi_control_rx(vsi, true);
+       ret = i40e_vsi_enable_rx(vsi);
        if (ret)
                return ret;
-       ret = i40e_vsi_control_tx(vsi, true);
+       ret = i40e_vsi_enable_tx(vsi);
 
        return ret;
 }
 
+#define I40E_DISABLE_TX_GAP_MSEC       50
+
 /**
  * i40e_vsi_stop_rings - Stop a VSI's rings
  * @vsi: the VSI being configured
  **/
 void i40e_vsi_stop_rings(struct i40e_vsi *vsi)
 {
+       struct i40e_pf *pf = vsi->back;
+       int pf_q, err, q_end;
+
        /* When port TX is suspended, don't wait */
        if (test_bit(__I40E_PORT_SUSPENDED, vsi->back->state))
                return i40e_vsi_stop_rings_no_wait(vsi);
 
-       /* do rx first for enable and last for disable
-        * Ignore return value, we need to shutdown whatever we can
-        */
-       i40e_vsi_control_tx(vsi, false);
-       i40e_vsi_control_rx(vsi, false);
+       q_end = vsi->base_queue + vsi->num_queue_pairs;
+       for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++)
+               i40e_pre_tx_queue_cfg(&pf->hw, (u32)pf_q, false);
+
+       for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++) {
+               err = i40e_control_wait_rx_q(pf, pf_q, false);
+               if (err)
+                       dev_info(&pf->pdev->dev,
+                                "VSI seid %d Rx ring %d dissable timeout\n",
+                                vsi->seid, pf_q);
+       }
+
+       msleep(I40E_DISABLE_TX_GAP_MSEC);
+       pf_q = vsi->base_queue;
+       for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++)
+               wr32(&pf->hw, I40E_QTX_ENA(pf_q), 0);
+
+       i40e_vsi_wait_queues_disabled(vsi);
 }
 
 /**
@@ -7280,6 +7290,8 @@ static int i40e_validate_mqprio_qopt(struct i40e_vsi *vsi,
        }
        if (vsi->num_queue_pairs <
            (mqprio_qopt->qopt.offset[i] + mqprio_qopt->qopt.count[i])) {
+               dev_err(&vsi->back->pdev->dev,
+                       "Failed to create traffic channel, insufficient number of queues.\n");
                return -EINVAL;
        }
        if (sum_max_rate > i40e_get_link_speed(vsi)) {
@@ -13261,6 +13273,7 @@ static const struct net_device_ops i40e_netdev_ops = {
        .ndo_poll_controller    = i40e_netpoll,
 #endif
        .ndo_setup_tc           = __i40e_setup_tc,
+       .ndo_select_queue       = i40e_lan_select_queue,
        .ndo_set_features       = i40e_set_features,
        .ndo_set_vf_mac         = i40e_ndo_set_vf_mac,
        .ndo_set_vf_vlan        = i40e_ndo_set_vf_port_vlan,
index 38eb815..3f25bd8 100644 (file)
@@ -3631,6 +3631,56 @@ dma_error:
        return -1;
 }
 
+static u16 i40e_swdcb_skb_tx_hash(struct net_device *dev,
+                                 const struct sk_buff *skb,
+                                 u16 num_tx_queues)
+{
+       u32 jhash_initval_salt = 0xd631614b;
+       u32 hash;
+
+       if (skb->sk && skb->sk->sk_hash)
+               hash = skb->sk->sk_hash;
+       else
+               hash = (__force u16)skb->protocol ^ skb->hash;
+
+       hash = jhash_1word(hash, jhash_initval_salt);
+
+       return (u16)(((u64)hash * num_tx_queues) >> 32);
+}
+
+u16 i40e_lan_select_queue(struct net_device *netdev,
+                         struct sk_buff *skb,
+                         struct net_device __always_unused *sb_dev)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_hw *hw;
+       u16 qoffset;
+       u16 qcount;
+       u8 tclass;
+       u16 hash;
+       u8 prio;
+
+       /* is DCB enabled at all? */
+       if (vsi->tc_config.numtc == 1)
+               return i40e_swdcb_skb_tx_hash(netdev, skb,
+                                             netdev->real_num_tx_queues);
+
+       prio = skb->priority;
+       hw = &vsi->back->hw;
+       tclass = hw->local_dcbx_config.etscfg.prioritytable[prio];
+       /* sanity check */
+       if (unlikely(!(vsi->tc_config.enabled_tc & BIT(tclass))))
+               tclass = 0;
+
+       /* select a queue assigned for the given TC */
+       qcount = vsi->tc_config.tc_info[tclass].qcount;
+       hash = i40e_swdcb_skb_tx_hash(netdev, skb, qcount);
+
+       qoffset = vsi->tc_config.tc_info[tclass].qoffset;
+       return qoffset + hash;
+}
+
 /**
  * i40e_xmit_xdp_ring - transmits an XDP buffer to an XDP Tx ring
  * @xdpf: data to transmit
index 86fed05..bfc2845 100644 (file)
@@ -451,6 +451,8 @@ static inline unsigned int i40e_rx_pg_order(struct i40e_ring *ring)
 
 bool i40e_alloc_rx_buffers(struct i40e_ring *rxr, u16 cleaned_count);
 netdev_tx_t i40e_lan_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+u16 i40e_lan_select_queue(struct net_device *netdev, struct sk_buff *skb,
+                         struct net_device *sb_dev);
 void i40e_clean_tx_ring(struct i40e_ring *tx_ring);
 void i40e_clean_rx_ring(struct i40e_ring *rx_ring);
 int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring);
index 9169849..544c96c 100644 (file)
@@ -1504,8 +1504,8 @@ static int cgx_lmac_init(struct cgx *cgx)
 
                /* Add reference */
                cgx->lmac_idmap[lmac->lmac_id] = lmac;
-               cgx->mac_ops->mac_pause_frm_config(cgx, lmac->lmac_id, true);
                set_bit(lmac->lmac_id, &cgx->lmac_bmap);
+               cgx->mac_ops->mac_pause_frm_config(cgx, lmac->lmac_id, true);
        }
 
        return cgx_lmac_verify_fwi_version(cgx);
index 19bad9a..243cf80 100644 (file)
@@ -151,7 +151,10 @@ enum npc_kpu_lh_ltype {
  * Software assigns pkind for each incoming port such as CGX
  * Ethernet interfaces, LBK interfaces, etc.
  */
+#define NPC_UNRESERVED_PKIND_COUNT NPC_RX_VLAN_EXDSA_PKIND
+
 enum npc_pkind_type {
+       NPC_RX_LBK_PKIND = 0ULL,
        NPC_RX_VLAN_EXDSA_PKIND = 56ULL,
        NPC_RX_CHLEN24B_PKIND = 57ULL,
        NPC_RX_CPT_HDR_PKIND,
index 017163f..5fe277e 100644 (file)
@@ -391,8 +391,10 @@ void rvu_get_pf_numvfs(struct rvu *rvu, int pf, int *numvfs, int *hwvf)
 
        /* Get numVFs attached to this PF and first HWVF */
        cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf));
-       *numvfs = (cfg >> 12) & 0xFF;
-       *hwvf = cfg & 0xFFF;
+       if (numvfs)
+               *numvfs = (cfg >> 12) & 0xFF;
+       if (hwvf)
+               *hwvf = cfg & 0xFFF;
 }
 
 static int rvu_get_hwvf(struct rvu *rvu, int pcifunc)
index 0933699..4bfbbdf 100644 (file)
@@ -196,11 +196,22 @@ static void nix_rx_sync(struct rvu *rvu, int blkaddr)
 {
        int err;
 
-       /*Sync all in flight RX packets to LLC/DRAM */
+       /* Sync all in flight RX packets to LLC/DRAM */
        rvu_write64(rvu, blkaddr, NIX_AF_RX_SW_SYNC, BIT_ULL(0));
        err = rvu_poll_reg(rvu, blkaddr, NIX_AF_RX_SW_SYNC, BIT_ULL(0), true);
        if (err)
-               dev_err(rvu->dev, "NIX RX software sync failed\n");
+               dev_err(rvu->dev, "SYNC1: NIX RX software sync failed\n");
+
+       /* SW_SYNC ensures all existing transactions are finished and pkts
+        * are written to LLC/DRAM, queues should be teared down after
+        * successful SW_SYNC. Due to a HW errata, in some rare scenarios
+        * an existing transaction might end after SW_SYNC operation. To
+        * ensure operation is fully done, do the SW_SYNC twice.
+        */
+       rvu_write64(rvu, blkaddr, NIX_AF_RX_SW_SYNC, BIT_ULL(0));
+       err = rvu_poll_reg(rvu, blkaddr, NIX_AF_RX_SW_SYNC, BIT_ULL(0), true);
+       if (err)
+               dev_err(rvu->dev, "SYNC2: NIX RX software sync failed\n");
 }
 
 static bool is_valid_txschq(struct rvu *rvu, int blkaddr,
@@ -298,6 +309,7 @@ static int nix_interface_init(struct rvu *rvu, u16 pcifunc, int type, int nixlf)
                                        rvu_nix_chan_lbk(rvu, lbkid, vf + 1);
                pfvf->rx_chan_cnt = 1;
                pfvf->tx_chan_cnt = 1;
+               rvu_npc_set_pkind(rvu, NPC_RX_LBK_PKIND, pfvf);
                rvu_npc_install_promisc_entry(rvu, pcifunc, nixlf,
                                              pfvf->rx_chan_base,
                                              pfvf->rx_chan_cnt);
@@ -3842,7 +3854,6 @@ static void rvu_nix_block_freemem(struct rvu *rvu, int blkaddr,
                vlan = &nix_hw->txvlan;
                kfree(vlan->rsrc.bmap);
                mutex_destroy(&vlan->rsrc_lock);
-               devm_kfree(rvu->dev, vlan->entry2pfvf_map);
 
                mcast = &nix_hw->mcast;
                qmem_free(rvu->dev, mcast->mce_ctx);
index 1097291..52b2554 100644 (file)
@@ -1721,7 +1721,6 @@ static void npc_parser_profile_init(struct rvu *rvu, int blkaddr)
 {
        struct rvu_hwinfo *hw = rvu->hw;
        int num_pkinds, num_kpus, idx;
-       struct npc_pkind *pkind;
 
        /* Disable all KPUs and their entries */
        for (idx = 0; idx < hw->npc_kpus; idx++) {
@@ -1739,9 +1738,8 @@ static void npc_parser_profile_init(struct rvu *rvu, int blkaddr)
         * Check HW max count to avoid configuring junk or
         * writing to unsupported CSR addresses.
         */
-       pkind = &hw->pkind;
        num_pkinds = rvu->kpu.pkinds;
-       num_pkinds = min_t(int, pkind->rsrc.max, num_pkinds);
+       num_pkinds = min_t(int, hw->npc_pkinds, num_pkinds);
 
        for (idx = 0; idx < num_pkinds; idx++)
                npc_config_kpuaction(rvu, blkaddr, &rvu->kpu.ikpu[idx], 0, idx, true);
@@ -1891,7 +1889,8 @@ static void rvu_npc_hw_init(struct rvu *rvu, int blkaddr)
        if (npc_const1 & BIT_ULL(63))
                npc_const2 = rvu_read64(rvu, blkaddr, NPC_AF_CONST2);
 
-       pkind->rsrc.max = (npc_const1 >> 12) & 0xFFULL;
+       pkind->rsrc.max = NPC_UNRESERVED_PKIND_COUNT;
+       hw->npc_pkinds = (npc_const1 >> 12) & 0xFFULL;
        hw->npc_kpu_entries = npc_const1 & 0xFFFULL;
        hw->npc_kpus = (npc_const >> 8) & 0x1FULL;
        hw->npc_intfs = npc_const & 0xFULL;
@@ -2002,6 +2001,10 @@ int rvu_npc_init(struct rvu *rvu)
        err = rvu_alloc_bitmap(&pkind->rsrc);
        if (err)
                return err;
+       /* Reserve PKIND#0 for LBKs. Power reset value of LBK_CH_PKIND is '0',
+        * no need to configure PKIND for all LBKs separately.
+        */
+       rvu_alloc_rsrc(&pkind->rsrc);
 
        /* Allocate mem for pkind to PF and channel mapping info */
        pkind->pfchan_map = devm_kcalloc(rvu->dev, pkind->rsrc.max,
index 2e53797..820adf3 100644 (file)
@@ -71,8 +71,8 @@ static int rvu_switch_install_rules(struct rvu *rvu)
        struct rvu_switch *rswitch = &rvu->rswitch;
        u16 start = rswitch->start_entry;
        struct rvu_hwinfo *hw = rvu->hw;
-       int pf, vf, numvfs, hwvf;
        u16 pcifunc, entry = 0;
+       int pf, vf, numvfs;
        int err;
 
        for (pf = 1; pf < hw->total_pfs; pf++) {
@@ -110,8 +110,8 @@ static int rvu_switch_install_rules(struct rvu *rvu)
 
                rswitch->entry2pcifunc[entry++] = pcifunc;
 
-               rvu_get_pf_numvfs(rvu, pf, &numvfs, &hwvf);
-               for (vf = 0; vf < numvfs; vf++, hwvf++) {
+               rvu_get_pf_numvfs(rvu, pf, &numvfs, NULL);
+               for (vf = 0; vf < numvfs; vf++) {
                        pcifunc = pf << 10 | ((vf + 1) & 0x3FF);
                        rvu_get_nix_blkaddr(rvu, pcifunc);
 
@@ -198,7 +198,7 @@ void rvu_switch_disable(struct rvu *rvu)
        struct npc_mcam_free_entry_req free_req = { 0 };
        struct rvu_switch *rswitch = &rvu->rswitch;
        struct rvu_hwinfo *hw = rvu->hw;
-       int pf, vf, numvfs, hwvf;
+       int pf, vf, numvfs;
        struct msg_rsp rsp;
        u16 pcifunc;
        int err;
@@ -217,7 +217,8 @@ void rvu_switch_disable(struct rvu *rvu)
                                "Reverting RX rule for PF%d failed(%d)\n",
                                pf, err);
 
-               for (vf = 0; vf < numvfs; vf++, hwvf++) {
+               rvu_get_pf_numvfs(rvu, pf, &numvfs, NULL);
+               for (vf = 0; vf < numvfs; vf++) {
                        pcifunc = pf << 10 | ((vf + 1) & 0x3FF);
                        err = rvu_switch_install_rx_rule(rvu, pcifunc, 0xFFF);
                        if (err)
index 7cccd80..70fcc1f 100644 (file)
@@ -924,12 +924,14 @@ static int otx2_cq_init(struct otx2_nic *pfvf, u16 qidx)
                aq->cq.drop = RQ_DROP_LVL_CQ(pfvf->hw.rq_skid, cq->cqe_cnt);
                aq->cq.drop_ena = 1;
 
-               /* Enable receive CQ backpressure */
-               aq->cq.bp_ena = 1;
-               aq->cq.bpid = pfvf->bpid[0];
+               if (!is_otx2_lbkvf(pfvf->pdev)) {
+                       /* Enable receive CQ backpressure */
+                       aq->cq.bp_ena = 1;
+                       aq->cq.bpid = pfvf->bpid[0];
 
-               /* Set backpressure level is same as cq pass level */
-               aq->cq.bp = RQ_PASS_LVL_CQ(pfvf->hw.rq_skid, qset->rqe_cnt);
+                       /* Set backpressure level is same as cq pass level */
+                       aq->cq.bp = RQ_PASS_LVL_CQ(pfvf->hw.rq_skid, qset->rqe_cnt);
+               }
        }
 
        /* Fill AQ info */
@@ -1186,7 +1188,7 @@ static int otx2_aura_init(struct otx2_nic *pfvf, int aura_id,
        aq->aura.fc_hyst_bits = 0; /* Store count on all updates */
 
        /* Enable backpressure for RQ aura */
-       if (aura_id < pfvf->hw.rqpool_cnt) {
+       if (aura_id < pfvf->hw.rqpool_cnt && !is_otx2_lbkvf(pfvf->pdev)) {
                aq->aura.bp_ena = 0;
                aq->aura.nix0_bpid = pfvf->bpid[0];
                /* Set backpressure level for RQ's Aura */
index 8df748e..b906a0e 100644 (file)
@@ -298,15 +298,14 @@ static int otx2_set_channels(struct net_device *dev,
        err = otx2_set_real_num_queues(dev, channel->tx_count,
                                       channel->rx_count);
        if (err)
-               goto fail;
+               return err;
 
        pfvf->hw.rx_queues = channel->rx_count;
        pfvf->hw.tx_queues = channel->tx_count;
        pfvf->qset.cq_cnt = pfvf->hw.tx_queues +  pfvf->hw.rx_queues;
 
-fail:
        if (if_up)
-               dev->netdev_ops->ndo_open(dev);
+               err = dev->netdev_ops->ndo_open(dev);
 
        netdev_info(dev, "Setting num Tx rings to %d, Rx rings to %d success\n",
                    pfvf->hw.tx_queues, pfvf->hw.rx_queues);
@@ -410,7 +409,7 @@ static int otx2_set_ringparam(struct net_device *netdev,
        qs->rqe_cnt = rx_count;
 
        if (if_up)
-               netdev->netdev_ops->ndo_open(netdev);
+               return netdev->netdev_ops->ndo_open(netdev);
 
        return 0;
 }
index f300b80..2c24944 100644 (file)
@@ -1662,6 +1662,7 @@ int otx2_open(struct net_device *netdev)
 err_tx_stop_queues:
        netif_tx_stop_all_queues(netdev);
        netif_carrier_off(netdev);
+       pf->flags |= OTX2_FLAG_INTF_DOWN;
 err_free_cints:
        otx2_free_cints(pf, qidx);
        vec = pci_irq_vector(pf->pdev,
@@ -1689,6 +1690,10 @@ int otx2_stop(struct net_device *netdev)
        struct otx2_rss_info *rss;
        int qidx, vec, wrk;
 
+       /* If the DOWN flag is set resources are already freed */
+       if (pf->flags & OTX2_FLAG_INTF_DOWN)
+               return 0;
+
        netif_carrier_off(netdev);
        netif_tx_stop_all_queues(netdev);
 
index 00c8465..28ac469 100644 (file)
@@ -3535,6 +3535,7 @@ slave_start:
 
                if (!SRIOV_VALID_STATE(dev->flags)) {
                        mlx4_err(dev, "Invalid SRIOV state\n");
+                       err = -EINVAL;
                        goto err_close;
                }
        }
index ceebfc2..def2156 100644 (file)
@@ -500,10 +500,7 @@ static int next_phys_dev(struct device *dev, const void *data)
        return 1;
 }
 
-/* This function is called with two flows:
- * 1. During initialization of mlx5_core_dev and we don't need to lock it.
- * 2. During LAG configure stage and caller holds &mlx5_intf_mutex.
- */
+/* Must be called with intf_mutex held */
 struct mlx5_core_dev *mlx5_get_next_phys_dev(struct mlx5_core_dev *dev)
 {
        struct auxiliary_device *adev;
index 150c8e8..2cbf18c 100644 (file)
@@ -471,6 +471,15 @@ static void mlx5e_build_rx_cq_param(struct mlx5_core_dev *mdev,
        param->cq_period_mode = params->rx_cq_moderation.cq_period_mode;
 }
 
+static u8 rq_end_pad_mode(struct mlx5_core_dev *mdev, struct mlx5e_params *params)
+{
+       bool ro = pcie_relaxed_ordering_enabled(mdev->pdev) &&
+               MLX5_CAP_GEN(mdev, relaxed_ordering_write);
+
+       return ro && params->lro_en ?
+               MLX5_WQ_END_PAD_MODE_NONE : MLX5_WQ_END_PAD_MODE_ALIGN;
+}
+
 int mlx5e_build_rq_param(struct mlx5_core_dev *mdev,
                         struct mlx5e_params *params,
                         struct mlx5e_xsk_param *xsk,
@@ -508,7 +517,7 @@ int mlx5e_build_rq_param(struct mlx5_core_dev *mdev,
        }
 
        MLX5_SET(wq, wq, wq_type,          params->rq_wq_type);
-       MLX5_SET(wq, wq, end_padding_mode, MLX5_WQ_END_PAD_MODE_ALIGN);
+       MLX5_SET(wq, wq, end_padding_mode, rq_end_pad_mode(mdev, params));
        MLX5_SET(wq, wq, log_wq_stride,
                 mlx5e_get_rqwq_log_stride(params->rq_wq_type, ndsegs));
        MLX5_SET(wq, wq, pd,               mdev->mlx5e_res.hw_objs.pdn);
index 778e229..efef4ad 100644 (file)
@@ -482,8 +482,11 @@ static void mlx5e_ptp_build_params(struct mlx5e_ptp *c,
                params->log_sq_size = orig->log_sq_size;
                mlx5e_ptp_build_sq_param(c->mdev, params, &cparams->txq_sq_param);
        }
-       if (test_bit(MLX5E_PTP_STATE_RX, c->state))
+       /* RQ */
+       if (test_bit(MLX5E_PTP_STATE_RX, c->state)) {
+               params->vlan_strip_disable = orig->vlan_strip_disable;
                mlx5e_ptp_build_rq_param(c->mdev, c->netdev, c->priv->q_counter, cparams);
+       }
 }
 
 static int mlx5e_init_ptp_rq(struct mlx5e_ptp *c, struct mlx5e_params *params,
@@ -494,7 +497,7 @@ static int mlx5e_init_ptp_rq(struct mlx5e_ptp *c, struct mlx5e_params *params,
        int err;
 
        rq->wq_type      = params->rq_wq_type;
-       rq->pdev         = mdev->device;
+       rq->pdev         = c->pdev;
        rq->netdev       = priv->netdev;
        rq->priv         = priv;
        rq->clock        = &mdev->clock;
index 86ab4e8..7f94508 100644 (file)
@@ -37,7 +37,7 @@ static void mlx5e_init_trap_rq(struct mlx5e_trap *t, struct mlx5e_params *params
        struct mlx5e_priv *priv = t->priv;
 
        rq->wq_type      = params->rq_wq_type;
-       rq->pdev         = mdev->device;
+       rq->pdev         = t->pdev;
        rq->netdev       = priv->netdev;
        rq->priv         = priv;
        rq->clock        = &mdev->clock;
index d09e655..37c4408 100644 (file)
@@ -3384,7 +3384,7 @@ static int mlx5e_modify_channels_scatter_fcs(struct mlx5e_channels *chs, bool en
 
 static int mlx5e_modify_channels_vsd(struct mlx5e_channels *chs, bool vsd)
 {
-       int err = 0;
+       int err;
        int i;
 
        for (i = 0; i < chs->num; i++) {
@@ -3392,6 +3392,8 @@ static int mlx5e_modify_channels_vsd(struct mlx5e_channels *chs, bool vsd)
                if (err)
                        return err;
        }
+       if (chs->ptp && test_bit(MLX5E_PTP_STATE_RX, chs->ptp->state))
+               return mlx5e_modify_rq_vsd(&chs->ptp->rq, vsd);
 
        return 0;
 }
@@ -3829,6 +3831,24 @@ int mlx5e_set_features(struct net_device *netdev, netdev_features_t features)
        return 0;
 }
 
+static netdev_features_t mlx5e_fix_uplink_rep_features(struct net_device *netdev,
+                                                      netdev_features_t features)
+{
+       features &= ~NETIF_F_HW_TLS_RX;
+       if (netdev->features & NETIF_F_HW_TLS_RX)
+               netdev_warn(netdev, "Disabling hw_tls_rx, not supported in switchdev mode\n");
+
+       features &= ~NETIF_F_HW_TLS_TX;
+       if (netdev->features & NETIF_F_HW_TLS_TX)
+               netdev_warn(netdev, "Disabling hw_tls_tx, not supported in switchdev mode\n");
+
+       features &= ~NETIF_F_NTUPLE;
+       if (netdev->features & NETIF_F_NTUPLE)
+               netdev_warn(netdev, "Disabling ntuple, not supported in switchdev mode\n");
+
+       return features;
+}
+
 static netdev_features_t mlx5e_fix_features(struct net_device *netdev,
                                            netdev_features_t features)
 {
@@ -3860,15 +3880,8 @@ static netdev_features_t mlx5e_fix_features(struct net_device *netdev,
                        netdev_warn(netdev, "Disabling rxhash, not supported when CQE compress is active\n");
        }
 
-       if (mlx5e_is_uplink_rep(priv)) {
-               features &= ~NETIF_F_HW_TLS_RX;
-               if (netdev->features & NETIF_F_HW_TLS_RX)
-                       netdev_warn(netdev, "Disabling hw_tls_rx, not supported in switchdev mode\n");
-
-               features &= ~NETIF_F_HW_TLS_TX;
-               if (netdev->features & NETIF_F_HW_TLS_TX)
-                       netdev_warn(netdev, "Disabling hw_tls_tx, not supported in switchdev mode\n");
-       }
+       if (mlx5e_is_uplink_rep(priv))
+               features = mlx5e_fix_uplink_rep_features(netdev, features);
 
        mutex_unlock(&priv->state_lock);
 
@@ -4859,6 +4872,9 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
        if (MLX5_CAP_ETH(mdev, scatter_fcs))
                netdev->hw_features |= NETIF_F_RXFCS;
 
+       if (mlx5_qos_is_supported(mdev))
+               netdev->hw_features |= NETIF_F_HW_TC;
+
        netdev->features          = netdev->hw_features;
 
        /* Defaults */
@@ -4879,8 +4895,6 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
                netdev->hw_features      |= NETIF_F_NTUPLE;
 #endif
        }
-       if (mlx5_qos_is_supported(mdev))
-               netdev->features |= NETIF_F_HW_TC;
 
        netdev->features         |= NETIF_F_HIGHDMA;
        netdev->features         |= NETIF_F_HW_VLAN_STAG_FILTER;
index 629a61e..d273758 100644 (file)
@@ -452,12 +452,32 @@ static void mlx5e_detach_mod_hdr(struct mlx5e_priv *priv,
 static
 struct mlx5_core_dev *mlx5e_hairpin_get_mdev(struct net *net, int ifindex)
 {
+       struct mlx5_core_dev *mdev;
        struct net_device *netdev;
        struct mlx5e_priv *priv;
 
-       netdev = __dev_get_by_index(net, ifindex);
+       netdev = dev_get_by_index(net, ifindex);
+       if (!netdev)
+               return ERR_PTR(-ENODEV);
+
        priv = netdev_priv(netdev);
-       return priv->mdev;
+       mdev = priv->mdev;
+       dev_put(netdev);
+
+       /* Mirred tc action holds a refcount on the ifindex net_device (see
+        * net/sched/act_mirred.c:tcf_mirred_get_dev). So, it's okay to continue using mdev
+        * after dev_put(netdev), while we're in the context of adding a tc flow.
+        *
+        * The mdev pointer corresponds to the peer/out net_device of a hairpin. It is then
+        * stored in a hairpin object, which exists until all flows, that refer to it, get
+        * removed.
+        *
+        * On the other hand, after a hairpin object has been created, the peer net_device may
+        * be removed/unbound while there are still some hairpin flows that are using it. This
+        * case is handled by mlx5e_tc_hairpin_update_dead_peer, which is hooked to
+        * NETDEV_UNREGISTER event of the peer net_device.
+        */
+       return mdev;
 }
 
 static int mlx5e_hairpin_create_transport(struct mlx5e_hairpin *hp)
@@ -666,6 +686,10 @@ mlx5e_hairpin_create(struct mlx5e_priv *priv, struct mlx5_hairpin_params *params
 
        func_mdev = priv->mdev;
        peer_mdev = mlx5e_hairpin_get_mdev(dev_net(priv->netdev), peer_ifindex);
+       if (IS_ERR(peer_mdev)) {
+               err = PTR_ERR(peer_mdev);
+               goto create_pair_err;
+       }
 
        pair = mlx5_core_hairpin_create(func_mdev, peer_mdev, params);
        if (IS_ERR(pair)) {
@@ -804,6 +828,11 @@ static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv,
        int err;
 
        peer_mdev = mlx5e_hairpin_get_mdev(dev_net(priv->netdev), peer_ifindex);
+       if (IS_ERR(peer_mdev)) {
+               NL_SET_ERR_MSG_MOD(extack, "invalid ifindex of mirred device");
+               return PTR_ERR(peer_mdev);
+       }
+
        if (!MLX5_CAP_GEN(priv->mdev, hairpin) || !MLX5_CAP_GEN(peer_mdev, hairpin)) {
                NL_SET_ERR_MSG_MOD(extack, "hairpin is not supported");
                return -EOPNOTSUPP;
index 48cac5b..d562edf 100644 (file)
@@ -636,7 +636,7 @@ struct esw_vport_tbl_namespace {
 };
 
 struct mlx5_vport_tbl_attr {
-       u16 chain;
+       u32 chain;
        u16 prio;
        u16 vport;
        const struct esw_vport_tbl_namespace *vport_ns;
index 7579f34..011e766 100644 (file)
@@ -382,10 +382,11 @@ esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *f
 {
        dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
        dest[dest_idx].vport.num = esw_attr->dests[attr_idx].rep->vport;
-       dest[dest_idx].vport.vhca_id =
-               MLX5_CAP_GEN(esw_attr->dests[attr_idx].mdev, vhca_id);
-       if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
+       if (MLX5_CAP_ESW(esw->dev, merged_eswitch)) {
+               dest[dest_idx].vport.vhca_id =
+                       MLX5_CAP_GEN(esw_attr->dests[attr_idx].mdev, vhca_id);
                dest[dest_idx].vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
+       }
        if (esw_attr->dests[attr_idx].flags & MLX5_ESW_DEST_ENCAP) {
                if (pkt_reformat) {
                        flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
@@ -2367,6 +2368,9 @@ static int mlx5_esw_offloads_devcom_event(int event,
 
        switch (event) {
        case ESW_OFFLOADS_DEVCOM_PAIR:
+               if (mlx5_get_next_phys_dev(esw->dev) != peer_esw->dev)
+                       break;
+
                if (mlx5_eswitch_vport_match_metadata_enabled(esw) !=
                    mlx5_eswitch_vport_match_metadata_enabled(peer_esw))
                        break;
index d7bf0a3..c0697e1 100644 (file)
@@ -1024,17 +1024,19 @@ static int connect_fwd_rules(struct mlx5_core_dev *dev,
 static int connect_flow_table(struct mlx5_core_dev *dev, struct mlx5_flow_table *ft,
                              struct fs_prio *prio)
 {
-       struct mlx5_flow_table *next_ft;
+       struct mlx5_flow_table *next_ft, *first_ft;
        int err = 0;
 
        /* Connect_prev_fts and update_root_ft_create are mutually exclusive */
 
-       if (list_empty(&prio->node.children)) {
+       first_ft = list_first_entry_or_null(&prio->node.children,
+                                           struct mlx5_flow_table, node.list);
+       if (!first_ft || first_ft->level > ft->level) {
                err = connect_prev_fts(dev, ft, prio);
                if (err)
                        return err;
 
-               next_ft = find_next_chained_ft(prio);
+               next_ft = first_ft ? first_ft : find_next_chained_ft(prio);
                err = connect_fwd_rules(dev, ft, next_ft);
                if (err)
                        return err;
@@ -2120,7 +2122,7 @@ static int disconnect_flow_table(struct mlx5_flow_table *ft)
                                node.list) == ft))
                return 0;
 
-       next_ft = find_next_chained_ft(prio);
+       next_ft = find_next_ft(ft);
        err = connect_fwd_rules(dev, next_ft, ft);
        if (err)
                return err;
index 9ff163c..9abeb80 100644 (file)
@@ -626,8 +626,16 @@ static void mlx5_fw_fatal_reporter_err_work(struct work_struct *work)
        }
        fw_reporter_ctx.err_synd = health->synd;
        fw_reporter_ctx.miss_counter = health->miss_counter;
-       devlink_health_report(health->fw_fatal_reporter,
-                             "FW fatal error reported", &fw_reporter_ctx);
+       if (devlink_health_report(health->fw_fatal_reporter,
+                                 "FW fatal error reported", &fw_reporter_ctx) == -ECANCELED) {
+               /* If recovery wasn't performed, due to grace period,
+                * unload the driver. This ensures that the driver
+                * closes all its resources and it is not subjected to
+                * requests from the kernel.
+                */
+               mlx5_core_err(dev, "Driver is in error state. Unloading\n");
+               mlx5_unload_one(dev);
+       }
 }
 
 static const struct devlink_health_reporter_ops mlx5_fw_fatal_reporter_ops = {
index af3a536..e795fa6 100644 (file)
@@ -29,7 +29,7 @@ static const u8 ionic_qtype_versions[IONIC_QTYPE_MAX] = {
                                      */
 };
 
-static void ionic_lif_rx_mode(struct ionic_lif *lif, unsigned int rx_mode);
+static void ionic_lif_rx_mode(struct ionic_lif *lif);
 static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr);
 static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr);
 static void ionic_link_status_check(struct ionic_lif *lif);
@@ -53,7 +53,19 @@ static void ionic_dim_work(struct work_struct *work)
        cur_moder = net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
        qcq = container_of(dim, struct ionic_qcq, dim);
        new_coal = ionic_coal_usec_to_hw(qcq->q.lif->ionic, cur_moder.usec);
-       qcq->intr.dim_coal_hw = new_coal ? new_coal : 1;
+       new_coal = new_coal ? new_coal : 1;
+
+       if (qcq->intr.dim_coal_hw != new_coal) {
+               unsigned int qi = qcq->cq.bound_q->index;
+               struct ionic_lif *lif = qcq->q.lif;
+
+               qcq->intr.dim_coal_hw = new_coal;
+
+               ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
+                                    lif->rxqcqs[qi]->intr.index,
+                                    qcq->intr.dim_coal_hw);
+       }
+
        dim->state = DIM_START_MEASURE;
 }
 
@@ -77,7 +89,7 @@ static void ionic_lif_deferred_work(struct work_struct *work)
 
                switch (w->type) {
                case IONIC_DW_TYPE_RX_MODE:
-                       ionic_lif_rx_mode(lif, w->rx_mode);
+                       ionic_lif_rx_mode(lif);
                        break;
                case IONIC_DW_TYPE_RX_ADDR_ADD:
                        ionic_lif_addr_add(lif, w->addr);
@@ -1301,10 +1313,8 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
        return 0;
 }
 
-static int ionic_lif_addr(struct ionic_lif *lif, const u8 *addr, bool add,
-                         bool can_sleep)
+static int ionic_lif_addr(struct ionic_lif *lif, const u8 *addr, bool add)
 {
-       struct ionic_deferred_work *work;
        unsigned int nmfilters;
        unsigned int nufilters;
 
@@ -1330,97 +1340,46 @@ static int ionic_lif_addr(struct ionic_lif *lif, const u8 *addr, bool add,
                        lif->nucast--;
        }
 
-       if (!can_sleep) {
-               work = kzalloc(sizeof(*work), GFP_ATOMIC);
-               if (!work)
-                       return -ENOMEM;
-               work->type = add ? IONIC_DW_TYPE_RX_ADDR_ADD :
-                                  IONIC_DW_TYPE_RX_ADDR_DEL;
-               memcpy(work->addr, addr, ETH_ALEN);
-               netdev_dbg(lif->netdev, "deferred: rx_filter %s %pM\n",
-                          add ? "add" : "del", addr);
-               ionic_lif_deferred_enqueue(&lif->deferred, work);
-       } else {
-               netdev_dbg(lif->netdev, "rx_filter %s %pM\n",
-                          add ? "add" : "del", addr);
-               if (add)
-                       return ionic_lif_addr_add(lif, addr);
-               else
-                       return ionic_lif_addr_del(lif, addr);
-       }
+       netdev_dbg(lif->netdev, "rx_filter %s %pM\n",
+                  add ? "add" : "del", addr);
+       if (add)
+               return ionic_lif_addr_add(lif, addr);
+       else
+               return ionic_lif_addr_del(lif, addr);
 
        return 0;
 }
 
 static int ionic_addr_add(struct net_device *netdev, const u8 *addr)
 {
-       return ionic_lif_addr(netdev_priv(netdev), addr, ADD_ADDR, CAN_SLEEP);
-}
-
-static int ionic_ndo_addr_add(struct net_device *netdev, const u8 *addr)
-{
-       return ionic_lif_addr(netdev_priv(netdev), addr, ADD_ADDR, CAN_NOT_SLEEP);
+       return ionic_lif_addr(netdev_priv(netdev), addr, ADD_ADDR);
 }
 
 static int ionic_addr_del(struct net_device *netdev, const u8 *addr)
 {
-       return ionic_lif_addr(netdev_priv(netdev), addr, DEL_ADDR, CAN_SLEEP);
+       return ionic_lif_addr(netdev_priv(netdev), addr, DEL_ADDR);
 }
 
-static int ionic_ndo_addr_del(struct net_device *netdev, const u8 *addr)
+static void ionic_lif_rx_mode(struct ionic_lif *lif)
 {
-       return ionic_lif_addr(netdev_priv(netdev), addr, DEL_ADDR, CAN_NOT_SLEEP);
-}
-
-static void ionic_lif_rx_mode(struct ionic_lif *lif, unsigned int rx_mode)
-{
-       struct ionic_admin_ctx ctx = {
-               .work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
-               .cmd.rx_mode_set = {
-                       .opcode = IONIC_CMD_RX_MODE_SET,
-                       .lif_index = cpu_to_le16(lif->index),
-                       .rx_mode = cpu_to_le16(rx_mode),
-               },
-       };
+       struct net_device *netdev = lif->netdev;
+       unsigned int nfilters;
+       unsigned int nd_flags;
        char buf[128];
-       int err;
+       u16 rx_mode;
        int i;
 #define REMAIN(__x) (sizeof(buf) - (__x))
 
-       i = scnprintf(buf, sizeof(buf), "rx_mode 0x%04x -> 0x%04x:",
-                     lif->rx_mode, rx_mode);
-       if (rx_mode & IONIC_RX_MODE_F_UNICAST)
-               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_UNICAST");
-       if (rx_mode & IONIC_RX_MODE_F_MULTICAST)
-               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_MULTICAST");
-       if (rx_mode & IONIC_RX_MODE_F_BROADCAST)
-               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_BROADCAST");
-       if (rx_mode & IONIC_RX_MODE_F_PROMISC)
-               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_PROMISC");
-       if (rx_mode & IONIC_RX_MODE_F_ALLMULTI)
-               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_ALLMULTI");
-       netdev_dbg(lif->netdev, "lif%d %s\n", lif->index, buf);
-
-       err = ionic_adminq_post_wait(lif, &ctx);
-       if (err)
-               netdev_warn(lif->netdev, "set rx_mode 0x%04x failed: %d\n",
-                           rx_mode, err);
-       else
-               lif->rx_mode = rx_mode;
-}
+       mutex_lock(&lif->config_lock);
 
-static void ionic_set_rx_mode(struct net_device *netdev, bool can_sleep)
-{
-       struct ionic_lif *lif = netdev_priv(netdev);
-       struct ionic_deferred_work *work;
-       unsigned int nfilters;
-       unsigned int rx_mode;
+       /* grab the flags once for local use */
+       nd_flags = netdev->flags;
 
        rx_mode = IONIC_RX_MODE_F_UNICAST;
-       rx_mode |= (netdev->flags & IFF_MULTICAST) ? IONIC_RX_MODE_F_MULTICAST : 0;
-       rx_mode |= (netdev->flags & IFF_BROADCAST) ? IONIC_RX_MODE_F_BROADCAST : 0;
-       rx_mode |= (netdev->flags & IFF_PROMISC) ? IONIC_RX_MODE_F_PROMISC : 0;
-       rx_mode |= (netdev->flags & IFF_ALLMULTI) ? IONIC_RX_MODE_F_ALLMULTI : 0;
+       rx_mode |= (nd_flags & IFF_MULTICAST) ? IONIC_RX_MODE_F_MULTICAST : 0;
+       rx_mode |= (nd_flags & IFF_BROADCAST) ? IONIC_RX_MODE_F_BROADCAST : 0;
+       rx_mode |= (nd_flags & IFF_PROMISC) ? IONIC_RX_MODE_F_PROMISC : 0;
+       rx_mode |= (nd_flags & IFF_ALLMULTI) ? IONIC_RX_MODE_F_ALLMULTI : 0;
 
        /* sync unicast addresses
         * next check to see if we're in an overflow state
@@ -1429,49 +1388,83 @@ static void ionic_set_rx_mode(struct net_device *netdev, bool can_sleep)
         *       we remove our overflow flag and check the netdev flags
         *       to see if we can disable NIC PROMISC
         */
-       if (can_sleep)
-               __dev_uc_sync(netdev, ionic_addr_add, ionic_addr_del);
-       else
-               __dev_uc_sync(netdev, ionic_ndo_addr_add, ionic_ndo_addr_del);
+       __dev_uc_sync(netdev, ionic_addr_add, ionic_addr_del);
        nfilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
        if (netdev_uc_count(netdev) + 1 > nfilters) {
                rx_mode |= IONIC_RX_MODE_F_PROMISC;
                lif->uc_overflow = true;
        } else if (lif->uc_overflow) {
                lif->uc_overflow = false;
-               if (!(netdev->flags & IFF_PROMISC))
+               if (!(nd_flags & IFF_PROMISC))
                        rx_mode &= ~IONIC_RX_MODE_F_PROMISC;
        }
 
        /* same for multicast */
-       if (can_sleep)
-               __dev_mc_sync(netdev, ionic_addr_add, ionic_addr_del);
-       else
-               __dev_mc_sync(netdev, ionic_ndo_addr_add, ionic_ndo_addr_del);
+       __dev_mc_sync(netdev, ionic_addr_add, ionic_addr_del);
        nfilters = le32_to_cpu(lif->identity->eth.max_mcast_filters);
        if (netdev_mc_count(netdev) > nfilters) {
                rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
                lif->mc_overflow = true;
        } else if (lif->mc_overflow) {
                lif->mc_overflow = false;
-               if (!(netdev->flags & IFF_ALLMULTI))
+               if (!(nd_flags & IFF_ALLMULTI))
                        rx_mode &= ~IONIC_RX_MODE_F_ALLMULTI;
        }
 
+       i = scnprintf(buf, sizeof(buf), "rx_mode 0x%04x -> 0x%04x:",
+                     lif->rx_mode, rx_mode);
+       if (rx_mode & IONIC_RX_MODE_F_UNICAST)
+               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_UNICAST");
+       if (rx_mode & IONIC_RX_MODE_F_MULTICAST)
+               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_MULTICAST");
+       if (rx_mode & IONIC_RX_MODE_F_BROADCAST)
+               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_BROADCAST");
+       if (rx_mode & IONIC_RX_MODE_F_PROMISC)
+               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_PROMISC");
+       if (rx_mode & IONIC_RX_MODE_F_ALLMULTI)
+               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_ALLMULTI");
+       if (rx_mode & IONIC_RX_MODE_F_RDMA_SNIFFER)
+               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_RDMA_SNIFFER");
+       netdev_dbg(netdev, "lif%d %s\n", lif->index, buf);
+
        if (lif->rx_mode != rx_mode) {
-               if (!can_sleep) {
-                       work = kzalloc(sizeof(*work), GFP_ATOMIC);
-                       if (!work) {
-                               netdev_err(lif->netdev, "rxmode change dropped\n");
-                               return;
-                       }
-                       work->type = IONIC_DW_TYPE_RX_MODE;
-                       work->rx_mode = rx_mode;
-                       netdev_dbg(lif->netdev, "deferred: rx_mode\n");
-                       ionic_lif_deferred_enqueue(&lif->deferred, work);
-               } else {
-                       ionic_lif_rx_mode(lif, rx_mode);
+               struct ionic_admin_ctx ctx = {
+                       .work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
+                       .cmd.rx_mode_set = {
+                               .opcode = IONIC_CMD_RX_MODE_SET,
+                               .lif_index = cpu_to_le16(lif->index),
+                       },
+               };
+               int err;
+
+               ctx.cmd.rx_mode_set.rx_mode = cpu_to_le16(rx_mode);
+               err = ionic_adminq_post_wait(lif, &ctx);
+               if (err)
+                       netdev_warn(netdev, "set rx_mode 0x%04x failed: %d\n",
+                                   rx_mode, err);
+               else
+                       lif->rx_mode = rx_mode;
+       }
+
+       mutex_unlock(&lif->config_lock);
+}
+
+static void ionic_set_rx_mode(struct net_device *netdev, bool can_sleep)
+{
+       struct ionic_lif *lif = netdev_priv(netdev);
+       struct ionic_deferred_work *work;
+
+       if (!can_sleep) {
+               work = kzalloc(sizeof(*work), GFP_ATOMIC);
+               if (!work) {
+                       netdev_err(lif->netdev, "rxmode change dropped\n");
+                       return;
                }
+               work->type = IONIC_DW_TYPE_RX_MODE;
+               netdev_dbg(lif->netdev, "deferred: rx_mode\n");
+               ionic_lif_deferred_enqueue(&lif->deferred, work);
+       } else {
+               ionic_lif_rx_mode(lif);
        }
 }
 
@@ -3058,6 +3051,7 @@ void ionic_lif_deinit(struct ionic_lif *lif)
        ionic_lif_qcq_deinit(lif, lif->notifyqcq);
        ionic_lif_qcq_deinit(lif, lif->adminqcq);
 
+       mutex_destroy(&lif->config_lock);
        mutex_destroy(&lif->queue_lock);
        ionic_lif_reset(lif);
 }
@@ -3185,7 +3179,7 @@ static int ionic_station_set(struct ionic_lif *lif)
                 */
                if (!ether_addr_equal(ctx.comp.lif_getattr.mac,
                                      netdev->dev_addr))
-                       ionic_lif_addr(lif, netdev->dev_addr, ADD_ADDR, CAN_SLEEP);
+                       ionic_lif_addr(lif, netdev->dev_addr, ADD_ADDR);
        } else {
                /* Update the netdev mac with the device's mac */
                memcpy(addr.sa_data, ctx.comp.lif_getattr.mac, netdev->addr_len);
@@ -3202,7 +3196,7 @@ static int ionic_station_set(struct ionic_lif *lif)
 
        netdev_dbg(lif->netdev, "adding station MAC addr %pM\n",
                   netdev->dev_addr);
-       ionic_lif_addr(lif, netdev->dev_addr, ADD_ADDR, CAN_SLEEP);
+       ionic_lif_addr(lif, netdev->dev_addr, ADD_ADDR);
 
        return 0;
 }
@@ -3225,6 +3219,7 @@ int ionic_lif_init(struct ionic_lif *lif)
 
        lif->hw_index = le16_to_cpu(comp.hw_index);
        mutex_init(&lif->queue_lock);
+       mutex_init(&lif->config_lock);
 
        /* now that we have the hw_index we can figure out our doorbell page */
        lif->dbid_count = le32_to_cpu(lif->ionic->ident.dev.ndbpgs_per_lif);
index 346506f..69ab59f 100644 (file)
@@ -108,7 +108,6 @@ struct ionic_deferred_work {
        struct list_head list;
        enum ionic_deferred_work_type type;
        union {
-               unsigned int rx_mode;
                u8 addr[ETH_ALEN];
                u8 fw_status;
        };
@@ -179,6 +178,7 @@ struct ionic_lif {
        unsigned int index;
        unsigned int hw_index;
        struct mutex queue_lock;        /* lock for queue structures */
+       struct mutex config_lock;       /* lock for config actions */
        spinlock_t adminq_lock;         /* lock for AdminQ operations */
        struct ionic_qcq *adminqcq;
        struct ionic_qcq *notifyqcq;
@@ -199,7 +199,7 @@ struct ionic_lif {
        unsigned int nrxq_descs;
        u32 rx_copybreak;
        u64 rxq_features;
-       unsigned int rx_mode;
+       u16 rx_mode;
        u64 hw_features;
        bool registered;
        bool mc_overflow;
@@ -302,7 +302,7 @@ int ionic_lif_identify(struct ionic *ionic, u8 lif_type,
 int ionic_lif_size(struct ionic *ionic);
 
 #if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
-int ionic_lif_hwstamp_replay(struct ionic_lif *lif);
+void ionic_lif_hwstamp_replay(struct ionic_lif *lif);
 int ionic_lif_hwstamp_set(struct ionic_lif *lif, struct ifreq *ifr);
 int ionic_lif_hwstamp_get(struct ionic_lif *lif, struct ifreq *ifr);
 ktime_t ionic_lif_phc_ktime(struct ionic_lif *lif, u64 counter);
@@ -311,10 +311,7 @@ void ionic_lif_unregister_phc(struct ionic_lif *lif);
 void ionic_lif_alloc_phc(struct ionic_lif *lif);
 void ionic_lif_free_phc(struct ionic_lif *lif);
 #else
-static inline int ionic_lif_hwstamp_replay(struct ionic_lif *lif)
-{
-       return -EOPNOTSUPP;
-}
+static inline void ionic_lif_hwstamp_replay(struct ionic_lif *lif) {}
 
 static inline int ionic_lif_hwstamp_set(struct ionic_lif *lif, struct ifreq *ifr)
 {
index a87c87e..6e2403c 100644 (file)
@@ -188,6 +188,9 @@ int ionic_lif_hwstamp_set(struct ionic_lif *lif, struct ifreq *ifr)
        struct hwtstamp_config config;
        int err;
 
+       if (!lif->phc || !lif->phc->ptp)
+               return -EOPNOTSUPP;
+
        if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
                return -EFAULT;
 
@@ -203,15 +206,16 @@ int ionic_lif_hwstamp_set(struct ionic_lif *lif, struct ifreq *ifr)
        return 0;
 }
 
-int ionic_lif_hwstamp_replay(struct ionic_lif *lif)
+void ionic_lif_hwstamp_replay(struct ionic_lif *lif)
 {
        int err;
 
+       if (!lif->phc || !lif->phc->ptp)
+               return;
+
        err = ionic_lif_hwstamp_set_ts_config(lif, NULL);
        if (err)
                netdev_info(lif->netdev, "hwstamp replay failed: %d\n", err);
-
-       return err;
 }
 
 int ionic_lif_hwstamp_get(struct ionic_lif *lif, struct ifreq *ifr)
index 0893488..0887019 100644 (file)
@@ -274,12 +274,11 @@ static void ionic_rx_clean(struct ionic_queue *q,
                }
        }
 
-       if (likely(netdev->features & NETIF_F_RXCSUM)) {
-               if (comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_CALC) {
-                       skb->ip_summed = CHECKSUM_COMPLETE;
-                       skb->csum = (__force __wsum)le16_to_cpu(comp->csum);
-                       stats->csum_complete++;
-               }
+       if (likely(netdev->features & NETIF_F_RXCSUM) &&
+           (comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_CALC)) {
+               skb->ip_summed = CHECKSUM_COMPLETE;
+               skb->csum = (__force __wsum)le16_to_cpu(comp->csum);
+               stats->csum_complete++;
        } else {
                stats->csum_none++;
        }
@@ -451,11 +450,12 @@ void ionic_rx_empty(struct ionic_queue *q)
        q->tail_idx = 0;
 }
 
-static void ionic_dim_update(struct ionic_qcq *qcq)
+static void ionic_dim_update(struct ionic_qcq *qcq, int napi_mode)
 {
        struct dim_sample dim_sample;
        struct ionic_lif *lif;
        unsigned int qi;
+       u64 pkts, bytes;
 
        if (!qcq->intr.dim_coal_hw)
                return;
@@ -463,14 +463,23 @@ static void ionic_dim_update(struct ionic_qcq *qcq)
        lif = qcq->q.lif;
        qi = qcq->cq.bound_q->index;
 
-       ionic_intr_coal_init(lif->ionic->idev.intr_ctrl,
-                            lif->rxqcqs[qi]->intr.index,
-                            qcq->intr.dim_coal_hw);
+       switch (napi_mode) {
+       case IONIC_LIF_F_TX_DIM_INTR:
+               pkts = lif->txqstats[qi].pkts;
+               bytes = lif->txqstats[qi].bytes;
+               break;
+       case IONIC_LIF_F_RX_DIM_INTR:
+               pkts = lif->rxqstats[qi].pkts;
+               bytes = lif->rxqstats[qi].bytes;
+               break;
+       default:
+               pkts = lif->txqstats[qi].pkts + lif->rxqstats[qi].pkts;
+               bytes = lif->txqstats[qi].bytes + lif->rxqstats[qi].bytes;
+               break;
+       }
 
        dim_update_sample(qcq->cq.bound_intr->rearm_count,
-                         lif->txqstats[qi].pkts,
-                         lif->txqstats[qi].bytes,
-                         &dim_sample);
+                         pkts, bytes, &dim_sample);
 
        net_dim(&qcq->dim, dim_sample);
 }
@@ -491,7 +500,7 @@ int ionic_tx_napi(struct napi_struct *napi, int budget)
                                     ionic_tx_service, NULL, NULL);
 
        if (work_done < budget && napi_complete_done(napi, work_done)) {
-               ionic_dim_update(qcq);
+               ionic_dim_update(qcq, IONIC_LIF_F_TX_DIM_INTR);
                flags |= IONIC_INTR_CRED_UNMASK;
                cq->bound_intr->rearm_count++;
        }
@@ -530,7 +539,7 @@ int ionic_rx_napi(struct napi_struct *napi, int budget)
                ionic_rx_fill(cq->bound_q);
 
        if (work_done < budget && napi_complete_done(napi, work_done)) {
-               ionic_dim_update(qcq);
+               ionic_dim_update(qcq, IONIC_LIF_F_RX_DIM_INTR);
                flags |= IONIC_INTR_CRED_UNMASK;
                cq->bound_intr->rearm_count++;
        }
@@ -576,7 +585,7 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget)
                ionic_rx_fill(rxcq->bound_q);
 
        if (rx_work_done < budget && napi_complete_done(napi, rx_work_done)) {
-               ionic_dim_update(qcq);
+               ionic_dim_update(qcq, 0);
                flags |= IONIC_INTR_CRED_UNMASK;
                rxcq->bound_intr->rearm_count++;
        }
index c59b72c..a2e4dfb 100644 (file)
@@ -831,7 +831,7 @@ int qede_configure_vlan_filters(struct qede_dev *edev)
 int qede_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
 {
        struct qede_dev *edev = netdev_priv(dev);
-       struct qede_vlan *vlan = NULL;
+       struct qede_vlan *vlan;
        int rc = 0;
 
        DP_VERBOSE(edev, NETIF_MSG_IFDOWN, "Removing vlan 0x%04x\n", vid);
@@ -842,7 +842,7 @@ int qede_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
                if (vlan->vid == vid)
                        break;
 
-       if (!vlan || (vlan->vid != vid)) {
+       if (list_entry_is_head(vlan, &edev->vlan_list, list)) {
                DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
                           "Vlan isn't configured\n");
                goto out;
index 2376b27..c00ad57 100644 (file)
@@ -154,7 +154,7 @@ static int ql_wait_for_drvr_lock(struct ql3_adapter *qdev)
                                      "driver lock acquired\n");
                        return 1;
                }
-               ssleep(1);
+               mdelay(1000);
        } while (++i < 10);
 
        netdev_err(qdev->ndev, "Timed out waiting for driver lock...\n");
@@ -3274,7 +3274,7 @@ static int ql_adapter_reset(struct ql3_adapter *qdev)
                if ((value & ISP_CONTROL_SR) == 0)
                        break;
 
-               ssleep(1);
+               mdelay(1000);
        } while ((--max_wait_time));
 
        /*
@@ -3310,7 +3310,7 @@ static int ql_adapter_reset(struct ql3_adapter *qdev)
                                                   ispControlStatus);
                        if ((value & ISP_CONTROL_FSR) == 0)
                                break;
-                       ssleep(1);
+                       mdelay(1000);
                } while ((--max_wait_time));
        }
        if (max_wait_time == 0)
index ca9c00b..cff87de 100644 (file)
@@ -443,7 +443,7 @@ static int sis900_probe(struct pci_dev *pci_dev,
 #endif
 
        /* setup various bits in PCI command register */
-       ret = pci_enable_device(pci_dev);
+       ret = pcim_enable_device(pci_dev);
        if(ret) return ret;
 
        i = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32));
@@ -469,7 +469,7 @@ static int sis900_probe(struct pci_dev *pci_dev,
        ioaddr = pci_iomap(pci_dev, 0, 0);
        if (!ioaddr) {
                ret = -ENOMEM;
-               goto err_out_cleardev;
+               goto err_out;
        }
 
        sis_priv = netdev_priv(net_dev);
@@ -581,8 +581,6 @@ err_unmap_tx:
                          sis_priv->tx_ring_dma);
 err_out_unmap:
        pci_iounmap(pci_dev, ioaddr);
-err_out_cleardev:
-       pci_release_regions(pci_dev);
  err_out:
        free_netdev(net_dev);
        return ret;
@@ -2499,7 +2497,6 @@ static void sis900_remove(struct pci_dev *pci_dev)
                          sis_priv->tx_ring_dma);
        pci_iounmap(pci_dev, sis_priv->ioaddr);
        free_netdev(net_dev);
-       pci_release_regions(pci_dev);
 }
 
 static int __maybe_unused sis900_suspend(struct device *dev)
index 67ba083..b217453 100644 (file)
@@ -1249,6 +1249,7 @@ const struct stmmac_ops dwmac410_ops = {
        .config_l3_filter = dwmac4_config_l3_filter,
        .config_l4_filter = dwmac4_config_l4_filter,
        .est_configure = dwmac5_est_configure,
+       .est_irq_status = dwmac5_est_irq_status,
        .fpe_configure = dwmac5_fpe_configure,
        .fpe_send_mpacket = dwmac5_fpe_send_mpacket,
        .fpe_irq_status = dwmac5_fpe_irq_status,
@@ -1300,6 +1301,7 @@ const struct stmmac_ops dwmac510_ops = {
        .config_l3_filter = dwmac4_config_l3_filter,
        .config_l4_filter = dwmac4_config_l4_filter,
        .est_configure = dwmac5_est_configure,
+       .est_irq_status = dwmac5_est_irq_status,
        .fpe_configure = dwmac5_fpe_configure,
        .fpe_send_mpacket = dwmac5_fpe_send_mpacket,
        .fpe_irq_status = dwmac5_fpe_irq_status,
index 74e7486..860644d 100644 (file)
@@ -8191,8 +8191,9 @@ static int niu_pci_vpd_fetch(struct niu *np, u32 start)
                err = niu_pci_vpd_scan_props(np, here, end);
                if (err < 0)
                        return err;
+               /* ret == 1 is not an error */
                if (err == 1)
-                       return -EINVAL;
+                       return 0;
        }
        return 0;
 }
index 7bf3011..83aea5c 100644 (file)
@@ -288,7 +288,7 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
        if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) {
                if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E ||
                    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810 ||
-                   BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E)
+                   BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811)
                        val |= BCM54XX_SHD_SCR3_RXCTXC_DIS;
                else
                        val |= BCM54XX_SHD_SCR3_TRDDAPD;
index 1df9595..514f2c1 100644 (file)
@@ -136,6 +136,29 @@ static struct ieee80211_supported_band band_5ghz = {
 /* Assigned at module init. Guaranteed locally-administered and unicast. */
 static u8 fake_router_bssid[ETH_ALEN] __ro_after_init = {};
 
+static void virt_wifi_inform_bss(struct wiphy *wiphy)
+{
+       u64 tsf = div_u64(ktime_get_boottime_ns(), 1000);
+       struct cfg80211_bss *informed_bss;
+       static const struct {
+               u8 tag;
+               u8 len;
+               u8 ssid[8];
+       } __packed ssid = {
+               .tag = WLAN_EID_SSID,
+               .len = 8,
+               .ssid = "VirtWifi",
+       };
+
+       informed_bss = cfg80211_inform_bss(wiphy, &channel_5ghz,
+                                          CFG80211_BSS_FTYPE_PRESP,
+                                          fake_router_bssid, tsf,
+                                          WLAN_CAPABILITY_ESS, 0,
+                                          (void *)&ssid, sizeof(ssid),
+                                          DBM_TO_MBM(-50), GFP_KERNEL);
+       cfg80211_put_bss(wiphy, informed_bss);
+}
+
 /* Called with the rtnl lock held. */
 static int virt_wifi_scan(struct wiphy *wiphy,
                          struct cfg80211_scan_request *request)
@@ -156,28 +179,13 @@ static int virt_wifi_scan(struct wiphy *wiphy,
 /* Acquires and releases the rdev BSS lock. */
 static void virt_wifi_scan_result(struct work_struct *work)
 {
-       struct {
-               u8 tag;
-               u8 len;
-               u8 ssid[8];
-       } __packed ssid = {
-               .tag = WLAN_EID_SSID, .len = 8, .ssid = "VirtWifi",
-       };
-       struct cfg80211_bss *informed_bss;
        struct virt_wifi_wiphy_priv *priv =
                container_of(work, struct virt_wifi_wiphy_priv,
                             scan_result.work);
        struct wiphy *wiphy = priv_to_wiphy(priv);
        struct cfg80211_scan_info scan_info = { .aborted = false };
-       u64 tsf = div_u64(ktime_get_boottime_ns(), 1000);
 
-       informed_bss = cfg80211_inform_bss(wiphy, &channel_5ghz,
-                                          CFG80211_BSS_FTYPE_PRESP,
-                                          fake_router_bssid, tsf,
-                                          WLAN_CAPABILITY_ESS, 0,
-                                          (void *)&ssid, sizeof(ssid),
-                                          DBM_TO_MBM(-50), GFP_KERNEL);
-       cfg80211_put_bss(wiphy, informed_bss);
+       virt_wifi_inform_bss(wiphy);
 
        /* Schedules work which acquires and releases the rtnl lock. */
        cfg80211_scan_done(priv->scan_request, &scan_info);
@@ -225,10 +233,12 @@ static int virt_wifi_connect(struct wiphy *wiphy, struct net_device *netdev,
        if (!could_schedule)
                return -EBUSY;
 
-       if (sme->bssid)
+       if (sme->bssid) {
                ether_addr_copy(priv->connect_requested_bss, sme->bssid);
-       else
+       } else {
+               virt_wifi_inform_bss(wiphy);
                eth_zero_addr(priv->connect_requested_bss);
+       }
 
        wiphy_debug(wiphy, "connect\n");
 
@@ -241,11 +251,13 @@ static void virt_wifi_connect_complete(struct work_struct *work)
        struct virt_wifi_netdev_priv *priv =
                container_of(work, struct virt_wifi_netdev_priv, connect.work);
        u8 *requested_bss = priv->connect_requested_bss;
-       bool has_addr = !is_zero_ether_addr(requested_bss);
        bool right_addr = ether_addr_equal(requested_bss, fake_router_bssid);
        u16 status = WLAN_STATUS_SUCCESS;
 
-       if (!priv->is_up || (has_addr && !right_addr))
+       if (is_zero_ether_addr(requested_bss))
+               requested_bss = NULL;
+
+       if (!priv->is_up || (requested_bss && !right_addr))
                status = WLAN_STATUS_UNSPECIFIED_FAILURE;
        else
                priv->is_connected = true;
index 3e16c31..674a81d 100644 (file)
@@ -984,6 +984,8 @@ static void wwan_create_default_link(struct wwan_device *wwandev,
                goto unlock;
        }
 
+       rtnl_configure_link(dev, NULL); /* Link initialized, notify new link */
+
 unlock:
        rtnl_unlock();
 
index a9864fc..dd27c85 100644 (file)
@@ -192,8 +192,7 @@ static void nfcsim_recv_wq(struct work_struct *work)
 
                if (!IS_ERR(skb))
                        dev_kfree_skb(skb);
-
-               skb = ERR_PTR(-ENODEV);
+               return;
        }
 
        dev->cb(dev->nfc_digital_dev, dev->arg, skb);
index eb5d7a5..e3e72b8 100644 (file)
@@ -423,7 +423,7 @@ int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info)
        if (IS_ERR(tfm)) {
                ret = PTR_ERR(tfm);
                dev_err(&fw_info->ndev->nfc_dev->dev,
-                       "Cannot allocate shash (code=%d)\n", ret);
+                       "Cannot allocate shash (code=%pe)\n", tfm);
                goto out;
        }
 
index 85887d8..192c904 100644 (file)
@@ -112,6 +112,7 @@ static int i82092aa_pci_probe(struct pci_dev *dev,
        for (i = 0; i < socket_count; i++) {
                sockets[i].card_state = 1; /* 1 = present but empty */
                sockets[i].io_base = pci_resource_start(dev, 0);
+               sockets[i].dev = dev;
                sockets[i].socket.features |= SS_CAP_PCCARD;
                sockets[i].socket.map_size = 0x1000;
                sockets[i].socket.irq_mask = 0;
index b9da58e..3481479 100644 (file)
 #define AMD_PMC_RESULT_CMD_UNKNOWN           0xFE
 #define AMD_PMC_RESULT_FAILED                0xFF
 
+/* FCH SSC Registers */
+#define FCH_S0I3_ENTRY_TIME_L_OFFSET   0x30
+#define FCH_S0I3_ENTRY_TIME_H_OFFSET   0x34
+#define FCH_S0I3_EXIT_TIME_L_OFFSET    0x38
+#define FCH_S0I3_EXIT_TIME_H_OFFSET    0x3C
+#define FCH_SSC_MAPPING_SIZE           0x800
+#define FCH_BASE_PHY_ADDR_LOW          0xFED81100
+#define FCH_BASE_PHY_ADDR_HIGH         0x00000000
+
+/* SMU Message Definations */
+#define SMU_MSG_GETSMUVERSION          0x02
+#define SMU_MSG_LOG_GETDRAM_ADDR_HI    0x04
+#define SMU_MSG_LOG_GETDRAM_ADDR_LO    0x05
+#define SMU_MSG_LOG_START              0x06
+#define SMU_MSG_LOG_RESET              0x07
+#define SMU_MSG_LOG_DUMP_DATA          0x08
+#define SMU_MSG_GET_SUP_CONSTRAINTS    0x09
 /* List of supported CPU ids */
 #define AMD_CPU_ID_RV                  0x15D0
 #define AMD_CPU_ID_RN                  0x1630
 #define AMD_CPU_ID_PCO                 AMD_CPU_ID_RV
 #define AMD_CPU_ID_CZN                 AMD_CPU_ID_RN
+#define AMD_CPU_ID_YC                  0x14B5
 
-#define AMD_SMU_FW_VERSION             0x0
 #define PMC_MSG_DELAY_MIN_US           100
 #define RESPONSE_REGISTER_LOOP_MAX     200
 
+#define SOC_SUBSYSTEM_IP_MAX   12
+#define DELAY_MIN_US           2000
+#define DELAY_MAX_US           3000
 enum amd_pmc_def {
        MSG_TEST = 0x01,
        MSG_OS_HINT_PCO,
        MSG_OS_HINT_RN,
 };
 
+struct amd_pmc_bit_map {
+       const char *name;
+       u32 bit_mask;
+};
+
+static const struct amd_pmc_bit_map soc15_ip_blk[] = {
+       {"DISPLAY",     BIT(0)},
+       {"CPU",         BIT(1)},
+       {"GFX",         BIT(2)},
+       {"VDD",         BIT(3)},
+       {"ACP",         BIT(4)},
+       {"VCN",         BIT(5)},
+       {"ISP",         BIT(6)},
+       {"NBIO",        BIT(7)},
+       {"DF",          BIT(8)},
+       {"USB0",        BIT(9)},
+       {"USB1",        BIT(10)},
+       {"LAPIC",       BIT(11)},
+       {}
+};
+
 struct amd_pmc_dev {
        void __iomem *regbase;
-       void __iomem *smu_base;
+       void __iomem *smu_virt_addr;
+       void __iomem *fch_virt_addr;
        u32 base_addr;
        u32 cpu_id;
+       u32 active_ips;
        struct device *dev;
+       struct mutex lock; /* generic mutex lock */
 #if IS_ENABLED(CONFIG_DEBUG_FS)
        struct dentry *dbgfs_dir;
 #endif /* CONFIG_DEBUG_FS */
 };
 
 static struct amd_pmc_dev pmc;
+static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set, u32 *data, u8 msg, bool ret);
 
 static inline u32 amd_pmc_reg_read(struct amd_pmc_dev *dev, int reg_offset)
 {
@@ -85,18 +130,77 @@ static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u3
        iowrite32(val, dev->regbase + reg_offset);
 }
 
+struct smu_metrics {
+       u32 table_version;
+       u32 hint_count;
+       u32 s0i3_cyclecount;
+       u32 timein_s0i2;
+       u64 timeentering_s0i3_lastcapture;
+       u64 timeentering_s0i3_totaltime;
+       u64 timeto_resume_to_os_lastcapture;
+       u64 timeto_resume_to_os_totaltime;
+       u64 timein_s0i3_lastcapture;
+       u64 timein_s0i3_totaltime;
+       u64 timein_swdrips_lastcapture;
+       u64 timein_swdrips_totaltime;
+       u64 timecondition_notmet_lastcapture[SOC_SUBSYSTEM_IP_MAX];
+       u64 timecondition_notmet_totaltime[SOC_SUBSYSTEM_IP_MAX];
+} __packed;
+
 #ifdef CONFIG_DEBUG_FS
 static int smu_fw_info_show(struct seq_file *s, void *unused)
 {
        struct amd_pmc_dev *dev = s->private;
-       u32 value;
+       struct smu_metrics table;
+       int idx;
+
+       if (dev->cpu_id == AMD_CPU_ID_PCO)
+               return -EINVAL;
+
+       memcpy_fromio(&table, dev->smu_virt_addr, sizeof(struct smu_metrics));
+
+       seq_puts(s, "\n=== SMU Statistics ===\n");
+       seq_printf(s, "Table Version: %d\n", table.table_version);
+       seq_printf(s, "Hint Count: %d\n", table.hint_count);
+       seq_printf(s, "S0i3 Cycle Count: %d\n", table.s0i3_cyclecount);
+       seq_printf(s, "Time (in us) to S0i3: %lld\n", table.timeentering_s0i3_lastcapture);
+       seq_printf(s, "Time (in us) in S0i3: %lld\n", table.timein_s0i3_lastcapture);
+
+       seq_puts(s, "\n=== Active time (in us) ===\n");
+       for (idx = 0 ; idx < SOC_SUBSYSTEM_IP_MAX ; idx++) {
+               if (soc15_ip_blk[idx].bit_mask & dev->active_ips)
+                       seq_printf(s, "%-8s : %lld\n", soc15_ip_blk[idx].name,
+                                  table.timecondition_notmet_lastcapture[idx]);
+       }
 
-       value = ioread32(dev->smu_base + AMD_SMU_FW_VERSION);
-       seq_printf(s, "SMU FW Info: %x\n", value);
        return 0;
 }
 DEFINE_SHOW_ATTRIBUTE(smu_fw_info);
 
+static int s0ix_stats_show(struct seq_file *s, void *unused)
+{
+       struct amd_pmc_dev *dev = s->private;
+       u64 entry_time, exit_time, residency;
+
+       entry_time = ioread32(dev->fch_virt_addr + FCH_S0I3_ENTRY_TIME_H_OFFSET);
+       entry_time = entry_time << 32 | ioread32(dev->fch_virt_addr + FCH_S0I3_ENTRY_TIME_L_OFFSET);
+
+       exit_time = ioread32(dev->fch_virt_addr + FCH_S0I3_EXIT_TIME_H_OFFSET);
+       exit_time = exit_time << 32 | ioread32(dev->fch_virt_addr + FCH_S0I3_EXIT_TIME_L_OFFSET);
+
+       /* It's in 48MHz. We need to convert it */
+       residency = exit_time - entry_time;
+       do_div(residency, 48);
+
+       seq_puts(s, "=== S0ix statistics ===\n");
+       seq_printf(s, "S0ix Entry Time: %lld\n", entry_time);
+       seq_printf(s, "S0ix Exit Time: %lld\n", exit_time);
+       seq_printf(s, "Residency Time: %lld\n", residency);
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(s0ix_stats);
+
 static void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev)
 {
        debugfs_remove_recursive(dev->dbgfs_dir);
@@ -107,6 +211,8 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
        dev->dbgfs_dir = debugfs_create_dir("amd_pmc", NULL);
        debugfs_create_file("smu_fw_info", 0644, dev->dbgfs_dir, dev,
                            &smu_fw_info_fops);
+       debugfs_create_file("s0ix_stats", 0644, dev->dbgfs_dir, dev,
+                           &s0ix_stats_fops);
 }
 #else
 static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
@@ -118,6 +224,32 @@ static inline void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev)
 }
 #endif /* CONFIG_DEBUG_FS */
 
+static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev)
+{
+       u32 phys_addr_low, phys_addr_hi;
+       u64 smu_phys_addr;
+
+       if (dev->cpu_id == AMD_CPU_ID_PCO)
+               return -EINVAL;
+
+       /* Get Active devices list from SMU */
+       amd_pmc_send_cmd(dev, 0, &dev->active_ips, SMU_MSG_GET_SUP_CONSTRAINTS, 1);
+
+       /* Get dram address */
+       amd_pmc_send_cmd(dev, 0, &phys_addr_low, SMU_MSG_LOG_GETDRAM_ADDR_LO, 1);
+       amd_pmc_send_cmd(dev, 0, &phys_addr_hi, SMU_MSG_LOG_GETDRAM_ADDR_HI, 1);
+       smu_phys_addr = ((u64)phys_addr_hi << 32 | phys_addr_low);
+
+       dev->smu_virt_addr = devm_ioremap(dev->dev, smu_phys_addr, sizeof(struct smu_metrics));
+       if (!dev->smu_virt_addr)
+               return -ENOMEM;
+
+       /* Start the logging */
+       amd_pmc_send_cmd(dev, 0, NULL, SMU_MSG_LOG_START, 0);
+
+       return 0;
+}
+
 static void amd_pmc_dump_registers(struct amd_pmc_dev *dev)
 {
        u32 value;
@@ -132,19 +264,19 @@ static void amd_pmc_dump_registers(struct amd_pmc_dev *dev)
        dev_dbg(dev->dev, "AMD_PMC_REGISTER_MESSAGE:%x\n", value);
 }
 
-static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set)
+static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set, u32 *data, u8 msg, bool ret)
 {
        int rc;
-       u8 msg;
        u32 val;
 
+       mutex_lock(&dev->lock);
        /* Wait until we get a valid response */
        rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMC_REGISTER_RESPONSE,
-                               val, val > 0, PMC_MSG_DELAY_MIN_US,
+                               val, val != 0, PMC_MSG_DELAY_MIN_US,
                                PMC_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX);
        if (rc) {
                dev_err(dev->dev, "failed to talk to SMU\n");
-               return rc;
+               goto out_unlock;
        }
 
        /* Write zero to response register */
@@ -154,34 +286,91 @@ static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set)
        amd_pmc_reg_write(dev, AMD_PMC_REGISTER_ARGUMENT, set);
 
        /* Write message ID to message ID register */
-       msg = (dev->cpu_id == AMD_CPU_ID_RN) ? MSG_OS_HINT_RN : MSG_OS_HINT_PCO;
        amd_pmc_reg_write(dev, AMD_PMC_REGISTER_MESSAGE, msg);
-       return 0;
+
+       /* Wait until we get a valid response */
+       rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMC_REGISTER_RESPONSE,
+                               val, val != 0, PMC_MSG_DELAY_MIN_US,
+                               PMC_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX);
+       if (rc) {
+               dev_err(dev->dev, "SMU response timed out\n");
+               goto out_unlock;
+       }
+
+       switch (val) {
+       case AMD_PMC_RESULT_OK:
+               if (ret) {
+                       /* PMFW may take longer time to return back the data */
+                       usleep_range(DELAY_MIN_US, 10 * DELAY_MAX_US);
+                       *data = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_ARGUMENT);
+               }
+               break;
+       case AMD_PMC_RESULT_CMD_REJECT_BUSY:
+               dev_err(dev->dev, "SMU not ready. err: 0x%x\n", val);
+               rc = -EBUSY;
+               goto out_unlock;
+       case AMD_PMC_RESULT_CMD_UNKNOWN:
+               dev_err(dev->dev, "SMU cmd unknown. err: 0x%x\n", val);
+               rc = -EINVAL;
+               goto out_unlock;
+       case AMD_PMC_RESULT_CMD_REJECT_PREREQ:
+       case AMD_PMC_RESULT_FAILED:
+       default:
+               dev_err(dev->dev, "SMU cmd failed. err: 0x%x\n", val);
+               rc = -EIO;
+               goto out_unlock;
+       }
+
+out_unlock:
+       mutex_unlock(&dev->lock);
+       amd_pmc_dump_registers(dev);
+       return rc;
+}
+
+static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev)
+{
+       switch (dev->cpu_id) {
+       case AMD_CPU_ID_PCO:
+               return MSG_OS_HINT_PCO;
+       case AMD_CPU_ID_RN:
+       case AMD_CPU_ID_YC:
+               return MSG_OS_HINT_RN;
+       }
+       return -EINVAL;
 }
 
 static int __maybe_unused amd_pmc_suspend(struct device *dev)
 {
        struct amd_pmc_dev *pdev = dev_get_drvdata(dev);
        int rc;
+       u8 msg;
+
+       /* Reset and Start SMU logging - to monitor the s0i3 stats */
+       amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_RESET, 0);
+       amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_START, 0);
 
-       rc = amd_pmc_send_cmd(pdev, 1);
+       msg = amd_pmc_get_os_hint(pdev);
+       rc = amd_pmc_send_cmd(pdev, 1, NULL, msg, 0);
        if (rc)
                dev_err(pdev->dev, "suspend failed\n");
 
-       amd_pmc_dump_registers(pdev);
-       return 0;
+       return rc;
 }
 
 static int __maybe_unused amd_pmc_resume(struct device *dev)
 {
        struct amd_pmc_dev *pdev = dev_get_drvdata(dev);
        int rc;
+       u8 msg;
+
+       /* Let SMU know that we are looking for stats */
+       amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_DUMP_DATA, 0);
 
-       rc = amd_pmc_send_cmd(pdev, 0);
+       msg = amd_pmc_get_os_hint(pdev);
+       rc = amd_pmc_send_cmd(pdev, 0, NULL, msg, 0);
        if (rc)
                dev_err(pdev->dev, "resume failed\n");
 
-       amd_pmc_dump_registers(pdev);
        return 0;
 }
 
@@ -190,6 +379,7 @@ static const struct dev_pm_ops amd_pmc_pm_ops = {
 };
 
 static const struct pci_device_id pmc_pci_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_YC) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CZN) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RN) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PCO) },
@@ -201,9 +391,8 @@ static int amd_pmc_probe(struct platform_device *pdev)
 {
        struct amd_pmc_dev *dev = &pmc;
        struct pci_dev *rdev;
-       u32 base_addr_lo;
-       u32 base_addr_hi;
-       u64 base_addr;
+       u32 base_addr_lo, base_addr_hi;
+       u64 base_addr, fch_phys_addr;
        int err;
        u32 val;
 
@@ -248,16 +437,25 @@ static int amd_pmc_probe(struct platform_device *pdev)
        pci_dev_put(rdev);
        base_addr = ((u64)base_addr_hi << 32 | base_addr_lo);
 
-       dev->smu_base = devm_ioremap(dev->dev, base_addr, AMD_PMC_MAPPING_SIZE);
-       if (!dev->smu_base)
-               return -ENOMEM;
-
        dev->regbase = devm_ioremap(dev->dev, base_addr + AMD_PMC_BASE_ADDR_OFFSET,
                                    AMD_PMC_MAPPING_SIZE);
        if (!dev->regbase)
                return -ENOMEM;
 
-       amd_pmc_dump_registers(dev);
+       mutex_init(&dev->lock);
+
+       /* Use FCH registers to get the S0ix stats */
+       base_addr_lo = FCH_BASE_PHY_ADDR_LOW;
+       base_addr_hi = FCH_BASE_PHY_ADDR_HIGH;
+       fch_phys_addr = ((u64)base_addr_hi << 32 | base_addr_lo);
+       dev->fch_virt_addr = devm_ioremap(dev->dev, fch_phys_addr, FCH_SSC_MAPPING_SIZE);
+       if (!dev->fch_virt_addr)
+               return -ENOMEM;
+
+       /* Use SMU to get the s0i3 debug stats */
+       err = amd_pmc_setup_smu_logging(dev);
+       if (err)
+               dev_err(dev->dev, "SMU debugging info not supported on this platform\n");
 
        platform_set_drvdata(pdev, dev);
        amd_pmc_dbgfs_register(dev);
@@ -269,11 +467,14 @@ static int amd_pmc_remove(struct platform_device *pdev)
        struct amd_pmc_dev *dev = platform_get_drvdata(pdev);
 
        amd_pmc_dbgfs_unregister(dev);
+       mutex_destroy(&dev->lock);
        return 0;
 }
 
 static const struct acpi_device_id amd_pmc_acpi_ids[] = {
        {"AMDI0005", 0},
+       {"AMDI0006", 0},
+       {"AMDI0007", 0},
        {"AMD0004", 0},
        { }
 };
index 5529d7b..fbb224a 100644 (file)
@@ -141,6 +141,7 @@ static u8 gigabyte_wmi_detect_sensor_usability(struct wmi_device *wdev)
 
 static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = {
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE"),
+       DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE V2"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 GAMING X V2"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M AORUS PRO-P"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M DS3H"),
index 078648a..e5fbe01 100644 (file)
@@ -25,6 +25,7 @@ static const struct acpi_device_id intel_hid_ids[] = {
        {"INT33D5", 0},
        {"INTC1051", 0},
        {"INTC1054", 0},
+       {"INTC1070", 0},
        {"", 0},
 };
 MODULE_DEVICE_TABLE(acpi, intel_hid_ids);
index 3671b5d..6cfed44 100644 (file)
@@ -571,6 +571,11 @@ static ssize_t current_value_store(struct kobject *kobj,
        else
                ret = tlmi_save_bios_settings("");
 
+       if (!ret && !tlmi_priv.pending_changes) {
+               tlmi_priv.pending_changes = true;
+               /* let userland know it may need to check reboot pending again */
+               kobject_uevent(&tlmi_priv.class_dev->kobj, KOBJ_CHANGE);
+       }
 out:
        kfree(auth_str);
        kfree(set_str);
@@ -647,6 +652,14 @@ static struct kobj_type tlmi_pwd_setting_ktype = {
        .sysfs_ops      = &tlmi_kobj_sysfs_ops,
 };
 
+static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr,
+                                  char *buf)
+{
+       return sprintf(buf, "%d\n", tlmi_priv.pending_changes);
+}
+
+static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
+
 /* ---- Initialisation --------------------------------------------------------- */
 static void tlmi_release_attr(void)
 {
@@ -659,6 +672,7 @@ static void tlmi_release_attr(void)
                        kobject_put(&tlmi_priv.setting[i]->kobj);
                }
        }
+       sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &pending_reboot.attr);
        kset_unregister(tlmi_priv.attribute_kset);
 
        /* Authentication structures */
@@ -709,8 +723,8 @@ static int tlmi_sysfs_init(void)
 
                /* Build attribute */
                tlmi_priv.setting[i]->kobj.kset = tlmi_priv.attribute_kset;
-               ret = kobject_init_and_add(&tlmi_priv.setting[i]->kobj, &tlmi_attr_setting_ktype,
-                               NULL, "%s", tlmi_priv.setting[i]->display_name);
+               ret = kobject_add(&tlmi_priv.setting[i]->kobj, NULL,
+                                 "%s", tlmi_priv.setting[i]->display_name);
                if (ret)
                        goto fail_create_attr;
 
@@ -719,6 +733,10 @@ static int tlmi_sysfs_init(void)
                        goto fail_create_attr;
        }
 
+       ret = sysfs_create_file(&tlmi_priv.attribute_kset->kobj, &pending_reboot.attr);
+       if (ret)
+               goto fail_create_attr;
+
        /* Create authentication entries */
        tlmi_priv.authentication_kset = kset_create_and_add("authentication", NULL,
                                                                &tlmi_priv.class_dev->kobj);
@@ -727,8 +745,7 @@ static int tlmi_sysfs_init(void)
                goto fail_create_attr;
        }
        tlmi_priv.pwd_admin->kobj.kset = tlmi_priv.authentication_kset;
-       ret = kobject_init_and_add(&tlmi_priv.pwd_admin->kobj, &tlmi_pwd_setting_ktype,
-                       NULL, "%s", "Admin");
+       ret = kobject_add(&tlmi_priv.pwd_admin->kobj, NULL, "%s", "Admin");
        if (ret)
                goto fail_create_attr;
 
@@ -737,8 +754,7 @@ static int tlmi_sysfs_init(void)
                goto fail_create_attr;
 
        tlmi_priv.pwd_power->kobj.kset = tlmi_priv.authentication_kset;
-       ret = kobject_init_and_add(&tlmi_priv.pwd_power->kobj, &tlmi_pwd_setting_ktype,
-                       NULL, "%s", "System");
+       ret = kobject_add(&tlmi_priv.pwd_power->kobj, NULL, "%s", "System");
        if (ret)
                goto fail_create_attr;
 
@@ -818,6 +834,7 @@ static int tlmi_analyze(void)
                                pr_info("Error retrieving possible values for %d : %s\n",
                                                i, setting->display_name);
                }
+               kobject_init(&setting->kobj, &tlmi_attr_setting_ktype);
                tlmi_priv.setting[i] = setting;
                tlmi_priv.settings_count++;
                kfree(item);
@@ -844,10 +861,12 @@ static int tlmi_analyze(void)
        if (pwdcfg.password_state & TLMI_PAP_PWD)
                tlmi_priv.pwd_admin->valid = true;
 
+       kobject_init(&tlmi_priv.pwd_admin->kobj, &tlmi_pwd_setting_ktype);
+
        tlmi_priv.pwd_power = kzalloc(sizeof(struct tlmi_pwd_setting), GFP_KERNEL);
        if (!tlmi_priv.pwd_power) {
                ret = -ENOMEM;
-               goto fail_clear_attr;
+               goto fail_free_pwd_admin;
        }
        strscpy(tlmi_priv.pwd_power->kbdlang, "us", TLMI_LANG_MAXLEN);
        tlmi_priv.pwd_power->encoding = TLMI_ENCODING_ASCII;
@@ -859,11 +878,19 @@ static int tlmi_analyze(void)
        if (pwdcfg.password_state & TLMI_POP_PWD)
                tlmi_priv.pwd_power->valid = true;
 
+       kobject_init(&tlmi_priv.pwd_power->kobj, &tlmi_pwd_setting_ktype);
+
        return 0;
 
+fail_free_pwd_admin:
+       kfree(tlmi_priv.pwd_admin);
 fail_clear_attr:
-       for (i = 0; i < TLMI_SETTINGS_COUNT; ++i)
-               kfree(tlmi_priv.setting[i]);
+       for (i = 0; i < TLMI_SETTINGS_COUNT; ++i) {
+               if (tlmi_priv.setting[i]) {
+                       kfree(tlmi_priv.setting[i]->possible_values);
+                       kfree(tlmi_priv.setting[i]);
+               }
+       }
        return ret;
 }
 
index 6fa8da7..eb59884 100644 (file)
@@ -60,6 +60,7 @@ struct think_lmi {
        bool can_get_bios_selections;
        bool can_set_bios_password;
        bool can_get_password_settings;
+       bool pending_changes;
 
        struct tlmi_attr_setting *setting[TLMI_SETTINGS_COUNT];
        struct device *class_dev;
index b010e4c..11c60a2 100644 (file)
@@ -78,7 +78,7 @@ static int wl_add(struct acpi_device *device)
 
        err = wireless_input_setup();
        if (err)
-               pr_err("Failed to setup hp wireless hotkeys\n");
+               pr_err("Failed to setup wireless hotkeys\n");
 
        return err;
 }
index 84fc7a0..4a84599 100644 (file)
@@ -2642,6 +2642,7 @@ int acornscsi_abort(struct scsi_cmnd *SCpnt)
 //#endif
                clear_bit(SCpnt->device->id * 8 +
                          (u8)(SCpnt->device->lun & 0x7), host->busyluns);
+               fallthrough;
 
        /*
         * We found the command, and cleared it out.  Either
index 6baa9b3..9c4458a 100644 (file)
@@ -1375,6 +1375,7 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne
                case IS_COMPLETE:
                        break;
                }
+               break;
 
        default:
                break;
index 25f6e1a..66652ab 100644 (file)
@@ -453,8 +453,8 @@ static int initialize_controller(struct scsi_device *sdev,
                if (!h->ctlr)
                        err = SCSI_DH_RES_TEMP_UNAVAIL;
                else {
-                       list_add_rcu(&h->node, &h->ctlr->dh_list);
                        h->sdev = sdev;
+                       list_add_rcu(&h->node, &h->ctlr->dh_list);
                }
                spin_unlock(&list_lock);
                err = SCSI_DH_OK;
@@ -778,11 +778,11 @@ static void rdac_bus_detach( struct scsi_device *sdev )
        spin_lock(&list_lock);
        if (h->ctlr) {
                list_del_rcu(&h->node);
-               h->sdev = NULL;
                kref_put(&h->ctlr->kref, release_controller);
        }
        spin_unlock(&list_lock);
        sdev->handler_data = NULL;
+       synchronize_rcu();
        kfree(h);
 }
 
index bee1bec..935b01e 100644 (file)
@@ -807,6 +807,13 @@ static int ibmvfc_init_event_pool(struct ibmvfc_host *vhost,
        for (i = 0; i < size; ++i) {
                struct ibmvfc_event *evt = &pool->events[i];
 
+               /*
+                * evt->active states
+                *  1 = in flight
+                *  0 = being completed
+                * -1 = free/freed
+                */
+               atomic_set(&evt->active, -1);
                atomic_set(&evt->free, 1);
                evt->crq.valid = 0x80;
                evt->crq.ioba = cpu_to_be64(pool->iu_token + (sizeof(*evt->xfer_iu) * i));
@@ -1017,6 +1024,7 @@ static void ibmvfc_free_event(struct ibmvfc_event *evt)
 
        BUG_ON(!ibmvfc_valid_event(pool, evt));
        BUG_ON(atomic_inc_return(&evt->free) != 1);
+       BUG_ON(atomic_dec_and_test(&evt->active));
 
        spin_lock_irqsave(&evt->queue->l_lock, flags);
        list_add_tail(&evt->queue_list, &evt->queue->free);
@@ -1072,6 +1080,12 @@ static void ibmvfc_complete_purge(struct list_head *purge_list)
  **/
 static void ibmvfc_fail_request(struct ibmvfc_event *evt, int error_code)
 {
+       /*
+        * Anything we are failing should still be active. Otherwise, it
+        * implies we already got a response for the command and are doing
+        * something bad like double completing it.
+        */
+       BUG_ON(!atomic_dec_and_test(&evt->active));
        if (evt->cmnd) {
                evt->cmnd->result = (error_code << 16);
                evt->done = ibmvfc_scsi_eh_done;
@@ -1723,6 +1737,7 @@ static int ibmvfc_send_event(struct ibmvfc_event *evt,
 
                evt->done(evt);
        } else {
+               atomic_set(&evt->active, 1);
                spin_unlock_irqrestore(&evt->queue->l_lock, flags);
                ibmvfc_trc_start(evt);
        }
@@ -3251,7 +3266,7 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost,
                return;
        }
 
-       if (unlikely(atomic_read(&evt->free))) {
+       if (unlikely(atomic_dec_if_positive(&evt->active))) {
                dev_err(vhost->dev, "Received duplicate correlation_token 0x%08llx!\n",
                        crq->ioba);
                return;
@@ -3778,7 +3793,7 @@ static void ibmvfc_handle_scrq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost
                return;
        }
 
-       if (unlikely(atomic_read(&evt->free))) {
+       if (unlikely(atomic_dec_if_positive(&evt->active))) {
                dev_err(vhost->dev, "Received duplicate correlation_token 0x%08llx!\n",
                        crq->ioba);
                return;
index 4f0f3ba..92fb889 100644 (file)
@@ -745,6 +745,7 @@ struct ibmvfc_event {
        struct ibmvfc_target *tgt;
        struct scsi_cmnd *cmnd;
        atomic_t free;
+       atomic_t active;
        union ibmvfc_iu *xfer_iu;
        void (*done)(struct ibmvfc_event *evt);
        void (*_done)(struct ibmvfc_event *evt);
index abf7b40..c509440 100644 (file)
@@ -238,7 +238,7 @@ mraid_mm_get_adapter(mimd_t __user *umimd, int *rval)
        mimd_t          mimd;
        uint32_t        adapno;
        int             iterator;
-
+       bool            is_found;
 
        if (copy_from_user(&mimd, umimd, sizeof(mimd_t))) {
                *rval = -EFAULT;
@@ -254,12 +254,16 @@ mraid_mm_get_adapter(mimd_t __user *umimd, int *rval)
 
        adapter = NULL;
        iterator = 0;
+       is_found = false;
 
        list_for_each_entry(adapter, &adapters_list_g, list) {
-               if (iterator++ == adapno) break;
+               if (iterator++ == adapno) {
+                       is_found = true;
+                       break;
+               }
        }
 
-       if (!adapter) {
+       if (!is_found) {
                *rval = -ENODEV;
                return NULL;
        }
@@ -725,6 +729,7 @@ ioctl_done(uioc_t *kioc)
        uint32_t        adapno;
        int             iterator;
        mraid_mmadp_t*  adapter;
+       bool            is_found;
 
        /*
         * When the kioc returns from driver, make sure it still doesn't
@@ -747,19 +752,23 @@ ioctl_done(uioc_t *kioc)
                iterator        = 0;
                adapter         = NULL;
                adapno          = kioc->adapno;
+               is_found        = false;
 
                con_log(CL_ANN, ( KERN_WARNING "megaraid cmm: completed "
                                        "ioctl that was timedout before\n"));
 
                list_for_each_entry(adapter, &adapters_list_g, list) {
-                       if (iterator++ == adapno) break;
+                       if (iterator++ == adapno) {
+                               is_found = true;
+                               break;
+                       }
                }
 
                kioc->timedout = 0;
 
-               if (adapter) {
+               if (is_found)
                        mraid_mm_dealloc_kioc( adapter, kioc );
-               }
+
        }
        else {
                wake_up(&wait_q);
index 48548a9..32e60f0 100644 (file)
@@ -684,8 +684,7 @@ int pm8001_dev_found(struct domain_device *dev)
 
 void pm8001_task_done(struct sas_task *task)
 {
-       if (!del_timer(&task->slow_task->timer))
-               return;
+       del_timer(&task->slow_task->timer);
        complete(&task->slow_task->completion);
 }
 
@@ -693,9 +692,14 @@ static void pm8001_tmf_timedout(struct timer_list *t)
 {
        struct sas_task_slow *slow = from_timer(slow, t, timer);
        struct sas_task *task = slow->task;
+       unsigned long flags;
 
-       task->task_state_flags |= SAS_TASK_STATE_ABORTED;
-       complete(&task->slow_task->completion);
+       spin_lock_irqsave(&task->task_state_lock, flags);
+       if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+               task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+               complete(&task->slow_task->completion);
+       }
+       spin_unlock_irqrestore(&task->task_state_lock, flags);
 }
 
 #define PM8001_TASK_TIMEOUT 20
@@ -748,13 +752,10 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
                }
                res = -TMF_RESP_FUNC_FAILED;
                /* Even TMF timed out, return direct. */
-               if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
-                       if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
-                               pm8001_dbg(pm8001_ha, FAIL,
-                                          "TMF task[%x]timeout.\n",
-                                          tmf->tmf);
-                               goto ex_err;
-                       }
+               if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+                       pm8001_dbg(pm8001_ha, FAIL, "TMF task[%x]timeout.\n",
+                                  tmf->tmf);
+                       goto ex_err;
                }
 
                if (task->task_status.resp == SAS_TASK_COMPLETE &&
@@ -834,12 +835,9 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha,
                wait_for_completion(&task->slow_task->completion);
                res = TMF_RESP_FUNC_FAILED;
                /* Even TMF timed out, return direct. */
-               if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
-                       if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
-                               pm8001_dbg(pm8001_ha, FAIL,
-                                          "TMF task timeout.\n");
-                               goto ex_err;
-                       }
+               if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+                       pm8001_dbg(pm8001_ha, FAIL, "TMF task timeout.\n");
+                       goto ex_err;
                }
 
                if (task->task_status.resp == SAS_TASK_COMPLETE &&
index b059bf2..5b6996a 100644 (file)
@@ -475,7 +475,8 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
                error = shost->hostt->target_alloc(starget);
 
                if(error) {
-                       dev_printk(KERN_ERR, dev, "target allocation failed, error %d\n", error);
+                       if (error != -ENXIO)
+                               dev_err(dev, "target allocation failed, error %d\n", error);
                        /* don't want scsi_target_reap to do the final
                         * put because it will be under the host lock */
                        scsi_target_destroy(starget);
index 32489d2..ae9bfc6 100644 (file)
@@ -807,11 +807,14 @@ store_state_field(struct device *dev, struct device_attribute *attr,
        mutex_lock(&sdev->state_mutex);
        ret = scsi_device_set_state(sdev, state);
        /*
-        * If the device state changes to SDEV_RUNNING, we need to run
-        * the queue to avoid I/O hang.
+        * If the device state changes to SDEV_RUNNING, we need to
+        * rescan the device to revalidate it, and run the queue to
+        * avoid I/O hang.
         */
-       if (ret == 0 && state == SDEV_RUNNING)
+       if (ret == 0 && state == SDEV_RUNNING) {
+               scsi_rescan_device(dev);
                blk_mq_run_hw_queues(sdev->request_queue, true);
+       }
        mutex_unlock(&sdev->state_mutex);
 
        return ret == 0 ? count : -EINVAL;
index 94c254e..a6d3ac0 100644 (file)
@@ -221,7 +221,7 @@ static unsigned int sr_get_events(struct scsi_device *sdev)
        else if (med->media_event_code == 2)
                return DISK_EVENT_MEDIA_CHANGE;
        else if (med->media_event_code == 3)
-               return DISK_EVENT_EJECT_REQUEST;
+               return DISK_EVENT_MEDIA_CHANGE;
        return 0;
 }
 
index 06fb7a9..4d5ae61 100644 (file)
@@ -168,21 +168,6 @@ config OSF4_COMPAT
          with v4 shared libraries freely available from Compaq. If you're
          going to use shared libraries from Tru64 version 5.0 or later, say N.
 
-config BINFMT_EM86
-       tristate "Kernel support for Linux/Intel ELF binaries"
-       depends on ALPHA
-       help
-         Say Y here if you want to be able to execute Linux/Intel ELF
-         binaries just like native Alpha binaries on your Alpha machine. For
-         this to work, you need to have the emulator /usr/bin/em86 in place.
-
-         You can get the same functionality by saying N here and saying Y to
-         "Kernel support for MISC binaries".
-
-         You may answer M to compile the emulation support as a module and
-         later load the module when you want to use a Linux/Intel binary. The
-         module will be called binfmt_em86. If unsure, say Y.
-
 config BINFMT_MISC
        tristate "Kernel support for MISC binaries"
        help
index 9c708e1..f98f3e6 100644 (file)
@@ -39,7 +39,6 @@ obj-$(CONFIG_FS_ENCRYPTION)   += crypto/
 obj-$(CONFIG_FS_VERITY)                += verity/
 obj-$(CONFIG_FILE_LOCKING)      += locks.o
 obj-$(CONFIG_BINFMT_AOUT)      += binfmt_aout.o
-obj-$(CONFIG_BINFMT_EM86)      += binfmt_em86.o
 obj-$(CONFIG_BINFMT_MISC)      += binfmt_misc.o
 obj-$(CONFIG_BINFMT_SCRIPT)    += binfmt_script.o
 obj-$(CONFIG_BINFMT_ELF)       += binfmt_elf.o
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
deleted file mode 100644 (file)
index 06b9b9f..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  linux/fs/binfmt_em86.c
- *
- *  Based on linux/fs/binfmt_script.c
- *  Copyright (C) 1996  Martin von Löwis
- *  original #!-checking implemented by tytso.
- *
- *  em86 changes Copyright (C) 1997  Jim Paradis
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/binfmts.h>
-#include <linux/elf.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/errno.h>
-
-
-#define EM86_INTERP    "/usr/bin/em86"
-#define EM86_I_NAME    "em86"
-
-static int load_em86(struct linux_binprm *bprm)
-{
-       const char *i_name, *i_arg;
-       char *interp;
-       struct file * file;
-       int retval;
-       struct elfhdr   elf_ex;
-
-       /* Make sure this is a Linux/Intel ELF executable... */
-       elf_ex = *((struct elfhdr *)bprm->buf);
-
-       if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
-               return  -ENOEXEC;
-
-       /* First of all, some simple consistency checks */
-       if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
-               (!((elf_ex.e_machine == EM_386) || (elf_ex.e_machine == EM_486))) ||
-               !bprm->file->f_op->mmap) {
-                       return -ENOEXEC;
-       }
-
-       /* Need to be able to load the file after exec */
-       if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE)
-               return -ENOENT;
-
-       /* Unlike in the script case, we don't have to do any hairy
-        * parsing to find our interpreter... it's hardcoded!
-        */
-       interp = EM86_INTERP;
-       i_name = EM86_I_NAME;
-       i_arg = NULL;           /* We reserve the right to add an arg later */
-
-       /*
-        * Splice in (1) the interpreter's name for argv[0]
-        *           (2) (optional) argument to interpreter
-        *           (3) filename of emulated file (replace argv[0])
-        *
-        * This is done in reverse order, because of how the
-        * user environment and arguments are stored.
-        */
-       remove_arg_zero(bprm);
-       retval = copy_string_kernel(bprm->filename, bprm);
-       if (retval < 0) return retval; 
-       bprm->argc++;
-       if (i_arg) {
-               retval = copy_string_kernel(i_arg, bprm);
-               if (retval < 0) return retval; 
-               bprm->argc++;
-       }
-       retval = copy_string_kernel(i_name, bprm);
-       if (retval < 0) return retval;
-       bprm->argc++;
-
-       /*
-        * OK, now restart the process with the interpreter's inode.
-        * Note that we use open_exec() as the name is now in kernel
-        * space, and we don't need to copy it.
-        */
-       file = open_exec(interp);
-       if (IS_ERR(file))
-               return PTR_ERR(file);
-
-       bprm->interpreter = file;
-       return 0;
-}
-
-static struct linux_binfmt em86_format = {
-       .module         = THIS_MODULE,
-       .load_binary    = load_em86,
-};
-
-static int __init init_em86_binfmt(void)
-{
-       register_binfmt(&em86_format);
-       return 0;
-}
-
-static void __exit exit_em86_binfmt(void)
-{
-       unregister_binfmt(&em86_format);
-}
-
-core_initcall(init_em86_binfmt);
-module_exit(exit_em86_binfmt);
-MODULE_LICENSE("GPL");
index 0c424a0..9ef4f1f 100644 (file)
@@ -812,6 +812,8 @@ static void bdev_free_inode(struct inode *inode)
        free_percpu(bdev->bd_stats);
        kfree(bdev->bd_meta_info);
 
+       if (!bdev_is_partition(bdev))
+               kfree(bdev->bd_disk);
        kmem_cache_free(bdev_cachep, BDEV_I(inode));
 }
 
index 9a023ae..30d82cd 100644 (file)
@@ -352,7 +352,7 @@ static void end_compressed_bio_write(struct bio *bio)
        btrfs_record_physical_zoned(inode, cb->start, bio);
        btrfs_writepage_endio_finish_ordered(BTRFS_I(inode), NULL,
                        cb->start, cb->start + cb->len - 1,
-                       bio->bi_status == BLK_STS_OK);
+                       !cb->errors);
 
        end_compressed_writeback(inode, cb);
        /* note, our inode could be gone now */
index b117dd3..a59ab7b 100644 (file)
@@ -209,7 +209,7 @@ void btrfs_set_buffer_lockdep_class(u64 objectid, struct extent_buffer *eb,
 static void csum_tree_block(struct extent_buffer *buf, u8 *result)
 {
        struct btrfs_fs_info *fs_info = buf->fs_info;
-       const int num_pages = fs_info->nodesize >> PAGE_SHIFT;
+       const int num_pages = num_extent_pages(buf);
        const int first_page_part = min_t(u32, PAGE_SIZE, fs_info->nodesize);
        SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
        char *kaddr;
index 9fd0348..e6430ac 100644 (file)
@@ -6503,8 +6503,8 @@ void btrfs_log_new_name(struct btrfs_trans_handle *trans,
         * if this inode hasn't been logged and directory we're renaming it
         * from hasn't been logged, we don't need to log it
         */
-       if (inode->logged_trans < trans->transid &&
-           (!old_dir || old_dir->logged_trans < trans->transid))
+       if (!inode_logged(trans, inode) &&
+           (!old_dir || !inode_logged(trans, old_dir)))
                return;
 
        /*
index 1e4d43f..70f94b7 100644 (file)
@@ -1078,6 +1078,7 @@ static void __btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices,
                if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
                        list_del_init(&device->dev_alloc_list);
                        clear_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
+                       fs_devices->rw_devices--;
                }
                list_del_init(&device->dev_list);
                fs_devices->num_devices--;
index cd10860..0a72840 100644 (file)
@@ -4619,7 +4619,7 @@ read_complete:
 
 static int cifs_readpage(struct file *file, struct page *page)
 {
-       loff_t offset = (loff_t)page->index << PAGE_SHIFT;
+       loff_t offset = page_file_offset(page);
        int rc = -EACCES;
        unsigned int xid;
 
index 9a59d7f..eed59bc 100644 (file)
@@ -925,6 +925,13 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
                ctx->cred_uid = uid;
                ctx->cruid_specified = true;
                break;
+       case Opt_backupuid:
+               uid = make_kuid(current_user_ns(), result.uint_32);
+               if (!uid_valid(uid))
+                       goto cifs_parse_mount_err;
+               ctx->backupuid = uid;
+               ctx->backupuid_specified = true;
+               break;
        case Opt_backupgid:
                gid = make_kgid(current_user_ns(), result.uint_32);
                if (!gid_valid(gid))
index 23d6f4d..2dfd0d8 100644 (file)
@@ -3617,7 +3617,8 @@ static int smb3_simple_fallocate_write_range(unsigned int xid,
                                             char *buf)
 {
        struct cifs_io_parms io_parms = {0};
-       int rc, nbytes;
+       int nbytes;
+       int rc = 0;
        struct kvec iov[2];
 
        io_parms.netfid = cfile->fid.netfid;
index 14292db..2c2f179 100644 (file)
@@ -106,12 +106,11 @@ static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len)
        return err;
 }
 
-static bool ext2_check_page(struct page *page, int quiet)
+static bool ext2_check_page(struct page *page, int quiet, char *kaddr)
 {
        struct inode *dir = page->mapping->host;
        struct super_block *sb = dir->i_sb;
        unsigned chunk_size = ext2_chunk_size(dir);
-       char *kaddr = page_address(page);
        u32 max_inumber = le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count);
        unsigned offs, rec_len;
        unsigned limit = PAGE_SIZE;
@@ -205,7 +204,8 @@ static struct page * ext2_get_page(struct inode *dir, unsigned long n,
        if (!IS_ERR(page)) {
                *page_addr = kmap_local_page(page);
                if (unlikely(!PageChecked(page))) {
-                       if (PageError(page) || !ext2_check_page(page, quiet))
+                       if (PageError(page) || !ext2_check_page(page, quiet,
+                                                               *page_addr))
                                goto fail;
                }
        }
@@ -584,10 +584,10 @@ out_unlock:
  * ext2_delete_entry deletes a directory entry by merging it with the
  * previous entry. Page is up-to-date.
  */
-int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
+int ext2_delete_entry (struct ext2_dir_entry_2 *dir, struct page *page,
+                       char *kaddr)
 {
        struct inode *inode = page->mapping->host;
-       char *kaddr = page_address(page);
        unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1);
        unsigned to = ((char *)dir - kaddr) +
                                ext2_rec_len_from_disk(dir->rec_len);
@@ -607,7 +607,7 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
                de = ext2_next_entry(de);
        }
        if (pde)
-               from = (char*)pde - (char*)page_address(page);
+               from = (char *)pde - kaddr;
        pos = page_offset(page) + from;
        lock_page(page);
        err = ext2_prepare_chunk(page, pos, to - from);
index b0a6948..e512630 100644 (file)
@@ -740,7 +740,8 @@ extern int ext2_inode_by_name(struct inode *dir,
 extern int ext2_make_empty(struct inode *, struct inode *);
 extern struct ext2_dir_entry_2 *ext2_find_entry(struct inode *, const struct qstr *,
                                                struct page **, void **res_page_addr);
-extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *);
+extern int ext2_delete_entry(struct ext2_dir_entry_2 *dir, struct page *page,
+                            char *kaddr);
 extern int ext2_empty_dir (struct inode *);
 extern struct ext2_dir_entry_2 *ext2_dotdot(struct inode *dir, struct page **p, void **pa);
 extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, void *,
index 1f69b81..5f6b756 100644 (file)
@@ -293,7 +293,7 @@ static int ext2_unlink(struct inode * dir, struct dentry *dentry)
                goto out;
        }
 
-       err = ext2_delete_entry (de, page);
+       err = ext2_delete_entry (de, page, page_addr);
        ext2_put_page(page, page_addr);
        if (err)
                goto out;
@@ -397,7 +397,7 @@ static int ext2_rename (struct user_namespace * mnt_userns,
        old_inode->i_ctime = current_time(old_inode);
        mark_inode_dirty(old_inode);
 
-       ext2_delete_entry(old_de, old_page);
+       ext2_delete_entry(old_de, old_page, old_page_addr);
 
        if (dir_de) {
                if (old_dir != new_dir)
index 3ce8edb..82e8eb3 100644 (file)
@@ -61,7 +61,6 @@ extern void __init chrdev_init(void);
  */
 extern const struct fs_context_operations legacy_fs_context_ops;
 extern int parse_monolithic_mount_data(struct fs_context *, void *);
-extern void fc_drop_locked(struct fs_context *);
 extern void vfs_clean_context(struct fs_context *fc);
 extern int finish_clean_context(struct fs_context *fc);
 
index 5a0fd6b..bf548af 100644 (file)
@@ -1279,8 +1279,17 @@ static void io_prep_async_link(struct io_kiocb *req)
 {
        struct io_kiocb *cur;
 
-       io_for_each_link(cur, req)
-               io_prep_async_work(cur);
+       if (req->flags & REQ_F_LINK_TIMEOUT) {
+               struct io_ring_ctx *ctx = req->ctx;
+
+               spin_lock_irq(&ctx->completion_lock);
+               io_for_each_link(cur, req)
+                       io_prep_async_work(cur);
+               spin_unlock_irq(&ctx->completion_lock);
+       } else {
+               io_for_each_link(cur, req)
+                       io_prep_async_work(cur);
+       }
 }
 
 static void io_queue_async_work(struct io_kiocb *req)
@@ -1950,9 +1959,13 @@ static void tctx_task_work(struct callback_head *cb)
                        node = next;
                }
                if (wq_list_empty(&tctx->task_list)) {
+                       spin_lock_irq(&tctx->task_lock);
                        clear_bit(0, &tctx->task_state);
-                       if (wq_list_empty(&tctx->task_list))
+                       if (wq_list_empty(&tctx->task_list)) {
+                               spin_unlock_irq(&tctx->task_lock);
                                break;
+                       }
+                       spin_unlock_irq(&tctx->task_lock);
                        /* another tctx_task_work() is enqueued, yield */
                        if (test_and_set_bit(0, &tctx->task_state))
                                break;
@@ -2047,6 +2060,12 @@ static void io_req_task_queue(struct io_kiocb *req)
        io_req_task_work_add(req);
 }
 
+static void io_req_task_queue_reissue(struct io_kiocb *req)
+{
+       req->io_task_work.func = io_queue_async_work;
+       io_req_task_work_add(req);
+}
+
 static inline void io_queue_next(struct io_kiocb *req)
 {
        struct io_kiocb *nxt = io_req_find_next(req);
@@ -2235,7 +2254,7 @@ static void io_iopoll_complete(struct io_ring_ctx *ctx, unsigned int *nr_events,
                    !(req->flags & REQ_F_DONT_REISSUE)) {
                        req->iopoll_completed = 0;
                        req_ref_get(req);
-                       io_queue_async_work(req);
+                       io_req_task_queue_reissue(req);
                        continue;
                }
 
@@ -2428,6 +2447,12 @@ static bool io_rw_should_reissue(struct io_kiocb *req)
         */
        if (percpu_ref_is_dying(&ctx->refs))
                return false;
+       /*
+        * Play it safe and assume not safe to re-import and reissue if we're
+        * not in the original thread group (or in task context).
+        */
+       if (!same_thread_group(req->task, current) || !in_task())
+               return false;
        return true;
 }
 #else
@@ -2758,7 +2783,7 @@ static void kiocb_done(struct kiocb *kiocb, ssize_t ret,
                req->flags &= ~REQ_F_REISSUE;
                if (io_resubmit_prep(req)) {
                        req_ref_get(req);
-                       io_queue_async_work(req);
+                       io_req_task_queue_reissue(req);
                } else {
                        int cflags = 0;
 
@@ -4914,7 +4939,6 @@ static bool io_poll_complete(struct io_kiocb *req, __poll_t mask)
        if (req->poll.events & EPOLLONESHOT)
                flags = 0;
        if (!io_cqring_fill_event(ctx, req->user_data, error, flags)) {
-               io_poll_remove_waitqs(req);
                req->poll.done = true;
                flags = 0;
        }
@@ -4937,6 +4961,7 @@ static void io_poll_task_func(struct io_kiocb *req)
 
                done = io_poll_complete(req, req->result);
                if (done) {
+                       io_poll_remove_double(req);
                        hash_del(&req->hash_node);
                } else {
                        req->result = 0;
@@ -5124,7 +5149,7 @@ static __poll_t __io_arm_poll_handler(struct io_kiocb *req,
                ipt->error = -EINVAL;
 
        spin_lock_irq(&ctx->completion_lock);
-       if (ipt->error)
+       if (ipt->error || (mask && (poll->events & EPOLLONESHOT)))
                io_poll_remove_double(req);
        if (likely(poll->head)) {
                spin_lock(&poll->head->lock);
@@ -5196,7 +5221,6 @@ static int io_arm_poll_handler(struct io_kiocb *req)
        ret = __io_arm_poll_handler(req, &apoll->poll, &ipt, mask,
                                        io_async_wake);
        if (ret || ipt.error) {
-               io_poll_remove_double(req);
                spin_unlock_irq(&ctx->completion_lock);
                if (ret)
                        return IO_APOLL_READY;
index 7756579..54d7843 100644 (file)
@@ -1529,6 +1529,45 @@ static void ocfs2_truncate_cluster_pages(struct inode *inode, u64 byte_start,
        }
 }
 
+/*
+ * zero out partial blocks of one cluster.
+ *
+ * start: file offset where zero starts, will be made upper block aligned.
+ * len: it will be trimmed to the end of current cluster if "start + len"
+ *      is bigger than it.
+ */
+static int ocfs2_zeroout_partial_cluster(struct inode *inode,
+                                       u64 start, u64 len)
+{
+       int ret;
+       u64 start_block, end_block, nr_blocks;
+       u64 p_block, offset;
+       u32 cluster, p_cluster, nr_clusters;
+       struct super_block *sb = inode->i_sb;
+       u64 end = ocfs2_align_bytes_to_clusters(sb, start);
+
+       if (start + len < end)
+               end = start + len;
+
+       start_block = ocfs2_blocks_for_bytes(sb, start);
+       end_block = ocfs2_blocks_for_bytes(sb, end);
+       nr_blocks = end_block - start_block;
+       if (!nr_blocks)
+               return 0;
+
+       cluster = ocfs2_bytes_to_clusters(sb, start);
+       ret = ocfs2_get_clusters(inode, cluster, &p_cluster,
+                               &nr_clusters, NULL);
+       if (ret)
+               return ret;
+       if (!p_cluster)
+               return 0;
+
+       offset = start_block - ocfs2_clusters_to_blocks(sb, cluster);
+       p_block = ocfs2_clusters_to_blocks(sb, p_cluster) + offset;
+       return sb_issue_zeroout(sb, p_block, nr_blocks, GFP_NOFS);
+}
+
 static int ocfs2_zero_partial_clusters(struct inode *inode,
                                       u64 start, u64 len)
 {
@@ -1538,6 +1577,7 @@ static int ocfs2_zero_partial_clusters(struct inode *inode,
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        unsigned int csize = osb->s_clustersize;
        handle_t *handle;
+       loff_t isize = i_size_read(inode);
 
        /*
         * The "start" and "end" values are NOT necessarily part of
@@ -1558,6 +1598,26 @@ static int ocfs2_zero_partial_clusters(struct inode *inode,
        if ((start & (csize - 1)) == 0 && (end & (csize - 1)) == 0)
                goto out;
 
+       /* No page cache for EOF blocks, issue zero out to disk. */
+       if (end > isize) {
+               /*
+                * zeroout eof blocks in last cluster starting from
+                * "isize" even "start" > "isize" because it is
+                * complicated to zeroout just at "start" as "start"
+                * may be not aligned with block size, buffer write
+                * would be required to do that, but out of eof buffer
+                * write is not supported.
+                */
+               ret = ocfs2_zeroout_partial_cluster(inode, isize,
+                                       end - isize);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+               if (start >= isize)
+                       goto out;
+               end = isize;
+       }
        handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
        if (IS_ERR(handle)) {
                ret = PTR_ERR(handle);
@@ -1856,45 +1916,6 @@ out:
 }
 
 /*
- * zero out partial blocks of one cluster.
- *
- * start: file offset where zero starts, will be made upper block aligned.
- * len: it will be trimmed to the end of current cluster if "start + len"
- *      is bigger than it.
- */
-static int ocfs2_zeroout_partial_cluster(struct inode *inode,
-                                       u64 start, u64 len)
-{
-       int ret;
-       u64 start_block, end_block, nr_blocks;
-       u64 p_block, offset;
-       u32 cluster, p_cluster, nr_clusters;
-       struct super_block *sb = inode->i_sb;
-       u64 end = ocfs2_align_bytes_to_clusters(sb, start);
-
-       if (start + len < end)
-               end = start + len;
-
-       start_block = ocfs2_blocks_for_bytes(sb, start);
-       end_block = ocfs2_blocks_for_bytes(sb, end);
-       nr_blocks = end_block - start_block;
-       if (!nr_blocks)
-               return 0;
-
-       cluster = ocfs2_bytes_to_clusters(sb, start);
-       ret = ocfs2_get_clusters(inode, cluster, &p_cluster,
-                               &nr_clusters, NULL);
-       if (ret)
-               return ret;
-       if (!p_cluster)
-               return 0;
-
-       offset = start_block - ocfs2_clusters_to_blocks(sb, cluster);
-       p_block = ocfs2_clusters_to_blocks(sb, p_cluster) + offset;
-       return sb_issue_zeroout(sb, p_block, nr_blocks, GFP_NOFS);
-}
-
-/*
  * Parts of this function taken from xfs_change_file_space()
  */
 static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
@@ -1935,7 +1956,6 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
                goto out_inode_unlock;
        }
 
-       orig_isize = i_size_read(inode);
        switch (sr->l_whence) {
        case 0: /*SEEK_SET*/
                break;
@@ -1943,7 +1963,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
                sr->l_start += f_pos;
                break;
        case 2: /*SEEK_END*/
-               sr->l_start += orig_isize;
+               sr->l_start += i_size_read(inode);
                break;
        default:
                ret = -EINVAL;
@@ -1998,6 +2018,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
                ret = -EINVAL;
        }
 
+       orig_isize = i_size_read(inode);
        /* zeroout eof blocks in the cluster. */
        if (!ret && change_size && orig_isize < size) {
                ret = ocfs2_zeroout_partial_cluster(inode, orig_isize,
index bfd946a..8e6ef62 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
 #include "internal.h"
 
 /*
+ * New pipe buffers will be restricted to this size while the user is exceeding
+ * their pipe buffer quota. The general pipe use case needs at least two
+ * buffers: one for data yet to be read, and one for new data. If this is less
+ * than two, then a write to a non-empty pipe may block even if the pipe is not
+ * full. This can occur with GNU make jobserver or similar uses of pipes as
+ * semaphores: multiple processes may be waiting to write tokens back to the
+ * pipe before reading tokens: https://lore.kernel.org/lkml/1628086770.5rn8p04n6j.none@localhost/.
+ *
+ * Users can reduce their pipe buffers with F_SETPIPE_SZ below this at their
+ * own risk, namely: pipe writes to non-full pipes may block until the pipe is
+ * emptied.
+ */
+#define PIPE_MIN_DEF_BUFFERS 2
+
+/*
  * The max size that a non-root user is allowed to grow the pipe. Can
  * be set by root in /proc/sys/fs/pipe-max-size
  */
@@ -429,20 +444,20 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
 #endif
 
        /*
-        * Only wake up if the pipe started out empty, since
-        * otherwise there should be no readers waiting.
+        * Epoll nonsensically wants a wakeup whether the pipe
+        * was already empty or not.
         *
         * If it wasn't empty we try to merge new data into
         * the last buffer.
         *
         * That naturally merges small writes, but it also
-        * page-aligs the rest of the writes for large writes
+        * page-aligns the rest of the writes for large writes
         * spanning multiple pages.
         */
        head = pipe->head;
-       was_empty = pipe_empty(head, pipe->tail);
+       was_empty = true;
        chars = total_len & (PAGE_SIZE-1);
-       if (chars && !was_empty) {
+       if (chars && !pipe_empty(head, pipe->tail)) {
                unsigned int mask = pipe->ring_size - 1;
                struct pipe_buffer *buf = &pipe->bufs[(head - 1) & mask];
                int offset = buf->offset + buf->len;
@@ -781,8 +796,8 @@ struct pipe_inode_info *alloc_pipe_info(void)
        user_bufs = account_pipe_buffers(user, 0, pipe_bufs);
 
        if (too_many_pipe_buffers_soft(user_bufs) && pipe_is_unprivileged_user()) {
-               user_bufs = account_pipe_buffers(user, pipe_bufs, 1);
-               pipe_bufs = 1;
+               user_bufs = account_pipe_buffers(user, pipe_bufs, PIPE_MIN_DEF_BUFFERS);
+               pipe_bufs = PIPE_MIN_DEF_BUFFERS;
        }
 
        if (too_many_pipe_buffers_hard(user_bufs) && pipe_is_unprivileged_user())
index 476a7ff..ef42729 100644 (file)
@@ -387,6 +387,24 @@ void pathrelse(struct treepath *search_path)
        search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
 }
 
+static int has_valid_deh_location(struct buffer_head *bh, struct item_head *ih)
+{
+       struct reiserfs_de_head *deh;
+       int i;
+
+       deh = B_I_DEH(bh, ih);
+       for (i = 0; i < ih_entry_count(ih); i++) {
+               if (deh_location(&deh[i]) > ih_item_len(ih)) {
+                       reiserfs_warning(NULL, "reiserfs-5094",
+                                        "directory entry location seems wrong %h",
+                                        &deh[i]);
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
 static int is_leaf(char *buf, int blocksize, struct buffer_head *bh)
 {
        struct block_head *blkh;
@@ -454,11 +472,14 @@ static int is_leaf(char *buf, int blocksize, struct buffer_head *bh)
                                         "(second one): %h", ih);
                        return 0;
                }
-               if (is_direntry_le_ih(ih) && (ih_item_len(ih) < (ih_entry_count(ih) * IH_SIZE))) {
-                       reiserfs_warning(NULL, "reiserfs-5093",
-                                        "item entry count seems wrong %h",
-                                        ih);
-                       return 0;
+               if (is_direntry_le_ih(ih)) {
+                       if (ih_item_len(ih) < (ih_entry_count(ih) * IH_SIZE)) {
+                               reiserfs_warning(NULL, "reiserfs-5093",
+                                                "item entry count seems wrong %h",
+                                                ih);
+                               return 0;
+                       }
+                       return has_valid_deh_location(bh, ih);
                }
                prev_location = ih_location(ih);
        }
index 3ffafc7..58481f8 100644 (file)
@@ -2082,6 +2082,14 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
                unlock_new_inode(root_inode);
        }
 
+       if (!S_ISDIR(root_inode->i_mode) || !inode_get_bytes(root_inode) ||
+           !root_inode->i_size) {
+               SWARN(silent, s, "", "corrupt root inode, run fsck");
+               iput(root_inode);
+               errval = -EUCLEAN;
+               goto error;
+       }
+
        s->s_root = d_make_root(root_inode);
        if (!s->s_root)
                goto error;
index d548ea4..2c5bcbc 100644 (file)
@@ -411,7 +411,16 @@ struct xfs_log_dinode {
        /* start of the extended dinode, writable fields */
        uint32_t        di_crc;         /* CRC of the inode */
        uint64_t        di_changecount; /* number of attribute changes */
-       xfs_lsn_t       di_lsn;         /* flush sequence */
+
+       /*
+        * The LSN we write to this field during formatting is not a reflection
+        * of the current on-disk LSN. It should never be used for recovery
+        * sequencing, nor should it be recovered into the on-disk inode at all.
+        * See xlog_recover_inode_commit_pass2() and xfs_log_dinode_to_disk()
+        * for details.
+        */
+       xfs_lsn_t       di_lsn;
+
        uint64_t        di_flags2;      /* more random flags */
        uint32_t        di_cowextsize;  /* basic cow extent size for file */
        uint8_t         di_pad2[12];    /* more padding for future expansion */
index d44e8b4..4775485 100644 (file)
@@ -698,7 +698,8 @@ xlog_recover_do_inode_buffer(
 static xfs_lsn_t
 xlog_recover_get_buf_lsn(
        struct xfs_mount        *mp,
-       struct xfs_buf          *bp)
+       struct xfs_buf          *bp,
+       struct xfs_buf_log_format *buf_f)
 {
        uint32_t                magic32;
        uint16_t                magic16;
@@ -706,11 +707,20 @@ xlog_recover_get_buf_lsn(
        void                    *blk = bp->b_addr;
        uuid_t                  *uuid;
        xfs_lsn_t               lsn = -1;
+       uint16_t                blft;
 
        /* v4 filesystems always recover immediately */
        if (!xfs_sb_version_hascrc(&mp->m_sb))
                goto recover_immediately;
 
+       /*
+        * realtime bitmap and summary file blocks do not have magic numbers or
+        * UUIDs, so we must recover them immediately.
+        */
+       blft = xfs_blft_from_flags(buf_f);
+       if (blft == XFS_BLFT_RTBITMAP_BUF || blft == XFS_BLFT_RTSUMMARY_BUF)
+               goto recover_immediately;
+
        magic32 = be32_to_cpu(*(__be32 *)blk);
        switch (magic32) {
        case XFS_ABTB_CRC_MAGIC:
@@ -796,6 +806,7 @@ xlog_recover_get_buf_lsn(
        switch (magicda) {
        case XFS_DIR3_LEAF1_MAGIC:
        case XFS_DIR3_LEAFN_MAGIC:
+       case XFS_ATTR3_LEAF_MAGIC:
        case XFS_DA3_NODE_MAGIC:
                lsn = be64_to_cpu(((struct xfs_da3_blkinfo *)blk)->lsn);
                uuid = &((struct xfs_da3_blkinfo *)blk)->uuid;
@@ -919,7 +930,7 @@ xlog_recover_buf_commit_pass2(
         * the verifier will be reset to match whatever recover turns that
         * buffer into.
         */
-       lsn = xlog_recover_get_buf_lsn(mp, bp);
+       lsn = xlog_recover_get_buf_lsn(mp, bp, buf_f);
        if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
                trace_xfs_log_recover_buf_skip(log, buf_f);
                xlog_recover_validate_buf_type(mp, bp, buf_f, NULLCOMMITLSN);
index 7b79518..e0072a6 100644 (file)
@@ -145,7 +145,8 @@ xfs_log_dinode_to_disk_ts(
 STATIC void
 xfs_log_dinode_to_disk(
        struct xfs_log_dinode   *from,
-       struct xfs_dinode       *to)
+       struct xfs_dinode       *to,
+       xfs_lsn_t               lsn)
 {
        to->di_magic = cpu_to_be16(from->di_magic);
        to->di_mode = cpu_to_be16(from->di_mode);
@@ -182,7 +183,7 @@ xfs_log_dinode_to_disk(
                to->di_flags2 = cpu_to_be64(from->di_flags2);
                to->di_cowextsize = cpu_to_be32(from->di_cowextsize);
                to->di_ino = cpu_to_be64(from->di_ino);
-               to->di_lsn = cpu_to_be64(from->di_lsn);
+               to->di_lsn = cpu_to_be64(lsn);
                memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
                uuid_copy(&to->di_uuid, &from->di_uuid);
                to->di_flushiter = 0;
@@ -261,16 +262,25 @@ xlog_recover_inode_commit_pass2(
        }
 
        /*
-        * If the inode has an LSN in it, recover the inode only if it's less
-        * than the lsn of the transaction we are replaying. Note: we still
-        * need to replay an owner change even though the inode is more recent
-        * than the transaction as there is no guarantee that all the btree
-        * blocks are more recent than this transaction, too.
+        * If the inode has an LSN in it, recover the inode only if the on-disk
+        * inode's LSN is older than the lsn of the transaction we are
+        * replaying. We can have multiple checkpoints with the same start LSN,
+        * so the current LSN being equal to the on-disk LSN doesn't necessarily
+        * mean that the on-disk inode is more recent than the change being
+        * replayed.
+        *
+        * We must check the current_lsn against the on-disk inode
+        * here because the we can't trust the log dinode to contain a valid LSN
+        * (see comment below before replaying the log dinode for details).
+        *
+        * Note: we still need to replay an owner change even though the inode
+        * is more recent than the transaction as there is no guarantee that all
+        * the btree blocks are more recent than this transaction, too.
         */
        if (dip->di_version >= 3) {
                xfs_lsn_t       lsn = be64_to_cpu(dip->di_lsn);
 
-               if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
+               if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) > 0) {
                        trace_xfs_log_recover_inode_skip(log, in_f);
                        error = 0;
                        goto out_owner_change;
@@ -368,8 +378,17 @@ xlog_recover_inode_commit_pass2(
                goto out_release;
        }
 
-       /* recover the log dinode inode into the on disk inode */
-       xfs_log_dinode_to_disk(ldip, dip);
+       /*
+        * Recover the log dinode inode into the on disk inode.
+        *
+        * The LSN in the log dinode is garbage - it can be zero or reflect
+        * stale in-memory runtime state that isn't coherent with the changes
+        * logged in this transaction or the changes written to the on-disk
+        * inode.  Hence we write the current lSN into the inode because that
+        * matches what xfs_iflush() would write inode the inode when flushing
+        * the changes in this transaction.
+        */
+       xfs_log_dinode_to_disk(ldip, dip, current_lsn);
 
        fields = in_f->ilf_fields;
        if (fields & XFS_ILOG_DEV)
index 36fa265..60ac5fd 100644 (file)
@@ -78,13 +78,12 @@ xlog_verify_iclog(
 STATIC void
 xlog_verify_tail_lsn(
        struct xlog             *log,
-       struct xlog_in_core     *iclog,
-       xfs_lsn_t               tail_lsn);
+       struct xlog_in_core     *iclog);
 #else
 #define xlog_verify_dest_ptr(a,b)
 #define xlog_verify_grant_tail(a)
 #define xlog_verify_iclog(a,b,c)
-#define xlog_verify_tail_lsn(a,b,c)
+#define xlog_verify_tail_lsn(a,b)
 #endif
 
 STATIC int
@@ -487,51 +486,80 @@ out_error:
        return error;
 }
 
-static bool
-__xlog_state_release_iclog(
-       struct xlog             *log,
-       struct xlog_in_core     *iclog)
-{
-       lockdep_assert_held(&log->l_icloglock);
-
-       if (iclog->ic_state == XLOG_STATE_WANT_SYNC) {
-               /* update tail before writing to iclog */
-               xfs_lsn_t tail_lsn = xlog_assign_tail_lsn(log->l_mp);
-
-               iclog->ic_state = XLOG_STATE_SYNCING;
-               iclog->ic_header.h_tail_lsn = cpu_to_be64(tail_lsn);
-               xlog_verify_tail_lsn(log, iclog, tail_lsn);
-               /* cycle incremented when incrementing curr_block */
-               trace_xlog_iclog_syncing(iclog, _RET_IP_);
-               return true;
-       }
-
-       ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE);
-       return false;
-}
-
 /*
  * Flush iclog to disk if this is the last reference to the given iclog and the
  * it is in the WANT_SYNC state.
+ *
+ * If the caller passes in a non-zero @old_tail_lsn and the current log tail
+ * does not match, there may be metadata on disk that must be persisted before
+ * this iclog is written.  To satisfy that requirement, set the
+ * XLOG_ICL_NEED_FLUSH flag as a condition for writing this iclog with the new
+ * log tail value.
+ *
+ * If XLOG_ICL_NEED_FUA is already set on the iclog, we need to ensure that the
+ * log tail is updated correctly. NEED_FUA indicates that the iclog will be
+ * written to stable storage, and implies that a commit record is contained
+ * within the iclog. We need to ensure that the log tail does not move beyond
+ * the tail that the first commit record in the iclog ordered against, otherwise
+ * correct recovery of that checkpoint becomes dependent on future operations
+ * performed on this iclog.
+ *
+ * Hence if NEED_FUA is set and the current iclog tail lsn is empty, write the
+ * current tail into iclog. Once the iclog tail is set, future operations must
+ * not modify it, otherwise they potentially violate ordering constraints for
+ * the checkpoint commit that wrote the initial tail lsn value. The tail lsn in
+ * the iclog will get zeroed on activation of the iclog after sync, so we
+ * always capture the tail lsn on the iclog on the first NEED_FUA release
+ * regardless of the number of active reference counts on this iclog.
  */
+
 int
 xlog_state_release_iclog(
        struct xlog             *log,
-       struct xlog_in_core     *iclog)
+       struct xlog_in_core     *iclog,
+       xfs_lsn_t               old_tail_lsn)
 {
+       xfs_lsn_t               tail_lsn;
        lockdep_assert_held(&log->l_icloglock);
 
        trace_xlog_iclog_release(iclog, _RET_IP_);
        if (iclog->ic_state == XLOG_STATE_IOERROR)
                return -EIO;
 
-       if (atomic_dec_and_test(&iclog->ic_refcnt) &&
-           __xlog_state_release_iclog(log, iclog)) {
-               spin_unlock(&log->l_icloglock);
-               xlog_sync(log, iclog);
-               spin_lock(&log->l_icloglock);
+       /*
+        * Grabbing the current log tail needs to be atomic w.r.t. the writing
+        * of the tail LSN into the iclog so we guarantee that the log tail does
+        * not move between deciding if a cache flush is required and writing
+        * the LSN into the iclog below.
+        */
+       if (old_tail_lsn || iclog->ic_state == XLOG_STATE_WANT_SYNC) {
+               tail_lsn = xlog_assign_tail_lsn(log->l_mp);
+
+               if (old_tail_lsn && tail_lsn != old_tail_lsn)
+                       iclog->ic_flags |= XLOG_ICL_NEED_FLUSH;
+
+               if ((iclog->ic_flags & XLOG_ICL_NEED_FUA) &&
+                   !iclog->ic_header.h_tail_lsn)
+                       iclog->ic_header.h_tail_lsn = cpu_to_be64(tail_lsn);
        }
 
+       if (!atomic_dec_and_test(&iclog->ic_refcnt))
+               return 0;
+
+       if (iclog->ic_state != XLOG_STATE_WANT_SYNC) {
+               ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE);
+               return 0;
+       }
+
+       iclog->ic_state = XLOG_STATE_SYNCING;
+       if (!iclog->ic_header.h_tail_lsn)
+               iclog->ic_header.h_tail_lsn = cpu_to_be64(tail_lsn);
+       xlog_verify_tail_lsn(log, iclog);
+       trace_xlog_iclog_syncing(iclog, _RET_IP_);
+
+       spin_unlock(&log->l_icloglock);
+       xlog_sync(log, iclog);
+       spin_lock(&log->l_icloglock);
        return 0;
 }
 
@@ -774,6 +802,21 @@ xfs_log_mount_cancel(
 }
 
 /*
+ * Flush out the iclog to disk ensuring that device caches are flushed and
+ * the iclog hits stable storage before any completion waiters are woken.
+ */
+static inline int
+xlog_force_iclog(
+       struct xlog_in_core     *iclog)
+{
+       atomic_inc(&iclog->ic_refcnt);
+       iclog->ic_flags |= XLOG_ICL_NEED_FLUSH | XLOG_ICL_NEED_FUA;
+       if (iclog->ic_state == XLOG_STATE_ACTIVE)
+               xlog_state_switch_iclogs(iclog->ic_log, iclog, 0);
+       return xlog_state_release_iclog(iclog->ic_log, iclog, 0);
+}
+
+/*
  * Wait for the iclog and all prior iclogs to be written disk as required by the
  * log force state machine. Waiting on ic_force_wait ensures iclog completions
  * have been ordered and callbacks run before we are woken here, hence
@@ -827,13 +870,6 @@ xlog_write_unmount_record(
        /* account for space used by record data */
        ticket->t_curr_res -= sizeof(ulf);
 
-       /*
-        * For external log devices, we need to flush the data device cache
-        * first to ensure all metadata writeback is on stable storage before we
-        * stamp the tail LSN into the unmount record.
-        */
-       if (log->l_targ != log->l_mp->m_ddev_targp)
-               blkdev_issue_flush(log->l_targ->bt_bdev);
        return xlog_write(log, &vec, ticket, NULL, NULL, XLOG_UNMOUNT_TRANS);
 }
 
@@ -865,18 +901,7 @@ out_err:
 
        spin_lock(&log->l_icloglock);
        iclog = log->l_iclog;
-       atomic_inc(&iclog->ic_refcnt);
-       if (iclog->ic_state == XLOG_STATE_ACTIVE)
-               xlog_state_switch_iclogs(log, iclog, 0);
-       else
-               ASSERT(iclog->ic_state == XLOG_STATE_WANT_SYNC ||
-                      iclog->ic_state == XLOG_STATE_IOERROR);
-       /*
-        * Ensure the journal is fully flushed and on stable storage once the
-        * iclog containing the unmount record is written.
-        */
-       iclog->ic_flags |= (XLOG_ICL_NEED_FLUSH | XLOG_ICL_NEED_FUA);
-       error = xlog_state_release_iclog(log, iclog);
+       error = xlog_force_iclog(iclog);
        xlog_wait_on_iclog(iclog);
 
        if (tic) {
@@ -1796,10 +1821,20 @@ xlog_write_iclog(
         * metadata writeback and causing priority inversions.
         */
        iclog->ic_bio.bi_opf = REQ_OP_WRITE | REQ_META | REQ_SYNC | REQ_IDLE;
-       if (iclog->ic_flags & XLOG_ICL_NEED_FLUSH)
+       if (iclog->ic_flags & XLOG_ICL_NEED_FLUSH) {
                iclog->ic_bio.bi_opf |= REQ_PREFLUSH;
+               /*
+                * For external log devices, we also need to flush the data
+                * device cache first to ensure all metadata writeback covered
+                * by the LSN in this iclog is on stable storage. This is slow,
+                * but it *must* complete before we issue the external log IO.
+                */
+               if (log->l_targ != log->l_mp->m_ddev_targp)
+                       blkdev_issue_flush(log->l_mp->m_ddev_targp->bt_bdev);
+       }
        if (iclog->ic_flags & XLOG_ICL_NEED_FUA)
                iclog->ic_bio.bi_opf |= REQ_FUA;
+
        iclog->ic_flags &= ~(XLOG_ICL_NEED_FLUSH | XLOG_ICL_NEED_FUA);
 
        if (xlog_map_iclog_data(&iclog->ic_bio, iclog->ic_data, count)) {
@@ -2310,7 +2345,7 @@ xlog_write_copy_finish(
        return 0;
 
 release_iclog:
-       error = xlog_state_release_iclog(log, iclog);
+       error = xlog_state_release_iclog(log, iclog, 0);
        spin_unlock(&log->l_icloglock);
        return error;
 }
@@ -2529,7 +2564,7 @@ next_lv:
                ASSERT(optype & XLOG_COMMIT_TRANS);
                *commit_iclog = iclog;
        } else {
-               error = xlog_state_release_iclog(log, iclog);
+               error = xlog_state_release_iclog(log, iclog, 0);
        }
        spin_unlock(&log->l_icloglock);
 
@@ -2567,6 +2602,7 @@ xlog_state_activate_iclog(
        memset(iclog->ic_header.h_cycle_data, 0,
                sizeof(iclog->ic_header.h_cycle_data));
        iclog->ic_header.h_lsn = 0;
+       iclog->ic_header.h_tail_lsn = 0;
 }
 
 /*
@@ -2967,7 +3003,7 @@ restart:
                 * reference to the iclog.
                 */
                if (!atomic_add_unless(&iclog->ic_refcnt, -1, 1))
-                       error = xlog_state_release_iclog(log, iclog);
+                       error = xlog_state_release_iclog(log, iclog, 0);
                spin_unlock(&log->l_icloglock);
                if (error)
                        return error;
@@ -3132,6 +3168,35 @@ xlog_state_switch_iclogs(
 }
 
 /*
+ * Force the iclog to disk and check if the iclog has been completed before
+ * xlog_force_iclog() returns. This can happen on synchronous (e.g.
+ * pmem) or fast async storage because we drop the icloglock to issue the IO.
+ * If completion has already occurred, tell the caller so that it can avoid an
+ * unnecessary wait on the iclog.
+ */
+static int
+xlog_force_and_check_iclog(
+       struct xlog_in_core     *iclog,
+       bool                    *completed)
+{
+       xfs_lsn_t               lsn = be64_to_cpu(iclog->ic_header.h_lsn);
+       int                     error;
+
+       *completed = false;
+       error = xlog_force_iclog(iclog);
+       if (error)
+               return error;
+
+       /*
+        * If the iclog has already been completed and reused the header LSN
+        * will have been rewritten by completion
+        */
+       if (be64_to_cpu(iclog->ic_header.h_lsn) != lsn)
+               *completed = true;
+       return 0;
+}
+
+/*
  * Write out all data in the in-core log as of this exact moment in time.
  *
  * Data may be written to the in-core log during this call.  However,
@@ -3165,7 +3230,6 @@ xfs_log_force(
 {
        struct xlog             *log = mp->m_log;
        struct xlog_in_core     *iclog;
-       xfs_lsn_t               lsn;
 
        XFS_STATS_INC(mp, xs_log_force);
        trace_xfs_log_force(mp, 0, _RET_IP_);
@@ -3193,39 +3257,33 @@ xfs_log_force(
                iclog = iclog->ic_prev;
        } else if (iclog->ic_state == XLOG_STATE_ACTIVE) {
                if (atomic_read(&iclog->ic_refcnt) == 0) {
-                       /*
-                        * We are the only one with access to this iclog.
-                        *
-                        * Flush it out now.  There should be a roundoff of zero
-                        * to show that someone has already taken care of the
-                        * roundoff from the previous sync.
-                        */
-                       atomic_inc(&iclog->ic_refcnt);
-                       lsn = be64_to_cpu(iclog->ic_header.h_lsn);
-                       xlog_state_switch_iclogs(log, iclog, 0);
-                       if (xlog_state_release_iclog(log, iclog))
+                       /* We have exclusive access to this iclog. */
+                       bool    completed;
+
+                       if (xlog_force_and_check_iclog(iclog, &completed))
                                goto out_error;
 
-                       if (be64_to_cpu(iclog->ic_header.h_lsn) != lsn)
+                       if (completed)
                                goto out_unlock;
                } else {
                        /*
-                        * Someone else is writing to this iclog.
-                        *
-                        * Use its call to flush out the data.  However, the
-                        * other thread may not force out this LR, so we mark
-                        * it WANT_SYNC.
+                        * Someone else is still writing to this iclog, so we
+                        * need to ensure that when they release the iclog it
+                        * gets synced immediately as we may be waiting on it.
                         */
                        xlog_state_switch_iclogs(log, iclog, 0);
                }
-       } else {
-               /*
-                * If the head iclog is not active nor dirty, we just attach
-                * ourselves to the head and go to sleep if necessary.
-                */
-               ;
        }
 
+       /*
+        * The iclog we are about to wait on may contain the checkpoint pushed
+        * by the above xlog_cil_force() call, but it may not have been pushed
+        * to disk yet. Like the ACTIVE case above, we need to make sure caches
+        * are flushed when this iclog is written.
+        */
+       if (iclog->ic_state == XLOG_STATE_WANT_SYNC)
+               iclog->ic_flags |= XLOG_ICL_NEED_FLUSH | XLOG_ICL_NEED_FUA;
+
        if (flags & XFS_LOG_SYNC)
                return xlog_wait_on_iclog(iclog);
 out_unlock:
@@ -3245,6 +3303,7 @@ xlog_force_lsn(
        bool                    already_slept)
 {
        struct xlog_in_core     *iclog;
+       bool                    completed;
 
        spin_lock(&log->l_icloglock);
        iclog = log->l_iclog;
@@ -3258,7 +3317,8 @@ xlog_force_lsn(
                        goto out_unlock;
        }
 
-       if (iclog->ic_state == XLOG_STATE_ACTIVE) {
+       switch (iclog->ic_state) {
+       case XLOG_STATE_ACTIVE:
                /*
                 * We sleep here if we haven't already slept (e.g. this is the
                 * first time we've looked at the correct iclog buf) and the
@@ -3281,12 +3341,31 @@ xlog_force_lsn(
                                        &log->l_icloglock);
                        return -EAGAIN;
                }
-               atomic_inc(&iclog->ic_refcnt);
-               xlog_state_switch_iclogs(log, iclog, 0);
-               if (xlog_state_release_iclog(log, iclog))
+               if (xlog_force_and_check_iclog(iclog, &completed))
                        goto out_error;
                if (log_flushed)
                        *log_flushed = 1;
+               if (completed)
+                       goto out_unlock;
+               break;
+       case XLOG_STATE_WANT_SYNC:
+               /*
+                * This iclog may contain the checkpoint pushed by the
+                * xlog_cil_force_seq() call, but there are other writers still
+                * accessing it so it hasn't been pushed to disk yet. Like the
+                * ACTIVE case above, we need to make sure caches are flushed
+                * when this iclog is written.
+                */
+               iclog->ic_flags |= XLOG_ICL_NEED_FLUSH | XLOG_ICL_NEED_FUA;
+               break;
+       default:
+               /*
+                * The entire checkpoint was written by the CIL force and is on
+                * its way to disk already. It will be stable when it
+                * completes, so we don't need to manipulate caches here at all.
+                * We just need to wait for completion if necessary.
+                */
+               break;
        }
 
        if (flags & XFS_LOG_SYNC)
@@ -3559,10 +3638,10 @@ xlog_verify_grant_tail(
 STATIC void
 xlog_verify_tail_lsn(
        struct xlog             *log,
-       struct xlog_in_core     *iclog,
-       xfs_lsn_t               tail_lsn)
+       struct xlog_in_core     *iclog)
 {
-    int blocks;
+       xfs_lsn_t       tail_lsn = be64_to_cpu(iclog->ic_header.h_tail_lsn);
+       int             blocks;
 
     if (CYCLE_LSN(tail_lsn) == log->l_prev_cycle) {
        blocks =
index b128aaa..4c44bc3 100644 (file)
@@ -654,8 +654,9 @@ xlog_cil_push_work(
        struct xfs_trans_header thdr;
        struct xfs_log_iovec    lhdr;
        struct xfs_log_vec      lvhdr = { NULL };
+       xfs_lsn_t               preflush_tail_lsn;
        xfs_lsn_t               commit_lsn;
-       xfs_lsn_t               push_seq;
+       xfs_csn_t               push_seq;
        struct bio              bio;
        DECLARE_COMPLETION_ONSTACK(bdev_flush);
 
@@ -730,7 +731,15 @@ xlog_cil_push_work(
         * because we hold the flush lock exclusively. Hence we can now issue
         * a cache flush to ensure all the completed metadata in the journal we
         * are about to overwrite is on stable storage.
+        *
+        * Because we are issuing this cache flush before we've written the
+        * tail lsn to the iclog, we can have metadata IO completions move the
+        * tail forwards between the completion of this flush and the iclog
+        * being written. In this case, we need to re-issue the cache flush
+        * before the iclog write. To detect whether the log tail moves, sample
+        * the tail LSN *before* we issue the flush.
         */
+       preflush_tail_lsn = atomic64_read(&log->l_tail_lsn);
        xfs_flush_bdev_async(&bio, log->l_mp->m_ddev_targp->bt_bdev,
                                &bdev_flush);
 
@@ -941,7 +950,7 @@ restart:
         * storage.
         */
        commit_iclog->ic_flags |= XLOG_ICL_NEED_FUA;
-       xlog_state_release_iclog(log, commit_iclog);
+       xlog_state_release_iclog(log, commit_iclog, preflush_tail_lsn);
        spin_unlock(&log->l_icloglock);
        return;
 
index 4c41bbf..f3e79a4 100644 (file)
@@ -59,6 +59,16 @@ enum xlog_iclog_state {
        { XLOG_STATE_DIRTY,     "XLOG_STATE_DIRTY" }, \
        { XLOG_STATE_IOERROR,   "XLOG_STATE_IOERROR" }
 
+/*
+ * In core log flags
+ */
+#define XLOG_ICL_NEED_FLUSH    (1 << 0)        /* iclog needs REQ_PREFLUSH */
+#define XLOG_ICL_NEED_FUA      (1 << 1)        /* iclog needs REQ_FUA */
+
+#define XLOG_ICL_STRINGS \
+       { XLOG_ICL_NEED_FLUSH,  "XLOG_ICL_NEED_FLUSH" }, \
+       { XLOG_ICL_NEED_FUA,    "XLOG_ICL_NEED_FUA" }
+
 
 /*
  * Log ticket flags
@@ -143,9 +153,6 @@ enum xlog_iclog_state {
 
 #define XLOG_COVER_OPS         5
 
-#define XLOG_ICL_NEED_FLUSH    (1 << 0)        /* iclog needs REQ_PREFLUSH */
-#define XLOG_ICL_NEED_FUA      (1 << 1)        /* iclog needs REQ_FUA */
-
 /* Ticket reservation region accounting */ 
 #define XLOG_TIC_LEN_MAX       15
 
@@ -497,7 +504,8 @@ int xlog_commit_record(struct xlog *log, struct xlog_ticket *ticket,
 void   xfs_log_ticket_ungrant(struct xlog *log, struct xlog_ticket *ticket);
 void   xfs_log_ticket_regrant(struct xlog *log, struct xlog_ticket *ticket);
 
-int xlog_state_release_iclog(struct xlog *log, struct xlog_in_core *iclog);
+int xlog_state_release_iclog(struct xlog *log, struct xlog_in_core *iclog,
+               xfs_lsn_t log_tail_lsn);
 
 /*
  * When we crack an atomic LSN, we sample it first so that the value will not
index f9d8d60..1926029 100644 (file)
@@ -3944,6 +3944,7 @@ DECLARE_EVENT_CLASS(xlog_iclog_class,
                __field(uint32_t, state)
                __field(int32_t, refcount)
                __field(uint32_t, offset)
+               __field(uint32_t, flags)
                __field(unsigned long long, lsn)
                __field(unsigned long, caller_ip)
        ),
@@ -3952,15 +3953,17 @@ DECLARE_EVENT_CLASS(xlog_iclog_class,
                __entry->state = iclog->ic_state;
                __entry->refcount = atomic_read(&iclog->ic_refcnt);
                __entry->offset = iclog->ic_offset;
+               __entry->flags = iclog->ic_flags;
                __entry->lsn = be64_to_cpu(iclog->ic_header.h_lsn);
                __entry->caller_ip = caller_ip;
        ),
-       TP_printk("dev %d:%d state %s refcnt %d offset %u lsn 0x%llx caller %pS",
+       TP_printk("dev %d:%d state %s refcnt %d offset %u lsn 0x%llx flags %s caller %pS",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  __print_symbolic(__entry->state, XLOG_STATE_STRINGS),
                  __entry->refcount,
                  __entry->offset,
                  __entry->lsn,
+                 __print_flags(__entry->flags, "|", XLOG_ICL_STRINGS),
                  (char *)__entry->caller_ip)
 
 );
index a9db1ea..ae3ac3a 100644 (file)
@@ -134,4 +134,5 @@ BPF_LINK_TYPE(BPF_LINK_TYPE_CGROUP, cgroup)
 BPF_LINK_TYPE(BPF_LINK_TYPE_ITER, iter)
 #ifdef CONFIG_NET
 BPF_LINK_TYPE(BPF_LINK_TYPE_NETNS, netns)
+BPF_LINK_TYPE(BPF_LINK_TYPE_XDP, xdp)
 #endif
index e774ecc..828d08a 100644 (file)
@@ -340,8 +340,8 @@ struct bpf_insn_aux_data {
        };
        u64 map_key_state; /* constant (32 bit) key tracking for maps */
        int ctx_field_size; /* the ctx field size for load insn, maybe 0 */
-       int sanitize_stack_off; /* stack slot to be cleared */
        u32 seen; /* this insn was processed by the verifier at env->pass_cnt */
+       bool sanitize_stack_spill; /* subject to Spectre v4 sanitation */
        bool zext_dst; /* this insn zero extends dst reg */
        u8 alu_state; /* used in combination with alu_limit */
 
@@ -414,6 +414,7 @@ struct bpf_verifier_env {
        u32 used_map_cnt;               /* number of used maps */
        u32 used_btf_cnt;               /* number of used BTF objects */
        u32 id_gen;                     /* used to generate unique reg IDs */
+       bool explore_alu_limits;
        bool allow_ptr_leaks;
        bool allow_uninit_stack;
        bool allow_ptr_to_map_access;
index 472f970..83b8960 100644 (file)
@@ -73,6 +73,11 @@ struct ctl_table_header;
 /* unused opcode to mark call to interpreter with arguments */
 #define BPF_CALL_ARGS  0xe0
 
+/* unused opcode to mark speculation barrier for mitigating
+ * Speculative Store Bypass
+ */
+#define BPF_NOSPEC     0xc0
+
 /* As per nm, we expose JITed images as text (code) section for
  * kallsyms. That way, tools like perf can find it to match
  * addresses.
@@ -390,6 +395,16 @@ static inline bool insn_is_zext(const struct bpf_insn *insn)
                .off   = 0,                                     \
                .imm   = 0 })
 
+/* Speculation barrier */
+
+#define BPF_ST_NOSPEC()                                                \
+       ((struct bpf_insn) {                                    \
+               .code  = BPF_ST | BPF_NOSPEC,                   \
+               .dst_reg = 0,                                   \
+               .src_reg = 0,                                   \
+               .off   = 0,                                     \
+               .imm   = 0 })
+
 /* Internal classic blocks for direct assignment */
 
 #define __BPF_STMT(CODE, K)                                    \
index e2bc163..6b54982 100644 (file)
@@ -141,6 +141,7 @@ extern int vfs_get_tree(struct fs_context *fc);
 extern void put_fs_context(struct fs_context *fc);
 extern int vfs_parse_fs_param_source(struct fs_context *fc,
                                     struct fs_parameter *param);
+extern void fc_drop_locked(struct fs_context *fc);
 
 /*
  * sget() wrappers to be called from the ->get_tree() op.
index 25e2b4e..aee8ff4 100644 (file)
@@ -81,6 +81,8 @@ int ishtp_register_event_cb(struct ishtp_cl_device *device,
 
 /* Get the device * from ishtp device instance */
 struct device *ishtp_device(struct ishtp_cl_device *cl_device);
+/* wait for IPC resume */
+bool ishtp_wait_resume(struct ishtp_device *dev);
 /* Trace interface for clients */
 ishtp_print_log ishtp_trace_callback(struct ishtp_cl_device *cl_device);
 /* Get device pointer of PCI device for DMA acces */
index 96f3190..14ab0c0 100644 (file)
@@ -285,11 +285,45 @@ static inline struct sk_psock *sk_psock(const struct sock *sk)
        return rcu_dereference_sk_user_data(sk);
 }
 
+static inline void sk_psock_set_state(struct sk_psock *psock,
+                                     enum sk_psock_state_bits bit)
+{
+       set_bit(bit, &psock->state);
+}
+
+static inline void sk_psock_clear_state(struct sk_psock *psock,
+                                       enum sk_psock_state_bits bit)
+{
+       clear_bit(bit, &psock->state);
+}
+
+static inline bool sk_psock_test_state(const struct sk_psock *psock,
+                                      enum sk_psock_state_bits bit)
+{
+       return test_bit(bit, &psock->state);
+}
+
+static inline void sock_drop(struct sock *sk, struct sk_buff *skb)
+{
+       sk_drops_add(sk, skb);
+       kfree_skb(skb);
+}
+
+static inline void drop_sk_msg(struct sk_psock *psock, struct sk_msg *msg)
+{
+       if (msg->skb)
+               sock_drop(psock->sk, msg->skb);
+       kfree(msg);
+}
+
 static inline void sk_psock_queue_msg(struct sk_psock *psock,
                                      struct sk_msg *msg)
 {
        spin_lock_bh(&psock->ingress_lock);
-       list_add_tail(&msg->list, &psock->ingress_msg);
+       if (sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED))
+               list_add_tail(&msg->list, &psock->ingress_msg);
+       else
+               drop_sk_msg(psock, msg);
        spin_unlock_bh(&psock->ingress_lock);
 }
 
@@ -406,24 +440,6 @@ static inline void sk_psock_restore_proto(struct sock *sk,
                psock->psock_update_sk_prot(sk, psock, true);
 }
 
-static inline void sk_psock_set_state(struct sk_psock *psock,
-                                     enum sk_psock_state_bits bit)
-{
-       set_bit(bit, &psock->state);
-}
-
-static inline void sk_psock_clear_state(struct sk_psock *psock,
-                                       enum sk_psock_state_bits bit)
-{
-       clear_bit(bit, &psock->state);
-}
-
-static inline bool sk_psock_test_state(const struct sk_psock *psock,
-                                      enum sk_psock_state_bits bit)
-{
-       return test_bit(bit, &psock->state);
-}
-
 static inline struct sk_psock *sk_psock_get(struct sock *sk)
 {
        struct sk_psock *psock;
index c0f0a13..49aa79c 100644 (file)
 #include <linux/if_ether.h>
 
 /* Lengths of frame formats */
-#define LLC_PDU_LEN_I  4       /* header and 2 control bytes */
-#define LLC_PDU_LEN_S  4
-#define LLC_PDU_LEN_U  3       /* header and 1 control byte */
+#define LLC_PDU_LEN_I          4       /* header and 2 control bytes */
+#define LLC_PDU_LEN_S          4
+#define LLC_PDU_LEN_U          3       /* header and 1 control byte */
+/* header and 1 control byte and XID info */
+#define LLC_PDU_LEN_U_XID      (LLC_PDU_LEN_U + sizeof(struct llc_xid_info))
 /* Known SAP addresses */
 #define LLC_GLOBAL_SAP 0xFF
 #define LLC_NULL_SAP   0x00    /* not network-layer visible */
 #define LLC_PDU_TYPE_U_MASK    0x03    /* 8-bit control field */
 #define LLC_PDU_TYPE_MASK      0x03
 
-#define LLC_PDU_TYPE_I 0       /* first bit */
-#define LLC_PDU_TYPE_S 1       /* first two bits */
-#define LLC_PDU_TYPE_U 3       /* first two bits */
+#define LLC_PDU_TYPE_I         0       /* first bit */
+#define LLC_PDU_TYPE_S         1       /* first two bits */
+#define LLC_PDU_TYPE_U         3       /* first two bits */
+#define LLC_PDU_TYPE_U_XID     4       /* private type for detecting XID commands */
 
 #define LLC_PDU_TYPE_IS_I(pdu) \
        ((!(pdu->ctrl_1 & LLC_PDU_TYPE_I_MASK)) ? 1 : 0)
@@ -230,9 +233,18 @@ static inline struct llc_pdu_un *llc_pdu_un_hdr(struct sk_buff *skb)
 static inline void llc_pdu_header_init(struct sk_buff *skb, u8 type,
                                       u8 ssap, u8 dsap, u8 cr)
 {
-       const int hlen = type == LLC_PDU_TYPE_U ? 3 : 4;
+       int hlen = 4; /* default value for I and S types */
        struct llc_pdu_un *pdu;
 
+       switch (type) {
+       case LLC_PDU_TYPE_U:
+               hlen = 3;
+               break;
+       case LLC_PDU_TYPE_U_XID:
+               hlen = 6;
+               break;
+       }
+
        skb_push(skb, hlen);
        skb_reset_network_header(skb);
        pdu = llc_pdu_un_hdr(skb);
@@ -374,7 +386,10 @@ static inline void llc_pdu_init_as_xid_cmd(struct sk_buff *skb,
        xid_info->fmt_id = LLC_XID_FMT_ID;      /* 0x81 */
        xid_info->type   = svcs_supported;
        xid_info->rw     = rx_window << 1;      /* size of receive window */
-       skb_put(skb, sizeof(struct llc_xid_info));
+
+       /* no need to push/put since llc_pdu_header_init() has already
+        * pushed 3 + 3 bytes
+        */
 }
 
 /**
index 32fc4a3..651bba6 100644 (file)
@@ -984,6 +984,7 @@ struct sctp_transport {
        } cacc;
 
        struct {
+               __u32 last_rtx_chunks;
                __u16 pmtu;
                __u16 probe_size;
                __u16 probe_high;
@@ -1024,8 +1025,8 @@ bool sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu);
 void sctp_transport_immediate_rtx(struct sctp_transport *);
 void sctp_transport_dst_release(struct sctp_transport *t);
 void sctp_transport_dst_confirm(struct sctp_transport *t);
-void sctp_transport_pl_send(struct sctp_transport *t);
-void sctp_transport_pl_recv(struct sctp_transport *t);
+bool sctp_transport_pl_send(struct sctp_transport *t);
+bool sctp_transport_pl_recv(struct sctp_transport *t);
 
 
 /* This is the structure we use to queue packets as they come into
index e33997b..edc346a 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* SPDX-License-Identifier: LGPL-2.1 WITH Linux-syscall-note */
 /* Copyright(c) 2019 Intel Corporation. All rights rsvd. */
 #ifndef _USR_IDXD_H_
 #define _USR_IDXD_H_
index 26b638a..a7085e0 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR Linux-OpenIB) */
+/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR Linux-OpenIB */
 /*
  * Copyright (c) 2006 - 2021 Intel Corporation.  All rights reserved.
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
index 9b15774..b1a5fc0 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/perf_event.h>
 #include <linux/extable.h>
 #include <linux/log2.h>
+
+#include <asm/barrier.h>
 #include <asm/unaligned.h>
 
 /* Registers */
@@ -1377,6 +1379,7 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn)
                /* Non-UAPI available opcodes. */
                [BPF_JMP | BPF_CALL_ARGS] = &&JMP_CALL_ARGS,
                [BPF_JMP | BPF_TAIL_CALL] = &&JMP_TAIL_CALL,
+               [BPF_ST  | BPF_NOSPEC] = &&ST_NOSPEC,
                [BPF_LDX | BPF_PROBE_MEM | BPF_B] = &&LDX_PROBE_MEM_B,
                [BPF_LDX | BPF_PROBE_MEM | BPF_H] = &&LDX_PROBE_MEM_H,
                [BPF_LDX | BPF_PROBE_MEM | BPF_W] = &&LDX_PROBE_MEM_W,
@@ -1621,7 +1624,21 @@ out:
        COND_JMP(s, JSGE, >=)
        COND_JMP(s, JSLE, <=)
 #undef COND_JMP
-       /* STX and ST and LDX*/
+       /* ST, STX and LDX*/
+       ST_NOSPEC:
+               /* Speculation barrier for mitigating Speculative Store Bypass.
+                * In case of arm64, we rely on the firmware mitigation as
+                * controlled via the ssbd kernel parameter. Whenever the
+                * mitigation is enabled, it works for all of the kernel code
+                * with no need to provide any additional instructions here.
+                * In case of x86, we use 'lfence' insn for mitigation. We
+                * reuse preexisting logic from Spectre v1 mitigation that
+                * happens to produce the required code on x86 for v4 as well.
+                */
+#ifdef CONFIG_X86
+               barrier_nospec();
+#endif
+               CONT;
 #define LDST(SIZEOP, SIZE)                                             \
        STX_MEM_##SIZEOP:                                               \
                *(SIZE *)(unsigned long) (DST + insn->off) = SRC;       \
index bbfc6bb..ca3cd9a 100644 (file)
@@ -206,15 +206,17 @@ void print_bpf_insn(const struct bpf_insn_cbs *cbs,
                        verbose(cbs->private_data, "BUG_%02x\n", insn->code);
                }
        } else if (class == BPF_ST) {
-               if (BPF_MODE(insn->code) != BPF_MEM) {
+               if (BPF_MODE(insn->code) == BPF_MEM) {
+                       verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = %d\n",
+                               insn->code,
+                               bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
+                               insn->dst_reg,
+                               insn->off, insn->imm);
+               } else if (BPF_MODE(insn->code) == 0xc0 /* BPF_NOSPEC, no UAPI */) {
+                       verbose(cbs->private_data, "(%02x) nospec\n", insn->code);
+               } else {
                        verbose(cbs->private_data, "BUG_st_%02x\n", insn->code);
-                       return;
                }
-               verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = %d\n",
-                       insn->code,
-                       bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
-                       insn->dst_reg,
-                       insn->off, insn->imm);
        } else if (class == BPF_LDX) {
                if (BPF_MODE(insn->code) != BPF_MEM) {
                        verbose(cbs->private_data, "BUG_ldx_%02x\n", insn->code);
index 9de3c9c..f9bda54 100644 (file)
@@ -2610,6 +2610,19 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
        cur = env->cur_state->frame[env->cur_state->curframe];
        if (value_regno >= 0)
                reg = &cur->regs[value_regno];
+       if (!env->bypass_spec_v4) {
+               bool sanitize = reg && is_spillable_regtype(reg->type);
+
+               for (i = 0; i < size; i++) {
+                       if (state->stack[spi].slot_type[i] == STACK_INVALID) {
+                               sanitize = true;
+                               break;
+                       }
+               }
+
+               if (sanitize)
+                       env->insn_aux_data[insn_idx].sanitize_stack_spill = true;
+       }
 
        if (reg && size == BPF_REG_SIZE && register_is_bounded(reg) &&
            !register_is_null(reg) && env->bpf_capable) {
@@ -2632,47 +2645,10 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
                        verbose(env, "invalid size of register spill\n");
                        return -EACCES;
                }
-
                if (state != cur && reg->type == PTR_TO_STACK) {
                        verbose(env, "cannot spill pointers to stack into stack frame of the caller\n");
                        return -EINVAL;
                }
-
-               if (!env->bypass_spec_v4) {
-                       bool sanitize = false;
-
-                       if (state->stack[spi].slot_type[0] == STACK_SPILL &&
-                           register_is_const(&state->stack[spi].spilled_ptr))
-                               sanitize = true;
-                       for (i = 0; i < BPF_REG_SIZE; i++)
-                               if (state->stack[spi].slot_type[i] == STACK_MISC) {
-                                       sanitize = true;
-                                       break;
-                               }
-                       if (sanitize) {
-                               int *poff = &env->insn_aux_data[insn_idx].sanitize_stack_off;
-                               int soff = (-spi - 1) * BPF_REG_SIZE;
-
-                               /* detected reuse of integer stack slot with a pointer
-                                * which means either llvm is reusing stack slot or
-                                * an attacker is trying to exploit CVE-2018-3639
-                                * (speculative store bypass)
-                                * Have to sanitize that slot with preemptive
-                                * store of zero.
-                                */
-                               if (*poff && *poff != soff) {
-                                       /* disallow programs where single insn stores
-                                        * into two different stack slots, since verifier
-                                        * cannot sanitize them
-                                        */
-                                       verbose(env,
-                                               "insn %d cannot access two stack slots fp%d and fp%d",
-                                               insn_idx, *poff, soff);
-                                       return -EINVAL;
-                               }
-                               *poff = soff;
-                       }
-               }
                save_register_state(state, spi, reg);
        } else {
                u8 type = STACK_MISC;
@@ -6561,6 +6537,12 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env,
                alu_state |= off_is_imm ? BPF_ALU_IMMEDIATE : 0;
                alu_state |= ptr_is_dst_reg ?
                             BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST;
+
+               /* Limit pruning on unknown scalars to enable deep search for
+                * potential masking differences from other program paths.
+                */
+               if (!off_is_imm)
+                       env->explore_alu_limits = true;
        }
 
        err = update_alu_sanitation_state(aux, alu_state, alu_limit);
@@ -9936,8 +9918,8 @@ next:
 }
 
 /* Returns true if (rold safe implies rcur safe) */
-static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur,
-                   struct bpf_id_pair *idmap)
+static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold,
+                   struct bpf_reg_state *rcur, struct bpf_id_pair *idmap)
 {
        bool equal;
 
@@ -9963,6 +9945,8 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur,
                return false;
        switch (rold->type) {
        case SCALAR_VALUE:
+               if (env->explore_alu_limits)
+                       return false;
                if (rcur->type == SCALAR_VALUE) {
                        if (!rold->precise && !rcur->precise)
                                return true;
@@ -10053,9 +10037,8 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur,
        return false;
 }
 
-static bool stacksafe(struct bpf_func_state *old,
-                     struct bpf_func_state *cur,
-                     struct bpf_id_pair *idmap)
+static bool stacksafe(struct bpf_verifier_env *env, struct bpf_func_state *old,
+                     struct bpf_func_state *cur, struct bpf_id_pair *idmap)
 {
        int i, spi;
 
@@ -10100,9 +10083,8 @@ static bool stacksafe(struct bpf_func_state *old,
                        continue;
                if (old->stack[spi].slot_type[0] != STACK_SPILL)
                        continue;
-               if (!regsafe(&old->stack[spi].spilled_ptr,
-                            &cur->stack[spi].spilled_ptr,
-                            idmap))
+               if (!regsafe(env, &old->stack[spi].spilled_ptr,
+                            &cur->stack[spi].spilled_ptr, idmap))
                        /* when explored and current stack slot are both storing
                         * spilled registers, check that stored pointers types
                         * are the same as well.
@@ -10159,10 +10141,11 @@ static bool func_states_equal(struct bpf_verifier_env *env, struct bpf_func_stat
 
        memset(env->idmap_scratch, 0, sizeof(env->idmap_scratch));
        for (i = 0; i < MAX_BPF_REG; i++)
-               if (!regsafe(&old->regs[i], &cur->regs[i], env->idmap_scratch))
+               if (!regsafe(env, &old->regs[i], &cur->regs[i],
+                            env->idmap_scratch))
                        return false;
 
-       if (!stacksafe(old, cur, env->idmap_scratch))
+       if (!stacksafe(env, old, cur, env->idmap_scratch))
                return false;
 
        if (!refsafe(old, cur))
@@ -11906,35 +11889,33 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
 
        for (i = 0; i < insn_cnt; i++, insn++) {
                bpf_convert_ctx_access_t convert_ctx_access;
+               bool ctx_access;
 
                if (insn->code == (BPF_LDX | BPF_MEM | BPF_B) ||
                    insn->code == (BPF_LDX | BPF_MEM | BPF_H) ||
                    insn->code == (BPF_LDX | BPF_MEM | BPF_W) ||
-                   insn->code == (BPF_LDX | BPF_MEM | BPF_DW))
+                   insn->code == (BPF_LDX | BPF_MEM | BPF_DW)) {
                        type = BPF_READ;
-               else if (insn->code == (BPF_STX | BPF_MEM | BPF_B) ||
-                        insn->code == (BPF_STX | BPF_MEM | BPF_H) ||
-                        insn->code == (BPF_STX | BPF_MEM | BPF_W) ||
-                        insn->code == (BPF_STX | BPF_MEM | BPF_DW))
+                       ctx_access = true;
+               } else if (insn->code == (BPF_STX | BPF_MEM | BPF_B) ||
+                          insn->code == (BPF_STX | BPF_MEM | BPF_H) ||
+                          insn->code == (BPF_STX | BPF_MEM | BPF_W) ||
+                          insn->code == (BPF_STX | BPF_MEM | BPF_DW) ||
+                          insn->code == (BPF_ST | BPF_MEM | BPF_B) ||
+                          insn->code == (BPF_ST | BPF_MEM | BPF_H) ||
+                          insn->code == (BPF_ST | BPF_MEM | BPF_W) ||
+                          insn->code == (BPF_ST | BPF_MEM | BPF_DW)) {
                        type = BPF_WRITE;
-               else
+                       ctx_access = BPF_CLASS(insn->code) == BPF_STX;
+               } else {
                        continue;
+               }
 
                if (type == BPF_WRITE &&
-                   env->insn_aux_data[i + delta].sanitize_stack_off) {
+                   env->insn_aux_data[i + delta].sanitize_stack_spill) {
                        struct bpf_insn patch[] = {
-                               /* Sanitize suspicious stack slot with zero.
-                                * There are no memory dependencies for this store,
-                                * since it's only using frame pointer and immediate
-                                * constant of zero
-                                */
-                               BPF_ST_MEM(BPF_DW, BPF_REG_FP,
-                                          env->insn_aux_data[i + delta].sanitize_stack_off,
-                                          0),
-                               /* the original STX instruction will immediately
-                                * overwrite the same stack slot with appropriate value
-                                */
                                *insn,
+                               BPF_ST_NOSPEC(),
                        };
 
                        cnt = ARRAY_SIZE(patch);
@@ -11948,6 +11929,9 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
                        continue;
                }
 
+               if (!ctx_access)
+                       continue;
+
                switch (env->insn_aux_data[i + delta].ptr_type) {
                case PTR_TO_CTX:
                        if (!ops->convert_ctx_access)
@@ -12752,37 +12736,6 @@ static void free_states(struct bpf_verifier_env *env)
        }
 }
 
-/* The verifier is using insn_aux_data[] to store temporary data during
- * verification and to store information for passes that run after the
- * verification like dead code sanitization. do_check_common() for subprogram N
- * may analyze many other subprograms. sanitize_insn_aux_data() clears all
- * temporary data after do_check_common() finds that subprogram N cannot be
- * verified independently. pass_cnt counts the number of times
- * do_check_common() was run and insn->aux->seen tells the pass number
- * insn_aux_data was touched. These variables are compared to clear temporary
- * data from failed pass. For testing and experiments do_check_common() can be
- * run multiple times even when prior attempt to verify is unsuccessful.
- *
- * Note that special handling is needed on !env->bypass_spec_v1 if this is
- * ever called outside of error path with subsequent program rejection.
- */
-static void sanitize_insn_aux_data(struct bpf_verifier_env *env)
-{
-       struct bpf_insn *insn = env->prog->insnsi;
-       struct bpf_insn_aux_data *aux;
-       int i, class;
-
-       for (i = 0; i < env->prog->len; i++) {
-               class = BPF_CLASS(insn[i].code);
-               if (class != BPF_LDX && class != BPF_STX)
-                       continue;
-               aux = &env->insn_aux_data[i];
-               if (aux->seen != env->pass_cnt)
-                       continue;
-               memset(aux, 0, offsetof(typeof(*aux), orig_idx));
-       }
-}
-
 static int do_check_common(struct bpf_verifier_env *env, int subprog)
 {
        bool pop_log = !(env->log.level & BPF_LOG_LEVEL2);
@@ -12859,9 +12812,6 @@ out:
        if (!ret && pop_log)
                bpf_vlog_reset(&env->log, 0);
        free_states(env);
-       if (ret)
-               /* clean aux data in case subprog was rejected */
-               sanitize_insn_aux_data(env);
        return ret;
 }
 
index 8d6bf56..de2c432 100644 (file)
@@ -1221,9 +1221,7 @@ int cgroup1_get_tree(struct fs_context *fc)
                ret = cgroup_do_get_tree(fc);
 
        if (!ret && percpu_ref_is_dying(&ctx->root->cgrp.self.refcnt)) {
-               struct super_block *sb = fc->root->d_sb;
-               dput(fc->root);
-               deactivate_locked_super(sb);
+               fc_drop_locked(fc);
                ret = 1;
        }
 
index c59dd35..33899a7 100644 (file)
@@ -9135,8 +9135,10 @@ static int trace_array_create_dir(struct trace_array *tr)
                return -EINVAL;
 
        ret = event_trace_add_tracer(tr->dir, tr);
-       if (ret)
+       if (ret) {
                tracefs_remove(tr->dir);
+               return ret;
+       }
 
        init_tracer_tracefs(tr, tr->dir);
        __update_tracer_options(tr);
index 34325f4..949ef09 100644 (file)
@@ -65,7 +65,8 @@
        C(INVALID_SORT_MODIFIER,"Invalid sort modifier"),               \
        C(EMPTY_SORT_FIELD,     "Empty sort field"),                    \
        C(TOO_MANY_SORT_FIELDS, "Too many sort fields (Max = 2)"),      \
-       C(INVALID_SORT_FIELD,   "Sort field must be a key or a val"),
+       C(INVALID_SORT_FIELD,   "Sort field must be a key or a val"),   \
+       C(INVALID_STR_OPERAND,  "String type can not be an operand in expression"),
 
 #undef C
 #define C(a, b)                HIST_ERR_##a
@@ -2156,6 +2157,13 @@ static struct hist_field *parse_unary(struct hist_trigger_data *hist_data,
                ret = PTR_ERR(operand1);
                goto free;
        }
+       if (operand1->flags & HIST_FIELD_FL_STRING) {
+               /* String type can not be the operand of unary operator. */
+               hist_err(file->tr, HIST_ERR_INVALID_STR_OPERAND, errpos(str));
+               destroy_hist_field(operand1, 0);
+               ret = -EINVAL;
+               goto free;
+       }
 
        expr->flags |= operand1->flags &
                (HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS);
@@ -2257,6 +2265,11 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
                operand1 = NULL;
                goto free;
        }
+       if (operand1->flags & HIST_FIELD_FL_STRING) {
+               hist_err(file->tr, HIST_ERR_INVALID_STR_OPERAND, errpos(operand1_str));
+               ret = -EINVAL;
+               goto free;
+       }
 
        /* rest of string could be another expression e.g. b+c in a+b+c */
        operand_flags = 0;
@@ -2266,6 +2279,11 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
                operand2 = NULL;
                goto free;
        }
+       if (operand2->flags & HIST_FIELD_FL_STRING) {
+               hist_err(file->tr, HIST_ERR_INVALID_STR_OPERAND, errpos(str));
+               ret = -EINVAL;
+               goto free;
+       }
 
        ret = check_expr_operands(file->tr, operand1, operand2);
        if (ret)
@@ -2287,6 +2305,10 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
 
        expr->operands[0] = operand1;
        expr->operands[1] = operand2;
+
+       /* The operand sizes should be the same, so just pick one */
+       expr->size = operand1->size;
+
        expr->operator = field_op;
        expr->name = expr_str(expr, 0);
        expr->type = kstrdup(operand1->type, GFP_KERNEL);
index a6c0cda..14f46aa 100644 (file)
@@ -327,7 +327,7 @@ static void move_to_next_cpu(void)
 
        get_online_cpus();
        cpumask_and(current_mask, cpu_online_mask, tr->tracing_cpumask);
-       next_cpu = cpumask_next(smp_processor_id(), current_mask);
+       next_cpu = cpumask_next(raw_smp_processor_id(), current_mask);
        put_online_cpus();
 
        if (next_cpu >= nr_cpu_ids)
index 50142fc..f148eac 100644 (file)
@@ -3676,15 +3676,21 @@ static void pwq_unbound_release_workfn(struct work_struct *work)
                                                  unbound_release_work);
        struct workqueue_struct *wq = pwq->wq;
        struct worker_pool *pool = pwq->pool;
-       bool is_last;
+       bool is_last = false;
 
-       if (WARN_ON_ONCE(!(wq->flags & WQ_UNBOUND)))
-               return;
+       /*
+        * when @pwq is not linked, it doesn't hold any reference to the
+        * @wq, and @wq is invalid to access.
+        */
+       if (!list_empty(&pwq->pwqs_node)) {
+               if (WARN_ON_ONCE(!(wq->flags & WQ_UNBOUND)))
+                       return;
 
-       mutex_lock(&wq->mutex);
-       list_del_rcu(&pwq->pwqs_node);
-       is_last = list_empty(&wq->pwqs);
-       mutex_unlock(&wq->mutex);
+               mutex_lock(&wq->mutex);
+               list_del_rcu(&pwq->pwqs_node);
+               is_last = list_empty(&wq->pwqs);
+               mutex_unlock(&wq->mutex);
+       }
 
        mutex_lock(&wq_pool_mutex);
        put_unbound_pool(pool);
index d241fe4..5c9c068 100644 (file)
@@ -683,9 +683,6 @@ config PARMAN
 config OBJAGG
        tristate "objagg" if COMPILE_TEST
 
-config STRING_SELFTEST
-       tristate "Test string functions"
-
 endmenu
 
 config GENERIC_IOREMAP
index 8312127..5ddd575 100644 (file)
@@ -2180,6 +2180,9 @@ config ASYNC_RAID6_TEST
 config TEST_HEXDUMP
        tristate "Test functions located in the hexdump module at runtime"
 
+config STRING_SELFTEST
+       tristate "Test string functions at runtime"
+
 config TEST_STRING_HELPERS
        tristate "Test functions located in the string_helpers module at runtime"
 
index ae1f5d0..eb8e87c 100644 (file)
@@ -3574,7 +3574,8 @@ static unsigned long mem_cgroup_usage(struct mem_cgroup *memcg, bool swap)
        unsigned long val;
 
        if (mem_cgroup_is_root(memcg)) {
-               cgroup_rstat_flush(memcg->css.cgroup);
+               /* mem_cgroup_threshold() calls here from irqsafe context */
+               cgroup_rstat_flush_irqsafe(memcg->css.cgroup);
                val = memcg_page_state(memcg, NR_FILE_PAGES) +
                        memcg_page_state(memcg, NR_ANON_MAPPED);
                if (swap)
index 34a9ad3..7e24043 100644 (file)
@@ -2068,7 +2068,7 @@ int migrate_misplaced_page(struct page *page, struct vm_area_struct *vma,
        LIST_HEAD(migratepages);
        new_page_t *new;
        bool compound;
-       unsigned int nr_pages = thp_nr_pages(page);
+       int nr_pages = thp_nr_pages(page);
 
        /*
         * PTE mapped THP or HugeTLB page can't reach here so the page could
index f997fd5..58c01a3 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -346,7 +346,7 @@ static inline void memcg_slab_free_hook(struct kmem_cache *s_orig,
                        continue;
 
                page = virt_to_head_page(p[i]);
-               objcgs = page_objcgs(page);
+               objcgs = page_objcgs_check(page);
                if (!objcgs)
                        continue;
 
index 090fa14..af984e4 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -3236,6 +3236,16 @@ struct detached_freelist {
        struct kmem_cache *s;
 };
 
+static inline void free_nonslab_page(struct page *page)
+{
+       unsigned int order = compound_order(page);
+
+       VM_BUG_ON_PAGE(!PageCompound(page), page);
+       kfree_hook(page_address(page));
+       mod_lruvec_page_state(page, NR_SLAB_UNRECLAIMABLE_B, -(PAGE_SIZE << order));
+       __free_pages(page, order);
+}
+
 /*
  * This function progressively scans the array with free objects (with
  * a limited look ahead) and extract objects belonging to the same
@@ -3272,9 +3282,7 @@ int build_detached_freelist(struct kmem_cache *s, size_t size,
        if (!s) {
                /* Handle kalloc'ed objects */
                if (unlikely(!PageSlab(page))) {
-                       BUG_ON(!PageCompound(page));
-                       kfree_hook(object);
-                       __free_pages(page, compound_order(page));
+                       free_nonslab_page(page);
                        p[size] = NULL; /* mark object processed */
                        return size;
                }
@@ -4250,13 +4258,7 @@ void kfree(const void *x)
 
        page = virt_to_head_page(x);
        if (unlikely(!PageSlab(page))) {
-               unsigned int order = compound_order(page);
-
-               BUG_ON(!PageCompound(page));
-               kfree_hook(object);
-               mod_lruvec_page_state(page, NR_SLAB_UNRECLAIMABLE_B,
-                                     -(PAGE_SIZE << order));
-               __free_pages(page, order);
+               free_nonslab_page(page);
                return;
        }
        slab_free(page->slab_cache, page, object, NULL, 1, _RET_IP_);
index c3946c3..bdc95bd 100644 (file)
@@ -1075,11 +1075,16 @@ static bool j1939_session_deactivate_locked(struct j1939_session *session)
 
 static bool j1939_session_deactivate(struct j1939_session *session)
 {
+       struct j1939_priv *priv = session->priv;
        bool active;
 
-       j1939_session_list_lock(session->priv);
+       j1939_session_list_lock(priv);
+       /* This function should be called with a session ref-count of at
+        * least 2.
+        */
+       WARN_ON_ONCE(kref_read(&session->kref) < 2);
        active = j1939_session_deactivate_locked(session);
-       j1939_session_list_unlock(session->priv);
+       j1939_session_list_unlock(priv);
 
        return active;
 }
@@ -1869,7 +1874,7 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
                if (!session->transmission)
                        j1939_tp_schedule_txtimer(session, 0);
        } else {
-               j1939_tp_set_rxtimeout(session, 250);
+               j1939_tp_set_rxtimeout(session, 750);
        }
        session->last_cmd = 0xff;
        consume_skb(se_skb);
index ed4fcb7..cd5a493 100644 (file)
@@ -546,10 +546,18 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
                                return -EFAULT;
                }
 
+               rtnl_lock();
                lock_sock(sk);
 
-               if (ro->bound && ro->ifindex)
+               if (ro->bound && ro->ifindex) {
                        dev = dev_get_by_index(sock_net(sk), ro->ifindex);
+                       if (!dev) {
+                               if (count > 1)
+                                       kfree(filter);
+                               err = -ENODEV;
+                               goto out_fil;
+                       }
+               }
 
                if (ro->bound) {
                        /* (try to) register the new filters */
@@ -588,6 +596,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
                        dev_put(dev);
 
                release_sock(sk);
+               rtnl_unlock();
 
                break;
 
@@ -600,10 +609,16 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
 
                err_mask &= CAN_ERR_MASK;
 
+               rtnl_lock();
                lock_sock(sk);
 
-               if (ro->bound && ro->ifindex)
+               if (ro->bound && ro->ifindex) {
                        dev = dev_get_by_index(sock_net(sk), ro->ifindex);
+                       if (!dev) {
+                               err = -ENODEV;
+                               goto out_err;
+                       }
+               }
 
                /* remove current error mask */
                if (ro->bound) {
@@ -627,6 +642,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
                        dev_put(dev);
 
                release_sock(sk);
+               rtnl_unlock();
 
                break;
 
index 8fdd04f..8503262 100644 (file)
@@ -9328,18 +9328,10 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
 
        switch (attrs->flavour) {
        case DEVLINK_PORT_FLAVOUR_PHYSICAL:
-       case DEVLINK_PORT_FLAVOUR_VIRTUAL:
                n = snprintf(name, len, "p%u", attrs->phys.port_number);
                if (n < len && attrs->split)
                        n += snprintf(name + n, len - n, "s%u",
                                      attrs->phys.split_subport_number);
-               if (!attrs->split)
-                       n = snprintf(name, len, "p%u", attrs->phys.port_number);
-               else
-                       n = snprintf(name, len, "p%us%u",
-                                    attrs->phys.port_number,
-                                    attrs->phys.split_subport_number);
-
                break;
        case DEVLINK_PORT_FLAVOUR_CPU:
        case DEVLINK_PORT_FLAVOUR_DSA:
@@ -9381,6 +9373,8 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
                n = snprintf(name, len, "pf%usf%u", attrs->pci_sf.pf,
                             attrs->pci_sf.sf);
                break;
+       case DEVLINK_PORT_FLAVOUR_VIRTUAL:
+               return -EOPNOTSUPP;
        }
 
        if (n >= len)
index 2aadbfc..4b2415d 100644 (file)
@@ -1504,7 +1504,7 @@ __be32 flow_get_u32_dst(const struct flow_keys *flow)
 }
 EXPORT_SYMBOL(flow_get_u32_dst);
 
-/* Sort the source and destination IP (and the ports if the IP are the same),
+/* Sort the source and destination IP and the ports,
  * to have consistent hash within the two directions
  */
 static inline void __flow_hash_consistentify(struct flow_keys *keys)
@@ -1515,11 +1515,11 @@ static inline void __flow_hash_consistentify(struct flow_keys *keys)
        case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
                addr_diff = (__force u32)keys->addrs.v4addrs.dst -
                            (__force u32)keys->addrs.v4addrs.src;
-               if ((addr_diff < 0) ||
-                   (addr_diff == 0 &&
-                    ((__force u16)keys->ports.dst <
-                     (__force u16)keys->ports.src))) {
+               if (addr_diff < 0)
                        swap(keys->addrs.v4addrs.src, keys->addrs.v4addrs.dst);
+
+               if ((__force u16)keys->ports.dst <
+                   (__force u16)keys->ports.src) {
                        swap(keys->ports.src, keys->ports.dst);
                }
                break;
@@ -1527,13 +1527,13 @@ static inline void __flow_hash_consistentify(struct flow_keys *keys)
                addr_diff = memcmp(&keys->addrs.v6addrs.dst,
                                   &keys->addrs.v6addrs.src,
                                   sizeof(keys->addrs.v6addrs.dst));
-               if ((addr_diff < 0) ||
-                   (addr_diff == 0 &&
-                    ((__force u16)keys->ports.dst <
-                     (__force u16)keys->ports.src))) {
+               if (addr_diff < 0) {
                        for (i = 0; i < 4; i++)
                                swap(keys->addrs.v6addrs.src.s6_addr32[i],
                                     keys->addrs.v6addrs.dst.s6_addr32[i]);
+               }
+               if ((__force u16)keys->ports.dst <
+                   (__force u16)keys->ports.src) {
                        swap(keys->ports.src, keys->ports.dst);
                }
                break;
index 15d7128..2d6249b 100644 (file)
@@ -584,29 +584,42 @@ static int sk_psock_handle_skb(struct sk_psock *psock, struct sk_buff *skb,
        return sk_psock_skb_ingress(psock, skb);
 }
 
-static void sock_drop(struct sock *sk, struct sk_buff *skb)
+static void sk_psock_skb_state(struct sk_psock *psock,
+                              struct sk_psock_work_state *state,
+                              struct sk_buff *skb,
+                              int len, int off)
 {
-       sk_drops_add(sk, skb);
-       kfree_skb(skb);
+       spin_lock_bh(&psock->ingress_lock);
+       if (sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) {
+               state->skb = skb;
+               state->len = len;
+               state->off = off;
+       } else {
+               sock_drop(psock->sk, skb);
+       }
+       spin_unlock_bh(&psock->ingress_lock);
 }
 
 static void sk_psock_backlog(struct work_struct *work)
 {
        struct sk_psock *psock = container_of(work, struct sk_psock, work);
        struct sk_psock_work_state *state = &psock->work_state;
-       struct sk_buff *skb;
+       struct sk_buff *skb = NULL;
        bool ingress;
        u32 len, off;
        int ret;
 
        mutex_lock(&psock->work_mutex);
-       if (state->skb) {
+       if (unlikely(state->skb)) {
+               spin_lock_bh(&psock->ingress_lock);
                skb = state->skb;
                len = state->len;
                off = state->off;
                state->skb = NULL;
-               goto start;
+               spin_unlock_bh(&psock->ingress_lock);
        }
+       if (skb)
+               goto start;
 
        while ((skb = skb_dequeue(&psock->ingress_skb))) {
                len = skb->len;
@@ -621,9 +634,8 @@ start:
                                                          len, ingress);
                        if (ret <= 0) {
                                if (ret == -EAGAIN) {
-                                       state->skb = skb;
-                                       state->len = len;
-                                       state->off = off;
+                                       sk_psock_skb_state(psock, state, skb,
+                                                          len, off);
                                        goto end;
                                }
                                /* Hard errors break pipe and stop xmit. */
@@ -722,6 +734,11 @@ static void __sk_psock_zap_ingress(struct sk_psock *psock)
                skb_bpf_redirect_clear(skb);
                sock_drop(psock->sk, skb);
        }
+       kfree_skb(psock->work_state.skb);
+       /* We null the skb here to ensure that calls to sk_psock_backlog
+        * do not pick up the free'd skb.
+        */
+       psock->work_state.skb = NULL;
        __sk_psock_purge_ingress_msg(psock);
 }
 
@@ -773,8 +790,6 @@ static void sk_psock_destroy(struct work_struct *work)
 
 void sk_psock_drop(struct sock *sk, struct sk_psock *psock)
 {
-       sk_psock_stop(psock, false);
-
        write_lock_bh(&sk->sk_callback_lock);
        sk_psock_restore_proto(sk, psock);
        rcu_assign_sk_user_data(sk, NULL);
@@ -784,6 +799,8 @@ void sk_psock_drop(struct sock *sk, struct sk_psock *psock)
                sk_psock_stop_verdict(sk, psock);
        write_unlock_bh(&sk->sk_callback_lock);
 
+       sk_psock_stop(psock, false);
+
        INIT_RCU_WORK(&psock->rwork, sk_psock_destroy);
        queue_rcu_work(system_wq, &psock->rwork);
 }
index 0dca007..be75b40 100644 (file)
@@ -390,7 +390,7 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
                tunnel->i_seqno = ntohl(tpi->seq) + 1;
        }
 
-       skb_reset_network_header(skb);
+       skb_set_network_header(skb, (tunnel->dev->type == ARPHRD_ETHER) ? ETH_HLEN : 0);
 
        err = IP_ECN_decapsulate(iph, skb);
        if (unlikely(err)) {
index e1b9f7a..8e6ca9a 100644 (file)
@@ -549,9 +549,10 @@ int ip6_forward(struct sk_buff *skb)
        if (net->ipv6.devconf_all->proxy_ndp &&
            pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) {
                int proxied = ip6_forward_proxy_check(skb);
-               if (proxied > 0)
+               if (proxied > 0) {
+                       hdr->hop_limit--;
                        return ip6_input(skb);
-               else if (proxied < 0) {
+               else if (proxied < 0) {
                        __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS);
                        goto drop;
                }
index 7180979..ac5cadd 100644 (file)
@@ -98,8 +98,16 @@ static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr)
 {
        u8 rc = LLC_PDU_LEN_U;
 
-       if (addr->sllc_test || addr->sllc_xid)
+       if (addr->sllc_test)
                rc = LLC_PDU_LEN_U;
+       else if (addr->sllc_xid)
+               /* We need to expand header to sizeof(struct llc_xid_info)
+                * since llc_pdu_init_as_xid_cmd() sets 4,5,6 bytes of LLC header
+                * as XID PDU. In llc_ui_sendmsg() we reserved header size and then
+                * filled all other space with user data. If we won't reserve this
+                * bytes, llc_pdu_init_as_xid_cmd() will overwrite user data
+                */
+               rc = LLC_PDU_LEN_U_XID;
        else if (sk->sk_type == SOCK_STREAM)
                rc = LLC_PDU_LEN_I;
        return rc;
index b554f26..79d1cef 100644 (file)
@@ -79,7 +79,7 @@ int llc_sap_action_send_xid_c(struct llc_sap *sap, struct sk_buff *skb)
        struct llc_sap_state_ev *ev = llc_sap_ev(skb);
        int rc;
 
-       llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap,
+       llc_pdu_header_init(skb, LLC_PDU_TYPE_U_XID, ev->saddr.lsap,
                            ev->daddr.lsap, LLC_PDU_CMD);
        llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 0);
        rc = llc_mac_hdr_init(skb, ev->saddr.mac, ev->daddr.mac);
index 84cc773..4e6f11e 100644 (file)
@@ -152,6 +152,8 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                                  struct vif_params *params)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
+       struct sta_info *sta;
        int ret;
 
        ret = ieee80211_if_change_type(sdata, type);
@@ -162,7 +164,24 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
                ieee80211_check_fast_rx_iface(sdata);
        } else if (type == NL80211_IFTYPE_STATION && params->use_4addr >= 0) {
+               struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+               if (params->use_4addr == ifmgd->use_4addr)
+                       return 0;
+
                sdata->u.mgd.use_4addr = params->use_4addr;
+               if (!ifmgd->associated)
+                       return 0;
+
+               mutex_lock(&local->sta_mtx);
+               sta = sta_info_get(sdata, ifmgd->bssid);
+               if (sta)
+                       drv_sta_set_4addr(local, sdata, &sta->sta,
+                                         params->use_4addr);
+               mutex_unlock(&local->sta_mtx);
+
+               if (params->use_4addr)
+                       ieee80211_send_4addr_nullfunc(local, sdata);
        }
 
        if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
index 22549b9..30ce6d2 100644 (file)
@@ -2201,6 +2201,8 @@ void ieee80211_dynamic_ps_timer(struct timer_list *t);
 void ieee80211_send_nullfunc(struct ieee80211_local *local,
                             struct ieee80211_sub_if_data *sdata,
                             bool powersave);
+void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
+                                  struct ieee80211_sub_if_data *sdata);
 void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
                             struct ieee80211_hdr *hdr, bool ack, u16 tx_time);
 
index a00f11a..c0ea3b1 100644 (file)
@@ -1095,8 +1095,8 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
        ieee80211_tx_skb(sdata, skb);
 }
 
-static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
-                                         struct ieee80211_sub_if_data *sdata)
+void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
+                                  struct ieee80211_sub_if_data *sdata)
 {
        struct sk_buff *skb;
        struct ieee80211_hdr *nullfunc;
index 771921c..2563473 100644 (file)
@@ -730,7 +730,8 @@ ieee80211_make_monitor_skb(struct ieee80211_local *local,
                 * Need to make a copy and possibly remove radiotap header
                 * and FCS from the original.
                 */
-               skb = skb_copy_expand(*origskb, needed_headroom, 0, GFP_ATOMIC);
+               skb = skb_copy_expand(*origskb, needed_headroom + NET_SKB_PAD,
+                                     0, GFP_ATOMIC);
 
                if (!skb)
                        return NULL;
index e969811..8509778 100644 (file)
@@ -1147,6 +1147,29 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
        return queued;
 }
 
+static void
+ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata,
+                    struct sta_info *sta,
+                    struct sk_buff *skb)
+{
+       struct rate_control_ref *ref = sdata->local->rate_ctrl;
+       u16 tid;
+
+       if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER))
+               return;
+
+       if (!sta || !sta->sta.ht_cap.ht_supported ||
+           !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO ||
+           skb->protocol == sdata->control_port_protocol)
+               return;
+
+       tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+       if (likely(sta->ampdu_mlme.tid_tx[tid]))
+               return;
+
+       ieee80211_start_tx_ba_session(&sta->sta, tid, 0);
+}
+
 /*
  * initialises @tx
  * pass %NULL for the station if unknown, a valid pointer if known
@@ -1160,6 +1183,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_hdr *hdr;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       bool aggr_check = false;
        int tid;
 
        memset(tx, 0, sizeof(*tx));
@@ -1188,8 +1212,10 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
                } else if (tx->sdata->control_port_protocol == tx->skb->protocol) {
                        tx->sta = sta_info_get_bss(sdata, hdr->addr1);
                }
-               if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
+               if (!tx->sta && !is_multicast_ether_addr(hdr->addr1)) {
                        tx->sta = sta_info_get(sdata, hdr->addr1);
+                       aggr_check = true;
+               }
        }
 
        if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
@@ -1199,8 +1225,12 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
                struct tid_ampdu_tx *tid_tx;
 
                tid = ieee80211_get_tid(hdr);
-
                tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
+               if (!tid_tx && aggr_check) {
+                       ieee80211_aggr_check(sdata, tx->sta, skb);
+                       tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
+               }
+
                if (tid_tx) {
                        bool queued;
 
@@ -4120,29 +4150,6 @@ void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
 }
 EXPORT_SYMBOL(ieee80211_txq_schedule_start);
 
-static void
-ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata,
-                    struct sta_info *sta,
-                    struct sk_buff *skb)
-{
-       struct rate_control_ref *ref = sdata->local->rate_ctrl;
-       u16 tid;
-
-       if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER))
-               return;
-
-       if (!sta || !sta->sta.ht_cap.ht_supported ||
-           !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO ||
-           skb->protocol == sdata->control_port_protocol)
-               return;
-
-       tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
-       if (likely(sta->ampdu_mlme.tid_tx[tid]))
-               return;
-
-       ieee80211_start_tx_ba_session(&sta->sta, tid, 0);
-}
-
 void __ieee80211_subif_start_xmit(struct sk_buff *skb,
                                  struct net_device *dev,
                                  u32 info_flags,
index 83c52df..5c03e51 100644 (file)
@@ -670,8 +670,13 @@ bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report)
                return false;
 
        tstamp = nf_conn_tstamp_find(ct);
-       if (tstamp && tstamp->stop == 0)
+       if (tstamp) {
+               s32 timeout = ct->timeout - nfct_time_stamp;
+
                tstamp->stop = ktime_get_real_ns();
+               if (timeout < 0)
+                       tstamp->stop -= jiffies_to_nsecs(-timeout);
+       }
 
        if (nf_conntrack_event_report(IPCT_DESTROY, ct,
                                    portid, report) < 0) {
index 1e50908..551976e 100644 (file)
@@ -331,7 +331,11 @@ EXPORT_SYMBOL_GPL(flow_offload_add);
 void flow_offload_refresh(struct nf_flowtable *flow_table,
                          struct flow_offload *flow)
 {
-       flow->timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
+       u32 timeout;
+
+       timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
+       if (READ_ONCE(flow->timeout) != timeout)
+               WRITE_ONCE(flow->timeout, timeout);
 
        if (likely(!nf_flowtable_hw_offload(flow_table)))
                return;
index de182d1..081437d 100644 (file)
@@ -8445,6 +8445,16 @@ static int nf_tables_commit_audit_alloc(struct list_head *adl,
        return 0;
 }
 
+static void nf_tables_commit_audit_free(struct list_head *adl)
+{
+       struct nft_audit_data *adp, *adn;
+
+       list_for_each_entry_safe(adp, adn, adl, list) {
+               list_del(&adp->list);
+               kfree(adp);
+       }
+}
+
 static void nf_tables_commit_audit_collect(struct list_head *adl,
                                           struct nft_table *table, u32 op)
 {
@@ -8509,6 +8519,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
                ret = nf_tables_commit_audit_alloc(&adl, trans->ctx.table);
                if (ret) {
                        nf_tables_commit_chain_prepare_cancel(net);
+                       nf_tables_commit_audit_free(&adl);
                        return ret;
                }
                if (trans->msg_type == NFT_MSG_NEWRULE ||
@@ -8518,6 +8529,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
                        ret = nf_tables_commit_chain_prepare(net, chain);
                        if (ret < 0) {
                                nf_tables_commit_chain_prepare_cancel(net);
+                               nf_tables_commit_audit_free(&adl);
                                return ret;
                        }
                }
index 50b4e3c..202f57d 100644 (file)
@@ -174,7 +174,9 @@ static const struct nf_hook_entries *
 nfnl_hook_entries_head(u8 pf, unsigned int hook, struct net *net, const char *dev)
 {
        const struct nf_hook_entries *hook_head = NULL;
+#ifdef CONFIG_NETFILTER_INGRESS
        struct net_device *netdev;
+#endif
 
        switch (pf) {
        case NFPROTO_IPV4:
index 8088b99..304e33c 100644 (file)
@@ -48,24 +48,30 @@ static void nft_last_eval(const struct nft_expr *expr,
 {
        struct nft_last_priv *priv = nft_expr_priv(expr);
 
-       priv->last_jiffies = jiffies;
-       priv->last_set = 1;
+       if (READ_ONCE(priv->last_jiffies) != jiffies)
+               WRITE_ONCE(priv->last_jiffies, jiffies);
+       if (READ_ONCE(priv->last_set) == 0)
+               WRITE_ONCE(priv->last_set, 1);
 }
 
 static int nft_last_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        struct nft_last_priv *priv = nft_expr_priv(expr);
+       unsigned long last_jiffies = READ_ONCE(priv->last_jiffies);
+       u32 last_set = READ_ONCE(priv->last_set);
        __be64 msecs;
 
-       if (time_before(jiffies, priv->last_jiffies))
-               priv->last_set = 0;
+       if (time_before(jiffies, last_jiffies)) {
+               WRITE_ONCE(priv->last_set, 0);
+               last_set = 0;
+       }
 
-       if (priv->last_set)
-               msecs = nf_jiffies64_to_msecs(jiffies - priv->last_jiffies);
+       if (last_set)
+               msecs = nf_jiffies64_to_msecs(jiffies - last_jiffies);
        else
                msecs = 0;
 
-       if (nla_put_be32(skb, NFTA_LAST_SET, htonl(priv->last_set)) ||
+       if (nla_put_be32(skb, NFTA_LAST_SET, htonl(last_set)) ||
            nla_put_be64(skb, NFTA_LAST_MSECS, msecs, NFTA_LAST_PAD))
                goto nla_put_failure;
 
index 0840c63..be1595d 100644 (file)
@@ -201,7 +201,9 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
                alen = sizeof_field(struct nf_nat_range, min_addr.ip6);
                break;
        default:
-               return -EAFNOSUPPORT;
+               if (tb[NFTA_NAT_REG_ADDR_MIN])
+                       return -EAFNOSUPPORT;
+               break;
        }
        priv->family = family;
 
index e6f4a62..171b7f3 100644 (file)
@@ -518,8 +518,10 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
                if (!ipc)
                        goto err;
 
-               if (sock_queue_rcv_skb(&ipc->sk, skb))
+               if (sock_queue_rcv_skb(&ipc->sk, skb)) {
+                       qrtr_port_put(ipc);
                        goto err;
+               }
 
                qrtr_port_put(ipc);
        }
@@ -839,6 +841,8 @@ static int qrtr_local_enqueue(struct qrtr_node *node, struct sk_buff *skb,
 
        ipc = qrtr_port_lookup(to->sq_port);
        if (!ipc || &ipc->sk == skb->sk) { /* do not send to self */
+               if (ipc)
+                       qrtr_port_put(ipc);
                kfree_skb(skb);
                return -ENODEV;
        }
index eb3c2a3..5ef86fd 100644 (file)
@@ -1203,7 +1203,7 @@ static struct sctp_association *__sctp_rcv_asconf_lookup(
        if (unlikely(!af))
                return NULL;
 
-       if (af->from_addr_param(&paddr, param, peer_port, 0))
+       if (!af->from_addr_param(&paddr, param, peer_port, 0))
                return NULL;
 
        return __sctp_lookup_association(net, laddr, &paddr, transportp);
index e48dd90..470dbdc 100644 (file)
@@ -100,8 +100,9 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
                list_for_each_entry_safe(addr, temp,
                                        &net->sctp.local_addr_list, list) {
                        if (addr->a.sa.sa_family == AF_INET6 &&
-                                       ipv6_addr_equal(&addr->a.v6.sin6_addr,
-                                               &ifa->addr)) {
+                           ipv6_addr_equal(&addr->a.v6.sin6_addr,
+                                           &ifa->addr) &&
+                           addr->a.v6.sin6_scope_id == ifa->idev->dev->ifindex) {
                                sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_DEL);
                                found = 1;
                                addr->valid = 0;
index 09a8f23..32df65f 100644 (file)
@@ -1109,12 +1109,12 @@ enum sctp_disposition sctp_sf_send_probe(struct net *net,
        if (!sctp_transport_pl_enabled(transport))
                return SCTP_DISPOSITION_CONSUME;
 
-       sctp_transport_pl_send(transport);
-
-       reply = sctp_make_heartbeat(asoc, transport, transport->pl.probe_size);
-       if (!reply)
-               return SCTP_DISPOSITION_NOMEM;
-       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
+       if (sctp_transport_pl_send(transport)) {
+               reply = sctp_make_heartbeat(asoc, transport, transport->pl.probe_size);
+               if (!reply)
+                       return SCTP_DISPOSITION_NOMEM;
+               sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
+       }
        sctp_add_cmd_sf(commands, SCTP_CMD_PROBE_TIMER_UPDATE,
                        SCTP_TRANSPORT(transport));
 
@@ -1274,8 +1274,7 @@ enum sctp_disposition sctp_sf_backbeat_8_3(struct net *net,
                    !sctp_transport_pl_enabled(link))
                        return SCTP_DISPOSITION_DISCARD;
 
-               sctp_transport_pl_recv(link);
-               if (link->pl.state == SCTP_PL_COMPLETE)
+               if (sctp_transport_pl_recv(link))
                        return SCTP_DISPOSITION_CONSUME;
 
                return sctp_sf_send_probe(net, ep, asoc, type, link, commands);
index 397a624..a3d3ca6 100644 (file)
@@ -258,16 +258,13 @@ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk)
        sctp_transport_pl_update(transport);
 }
 
-void sctp_transport_pl_send(struct sctp_transport *t)
+bool sctp_transport_pl_send(struct sctp_transport *t)
 {
-       pr_debug("%s: PLPMTUD: transport: %p, state: %d, pmtu: %d, size: %d, high: %d\n",
-                __func__, t, t->pl.state, t->pl.pmtu, t->pl.probe_size, t->pl.probe_high);
-
-       if (t->pl.probe_count < SCTP_MAX_PROBES) {
-               t->pl.probe_count++;
-               return;
-       }
+       if (t->pl.probe_count < SCTP_MAX_PROBES)
+               goto out;
 
+       t->pl.last_rtx_chunks = t->asoc->rtx_data_chunks;
+       t->pl.probe_count = 0;
        if (t->pl.state == SCTP_PL_BASE) {
                if (t->pl.probe_size == SCTP_BASE_PLPMTU) { /* BASE_PLPMTU Confirmation Failed */
                        t->pl.state = SCTP_PL_ERROR; /* Base -> Error */
@@ -299,14 +296,27 @@ void sctp_transport_pl_send(struct sctp_transport *t)
                        sctp_assoc_sync_pmtu(t->asoc);
                }
        }
-       t->pl.probe_count = 1;
+
+out:
+       if (t->pl.state == SCTP_PL_COMPLETE && t->pl.raise_count < 30 &&
+           !t->pl.probe_count && t->pl.last_rtx_chunks == t->asoc->rtx_data_chunks) {
+               t->pl.raise_count++;
+               return false;
+       }
+
+       pr_debug("%s: PLPMTUD: transport: %p, state: %d, pmtu: %d, size: %d, high: %d\n",
+                __func__, t, t->pl.state, t->pl.pmtu, t->pl.probe_size, t->pl.probe_high);
+
+       t->pl.probe_count++;
+       return true;
 }
 
-void sctp_transport_pl_recv(struct sctp_transport *t)
+bool sctp_transport_pl_recv(struct sctp_transport *t)
 {
        pr_debug("%s: PLPMTUD: transport: %p, state: %d, pmtu: %d, size: %d, high: %d\n",
                 __func__, t, t->pl.state, t->pl.pmtu, t->pl.probe_size, t->pl.probe_high);
 
+       t->pl.last_rtx_chunks = t->asoc->rtx_data_chunks;
        t->pl.pmtu = t->pl.probe_size;
        t->pl.probe_count = 0;
        if (t->pl.state == SCTP_PL_BASE) {
@@ -323,7 +333,7 @@ void sctp_transport_pl_recv(struct sctp_transport *t)
                if (!t->pl.probe_high) {
                        t->pl.probe_size = min(t->pl.probe_size + SCTP_PL_BIG_STEP,
                                               SCTP_MAX_PLPMTU);
-                       return;
+                       return false;
                }
                t->pl.probe_size += SCTP_PL_MIN_STEP;
                if (t->pl.probe_size >= t->pl.probe_high) {
@@ -335,14 +345,13 @@ void sctp_transport_pl_recv(struct sctp_transport *t)
                        t->pathmtu = t->pl.pmtu + sctp_transport_pl_hlen(t);
                        sctp_assoc_sync_pmtu(t->asoc);
                }
-       } else if (t->pl.state == SCTP_PL_COMPLETE) {
-               t->pl.raise_count++;
-               if (t->pl.raise_count == 30) {
-                       /* Raise probe_size again after 30 * interval in Search Complete */
-                       t->pl.state = SCTP_PL_SEARCH; /* Search Complete -> Search */
-                       t->pl.probe_size += SCTP_PL_MIN_STEP;
-               }
+       } else if (t->pl.state == SCTP_PL_COMPLETE && t->pl.raise_count == 30) {
+               /* Raise probe_size again after 30 * interval in Search Complete */
+               t->pl.state = SCTP_PL_SEARCH; /* Search Complete -> Search */
+               t->pl.probe_size += SCTP_PL_MIN_STEP;
        }
+
+       return t->pl.state == SCTP_PL_COMPLETE;
 }
 
 static bool sctp_transport_pl_toobig(struct sctp_transport *t, u32 pmtu)
index e5c43d4..c9391d3 100644 (file)
@@ -898,16 +898,10 @@ static int tipc_aead_decrypt(struct net *net, struct tipc_aead *aead,
        if (unlikely(!aead))
                return -ENOKEY;
 
-       /* Cow skb data if needed */
-       if (likely(!skb_cloned(skb) &&
-                  (!skb_is_nonlinear(skb) || !skb_has_frag_list(skb)))) {
-               nsg = 1 + skb_shinfo(skb)->nr_frags;
-       } else {
-               nsg = skb_cow_data(skb, 0, &unused);
-               if (unlikely(nsg < 0)) {
-                       pr_err("RX: skb_cow_data() returned %d\n", nsg);
-                       return nsg;
-               }
+       nsg = skb_cow_data(skb, 0, &unused);
+       if (unlikely(nsg < 0)) {
+               pr_err("RX: skb_cow_data() returned %d\n", nsg);
+               return nsg;
        }
 
        /* Allocate memory for the AEAD operation */
index 34a97ea..75b99b7 100644 (file)
@@ -158,6 +158,7 @@ static void tipc_sk_remove(struct tipc_sock *tsk);
 static int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dsz);
 static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz);
 static void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack);
+static int tipc_wait_for_connect(struct socket *sock, long *timeo_p);
 
 static const struct proto_ops packet_ops;
 static const struct proto_ops stream_ops;
@@ -1515,8 +1516,13 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)
                rc = 0;
        }
 
-       if (unlikely(syn && !rc))
+       if (unlikely(syn && !rc)) {
                tipc_set_sk_state(sk, TIPC_CONNECTING);
+               if (timeout) {
+                       timeout = msecs_to_jiffies(timeout);
+                       tipc_wait_for_connect(sock, &timeout);
+               }
+       }
 
        return rc ? rc : dlen;
 }
@@ -1564,7 +1570,7 @@ static int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dlen)
                return -EMSGSIZE;
 
        /* Handle implicit connection setup */
-       if (unlikely(dest)) {
+       if (unlikely(dest && sk->sk_state == TIPC_OPEN)) {
                rc = __tipc_sendmsg(sock, m, dlen);
                if (dlen && dlen == rc) {
                        tsk->peer_caps = tipc_node_get_capabilities(net, dnode);
@@ -2646,7 +2652,7 @@ static int tipc_listen(struct socket *sock, int len)
 static int tipc_wait_for_accept(struct socket *sock, long timeo)
 {
        struct sock *sk = sock->sk;
-       DEFINE_WAIT(wait);
+       DEFINE_WAIT_FUNC(wait, woken_wake_function);
        int err;
 
        /* True wake-one mechanism for incoming connections: only
@@ -2655,12 +2661,12 @@ static int tipc_wait_for_accept(struct socket *sock, long timeo)
         * anymore, the common case will execute the loop only once.
        */
        for (;;) {
-               prepare_to_wait_exclusive(sk_sleep(sk), &wait,
-                                         TASK_INTERRUPTIBLE);
                if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
+                       add_wait_queue(sk_sleep(sk), &wait);
                        release_sock(sk);
-                       timeo = schedule_timeout(timeo);
+                       timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
                        lock_sock(sk);
+                       remove_wait_queue(sk_sleep(sk), &wait);
                }
                err = 0;
                if (!skb_queue_empty(&sk->sk_receive_queue))
@@ -2672,7 +2678,6 @@ static int tipc_wait_for_accept(struct socket *sock, long timeo)
                if (signal_pending(current))
                        break;
        }
-       finish_wait(sk_sleep(sk), &wait);
        return err;
 }
 
@@ -2689,9 +2694,10 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags,
                       bool kern)
 {
        struct sock *new_sk, *sk = sock->sk;
-       struct sk_buff *buf;
        struct tipc_sock *new_tsock;
+       struct msghdr m = {NULL,};
        struct tipc_msg *msg;
+       struct sk_buff *buf;
        long timeo;
        int res;
 
@@ -2737,19 +2743,17 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags,
        }
 
        /*
-        * Respond to 'SYN-' by discarding it & returning 'ACK'-.
-        * Respond to 'SYN+' by queuing it on new socket.
+        * Respond to 'SYN-' by discarding it & returning 'ACK'.
+        * Respond to 'SYN+' by queuing it on new socket & returning 'ACK'.
         */
        if (!msg_data_sz(msg)) {
-               struct msghdr m = {NULL,};
-
                tsk_advance_rx_queue(sk);
-               __tipc_sendstream(new_sock, &m, 0);
        } else {
                __skb_dequeue(&sk->sk_receive_queue);
                __skb_queue_head(&new_sk->sk_receive_queue, buf);
                skb_set_owner_r(buf, new_sk);
        }
+       __tipc_sendstream(new_sock, &m, 0);
        release_sock(new_sk);
 exit:
        release_sock(sk);
index 23c92ad..ba7ced9 100644 (file)
@@ -1526,6 +1526,53 @@ out:
        return err;
 }
 
+static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb)
+{
+       scm->fp = scm_fp_dup(UNIXCB(skb).fp);
+
+       /*
+        * Garbage collection of unix sockets starts by selecting a set of
+        * candidate sockets which have reference only from being in flight
+        * (total_refs == inflight_refs).  This condition is checked once during
+        * the candidate collection phase, and candidates are marked as such, so
+        * that non-candidates can later be ignored.  While inflight_refs is
+        * protected by unix_gc_lock, total_refs (file count) is not, hence this
+        * is an instantaneous decision.
+        *
+        * Once a candidate, however, the socket must not be reinstalled into a
+        * file descriptor while the garbage collection is in progress.
+        *
+        * If the above conditions are met, then the directed graph of
+        * candidates (*) does not change while unix_gc_lock is held.
+        *
+        * Any operations that changes the file count through file descriptors
+        * (dup, close, sendmsg) does not change the graph since candidates are
+        * not installed in fds.
+        *
+        * Dequeing a candidate via recvmsg would install it into an fd, but
+        * that takes unix_gc_lock to decrement the inflight count, so it's
+        * serialized with garbage collection.
+        *
+        * MSG_PEEK is special in that it does not change the inflight count,
+        * yet does install the socket into an fd.  The following lock/unlock
+        * pair is to ensure serialization with garbage collection.  It must be
+        * done between incrementing the file count and installing the file into
+        * an fd.
+        *
+        * If garbage collection starts after the barrier provided by the
+        * lock/unlock, then it will see the elevated refcount and not mark this
+        * as a candidate.  If a garbage collection is already in progress
+        * before the file count was incremented, then the lock/unlock pair will
+        * ensure that garbage collection is finished before progressing to
+        * installing the fd.
+        *
+        * (*) A -> B where B is on the queue of A or B is on the queue of C
+        * which is on the queue of listening socket A.
+        */
+       spin_lock(&unix_gc_lock);
+       spin_unlock(&unix_gc_lock);
+}
+
 static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds)
 {
        int err = 0;
@@ -2175,7 +2222,7 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
                sk_peek_offset_fwd(sk, size);
 
                if (UNIXCB(skb).fp)
-                       scm.fp = scm_fp_dup(UNIXCB(skb).fp);
+                       unix_peek_fds(&scm, skb);
        }
        err = (flags & MSG_TRUNC) ? skb->len - skip : size;
 
@@ -2418,7 +2465,7 @@ unlock:
                        /* It is questionable, see note in unix_dgram_recvmsg.
                         */
                        if (UNIXCB(skb).fp)
-                               scm.fp = scm_fp_dup(UNIXCB(skb).fp);
+                               unix_peek_fds(&scm, skb);
 
                        sk_peek_offset_fwd(sk, chunk);
 
index 50eb405..16c88be 100644 (file)
@@ -2351,7 +2351,10 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                        goto nla_put_failure;
 
                for (band = state->band_start;
-                    band < NUM_NL80211_BANDS; band++) {
+                    band < (state->split ?
+                               NUM_NL80211_BANDS :
+                               NL80211_BAND_60GHZ + 1);
+                    band++) {
                        struct ieee80211_supported_band *sband;
 
                        /* omit higher bands for ancient software */
index f03c7ac..7897b14 100644 (file)
@@ -1754,16 +1754,14 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
                         * be grouped with this beacon for updates ...
                         */
                        if (!cfg80211_combine_bsses(rdev, new)) {
-                               kfree(new);
+                               bss_ref_put(rdev, new);
                                goto drop;
                        }
                }
 
                if (rdev->bss_entries >= bss_entries_limit &&
                    !cfg80211_bss_expire_oldest(rdev)) {
-                       if (!list_empty(&new->hidden_list))
-                               list_del(&new->hidden_list);
-                       kfree(new);
+                       bss_ref_put(rdev, new);
                        goto drop;
                }
 
index c17e480..8f6b13a 100755 (executable)
@@ -173,39 +173,6 @@ my $mcount_regex;  # Find the call site to mcount (return offset)
 my $mcount_adjust;     # Address adjustment to mcount offset
 my $alignment;         # The .align value to use for $mcount_section
 my $section_type;      # Section header plus possible alignment command
-my $can_use_local = 0;         # If we can use local function references
-
-# Shut up recordmcount if user has older objcopy
-my $quiet_recordmcount = ".tmp_quiet_recordmcount";
-my $print_warning = 1;
-$print_warning = 0 if ( -f $quiet_recordmcount);
-
-##
-# check_objcopy - whether objcopy supports --globalize-symbols
-#
-#  --globalize-symbols came out in 2.17, we must test the version
-#  of objcopy, and if it is less than 2.17, then we can not
-#  record local functions.
-sub check_objcopy
-{
-    open (IN, "$objcopy --version |") or die "error running $objcopy";
-    while (<IN>) {
-       if (/objcopy.*\s(\d+)\.(\d+)/) {
-           $can_use_local = 1 if ($1 > 2 || ($1 == 2 && $2 >= 17));
-           last;
-       }
-    }
-    close (IN);
-
-    if (!$can_use_local && $print_warning) {
-       print STDERR "WARNING: could not find objcopy version or version " .
-           "is less than 2.17.\n" .
-           "\tLocal function references are disabled.\n";
-       open (QUIET, ">$quiet_recordmcount");
-       printf QUIET "Disables the warning from recordmcount.pl\n";
-       close QUIET;
-    }
-}
 
 if ($arch =~ /(x86(_64)?)|(i386)/) {
     if ($bits == 64) {
@@ -434,8 +401,6 @@ if ($filename =~ m,^(.*)(\.\S),) {
 my $mcount_s = $dirname . "/.tmp_mc_" . $prefix . ".s";
 my $mcount_o = $dirname . "/.tmp_mc_" . $prefix . ".o";
 
-check_objcopy();
-
 #
 # Step 1: find all the local (static functions) and weak symbols.
 #         't' is local, 'w/W' is weak
@@ -473,11 +438,6 @@ sub update_funcs
 
     # is this function static? If so, note this fact.
     if (defined $locals{$ref_func}) {
-
-       # only use locals if objcopy supports globalize-symbols
-       if (!$can_use_local) {
-           return;
-       }
        $convert{$ref_func} = 1;
     }
 
index 74f8aad..7011fbe 100755 (executable)
@@ -17,7 +17,7 @@ Usage:
        $ cat /sys/kernel/debug/tracing/trace_pipe > ~/raw_trace_func
        Wait some times but not too much, the script is a bit slow.
        Break the pipe (Ctrl + Z)
-       $ scripts/draw_functrace.py < raw_trace_func > draw_functrace
+       $ scripts/tracing/draw_functrace.py < ~/raw_trace_func > draw_functrace
        Then you have your drawn trace in draw_functrace
 """
 
@@ -103,10 +103,10 @@ def parseLine(line):
        line = line.strip()
        if line.startswith("#"):
                raise CommentLineException
-       m = re.match("[^]]+?\\] +([0-9.]+): (\\w+) <-(\\w+)", line)
+       m = re.match("[^]]+?\\] +([a-z.]+) +([0-9.]+): (\\w+) <-(\\w+)", line)
        if m is None:
                raise BrokenLineException
-       return (m.group(1), m.group(2), m.group(3))
+       return (m.group(2), m.group(3), m.group(4))
 
 
 def main():
index 22f8326..bc1f648 100644 (file)
@@ -2434,6 +2434,22 @@ static int cs_etm__process_event(struct perf_session *session,
        return 0;
 }
 
+static void dump_queued_data(struct cs_etm_auxtrace *etm,
+                            struct perf_record_auxtrace *event)
+{
+       struct auxtrace_buffer *buf;
+       unsigned int i;
+       /*
+        * Find all buffers with same reference in the queues and dump them.
+        * This is because the queues can contain multiple entries of the same
+        * buffer that were split on aux records.
+        */
+       for (i = 0; i < etm->queues.nr_queues; ++i)
+               list_for_each_entry(buf, &etm->queues.queue_array[i].head, list)
+                       if (buf->reference == event->reference)
+                               cs_etm__dump_event(etm, buf);
+}
+
 static int cs_etm__process_auxtrace_event(struct perf_session *session,
                                          union perf_event *event,
                                          struct perf_tool *tool __maybe_unused)
@@ -2466,7 +2482,8 @@ static int cs_etm__process_auxtrace_event(struct perf_session *session,
                                cs_etm__dump_event(etm, buffer);
                                auxtrace_buffer__put_data(buffer);
                        }
-       }
+       } else if (dump_trace)
+               dump_queued_data(etm, &event->auxtrace);
 
        return 0;
 }
@@ -3042,7 +3059,6 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
 
        if (dump_trace) {
                cs_etm__print_auxtrace_info(auxtrace_info->priv, num_cpu);
-               return 0;
        }
 
        err = cs_etm__synth_events(etm, session);
index 72e7f36..8af693d 100644 (file)
@@ -192,8 +192,6 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
                        if (!(prot & PROT_EXEC))
                                dso__set_loaded(dso);
                }
-
-               nsinfo__put(dso->nsinfo);
                dso->nsinfo = nsi;
 
                if (build_id__is_defined(bid))
index a1bd700..fc683bc 100644 (file)
@@ -742,9 +742,13 @@ struct pmu_events_map *__weak pmu_events_map__find(void)
        return perf_pmu__find_map(NULL);
 }
 
-static bool perf_pmu__valid_suffix(char *pmu_name, char *tok)
+/*
+ * Suffix must be in form tok_{digits}, or tok{digits}, or same as pmu_name
+ * to be valid.
+ */
+static bool perf_pmu__valid_suffix(const char *pmu_name, char *tok)
 {
-       char *p;
+       const char *p;
 
        if (strncmp(pmu_name, tok, strlen(tok)))
                return false;
@@ -753,12 +757,16 @@ static bool perf_pmu__valid_suffix(char *pmu_name, char *tok)
        if (*p == 0)
                return true;
 
-       if (*p != '_')
-               return false;
+       if (*p == '_')
+               ++p;
 
-       ++p;
-       if (*p == 0 || !isdigit(*p))
-               return false;
+       /* Ensure we end in a number */
+       while (1) {
+               if (!isdigit(*p))
+                       return false;
+               if (*(++p) == 0)
+                       break;
+       }
 
        return true;
 }
@@ -789,12 +797,19 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
         *          match "socket" in "socketX_pmunameY" and then "pmuname" in
         *          "pmunameY".
         */
-       for (; tok; name += strlen(tok), tok = strtok_r(NULL, ",", &tmp)) {
+       while (1) {
+               char *next_tok = strtok_r(NULL, ",", &tmp);
+
                name = strstr(name, tok);
-               if (!name || !perf_pmu__valid_suffix((char *)name, tok)) {
+               if (!name ||
+                   (!next_tok && !perf_pmu__valid_suffix(name, tok))) {
                        res = false;
                        goto out;
                }
+               if (!next_tok)
+                       break;
+               tok = next_tok;
+               name += strlen(tok);
        }
 
        res = true;
index a3e593d..2debba4 100644 (file)
@@ -1,4 +1,233 @@
 {
+       "map access: known scalar += value_ptr unknown vs const",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+                   offsetof(struct __sk_buff, len)),
+       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 1, 3),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 1, 2),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
+       BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_0, 0),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_4, 1, 4),
+       BPF_MOV64_IMM(BPF_REG_1, 6),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_1, 0),
+       BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x7),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_MOV64_IMM(BPF_REG_1, 3),
+       BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
+       BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_EXIT_INSN(),
+       },
+       .fixup_map_hash_16b = { 5 },
+       .fixup_map_array_48b = { 8 },
+       .result_unpriv = REJECT,
+       .errstr_unpriv = "R1 tried to add from different maps, paths or scalars",
+       .result = ACCEPT,
+       .retval = 1,
+},
+{
+       "map access: known scalar += value_ptr const vs unknown",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+                   offsetof(struct __sk_buff, len)),
+       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 1, 3),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 1, 2),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
+       BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_0, 0),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_4, 1, 2),
+       BPF_MOV64_IMM(BPF_REG_1, 3),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 3),
+       BPF_MOV64_IMM(BPF_REG_1, 6),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_1, 0),
+       BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x7),
+       BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
+       BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_EXIT_INSN(),
+       },
+       .fixup_map_hash_16b = { 5 },
+       .fixup_map_array_48b = { 8 },
+       .result_unpriv = REJECT,
+       .errstr_unpriv = "R1 tried to add from different maps, paths or scalars",
+       .result = ACCEPT,
+       .retval = 1,
+},
+{
+       "map access: known scalar += value_ptr const vs const (ne)",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+                   offsetof(struct __sk_buff, len)),
+       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 1, 3),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 1, 2),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
+       BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_0, 0),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_4, 1, 2),
+       BPF_MOV64_IMM(BPF_REG_1, 3),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_MOV64_IMM(BPF_REG_1, 5),
+       BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
+       BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_EXIT_INSN(),
+       },
+       .fixup_map_hash_16b = { 5 },
+       .fixup_map_array_48b = { 8 },
+       .result_unpriv = REJECT,
+       .errstr_unpriv = "R1 tried to add from different maps, paths or scalars",
+       .result = ACCEPT,
+       .retval = 1,
+},
+{
+       "map access: known scalar += value_ptr const vs const (eq)",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+                   offsetof(struct __sk_buff, len)),
+       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 1, 3),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 1, 2),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
+       BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_0, 0),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_4, 1, 2),
+       BPF_MOV64_IMM(BPF_REG_1, 5),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_MOV64_IMM(BPF_REG_1, 5),
+       BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
+       BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_EXIT_INSN(),
+       },
+       .fixup_map_hash_16b = { 5 },
+       .fixup_map_array_48b = { 8 },
+       .result = ACCEPT,
+       .retval = 1,
+},
+{
+       "map access: known scalar += value_ptr unknown vs unknown (eq)",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+                   offsetof(struct __sk_buff, len)),
+       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 1, 3),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 1, 2),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 11),
+       BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_0, 0),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_4, 1, 4),
+       BPF_MOV64_IMM(BPF_REG_1, 6),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_1, 0),
+       BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x7),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 3),
+       BPF_MOV64_IMM(BPF_REG_1, 6),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_1, 0),
+       BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x7),
+       BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
+       BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_EXIT_INSN(),
+       },
+       .fixup_map_hash_16b = { 5 },
+       .fixup_map_array_48b = { 8 },
+       .result = ACCEPT,
+       .retval = 1,
+},
+{
+       "map access: known scalar += value_ptr unknown vs unknown (lt)",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+                   offsetof(struct __sk_buff, len)),
+       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 1, 3),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 1, 2),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 11),
+       BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_0, 0),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_4, 1, 4),
+       BPF_MOV64_IMM(BPF_REG_1, 6),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_1, 0),
+       BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x3),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 3),
+       BPF_MOV64_IMM(BPF_REG_1, 6),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_1, 0),
+       BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x7),
+       BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
+       BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_EXIT_INSN(),
+       },
+       .fixup_map_hash_16b = { 5 },
+       .fixup_map_array_48b = { 8 },
+       .result_unpriv = REJECT,
+       .errstr_unpriv = "R1 tried to add from different maps, paths or scalars",
+       .result = ACCEPT,
+       .retval = 1,
+},
+{
+       "map access: known scalar += value_ptr unknown vs unknown (gt)",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
+                   offsetof(struct __sk_buff, len)),
+       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 1, 3),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 1, 2),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 11),
+       BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_0, 0),
+       BPF_JMP_IMM(BPF_JEQ, BPF_REG_4, 1, 4),
+       BPF_MOV64_IMM(BPF_REG_1, 6),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_1, 0),
+       BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x7),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 3),
+       BPF_MOV64_IMM(BPF_REG_1, 6),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_1, 0),
+       BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x3),
+       BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
+       BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_EXIT_INSN(),
+       },
+       .fixup_map_hash_16b = { 5 },
+       .fixup_map_array_48b = { 8 },
+       .result_unpriv = REJECT,
+       .errstr_unpriv = "R1 tried to add from different maps, paths or scalars",
+       .result = ACCEPT,
+       .retval = 1,
+},
+{
        "map access: known scalar += value_ptr from different maps",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
index 06a351b..0709af0 100644 (file)
@@ -38,6 +38,7 @@
 /x86_64/xen_vmcall_test
 /x86_64/xss_msr_test
 /x86_64/vmx_pmu_msrs_test
+/access_tracking_perf_test
 /demand_paging_test
 /dirty_log_test
 /dirty_log_perf_test
index b853be2..5832f51 100644 (file)
@@ -71,6 +71,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/tsc_msrs_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_pmu_msrs_test
 TEST_GEN_PROGS_x86_64 += x86_64/xen_shinfo_test
 TEST_GEN_PROGS_x86_64 += x86_64/xen_vmcall_test
+TEST_GEN_PROGS_x86_64 += access_tracking_perf_test
 TEST_GEN_PROGS_x86_64 += demand_paging_test
 TEST_GEN_PROGS_x86_64 += dirty_log_test
 TEST_GEN_PROGS_x86_64 += dirty_log_perf_test
index a16c8f0..cc89818 100644 (file)
@@ -1019,7 +1019,8 @@ static __u64 sve_rejects_set[] = {
 #define VREGS_SUBLIST \
        { "vregs", .regs = vregs, .regs_n = ARRAY_SIZE(vregs), }
 #define PMU_SUBLIST \
-       { "pmu", .regs = pmu_regs, .regs_n = ARRAY_SIZE(pmu_regs), }
+       { "pmu", .capability = KVM_CAP_ARM_PMU_V3, .feature = KVM_ARM_VCPU_PMU_V3, \
+         .regs = pmu_regs, .regs_n = ARRAY_SIZE(pmu_regs), }
 #define SVE_SUBLIST \
        { "sve", .capability = KVM_CAP_ARM_SVE, .feature = KVM_ARM_VCPU_SVE, .finalize = true, \
          .regs = sve_regs, .regs_n = ARRAY_SIZE(sve_regs), \
diff --git a/tools/testing/selftests/kvm/access_tracking_perf_test.c b/tools/testing/selftests/kvm/access_tracking_perf_test.c
new file mode 100644 (file)
index 0000000..e2baa18
--- /dev/null
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * access_tracking_perf_test
+ *
+ * Copyright (C) 2021, Google, Inc.
+ *
+ * This test measures the performance effects of KVM's access tracking.
+ * Access tracking is driven by the MMU notifiers test_young, clear_young, and
+ * clear_flush_young. These notifiers do not have a direct userspace API,
+ * however the clear_young notifier can be triggered by marking a pages as idle
+ * in /sys/kernel/mm/page_idle/bitmap. This test leverages that mechanism to
+ * enable access tracking on guest memory.
+ *
+ * To measure performance this test runs a VM with a configurable number of
+ * vCPUs that each touch every page in disjoint regions of memory. Performance
+ * is measured in the time it takes all vCPUs to finish touching their
+ * predefined region.
+ *
+ * Note that a deterministic correctness test of access tracking is not possible
+ * by using page_idle as it exists today. This is for a few reasons:
+ *
+ * 1. page_idle only issues clear_young notifiers, which lack a TLB flush. This
+ *    means subsequent guest accesses are not guaranteed to see page table
+ *    updates made by KVM until some time in the future.
+ *
+ * 2. page_idle only operates on LRU pages. Newly allocated pages are not
+ *    immediately allocated to LRU lists. Instead they are held in a "pagevec",
+ *    which is drained to LRU lists some time in the future. There is no
+ *    userspace API to force this drain to occur.
+ *
+ * These limitations are worked around in this test by using a large enough
+ * region of memory for each vCPU such that the number of translations cached in
+ * the TLB and the number of pages held in pagevecs are a small fraction of the
+ * overall workload. And if either of those conditions are not true this test
+ * will fail rather than silently passing.
+ */
+#include <inttypes.h>
+#include <limits.h>
+#include <pthread.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "kvm_util.h"
+#include "test_util.h"
+#include "perf_test_util.h"
+#include "guest_modes.h"
+
+/* Global variable used to synchronize all of the vCPU threads. */
+static int iteration = -1;
+
+/* Defines what vCPU threads should do during a given iteration. */
+static enum {
+       /* Run the vCPU to access all its memory. */
+       ITERATION_ACCESS_MEMORY,
+       /* Mark the vCPU's memory idle in page_idle. */
+       ITERATION_MARK_IDLE,
+} iteration_work;
+
+/* Set to true when vCPU threads should exit. */
+static bool done;
+
+/* The iteration that was last completed by each vCPU. */
+static int vcpu_last_completed_iteration[KVM_MAX_VCPUS];
+
+/* Whether to overlap the regions of memory vCPUs access. */
+static bool overlap_memory_access;
+
+struct test_params {
+       /* The backing source for the region of memory. */
+       enum vm_mem_backing_src_type backing_src;
+
+       /* The amount of memory to allocate for each vCPU. */
+       uint64_t vcpu_memory_bytes;
+
+       /* The number of vCPUs to create in the VM. */
+       int vcpus;
+};
+
+static uint64_t pread_uint64(int fd, const char *filename, uint64_t index)
+{
+       uint64_t value;
+       off_t offset = index * sizeof(value);
+
+       TEST_ASSERT(pread(fd, &value, sizeof(value), offset) == sizeof(value),
+                   "pread from %s offset 0x%" PRIx64 " failed!",
+                   filename, offset);
+
+       return value;
+
+}
+
+#define PAGEMAP_PRESENT (1ULL << 63)
+#define PAGEMAP_PFN_MASK ((1ULL << 55) - 1)
+
+static uint64_t lookup_pfn(int pagemap_fd, struct kvm_vm *vm, uint64_t gva)
+{
+       uint64_t hva = (uint64_t) addr_gva2hva(vm, gva);
+       uint64_t entry;
+       uint64_t pfn;
+
+       entry = pread_uint64(pagemap_fd, "pagemap", hva / getpagesize());
+       if (!(entry & PAGEMAP_PRESENT))
+               return 0;
+
+       pfn = entry & PAGEMAP_PFN_MASK;
+       if (!pfn) {
+               print_skip("Looking up PFNs requires CAP_SYS_ADMIN");
+               exit(KSFT_SKIP);
+       }
+
+       return pfn;
+}
+
+static bool is_page_idle(int page_idle_fd, uint64_t pfn)
+{
+       uint64_t bits = pread_uint64(page_idle_fd, "page_idle", pfn / 64);
+
+       return !!((bits >> (pfn % 64)) & 1);
+}
+
+static void mark_page_idle(int page_idle_fd, uint64_t pfn)
+{
+       uint64_t bits = 1ULL << (pfn % 64);
+
+       TEST_ASSERT(pwrite(page_idle_fd, &bits, 8, 8 * (pfn / 64)) == 8,
+                   "Set page_idle bits for PFN 0x%" PRIx64, pfn);
+}
+
+static void mark_vcpu_memory_idle(struct kvm_vm *vm, int vcpu_id)
+{
+       uint64_t base_gva = perf_test_args.vcpu_args[vcpu_id].gva;
+       uint64_t pages = perf_test_args.vcpu_args[vcpu_id].pages;
+       uint64_t page;
+       uint64_t still_idle = 0;
+       uint64_t no_pfn = 0;
+       int page_idle_fd;
+       int pagemap_fd;
+
+       /* If vCPUs are using an overlapping region, let vCPU 0 mark it idle. */
+       if (overlap_memory_access && vcpu_id)
+               return;
+
+       page_idle_fd = open("/sys/kernel/mm/page_idle/bitmap", O_RDWR);
+       TEST_ASSERT(page_idle_fd > 0, "Failed to open page_idle.");
+
+       pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
+       TEST_ASSERT(pagemap_fd > 0, "Failed to open pagemap.");
+
+       for (page = 0; page < pages; page++) {
+               uint64_t gva = base_gva + page * perf_test_args.guest_page_size;
+               uint64_t pfn = lookup_pfn(pagemap_fd, vm, gva);
+
+               if (!pfn) {
+                       no_pfn++;
+                       continue;
+               }
+
+               if (is_page_idle(page_idle_fd, pfn)) {
+                       still_idle++;
+                       continue;
+               }
+
+               mark_page_idle(page_idle_fd, pfn);
+       }
+
+       /*
+        * Assumption: Less than 1% of pages are going to be swapped out from
+        * under us during this test.
+        */
+       TEST_ASSERT(no_pfn < pages / 100,
+                   "vCPU %d: No PFN for %" PRIu64 " out of %" PRIu64 " pages.",
+                   vcpu_id, no_pfn, pages);
+
+       /*
+        * Test that at least 90% of memory has been marked idle (the rest might
+        * not be marked idle because the pages have not yet made it to an LRU
+        * list or the translations are still cached in the TLB). 90% is
+        * arbitrary; high enough that we ensure most memory access went through
+        * access tracking but low enough as to not make the test too brittle
+        * over time and across architectures.
+        */
+       TEST_ASSERT(still_idle < pages / 10,
+                   "vCPU%d: Too many pages still idle (%"PRIu64 " out of %"
+                   PRIu64 ").\n",
+                   vcpu_id, still_idle, pages);
+
+       close(page_idle_fd);
+       close(pagemap_fd);
+}
+
+static void assert_ucall(struct kvm_vm *vm, uint32_t vcpu_id,
+                        uint64_t expected_ucall)
+{
+       struct ucall uc;
+       uint64_t actual_ucall = get_ucall(vm, vcpu_id, &uc);
+
+       TEST_ASSERT(expected_ucall == actual_ucall,
+                   "Guest exited unexpectedly (expected ucall %" PRIu64
+                   ", got %" PRIu64 ")",
+                   expected_ucall, actual_ucall);
+}
+
+static bool spin_wait_for_next_iteration(int *current_iteration)
+{
+       int last_iteration = *current_iteration;
+
+       do {
+               if (READ_ONCE(done))
+                       return false;
+
+               *current_iteration = READ_ONCE(iteration);
+       } while (last_iteration == *current_iteration);
+
+       return true;
+}
+
+static void *vcpu_thread_main(void *arg)
+{
+       struct perf_test_vcpu_args *vcpu_args = arg;
+       struct kvm_vm *vm = perf_test_args.vm;
+       int vcpu_id = vcpu_args->vcpu_id;
+       int current_iteration = -1;
+
+       vcpu_args_set(vm, vcpu_id, 1, vcpu_id);
+
+       while (spin_wait_for_next_iteration(&current_iteration)) {
+               switch (READ_ONCE(iteration_work)) {
+               case ITERATION_ACCESS_MEMORY:
+                       vcpu_run(vm, vcpu_id);
+                       assert_ucall(vm, vcpu_id, UCALL_SYNC);
+                       break;
+               case ITERATION_MARK_IDLE:
+                       mark_vcpu_memory_idle(vm, vcpu_id);
+                       break;
+               };
+
+               vcpu_last_completed_iteration[vcpu_id] = current_iteration;
+       }
+
+       return NULL;
+}
+
+static void spin_wait_for_vcpu(int vcpu_id, int target_iteration)
+{
+       while (READ_ONCE(vcpu_last_completed_iteration[vcpu_id]) !=
+              target_iteration) {
+               continue;
+       }
+}
+
+/* The type of memory accesses to perform in the VM. */
+enum access_type {
+       ACCESS_READ,
+       ACCESS_WRITE,
+};
+
+static void run_iteration(struct kvm_vm *vm, int vcpus, const char *description)
+{
+       struct timespec ts_start;
+       struct timespec ts_elapsed;
+       int next_iteration;
+       int vcpu_id;
+
+       /* Kick off the vCPUs by incrementing iteration. */
+       next_iteration = ++iteration;
+
+       clock_gettime(CLOCK_MONOTONIC, &ts_start);
+
+       /* Wait for all vCPUs to finish the iteration. */
+       for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++)
+               spin_wait_for_vcpu(vcpu_id, next_iteration);
+
+       ts_elapsed = timespec_elapsed(ts_start);
+       pr_info("%-30s: %ld.%09lds\n",
+               description, ts_elapsed.tv_sec, ts_elapsed.tv_nsec);
+}
+
+static void access_memory(struct kvm_vm *vm, int vcpus, enum access_type access,
+                         const char *description)
+{
+       perf_test_args.wr_fract = (access == ACCESS_READ) ? INT_MAX : 1;
+       sync_global_to_guest(vm, perf_test_args);
+       iteration_work = ITERATION_ACCESS_MEMORY;
+       run_iteration(vm, vcpus, description);
+}
+
+static void mark_memory_idle(struct kvm_vm *vm, int vcpus)
+{
+       /*
+        * Even though this parallelizes the work across vCPUs, this is still a
+        * very slow operation because page_idle forces the test to mark one pfn
+        * at a time and the clear_young notifier serializes on the KVM MMU
+        * lock.
+        */
+       pr_debug("Marking VM memory idle (slow)...\n");
+       iteration_work = ITERATION_MARK_IDLE;
+       run_iteration(vm, vcpus, "Mark memory idle");
+}
+
+static pthread_t *create_vcpu_threads(int vcpus)
+{
+       pthread_t *vcpu_threads;
+       int i;
+
+       vcpu_threads = malloc(vcpus * sizeof(vcpu_threads[0]));
+       TEST_ASSERT(vcpu_threads, "Failed to allocate vcpu_threads.");
+
+       for (i = 0; i < vcpus; i++) {
+               vcpu_last_completed_iteration[i] = iteration;
+               pthread_create(&vcpu_threads[i], NULL, vcpu_thread_main,
+                              &perf_test_args.vcpu_args[i]);
+       }
+
+       return vcpu_threads;
+}
+
+static void terminate_vcpu_threads(pthread_t *vcpu_threads, int vcpus)
+{
+       int i;
+
+       /* Set done to signal the vCPU threads to exit */
+       done = true;
+
+       for (i = 0; i < vcpus; i++)
+               pthread_join(vcpu_threads[i], NULL);
+}
+
+static void run_test(enum vm_guest_mode mode, void *arg)
+{
+       struct test_params *params = arg;
+       struct kvm_vm *vm;
+       pthread_t *vcpu_threads;
+       int vcpus = params->vcpus;
+
+       vm = perf_test_create_vm(mode, vcpus, params->vcpu_memory_bytes,
+                                params->backing_src);
+
+       perf_test_setup_vcpus(vm, vcpus, params->vcpu_memory_bytes,
+                             !overlap_memory_access);
+
+       vcpu_threads = create_vcpu_threads(vcpus);
+
+       pr_info("\n");
+       access_memory(vm, vcpus, ACCESS_WRITE, "Populating memory");
+
+       /* As a control, read and write to the populated memory first. */
+       access_memory(vm, vcpus, ACCESS_WRITE, "Writing to populated memory");
+       access_memory(vm, vcpus, ACCESS_READ, "Reading from populated memory");
+
+       /* Repeat on memory that has been marked as idle. */
+       mark_memory_idle(vm, vcpus);
+       access_memory(vm, vcpus, ACCESS_WRITE, "Writing to idle memory");
+       mark_memory_idle(vm, vcpus);
+       access_memory(vm, vcpus, ACCESS_READ, "Reading from idle memory");
+
+       terminate_vcpu_threads(vcpu_threads, vcpus);
+       free(vcpu_threads);
+       perf_test_destroy_vm(vm);
+}
+
+static void help(char *name)
+{
+       puts("");
+       printf("usage: %s [-h] [-m mode] [-b vcpu_bytes] [-v vcpus] [-o]  [-s mem_type]\n",
+              name);
+       puts("");
+       printf(" -h: Display this help message.");
+       guest_modes_help();
+       printf(" -b: specify the size of the memory region which should be\n"
+              "     dirtied by each vCPU. e.g. 10M or 3G.\n"
+              "     (default: 1G)\n");
+       printf(" -v: specify the number of vCPUs to run.\n");
+       printf(" -o: Overlap guest memory accesses instead of partitioning\n"
+              "     them into a separate region of memory for each vCPU.\n");
+       printf(" -s: specify the type of memory that should be used to\n"
+              "     back the guest data region.\n\n");
+       backing_src_help();
+       puts("");
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct test_params params = {
+               .backing_src = VM_MEM_SRC_ANONYMOUS,
+               .vcpu_memory_bytes = DEFAULT_PER_VCPU_MEM_SIZE,
+               .vcpus = 1,
+       };
+       int page_idle_fd;
+       int opt;
+
+       guest_modes_append_default();
+
+       while ((opt = getopt(argc, argv, "hm:b:v:os:")) != -1) {
+               switch (opt) {
+               case 'm':
+                       guest_modes_cmdline(optarg);
+                       break;
+               case 'b':
+                       params.vcpu_memory_bytes = parse_size(optarg);
+                       break;
+               case 'v':
+                       params.vcpus = atoi(optarg);
+                       break;
+               case 'o':
+                       overlap_memory_access = true;
+                       break;
+               case 's':
+                       params.backing_src = parse_backing_src_type(optarg);
+                       break;
+               case 'h':
+               default:
+                       help(argv[0]);
+                       break;
+               }
+       }
+
+       page_idle_fd = open("/sys/kernel/mm/page_idle/bitmap", O_RDWR);
+       if (page_idle_fd < 0) {
+               print_skip("CONFIG_IDLE_PAGE_TRACKING is not enabled");
+               exit(KSFT_SKIP);
+       }
+       close(page_idle_fd);
+
+       for_each_guest_mode(run_test, &params);
+
+       return 0;
+}
index 04a2641..80cbd3a 100644 (file)
@@ -312,6 +312,7 @@ int main(int argc, char *argv[])
                        break;
                case 'o':
                        p.partition_vcpu_memory_access = false;
+                       break;
                case 's':
                        p.backing_src = parse_backing_src_type(optarg);
                        break;
index 412eaee..b669107 100644 (file)
 #define HV_X64_GUEST_DEBUGGING_AVAILABLE               BIT(1)
 #define HV_X64_PERF_MONITOR_AVAILABLE                  BIT(2)
 #define HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE      BIT(3)
-#define HV_X64_HYPERCALL_PARAMS_XMM_AVAILABLE          BIT(4)
+#define HV_X64_HYPERCALL_XMM_INPUT_AVAILABLE           BIT(4)
 #define HV_X64_GUEST_IDLE_STATE_AVAILABLE              BIT(5)
 #define HV_FEATURE_FREQUENCY_MSRS_AVAILABLE            BIT(8)
 #define HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE           BIT(10)
 #define HV_STATUS_INVALID_CONNECTION_ID                18
 #define HV_STATUS_INSUFFICIENT_BUFFERS         19
 
+/* hypercall options */
+#define HV_HYPERCALL_FAST_BIT          BIT(16)
+
 #endif /* !SELFTEST_KVM_HYPERV_H */
index b0031f2..ecec308 100644 (file)
@@ -320,7 +320,7 @@ int main(int ac, char **av)
                run_delay = get_run_delay();
                pthread_create(&thread, &attr, do_steal_time, NULL);
                do
-                       pthread_yield();
+                       sched_yield();
                while (get_run_delay() - run_delay < MIN_RUN_DELAY_NS);
                pthread_join(thread, NULL);
                run_delay = get_run_delay() - run_delay;
index bab10ae..e0b2bb1 100644 (file)
@@ -215,7 +215,7 @@ int main(void)
        vcpu_set_hv_cpuid(vm, VCPU_ID);
 
        tsc_page_gva = vm_vaddr_alloc_page(vm);
-       memset(addr_gpa2hva(vm, tsc_page_gva), 0x0, getpagesize());
+       memset(addr_gva2hva(vm, tsc_page_gva), 0x0, getpagesize());
        TEST_ASSERT((addr_gva2gpa(vm, tsc_page_gva) & (getpagesize() - 1)) == 0,
                "TSC page has to be page aligned\n");
        vcpu_args_set(vm, VCPU_ID, 2, tsc_page_gva, addr_gva2gpa(vm, tsc_page_gva));
index af27c7e..91d88aa 100644 (file)
@@ -47,6 +47,7 @@ static void do_wrmsr(u32 idx, u64 val)
 }
 
 static int nr_gp;
+static int nr_ud;
 
 static inline u64 hypercall(u64 control, vm_vaddr_t input_address,
                            vm_vaddr_t output_address)
@@ -80,6 +81,12 @@ static void guest_gp_handler(struct ex_regs *regs)
                regs->rip = (uint64_t)&wrmsr_end;
 }
 
+static void guest_ud_handler(struct ex_regs *regs)
+{
+       nr_ud++;
+       regs->rip += 3;
+}
+
 struct msr_data {
        uint32_t idx;
        bool available;
@@ -90,6 +97,7 @@ struct msr_data {
 struct hcall_data {
        uint64_t control;
        uint64_t expect;
+       bool ud_expected;
 };
 
 static void guest_msr(struct msr_data *msr)
@@ -117,13 +125,26 @@ static void guest_msr(struct msr_data *msr)
 static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall)
 {
        int i = 0;
+       u64 res, input, output;
 
        wrmsr(HV_X64_MSR_GUEST_OS_ID, LINUX_OS_ID);
        wrmsr(HV_X64_MSR_HYPERCALL, pgs_gpa);
 
        while (hcall->control) {
-               GUEST_ASSERT(hypercall(hcall->control, pgs_gpa,
-                                      pgs_gpa + 4096) == hcall->expect);
+               nr_ud = 0;
+               if (!(hcall->control & HV_HYPERCALL_FAST_BIT)) {
+                       input = pgs_gpa;
+                       output = pgs_gpa + 4096;
+               } else {
+                       input = output = 0;
+               }
+
+               res = hypercall(hcall->control, input, output);
+               if (hcall->ud_expected)
+                       GUEST_ASSERT(nr_ud == 1);
+               else
+                       GUEST_ASSERT(res == hcall->expect);
+
                GUEST_SYNC(i++);
        }
 
@@ -552,8 +573,18 @@ static void guest_test_hcalls_access(struct kvm_vm *vm, struct hcall_data *hcall
                        recomm.ebx = 0xfff;
                        hcall->expect = HV_STATUS_SUCCESS;
                        break;
-
                case 17:
+                       /* XMM fast hypercall */
+                       hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE | HV_HYPERCALL_FAST_BIT;
+                       hcall->ud_expected = true;
+                       break;
+               case 18:
+                       feat.edx |= HV_X64_HYPERCALL_XMM_INPUT_AVAILABLE;
+                       hcall->ud_expected = false;
+                       hcall->expect = HV_STATUS_SUCCESS;
+                       break;
+
+               case 19:
                        /* END */
                        hcall->control = 0;
                        break;
@@ -625,6 +656,10 @@ int main(void)
        /* Test hypercalls */
        vm = vm_create_default(VCPU_ID, 0, guest_hcall);
 
+       vm_init_descriptor_tables(vm);
+       vcpu_init_descriptor_tables(vm, VCPU_ID);
+       vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler);
+
        /* Hypercall input/output */
        hcall_page = vm_vaddr_alloc_pages(vm, 2);
        memset(addr_gva2hva(vm, hcall_page), 0x0, 2 * getpagesize());
index 9869598..b50dbe2 100644 (file)
@@ -892,6 +892,8 @@ static void kvm_destroy_vm_debugfs(struct kvm *kvm)
 
 static int kvm_create_vm_debugfs(struct kvm *kvm, int fd)
 {
+       static DEFINE_MUTEX(kvm_debugfs_lock);
+       struct dentry *dent;
        char dir_name[ITOA_MAX_LEN * 2];
        struct kvm_stat_data *stat_data;
        const struct _kvm_stats_desc *pdesc;
@@ -903,8 +905,20 @@ static int kvm_create_vm_debugfs(struct kvm *kvm, int fd)
                return 0;
 
        snprintf(dir_name, sizeof(dir_name), "%d-%d", task_pid_nr(current), fd);
-       kvm->debugfs_dentry = debugfs_create_dir(dir_name, kvm_debugfs_dir);
+       mutex_lock(&kvm_debugfs_lock);
+       dent = debugfs_lookup(dir_name, kvm_debugfs_dir);
+       if (dent) {
+               pr_warn_ratelimited("KVM: debugfs: duplicate directory %s\n", dir_name);
+               dput(dent);
+               mutex_unlock(&kvm_debugfs_lock);
+               return 0;
+       }
+       dent = debugfs_create_dir(dir_name, kvm_debugfs_dir);
+       mutex_unlock(&kvm_debugfs_lock);
+       if (IS_ERR(dent))
+               return 0;
 
+       kvm->debugfs_dentry = dent;
        kvm->debugfs_stat_data = kcalloc(kvm_debugfs_num_entries,
                                         sizeof(*kvm->debugfs_stat_data),
                                         GFP_KERNEL_ACCOUNT);
@@ -3110,6 +3124,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
                                        ++vcpu->stat.generic.halt_poll_invalid;
                                goto out;
                        }
+                       cpu_relax();
                        poll_end = cur = ktime_get();
                } while (kvm_vcpu_can_poll(cur, stop));
        }
@@ -4390,6 +4405,16 @@ struct compat_kvm_dirty_log {
        };
 };
 
+struct compat_kvm_clear_dirty_log {
+       __u32 slot;
+       __u32 num_pages;
+       __u64 first_page;
+       union {
+               compat_uptr_t dirty_bitmap; /* one bit per page */
+               __u64 padding2;
+       };
+};
+
 static long kvm_vm_compat_ioctl(struct file *filp,
                           unsigned int ioctl, unsigned long arg)
 {
@@ -4399,6 +4424,24 @@ static long kvm_vm_compat_ioctl(struct file *filp,
        if (kvm->mm != current->mm)
                return -EIO;
        switch (ioctl) {
+#ifdef CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT
+       case KVM_CLEAR_DIRTY_LOG: {
+               struct compat_kvm_clear_dirty_log compat_log;
+               struct kvm_clear_dirty_log log;
+
+               if (copy_from_user(&compat_log, (void __user *)arg,
+                                  sizeof(compat_log)))
+                       return -EFAULT;
+               log.slot         = compat_log.slot;
+               log.num_pages    = compat_log.num_pages;
+               log.first_page   = compat_log.first_page;
+               log.padding2     = compat_log.padding2;
+               log.dirty_bitmap = compat_ptr(compat_log.dirty_bitmap);
+
+               r = kvm_vm_ioctl_clear_dirty_log(kvm, &log);
+               break;
+       }
+#endif
        case KVM_GET_DIRTY_LOG: {
                struct compat_kvm_dirty_log compat_log;
                struct kvm_dirty_log log;
@@ -5172,7 +5215,7 @@ static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm)
        }
        add_uevent_var(env, "PID=%d", kvm->userspace_pid);
 
-       if (!IS_ERR_OR_NULL(kvm->debugfs_dentry)) {
+       if (kvm->debugfs_dentry) {
                char *tmp, *p = kmalloc(PATH_MAX, GFP_KERNEL_ACCOUNT);
 
                if (p) {