OSDN Git Service

Merge tag 'mtd/fixes-for-6.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 11 Apr 2023 17:09:29 +0000 (10:09 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 11 Apr 2023 17:09:29 +0000 (10:09 -0700)
Pull mtd fixes from Miquel Raynal:
 "Core fix:

   - mtdblock: Tolerate corrected bit-flips

  Raw NAND fixes:

   - meson: Fix bitmask for length in command word

   - stm32_fmc2:

       - Remove unsupported EDO mode

       - Use timings.mode instead of checking tRC_min.

         The first patch is the real fix but nowadays we use
         timings.mode instead of bare timings, so in order to ease the
         backports, the fix was split into two steps, the first one easy
         to backport on older kernels, the second one just as a
         follow-up so recent stable kernels would look like the
         mainline"

* tag 'mtd/fixes-for-6.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux:
  mtd: rawnand: meson: fix bitmask for length in command word
  mtdblock: tolerate corrected bit-flips
  mtd: rawnand: stm32_fmc2: use timings.mode instead of checking tRC_min
  mtd: rawnand: stm32_fmc2: remove unsupported EDO mode

228 files changed:
.mailmap
Documentation/devicetree/bindings/serial/renesas,scif.yaml
Documentation/mm/zsmalloc.rst
Documentation/virt/kvm/api.rst
MAINTAINERS
Makefile
arch/arm64/kernel/compat_alignment.c
arch/arm64/kvm/arm.c
arch/arm64/kvm/hyp/include/nvhe/fixed_config.h
arch/arm64/kvm/hyp/nvhe/sys_regs.c
arch/arm64/kvm/pmu-emul.c
arch/arm64/kvm/sys_regs.c
arch/powerpc/kvm/powerpc.c
arch/s390/kvm/intercept.c
arch/s390/kvm/kvm-s390.c
arch/x86/Makefile.um
arch/x86/include/asm/intel-family.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kvm/ioapic.c
arch/x86/kvm/kvm_onhyperv.h
arch/x86/kvm/svm/svm.c
arch/x86/kvm/svm/svm_onhyperv.h
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/x86.c
block/blk-mq.c
block/genhd.c
drivers/accel/ivpu/ivpu_job.c
drivers/accel/ivpu/ivpu_pm.c
drivers/acpi/acpi_video.c
drivers/acpi/video_detect.c
drivers/block/ublk_drv.c
drivers/block/virtio_blk.c
drivers/counter/104-quad-8.c
drivers/cxl/core/hdm.c
drivers/cxl/core/pci.c
drivers/cxl/core/pmem.c
drivers/cxl/core/port.c
drivers/cxl/core/region.c
drivers/cxl/cxl.h
drivers/cxl/cxlpci.h
drivers/cxl/port.c
drivers/gpio/Kconfig
drivers/gpio/gpio-davinci.c
drivers/gpu/drm/i915/display/intel_dp_mst.c
drivers/gpu/drm/i915/gem/i915_gem_ttm.c
drivers/gpu/drm/i915/gt/intel_execlists_submission.c
drivers/gpu/drm/i915/gt/uc/intel_huc.c
drivers/gpu/drm/i915/gt/uc/intel_huc.h
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/nouveau/dispnv50/disp.c
drivers/gpu/drm/nouveau/nouveau_dp.c
drivers/gpu/drm/panfrost/panfrost_mmu.c
drivers/hv/connection.c
drivers/hwtracing/coresight/coresight-etm4x-core.c
drivers/hwtracing/coresight/coresight-etm4x.h
drivers/iio/accel/kionix-kx022a.c
drivers/iio/adc/ad7791.c
drivers/iio/adc/ltc2497.c
drivers/iio/adc/max11410.c
drivers/iio/adc/palmas_gpadc.c
drivers/iio/adc/qcom-spmi-adc5.c
drivers/iio/adc/ti-ads7950.c
drivers/iio/dac/cio-dac.c
drivers/iio/imu/Kconfig
drivers/iio/industrialio-buffer.c
drivers/iio/light/cm32181.c
drivers/iio/light/vcnl4000.c
drivers/iommu/iommufd/pages.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/mv88e6xxx/global2.c
drivers/net/dsa/mv88e6xxx/global2.h
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/google/gve/gve.h
drivers/net/ethernet/google/gve/gve_tx.c
drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c
drivers/net/ethernet/mediatek/mtk_eth_soc.c
drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/ti/am65-cpsw-nuss.c
drivers/net/phy/phylink.c
drivers/net/phy/sfp.c
drivers/net/wireless/ath/ath11k/mhi.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
drivers/net/wireless/mediatek/mt76/mt7603/main.c
drivers/net/wireless/mediatek/mt76/mt7615/mac.c
drivers/net/wireless/mediatek/mt76/mt7615/main.c
drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
drivers/net/wireless/mediatek/mt76/mt76x02_util.c
drivers/net/wireless/mediatek/mt76/mt7915/main.c
drivers/net/wireless/mediatek/mt76/mt7921/init.c
drivers/net/wireless/mediatek/mt76/mt7921/main.c
drivers/net/wireless/mediatek/mt76/mt7921/pci.c
drivers/net/wireless/mediatek/mt76/mt7996/main.c
drivers/net/wwan/t7xx/Makefile
drivers/nvme/host/core.c
drivers/pci/doe.c
drivers/platform/x86/think-lmi.c
drivers/platform/x86/thinkpad_acpi.c
drivers/pwm/core.c
drivers/pwm/pwm-cros-ec.c
drivers/pwm/pwm-hibvt.c
drivers/pwm/pwm-iqs620a.c
drivers/pwm/pwm-meson.c
drivers/pwm/pwm-sprd.c
drivers/scsi/iscsi_tcp.c
drivers/scsi/mpi3mr/mpi3mr_fw.c
drivers/scsi/qla2xxx/qla_os.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/sh-sci.c
drivers/ufs/core/ufshcd.c
drivers/usb/cdns3/cdnsp-ep0.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/legacy/inode.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-tegra.c
drivers/usb/host/xhci.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/option.c
drivers/usb/typec/altmodes/displayport.c
drivers/vdpa/mlx5/net/mlx5_vnet.c
drivers/vdpa/vdpa_sim/vdpa_sim_net.c
drivers/vhost/scsi.c
fs/9p/xattr.c
fs/cifs/cifssmb.c
fs/cifs/fs_context.c
fs/cifs/fs_context.h
fs/cifs/misc.c
fs/dax.c
fs/ksmbd/connection.c
fs/ksmbd/ksmbd_work.h
fs/ksmbd/server.c
fs/ksmbd/smb2pdu.c
fs/ksmbd/smb2pdu.h
fs/ksmbd/smb_common.c
fs/ksmbd/smb_common.h
fs/ksmbd/unicode.c
fs/namespace.c
fs/nfs/Kconfig
fs/nfsd/blocklayout.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4xdr.c
fs/nilfs2/btree.c
fs/nilfs2/direct.c
fs/nilfs2/segment.c
fs/nilfs2/super.c
fs/nilfs2/the_nilfs.c
include/acpi/video.h
include/asm-generic/atomic.h
include/asm-generic/cmpxchg-local.h
include/asm-generic/cmpxchg.h
include/asm-generic/io.h
include/linux/ftrace.h
include/linux/kvm_host.h
include/linux/kvm_irqfd.h
include/linux/mm_types.h
include/linux/pci-doe.h
include/linux/phylink.h
include/net/raw.h
include/trace/stages/stage5_get_offsets.h
include/uapi/linux/virtio_blk.h
include/ufs/ufshcd.h
io_uring/io_uring.c
io_uring/kbuf.c
kernel/dma/swiotlb.c
kernel/events/core.c
kernel/fork.c
kernel/rcu/tree.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace_events_synth.c
kernel/trace/trace_osnoise.c
lib/Kconfig.debug
lib/maple_tree.c
mm/hugetlb.c
mm/kfence/core.c
mm/memory.c
mm/mmap.c
mm/swapfile.c
mm/vmalloc.c
net/9p/trans_xen.c
net/can/isotp.c
net/can/j1939/transport.c
net/core/netpoll.c
net/ethtool/linkmodes.c
net/ipv4/icmp.c
net/ipv4/ping.c
net/ipv4/raw.c
net/ipv4/raw_diag.c
net/ipv6/ip6_output.c
net/ipv6/raw.c
net/l2tp/l2tp_ip.c
net/l2tp/l2tp_ip6.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/util.c
net/netlink/af_netlink.c
net/qrtr/af_qrtr.c
net/qrtr/ns.c
net/sctp/socket.c
net/sunrpc/svcauth_unix.c
net/vmw_vsock/virtio_transport_common.c
net/vmw_vsock/vmci_transport.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/soc/amd/yc/acp6x-mach.c
sound/soc/codecs/da7213.c
sound/soc/codecs/hdac_hdmi.c
sound/soc/codecs/lpass-rx-macro.c
sound/soc/codecs/lpass-tx-macro.c
sound/soc/codecs/lpass-wsa-macro.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/sof_sdw.c
sound/soc/intel/common/soc-acpi-intel-adl-match.c
sound/soc/soc-pcm.c
sound/soc/sof/ipc4-topology.c
sound/soc/sof/ipc4.c
tools/testing/radix-tree/maple.c
tools/testing/selftests/mount_setattr/mount_setattr_test.c
tools/testing/selftests/net/rps_default_mask.sh
tools/virtio/virtio-trace/README
virt/kvm/eventfd.c
virt/kvm/kvm_main.c

index e2af78f..e424863 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -265,7 +265,9 @@ Krzysztof Kozlowski <krzk@kernel.org> <k.kozlowski@samsung.com>
 Krzysztof Kozlowski <krzk@kernel.org> <krzysztof.kozlowski@canonical.com>
 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 Kuogee Hsieh <quic_khsieh@quicinc.com> <khsieh@codeaurora.org>
+Leonard Crestez <leonard.crestez@nxp.com> Leonard Crestez <cdleonard@gmail.com>
 Leonardo Bras <leobras.c@gmail.com> <leonardo@linux.ibm.com>
+Leonard Göhrs <l.goehrs@pengutronix.de>
 Leonid I Ananiev <leonid.i.ananiev@intel.com>
 Leon Romanovsky <leon@kernel.org> <leon@leon.nu>
 Leon Romanovsky <leon@kernel.org> <leonro@mellanox.com>
index 1989bd6..54e4f41 100644 (file)
@@ -92,7 +92,7 @@ properties:
           - description: Error interrupt
           - description: Receive buffer full interrupt
           - description: Transmit buffer empty interrupt
-          - description: Transmit End interrupt
+          - description: Break interrupt
       - items:
           - description: Error interrupt
           - description: Receive buffer full interrupt
@@ -107,7 +107,7 @@ properties:
           - const: eri
           - const: rxi
           - const: txi
-          - const: tei
+          - const: bri
       - items:
           - const: eri
           - const: rxi
index 64d127b..a3c26d5 100644 (file)
@@ -39,13 +39,12 @@ With CONFIG_ZSMALLOC_STAT, we could see zsmalloc internal information via
 
  # cat /sys/kernel/debug/zsmalloc/zram0/classes
 
- class  size almost_full almost_empty obj_allocated   obj_used pages_used pages_per_zspage
+ class  size       10%       20%       30%       40%       50%       60%       70%       80%       90%       99%      100% obj_allocated   obj_used pages_used pages_per_zspage freeable
     ...
     ...
-     9   176           0            1           186        129          8                4
-    10   192           1            0          2880       2872        135                3
-    11   208           0            1           819        795         42                2
-    12   224           0            1           219        159         12                4
+    30   512         0        12         4         1         0         1         0         0         1         0       414          3464       3346        433                1       14
+    31   528         2         7         2         2         1         0         1         0         0         2       117          4154       3793        536                4       44
+    32   544         6         3         4         1         2         1         0         0         0         1       260          4170       3965        556                2       26
     ...
     ...
 
@@ -54,10 +53,28 @@ class
        index
 size
        object size zspage stores
-almost_empty
-       the number of ZS_ALMOST_EMPTY zspages(see below)
-almost_full
-       the number of ZS_ALMOST_FULL zspages(see below)
+10%
+       the number of zspages with usage ratio less than 10% (see below)
+20%
+       the number of zspages with usage ratio between 10% and 20%
+30%
+       the number of zspages with usage ratio between 20% and 30%
+40%
+       the number of zspages with usage ratio between 30% and 40%
+50%
+       the number of zspages with usage ratio between 40% and 50%
+60%
+       the number of zspages with usage ratio between 50% and 60%
+70%
+       the number of zspages with usage ratio between 60% and 70%
+80%
+       the number of zspages with usage ratio between 70% and 80%
+90%
+       the number of zspages with usage ratio between 80% and 90%
+99%
+       the number of zspages with usage ratio between 90% and 99%
+100%
+       the number of zspages with usage ratio 100%
 obj_allocated
        the number of objects allocated
 obj_used
@@ -66,19 +83,14 @@ pages_used
        the number of pages allocated for the class
 pages_per_zspage
        the number of 0-order pages to make a zspage
+freeable
+       the approximate number of pages class compaction can free
 
-We assign a zspage to ZS_ALMOST_EMPTY fullness group when n <= N / f, where
-
-* n = number of allocated objects
-* N = total number of objects zspage can store
-* f = fullness_threshold_frac(ie, 4 at the moment)
-
-Similarly, we assign zspage to:
-
-* ZS_ALMOST_FULL  when n > N / f
-* ZS_EMPTY        when n == 0
-* ZS_FULL         when n == N
-
+Each zspage maintains inuse counter which keeps track of the number of
+objects stored in the zspage.  The inuse counter determines the zspage's
+"fullness group" which is calculated as the ratio of the "inuse" objects to
+the total number of objects the zspage can hold (objs_per_zspage). The
+closer the inuse counter is to objs_per_zspage, the better.
 
 Internals
 =========
@@ -94,10 +106,10 @@ of objects that each zspage can store.
 
 For instance, consider the following size classes:::
 
-  class  size almost_full almost_empty obj_allocated   obj_used pages_used pages_per_zspage freeable
+  class  size       10%   ....    100% obj_allocated   obj_used pages_used pages_per_zspage freeable
   ...
-     94  1536           0            0             0          0          0                3        0
-    100  1632           0            0             0          0          0                2        0
+     94  1536        0    ....       0             0          0          0                3        0
+    100  1632        0    ....       0             0          0          0                2        0
   ...
 
 
@@ -134,10 +146,11 @@ reduces memory wastage.
 
 Let's take a closer look at the bottom of `/sys/kernel/debug/zsmalloc/zramX/classes`:::
 
-  class  size almost_full almost_empty obj_allocated   obj_used pages_used pages_per_zspage freeable
+  class  size       10%   ....    100% obj_allocated   obj_used pages_used pages_per_zspage freeable
+
   ...
-    202  3264           0            0             0          0          0                4        0
-    254  4096           0            0             0          0          0                1        0
+    202  3264         0   ..         0             0          0          0                4        0
+    254  4096         0   ..         0             0          0          0                1        0
   ...
 
 Size class #202 stores objects of size 3264 bytes and has a maximum of 4 pages
@@ -151,40 +164,42 @@ efficient storage of large objects.
 
 For zspage chain size of 8, huge class watermark becomes 3632 bytes:::
 
-  class  size almost_full almost_empty obj_allocated   obj_used pages_used pages_per_zspage freeable
+  class  size       10%   ....    100% obj_allocated   obj_used pages_used pages_per_zspage freeable
+
   ...
-    202  3264           0            0             0          0          0                4        0
-    211  3408           0            0             0          0          0                5        0
-    217  3504           0            0             0          0          0                6        0
-    222  3584           0            0             0          0          0                7        0
-    225  3632           0            0             0          0          0                8        0
-    254  4096           0            0             0          0          0                1        0
+    202  3264         0   ..         0             0          0          0                4        0
+    211  3408         0   ..         0             0          0          0                5        0
+    217  3504         0   ..         0             0          0          0                6        0
+    222  3584         0   ..         0             0          0          0                7        0
+    225  3632         0   ..         0             0          0          0                8        0
+    254  4096         0   ..         0             0          0          0                1        0
   ...
 
 For zspage chain size of 16, huge class watermark becomes 3840 bytes:::
 
-  class  size almost_full almost_empty obj_allocated   obj_used pages_used pages_per_zspage freeable
+  class  size       10%   ....    100% obj_allocated   obj_used pages_used pages_per_zspage freeable
+
   ...
-    202  3264           0            0             0          0          0                4        0
-    206  3328           0            0             0          0          0               13        0
-    207  3344           0            0             0          0          0                9        0
-    208  3360           0            0             0          0          0               14        0
-    211  3408           0            0             0          0          0                5        0
-    212  3424           0            0             0          0          0               16        0
-    214  3456           0            0             0          0          0               11        0
-    217  3504           0            0             0          0          0                6        0
-    219  3536           0            0             0          0          0               13        0
-    222  3584           0            0             0          0          0                7        0
-    223  3600           0            0             0          0          0               15        0
-    225  3632           0            0             0          0          0                8        0
-    228  3680           0            0             0          0          0                9        0
-    230  3712           0            0             0          0          0               10        0
-    232  3744           0            0             0          0          0               11        0
-    234  3776           0            0             0          0          0               12        0
-    235  3792           0            0             0          0          0               13        0
-    236  3808           0            0             0          0          0               14        0
-    238  3840           0            0             0          0          0               15        0
-    254  4096           0            0             0          0          0                1        0
+    202  3264         0   ..         0             0          0          0                4        0
+    206  3328         0   ..         0             0          0          0               13        0
+    207  3344         0   ..         0             0          0          0                9        0
+    208  3360         0   ..         0             0          0          0               14        0
+    211  3408         0   ..         0             0          0          0                5        0
+    212  3424         0   ..         0             0          0          0               16        0
+    214  3456         0   ..         0             0          0          0               11        0
+    217  3504         0   ..         0             0          0          0                6        0
+    219  3536         0   ..         0             0          0          0               13        0
+    222  3584         0   ..         0             0          0          0                7        0
+    223  3600         0   ..         0             0          0          0               15        0
+    225  3632         0   ..         0             0          0          0                8        0
+    228  3680         0   ..         0             0          0          0                9        0
+    230  3712         0   ..         0             0          0          0               10        0
+    232  3744         0   ..         0             0          0          0               11        0
+    234  3776         0   ..         0             0          0          0               12        0
+    235  3792         0   ..         0             0          0          0               13        0
+    236  3808         0   ..         0             0          0          0               14        0
+    238  3840         0   ..         0             0          0          0               15        0
+    254  4096         0   ..         0             0          0          0                1        0
   ...
 
 Overall the combined zspage chain size effect on zsmalloc pool configuration:::
@@ -214,9 +229,10 @@ zram as a build artifacts storage (Linux kernel compilation).
 
   zsmalloc classes stats:::
 
-    class  size almost_full almost_empty obj_allocated   obj_used pages_used pages_per_zspage freeable
+    class  size       10%   ....    100% obj_allocated   obj_used pages_used pages_per_zspage freeable
+
     ...
-    Total                13           51        413836     412973     159955                         3
+    Total              13   ..        51        413836     412973     159955                         3
 
   zram mm_stat:::
 
@@ -227,9 +243,10 @@ zram as a build artifacts storage (Linux kernel compilation).
 
   zsmalloc classes stats:::
 
-    class  size almost_full almost_empty obj_allocated   obj_used pages_used pages_per_zspage freeable
+    class  size       10%   ....    100% obj_allocated   obj_used pages_used pages_per_zspage freeable
+
     ...
-    Total                18           87        414852     412978     156666                         0
+    Total              18   ..        87        414852     412978     156666                         0
 
   zram mm_stat:::
 
index 62de076..a5c803f 100644 (file)
@@ -8296,11 +8296,11 @@ ENOSYS for the others.
 8.35 KVM_CAP_PMU_CAPABILITY
 ---------------------------
 
-:Capability KVM_CAP_PMU_CAPABILITY
+:Capability: KVM_CAP_PMU_CAPABILITY
 :Architectures: x86
 :Type: vm
 :Parameters: arg[0] is bitmask of PMU virtualization capabilities.
-:Returns 0 on success, -EINVAL when arg[0] contains invalid bits
+:Returns: 0 on success, -EINVAL when arg[0] contains invalid bits
 
 This capability alters PMU virtualization in KVM.
 
index 90abe83..0e64787 100644 (file)
@@ -224,13 +224,13 @@ S:        Orphan / Obsolete
 F:     drivers/net/ethernet/8390/
 
 9P FILE SYSTEM
-M:     Eric Van Hensbergen <ericvh@gmail.com>
+M:     Eric Van Hensbergen <ericvh@kernel.org>
 M:     Latchesar Ionkov <lucho@ionkov.net>
 M:     Dominique Martinet <asmadeus@codewreck.org>
 R:     Christian Schoenebeck <linux_oss@crudebyte.com>
-L:     v9fs-developer@lists.sourceforge.net
+L:     v9fs@lists.linux.dev
 S:     Maintained
-W:     http://swik.net/v9fs
+W:     http://github.com/v9fs
 Q:     http://patchwork.kernel.org/project/v9fs-devel/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs.git
 T:     git git://github.com/martinetd/linux.git
@@ -4461,14 +4461,14 @@ F:      Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
 F:     drivers/net/ieee802154/ca8210.c
 
 CANAAN/KENDRYTE K210 SOC FPIOA DRIVER
-M:     Damien Le Moal <damien.lemoal@wdc.com>
+M:     Damien Le Moal <dlemoal@kernel.org>
 L:     linux-riscv@lists.infradead.org
 L:     linux-gpio@vger.kernel.org (pinctrl driver)
 F:     Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
 F:     drivers/pinctrl/pinctrl-k210.c
 
 CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER
-M:     Damien Le Moal <damien.lemoal@wdc.com>
+M:     Damien Le Moal <dlemoal@kernel.org>
 L:     linux-kernel@vger.kernel.org
 L:     linux-riscv@lists.infradead.org
 S:     Maintained
@@ -4476,7 +4476,7 @@ F:        Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
 F:     drivers/reset/reset-k210.c
 
 CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
-M:     Damien Le Moal <damien.lemoal@wdc.com>
+M:     Damien Le Moal <dlemoal@kernel.org>
 L:     linux-riscv@lists.infradead.org
 S:     Maintained
 F:      Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml
@@ -11758,7 +11758,7 @@ T:      git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 F:     drivers/ata/sata_promise.*
 
 LIBATA SUBSYSTEM (Serial and Parallel ATA drivers)
-M:     Damien Le Moal <damien.lemoal@opensource.wdc.com>
+M:     Damien Le Moal <dlemoal@kernel.org>
 L:     linux-ide@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata.git
@@ -23115,7 +23115,7 @@ S:      Maintained
 F:     arch/x86/kernel/cpu/zhaoxin.c
 
 ZONEFS FILESYSTEM
-M:     Damien Le Moal <damien.lemoal@opensource.wdc.com>
+M:     Damien Le Moal <dlemoal@kernel.org>
 M:     Naohiro Aota <naohiro.aota@wdc.com>
 R:     Johannes Thumshirn <jth@kernel.org>
 L:     linux-fsdevel@vger.kernel.org
index ef4e96b..5aeea3d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 6
 PATCHLEVEL = 3
 SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc6
 NAME = Hurr durr I'ma ninja sloth
 
 # *DOCUMENTATION*
index 5edec2f..deff21b 100644 (file)
@@ -314,36 +314,32 @@ int do_compat_alignment_fixup(unsigned long addr, struct pt_regs *regs)
        int (*handler)(unsigned long addr, u32 instr, struct pt_regs *regs);
        unsigned int type;
        u32 instr = 0;
-       u16 tinstr = 0;
        int isize = 4;
        int thumb2_32b = 0;
-       int fault;
 
        instrptr = instruction_pointer(regs);
 
        if (compat_thumb_mode(regs)) {
                __le16 __user *ptr = (__le16 __user *)(instrptr & ~1);
+               u16 tinstr, tinst2;
 
-               fault = alignment_get_thumb(regs, ptr, &tinstr);
-               if (!fault) {
-                       if (IS_T32(tinstr)) {
-                               /* Thumb-2 32-bit */
-                               u16 tinst2;
-                               fault = alignment_get_thumb(regs, ptr + 1, &tinst2);
-                               instr = ((u32)tinstr << 16) | tinst2;
-                               thumb2_32b = 1;
-                       } else {
-                               isize = 2;
-                               instr = thumb2arm(tinstr);
-                       }
+               if (alignment_get_thumb(regs, ptr, &tinstr))
+                       return 1;
+
+               if (IS_T32(tinstr)) { /* Thumb-2 32-bit */
+                       if (alignment_get_thumb(regs, ptr + 1, &tinst2))
+                               return 1;
+                       instr = ((u32)tinstr << 16) | tinst2;
+                       thumb2_32b = 1;
+               } else {
+                       isize = 2;
+                       instr = thumb2arm(tinstr);
                }
        } else {
-               fault = alignment_get_arm(regs, (__le32 __user *)instrptr, &instr);
+               if (alignment_get_arm(regs, (__le32 __user *)instrptr, &instr))
+                       return 1;
        }
 
-       if (fault)
-               return 1;
-
        switch (CODING_BITS(instr)) {
        case 0x00000000:        /* 3.13.4 load/store instruction extensions */
                if (LDSTHD_I_BIT(instr))
index 3bd732e..4b2e16e 100644 (file)
@@ -220,6 +220,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_VCPU_ATTRIBUTES:
        case KVM_CAP_PTP_KVM:
        case KVM_CAP_ARM_SYSTEM_SUSPEND:
+       case KVM_CAP_IRQFD_RESAMPLE:
                r = 1;
                break;
        case KVM_CAP_SET_GUEST_DEBUG2:
@@ -1889,9 +1890,33 @@ static int __init do_pkvm_init(u32 hyp_va_bits)
        return ret;
 }
 
+static u64 get_hyp_id_aa64pfr0_el1(void)
+{
+       /*
+        * Track whether the system isn't affected by spectre/meltdown in the
+        * hypervisor's view of id_aa64pfr0_el1, used for protected VMs.
+        * Although this is per-CPU, we make it global for simplicity, e.g., not
+        * to have to worry about vcpu migration.
+        *
+        * Unlike for non-protected VMs, userspace cannot override this for
+        * protected VMs.
+        */
+       u64 val = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
+
+       val &= ~(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2) |
+                ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3));
+
+       val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2),
+                         arm64_get_spectre_v2_state() == SPECTRE_UNAFFECTED);
+       val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3),
+                         arm64_get_meltdown_state() == SPECTRE_UNAFFECTED);
+
+       return val;
+}
+
 static void kvm_hyp_init_symbols(void)
 {
-       kvm_nvhe_sym(id_aa64pfr0_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
+       kvm_nvhe_sym(id_aa64pfr0_el1_sys_val) = get_hyp_id_aa64pfr0_el1();
        kvm_nvhe_sym(id_aa64pfr1_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1);
        kvm_nvhe_sym(id_aa64isar0_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64ISAR0_EL1);
        kvm_nvhe_sym(id_aa64isar1_el1_sys_val) = read_sanitised_ftr_reg(SYS_ID_AA64ISAR1_EL1);
index 07edfc7..37440e1 100644 (file)
  * Allow for protected VMs:
  * - Floating-point and Advanced SIMD
  * - Data Independent Timing
+ * - Spectre/Meltdown Mitigation
  */
 #define PVM_ID_AA64PFR0_ALLOW (\
        ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_FP) | \
        ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_AdvSIMD) | \
-       ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_DIT) \
+       ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_DIT) | \
+       ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2) | \
+       ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3) \
        )
 
 /*
index 08d2b00..edd969a 100644 (file)
@@ -85,19 +85,12 @@ static u64 get_restricted_features_unsigned(u64 sys_reg_val,
 
 static u64 get_pvm_id_aa64pfr0(const struct kvm_vcpu *vcpu)
 {
-       const struct kvm *kvm = (const struct kvm *)kern_hyp_va(vcpu->kvm);
        u64 set_mask = 0;
        u64 allow_mask = PVM_ID_AA64PFR0_ALLOW;
 
        set_mask |= get_restricted_features_unsigned(id_aa64pfr0_el1_sys_val,
                PVM_ID_AA64PFR0_RESTRICT_UNSIGNED);
 
-       /* Spectre and Meltdown mitigation in KVM */
-       set_mask |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV2),
-                              (u64)kvm->arch.pfr0_csv2);
-       set_mask |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_CSV3),
-                              (u64)kvm->arch.pfr0_csv3);
-
        return (id_aa64pfr0_el1_sys_val & allow_mask) | set_mask;
 }
 
index c243b10..5eca0cd 100644 (file)
@@ -558,6 +558,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
                for_each_set_bit(i, &mask, 32)
                        kvm_pmu_set_pmc_value(kvm_vcpu_idx_to_pmc(vcpu, i), 0, true);
        }
+       kvm_vcpu_pmu_restore_guest(vcpu);
 }
 
 static bool kvm_pmu_counter_is_enabled(struct kvm_pmc *pmc)
index 1b2c161..3468891 100644 (file)
@@ -794,7 +794,6 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
                if (!kvm_supports_32bit_el0())
                        val |= ARMV8_PMU_PMCR_LC;
                kvm_pmu_handle_pmcr(vcpu, val);
-               kvm_vcpu_pmu_restore_guest(vcpu);
        } else {
                /* PMCR.P & PMCR.C are RAZ */
                val = __vcpu_sys_reg(vcpu, PMCR_EL0)
index 4c5405f..d23e25e 100644 (file)
@@ -576,6 +576,12 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                break;
 #endif
 
+#ifdef CONFIG_HAVE_KVM_IRQFD
+       case KVM_CAP_IRQFD_RESAMPLE:
+               r = !xive_enabled();
+               break;
+#endif
+
        case KVM_CAP_PPC_ALLOC_HTAB:
                r = hv_enabled;
                break;
index 0ee02da..2cda8d9 100644 (file)
@@ -271,10 +271,18 @@ static int handle_prog(struct kvm_vcpu *vcpu)
  * handle_external_interrupt - used for external interruption interceptions
  * @vcpu: virtual cpu
  *
- * This interception only occurs if the CPUSTAT_EXT_INT bit was set, or if
- * the new PSW does not have external interrupts disabled. In the first case,
- * we've got to deliver the interrupt manually, and in the second case, we
- * drop to userspace to handle the situation there.
+ * This interception occurs if:
+ * - the CPUSTAT_EXT_INT bit was already set when the external interrupt
+ *   occurred. In this case, the interrupt needs to be injected manually to
+ *   preserve interrupt priority.
+ * - the external new PSW has external interrupts enabled, which will cause an
+ *   interruption loop. We drop to userspace in this case.
+ *
+ * The latter case can be detected by inspecting the external mask bit in the
+ * external new psw.
+ *
+ * Under PV, only the latter case can occur, since interrupt priorities are
+ * handled in the ultravisor.
  */
 static int handle_external_interrupt(struct kvm_vcpu *vcpu)
 {
@@ -285,10 +293,18 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu)
 
        vcpu->stat.exit_external_interrupt++;
 
-       rc = read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &newpsw, sizeof(psw_t));
-       if (rc)
-               return rc;
-       /* We can not handle clock comparator or timer interrupt with bad PSW */
+       if (kvm_s390_pv_cpu_is_protected(vcpu)) {
+               newpsw = vcpu->arch.sie_block->gpsw;
+       } else {
+               rc = read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &newpsw, sizeof(psw_t));
+               if (rc)
+                       return rc;
+       }
+
+       /*
+        * Clock comparator or timer interrupt with external interrupt enabled
+        * will cause interrupt loop. Drop to userspace.
+        */
        if ((eic == EXT_IRQ_CLK_COMP || eic == EXT_IRQ_CPU_TIMER) &&
            (newpsw.mask & PSW_MASK_EXT))
                return -EOPNOTSUPP;
index 39b3656..1eeb9ae 100644 (file)
@@ -573,6 +573,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_S390_VCPU_RESETS:
        case KVM_CAP_SET_GUEST_DEBUG:
        case KVM_CAP_S390_DIAG318:
+       case KVM_CAP_IRQFD_RESAMPLE:
                r = 1;
                break;
        case KVM_CAP_SET_GUEST_DEBUG2:
index b70559b..2106a2b 100644 (file)
@@ -3,9 +3,14 @@ core-y += arch/x86/crypto/
 
 #
 # Disable SSE and other FP/SIMD instructions to match normal x86
+# This is required to work around issues in older LLVM versions, but breaks
+# GCC versions < 11. See:
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99652
 #
+ifeq ($(CONFIG_CC_IS_CLANG),y)
 KBUILD_CFLAGS += -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx
 KBUILD_RUSTFLAGS += -Ctarget-feature=-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2
+endif
 
 ifeq ($(CONFIG_X86_32),y)
 START := 0x8048000
index cbaf174..b3af2d4 100644 (file)
 
 #define INTEL_FAM6_LUNARLAKE_M         0xBD
 
+#define INTEL_FAM6_ARROWLAKE           0xC6
+
 /* "Small Core" Processors (Atom/E-Core) */
 
 #define INTEL_FAM6_ATOM_BONNELL                0x1C /* Diamondville, Pineview */
index 1c38174..0dac4ab 100644 (file)
@@ -146,7 +146,11 @@ static int __init acpi_parse_madt(struct acpi_table_header *table)
 
                pr_debug("Local APIC address 0x%08x\n", madt->address);
        }
-       if (madt->header.revision >= 5)
+
+       /* ACPI 6.3 and newer support the online capable bit. */
+       if (acpi_gbl_FADT.header.revision > 6 ||
+           (acpi_gbl_FADT.header.revision == 6 &&
+            acpi_gbl_FADT.minor_revision >= 3))
                acpi_support_online_capable = true;
 
        default_acpi_madt_oem_check(madt->header.oem_id,
@@ -193,7 +197,8 @@ static bool __init acpi_is_processor_usable(u32 lapic_flags)
        if (lapic_flags & ACPI_MADT_ENABLED)
                return true;
 
-       if (acpi_support_online_capable && (lapic_flags & ACPI_MADT_ONLINE_CAPABLE))
+       if (!acpi_support_online_capable ||
+           (lapic_flags & ACPI_MADT_ONLINE_CAPABLE))
                return true;
 
        return false;
index f36dc2f..f119736 100644 (file)
@@ -358,12 +358,16 @@ static void __init ms_hyperv_init_platform(void)
         * To mirror what Windows does we should extract CPU management
         * features and use the ReservedIdentityBit to detect if Linux is the
         * root partition. But that requires negotiating CPU management
-        * interface (a process to be finalized).
+        * interface (a process to be finalized). For now, use the privilege
+        * flag as the indicator for running as root.
         *
-        * For now, use the privilege flag as the indicator for running as
-        * root.
+        * Hyper-V should never specify running as root and as a Confidential
+        * VM. But to protect against a compromised/malicious Hyper-V trying
+        * to exploit root behavior to expose Confidential VM memory, ignore
+        * the root partition setting if also a Confidential VM.
         */
-       if (cpuid_ebx(HYPERV_CPUID_FEATURES) & HV_CPU_MANAGEMENT) {
+       if ((ms_hyperv.priv_high & HV_CPU_MANAGEMENT) &&
+           !(ms_hyperv.priv_high & HV_ISOLATION)) {
                hv_root_partition = true;
                pr_info("Hyper-V: running as root partition\n");
        }
index 042dee5..995eb50 100644 (file)
@@ -368,9 +368,39 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
                mask_after = e->fields.mask;
                if (mask_before != mask_after)
                        kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after);
-               if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG
-                   && ioapic->irr & (1 << index))
-                       ioapic_service(ioapic, index, false);
+               if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG &&
+                   ioapic->irr & (1 << index) && !e->fields.mask && !e->fields.remote_irr) {
+                       /*
+                        * Pending status in irr may be outdated: the IRQ line may have
+                        * already been deasserted by a device while the IRQ was masked.
+                        * This occurs, for instance, if the interrupt is handled in a
+                        * Linux guest as a oneshot interrupt (IRQF_ONESHOT). In this
+                        * case the guest acknowledges the interrupt to the device in
+                        * its threaded irq handler, i.e. after the EOI but before
+                        * unmasking, so at the time of unmasking the IRQ line is
+                        * already down but our pending irr bit is still set. In such
+                        * cases, injecting this pending interrupt to the guest is
+                        * buggy: the guest will receive an extra unwanted interrupt.
+                        *
+                        * So we need to check here if the IRQ is actually still pending.
+                        * As we are generally not able to probe the IRQ line status
+                        * directly, we do it through irqfd resampler. Namely, we clear
+                        * the pending status and notify the resampler that this interrupt
+                        * is done, without actually injecting it into the guest. If the
+                        * IRQ line is actually already deasserted, we are done. If it is
+                        * still asserted, a new interrupt will be shortly triggered
+                        * through irqfd and injected into the guest.
+                        *
+                        * If, however, it's not possible to resample (no irqfd resampler
+                        * registered for this irq), then unconditionally inject this
+                        * pending interrupt into the guest, so the guest will not miss
+                        * an interrupt, although may get an extra unwanted interrupt.
+                        */
+                       if (kvm_notify_irqfd_resampler(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index))
+                               ioapic->irr &= ~(1 << index);
+                       else
+                               ioapic_service(ioapic, index, false);
+               }
                if (e->fields.delivery_mode == APIC_DM_FIXED) {
                        struct kvm_lapic_irq irq;
 
index 287e98e..6272dab 100644 (file)
@@ -12,6 +12,11 @@ int hv_remote_flush_tlb_with_range(struct kvm *kvm,
 int hv_remote_flush_tlb(struct kvm *kvm);
 void hv_track_root_tdp(struct kvm_vcpu *vcpu, hpa_t root_tdp);
 #else /* !CONFIG_HYPERV */
+static inline int hv_remote_flush_tlb(struct kvm *kvm)
+{
+       return -EOPNOTSUPP;
+}
+
 static inline void hv_track_root_tdp(struct kvm_vcpu *vcpu, hpa_t root_tdp)
 {
 }
index 252e7f3..f25bc3c 100644 (file)
@@ -3729,7 +3729,7 @@ static void svm_enable_nmi_window(struct kvm_vcpu *vcpu)
        svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF);
 }
 
-static void svm_flush_tlb_current(struct kvm_vcpu *vcpu)
+static void svm_flush_tlb_asid(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
@@ -3753,6 +3753,37 @@ static void svm_flush_tlb_current(struct kvm_vcpu *vcpu)
                svm->current_vmcb->asid_generation--;
 }
 
+static void svm_flush_tlb_current(struct kvm_vcpu *vcpu)
+{
+       hpa_t root_tdp = vcpu->arch.mmu->root.hpa;
+
+       /*
+        * When running on Hyper-V with EnlightenedNptTlb enabled, explicitly
+        * flush the NPT mappings via hypercall as flushing the ASID only
+        * affects virtual to physical mappings, it does not invalidate guest
+        * physical to host physical mappings.
+        */
+       if (svm_hv_is_enlightened_tlb_enabled(vcpu) && VALID_PAGE(root_tdp))
+               hyperv_flush_guest_mapping(root_tdp);
+
+       svm_flush_tlb_asid(vcpu);
+}
+
+static void svm_flush_tlb_all(struct kvm_vcpu *vcpu)
+{
+       /*
+        * When running on Hyper-V with EnlightenedNptTlb enabled, remote TLB
+        * flushes should be routed to hv_remote_flush_tlb() without requesting
+        * a "regular" remote flush.  Reaching this point means either there's
+        * a KVM bug or a prior hv_remote_flush_tlb() call failed, both of
+        * which might be fatal to the guest.  Yell, but try to recover.
+        */
+       if (WARN_ON_ONCE(svm_hv_is_enlightened_tlb_enabled(vcpu)))
+               hv_remote_flush_tlb(vcpu->kvm);
+
+       svm_flush_tlb_asid(vcpu);
+}
+
 static void svm_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t gva)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -4745,10 +4776,10 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
        .set_rflags = svm_set_rflags,
        .get_if_flag = svm_get_if_flag,
 
-       .flush_tlb_all = svm_flush_tlb_current,
+       .flush_tlb_all = svm_flush_tlb_all,
        .flush_tlb_current = svm_flush_tlb_current,
        .flush_tlb_gva = svm_flush_tlb_gva,
-       .flush_tlb_guest = svm_flush_tlb_current,
+       .flush_tlb_guest = svm_flush_tlb_asid,
 
        .vcpu_pre_run = svm_vcpu_pre_run,
        .vcpu_run = svm_vcpu_run,
index cff838f..786d46d 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef __ARCH_X86_KVM_SVM_ONHYPERV_H__
 #define __ARCH_X86_KVM_SVM_ONHYPERV_H__
 
+#include <asm/mshyperv.h>
+
 #if IS_ENABLED(CONFIG_HYPERV)
 
 #include "kvm_onhyperv.h"
@@ -15,6 +17,14 @@ static struct kvm_x86_ops svm_x86_ops;
 
 int svm_hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu);
 
+static inline bool svm_hv_is_enlightened_tlb_enabled(struct kvm_vcpu *vcpu)
+{
+       struct hv_vmcb_enlightenments *hve = &to_svm(vcpu)->vmcb->control.hv_enlightenments;
+
+       return ms_hyperv.nested_features & HV_X64_NESTED_ENLIGHTENED_TLB &&
+              !!hve->hv_enlightenments_control.enlightened_npt_tlb;
+}
+
 static inline void svm_hv_init_vmcb(struct vmcb *vmcb)
 {
        struct hv_vmcb_enlightenments *hve = &vmcb->control.hv_enlightenments;
@@ -80,6 +90,11 @@ static inline void svm_hv_update_vp_id(struct vmcb *vmcb, struct kvm_vcpu *vcpu)
 }
 #else
 
+static inline bool svm_hv_is_enlightened_tlb_enabled(struct kvm_vcpu *vcpu)
+{
+       return false;
+}
+
 static inline void svm_hv_init_vmcb(struct vmcb *vmcb)
 {
 }
index 1bc2b80..7684876 100644 (file)
@@ -3868,7 +3868,12 @@ static void nested_vmx_inject_exception_vmexit(struct kvm_vcpu *vcpu)
                exit_qual = 0;
        }
 
-       if (ex->has_error_code) {
+       /*
+        * Unlike AMD's Paged Real Mode, which reports an error code on #PF
+        * VM-Exits even if the CPU is in Real Mode, Intel VMX never sets the
+        * "has error code" flags on VM-Exit if the CPU is in Real Mode.
+        */
+       if (ex->has_error_code && is_protmode(vcpu)) {
                /*
                 * Intel CPUs do not generate error codes with bits 31:16 set,
                 * and more importantly VMX disallows setting bits 31:16 in the
index 7713420..3d852ce 100644 (file)
@@ -4432,6 +4432,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_VAPIC:
        case KVM_CAP_ENABLE_CAP:
        case KVM_CAP_VM_DISABLE_NX_HUGE_PAGES:
+       case KVM_CAP_IRQFD_RESAMPLE:
                r = 1;
                break;
        case KVM_CAP_EXIT_HYPERCALL:
@@ -8903,6 +8904,8 @@ restart:
        }
 
        if (ctxt->have_exception) {
+               WARN_ON_ONCE(vcpu->mmio_needed && !vcpu->mmio_is_write);
+               vcpu->mmio_needed = false;
                r = 1;
                inject_emulated_exception(vcpu);
        } else if (vcpu->arch.pio.count) {
@@ -9906,13 +9909,20 @@ int kvm_check_nested_events(struct kvm_vcpu *vcpu)
 
 static void kvm_inject_exception(struct kvm_vcpu *vcpu)
 {
+       /*
+        * Suppress the error code if the vCPU is in Real Mode, as Real Mode
+        * exceptions don't report error codes.  The presence of an error code
+        * is carried with the exception and only stripped when the exception
+        * is injected as intercepted #PF VM-Exits for AMD's Paged Real Mode do
+        * report an error code despite the CPU being in Real Mode.
+        */
+       vcpu->arch.exception.has_error_code &= is_protmode(vcpu);
+
        trace_kvm_inj_exception(vcpu->arch.exception.vector,
                                vcpu->arch.exception.has_error_code,
                                vcpu->arch.exception.error_code,
                                vcpu->arch.exception.injected);
 
-       if (vcpu->arch.exception.error_code && !is_protmode(vcpu))
-               vcpu->arch.exception.error_code = false;
        static_call(kvm_x86_inject_exception)(vcpu);
 }
 
index cf1a39a..f0ea9dc 100644 (file)
@@ -1359,8 +1359,6 @@ bool blk_rq_is_poll(struct request *rq)
                return false;
        if (rq->mq_hctx->type != HCTX_TYPE_POLL)
                return false;
-       if (WARN_ON_ONCE(!rq->bio))
-               return false;
        return true;
 }
 EXPORT_SYMBOL_GPL(blk_rq_is_poll);
@@ -1368,7 +1366,7 @@ EXPORT_SYMBOL_GPL(blk_rq_is_poll);
 static void blk_rq_poll_completion(struct request *rq, struct completion *wait)
 {
        do {
-               bio_poll(rq->bio, NULL, 0);
+               blk_mq_poll(rq->q, blk_rq_to_qc(rq), NULL, 0);
                cond_resched();
        } while (!completion_done(wait));
 }
index 02d9cfb..7f87473 100644 (file)
@@ -368,7 +368,6 @@ int disk_scan_partitions(struct gendisk *disk, fmode_t mode)
        if (disk->open_partitions)
                return -EBUSY;
 
-       set_bit(GD_NEED_PART_SCAN, &disk->state);
        /*
         * If the device is opened exclusively by current thread already, it's
         * safe to scan partitons, otherwise, use bd_prepare_to_claim() to
@@ -381,12 +380,19 @@ int disk_scan_partitions(struct gendisk *disk, fmode_t mode)
                        return ret;
        }
 
+       set_bit(GD_NEED_PART_SCAN, &disk->state);
        bdev = blkdev_get_by_dev(disk_devt(disk), mode & ~FMODE_EXCL, NULL);
        if (IS_ERR(bdev))
                ret =  PTR_ERR(bdev);
        else
                blkdev_put(bdev, mode & ~FMODE_EXCL);
 
+       /*
+        * If blkdev_get_by_dev() failed early, GD_NEED_PART_SCAN is still set,
+        * and this will cause that re-assemble partitioned raid device will
+        * creat partition for underlying disk.
+        */
+       clear_bit(GD_NEED_PART_SCAN, &disk->state);
        if (!(mode & FMODE_EXCL))
                bd_abort_claiming(disk->part0, disk_scan_partitions);
        return ret;
index 910301f..3c6f1e1 100644 (file)
@@ -461,26 +461,22 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32
 
        job->cmd_buf_vpu_addr = bo->vpu_addr + commands_offset;
 
-       ret = drm_gem_lock_reservations((struct drm_gem_object **)job->bos, buf_count,
-                                       &acquire_ctx);
+       ret = drm_gem_lock_reservations((struct drm_gem_object **)job->bos, 1, &acquire_ctx);
        if (ret) {
                ivpu_warn(vdev, "Failed to lock reservations: %d\n", ret);
                return ret;
        }
 
-       for (i = 0; i < buf_count; i++) {
-               ret = dma_resv_reserve_fences(job->bos[i]->base.resv, 1);
-               if (ret) {
-                       ivpu_warn(vdev, "Failed to reserve fences: %d\n", ret);
-                       goto unlock_reservations;
-               }
+       ret = dma_resv_reserve_fences(bo->base.resv, 1);
+       if (ret) {
+               ivpu_warn(vdev, "Failed to reserve fences: %d\n", ret);
+               goto unlock_reservations;
        }
 
-       for (i = 0; i < buf_count; i++)
-               dma_resv_add_fence(job->bos[i]->base.resv, job->done_fence, DMA_RESV_USAGE_WRITE);
+       dma_resv_add_fence(bo->base.resv, job->done_fence, DMA_RESV_USAGE_WRITE);
 
 unlock_reservations:
-       drm_gem_unlock_reservations((struct drm_gem_object **)job->bos, buf_count, &acquire_ctx);
+       drm_gem_unlock_reservations((struct drm_gem_object **)job->bos, 1, &acquire_ctx);
 
        wmb(); /* Flush write combining buffers */
 
index 7df72fa..bde42d6 100644 (file)
@@ -140,32 +140,28 @@ int ivpu_pm_suspend_cb(struct device *dev)
 {
        struct drm_device *drm = dev_get_drvdata(dev);
        struct ivpu_device *vdev = to_ivpu_device(drm);
-       int ret;
+       unsigned long timeout;
 
        ivpu_dbg(vdev, PM, "Suspend..\n");
 
-       ret = ivpu_suspend(vdev);
-       if (ret && vdev->pm->suspend_reschedule_counter) {
-               ivpu_dbg(vdev, PM, "Failed to enter idle, rescheduling suspend, retries left %d\n",
-                        vdev->pm->suspend_reschedule_counter);
-               pm_schedule_suspend(dev, vdev->timeout.reschedule_suspend);
-               vdev->pm->suspend_reschedule_counter--;
-               return -EBUSY;
-       } else if (!vdev->pm->suspend_reschedule_counter) {
-               ivpu_warn(vdev, "Failed to enter idle, force suspend\n");
-               ivpu_pm_prepare_cold_boot(vdev);
-       } else {
-               ivpu_pm_prepare_warm_boot(vdev);
+       timeout = jiffies + msecs_to_jiffies(vdev->timeout.tdr);
+       while (!ivpu_hw_is_idle(vdev)) {
+               cond_resched();
+               if (time_after_eq(jiffies, timeout)) {
+                       ivpu_err(vdev, "Failed to enter idle on system suspend\n");
+                       return -EBUSY;
+               }
        }
 
-       vdev->pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT;
+       ivpu_suspend(vdev);
+       ivpu_pm_prepare_warm_boot(vdev);
 
        pci_save_state(to_pci_dev(dev));
        pci_set_power_state(to_pci_dev(dev), PCI_D3hot);
 
        ivpu_dbg(vdev, PM, "Suspend done.\n");
 
-       return ret;
+       return 0;
 }
 
 int ivpu_pm_resume_cb(struct device *dev)
index 97b711e..c7a6d0b 100644 (file)
@@ -1984,6 +1984,7 @@ static int instance;
 static int acpi_video_bus_add(struct acpi_device *device)
 {
        struct acpi_video_bus *video;
+       bool auto_detect;
        int error;
        acpi_status status;
 
@@ -2045,10 +2046,20 @@ static int acpi_video_bus_add(struct acpi_device *device)
        mutex_unlock(&video_list_lock);
 
        /*
-        * The userspace visible backlight_device gets registered separately
-        * from acpi_video_register_backlight().
+        * If backlight-type auto-detection is used then a native backlight may
+        * show up later and this may change the result from video to native.
+        * Therefor normally the userspace visible /sys/class/backlight device
+        * gets registered separately by the GPU driver calling
+        * acpi_video_register_backlight() when an internal panel is detected.
+        * Register the backlight now when not using auto-detection, so that
+        * when the kernel cmdline or DMI-quirks are used the backlight will
+        * get registered even if acpi_video_register_backlight() is not called.
         */
        acpi_video_run_bcl_for_osi(video);
+       if (__acpi_video_get_backlight_type(false, &auto_detect) == acpi_backlight_video &&
+           !auto_detect)
+               acpi_video_bus_register_backlight(video);
+
        acpi_video_bus_add_notify_handler(video);
 
        return 0;
index fd7cbce..e85729f 100644 (file)
@@ -277,6 +277,43 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
 
        /*
+        * Models which need acpi_video backlight control where the GPU drivers
+        * do not call acpi_video_register_backlight() because no internal panel
+        * is detected. Typically these are all-in-ones (monitors with builtin
+        * PC) where the panel connection shows up as regular DP instead of eDP.
+        */
+       {
+        .callback = video_detect_force_video,
+        /* Apple iMac14,1 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "iMac14,1"),
+               },
+       },
+       {
+        .callback = video_detect_force_video,
+        /* Apple iMac14,2 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "iMac14,2"),
+               },
+       },
+
+       /*
+        * Older models with nvidia GPU which need acpi_video backlight
+        * control and where the old nvidia binary driver series does not
+        * call acpi_video_register_backlight().
+        */
+       {
+        .callback = video_detect_force_video,
+        /* ThinkPad W530 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W530"),
+               },
+       },
+
+       /*
         * These models have a working acpi_video backlight control, and using
         * native backlight causes a regression where backlight does not work
         * when userspace is not handling brightness key events. Disable
@@ -782,7 +819,7 @@ static bool prefer_native_over_acpi_video(void)
  * Determine which type of backlight interface to use on this system,
  * First check cmdline, then dmi quirks, then do autodetect.
  */
-static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native)
+enum acpi_backlight_type __acpi_video_get_backlight_type(bool native, bool *auto_detect)
 {
        static DEFINE_MUTEX(init_mutex);
        static bool nvidia_wmi_ec_present;
@@ -807,6 +844,9 @@ static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native)
                native_available = true;
        mutex_unlock(&init_mutex);
 
+       if (auto_detect)
+               *auto_detect = false;
+
        /*
         * The below heuristics / detection steps are in order of descending
         * presedence. The commandline takes presedence over anything else.
@@ -818,6 +858,9 @@ static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native)
        if (acpi_backlight_dmi != acpi_backlight_undef)
                return acpi_backlight_dmi;
 
+       if (auto_detect)
+               *auto_detect = true;
+
        /* Special cases such as nvidia_wmi_ec and apple gmux. */
        if (nvidia_wmi_ec_present)
                return acpi_backlight_nvidia_wmi_ec;
@@ -837,15 +880,4 @@ static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native)
        /* No ACPI video/native (old hw), use vendor specific fw methods. */
        return acpi_backlight_vendor;
 }
-
-enum acpi_backlight_type acpi_video_get_backlight_type(void)
-{
-       return __acpi_video_get_backlight_type(false);
-}
-EXPORT_SYMBOL(acpi_video_get_backlight_type);
-
-bool acpi_video_backlight_use_native(void)
-{
-       return __acpi_video_get_backlight_type(true) == acpi_backlight_native;
-}
-EXPORT_SYMBOL(acpi_video_backlight_use_native);
+EXPORT_SYMBOL(__acpi_video_get_backlight_type);
index c73cc57..604c1a1 100644 (file)
@@ -246,7 +246,7 @@ static int ublk_validate_params(const struct ublk_device *ub)
        if (ub->params.types & UBLK_PARAM_TYPE_BASIC) {
                const struct ublk_param_basic *p = &ub->params.basic;
 
-               if (p->logical_bs_shift > PAGE_SHIFT)
+               if (p->logical_bs_shift > PAGE_SHIFT || p->logical_bs_shift < 9)
                        return -EINVAL;
 
                if (p->logical_bs_shift > p->physical_bs_shift)
@@ -1261,9 +1261,10 @@ static void ublk_handle_need_get_data(struct ublk_device *ub, int q_id,
        ublk_queue_cmd(ubq, req);
 }
 
-static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
+static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
+                              unsigned int issue_flags,
+                              struct ublksrv_io_cmd *ub_cmd)
 {
-       struct ublksrv_io_cmd *ub_cmd = (struct ublksrv_io_cmd *)cmd->cmd;
        struct ublk_device *ub = cmd->file->private_data;
        struct ublk_queue *ubq;
        struct ublk_io *io;
@@ -1362,6 +1363,23 @@ static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
        return -EIOCBQUEUED;
 }
 
+static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
+{
+       struct ublksrv_io_cmd *ub_src = (struct ublksrv_io_cmd *) cmd->cmd;
+       struct ublksrv_io_cmd ub_cmd;
+
+       /*
+        * Not necessary for async retry, but let's keep it simple and always
+        * copy the values to avoid any potential reuse.
+        */
+       ub_cmd.q_id = READ_ONCE(ub_src->q_id);
+       ub_cmd.tag = READ_ONCE(ub_src->tag);
+       ub_cmd.result = READ_ONCE(ub_src->result);
+       ub_cmd.addr = READ_ONCE(ub_src->addr);
+
+       return __ublk_ch_uring_cmd(cmd, issue_flags, &ub_cmd);
+}
+
 static const struct file_operations ublk_ch_fops = {
        .owner = THIS_MODULE,
        .open = ublk_ch_open,
@@ -1952,6 +1970,8 @@ static int ublk_ctrl_set_params(struct ublk_device *ub,
                /* clear all we don't support yet */
                ub->params.types &= UBLK_PARAM_TYPE_ALL;
                ret = ublk_validate_params(ub);
+               if (ret)
+                       ub->params.types = 0;
        }
        mutex_unlock(&ub->mutex);
 
index 2723eed..2b918e2 100644 (file)
@@ -96,16 +96,14 @@ struct virtblk_req {
 
                /*
                 * The zone append command has an extended in header.
-                * The status field in zone_append_in_hdr must have
-                * the same offset in virtblk_req as the non-zoned
-                * status field above.
+                * The status field in zone_append_in_hdr must always
+                * be the last byte.
                 */
                struct {
+                       __virtio64 sector;
                        u8 status;
-                       u8 reserved[7];
-                       __le64 append_sector;
-               } zone_append_in_hdr;
-       };
+               } zone_append;
+       } in_hdr;
 
        size_t in_hdr_len;
 
@@ -154,7 +152,7 @@ static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr)
                        sgs[num_out + num_in++] = vbr->sg_table.sgl;
        }
 
-       sg_init_one(&in_hdr, &vbr->status, vbr->in_hdr_len);
+       sg_init_one(&in_hdr, &vbr->in_hdr.status, vbr->in_hdr_len);
        sgs[num_out + num_in++] = &in_hdr;
 
        return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
@@ -242,11 +240,14 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
                                      struct request *req,
                                      struct virtblk_req *vbr)
 {
-       size_t in_hdr_len = sizeof(vbr->status);
+       size_t in_hdr_len = sizeof(vbr->in_hdr.status);
        bool unmap = false;
        u32 type;
        u64 sector = 0;
 
+       if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) && op_is_zone_mgmt(req_op(req)))
+               return BLK_STS_NOTSUPP;
+
        /* Set fields for all request types */
        vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req));
 
@@ -287,7 +288,7 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
        case REQ_OP_ZONE_APPEND:
                type = VIRTIO_BLK_T_ZONE_APPEND;
                sector = blk_rq_pos(req);
-               in_hdr_len = sizeof(vbr->zone_append_in_hdr);
+               in_hdr_len = sizeof(vbr->in_hdr.zone_append);
                break;
        case REQ_OP_ZONE_RESET:
                type = VIRTIO_BLK_T_ZONE_RESET;
@@ -297,7 +298,10 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
                type = VIRTIO_BLK_T_ZONE_RESET_ALL;
                break;
        case REQ_OP_DRV_IN:
-               /* Out header already filled in, nothing to do */
+               /*
+                * Out header has already been prepared by the caller (virtblk_get_id()
+                * or virtblk_submit_zone_report()), nothing to do here.
+                */
                return 0;
        default:
                WARN_ON_ONCE(1);
@@ -318,16 +322,28 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
        return 0;
 }
 
+/*
+ * The status byte is always the last byte of the virtblk request
+ * in-header. This helper fetches its value for all in-header formats
+ * that are currently defined.
+ */
+static inline u8 virtblk_vbr_status(struct virtblk_req *vbr)
+{
+       return *((u8 *)&vbr->in_hdr + vbr->in_hdr_len - 1);
+}
+
 static inline void virtblk_request_done(struct request *req)
 {
        struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
-       blk_status_t status = virtblk_result(vbr->status);
+       blk_status_t status = virtblk_result(virtblk_vbr_status(vbr));
+       struct virtio_blk *vblk = req->mq_hctx->queue->queuedata;
 
        virtblk_unmap_data(req, vbr);
        virtblk_cleanup_cmd(req);
 
        if (req_op(req) == REQ_OP_ZONE_APPEND)
-               req->__sector = le64_to_cpu(vbr->zone_append_in_hdr.append_sector);
+               req->__sector = virtio64_to_cpu(vblk->vdev,
+                                               vbr->in_hdr.zone_append.sector);
 
        blk_mq_end_request(req, status);
 }
@@ -355,7 +371,7 @@ static int virtblk_handle_req(struct virtio_blk_vq *vq,
 
                if (likely(!blk_should_fake_timeout(req->q)) &&
                    !blk_mq_complete_request_remote(req) &&
-                   !blk_mq_add_to_batch(req, iob, vbr->status,
+                   !blk_mq_add_to_batch(req, iob, virtblk_vbr_status(vbr),
                                         virtblk_complete_batch))
                        virtblk_request_done(req);
                req_done++;
@@ -550,7 +566,6 @@ static void virtio_queue_rqs(struct request **rqlist)
 #ifdef CONFIG_BLK_DEV_ZONED
 static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk,
                                          unsigned int nr_zones,
-                                         unsigned int zone_sectors,
                                          size_t *buflen)
 {
        struct request_queue *q = vblk->disk->queue;
@@ -558,7 +573,7 @@ static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk,
        void *buf;
 
        nr_zones = min_t(unsigned int, nr_zones,
-                        get_capacity(vblk->disk) >> ilog2(zone_sectors));
+                        get_capacity(vblk->disk) >> ilog2(vblk->zone_sectors));
 
        bufsize = sizeof(struct virtio_blk_zone_report) +
                nr_zones * sizeof(struct virtio_blk_zone_descriptor);
@@ -592,7 +607,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk,
                return PTR_ERR(req);
 
        vbr = blk_mq_rq_to_pdu(req);
-       vbr->in_hdr_len = sizeof(vbr->status);
+       vbr->in_hdr_len = sizeof(vbr->in_hdr.status);
        vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_ZONE_REPORT);
        vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, sector);
 
@@ -601,7 +616,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk,
                goto out;
 
        blk_execute_rq(req, false);
-       err = blk_status_to_errno(virtblk_result(vbr->status));
+       err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status));
 out:
        blk_mq_free_request(req);
        return err;
@@ -609,29 +624,72 @@ out:
 
 static int virtblk_parse_zone(struct virtio_blk *vblk,
                               struct virtio_blk_zone_descriptor *entry,
-                              unsigned int idx, unsigned int zone_sectors,
-                              report_zones_cb cb, void *data)
+                              unsigned int idx, report_zones_cb cb, void *data)
 {
        struct blk_zone zone = { };
 
-       if (entry->z_type != VIRTIO_BLK_ZT_SWR &&
-           entry->z_type != VIRTIO_BLK_ZT_SWP &&
-           entry->z_type != VIRTIO_BLK_ZT_CONV) {
-               dev_err(&vblk->vdev->dev, "invalid zone type %#x\n",
-                       entry->z_type);
-               return -EINVAL;
+       zone.start = virtio64_to_cpu(vblk->vdev, entry->z_start);
+       if (zone.start + vblk->zone_sectors <= get_capacity(vblk->disk))
+               zone.len = vblk->zone_sectors;
+       else
+               zone.len = get_capacity(vblk->disk) - zone.start;
+       zone.capacity = virtio64_to_cpu(vblk->vdev, entry->z_cap);
+       zone.wp = virtio64_to_cpu(vblk->vdev, entry->z_wp);
+
+       switch (entry->z_type) {
+       case VIRTIO_BLK_ZT_SWR:
+               zone.type = BLK_ZONE_TYPE_SEQWRITE_REQ;
+               break;
+       case VIRTIO_BLK_ZT_SWP:
+               zone.type = BLK_ZONE_TYPE_SEQWRITE_PREF;
+               break;
+       case VIRTIO_BLK_ZT_CONV:
+               zone.type = BLK_ZONE_TYPE_CONVENTIONAL;
+               break;
+       default:
+               dev_err(&vblk->vdev->dev, "zone %llu: invalid type %#x\n",
+                       zone.start, entry->z_type);
+               return -EIO;
        }
 
-       zone.type = entry->z_type;
-       zone.cond = entry->z_state;
-       zone.len = zone_sectors;
-       zone.capacity = le64_to_cpu(entry->z_cap);
-       zone.start = le64_to_cpu(entry->z_start);
-       if (zone.cond == BLK_ZONE_COND_FULL)
+       switch (entry->z_state) {
+       case VIRTIO_BLK_ZS_EMPTY:
+               zone.cond = BLK_ZONE_COND_EMPTY;
+               break;
+       case VIRTIO_BLK_ZS_CLOSED:
+               zone.cond = BLK_ZONE_COND_CLOSED;
+               break;
+       case VIRTIO_BLK_ZS_FULL:
+               zone.cond = BLK_ZONE_COND_FULL;
                zone.wp = zone.start + zone.len;
-       else
-               zone.wp = le64_to_cpu(entry->z_wp);
+               break;
+       case VIRTIO_BLK_ZS_EOPEN:
+               zone.cond = BLK_ZONE_COND_EXP_OPEN;
+               break;
+       case VIRTIO_BLK_ZS_IOPEN:
+               zone.cond = BLK_ZONE_COND_IMP_OPEN;
+               break;
+       case VIRTIO_BLK_ZS_NOT_WP:
+               zone.cond = BLK_ZONE_COND_NOT_WP;
+               break;
+       case VIRTIO_BLK_ZS_RDONLY:
+               zone.cond = BLK_ZONE_COND_READONLY;
+               zone.wp = ULONG_MAX;
+               break;
+       case VIRTIO_BLK_ZS_OFFLINE:
+               zone.cond = BLK_ZONE_COND_OFFLINE;
+               zone.wp = ULONG_MAX;
+               break;
+       default:
+               dev_err(&vblk->vdev->dev, "zone %llu: invalid condition %#x\n",
+                       zone.start, entry->z_state);
+               return -EIO;
+       }
 
+       /*
+        * The callback below checks the validity of the reported
+        * entry data, no need to further validate it here.
+        */
        return cb(&zone, idx, data);
 }
 
@@ -641,39 +699,47 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
 {
        struct virtio_blk *vblk = disk->private_data;
        struct virtio_blk_zone_report *report;
-       unsigned int zone_sectors = vblk->zone_sectors;
-       unsigned int nz, i;
-       int ret, zone_idx = 0;
+       unsigned long long nz, i;
        size_t buflen;
+       unsigned int zone_idx = 0;
+       int ret;
 
        if (WARN_ON_ONCE(!vblk->zone_sectors))
                return -EOPNOTSUPP;
 
-       report = virtblk_alloc_report_buffer(vblk, nr_zones,
-                                            zone_sectors, &buflen);
+       report = virtblk_alloc_report_buffer(vblk, nr_zones, &buflen);
        if (!report)
                return -ENOMEM;
 
+       mutex_lock(&vblk->vdev_mutex);
+
+       if (!vblk->vdev) {
+               ret = -ENXIO;
+               goto fail_report;
+       }
+
        while (zone_idx < nr_zones && sector < get_capacity(vblk->disk)) {
                memset(report, 0, buflen);
 
                ret = virtblk_submit_zone_report(vblk, (char *)report,
                                                 buflen, sector);
-               if (ret) {
-                       if (ret > 0)
-                               ret = -EIO;
-                       goto out_free;
-               }
-               nz = min((unsigned int)le64_to_cpu(report->nr_zones), nr_zones);
+               if (ret)
+                       goto fail_report;
+
+               nz = min_t(u64, virtio64_to_cpu(vblk->vdev, report->nr_zones),
+                          nr_zones);
                if (!nz)
                        break;
 
                for (i = 0; i < nz && zone_idx < nr_zones; i++) {
                        ret = virtblk_parse_zone(vblk, &report->zones[i],
-                                                zone_idx, zone_sectors, cb, data);
+                                                zone_idx, cb, data);
                        if (ret)
-                               goto out_free;
-                       sector = le64_to_cpu(report->zones[i].z_start) + zone_sectors;
+                               goto fail_report;
+
+                       sector = virtio64_to_cpu(vblk->vdev,
+                                                report->zones[i].z_start) +
+                                vblk->zone_sectors;
                        zone_idx++;
                }
        }
@@ -682,7 +748,8 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
                ret = zone_idx;
        else
                ret = -EINVAL;
-out_free:
+fail_report:
+       mutex_unlock(&vblk->vdev_mutex);
        kvfree(report);
        return ret;
 }
@@ -691,20 +758,28 @@ static void virtblk_revalidate_zones(struct virtio_blk *vblk)
 {
        u8 model;
 
-       if (!vblk->zone_sectors)
-               return;
-
        virtio_cread(vblk->vdev, struct virtio_blk_config,
                     zoned.model, &model);
-       if (!blk_revalidate_disk_zones(vblk->disk, NULL))
-               set_capacity_and_notify(vblk->disk, 0);
+       switch (model) {
+       default:
+               dev_err(&vblk->vdev->dev, "unknown zone model %d\n", model);
+               fallthrough;
+       case VIRTIO_BLK_Z_NONE:
+       case VIRTIO_BLK_Z_HA:
+               disk_set_zoned(vblk->disk, BLK_ZONED_NONE);
+               return;
+       case VIRTIO_BLK_Z_HM:
+               WARN_ON_ONCE(!vblk->zone_sectors);
+               if (!blk_revalidate_disk_zones(vblk->disk, NULL))
+                       set_capacity_and_notify(vblk->disk, 0);
+       }
 }
 
 static int virtblk_probe_zoned_device(struct virtio_device *vdev,
                                       struct virtio_blk *vblk,
                                       struct request_queue *q)
 {
-       u32 v;
+       u32 v, wg;
        u8 model;
        int ret;
 
@@ -713,16 +788,11 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
 
        switch (model) {
        case VIRTIO_BLK_Z_NONE:
+       case VIRTIO_BLK_Z_HA:
+               /* Present the host-aware device as non-zoned */
                return 0;
        case VIRTIO_BLK_Z_HM:
                break;
-       case VIRTIO_BLK_Z_HA:
-               /*
-                * Present the host-aware device as a regular drive.
-                * TODO It is possible to add an option to make it appear
-                * in the system as a zoned drive.
-                */
-               return 0;
        default:
                dev_err(&vdev->dev, "unsupported zone model %d\n", model);
                return -EINVAL;
@@ -735,32 +805,31 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
 
        virtio_cread(vdev, struct virtio_blk_config,
                     zoned.max_open_zones, &v);
-       disk_set_max_open_zones(vblk->disk, le32_to_cpu(v));
-
-       dev_dbg(&vdev->dev, "max open zones = %u\n", le32_to_cpu(v));
+       disk_set_max_open_zones(vblk->disk, v);
+       dev_dbg(&vdev->dev, "max open zones = %u\n", v);
 
        virtio_cread(vdev, struct virtio_blk_config,
                     zoned.max_active_zones, &v);
-       disk_set_max_active_zones(vblk->disk, le32_to_cpu(v));
-       dev_dbg(&vdev->dev, "max active zones = %u\n", le32_to_cpu(v));
+       disk_set_max_active_zones(vblk->disk, v);
+       dev_dbg(&vdev->dev, "max active zones = %u\n", v);
 
        virtio_cread(vdev, struct virtio_blk_config,
-                    zoned.write_granularity, &v);
-       if (!v) {
+                    zoned.write_granularity, &wg);
+       if (!wg) {
                dev_warn(&vdev->dev, "zero write granularity reported\n");
                return -ENODEV;
        }
-       blk_queue_physical_block_size(q, le32_to_cpu(v));
-       blk_queue_io_min(q, le32_to_cpu(v));
+       blk_queue_physical_block_size(q, wg);
+       blk_queue_io_min(q, wg);
 
-       dev_dbg(&vdev->dev, "write granularity = %u\n", le32_to_cpu(v));
+       dev_dbg(&vdev->dev, "write granularity = %u\n", wg);
 
        /*
         * virtio ZBD specification doesn't require zones to be a power of
         * two sectors in size, but the code in this driver expects that.
         */
-       virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, &v);
-       vblk->zone_sectors = le32_to_cpu(v);
+       virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors,
+                    &vblk->zone_sectors);
        if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) {
                dev_err(&vdev->dev,
                        "zoned device with non power of two zone size %u\n",
@@ -783,36 +852,46 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
                        dev_warn(&vdev->dev, "zero max_append_sectors reported\n");
                        return -ENODEV;
                }
-               blk_queue_max_zone_append_sectors(q, le32_to_cpu(v));
-               dev_dbg(&vdev->dev, "max append sectors = %u\n", le32_to_cpu(v));
+               if ((v << SECTOR_SHIFT) < wg) {
+                       dev_err(&vdev->dev,
+                               "write granularity %u exceeds max_append_sectors %u limit\n",
+                               wg, v);
+                       return -ENODEV;
+               }
+
+               blk_queue_max_zone_append_sectors(q, v);
+               dev_dbg(&vdev->dev, "max append sectors = %u\n", v);
        }
 
        return ret;
 }
 
-static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
-{
-       return virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED);
-}
 #else
 
 /*
  * Zoned block device support is not configured in this kernel.
- * We only need to define a few symbols to avoid compilation errors.
+ * Host-managed zoned devices can't be supported, but others are
+ * good to go as regular block devices.
  */
 #define virtblk_report_zones       NULL
+
 static inline void virtblk_revalidate_zones(struct virtio_blk *vblk)
 {
 }
+
 static inline int virtblk_probe_zoned_device(struct virtio_device *vdev,
                        struct virtio_blk *vblk, struct request_queue *q)
 {
-       return -EOPNOTSUPP;
-}
+       u8 model;
 
-static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
-{
-       return false;
+       virtio_cread(vdev, struct virtio_blk_config, zoned.model, &model);
+       if (model == VIRTIO_BLK_Z_HM) {
+               dev_err(&vdev->dev,
+                       "virtio_blk: zoned devices are not supported");
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
 }
 #endif /* CONFIG_BLK_DEV_ZONED */
 
@@ -831,7 +910,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
                return PTR_ERR(req);
 
        vbr = blk_mq_rq_to_pdu(req);
-       vbr->in_hdr_len = sizeof(vbr->status);
+       vbr->in_hdr_len = sizeof(vbr->in_hdr.status);
        vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID);
        vbr->out_hdr.sector = 0;
 
@@ -840,7 +919,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
                goto out;
 
        blk_execute_rq(req, false);
-       err = blk_status_to_errno(virtblk_result(vbr->status));
+       err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status));
 out:
        blk_mq_free_request(req);
        return err;
@@ -1498,15 +1577,16 @@ static int virtblk_probe(struct virtio_device *vdev)
        virtblk_update_capacity(vblk, false);
        virtio_device_ready(vdev);
 
-       if (virtblk_has_zoned_feature(vdev)) {
+       /*
+        * All steps that follow use the VQs therefore they need to be
+        * placed after the virtio_device_ready() call above.
+        */
+       if (virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED)) {
                err = virtblk_probe_zoned_device(vdev, vblk, q);
                if (err)
                        goto out_cleanup_disk;
        }
 
-       dev_info(&vdev->dev, "blk config size: %zu\n",
-               sizeof(struct virtio_blk_config));
-
        err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups);
        if (err)
                goto out_cleanup_disk;
@@ -1607,10 +1687,7 @@ static unsigned int features[] = {
        VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
        VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE,
        VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES,
-       VIRTIO_BLK_F_SECURE_ERASE,
-#ifdef CONFIG_BLK_DEV_ZONED
-       VIRTIO_BLK_F_ZONED,
-#endif /* CONFIG_BLK_DEV_ZONED */
+       VIRTIO_BLK_F_SECURE_ERASE, VIRTIO_BLK_F_ZONED,
 };
 
 static struct virtio_driver virtio_blk = {
index deed4af..d9cb937 100644 (file)
@@ -97,10 +97,6 @@ struct quad8 {
        struct quad8_reg __iomem *reg;
 };
 
-/* Borrow Toggle flip-flop */
-#define QUAD8_FLAG_BT BIT(0)
-/* Carry Toggle flip-flop */
-#define QUAD8_FLAG_CT BIT(1)
 /* Error flag */
 #define QUAD8_FLAG_E BIT(4)
 /* Up/Down flag */
@@ -133,6 +129,9 @@ struct quad8 {
 #define QUAD8_CMR_QUADRATURE_X2 0x10
 #define QUAD8_CMR_QUADRATURE_X4 0x18
 
+/* Each Counter is 24 bits wide */
+#define LS7267_CNTR_MAX GENMASK(23, 0)
+
 static int quad8_signal_read(struct counter_device *counter,
                             struct counter_signal *signal,
                             enum counter_signal_level *level)
@@ -156,18 +155,10 @@ static int quad8_count_read(struct counter_device *counter,
 {
        struct quad8 *const priv = counter_priv(counter);
        struct channel_reg __iomem *const chan = priv->reg->channel + count->id;
-       unsigned int flags;
-       unsigned int borrow;
-       unsigned int carry;
        unsigned long irqflags;
        int i;
 
-       flags = ioread8(&chan->control);
-       borrow = flags & QUAD8_FLAG_BT;
-       carry = !!(flags & QUAD8_FLAG_CT);
-
-       /* Borrow XOR Carry effectively doubles count range */
-       *val = (unsigned long)(borrow ^ carry) << 24;
+       *val = 0;
 
        spin_lock_irqsave(&priv->lock, irqflags);
 
@@ -191,8 +182,7 @@ static int quad8_count_write(struct counter_device *counter,
        unsigned long irqflags;
        int i;
 
-       /* Only 24-bit values are supported */
-       if (val > 0xFFFFFF)
+       if (val > LS7267_CNTR_MAX)
                return -ERANGE;
 
        spin_lock_irqsave(&priv->lock, irqflags);
@@ -378,7 +368,7 @@ static int quad8_action_read(struct counter_device *counter,
 
        /* Handle Index signals */
        if (synapse->signal->id >= 16) {
-               if (priv->preset_enable[count->id])
+               if (!priv->preset_enable[count->id])
                        *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
                else
                        *action = COUNTER_SYNAPSE_ACTION_NONE;
@@ -806,8 +796,7 @@ static int quad8_count_preset_write(struct counter_device *counter,
        struct quad8 *const priv = counter_priv(counter);
        unsigned long irqflags;
 
-       /* Only 24-bit values are supported */
-       if (preset > 0xFFFFFF)
+       if (preset > LS7267_CNTR_MAX)
                return -ERANGE;
 
        spin_lock_irqsave(&priv->lock, irqflags);
@@ -834,8 +823,7 @@ static int quad8_count_ceiling_read(struct counter_device *counter,
                *ceiling = priv->preset[count->id];
                break;
        default:
-               /* By default 0x1FFFFFF (25 bits unsigned) is maximum count */
-               *ceiling = 0x1FFFFFF;
+               *ceiling = LS7267_CNTR_MAX;
                break;
        }
 
@@ -850,8 +838,7 @@ static int quad8_count_ceiling_write(struct counter_device *counter,
        struct quad8 *const priv = counter_priv(counter);
        unsigned long irqflags;
 
-       /* Only 24-bit values are supported */
-       if (ceiling > 0xFFFFFF)
+       if (ceiling > LS7267_CNTR_MAX)
                return -ERANGE;
 
        spin_lock_irqsave(&priv->lock, irqflags);
index 45deda1..02cc2c3 100644 (file)
@@ -101,25 +101,40 @@ static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb,
                                      BIT(CXL_CM_CAP_CAP_ID_HDM));
 }
 
-static struct cxl_hdm *devm_cxl_setup_emulated_hdm(struct cxl_port *port,
-                                                  struct cxl_endpoint_dvsec_info *info)
+static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info)
 {
-       struct device *dev = &port->dev;
        struct cxl_hdm *cxlhdm;
+       void __iomem *hdm;
+       u32 ctrl;
+       int i;
 
-       if (!info->mem_enabled)
-               return ERR_PTR(-ENODEV);
+       if (!info)
+               return false;
 
-       cxlhdm = devm_kzalloc(dev, sizeof(*cxlhdm), GFP_KERNEL);
-       if (!cxlhdm)
-               return ERR_PTR(-ENOMEM);
+       cxlhdm = dev_get_drvdata(&info->port->dev);
+       hdm = cxlhdm->regs.hdm_decoder;
 
-       cxlhdm->port = port;
-       cxlhdm->decoder_count = info->ranges;
-       cxlhdm->target_count = info->ranges;
-       dev_set_drvdata(&port->dev, cxlhdm);
+       if (!hdm)
+               return true;
 
-       return cxlhdm;
+       /*
+        * If HDM decoders are present and the driver is in control of
+        * Mem_Enable skip DVSEC based emulation
+        */
+       if (!info->mem_enabled)
+               return false;
+
+       /*
+        * If any decoders are committed already, there should not be any
+        * emulated DVSEC decoders.
+        */
+       for (i = 0; i < cxlhdm->decoder_count; i++) {
+               ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i));
+               if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl))
+                       return false;
+       }
+
+       return true;
 }
 
 /**
@@ -138,13 +153,14 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
        cxlhdm = devm_kzalloc(dev, sizeof(*cxlhdm), GFP_KERNEL);
        if (!cxlhdm)
                return ERR_PTR(-ENOMEM);
-
        cxlhdm->port = port;
-       crb = ioremap(port->component_reg_phys, CXL_COMPONENT_REG_BLOCK_SIZE);
-       if (!crb) {
-               if (info && info->mem_enabled)
-                       return devm_cxl_setup_emulated_hdm(port, info);
+       dev_set_drvdata(dev, cxlhdm);
 
+       crb = ioremap(port->component_reg_phys, CXL_COMPONENT_REG_BLOCK_SIZE);
+       if (!crb && info && info->mem_enabled) {
+               cxlhdm->decoder_count = info->ranges;
+               return cxlhdm;
+       } else if (!crb) {
                dev_err(dev, "No component registers mapped\n");
                return ERR_PTR(-ENXIO);
        }
@@ -160,7 +176,15 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
                return ERR_PTR(-ENXIO);
        }
 
-       dev_set_drvdata(dev, cxlhdm);
+       /*
+        * Now that the hdm capability is parsed, decide if range
+        * register emulation is needed and fixup cxlhdm accordingly.
+        */
+       if (should_emulate_decoders(info)) {
+               dev_dbg(dev, "Fallback map %d range register%s\n", info->ranges,
+                       info->ranges > 1 ? "s" : "");
+               cxlhdm->decoder_count = info->ranges;
+       }
 
        return cxlhdm;
 }
@@ -714,14 +738,20 @@ static int cxl_decoder_reset(struct cxl_decoder *cxld)
        return 0;
 }
 
-static int cxl_setup_hdm_decoder_from_dvsec(struct cxl_port *port,
-                                           struct cxl_decoder *cxld, int which,
-                                           struct cxl_endpoint_dvsec_info *info)
+static int cxl_setup_hdm_decoder_from_dvsec(
+       struct cxl_port *port, struct cxl_decoder *cxld, u64 *dpa_base,
+       int which, struct cxl_endpoint_dvsec_info *info)
 {
+       struct cxl_endpoint_decoder *cxled;
+       u64 len;
+       int rc;
+
        if (!is_cxl_endpoint(port))
                return -EOPNOTSUPP;
 
-       if (!range_len(&info->dvsec_range[which]))
+       cxled = to_cxl_endpoint_decoder(&cxld->dev);
+       len = range_len(&info->dvsec_range[which]);
+       if (!len)
                return -ENOENT;
 
        cxld->target_type = CXL_DECODER_EXPANDER;
@@ -736,40 +766,24 @@ static int cxl_setup_hdm_decoder_from_dvsec(struct cxl_port *port,
        cxld->flags |= CXL_DECODER_F_ENABLE | CXL_DECODER_F_LOCK;
        port->commit_end = cxld->id;
 
-       return 0;
-}
-
-static bool should_emulate_decoders(struct cxl_port *port)
-{
-       struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);
-       void __iomem *hdm = cxlhdm->regs.hdm_decoder;
-       u32 ctrl;
-       int i;
-
-       if (!is_cxl_endpoint(cxlhdm->port))
-               return false;
-
-       if (!hdm)
-               return true;
-
-       /*
-        * If any decoders are committed already, there should not be any
-        * emulated DVSEC decoders.
-        */
-       for (i = 0; i < cxlhdm->decoder_count; i++) {
-               ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i));
-               if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl))
-                       return false;
+       rc = devm_cxl_dpa_reserve(cxled, *dpa_base, len, 0);
+       if (rc) {
+               dev_err(&port->dev,
+                       "decoder%d.%d: Failed to reserve DPA range %#llx - %#llx\n (%d)",
+                       port->id, cxld->id, *dpa_base, *dpa_base + len - 1, rc);
+               return rc;
        }
+       *dpa_base += len;
+       cxled->state = CXL_DECODER_STATE_AUTO;
 
-       return true;
+       return 0;
 }
 
 static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
                            int *target_map, void __iomem *hdm, int which,
                            u64 *dpa_base, struct cxl_endpoint_dvsec_info *info)
 {
-       struct cxl_endpoint_decoder *cxled = NULL;
+       struct cxl_endpoint_decoder *cxled;
        u64 size, base, skip, dpa_size;
        bool committed;
        u32 remainder;
@@ -780,11 +794,9 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
                unsigned char target_id[8];
        } target_list;
 
-       if (should_emulate_decoders(port))
-               return cxl_setup_hdm_decoder_from_dvsec(port, cxld, which, info);
-
-       if (is_endpoint_decoder(&cxld->dev))
-               cxled = to_cxl_endpoint_decoder(&cxld->dev);
+       if (should_emulate_decoders(info))
+               return cxl_setup_hdm_decoder_from_dvsec(port, cxld, dpa_base,
+                                                       which, info);
 
        ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(which));
        base = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(which));
@@ -806,9 +818,6 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
                .end = base + size - 1,
        };
 
-       if (cxled && !committed && range_len(&info->dvsec_range[which]))
-               return cxl_setup_hdm_decoder_from_dvsec(port, cxld, which, info);
-
        /* decoders are enabled if committed */
        if (committed) {
                cxld->flags |= CXL_DECODER_F_ENABLE;
@@ -846,7 +855,7 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
        if (rc)
                return rc;
 
-       if (!cxled) {
+       if (!info) {
                target_list.value =
                        ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which));
                for (i = 0; i < cxld->interleave_ways; i++)
@@ -866,6 +875,7 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
                return -ENXIO;
        }
        skip = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SKIP_LOW(which));
+       cxled = to_cxl_endpoint_decoder(&cxld->dev);
        rc = devm_cxl_dpa_reserve(cxled, *dpa_base + skip, dpa_size, skip);
        if (rc) {
                dev_err(&port->dev,
index 7328a25..523d5b9 100644 (file)
@@ -462,7 +462,7 @@ static struct pci_doe_mb *find_cdat_doe(struct device *uport)
        return NULL;
 }
 
-#define CDAT_DOE_REQ(entry_handle)                                     \
+#define CDAT_DOE_REQ(entry_handle) cpu_to_le32                         \
        (FIELD_PREP(CXL_DOE_TABLE_ACCESS_REQ_CODE,                      \
                    CXL_DOE_TABLE_ACCESS_REQ_CODE_READ) |               \
         FIELD_PREP(CXL_DOE_TABLE_ACCESS_TABLE_TYPE,                    \
@@ -475,8 +475,8 @@ static void cxl_doe_task_complete(struct pci_doe_task *task)
 }
 
 struct cdat_doe_task {
-       u32 request_pl;
-       u32 response_pl[32];
+       __le32 request_pl;
+       __le32 response_pl[32];
        struct completion c;
        struct pci_doe_task task;
 };
@@ -510,10 +510,10 @@ static int cxl_cdat_get_length(struct device *dev,
                return rc;
        }
        wait_for_completion(&t.c);
-       if (t.task.rv < sizeof(u32))
+       if (t.task.rv < 2 * sizeof(__le32))
                return -EIO;
 
-       *length = t.response_pl[1];
+       *length = le32_to_cpu(t.response_pl[1]);
        dev_dbg(dev, "CDAT length %zu\n", *length);
 
        return 0;
@@ -524,13 +524,13 @@ static int cxl_cdat_read_table(struct device *dev,
                               struct cxl_cdat *cdat)
 {
        size_t length = cdat->length;
-       u32 *data = cdat->table;
+       __le32 *data = cdat->table;
        int entry_handle = 0;
 
        do {
                DECLARE_CDAT_DOE_TASK(CDAT_DOE_REQ(entry_handle), t);
+               struct cdat_entry_header *entry;
                size_t entry_dw;
-               u32 *entry;
                int rc;
 
                rc = pci_doe_submit_task(cdat_doe, &t.task);
@@ -539,26 +539,34 @@ static int cxl_cdat_read_table(struct device *dev,
                        return rc;
                }
                wait_for_completion(&t.c);
-               /* 1 DW header + 1 DW data min */
-               if (t.task.rv < (2 * sizeof(u32)))
+
+               /* 1 DW Table Access Response Header + CDAT entry */
+               entry = (struct cdat_entry_header *)(t.response_pl + 1);
+               if ((entry_handle == 0 &&
+                    t.task.rv != sizeof(__le32) + sizeof(struct cdat_header)) ||
+                   (entry_handle > 0 &&
+                    (t.task.rv < sizeof(__le32) + sizeof(*entry) ||
+                     t.task.rv != sizeof(__le32) + le16_to_cpu(entry->length))))
                        return -EIO;
 
                /* Get the CXL table access header entry handle */
                entry_handle = FIELD_GET(CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE,
-                                        t.response_pl[0]);
-               entry = t.response_pl + 1;
-               entry_dw = t.task.rv / sizeof(u32);
+                                        le32_to_cpu(t.response_pl[0]));
+               entry_dw = t.task.rv / sizeof(__le32);
                /* Skip Header */
                entry_dw -= 1;
-               entry_dw = min(length / sizeof(u32), entry_dw);
+               entry_dw = min(length / sizeof(__le32), entry_dw);
                /* Prevent length < 1 DW from causing a buffer overflow */
                if (entry_dw) {
-                       memcpy(data, entry, entry_dw * sizeof(u32));
-                       length -= entry_dw * sizeof(u32);
+                       memcpy(data, entry, entry_dw * sizeof(__le32));
+                       length -= entry_dw * sizeof(__le32);
                        data += entry_dw;
                }
        } while (entry_handle != CXL_DOE_TABLE_ACCESS_LAST_ENTRY);
 
+       /* Length in CDAT header may exceed concatenation of CDAT entries */
+       cdat->length -= length;
+
        return 0;
 }
 
index c2e4b10..f8c38d9 100644 (file)
@@ -62,9 +62,9 @@ static int match_nvdimm_bridge(struct device *dev, void *data)
        return is_cxl_nvdimm_bridge(dev);
 }
 
-struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *start)
+struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_memdev *cxlmd)
 {
-       struct cxl_port *port = find_cxl_root(start);
+       struct cxl_port *port = find_cxl_root(dev_get_drvdata(&cxlmd->dev));
        struct device *dev;
 
        if (!port)
@@ -253,7 +253,7 @@ int devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd)
        struct device *dev;
        int rc;
 
-       cxl_nvb = cxl_find_nvdimm_bridge(&cxlmd->dev);
+       cxl_nvb = cxl_find_nvdimm_bridge(cxlmd);
        if (!cxl_nvb)
                return -ENODEV;
 
index 8ee6b6e..4d1f9c5 100644 (file)
@@ -823,41 +823,17 @@ static bool dev_is_cxl_root_child(struct device *dev)
        return false;
 }
 
-/* Find a 2nd level CXL port that has a dport that is an ancestor of @match */
-static int match_root_child(struct device *dev, const void *match)
+struct cxl_port *find_cxl_root(struct cxl_port *port)
 {
-       const struct device *iter = NULL;
-       struct cxl_dport *dport;
-       struct cxl_port *port;
-
-       if (!dev_is_cxl_root_child(dev))
-               return 0;
-
-       port = to_cxl_port(dev);
-       iter = match;
-       while (iter) {
-               dport = cxl_find_dport_by_dev(port, iter);
-               if (dport)
-                       break;
-               iter = iter->parent;
-       }
-
-       return !!iter;
-}
+       struct cxl_port *iter = port;
 
-struct cxl_port *find_cxl_root(struct device *dev)
-{
-       struct device *port_dev;
-       struct cxl_port *root;
+       while (iter && !is_cxl_root(iter))
+               iter = to_cxl_port(iter->dev.parent);
 
-       port_dev = bus_find_device(&cxl_bus_type, NULL, dev, match_root_child);
-       if (!port_dev)
+       if (!iter)
                return NULL;
-
-       root = to_cxl_port(port_dev->parent);
-       get_device(&root->dev);
-       put_device(port_dev);
-       return root;
+       get_device(&iter->dev);
+       return iter;
 }
 EXPORT_SYMBOL_NS_GPL(find_cxl_root, CXL);
 
index f290281..b2fd67f 100644 (file)
@@ -134,9 +134,13 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count)
                struct cxl_endpoint_decoder *cxled = p->targets[i];
                struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
                struct cxl_port *iter = cxled_to_port(cxled);
+               struct cxl_dev_state *cxlds = cxlmd->cxlds;
                struct cxl_ep *ep;
                int rc = 0;
 
+               if (cxlds->rcd)
+                       goto endpoint_reset;
+
                while (!is_cxl_root(to_cxl_port(iter->dev.parent)))
                        iter = to_cxl_port(iter->dev.parent);
 
@@ -153,6 +157,7 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count)
                                return rc;
                }
 
+endpoint_reset:
                rc = cxled->cxld.reset(&cxled->cxld);
                if (rc)
                        return rc;
@@ -1199,6 +1204,7 @@ static void cxl_region_teardown_targets(struct cxl_region *cxlr)
 {
        struct cxl_region_params *p = &cxlr->params;
        struct cxl_endpoint_decoder *cxled;
+       struct cxl_dev_state *cxlds;
        struct cxl_memdev *cxlmd;
        struct cxl_port *iter;
        struct cxl_ep *ep;
@@ -1214,6 +1220,10 @@ static void cxl_region_teardown_targets(struct cxl_region *cxlr)
        for (i = 0; i < p->nr_targets; i++) {
                cxled = p->targets[i];
                cxlmd = cxled_to_memdev(cxled);
+               cxlds = cxlmd->cxlds;
+
+               if (cxlds->rcd)
+                       continue;
 
                iter = cxled_to_port(cxled);
                while (!is_cxl_root(to_cxl_port(iter->dev.parent)))
@@ -1229,14 +1239,24 @@ static int cxl_region_setup_targets(struct cxl_region *cxlr)
 {
        struct cxl_region_params *p = &cxlr->params;
        struct cxl_endpoint_decoder *cxled;
+       struct cxl_dev_state *cxlds;
+       int i, rc, rch = 0, vh = 0;
        struct cxl_memdev *cxlmd;
        struct cxl_port *iter;
        struct cxl_ep *ep;
-       int i, rc;
 
        for (i = 0; i < p->nr_targets; i++) {
                cxled = p->targets[i];
                cxlmd = cxled_to_memdev(cxled);
+               cxlds = cxlmd->cxlds;
+
+               /* validate that all targets agree on topology */
+               if (!cxlds->rcd) {
+                       vh++;
+               } else {
+                       rch++;
+                       continue;
+               }
 
                iter = cxled_to_port(cxled);
                while (!is_cxl_root(to_cxl_port(iter->dev.parent)))
@@ -1256,6 +1276,12 @@ static int cxl_region_setup_targets(struct cxl_region *cxlr)
                }
        }
 
+       if (rch && vh) {
+               dev_err(&cxlr->dev, "mismatched CXL topologies detected\n");
+               cxl_region_teardown_targets(cxlr);
+               return -ENXIO;
+       }
+
        return 0;
 }
 
@@ -1648,6 +1674,7 @@ static int cxl_region_attach(struct cxl_region *cxlr,
                if (rc)
                        goto err_decrement;
                p->state = CXL_CONFIG_ACTIVE;
+               set_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags);
        }
 
        cxled->cxld.interleave_ways = p->interleave_ways;
@@ -1749,8 +1776,6 @@ static int attach_target(struct cxl_region *cxlr,
 
        down_read(&cxl_dpa_rwsem);
        rc = cxl_region_attach(cxlr, cxled, pos);
-       if (rc == 0)
-               set_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags);
        up_read(&cxl_dpa_rwsem);
        up_write(&cxl_region_rwsem);
        return rc;
@@ -2251,7 +2276,7 @@ static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr)
                 * bridge for one device is the same for all.
                 */
                if (i == 0) {
-                       cxl_nvb = cxl_find_nvdimm_bridge(&cxlmd->dev);
+                       cxl_nvb = cxl_find_nvdimm_bridge(cxlmd);
                        if (!cxl_nvb) {
                                cxlr_pmem = ERR_PTR(-ENODEV);
                                goto out;
index f2b0962..044a92d 100644 (file)
@@ -658,7 +658,7 @@ struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port);
 struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
                                   resource_size_t component_reg_phys,
                                   struct cxl_dport *parent_dport);
-struct cxl_port *find_cxl_root(struct device *dev);
+struct cxl_port *find_cxl_root(struct cxl_port *port);
 int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
 void cxl_bus_rescan(void);
 void cxl_bus_drain(void);
@@ -695,13 +695,15 @@ int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint)
 
 /**
  * struct cxl_endpoint_dvsec_info - Cached DVSEC info
- * @mem_enabled: cached value of mem_enabled in the DVSEC, PCIE_DEVICE
+ * @mem_enabled: cached value of mem_enabled in the DVSEC at init time
  * @ranges: Number of active HDM ranges this device uses.
+ * @port: endpoint port associated with this info instance
  * @dvsec_range: cached attributes of the ranges in the DVSEC, PCIE_DEVICE
  */
 struct cxl_endpoint_dvsec_info {
        bool mem_enabled;
        int ranges;
+       struct cxl_port *port;
        struct range dvsec_range[2];
 };
 
@@ -758,7 +760,7 @@ struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev);
 bool is_cxl_nvdimm(struct device *dev);
 bool is_cxl_nvdimm_bridge(struct device *dev);
 int devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd);
-struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *dev);
+struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_memdev *cxlmd);
 
 #ifdef CONFIG_CXL_REGION
 bool is_cxl_pmem_region(struct device *dev);
index be6a2ef..0465ef9 100644 (file)
@@ -68,6 +68,20 @@ enum cxl_regloc_type {
        CXL_REGLOC_RBI_TYPES
 };
 
+struct cdat_header {
+       __le32 length;
+       u8 revision;
+       u8 checksum;
+       u8 reserved[6];
+       __le32 sequence;
+} __packed;
+
+struct cdat_entry_header {
+       u8 type;
+       u8 reserved;
+       __le16 length;
+} __packed;
+
 int devm_cxl_port_enumerate_dports(struct cxl_port *port);
 struct cxl_dev_state;
 int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
index 1049bb5..22a7ab2 100644 (file)
@@ -78,8 +78,8 @@ static int cxl_switch_port_probe(struct cxl_port *port)
 
 static int cxl_endpoint_port_probe(struct cxl_port *port)
 {
+       struct cxl_endpoint_dvsec_info info = { .port = port };
        struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport);
-       struct cxl_endpoint_dvsec_info info = { 0 };
        struct cxl_dev_state *cxlds = cxlmd->cxlds;
        struct cxl_hdm *cxlhdm;
        struct cxl_port *root;
@@ -119,7 +119,7 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
         * This can't fail in practice as CXL root exit unregisters all
         * descendant ports and that in turn synchronizes with cxl_port_probe()
         */
-       root = find_cxl_root(&cxlmd->dev);
+       root = find_cxl_root(port);
 
        /*
         * Now that all endpoint decoders are successfully enumerated, try to
index 13be729..badbe05 100644 (file)
@@ -100,7 +100,7 @@ config GPIO_GENERIC
        tristate
 
 config GPIO_REGMAP
-       depends on REGMAP
+       select REGMAP
        tristate
 
 # put drivers in the right section, in alphabetical order
index 26b1f74..43b2dc8 100644 (file)
@@ -324,7 +324,7 @@ static struct irq_chip gpio_irqchip = {
        .irq_enable     = gpio_irq_enable,
        .irq_disable    = gpio_irq_disable,
        .irq_set_type   = gpio_irq_type,
-       .flags          = IRQCHIP_SET_TYPE_MASKED,
+       .flags          = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_SKIP_SET_WAKE,
 };
 
 static void gpio_irq_handler(struct irq_desc *desc)
@@ -641,9 +641,6 @@ static void davinci_gpio_save_context(struct davinci_gpio_controller *chips,
                context->set_falling = readl_relaxed(&g->set_falling);
        }
 
-       /* Clear Bank interrupt enable bit */
-       writel_relaxed(0, base + BINTEN);
-
        /* Clear all interrupt status registers */
        writel_relaxed(GENMASK(31, 0), &g->intstat);
 }
index 2106b3d..7c9b328 100644 (file)
@@ -232,7 +232,7 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder,
                        return slots;
        }
 
-       intel_link_compute_m_n(crtc_state->pipe_bpp,
+       intel_link_compute_m_n(crtc_state->dsc.compressed_bpp,
                               crtc_state->lane_count,
                               adjusted_mode->crtc_clock,
                               crtc_state->port_clock,
index 7420276..4758f21 100644 (file)
@@ -1067,11 +1067,12 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf)
                        .interruptible = true,
                        .no_wait_gpu = true, /* should be idle already */
                };
+               int err;
 
                GEM_BUG_ON(!bo->ttm || !(bo->ttm->page_flags & TTM_TT_FLAG_SWAPPED));
 
-               ret = ttm_bo_validate(bo, i915_ttm_sys_placement(), &ctx);
-               if (ret) {
+               err = ttm_bo_validate(bo, i915_ttm_sys_placement(), &ctx);
+               if (err) {
                        dma_resv_unlock(bo->base.resv);
                        return VM_FAULT_SIGBUS;
                }
index 1bbe670..7503264 100644 (file)
@@ -2018,6 +2018,8 @@ process_csb(struct intel_engine_cs *engine, struct i915_request **inactive)
         * inspecting the queue to see if we need to resumbit.
         */
        if (*prev != *execlists->active) { /* elide lite-restores */
+               struct intel_context *prev_ce = NULL, *active_ce = NULL;
+
                /*
                 * Note the inherent discrepancy between the HW runtime,
                 * recorded as part of the context switch, and the CPU
@@ -2029,9 +2031,15 @@ process_csb(struct intel_engine_cs *engine, struct i915_request **inactive)
                 * and correct overselves later when updating from HW.
                 */
                if (*prev)
-                       lrc_runtime_stop((*prev)->context);
+                       prev_ce = (*prev)->context;
                if (*execlists->active)
-                       lrc_runtime_start((*execlists->active)->context);
+                       active_ce = (*execlists->active)->context;
+               if (prev_ce != active_ce) {
+                       if (prev_ce)
+                               lrc_runtime_stop(prev_ce);
+                       if (active_ce)
+                               lrc_runtime_start(active_ce);
+               }
                new_timeslice(execlists);
        }
 
index 410905d..0c103ca 100644 (file)
@@ -235,6 +235,13 @@ static void delayed_huc_load_fini(struct intel_huc *huc)
        i915_sw_fence_fini(&huc->delayed_load.fence);
 }
 
+int intel_huc_sanitize(struct intel_huc *huc)
+{
+       delayed_huc_load_complete(huc);
+       intel_uc_fw_sanitize(&huc->fw);
+       return 0;
+}
+
 static bool vcs_supported(struct intel_gt *gt)
 {
        intel_engine_mask_t mask = gt->info.engine_mask;
index 52db036..db555b3 100644 (file)
@@ -41,6 +41,7 @@ struct intel_huc {
        } delayed_load;
 };
 
+int intel_huc_sanitize(struct intel_huc *huc);
 void intel_huc_init_early(struct intel_huc *huc);
 int intel_huc_init(struct intel_huc *huc);
 void intel_huc_fini(struct intel_huc *huc);
@@ -54,12 +55,6 @@ bool intel_huc_is_authenticated(struct intel_huc *huc);
 void intel_huc_register_gsc_notifier(struct intel_huc *huc, struct bus_type *bus);
 void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, struct bus_type *bus);
 
-static inline int intel_huc_sanitize(struct intel_huc *huc)
-{
-       intel_uc_fw_sanitize(&huc->fw);
-       return 0;
-}
-
 static inline bool intel_huc_is_supported(struct intel_huc *huc)
 {
        return intel_uc_fw_is_supported(&huc->fw);
index 283a4a3..0040749 100644 (file)
@@ -4638,13 +4638,13 @@ int i915_perf_add_config_ioctl(struct drm_device *dev, void *data,
                err = oa_config->id;
                goto sysfs_err;
        }
-
-       mutex_unlock(&perf->metrics_lock);
+       id = oa_config->id;
 
        drm_dbg(&perf->i915->drm,
                "Added config %s id=%i\n", oa_config->uuid, oa_config->id);
+       mutex_unlock(&perf->metrics_lock);
 
-       return oa_config->id;
+       return id;
 
 sysfs_err:
        mutex_unlock(&perf->metrics_lock);
index ed9d374..5bb777f 100644 (file)
@@ -363,6 +363,35 @@ nv50_outp_atomic_check_view(struct drm_encoder *encoder,
        return 0;
 }
 
+static void
+nv50_outp_atomic_fix_depth(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state)
+{
+       struct nv50_head_atom *asyh = nv50_head_atom(crtc_state);
+       struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+       struct drm_display_mode *mode = &asyh->state.adjusted_mode;
+       unsigned int max_rate, mode_rate;
+
+       switch (nv_encoder->dcb->type) {
+       case DCB_OUTPUT_DP:
+               max_rate = nv_encoder->dp.link_nr * nv_encoder->dp.link_bw;
+
+               /* we don't support more than 10 anyway */
+               asyh->or.bpc = min_t(u8, asyh->or.bpc, 10);
+
+               /* reduce the bpc until it works out */
+               while (asyh->or.bpc > 6) {
+                       mode_rate = DIV_ROUND_UP(mode->clock * asyh->or.bpc * 3, 8);
+                       if (mode_rate <= max_rate)
+                               break;
+
+                       asyh->or.bpc -= 2;
+               }
+               break;
+       default:
+               break;
+       }
+}
+
 static int
 nv50_outp_atomic_check(struct drm_encoder *encoder,
                       struct drm_crtc_state *crtc_state,
@@ -381,6 +410,9 @@ nv50_outp_atomic_check(struct drm_encoder *encoder,
        if (crtc_state->mode_changed || crtc_state->connectors_changed)
                asyh->or.bpc = connector->display_info.bpc;
 
+       /* We might have to reduce the bpc */
+       nv50_outp_atomic_fix_depth(encoder, crtc_state);
+
        return 0;
 }
 
index e00876f..d49b487 100644 (file)
@@ -263,8 +263,6 @@ nouveau_dp_irq(struct work_struct *work)
 }
 
 /* TODO:
- * - Use the minimum possible BPC here, once we add support for the max bpc
- *   property.
  * - Validate against the DP caps advertised by the GPU (we don't check these
  *   yet)
  */
@@ -276,7 +274,11 @@ nv50_dp_mode_valid(struct drm_connector *connector,
 {
        const unsigned int min_clock = 25000;
        unsigned int max_rate, mode_rate, ds_max_dotclock, clock = mode->clock;
-       const u8 bpp = connector->display_info.bpc * 3;
+       /* Check with the minmum bpc always, so we can advertise better modes.
+        * In particlar not doing this causes modes to be dropped on HDR
+        * displays as we might check with a bpc of 16 even.
+        */
+       const u8 bpp = 6 * 3;
 
        if (mode->flags & DRM_MODE_FLAG_INTERLACE && !outp->caps.dp_interlace)
                return MODE_NO_INTERLACE;
index 666a5e5..e961fa2 100644 (file)
@@ -504,6 +504,7 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as,
                if (IS_ERR(pages[i])) {
                        mutex_unlock(&bo->base.pages_lock);
                        ret = PTR_ERR(pages[i]);
+                       pages[i] = NULL;
                        goto err_pages;
                }
        }
index 9dc27e5..da51b50 100644 (file)
@@ -409,6 +409,10 @@ void vmbus_disconnect(void)
  */
 struct vmbus_channel *relid2channel(u32 relid)
 {
+       if (vmbus_connection.channels == NULL) {
+               pr_warn_once("relid2channel: relid=%d: No channels mapped!\n", relid);
+               return NULL;
+       }
        if (WARN_ON(relid >= MAX_CHANNEL_RELIDS))
                return NULL;
        return READ_ONCE(vmbus_connection.channels[relid]);
index 1ea8f17..4c15fae 100644 (file)
@@ -472,7 +472,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
                if (etm4x_sspcicrn_present(drvdata, i))
                        etm4x_relaxed_write32(csa, config->ss_pe_cmp[i], TRCSSPCICRn(i));
        }
-       for (i = 0; i < drvdata->nr_addr_cmp; i++) {
+       for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
                etm4x_relaxed_write64(csa, config->addr_val[i], TRCACVRn(i));
                etm4x_relaxed_write64(csa, config->addr_acc[i], TRCACATRn(i));
        }
@@ -1070,25 +1070,21 @@ static bool etm4_init_iomem_access(struct etmv4_drvdata *drvdata,
                                   struct csdev_access *csa)
 {
        u32 devarch = readl_relaxed(drvdata->base + TRCDEVARCH);
-       u32 idr1 = readl_relaxed(drvdata->base + TRCIDR1);
 
        /*
         * All ETMs must implement TRCDEVARCH to indicate that
-        * the component is an ETMv4. To support any broken
-        * implementations we fall back to TRCIDR1 check, which
-        * is not really reliable.
+        * the component is an ETMv4. Even though TRCIDR1 also
+        * contains the information, it is part of the "Trace"
+        * register and must be accessed with the OSLK cleared,
+        * with MMIO. But we cannot touch the OSLK until we are
+        * sure this is an ETM. So rely only on the TRCDEVARCH.
         */
-       if ((devarch & ETM_DEVARCH_ID_MASK) == ETM_DEVARCH_ETMv4x_ARCH) {
-               drvdata->arch = etm_devarch_to_arch(devarch);
-       } else {
-               pr_warn("CPU%d: ETM4x incompatible TRCDEVARCH: %x, falling back to TRCIDR1\n",
-                       smp_processor_id(), devarch);
-
-               if (ETM_TRCIDR1_ARCH_MAJOR(idr1) != ETM_TRCIDR1_ARCH_ETMv4)
-                       return false;
-               drvdata->arch = etm_trcidr_to_arch(idr1);
+       if ((devarch & ETM_DEVARCH_ID_MASK) != ETM_DEVARCH_ETMv4x_ARCH) {
+               pr_warn_once("TRCDEVARCH doesn't match ETMv4 architecture\n");
+               return false;
        }
 
+       drvdata->arch = etm_devarch_to_arch(devarch);
        *csa = CSDEV_ACCESS_IOMEM(drvdata->base);
        return true;
 }
index 434f4e9..27c8a99 100644 (file)
  * TRCDEVARCH  - CoreSight architected register
  *                - Bits[15:12] - Major version
  *                - Bits[19:16] - Minor version
- * TRCIDR1     - ETM architected register
- *                - Bits[11:8] - Major version
- *                - Bits[7:4]  - Minor version
- * We must rely on TRCDEVARCH for the version information,
- * however we don't want to break the support for potential
- * old implementations which might not implement it. Thus
- * we fall back to TRCIDR1 if TRCDEVARCH is not implemented
- * for memory mapped components.
+ *
+ * We must rely only on TRCDEVARCH for the version information. Even though,
+ * TRCIDR1 also provides the architecture version, it is a "Trace" register
+ * and as such must be accessed only with Trace power domain ON. This may
+ * not be available at probe time.
+ *
  * Now to make certain decisions easier based on the version
  * we use an internal representation of the version in the
  * driver, as follows :
@@ -786,12 +784,6 @@ static inline u8 etm_devarch_to_arch(u32 devarch)
                                ETM_DEVARCH_REVISION(devarch));
 }
 
-static inline u8 etm_trcidr_to_arch(u32 trcidr1)
-{
-       return ETM_ARCH_VERSION(ETM_TRCIDR1_ARCH_MAJOR(trcidr1),
-                               ETM_TRCIDR1_ARCH_MINOR(trcidr1));
-}
-
 enum etm_impdef_type {
        ETM4_IMPDEF_HISI_CORE_COMMIT,
        ETM4_IMPDEF_FEATURE_MAX,
index f866859..1c3a723 100644 (file)
@@ -864,7 +864,7 @@ static irqreturn_t kx022a_trigger_handler(int irq, void *p)
        if (ret < 0)
                goto err_read;
 
-       iio_push_to_buffers_with_timestamp(idev, data->buffer, pf->timestamp);
+       iio_push_to_buffers_with_timestamp(idev, data->buffer, data->timestamp);
 err_read:
        iio_trigger_notify_done(idev->trig);
 
index fee8d12..86effe8 100644 (file)
@@ -253,7 +253,7 @@ static const struct ad_sigma_delta_info ad7791_sigma_delta_info = {
        .has_registers = true,
        .addr_shift = 4,
        .read_mask = BIT(3),
-       .irq_flags = IRQF_TRIGGER_LOW,
+       .irq_flags = IRQF_TRIGGER_FALLING,
 };
 
 static int ad7791_read_raw(struct iio_dev *indio_dev,
index 17370c5..ec198c6 100644 (file)
@@ -28,7 +28,6 @@ struct ltc2497_driverdata {
        struct ltc2497core_driverdata common_ddata;
        struct i2c_client *client;
        u32 recv_size;
-       u32 sub_lsb;
        /*
         * DMA (thus cache coherency maintenance) may require the
         * transfer buffers to live in their own cache lines.
@@ -65,10 +64,10 @@ static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
                 * equivalent to a sign extension.
                 */
                if (st->recv_size == 3) {
-                       *val = (get_unaligned_be24(st->data.d8) >> st->sub_lsb)
+                       *val = (get_unaligned_be24(st->data.d8) >> 6)
                                - BIT(ddata->chip_info->resolution + 1);
                } else {
-                       *val = (be32_to_cpu(st->data.d32) >> st->sub_lsb)
+                       *val = (be32_to_cpu(st->data.d32) >> 6)
                                - BIT(ddata->chip_info->resolution + 1);
                }
 
@@ -122,7 +121,6 @@ static int ltc2497_probe(struct i2c_client *client)
        st->common_ddata.chip_info = chip_info;
 
        resolution = chip_info->resolution;
-       st->sub_lsb = 31 - (resolution + 1);
        st->recv_size = BITS_TO_BYTES(resolution) + 1;
 
        return ltc2497core_probe(dev, indio_dev);
index b74b689..f6895bc 100644 (file)
@@ -414,13 +414,17 @@ static int max11410_sample(struct max11410_state *st, int *sample_raw,
                if (!ret)
                        return -ETIMEDOUT;
        } else {
+               int ret2;
+
                /* Wait for status register Conversion Ready flag */
-               ret = read_poll_timeout(max11410_read_reg, ret,
-                                       ret || (val & MAX11410_STATUS_CONV_READY_BIT),
+               ret = read_poll_timeout(max11410_read_reg, ret2,
+                                       ret2 || (val & MAX11410_STATUS_CONV_READY_BIT),
                                        5000, MAX11410_CONVERSION_TIMEOUT_MS * 1000,
                                        true, st, MAX11410_REG_STATUS, &val);
                if (ret)
                        return ret;
+               if (ret2)
+                       return ret2;
        }
 
        /* Read ADC Data */
@@ -851,17 +855,21 @@ static int max11410_init_vref(struct device *dev,
 
 static int max11410_calibrate(struct max11410_state *st, u32 cal_type)
 {
-       int ret, val;
+       int ret, ret2, val;
 
        ret = max11410_write_reg(st, MAX11410_REG_CAL_START, cal_type);
        if (ret)
                return ret;
 
        /* Wait for status register Calibration Ready flag */
-       return read_poll_timeout(max11410_read_reg, ret,
-                                ret || (val & MAX11410_STATUS_CAL_READY_BIT),
-                                50000, MAX11410_CALIB_TIMEOUT_MS * 1000, true,
-                                st, MAX11410_REG_STATUS, &val);
+       ret = read_poll_timeout(max11410_read_reg, ret2,
+                               ret2 || (val & MAX11410_STATUS_CAL_READY_BIT),
+                               50000, MAX11410_CALIB_TIMEOUT_MS * 1000, true,
+                               st, MAX11410_REG_STATUS, &val);
+       if (ret)
+               return ret;
+
+       return ret2;
 }
 
 static int max11410_self_calibrate(struct max11410_state *st)
index fd00034..849a697 100644 (file)
@@ -639,7 +639,7 @@ out:
 
 static int palmas_gpadc_remove(struct platform_device *pdev)
 {
-       struct iio_dev *indio_dev = dev_to_iio_dev(&pdev->dev);
+       struct iio_dev *indio_dev = dev_get_drvdata(&pdev->dev);
        struct palmas_gpadc *adc = iio_priv(indio_dev);
 
        if (adc->wakeup1_enable || adc->wakeup2_enable)
index e90c299..c2d5e06 100644 (file)
@@ -628,12 +628,20 @@ static int adc5_get_fw_channel_data(struct adc5_chip *adc,
                                    struct fwnode_handle *fwnode,
                                    const struct adc5_data *data)
 {
-       const char *name = fwnode_get_name(fwnode), *channel_name;
+       const char *channel_name;
+       char *name;
        u32 chan, value, varr[2];
        u32 sid = 0;
        int ret;
        struct device *dev = adc->dev;
 
+       name = devm_kasprintf(dev, GFP_KERNEL, "%pfwP", fwnode);
+       if (!name)
+               return -ENOMEM;
+
+       /* Cut the address part */
+       name[strchrnul(name, '@') - name] = '\0';
+
        ret = fwnode_property_read_u32(fwnode, "reg", &chan);
        if (ret) {
                dev_err(dev, "invalid channel number %s\n", name);
index 2cc9a9b..263fc3a 100644 (file)
@@ -634,6 +634,7 @@ static int ti_ads7950_probe(struct spi_device *spi)
        st->chip.label = dev_name(&st->spi->dev);
        st->chip.parent = &st->spi->dev;
        st->chip.owner = THIS_MODULE;
+       st->chip.can_sleep = true;
        st->chip.base = -1;
        st->chip.ngpio = TI_ADS7950_NUM_GPIOS;
        st->chip.get_direction = ti_ads7950_get_direction;
index 791dd99..18a64f7 100644 (file)
@@ -66,8 +66,8 @@ static int cio_dac_write_raw(struct iio_dev *indio_dev,
        if (mask != IIO_CHAN_INFO_RAW)
                return -EINVAL;
 
-       /* DAC can only accept up to a 16-bit value */
-       if ((unsigned int)val > 65535)
+       /* DAC can only accept up to a 12-bit value */
+       if ((unsigned int)val > 4095)
                return -EINVAL;
 
        priv->chan_out_states[chan->channel] = val;
index f1d7d4b..c2f9762 100644 (file)
@@ -47,6 +47,7 @@ config ADIS16480
        depends on SPI
        select IIO_ADIS_LIB
        select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
+       select CRC32
        help
          Say yes here to build support for Analog Devices ADIS16375, ADIS16480,
          ADIS16485, ADIS16488 inertial sensors.
index 80c78bd..a7a080b 100644 (file)
@@ -203,24 +203,27 @@ static ssize_t iio_buffer_write(struct file *filp, const char __user *buf,
                                break;
                        }
 
+                       if (filp->f_flags & O_NONBLOCK) {
+                               if (!written)
+                                       ret = -EAGAIN;
+                               break;
+                       }
+
                        wait_woken(&wait, TASK_INTERRUPTIBLE,
                                        MAX_SCHEDULE_TIMEOUT);
                        continue;
                }
 
                ret = rb->access->write(rb, n - written, buf + written);
-               if (ret == 0 && (filp->f_flags & O_NONBLOCK))
-                       ret = -EAGAIN;
+               if (ret < 0)
+                       break;
 
-               if (ret > 0) {
-                       written += ret;
-                       if (written != n && !(filp->f_flags & O_NONBLOCK))
-                               continue;
-               }
-       } while (ret == 0);
+               written += ret;
+
+       } while (written != n);
        remove_wait_queue(&rb->pollq, &wait);
 
-       return ret < 0 ? ret : n;
+       return ret < 0 ? ret : written;
 }
 
 /**
index b1674a5..d4a34a3 100644 (file)
@@ -429,6 +429,14 @@ static const struct iio_info cm32181_info = {
        .attrs                  = &cm32181_attribute_group,
 };
 
+static void cm32181_unregister_dummy_client(void *data)
+{
+       struct i2c_client *client = data;
+
+       /* Unregister the dummy client */
+       i2c_unregister_device(client);
+}
+
 static int cm32181_probe(struct i2c_client *client)
 {
        struct device *dev = &client->dev;
@@ -460,6 +468,10 @@ static int cm32181_probe(struct i2c_client *client)
                client = i2c_acpi_new_device(dev, 1, &board_info);
                if (IS_ERR(client))
                        return PTR_ERR(client);
+
+               ret = devm_add_action_or_reset(dev, cm32181_unregister_dummy_client, client);
+               if (ret)
+                       return ret;
        }
 
        cm32181 = iio_priv(indio_dev);
index 6bdfce9..5c44a36 100644 (file)
@@ -208,7 +208,6 @@ static int vcnl4000_init(struct vcnl4000_data *data)
 
        data->rev = ret & 0xf;
        data->al_scale = 250000;
-       mutex_init(&data->vcnl4000_lock);
 
        return data->chip_spec->set_power_state(data, true);
 };
@@ -1367,6 +1366,8 @@ static int vcnl4000_probe(struct i2c_client *client)
        data->id = id->driver_data;
        data->chip_spec = &vcnl4000_chip_spec_cfg[data->id];
 
+       mutex_init(&data->vcnl4000_lock);
+
        ret = data->chip_spec->init(data);
        if (ret < 0)
                return ret;
index f8d92c9..3c47846 100644 (file)
@@ -294,9 +294,9 @@ static void batch_clear_carry(struct pfn_batch *batch, unsigned int keep_pfns)
                        batch->npfns[batch->end - 1] < keep_pfns);
 
        batch->total_pfns = keep_pfns;
-       batch->npfns[0] = keep_pfns;
        batch->pfns[0] = batch->pfns[batch->end - 1] +
                         (batch->npfns[batch->end - 1] - keep_pfns);
+       batch->npfns[0] = keep_pfns;
        batch->end = 0;
 }
 
@@ -1142,6 +1142,7 @@ struct iopt_pages *iopt_alloc_pages(void __user *uptr, unsigned long length,
                                    bool writable)
 {
        struct iopt_pages *pages;
+       unsigned long end;
 
        /*
         * The iommu API uses size_t as the length, and protect the DIV_ROUND_UP
@@ -1150,6 +1151,9 @@ struct iopt_pages *iopt_alloc_pages(void __user *uptr, unsigned long length,
        if (length > SIZE_MAX - PAGE_SIZE || length == 0)
                return ERR_PTR(-EINVAL);
 
+       if (check_add_overflow((unsigned long)uptr, length, &end))
+               return ERR_PTR(-EOVERFLOW);
+
        pages = kzalloc(sizeof(*pages), GFP_KERNEL_ACCOUNT);
        if (!pages)
                return ERR_PTR(-ENOMEM);
@@ -1203,13 +1207,21 @@ iopt_area_unpin_domain(struct pfn_batch *batch, struct iopt_area *area,
                        unsigned long start =
                                max(start_index, *unmapped_end_index);
 
+                       if (IS_ENABLED(CONFIG_IOMMUFD_TEST) &&
+                           batch->total_pfns)
+                               WARN_ON(*unmapped_end_index -
+                                               batch->total_pfns !=
+                                       start_index);
                        batch_from_domain(batch, domain, area, start,
                                          last_index);
-                       batch_last_index = start + batch->total_pfns - 1;
+                       batch_last_index = start_index + batch->total_pfns - 1;
                } else {
                        batch_last_index = last_index;
                }
 
+               if (IS_ENABLED(CONFIG_IOMMUFD_TEST))
+                       WARN_ON(batch_last_index > real_last_index);
+
                /*
                 * unmaps must always 'cut' at a place where the pfns are not
                 * contiguous to pair with the maps that always install
index 0de7b36..7108f74 100644 (file)
@@ -5601,7 +5601,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
         * .port_set_upstream_port method.
         */
        .set_egress_port = mv88e6393x_set_egress_port,
-       .watchdog_ops = &mv88e6390_watchdog_ops,
+       .watchdog_ops = &mv88e6393x_watchdog_ops,
        .mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu,
        .pot_clear = mv88e6xxx_g2_pot_clear,
        .reset = mv88e6352_g1_reset,
index ed3b2f8..a7af3ce 100644 (file)
@@ -943,6 +943,26 @@ const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {
        .irq_free = mv88e6390_watchdog_free,
 };
 
+static int mv88e6393x_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
+{
+       mv88e6390_watchdog_action(chip, irq);
+
+       /* Fix for clearing the force WD event bit.
+        * Unreleased erratum on mv88e6393x.
+        */
+       mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
+                          MV88E6390_G2_WDOG_CTL_UPDATE |
+                          MV88E6390_G2_WDOG_CTL_PTR_EVENT);
+
+       return IRQ_HANDLED;
+}
+
+const struct mv88e6xxx_irq_ops mv88e6393x_watchdog_ops = {
+       .irq_action = mv88e6393x_watchdog_action,
+       .irq_setup = mv88e6390_watchdog_setup,
+       .irq_free = mv88e6390_watchdog_free,
+};
+
 static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id)
 {
        struct mv88e6xxx_chip *chip = dev_id;
index e973114..7e09196 100644 (file)
@@ -369,6 +369,7 @@ int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target,
 extern const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops;
 extern const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops;
 extern const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops;
+extern const struct mv88e6xxx_irq_ops mv88e6393x_watchdog_ops;
 
 extern const struct mv88e6xxx_avb_ops mv88e6165_avb_ops;
 extern const struct mv88e6xxx_avb_ops mv88e6352_avb_ops;
index 5ba1e0d..9939cca 100644 (file)
@@ -507,6 +507,11 @@ struct bufdesc_ex {
 /* i.MX6Q adds pm_qos support */
 #define FEC_QUIRK_HAS_PMQOS                    BIT(23)
 
+/* Not all FEC hardware block MDIOs support accesses in C45 mode.
+ * Older blocks in the ColdFire parts do not support it.
+ */
+#define FEC_QUIRK_HAS_MDIO_C45         BIT(24)
+
 struct bufdesc_prop {
        int qid;
        /* Address of Rx and Tx buffers */
index f3b16a6..160c1b3 100644 (file)
@@ -100,18 +100,19 @@ struct fec_devinfo {
 
 static const struct fec_devinfo fec_imx25_info = {
        .quirks = FEC_QUIRK_USE_GASKET | FEC_QUIRK_MIB_CLEAR |
-                 FEC_QUIRK_HAS_FRREG,
+                 FEC_QUIRK_HAS_FRREG | FEC_QUIRK_HAS_MDIO_C45,
 };
 
 static const struct fec_devinfo fec_imx27_info = {
-       .quirks = FEC_QUIRK_MIB_CLEAR | FEC_QUIRK_HAS_FRREG,
+       .quirks = FEC_QUIRK_MIB_CLEAR | FEC_QUIRK_HAS_FRREG |
+                 FEC_QUIRK_HAS_MDIO_C45,
 };
 
 static const struct fec_devinfo fec_imx28_info = {
        .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME |
                  FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_RACC |
                  FEC_QUIRK_HAS_FRREG | FEC_QUIRK_CLEAR_SETUP_MII |
-                 FEC_QUIRK_NO_HARD_RESET,
+                 FEC_QUIRK_NO_HARD_RESET | FEC_QUIRK_HAS_MDIO_C45,
 };
 
 static const struct fec_devinfo fec_imx6q_info = {
@@ -119,11 +120,12 @@ static const struct fec_devinfo fec_imx6q_info = {
                  FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
                  FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
                  FEC_QUIRK_HAS_RACC | FEC_QUIRK_CLEAR_SETUP_MII |
-                 FEC_QUIRK_HAS_PMQOS,
+                 FEC_QUIRK_HAS_PMQOS | FEC_QUIRK_HAS_MDIO_C45,
 };
 
 static const struct fec_devinfo fec_mvf600_info = {
-       .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC,
+       .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC |
+                 FEC_QUIRK_HAS_MDIO_C45,
 };
 
 static const struct fec_devinfo fec_imx6x_info = {
@@ -132,7 +134,8 @@ static const struct fec_devinfo fec_imx6x_info = {
                  FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
                  FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
                  FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE |
-                 FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES,
+                 FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES |
+                 FEC_QUIRK_HAS_MDIO_C45,
 };
 
 static const struct fec_devinfo fec_imx6ul_info = {
@@ -140,7 +143,8 @@ static const struct fec_devinfo fec_imx6ul_info = {
                  FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
                  FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR007885 |
                  FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC |
-                 FEC_QUIRK_HAS_COALESCE | FEC_QUIRK_CLEAR_SETUP_MII,
+                 FEC_QUIRK_HAS_COALESCE | FEC_QUIRK_CLEAR_SETUP_MII |
+                 FEC_QUIRK_HAS_MDIO_C45,
 };
 
 static const struct fec_devinfo fec_imx8mq_info = {
@@ -150,7 +154,8 @@ static const struct fec_devinfo fec_imx8mq_info = {
                  FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
                  FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE |
                  FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES |
-                 FEC_QUIRK_HAS_EEE | FEC_QUIRK_WAKEUP_FROM_INT2,
+                 FEC_QUIRK_HAS_EEE | FEC_QUIRK_WAKEUP_FROM_INT2 |
+                 FEC_QUIRK_HAS_MDIO_C45,
 };
 
 static const struct fec_devinfo fec_imx8qm_info = {
@@ -160,14 +165,15 @@ static const struct fec_devinfo fec_imx8qm_info = {
                  FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
                  FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE |
                  FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES |
-                 FEC_QUIRK_DELAYED_CLKS_SUPPORT,
+                 FEC_QUIRK_DELAYED_CLKS_SUPPORT | FEC_QUIRK_HAS_MDIO_C45,
 };
 
 static const struct fec_devinfo fec_s32v234_info = {
        .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
                  FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
                  FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
-                 FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE,
+                 FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
+                 FEC_QUIRK_HAS_MDIO_C45,
 };
 
 static struct platform_device_id fec_devtype[] = {
@@ -2434,8 +2440,10 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        fep->mii_bus->name = "fec_enet_mii_bus";
        fep->mii_bus->read = fec_enet_mdio_read_c22;
        fep->mii_bus->write = fec_enet_mdio_write_c22;
-       fep->mii_bus->read_c45 = fec_enet_mdio_read_c45;
-       fep->mii_bus->write_c45 = fec_enet_mdio_write_c45;
+       if (fep->quirks & FEC_QUIRK_HAS_MDIO_C45) {
+               fep->mii_bus->read_c45 = fec_enet_mdio_read_c45;
+               fep->mii_bus->write_c45 = fec_enet_mdio_write_c45;
+       }
        snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
                pdev->name, fep->dev_id + 1);
        fep->mii_bus->priv = fep;
index 64eb044..005cb9d 100644 (file)
@@ -47,6 +47,8 @@
 
 #define GVE_RX_BUFFER_SIZE_DQO 2048
 
+#define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182
+
 /* Each slot in the desc ring has a 1:1 mapping to a slot in the data ring */
 struct gve_rx_desc_queue {
        struct gve_rx_desc *desc_ring; /* the descriptor ring */
index 4888bf0..5e11b82 100644 (file)
@@ -284,8 +284,8 @@ static inline int gve_skb_fifo_bytes_required(struct gve_tx_ring *tx,
        int bytes;
        int hlen;
 
-       hlen = skb_is_gso(skb) ? skb_checksum_start_offset(skb) +
-                                tcp_hdrlen(skb) : skb_headlen(skb);
+       hlen = skb_is_gso(skb) ? skb_checksum_start_offset(skb) + tcp_hdrlen(skb) :
+                                min_t(int, GVE_GQ_TX_MIN_PKT_DESC_BYTES, skb->len);
 
        pad_bytes = gve_tx_fifo_pad_alloc_one_frag(&tx->tx_fifo,
                                                   hlen);
@@ -454,13 +454,11 @@ static int gve_tx_add_skb_copy(struct gve_priv *priv, struct gve_tx_ring *tx, st
        pkt_desc = &tx->desc[idx];
 
        l4_hdr_offset = skb_checksum_start_offset(skb);
-       /* If the skb is gso, then we want the tcp header in the first segment
-        * otherwise we want the linear portion of the skb (which will contain
-        * the checksum because skb->csum_start and skb->csum_offset are given
-        * relative to skb->head) in the first segment.
+       /* If the skb is gso, then we want the tcp header alone in the first segment
+        * otherwise we want the minimum required by the gVNIC spec.
         */
        hlen = is_gso ? l4_hdr_offset + tcp_hdrlen(skb) :
-                       skb_headlen(skb);
+                       min_t(int, GVE_GQ_TX_MIN_PKT_DESC_BYTES, skb->len);
 
        info->skb =  skb;
        /* We don't want to split the header, so if necessary, pad to the end
index 5fd75e7..daa6a1e 100644 (file)
@@ -542,6 +542,21 @@ static void ice_vc_fdir_rem_prof_all(struct ice_vf *vf)
 }
 
 /**
+ * ice_vc_fdir_reset_cnt_all - reset all FDIR counters for this VF FDIR
+ * @fdir: pointer to the VF FDIR structure
+ */
+static void ice_vc_fdir_reset_cnt_all(struct ice_vf_fdir *fdir)
+{
+       enum ice_fltr_ptype flow;
+
+       for (flow = ICE_FLTR_PTYPE_NONF_NONE;
+            flow < ICE_FLTR_PTYPE_MAX; flow++) {
+               fdir->fdir_fltr_cnt[flow][0] = 0;
+               fdir->fdir_fltr_cnt[flow][1] = 0;
+       }
+}
+
+/**
  * ice_vc_fdir_has_prof_conflict
  * @vf: pointer to the VF structure
  * @conf: FDIR configuration for each filter
@@ -1871,7 +1886,7 @@ int ice_vc_add_fdir_fltr(struct ice_vf *vf, u8 *msg)
                v_ret = VIRTCHNL_STATUS_SUCCESS;
                stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
                dev_dbg(dev, "VF %d: set FDIR context failed\n", vf->vf_id);
-               goto err_free_conf;
+               goto err_rem_entry;
        }
 
        ret = ice_vc_fdir_write_fltr(vf, conf, true, is_tun);
@@ -1880,15 +1895,16 @@ int ice_vc_add_fdir_fltr(struct ice_vf *vf, u8 *msg)
                stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
                dev_err(dev, "VF %d: writing FDIR rule failed, ret:%d\n",
                        vf->vf_id, ret);
-               goto err_rem_entry;
+               goto err_clr_irq;
        }
 
 exit:
        kfree(stat);
        return ret;
 
-err_rem_entry:
+err_clr_irq:
        ice_vc_fdir_clear_irq_ctx(vf);
+err_rem_entry:
        ice_vc_fdir_remove_entry(vf, conf, conf->flow_id);
 err_free_conf:
        devm_kfree(dev, conf);
@@ -1997,6 +2013,7 @@ void ice_vf_fdir_init(struct ice_vf *vf)
        spin_lock_init(&fdir->ctx_lock);
        fdir->ctx_irq.flags = 0;
        fdir->ctx_done.flags = 0;
+       ice_vc_fdir_reset_cnt_all(fdir);
 }
 
 /**
index 282f943..e14050e 100644 (file)
@@ -753,6 +753,7 @@ static void mtk_mac_link_up(struct phylink_config *config,
                 MAC_MCR_FORCE_RX_FC);
 
        /* Configure speed */
+       mac->speed = speed;
        switch (speed) {
        case SPEED_2500:
        case SPEED_1000:
@@ -3235,6 +3236,9 @@ found:
        if (dp->index >= MTK_QDMA_NUM_QUEUES)
                return NOTIFY_DONE;
 
+       if (mac->speed > 0 && mac->speed <= s.base.speed)
+               s.base.speed = 0;
+
        mtk_set_queue_speed(eth, dp->index + 3, s.base.speed);
 
        return NOTIFY_DONE;
index 13aa919..ab9f876 100644 (file)
@@ -251,7 +251,6 @@ static void intel_speed_mode_2500(struct net_device *ndev, void *intel_data)
                priv->plat->mdio_bus_data->xpcs_an_inband = false;
        } else {
                priv->plat->max_speed = 1000;
-               priv->plat->mdio_bus_data->xpcs_an_inband = true;
        }
 }
 
index 17310ad..d7fcab0 100644 (file)
@@ -1134,20 +1134,26 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
 static int stmmac_init_phy(struct net_device *dev)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
+       struct fwnode_handle *phy_fwnode;
        struct fwnode_handle *fwnode;
        int ret;
 
+       if (!phylink_expects_phy(priv->phylink))
+               return 0;
+
        fwnode = of_fwnode_handle(priv->plat->phylink_node);
        if (!fwnode)
                fwnode = dev_fwnode(priv->device);
 
        if (fwnode)
-               ret = phylink_fwnode_phy_connect(priv->phylink, fwnode, 0);
+               phy_fwnode = fwnode_get_phy_node(fwnode);
+       else
+               phy_fwnode = NULL;
 
        /* Some DT bindings do not set-up the PHY handle. Let's try to
         * manually parse it
         */
-       if (!fwnode || ret) {
+       if (!phy_fwnode || IS_ERR(phy_fwnode)) {
                int addr = priv->plat->phy_addr;
                struct phy_device *phydev;
 
@@ -1163,6 +1169,9 @@ static int stmmac_init_phy(struct net_device *dev)
                }
 
                ret = phylink_connect_phy(priv->phylink, phydev);
+       } else {
+               fwnode_handle_put(phy_fwnode);
+               ret = phylink_fwnode_phy_connect(priv->phylink, fwnode, 0);
        }
 
        if (!priv->plat->pmt) {
@@ -6622,6 +6631,8 @@ int stmmac_xdp_open(struct net_device *dev)
                goto init_error;
        }
 
+       stmmac_reset_queues_param(priv);
+
        /* DMA CSR Channel configuration */
        for (chan = 0; chan < dma_csr_ch; chan++) {
                stmmac_init_chan(priv, priv->ioaddr, priv->plat->dma_cfg, chan);
@@ -6948,7 +6959,7 @@ static void stmmac_napi_del(struct net_device *dev)
 int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
-       int ret = 0;
+       int ret = 0, i;
 
        if (netif_running(dev))
                stmmac_release(dev);
@@ -6957,6 +6968,10 @@ int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt)
 
        priv->plat->rx_queues_to_use = rx_cnt;
        priv->plat->tx_queues_to_use = tx_cnt;
+       if (!netif_is_rxfh_configured(dev))
+               for (i = 0; i < ARRAY_SIZE(priv->rss.table); i++)
+                       priv->rss.table[i] = ethtool_rxfh_indir_default(i,
+                                                                       rx_cnt);
 
        stmmac_napi_add(dev);
 
index 4e3861c..bcea87b 100644 (file)
@@ -2926,7 +2926,8 @@ err_free_phylink:
        am65_cpsw_nuss_phylink_cleanup(common);
        am65_cpts_release(common->cpts);
 err_of_clear:
-       of_platform_device_destroy(common->mdio_dev, NULL);
+       if (common->mdio_dev)
+               of_platform_device_destroy(common->mdio_dev, NULL);
 err_pm_clear:
        pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);
@@ -2956,7 +2957,8 @@ static int am65_cpsw_nuss_remove(struct platform_device *pdev)
        am65_cpts_release(common->cpts);
        am65_cpsw_disable_serdes_phy(common);
 
-       of_platform_device_destroy(common->mdio_dev, NULL);
+       if (common->mdio_dev)
+               of_platform_device_destroy(common->mdio_dev, NULL);
 
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
index 1a2f074..30c166b 100644 (file)
@@ -1586,6 +1586,25 @@ void phylink_destroy(struct phylink *pl)
 }
 EXPORT_SYMBOL_GPL(phylink_destroy);
 
+/**
+ * phylink_expects_phy() - Determine if phylink expects a phy to be attached
+ * @pl: a pointer to a &struct phylink returned from phylink_create()
+ *
+ * When using fixed-link mode, or in-band mode with 1000base-X or 2500base-X,
+ * no PHY is needed.
+ *
+ * Returns true if phylink will be expecting a PHY.
+ */
+bool phylink_expects_phy(struct phylink *pl)
+{
+       if (pl->cfg_link_an_mode == MLO_AN_FIXED ||
+           (pl->cfg_link_an_mode == MLO_AN_INBAND &&
+            phy_interface_mode_is_8023z(pl->link_config.interface)))
+               return false;
+       return true;
+}
+EXPORT_SYMBOL_GPL(phylink_expects_phy);
+
 static void phylink_phy_change(struct phy_device *phydev, bool up)
 {
        struct phylink *pl = phydev->phylink;
index fb98db6..8af10bb 100644 (file)
@@ -387,6 +387,10 @@ static const struct sfp_quirk sfp_quirks[] = {
 
        SFP_QUIRK_F("HALNy", "HL-GSFP", sfp_fixup_halny_gsfp),
 
+       // HG MXPD-483II-F 2.5G supports 2500Base-X, but incorrectly reports
+       // 2600MBd in their EERPOM
+       SFP_QUIRK_M("HG GENUINE", "MXPD-483II", sfp_quirk_2500basex),
+
        // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd NRZ in
        // their EEPROM
        SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex,
index 86995e8..a62ee05 100644 (file)
@@ -16,7 +16,7 @@
 #include "pci.h"
 #include "pcic.h"
 
-#define MHI_TIMEOUT_DEFAULT_MS 90000
+#define MHI_TIMEOUT_DEFAULT_MS 20000
 #define RDDM_DUMP_SIZE 0x420000
 
 static struct mhi_channel_config ath11k_mhi_channels_qca6390[] = {
index b7c918f..65d4799 100644 (file)
@@ -994,15 +994,34 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
 MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
 
 
-static void brcmf_sdiod_acpi_set_power_manageable(struct device *dev,
-                                                 int val)
+static void brcmf_sdiod_acpi_save_power_manageable(struct brcmf_sdio_dev *sdiodev)
 {
 #if IS_ENABLED(CONFIG_ACPI)
        struct acpi_device *adev;
 
-       adev = ACPI_COMPANION(dev);
+       adev = ACPI_COMPANION(&sdiodev->func1->dev);
        if (adev)
-               adev->flags.power_manageable = 0;
+               sdiodev->func1_power_manageable = adev->flags.power_manageable;
+
+       adev = ACPI_COMPANION(&sdiodev->func2->dev);
+       if (adev)
+               sdiodev->func2_power_manageable = adev->flags.power_manageable;
+#endif
+}
+
+static void brcmf_sdiod_acpi_set_power_manageable(struct brcmf_sdio_dev *sdiodev,
+                                                 int enable)
+{
+#if IS_ENABLED(CONFIG_ACPI)
+       struct acpi_device *adev;
+
+       adev = ACPI_COMPANION(&sdiodev->func1->dev);
+       if (adev)
+               adev->flags.power_manageable = enable ? sdiodev->func1_power_manageable : 0;
+
+       adev = ACPI_COMPANION(&sdiodev->func2->dev);
+       if (adev)
+               adev->flags.power_manageable = enable ? sdiodev->func2_power_manageable : 0;
 #endif
 }
 
@@ -1012,7 +1031,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
        int err;
        struct brcmf_sdio_dev *sdiodev;
        struct brcmf_bus *bus_if;
-       struct device *dev;
 
        brcmf_dbg(SDIO, "Enter\n");
        brcmf_dbg(SDIO, "Class=%x\n", func->class);
@@ -1020,14 +1038,9 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
        brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
        brcmf_dbg(SDIO, "Function#: %d\n", func->num);
 
-       dev = &func->dev;
-
        /* Set MMC_QUIRK_LENIENT_FN0 for this card */
        func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
 
-       /* prohibit ACPI power management for this device */
-       brcmf_sdiod_acpi_set_power_manageable(dev, 0);
-
        /* Consume func num 1 but dont do anything with it. */
        if (func->num == 1)
                return 0;
@@ -1059,6 +1072,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
        dev_set_drvdata(&sdiodev->func1->dev, bus_if);
        sdiodev->dev = &sdiodev->func1->dev;
 
+       brcmf_sdiod_acpi_save_power_manageable(sdiodev);
        brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN);
 
        brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n");
@@ -1124,6 +1138,8 @@ void brcmf_sdio_wowl_config(struct device *dev, bool enabled)
 
        if (sdiodev->settings->bus.sdio.oob_irq_supported ||
            pm_caps & MMC_PM_WAKE_SDIO_IRQ) {
+               /* Stop ACPI from turning off the device when wowl is enabled */
+               brcmf_sdiod_acpi_set_power_manageable(sdiodev, !enabled);
                sdiodev->wowl_enabled = enabled;
                brcmf_dbg(SDIO, "Configuring WOWL, enabled=%d\n", enabled);
                return;
index b76d34d..0d18ed1 100644 (file)
@@ -188,6 +188,8 @@ struct brcmf_sdio_dev {
        char nvram_name[BRCMF_FW_NAME_LEN];
        char clm_name[BRCMF_FW_NAME_LEN];
        bool wowl_enabled;
+       bool func1_power_manageable;
+       bool func2_power_manageable;
        enum brcmf_sdiod_state state;
        struct brcmf_sdiod_freezer *freezer;
        const struct firmware *clm_fw;
index ca50feb..1b1358c 100644 (file)
@@ -512,15 +512,15 @@ mt7603_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
            !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
                return -EOPNOTSUPP;
 
-       if (cmd == SET_KEY) {
-               key->hw_key_idx = wcid->idx;
-               wcid->hw_key_idx = idx;
-       } else {
+       if (cmd != SET_KEY) {
                if (idx == wcid->hw_key_idx)
                        wcid->hw_key_idx = -1;
 
-               key = NULL;
+               return 0;
        }
+
+       key->hw_key_idx = wcid->idx;
+       wcid->hw_key_idx = idx;
        mt76_wcid_key_setup(&dev->mt76, wcid, key);
 
        return mt7603_wtbl_set_key(dev, wcid->idx, key);
index a956024..51a968a 100644 (file)
@@ -1193,8 +1193,7 @@ EXPORT_SYMBOL_GPL(mt7615_mac_enable_rtscts);
 static int
 mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
                           struct ieee80211_key_conf *key,
-                          enum mt76_cipher_type cipher, u16 cipher_mask,
-                          enum set_key_cmd cmd)
+                          enum mt76_cipher_type cipher, u16 cipher_mask)
 {
        u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx) + 30 * 4;
        u8 data[32] = {};
@@ -1203,27 +1202,18 @@ mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
                return -EINVAL;
 
        mt76_rr_copy(dev, addr, data, sizeof(data));
-       if (cmd == SET_KEY) {
-               if (cipher == MT_CIPHER_TKIP) {
-                       /* Rx/Tx MIC keys are swapped */
-                       memcpy(data, key->key, 16);
-                       memcpy(data + 16, key->key + 24, 8);
-                       memcpy(data + 24, key->key + 16, 8);
-               } else {
-                       if (cipher_mask == BIT(cipher))
-                               memcpy(data, key->key, key->keylen);
-                       else if (cipher != MT_CIPHER_BIP_CMAC_128)
-                               memcpy(data, key->key, 16);
-                       if (cipher == MT_CIPHER_BIP_CMAC_128)
-                               memcpy(data + 16, key->key, 16);
-               }
+       if (cipher == MT_CIPHER_TKIP) {
+               /* Rx/Tx MIC keys are swapped */
+               memcpy(data, key->key, 16);
+               memcpy(data + 16, key->key + 24, 8);
+               memcpy(data + 24, key->key + 16, 8);
        } else {
+               if (cipher_mask == BIT(cipher))
+                       memcpy(data, key->key, key->keylen);
+               else if (cipher != MT_CIPHER_BIP_CMAC_128)
+                       memcpy(data, key->key, 16);
                if (cipher == MT_CIPHER_BIP_CMAC_128)
-                       memset(data + 16, 0, 16);
-               else if (cipher_mask)
-                       memset(data, 0, 16);
-               if (!cipher_mask)
-                       memset(data, 0, sizeof(data));
+                       memcpy(data + 16, key->key, 16);
        }
 
        mt76_wr_copy(dev, addr, data, sizeof(data));
@@ -1234,7 +1224,7 @@ mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
 static int
 mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid,
                          enum mt76_cipher_type cipher, u16 cipher_mask,
-                         int keyidx, enum set_key_cmd cmd)
+                         int keyidx)
 {
        u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx), w0, w1;
 
@@ -1253,9 +1243,7 @@ mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid,
        else
                w0 &= ~MT_WTBL_W0_RX_IK_VALID;
 
-       if (cmd == SET_KEY &&
-           (cipher != MT_CIPHER_BIP_CMAC_128 ||
-            cipher_mask == BIT(cipher))) {
+       if (cipher != MT_CIPHER_BIP_CMAC_128 || cipher_mask == BIT(cipher)) {
                w0 &= ~MT_WTBL_W0_KEY_IDX;
                w0 |= FIELD_PREP(MT_WTBL_W0_KEY_IDX, keyidx);
        }
@@ -1272,19 +1260,10 @@ mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid,
 
 static void
 mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, struct mt76_wcid *wcid,
-                             enum mt76_cipher_type cipher, u16 cipher_mask,
-                             enum set_key_cmd cmd)
+                             enum mt76_cipher_type cipher, u16 cipher_mask)
 {
        u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx);
 
-       if (!cipher_mask) {
-               mt76_clear(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE);
-               return;
-       }
-
-       if (cmd != SET_KEY)
-               return;
-
        if (cipher == MT_CIPHER_BIP_CMAC_128 &&
            cipher_mask & ~BIT(MT_CIPHER_BIP_CMAC_128))
                return;
@@ -1295,8 +1274,7 @@ mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, struct mt76_wcid *wcid,
 
 int __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev,
                              struct mt76_wcid *wcid,
-                             struct ieee80211_key_conf *key,
-                             enum set_key_cmd cmd)
+                             struct ieee80211_key_conf *key)
 {
        enum mt76_cipher_type cipher;
        u16 cipher_mask = wcid->cipher;
@@ -1306,19 +1284,14 @@ int __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev,
        if (cipher == MT_CIPHER_NONE)
                return -EOPNOTSUPP;
 
-       if (cmd == SET_KEY)
-               cipher_mask |= BIT(cipher);
-       else
-               cipher_mask &= ~BIT(cipher);
-
-       mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, cipher_mask, cmd);
-       err = mt7615_mac_wtbl_update_key(dev, wcid, key, cipher, cipher_mask,
-                                        cmd);
+       cipher_mask |= BIT(cipher);
+       mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, cipher_mask);
+       err = mt7615_mac_wtbl_update_key(dev, wcid, key, cipher, cipher_mask);
        if (err < 0)
                return err;
 
        err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, cipher_mask,
-                                       key->keyidx, cmd);
+                                       key->keyidx);
        if (err < 0)
                return err;
 
@@ -1329,13 +1302,12 @@ int __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev,
 
 int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev,
                            struct mt76_wcid *wcid,
-                           struct ieee80211_key_conf *key,
-                           enum set_key_cmd cmd)
+                           struct ieee80211_key_conf *key)
 {
        int err;
 
        spin_lock_bh(&dev->mt76.lock);
-       err = __mt7615_mac_wtbl_set_key(dev, wcid, key, cmd);
+       err = __mt7615_mac_wtbl_set_key(dev, wcid, key);
        spin_unlock_bh(&dev->mt76.lock);
 
        return err;
index ab4c1b4..dadb13f 100644 (file)
@@ -391,18 +391,17 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        if (cmd == SET_KEY)
                *wcid_keyidx = idx;
-       else if (idx == *wcid_keyidx)
-               *wcid_keyidx = -1;
-       else
+       else {
+               if (idx == *wcid_keyidx)
+                       *wcid_keyidx = -1;
                goto out;
+       }
 
-       mt76_wcid_key_setup(&dev->mt76, wcid,
-                           cmd == SET_KEY ? key : NULL);
-
+       mt76_wcid_key_setup(&dev->mt76, wcid, key);
        if (mt76_is_mmio(&dev->mt76))
-               err = mt7615_mac_wtbl_set_key(dev, wcid, key, cmd);
+               err = mt7615_mac_wtbl_set_key(dev, wcid, key);
        else
-               err = __mt7615_mac_wtbl_set_key(dev, wcid, key, cmd);
+               err = __mt7615_mac_wtbl_set_key(dev, wcid, key);
 
 out:
        mt7615_mutex_release(dev);
index 43591b4..9e58f69 100644 (file)
@@ -490,11 +490,9 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
 void mt7615_mac_set_timing(struct mt7615_phy *phy);
 int __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev,
                              struct mt76_wcid *wcid,
-                             struct ieee80211_key_conf *key,
-                             enum set_key_cmd cmd);
+                             struct ieee80211_key_conf *key);
 int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
-                           struct ieee80211_key_conf *key,
-                           enum set_key_cmd cmd);
+                           struct ieee80211_key_conf *key);
 void mt7615_mac_reset_work(struct work_struct *work);
 u32 mt7615_mac_get_sta_tid_sn(struct mt7615_dev *dev, int wcid, u8 tid);
 
index 7451a63..dcbb5c6 100644 (file)
@@ -454,20 +454,20 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        msta = sta ? (struct mt76x02_sta *)sta->drv_priv : NULL;
        wcid = msta ? &msta->wcid : &mvif->group_wcid;
 
-       if (cmd == SET_KEY) {
-               key->hw_key_idx = wcid->idx;
-               wcid->hw_key_idx = idx;
-               if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) {
-                       key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
-                       wcid->sw_iv = true;
-               }
-       } else {
+       if (cmd != SET_KEY) {
                if (idx == wcid->hw_key_idx) {
                        wcid->hw_key_idx = -1;
                        wcid->sw_iv = false;
                }
 
-               key = NULL;
+               return 0;
+       }
+
+       key->hw_key_idx = wcid->idx;
+       wcid->hw_key_idx = idx;
+       if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) {
+               key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
+               wcid->sw_iv = true;
        }
        mt76_wcid_key_setup(&dev->mt76, wcid, key);
 
index 3bbccbd..784191e 100644 (file)
@@ -410,16 +410,15 @@ static int mt7915_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                mt7915_mcu_add_bss_info(phy, vif, true);
        }
 
-       if (cmd == SET_KEY)
+       if (cmd == SET_KEY) {
                *wcid_keyidx = idx;
-       else if (idx == *wcid_keyidx)
-               *wcid_keyidx = -1;
-       else
+       } else {
+               if (idx == *wcid_keyidx)
+                       *wcid_keyidx = -1;
                goto out;
+       }
 
-       mt76_wcid_key_setup(&dev->mt76, wcid,
-                           cmd == SET_KEY ? key : NULL);
-
+       mt76_wcid_key_setup(&dev->mt76, wcid, key);
        err = mt76_connac_mcu_add_key(&dev->mt76, vif, &msta->bip,
                                      key, MCU_EXT_CMD(STA_REC_UPDATE),
                                      &msta->wcid, cmd);
index 80c71ac..cc94531 100644 (file)
@@ -171,12 +171,12 @@ mt7921_mac_init_band(struct mt7921_dev *dev, u8 band)
 
 u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm)
 {
-       struct mt7921_fw_features *features = NULL;
        const struct mt76_connac2_fw_trailer *hdr;
        struct mt7921_realease_info *rel_info;
        const struct firmware *fw;
        int ret, i, offset = 0;
        const u8 *data, *end;
+       u8 offload_caps = 0;
 
        ret = request_firmware(&fw, fw_wm, dev);
        if (ret)
@@ -208,7 +208,10 @@ u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm)
                data += sizeof(*rel_info);
 
                if (rel_info->tag == MT7921_FW_TAG_FEATURE) {
+                       struct mt7921_fw_features *features;
+
                        features = (struct mt7921_fw_features *)data;
+                       offload_caps = features->data;
                        break;
                }
 
@@ -218,7 +221,7 @@ u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm)
 out:
        release_firmware(fw);
 
-       return features ? features->data : 0;
+       return offload_caps;
 }
 EXPORT_SYMBOL_GPL(mt7921_check_offload_capability);
 
index 75eaf86..42933a6 100644 (file)
@@ -569,16 +569,15 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        mt7921_mutex_acquire(dev);
 
-       if (cmd == SET_KEY)
+       if (cmd == SET_KEY) {
                *wcid_keyidx = idx;
-       else if (idx == *wcid_keyidx)
-               *wcid_keyidx = -1;
-       else
+       } else {
+               if (idx == *wcid_keyidx)
+                       *wcid_keyidx = -1;
                goto out;
+       }
 
-       mt76_wcid_key_setup(&dev->mt76, wcid,
-                           cmd == SET_KEY ? key : NULL);
-
+       mt76_wcid_key_setup(&dev->mt76, wcid, key);
        err = mt76_connac_mcu_add_key(&dev->mt76, vif, &msta->bip,
                                      key, MCU_UNI_CMD(STA_REC_UPDATE),
                                      &msta->wcid, cmd);
index cb72ded..5c23c82 100644 (file)
@@ -20,7 +20,7 @@ static const struct pci_device_id mt7921_pci_device_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0608),
                .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM },
        { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0616),
-               .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM },
+               .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM },
        { },
 };
 
index 3e4da03..1ba22d1 100644 (file)
@@ -351,16 +351,15 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                mt7996_mcu_add_bss_info(phy, vif, true);
        }
 
-       if (cmd == SET_KEY)
+       if (cmd == SET_KEY) {
                *wcid_keyidx = idx;
-       else if (idx == *wcid_keyidx)
-               *wcid_keyidx = -1;
-       else
+       } else {
+               if (idx == *wcid_keyidx)
+                       *wcid_keyidx = -1;
                goto out;
+       }
 
-       mt76_wcid_key_setup(&dev->mt76, wcid,
-                           cmd == SET_KEY ? key : NULL);
-
+       mt76_wcid_key_setup(&dev->mt76, wcid, key);
        err = mt7996_mcu_add_key(&dev->mt76, vif, &msta->bip,
                                 key, MCU_WMWA_UNI_CMD(STA_REC_UPDATE),
                                 &msta->wcid, cmd);
index 268ff9e..2652cd0 100644 (file)
@@ -1,7 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-ccflags-y += -Werror
-
 obj-${CONFIG_MTK_T7XX} := mtk_t7xx.o
 mtk_t7xx-y:=   t7xx_pci.o \
                t7xx_pcie_mac.o \
index 53ef028..d6a9bac 100644 (file)
@@ -1674,6 +1674,9 @@ static void nvme_config_discard(struct gendisk *disk, struct nvme_ns *ns)
        struct request_queue *queue = disk->queue;
        u32 size = queue_logical_block_size(queue);
 
+       if (ctrl->dmrsl && ctrl->dmrsl <= nvme_sect_to_lba(ns, UINT_MAX))
+               ctrl->max_discard_sectors = nvme_lba_to_sect(ns, ctrl->dmrsl);
+
        if (ctrl->max_discard_sectors == 0) {
                blk_queue_max_discard_sectors(queue, 0);
                return;
@@ -1688,9 +1691,6 @@ static void nvme_config_discard(struct gendisk *disk, struct nvme_ns *ns)
        if (queue->limits.max_discard_sectors)
                return;
 
-       if (ctrl->dmrsl && ctrl->dmrsl <= nvme_sect_to_lba(ns, UINT_MAX))
-               ctrl->max_discard_sectors = nvme_lba_to_sect(ns, ctrl->dmrsl);
-
        blk_queue_max_discard_sectors(queue, ctrl->max_discard_sectors);
        blk_queue_max_discard_segments(queue, ctrl->max_discard_segments);
 
index 66d9ab2..e5e9b28 100644 (file)
@@ -128,7 +128,7 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb,
                return -EIO;
 
        /* Length is 2 DW of header + length of payload in DW */
-       length = 2 + task->request_pl_sz / sizeof(u32);
+       length = 2 + task->request_pl_sz / sizeof(__le32);
        if (length > PCI_DOE_MAX_LENGTH)
                return -EIO;
        if (length == PCI_DOE_MAX_LENGTH)
@@ -141,9 +141,9 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb,
        pci_write_config_dword(pdev, offset + PCI_DOE_WRITE,
                               FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH,
                                          length));
-       for (i = 0; i < task->request_pl_sz / sizeof(u32); i++)
+       for (i = 0; i < task->request_pl_sz / sizeof(__le32); i++)
                pci_write_config_dword(pdev, offset + PCI_DOE_WRITE,
-                                      task->request_pl[i]);
+                                      le32_to_cpu(task->request_pl[i]));
 
        pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_GO);
 
@@ -195,11 +195,11 @@ static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *tas
 
        /* First 2 dwords have already been read */
        length -= 2;
-       payload_length = min(length, task->response_pl_sz / sizeof(u32));
+       payload_length = min(length, task->response_pl_sz / sizeof(__le32));
        /* Read the rest of the response payload */
        for (i = 0; i < payload_length; i++) {
-               pci_read_config_dword(pdev, offset + PCI_DOE_READ,
-                                     &task->response_pl[i]);
+               pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
+               task->response_pl[i] = cpu_to_le32(val);
                /* Prior to the last ack, ensure Data Object Ready */
                if (i == (payload_length - 1) && !pci_doe_data_obj_ready(doe_mb))
                        return -EIO;
@@ -217,13 +217,14 @@ static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *tas
        if (FIELD_GET(PCI_DOE_STATUS_ERROR, val))
                return -EIO;
 
-       return min(length, task->response_pl_sz / sizeof(u32)) * sizeof(u32);
+       return min(length, task->response_pl_sz / sizeof(__le32)) * sizeof(__le32);
 }
 
 static void signal_task_complete(struct pci_doe_task *task, int rv)
 {
        task->rv = rv;
        task->complete(task);
+       destroy_work_on_stack(&task->work);
 }
 
 static void signal_task_abort(struct pci_doe_task *task, int rv)
@@ -317,14 +318,16 @@ static int pci_doe_discovery(struct pci_doe_mb *doe_mb, u8 *index, u16 *vid,
 {
        u32 request_pl = FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX,
                                    *index);
+       __le32 request_pl_le = cpu_to_le32(request_pl);
+       __le32 response_pl_le;
        u32 response_pl;
        DECLARE_COMPLETION_ONSTACK(c);
        struct pci_doe_task task = {
                .prot.vid = PCI_VENDOR_ID_PCI_SIG,
                .prot.type = PCI_DOE_PROTOCOL_DISCOVERY,
-               .request_pl = &request_pl,
+               .request_pl = &request_pl_le,
                .request_pl_sz = sizeof(request_pl),
-               .response_pl = &response_pl,
+               .response_pl = &response_pl_le,
                .response_pl_sz = sizeof(response_pl),
                .complete = pci_doe_task_complete,
                .private = &c,
@@ -340,6 +343,7 @@ static int pci_doe_discovery(struct pci_doe_mb *doe_mb, u8 *index, u16 *vid,
        if (task.rv != sizeof(response_pl))
                return -EIO;
 
+       response_pl = le32_to_cpu(response_pl_le);
        *vid = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID, response_pl);
        *protocol = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL,
                              response_pl);
@@ -520,6 +524,8 @@ EXPORT_SYMBOL_GPL(pci_doe_supports_prot);
  * task->complete will be called when the state machine is done processing this
  * task.
  *
+ * @task must be allocated on the stack.
+ *
  * Excess data will be discarded.
  *
  * RETURNS: 0 when task has been successfully queued, -ERRNO on error
@@ -533,15 +539,15 @@ int pci_doe_submit_task(struct pci_doe_mb *doe_mb, struct pci_doe_task *task)
         * DOE requests must be a whole number of DW and the response needs to
         * be big enough for at least 1 DW
         */
-       if (task->request_pl_sz % sizeof(u32) ||
-           task->response_pl_sz < sizeof(u32))
+       if (task->request_pl_sz % sizeof(__le32) ||
+           task->response_pl_sz < sizeof(__le32))
                return -EINVAL;
 
        if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags))
                return -EIO;
 
        task->doe_mb = doe_mb;
-       INIT_WORK(&task->work, doe_statemachine_work);
+       INIT_WORK_ONSTACK(&task->work, doe_statemachine_work);
        queue_work(doe_mb->work_queue, &task->work);
        return 0;
 }
index c816646..78dc82b 100644 (file)
@@ -920,7 +920,7 @@ static ssize_t display_name_show(struct kobject *kobj, struct kobj_attribute *at
 static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
        struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
-       char *item, *value;
+       char *item, *value, *p;
        int ret;
 
        ret = tlmi_setting(setting->index, &item, LENOVO_BIOS_SETTING_GUID);
@@ -930,10 +930,15 @@ static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *a
        /* validate and split from `item,value` -> `value` */
        value = strpbrk(item, ",");
        if (!value || value == item || !strlen(value + 1))
-               return -EINVAL;
-
-       ret = sysfs_emit(buf, "%s\n", value + 1);
+               ret = -EINVAL;
+       else {
+               /* On Workstations remove the Options part after the value */
+               p = strchrnul(value, ';');
+               *p = '\0';
+               ret = sysfs_emit(buf, "%s\n", value + 1);
+       }
        kfree(item);
+
        return ret;
 }
 
@@ -1457,10 +1462,10 @@ static int tlmi_analyze(void)
                         * name string.
                         * Try and pull that out if it's available.
                         */
-                       char *item, *optstart, *optend;
+                       char *optitem, *optstart, *optend;
 
-                       if (!tlmi_setting(setting->index, &item, LENOVO_BIOS_SETTING_GUID)) {
-                               optstart = strstr(item, "[Optional:");
+                       if (!tlmi_setting(setting->index, &optitem, LENOVO_BIOS_SETTING_GUID)) {
+                               optstart = strstr(optitem, "[Optional:");
                                if (optstart) {
                                        optstart += strlen("[Optional:");
                                        optend = strstr(optstart, "]");
@@ -1469,6 +1474,7 @@ static int tlmi_analyze(void)
                                                        kstrndup(optstart, optend - optstart,
                                                                        GFP_KERNEL);
                                }
+                               kfree(optitem);
                        }
                }
                /*
index 32c1045..7191ff2 100644 (file)
@@ -4479,6 +4479,14 @@ static const struct dmi_system_id fwbug_list[] __initconst = {
                }
        },
        {
+               .ident = "T14s Gen1 AMD",
+               .driver_data = &quirk_s2idle_bug,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "20UJ"),
+               }
+       },
+       {
                .ident = "P14s Gen1 AMD",
                .driver_data = &quirk_s2idle_bug,
                .matches = {
index e01147f..4747257 100644 (file)
@@ -115,7 +115,14 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
        }
 
        if (pwm->chip->ops->get_state) {
-               struct pwm_state state;
+               /*
+                * Zero-initialize state because most drivers are unaware of
+                * .usage_power. The other members of state are supposed to be
+                * set by lowlevel drivers. We still initialize the whole
+                * structure for simplicity even though this might paper over
+                * faulty implementations of .get_state().
+                */
+               struct pwm_state state = { 0, };
 
                err = pwm->chip->ops->get_state(pwm->chip, pwm, &state);
                trace_pwm_get(pwm, &state, err);
@@ -448,7 +455,7 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,
 {
        struct pwm_state *last = &pwm->last;
        struct pwm_chip *chip = pwm->chip;
-       struct pwm_state s1, s2;
+       struct pwm_state s1 = { 0 }, s2 = { 0 };
        int err;
 
        if (!IS_ENABLED(CONFIG_PWM_DEBUG))
@@ -530,6 +537,7 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,
                return;
        }
 
+       *last = (struct pwm_state){ 0 };
        err = chip->ops->get_state(chip, pwm, last);
        trace_pwm_get(pwm, last, err);
        if (err)
index 86df670..ad18b0e 100644 (file)
@@ -198,6 +198,7 @@ static int cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 
        state->enabled = (ret > 0);
        state->period = EC_PWM_MAX_DUTY;
+       state->polarity = PWM_POLARITY_NORMAL;
 
        /*
         * Note that "disabled" and "duty cycle == 0" are treated the same. If
index 12c05c1..1b9274c 100644 (file)
@@ -146,6 +146,7 @@ static int hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 
        value = readl(base + PWM_CTRL_ADDR(pwm->hwpwm));
        state->enabled = (PWM_ENABLE_MASK & value);
+       state->polarity = (PWM_POLARITY_MASK & value) ? PWM_POLARITY_INVERSED : PWM_POLARITY_NORMAL;
 
        return 0;
 }
index 8362b48..47b3141 100644 (file)
@@ -126,6 +126,7 @@ static int iqs620_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
        mutex_unlock(&iqs620_pwm->lock);
 
        state->period = IQS620_PWM_PERIOD_NS;
+       state->polarity = PWM_POLARITY_NORMAL;
 
        return 0;
 }
index 16d79ca..5cd7b90 100644 (file)
@@ -162,6 +162,12 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
        duty = state->duty_cycle;
        period = state->period;
 
+       /*
+        * Note this is wrong. The result is an output wave that isn't really
+        * inverted and so is wrongly identified by .get_state as normal.
+        * Fixing this needs some care however as some machines might rely on
+        * this.
+        */
        if (state->polarity == PWM_POLARITY_INVERSED)
                duty = period - duty;
 
@@ -358,6 +364,8 @@ static int meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
                state->duty_cycle = 0;
        }
 
+       state->polarity = PWM_POLARITY_NORMAL;
+
        return 0;
 }
 
index d866ce3..bde579a 100644 (file)
@@ -109,6 +109,7 @@ static int sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
        duty = val & SPRD_PWM_DUTY_MSK;
        tmp = (prescale + 1) * NSEC_PER_SEC * duty;
        state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, chn->clk_rate);
+       state->polarity = PWM_POLARITY_NORMAL;
 
        /* Disable PWM clocks if the PWM channel is not in enable state. */
        if (!state->enabled)
index c76f82f..15f4529 100644 (file)
@@ -771,13 +771,12 @@ static int iscsi_sw_tcp_conn_set_param(struct iscsi_cls_conn *cls_conn,
                iscsi_set_param(cls_conn, param, buf, buflen);
                break;
        case ISCSI_PARAM_DATADGST_EN:
-               iscsi_set_param(cls_conn, param, buf, buflen);
-
                mutex_lock(&tcp_sw_conn->sock_lock);
                if (!tcp_sw_conn->sock) {
                        mutex_unlock(&tcp_sw_conn->sock_lock);
                        return -ENOTCONN;
                }
+               iscsi_set_param(cls_conn, param, buf, buflen);
                tcp_sw_conn->sendpage = conn->datadgst_en ?
                        sock_no_sendpage : tcp_sw_conn->sock->ops->sendpage;
                mutex_unlock(&tcp_sw_conn->sock_lock);
index a565817..d109a4c 100644 (file)
@@ -2526,7 +2526,7 @@ static void mpi3mr_watchdog_work(struct work_struct *work)
                mrioc->unrecoverable = 1;
                goto schedule_work;
        case MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS:
-               return;
+               goto schedule_work;
        case MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET:
                reset_reason = MPI3MR_RESET_FROM_CIACTIV_FAULT;
                break;
index bee1b8a..d0cdbfe 100644 (file)
@@ -3617,6 +3617,7 @@ skip_dpc:
 probe_failed:
        qla_enode_stop(base_vha);
        qla_edb_stop(base_vha);
+       vfree(base_vha->scan.l);
        if (base_vha->gnl.l) {
                dma_free_coherent(&ha->pdev->dev, base_vha->gnl.size,
                                base_vha->gnl.l, base_vha->gnl.ldma);
index fa43df0..3ba9c8b 100644 (file)
@@ -1903,6 +1903,17 @@ EXPORT_SYMBOL_GPL(serial8250_modem_status);
 static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
 {
        switch (iir & 0x3f) {
+       case UART_IIR_THRI:
+               /*
+                * Postpone DMA or not decision to IIR_RDI or IIR_RX_TIMEOUT
+                * because it's impossible to do an informed decision about
+                * that with IIR_THRI.
+                *
+                * This also fixes one known DMA Rx corruption issue where
+                * DR is asserted but DMA Rx only gets a corrupted zero byte
+                * (too early DR?).
+                */
+               return false;
        case UART_IIR_RDI:
                if (!up->dma->rx_running)
                        break;
index 56e6ba3..074bfed 100644 (file)
@@ -858,11 +858,17 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port)
                        struct lpuart_port, port);
        unsigned long stat = lpuart32_read(port, UARTSTAT);
        unsigned long sfifo = lpuart32_read(port, UARTFIFO);
+       unsigned long ctrl = lpuart32_read(port, UARTCTRL);
 
        if (sport->dma_tx_in_progress)
                return 0;
 
-       if (stat & UARTSTAT_TC && sfifo & UARTFIFO_TXEMPT)
+       /*
+        * LPUART Transmission Complete Flag may never be set while queuing a break
+        * character, so avoid checking for transmission complete when UARTCTRL_SBK
+        * is asserted.
+        */
+       if ((stat & UARTSTAT_TC && sfifo & UARTFIFO_TXEMPT) || ctrl & UARTCTRL_SBK)
                return TIOCSER_TEMT;
 
        return 0;
@@ -2942,7 +2948,7 @@ static bool lpuart_uport_is_active(struct lpuart_port *sport)
        tty = tty_port_tty_get(port);
        if (tty) {
                tty_dev = tty->dev;
-               may_wake = device_may_wakeup(tty_dev);
+               may_wake = tty_dev && device_may_wakeup(tty_dev);
                tty_kref_put(tty);
        }
 
index 7bd0807..caa09a0 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/ioport.h>
 #include <linux/ktime.h>
 #include <linux/major.h>
+#include <linux/minmax.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/of.h>
@@ -2864,6 +2865,13 @@ static int sci_init_single(struct platform_device *dev,
                        sci_port->irqs[i] = platform_get_irq(dev, i);
        }
 
+       /*
+        * The fourth interrupt on SCI port is transmit end interrupt, so
+        * shuffle the interrupts.
+        */
+       if (p->type == PORT_SCI)
+               swap(sci_port->irqs[SCIx_BRI_IRQ], sci_port->irqs[SCIx_TEI_IRQ]);
+
        /* The SCI generates several interrupts. They can be muxed together or
         * connected to different interrupt lines. In the muxed case only one
         * interrupt resource is specified as there is only one interrupt ID.
@@ -2929,7 +2937,7 @@ static int sci_init_single(struct platform_device *dev,
        port->flags             = UPF_FIXED_PORT | UPF_BOOT_AUTOCONF | p->flags;
        port->fifosize          = sci_port->params->fifosize;
 
-       if (port->type == PORT_SCI) {
+       if (port->type == PORT_SCI && !dev->dev.of_node) {
                if (sci_port->reg_size >= 0x20)
                        port->regshift = 2;
                else
index 37e178a..70b1120 100644 (file)
@@ -1409,13 +1409,6 @@ static int ufshcd_devfreq_target(struct device *dev,
        struct ufs_clk_info *clki;
        unsigned long irq_flags;
 
-       /*
-        * Skip devfreq if UFS initialization is not finished.
-        * Otherwise ufs could be in a inconsistent state.
-        */
-       if (!smp_load_acquire(&hba->logical_unit_scan_finished))
-               return 0;
-
        if (!ufshcd_is_clkscaling_supported(hba))
                return -EINVAL;
 
@@ -8399,6 +8392,22 @@ static int ufshcd_add_lus(struct ufs_hba *hba)
        if (ret)
                goto out;
 
+       /* Initialize devfreq after UFS device is detected */
+       if (ufshcd_is_clkscaling_supported(hba)) {
+               memcpy(&hba->clk_scaling.saved_pwr_info.info,
+                       &hba->pwr_info,
+                       sizeof(struct ufs_pa_layer_attr));
+               hba->clk_scaling.saved_pwr_info.is_valid = true;
+               hba->clk_scaling.is_allowed = true;
+
+               ret = ufshcd_devfreq_init(hba);
+               if (ret)
+                       goto out;
+
+               hba->clk_scaling.is_enabled = true;
+               ufshcd_init_clk_scaling_sysfs(hba);
+       }
+
        ufs_bsg_probe(hba);
        ufshpb_init(hba);
        scsi_scan_host(hba->host);
@@ -8670,12 +8679,6 @@ out:
        if (ret) {
                pm_runtime_put_sync(hba->dev);
                ufshcd_hba_exit(hba);
-       } else {
-               /*
-                * Make sure that when reader code sees UFS initialization has finished,
-                * all initialization steps have really been executed.
-                */
-               smp_store_release(&hba->logical_unit_scan_finished, true);
        }
 }
 
@@ -10316,30 +10319,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
         */
        ufshcd_set_ufs_dev_active(hba);
 
-       /* Initialize devfreq */
-       if (ufshcd_is_clkscaling_supported(hba)) {
-               memcpy(&hba->clk_scaling.saved_pwr_info.info,
-                       &hba->pwr_info,
-                       sizeof(struct ufs_pa_layer_attr));
-               hba->clk_scaling.saved_pwr_info.is_valid = true;
-               hba->clk_scaling.is_allowed = true;
-
-               err = ufshcd_devfreq_init(hba);
-               if (err)
-                       goto rpm_put_sync;
-
-               hba->clk_scaling.is_enabled = true;
-               ufshcd_init_clk_scaling_sysfs(hba);
-       }
-
        async_schedule(ufshcd_async_scan, hba);
        ufs_sysfs_add_nodes(hba->dev);
 
        device_enable_async_suspend(dev);
        return 0;
 
-rpm_put_sync:
-       pm_runtime_put_sync(dev);
 free_tmf_queue:
        blk_mq_destroy_queue(hba->tmf_queue);
        blk_put_queue(hba->tmf_queue);
index d63d5d9..f317d3c 100644 (file)
@@ -414,7 +414,7 @@ static int cdnsp_ep0_std_request(struct cdnsp_device *pdev,
 void cdnsp_setup_analyze(struct cdnsp_device *pdev)
 {
        struct usb_ctrlrequest *ctrl = &pdev->setup;
-       int ret = 0;
+       int ret = -EINVAL;
        u16 len;
 
        trace_cdnsp_ctrl_req(ctrl);
@@ -424,7 +424,6 @@ void cdnsp_setup_analyze(struct cdnsp_device *pdev)
 
        if (pdev->gadget.state == USB_STATE_NOTATTACHED) {
                dev_err(pdev->dev, "ERR: Setup detected in unattached state\n");
-               ret = -EINVAL;
                goto out;
        }
 
index a23ddbb..5607935 100644 (file)
@@ -49,6 +49,7 @@
 #define PCI_DEVICE_ID_INTEL_RPLS               0x7a61
 #define PCI_DEVICE_ID_INTEL_MTLM               0x7eb1
 #define PCI_DEVICE_ID_INTEL_MTLP               0x7ec1
+#define PCI_DEVICE_ID_INTEL_MTLS               0x7f6f
 #define PCI_DEVICE_ID_INTEL_MTL                        0x7e7e
 #define PCI_DEVICE_ID_INTEL_TGL                        0x9a15
 #define PCI_DEVICE_ID_AMD_MR                   0x163a
@@ -474,6 +475,9 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLP),
          (kernel_ulong_t) &dwc3_pci_intel_swnode, },
 
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLS),
+         (kernel_ulong_t) &dwc3_pci_intel_swnode, },
+
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL),
          (kernel_ulong_t) &dwc3_pci_intel_swnode, },
 
index ddfc537..56cdfb2 100644 (file)
@@ -1251,7 +1251,7 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
        p->kiocb = kiocb;
        if (p->aio) {
                p->to_free = dup_iter(&p->data, to, GFP_KERNEL);
-               if (!p->to_free) {
+               if (!iter_is_ubuf(&p->data) && !p->to_free) {
                        kfree(p);
                        return -ENOMEM;
                }
index d605bc2..28249d0 100644 (file)
@@ -614,7 +614,7 @@ ep_read_iter(struct kiocb *iocb, struct iov_iter *to)
                if (!priv)
                        goto fail;
                priv->to_free = dup_iter(&priv->to, to, GFP_KERNEL);
-               if (!priv->to_free) {
+               if (!iter_is_ubuf(&priv->to) && !priv->to_free) {
                        kfree(priv);
                        goto fail;
                }
index fb988e4..6db07ca 100644 (file)
@@ -771,12 +771,11 @@ static struct pci_driver xhci_pci_driver = {
        /* suspend and resume implemented later */
 
        .shutdown =     usb_hcd_pci_shutdown,
-       .driver = {
 #ifdef CONFIG_PM
-               .pm = &usb_hcd_pci_pm_ops,
-#endif
-               .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+       .driver = {
+               .pm = &usb_hcd_pci_pm_ops
        },
+#endif
 };
 
 static int __init xhci_pci_init(void)
index 1ff22f6..a88c39e 100644 (file)
@@ -1360,6 +1360,9 @@ static void tegra_xhci_id_work(struct work_struct *work)
 
        mutex_unlock(&tegra->lock);
 
+       tegra->otg_usb3_port = tegra_xusb_padctl_get_usb3_companion(tegra->padctl,
+                                                                   tegra->otg_usb2_port);
+
        if (tegra->host_mode) {
                /* switch to host mode */
                if (tegra->otg_usb3_port >= 0) {
@@ -1474,9 +1477,6 @@ static int tegra_xhci_id_notify(struct notifier_block *nb,
        }
 
        tegra->otg_usb2_port = tegra_xusb_get_usb2_port(tegra, usbphy);
-       tegra->otg_usb3_port = tegra_xusb_padctl_get_usb3_companion(
-                                                       tegra->padctl,
-                                                       tegra->otg_usb2_port);
 
        tegra->host_mode = (usbphy->last_event == USB_EVENT_ID) ? true : false;
 
index 6183ce8..6307bae 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/iommu.h>
 #include <linux/iopoll.h>
 #include <linux/irq.h>
 #include <linux/log2.h>
@@ -228,6 +229,7 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us)
 static void xhci_zero_64b_regs(struct xhci_hcd *xhci)
 {
        struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
+       struct iommu_domain *domain;
        int err, i;
        u64 val;
        u32 intrs;
@@ -246,7 +248,9 @@ static void xhci_zero_64b_regs(struct xhci_hcd *xhci)
         * an iommu. Doing anything when there is no iommu is definitely
         * unsafe...
         */
-       if (!(xhci->quirks & XHCI_ZERO_64B_REGS) || !device_iommu_mapped(dev))
+       domain = iommu_get_domain_for_dev(dev);
+       if (!(xhci->quirks & XHCI_ZERO_64B_REGS) || !domain ||
+           domain->type == IOMMU_DOMAIN_IDENTITY)
                return;
 
        xhci_info(xhci, "Zeroing 64bit base registers, expecting fault\n");
@@ -4438,6 +4442,7 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
 
        if (!virt_dev || max_exit_latency == virt_dev->current_mel) {
                spin_unlock_irqrestore(&xhci->lock, flags);
+               xhci_free_command(xhci, command);
                return 0;
        }
 
index 832ad59..cdea1bf 100644 (file)
@@ -120,6 +120,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */
        { USB_DEVICE(0x10C4, 0x8281) }, /* Nanotec Plug & Drive */
        { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */
+       { USB_DEVICE(0x10C4, 0x82AA) }, /* Silicon Labs IFS-USB-DATACABLE used with Quint UPS */
        { USB_DEVICE(0x10C4, 0x82EF) }, /* CESINEL FALCO 6105 AC Power Supply */
        { USB_DEVICE(0x10C4, 0x82F1) }, /* CESINEL MEDCAL EFD Earth Fault Detector */
        { USB_DEVICE(0x10C4, 0x82F2) }, /* CESINEL MEDCAL ST Network Analyzer */
index e6d8d9b..f31cc3c 100644 (file)
@@ -1198,6 +1198,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0xff, 0x30) },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0x40) },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, 0x0900, 0xff, 0, 0), /* RM500U-CN */
+         .driver_info = ZLP },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200U, 0xff, 0, 0) },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200S_CN, 0xff, 0, 0) },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200T, 0xff, 0, 0) },
@@ -1300,6 +1302,14 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = NCTRL(0) | RSVD(1) },
        { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1075, 0xff),    /* Telit FN990 (PCIe) */
          .driver_info = RSVD(0) },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1080, 0xff),    /* Telit FE990 (rmnet) */
+         .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1081, 0xff),    /* Telit FE990 (MBIM) */
+         .driver_info = NCTRL(0) | RSVD(1) },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1082, 0xff),    /* Telit FE990 (RNDIS) */
+         .driver_info = NCTRL(2) | RSVD(3) },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1083, 0xff),    /* Telit FE990 (ECM) */
+         .driver_info = NCTRL(0) | RSVD(1) },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910),
          .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM),
index 662cd04..8f3e884 100644 (file)
@@ -112,8 +112,12 @@ static int dp_altmode_configure(struct dp_altmode *dp, u8 con)
                if (dp->data.status & DP_STATUS_PREFER_MULTI_FUNC &&
                    pin_assign & DP_PIN_ASSIGN_MULTI_FUNC_MASK)
                        pin_assign &= DP_PIN_ASSIGN_MULTI_FUNC_MASK;
-               else if (pin_assign & DP_PIN_ASSIGN_DP_ONLY_MASK)
+               else if (pin_assign & DP_PIN_ASSIGN_DP_ONLY_MASK) {
                        pin_assign &= DP_PIN_ASSIGN_DP_ONLY_MASK;
+                       /* Default to pin assign C if available */
+                       if (pin_assign & BIT(DP_PIN_ASSIGN_C))
+                               pin_assign = BIT(DP_PIN_ASSIGN_C);
+               }
 
                if (!pin_assign)
                        return -EINVAL;
index 520646a..195963b 100644 (file)
@@ -2467,10 +2467,11 @@ static int setup_driver(struct mlx5_vdpa_dev *mvdev)
                err = 0;
                goto out;
        }
+       mlx5_vdpa_add_debugfs(ndev);
        err = setup_virtqueues(mvdev);
        if (err) {
                mlx5_vdpa_warn(mvdev, "setup_virtqueues\n");
-               goto out;
+               goto err_setup;
        }
 
        err = create_rqt(ndev);
@@ -2500,6 +2501,8 @@ err_tir:
        destroy_rqt(ndev);
 err_rqt:
        teardown_virtqueues(ndev);
+err_setup:
+       mlx5_vdpa_remove_debugfs(ndev->debugfs);
 out:
        return err;
 }
@@ -2513,6 +2516,8 @@ static void teardown_driver(struct mlx5_vdpa_net *ndev)
        if (!ndev->setup)
                return;
 
+       mlx5_vdpa_remove_debugfs(ndev->debugfs);
+       ndev->debugfs = NULL;
        teardown_steering(ndev);
        destroy_tir(ndev);
        destroy_rqt(ndev);
@@ -3261,7 +3266,6 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
        if (err)
                goto err_reg;
 
-       mlx5_vdpa_add_debugfs(ndev);
        mgtdev->ndev = ndev;
        return 0;
 
index 862f405..dfe2ce3 100644 (file)
@@ -466,16 +466,21 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
 
        vdpasim_net_setup_config(simdev, config);
 
-       ret = _vdpa_register_device(&simdev->vdpa, VDPASIM_NET_VQ_NUM);
-       if (ret)
-               goto reg_err;
-
        net = sim_to_net(simdev);
 
        u64_stats_init(&net->tx_stats.syncp);
        u64_stats_init(&net->rx_stats.syncp);
        u64_stats_init(&net->cq_stats.syncp);
 
+       /*
+        * Initialization must be completed before this call, since it can
+        * connect the device to the vDPA bus, so requests can arrive after
+        * this call.
+        */
+       ret = _vdpa_register_device(&simdev->vdpa, VDPASIM_NET_VQ_NUM);
+       if (ret)
+               goto reg_err;
+
        return 0;
 
 reg_err:
index b244e7c..32d0be9 100644 (file)
@@ -125,7 +125,6 @@ struct vhost_scsi_tpg {
        struct se_portal_group se_tpg;
        /* Pointer back to vhost_scsi, protected by tv_tpg_mutex */
        struct vhost_scsi *vhost_scsi;
-       struct list_head tmf_queue;
 };
 
 struct vhost_scsi_tport {
@@ -206,10 +205,8 @@ struct vhost_scsi {
 
 struct vhost_scsi_tmf {
        struct vhost_work vwork;
-       struct vhost_scsi_tpg *tpg;
        struct vhost_scsi *vhost;
        struct vhost_scsi_virtqueue *svq;
-       struct list_head queue_entry;
 
        struct se_cmd se_cmd;
        u8 scsi_resp;
@@ -352,12 +349,9 @@ static void vhost_scsi_release_cmd_res(struct se_cmd *se_cmd)
 
 static void vhost_scsi_release_tmf_res(struct vhost_scsi_tmf *tmf)
 {
-       struct vhost_scsi_tpg *tpg = tmf->tpg;
        struct vhost_scsi_inflight *inflight = tmf->inflight;
 
-       mutex_lock(&tpg->tv_tpg_mutex);
-       list_add_tail(&tpg->tmf_queue, &tmf->queue_entry);
-       mutex_unlock(&tpg->tv_tpg_mutex);
+       kfree(tmf);
        vhost_scsi_put_inflight(inflight);
 }
 
@@ -1194,19 +1188,11 @@ vhost_scsi_handle_tmf(struct vhost_scsi *vs, struct vhost_scsi_tpg *tpg,
                goto send_reject;
        }
 
-       mutex_lock(&tpg->tv_tpg_mutex);
-       if (list_empty(&tpg->tmf_queue)) {
-               pr_err("Missing reserve TMF. Could not handle LUN RESET.\n");
-               mutex_unlock(&tpg->tv_tpg_mutex);
+       tmf = kzalloc(sizeof(*tmf), GFP_KERNEL);
+       if (!tmf)
                goto send_reject;
-       }
-
-       tmf = list_first_entry(&tpg->tmf_queue, struct vhost_scsi_tmf,
-                              queue_entry);
-       list_del_init(&tmf->queue_entry);
-       mutex_unlock(&tpg->tv_tpg_mutex);
 
-       tmf->tpg = tpg;
+       vhost_work_init(&tmf->vwork, vhost_scsi_tmf_resp_work);
        tmf->vhost = vs;
        tmf->svq = svq;
        tmf->resp_iov = vq->iov[vc->out];
@@ -1658,7 +1644,10 @@ undepend:
        for (i = 0; i < VHOST_SCSI_MAX_TARGET; i++) {
                tpg = vs_tpg[i];
                if (tpg) {
+                       mutex_lock(&tpg->tv_tpg_mutex);
+                       tpg->vhost_scsi = NULL;
                        tpg->tv_tpg_vhost_count--;
+                       mutex_unlock(&tpg->tv_tpg_mutex);
                        target_undepend_item(&tpg->se_tpg.tpg_group.cg_item);
                }
        }
@@ -2032,19 +2021,11 @@ static int vhost_scsi_port_link(struct se_portal_group *se_tpg,
 {
        struct vhost_scsi_tpg *tpg = container_of(se_tpg,
                                struct vhost_scsi_tpg, se_tpg);
-       struct vhost_scsi_tmf *tmf;
-
-       tmf = kzalloc(sizeof(*tmf), GFP_KERNEL);
-       if (!tmf)
-               return -ENOMEM;
-       INIT_LIST_HEAD(&tmf->queue_entry);
-       vhost_work_init(&tmf->vwork, vhost_scsi_tmf_resp_work);
 
        mutex_lock(&vhost_scsi_mutex);
 
        mutex_lock(&tpg->tv_tpg_mutex);
        tpg->tv_tpg_port_count++;
-       list_add_tail(&tmf->queue_entry, &tpg->tmf_queue);
        mutex_unlock(&tpg->tv_tpg_mutex);
 
        vhost_scsi_hotplug(tpg, lun);
@@ -2059,16 +2040,11 @@ static void vhost_scsi_port_unlink(struct se_portal_group *se_tpg,
 {
        struct vhost_scsi_tpg *tpg = container_of(se_tpg,
                                struct vhost_scsi_tpg, se_tpg);
-       struct vhost_scsi_tmf *tmf;
 
        mutex_lock(&vhost_scsi_mutex);
 
        mutex_lock(&tpg->tv_tpg_mutex);
        tpg->tv_tpg_port_count--;
-       tmf = list_first_entry(&tpg->tmf_queue, struct vhost_scsi_tmf,
-                              queue_entry);
-       list_del(&tmf->queue_entry);
-       kfree(tmf);
        mutex_unlock(&tpg->tv_tpg_mutex);
 
        vhost_scsi_hotunplug(tpg, lun);
@@ -2329,7 +2305,6 @@ vhost_scsi_make_tpg(struct se_wwn *wwn, const char *name)
        }
        mutex_init(&tpg->tv_tpg_mutex);
        INIT_LIST_HEAD(&tpg->tv_tpg_list);
-       INIT_LIST_HEAD(&tpg->tmf_queue);
        tpg->tport = tport;
        tpg->tport_tpgt = tpgt;
 
index 50f7f3f..1974a38 100644 (file)
@@ -35,10 +35,12 @@ ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name,
                return retval;
        }
        if (attr_size > buffer_size) {
-               if (!buffer_size) /* request to get the attr_size */
-                       retval = attr_size;
-               else
+               if (buffer_size)
                        retval = -ERANGE;
+               else if (attr_size > SSIZE_MAX)
+                       retval = -EOVERFLOW;
+               else /* request to get the attr_size */
+                       retval = attr_size;
        } else {
                iov_iter_truncate(&to, attr_size);
                retval = p9_client_read(attr_fid, 0, &to, &err);
index 0d30b17..9d963ca 100644 (file)
@@ -120,7 +120,7 @@ again:
        spin_lock(&server->srv_lock);
        if (server->tcpStatus == CifsNeedReconnect) {
                spin_unlock(&server->srv_lock);
-               mutex_lock(&ses->session_mutex);
+               mutex_unlock(&ses->session_mutex);
 
                if (tcon->retry)
                        goto again;
index 6d13f82..ace11a1 100644 (file)
@@ -441,13 +441,14 @@ out:
  * but there are some bugs that prevent rename from working if there are
  * multiple delimiters.
  *
- * Returns a sanitized duplicate of @path. The caller is responsible for
- * cleaning up the original.
+ * Returns a sanitized duplicate of @path. @gfp indicates the GFP_* flags
+ * for kstrdup.
+ * The caller is responsible for freeing the original.
  */
 #define IS_DELIM(c) ((c) == '/' || (c) == '\\')
-static char *sanitize_path(char *path)
+char *cifs_sanitize_prepath(char *prepath, gfp_t gfp)
 {
-       char *cursor1 = path, *cursor2 = path;
+       char *cursor1 = prepath, *cursor2 = prepath;
 
        /* skip all prepended delimiters */
        while (IS_DELIM(*cursor1))
@@ -469,7 +470,7 @@ static char *sanitize_path(char *path)
                cursor2--;
 
        *(cursor2) = '\0';
-       return kstrdup(path, GFP_KERNEL);
+       return kstrdup(prepath, gfp);
 }
 
 /*
@@ -531,7 +532,7 @@ smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx)
        if (!*pos)
                return 0;
 
-       ctx->prepath = sanitize_path(pos);
+       ctx->prepath = cifs_sanitize_prepath(pos, GFP_KERNEL);
        if (!ctx->prepath)
                return -ENOMEM;
 
index 3de00e7..f4eaf85 100644 (file)
@@ -287,4 +287,7 @@ extern void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb);
  */
 #define SMB3_MAX_DCLOSETIMEO (1 << 30)
 #define SMB3_DEF_DCLOSETIMEO (1 * HZ) /* even 1 sec enough to help eg open/write/close/open/read */
+
+extern char *cifs_sanitize_prepath(char *prepath, gfp_t gfp);
+
 #endif
index b44fb51..7f085ed 100644 (file)
@@ -1195,7 +1195,7 @@ int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix)
        kfree(cifs_sb->prepath);
 
        if (prefix && *prefix) {
-               cifs_sb->prepath = kstrdup(prefix, GFP_ATOMIC);
+               cifs_sb->prepath = cifs_sanitize_prepath(prefix, GFP_ATOMIC);
                if (!cifs_sb->prepath)
                        return -ENOMEM;
 
index 3e457a1..2ababb8 100644 (file)
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -781,6 +781,33 @@ out:
        return ret;
 }
 
+static int __dax_clear_dirty_range(struct address_space *mapping,
+               pgoff_t start, pgoff_t end)
+{
+       XA_STATE(xas, &mapping->i_pages, start);
+       unsigned int scanned = 0;
+       void *entry;
+
+       xas_lock_irq(&xas);
+       xas_for_each(&xas, entry, end) {
+               entry = get_unlocked_entry(&xas, 0);
+               xas_clear_mark(&xas, PAGECACHE_TAG_DIRTY);
+               xas_clear_mark(&xas, PAGECACHE_TAG_TOWRITE);
+               put_unlocked_entry(&xas, entry, WAKE_NEXT);
+
+               if (++scanned % XA_CHECK_SCHED)
+                       continue;
+
+               xas_pause(&xas);
+               xas_unlock_irq(&xas);
+               cond_resched();
+               xas_lock_irq(&xas);
+       }
+       xas_unlock_irq(&xas);
+
+       return 0;
+}
+
 /*
  * Delete DAX entry at @index from @mapping.  Wait for it
  * to be unlocked before deleting it.
@@ -1258,15 +1285,20 @@ static s64 dax_unshare_iter(struct iomap_iter *iter)
        /* don't bother with blocks that are not shared to start with */
        if (!(iomap->flags & IOMAP_F_SHARED))
                return length;
-       /* don't bother with holes or unwritten extents */
-       if (srcmap->type == IOMAP_HOLE || srcmap->type == IOMAP_UNWRITTEN)
-               return length;
 
        id = dax_read_lock();
        ret = dax_iomap_direct_access(iomap, pos, length, &daddr, NULL);
        if (ret < 0)
                goto out_unlock;
 
+       /* zero the distance if srcmap is HOLE or UNWRITTEN */
+       if (srcmap->flags & IOMAP_F_SHARED || srcmap->type == IOMAP_UNWRITTEN) {
+               memset(daddr, 0, length);
+               dax_flush(iomap->dax_dev, daddr, length);
+               ret = length;
+               goto out_unlock;
+       }
+
        ret = dax_iomap_direct_access(srcmap, pos, length, &saddr, NULL);
        if (ret < 0)
                goto out_unlock;
@@ -1435,6 +1467,16 @@ static loff_t dax_iomap_iter(const struct iomap_iter *iomi,
         * written by write(2) is visible in mmap.
         */
        if (iomap->flags & IOMAP_F_NEW || cow) {
+               /*
+                * Filesystem allows CoW on non-shared extents. The src extents
+                * may have been mmapped with dirty mark before. To be able to
+                * invalidate its dax entries, we need to clear the dirty mark
+                * in advance.
+                */
+               if (cow)
+                       __dax_clear_dirty_range(iomi->inode->i_mapping,
+                                               pos >> PAGE_SHIFT,
+                                               (end - 1) >> PAGE_SHIFT);
                invalidate_inode_pages2_range(iomi->inode->i_mapping,
                                              pos >> PAGE_SHIFT,
                                              (end - 1) >> PAGE_SHIFT);
@@ -2022,8 +2064,8 @@ int dax_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
 
        while ((ret = iomap_iter(&src_iter, ops)) > 0 &&
               (ret = iomap_iter(&dst_iter, ops)) > 0) {
-               compared = dax_range_compare_iter(&src_iter, &dst_iter, len,
-                                                 same);
+               compared = dax_range_compare_iter(&src_iter, &dst_iter,
+                               min(src_iter.len, dst_iter.len), same);
                if (compared < 0)
                        return ret;
                src_iter.processed = dst_iter.processed = compared;
index 115a67d..365ac32 100644 (file)
@@ -112,10 +112,8 @@ void ksmbd_conn_enqueue_request(struct ksmbd_work *work)
        struct ksmbd_conn *conn = work->conn;
        struct list_head *requests_queue = NULL;
 
-       if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE) {
+       if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE)
                requests_queue = &conn->requests;
-               work->synchronous = true;
-       }
 
        if (requests_queue) {
                atomic_inc(&conn->req_running);
@@ -136,14 +134,14 @@ int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
 
        if (!work->multiRsp)
                atomic_dec(&conn->req_running);
-       spin_lock(&conn->request_lock);
        if (!work->multiRsp) {
+               spin_lock(&conn->request_lock);
                list_del_init(&work->request_entry);
-               if (!work->synchronous)
-                       list_del_init(&work->async_request_entry);
+               spin_unlock(&conn->request_lock);
+               if (work->asynchronous)
+                       release_async_work(work);
                ret = 0;
        }
-       spin_unlock(&conn->request_lock);
 
        wake_up_all(&conn->req_running_q);
        return ret;
@@ -326,10 +324,7 @@ int ksmbd_conn_handler_loop(void *p)
 
                /* 4 for rfc1002 length field */
                size = pdu_size + 4;
-               conn->request_buf = kvmalloc(size,
-                                            GFP_KERNEL |
-                                            __GFP_NOWARN |
-                                            __GFP_NORETRY);
+               conn->request_buf = kvmalloc(size, GFP_KERNEL);
                if (!conn->request_buf)
                        break;
 
index 3234f2c..f8ae614 100644 (file)
@@ -68,7 +68,7 @@ struct ksmbd_work {
        /* Request is encrypted */
        bool                            encrypted:1;
        /* Is this SYNC or ASYNC ksmbd_work */
-       bool                            synchronous:1;
+       bool                            asynchronous:1;
        bool                            need_invalidate_rkey:1;
 
        unsigned int                    remote_key;
index 394b6ce..0d82427 100644 (file)
@@ -289,10 +289,7 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
        work->request_buf = conn->request_buf;
        conn->request_buf = NULL;
 
-       if (ksmbd_init_smb_server(work)) {
-               ksmbd_free_work_struct(work);
-               return -EINVAL;
-       }
+       ksmbd_init_smb_server(work);
 
        ksmbd_conn_enqueue_request(work);
        atomic_inc(&conn->r_count);
index 97c9d1b..8af939a 100644 (file)
@@ -229,9 +229,6 @@ int init_smb2_neg_rsp(struct ksmbd_work *work)
        struct smb2_negotiate_rsp *rsp;
        struct ksmbd_conn *conn = work->conn;
 
-       if (conn->need_neg == false)
-               return -EINVAL;
-
        *(__be32 *)work->response_buf =
                cpu_to_be32(conn->vals->header_size);
 
@@ -498,12 +495,6 @@ int init_smb2_rsp_hdr(struct ksmbd_work *work)
        rsp_hdr->SessionId = rcv_hdr->SessionId;
        memcpy(rsp_hdr->Signature, rcv_hdr->Signature, 16);
 
-       work->synchronous = true;
-       if (work->async_id) {
-               ksmbd_release_id(&conn->async_ida, work->async_id);
-               work->async_id = 0;
-       }
-
        return 0;
 }
 
@@ -644,7 +635,7 @@ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)
                pr_err("Failed to alloc async message id\n");
                return id;
        }
-       work->synchronous = false;
+       work->asynchronous = true;
        work->async_id = id;
        rsp_hdr->Id.AsyncId = cpu_to_le64(id);
 
@@ -664,6 +655,24 @@ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)
        return 0;
 }
 
+void release_async_work(struct ksmbd_work *work)
+{
+       struct ksmbd_conn *conn = work->conn;
+
+       spin_lock(&conn->request_lock);
+       list_del_init(&work->async_request_entry);
+       spin_unlock(&conn->request_lock);
+
+       work->asynchronous = 0;
+       work->cancel_fn = NULL;
+       kfree(work->cancel_argv);
+       work->cancel_argv = NULL;
+       if (work->async_id) {
+               ksmbd_release_id(&conn->async_ida, work->async_id);
+               work->async_id = 0;
+       }
+}
+
 void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status)
 {
        struct smb2_hdr *rsp_hdr;
@@ -7045,13 +7054,9 @@ skip:
 
                                ksmbd_vfs_posix_lock_wait(flock);
 
-                               spin_lock(&work->conn->request_lock);
                                spin_lock(&fp->f_lock);
                                list_del(&work->fp_entry);
-                               work->cancel_fn = NULL;
-                               kfree(argv);
                                spin_unlock(&fp->f_lock);
-                               spin_unlock(&work->conn->request_lock);
 
                                if (work->state != KSMBD_WORK_ACTIVE) {
                                        list_del(&smb_lock->llist);
@@ -7069,6 +7074,7 @@ skip:
                                                work->send_no_response = 1;
                                                goto out;
                                        }
+
                                        init_smb2_rsp_hdr(work);
                                        smb2_set_err_rsp(work);
                                        rsp->hdr.Status =
@@ -7081,7 +7087,7 @@ skip:
                                spin_lock(&work->conn->llist_lock);
                                list_del(&smb_lock->clist);
                                spin_unlock(&work->conn->llist_lock);
-
+                               release_async_work(work);
                                goto retry;
                        } else if (!rc) {
                                spin_lock(&work->conn->llist_lock);
index 0c8a770..9420dd2 100644 (file)
@@ -486,6 +486,7 @@ int find_matching_smb2_dialect(int start_index, __le16 *cli_dialects,
 struct file_lock *smb_flock_init(struct file *f);
 int setup_async_work(struct ksmbd_work *work, void (*fn)(void **),
                     void **arg);
+void release_async_work(struct ksmbd_work *work);
 void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status);
 struct channel *lookup_chann_list(struct ksmbd_session *sess,
                                  struct ksmbd_conn *conn);
index 9c1ce6d..af0c2a9 100644 (file)
@@ -283,20 +283,121 @@ err_out:
        return BAD_PROT_ID;
 }
 
-int ksmbd_init_smb_server(struct ksmbd_work *work)
+#define SMB_COM_NEGOTIATE_EX   0x0
+
+/**
+ * get_smb1_cmd_val() - get smb command value from smb header
+ * @work:      smb work containing smb header
+ *
+ * Return:      smb command value
+ */
+static u16 get_smb1_cmd_val(struct ksmbd_work *work)
 {
-       struct ksmbd_conn *conn = work->conn;
+       return SMB_COM_NEGOTIATE_EX;
+}
 
-       if (conn->need_neg == false)
+/**
+ * init_smb1_rsp_hdr() - initialize smb negotiate response header
+ * @work:      smb work containing smb request
+ *
+ * Return:      0 on success, otherwise -EINVAL
+ */
+static int init_smb1_rsp_hdr(struct ksmbd_work *work)
+{
+       struct smb_hdr *rsp_hdr = (struct smb_hdr *)work->response_buf;
+       struct smb_hdr *rcv_hdr = (struct smb_hdr *)work->request_buf;
+
+       /*
+        * Remove 4 byte direct TCP header.
+        */
+       *(__be32 *)work->response_buf =
+               cpu_to_be32(sizeof(struct smb_hdr) - 4);
+
+       rsp_hdr->Command = SMB_COM_NEGOTIATE;
+       *(__le32 *)rsp_hdr->Protocol = SMB1_PROTO_NUMBER;
+       rsp_hdr->Flags = SMBFLG_RESPONSE;
+       rsp_hdr->Flags2 = SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS |
+               SMBFLG2_EXT_SEC | SMBFLG2_IS_LONG_NAME;
+       rsp_hdr->Pid = rcv_hdr->Pid;
+       rsp_hdr->Mid = rcv_hdr->Mid;
+       return 0;
+}
+
+/**
+ * smb1_check_user_session() - check for valid session for a user
+ * @work:      smb work containing smb request buffer
+ *
+ * Return:      0 on success, otherwise error
+ */
+static int smb1_check_user_session(struct ksmbd_work *work)
+{
+       unsigned int cmd = work->conn->ops->get_cmd_val(work);
+
+       if (cmd == SMB_COM_NEGOTIATE_EX)
                return 0;
 
-       init_smb3_11_server(conn);
+       return -EINVAL;
+}
+
+/**
+ * smb1_allocate_rsp_buf() - allocate response buffer for a command
+ * @work:      smb work containing smb request
+ *
+ * Return:      0 on success, otherwise -ENOMEM
+ */
+static int smb1_allocate_rsp_buf(struct ksmbd_work *work)
+{
+       work->response_buf = kmalloc(MAX_CIFS_SMALL_BUFFER_SIZE,
+                       GFP_KERNEL | __GFP_ZERO);
+       work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
+
+       if (!work->response_buf) {
+               pr_err("Failed to allocate %u bytes buffer\n",
+                               MAX_CIFS_SMALL_BUFFER_SIZE);
+               return -ENOMEM;
+       }
 
-       if (conn->ops->get_cmd_val(work) != SMB_COM_NEGOTIATE)
-               conn->need_neg = false;
        return 0;
 }
 
+static struct smb_version_ops smb1_server_ops = {
+       .get_cmd_val = get_smb1_cmd_val,
+       .init_rsp_hdr = init_smb1_rsp_hdr,
+       .allocate_rsp_buf = smb1_allocate_rsp_buf,
+       .check_user_session = smb1_check_user_session,
+};
+
+static int smb1_negotiate(struct ksmbd_work *work)
+{
+       return ksmbd_smb_negotiate_common(work, SMB_COM_NEGOTIATE);
+}
+
+static struct smb_version_cmds smb1_server_cmds[1] = {
+       [SMB_COM_NEGOTIATE_EX]  = { .proc = smb1_negotiate, },
+};
+
+static void init_smb1_server(struct ksmbd_conn *conn)
+{
+       conn->ops = &smb1_server_ops;
+       conn->cmds = smb1_server_cmds;
+       conn->max_cmds = ARRAY_SIZE(smb1_server_cmds);
+}
+
+void ksmbd_init_smb_server(struct ksmbd_work *work)
+{
+       struct ksmbd_conn *conn = work->conn;
+       __le32 proto;
+
+       if (conn->need_neg == false)
+               return;
+
+       proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol;
+       if (proto == SMB1_PROTO_NUMBER)
+               init_smb1_server(conn);
+       else
+               init_smb3_11_server(conn);
+}
+
 int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level,
                                      struct ksmbd_file *dir,
                                      struct ksmbd_dir_info *d_info,
@@ -444,20 +545,10 @@ static int smb_handle_negotiate(struct ksmbd_work *work)
 
        ksmbd_debug(SMB, "Unsupported SMB1 protocol\n");
 
-       /*
-        * Remove 4 byte direct TCP header, add 2 byte bcc and
-        * 2 byte DialectIndex.
-        */
-       *(__be32 *)work->response_buf =
-               cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2 + 2);
+       /* Add 2 byte bcc and 2 byte DialectIndex. */
+       inc_rfc1001_len(work->response_buf, 4);
        neg_rsp->hdr.Status.CifsError = STATUS_SUCCESS;
 
-       neg_rsp->hdr.Command = SMB_COM_NEGOTIATE;
-       *(__le32 *)neg_rsp->hdr.Protocol = SMB1_PROTO_NUMBER;
-       neg_rsp->hdr.Flags = SMBFLG_RESPONSE;
-       neg_rsp->hdr.Flags2 = SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS |
-               SMBFLG2_EXT_SEC | SMBFLG2_IS_LONG_NAME;
-
        neg_rsp->hdr.WordCount = 1;
        neg_rsp->DialectIndex = cpu_to_le16(work->conn->dialect);
        neg_rsp->ByteCount = 0;
@@ -474,23 +565,12 @@ int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command)
        ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
 
        if (command == SMB2_NEGOTIATE_HE) {
-               struct smb2_hdr *smb2_hdr = smb2_get_msg(work->request_buf);
-
-               if (smb2_hdr->ProtocolId != SMB2_PROTO_NUMBER) {
-                       ksmbd_debug(SMB, "Downgrade to SMB1 negotiation\n");
-                       command = SMB_COM_NEGOTIATE;
-               }
-       }
-
-       if (command == SMB2_NEGOTIATE_HE) {
                ret = smb2_handle_negotiate(work);
-               init_smb2_neg_rsp(work);
                return ret;
        }
 
        if (command == SMB_COM_NEGOTIATE) {
                if (__smb2_negotiate(conn)) {
-                       conn->need_neg = true;
                        init_smb3_11_server(conn);
                        init_smb2_neg_rsp(work);
                        ksmbd_debug(SMB, "Upgrade to SMB2 negotiation\n");
index d30ce4c..9130d2e 100644 (file)
@@ -427,7 +427,7 @@ bool ksmbd_smb_request(struct ksmbd_conn *conn);
 
 int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count);
 
-int ksmbd_init_smb_server(struct ksmbd_work *work);
+void ksmbd_init_smb_server(struct ksmbd_work *work);
 
 struct ksmbd_kstat;
 int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work,
index a0db699..9ae6769 100644 (file)
@@ -114,24 +114,6 @@ cp_convert:
 }
 
 /*
- * is_char_allowed() - check for valid character
- * @ch:                input character to be checked
- *
- * Return:     1 if char is allowed, otherwise 0
- */
-static inline int is_char_allowed(char *ch)
-{
-       /* check for control chars, wildcards etc. */
-       if (!(*ch & 0x80) &&
-           (*ch <= 0x1f ||
-            *ch == '?' || *ch == '"' || *ch == '<' ||
-            *ch == '>' || *ch == '|'))
-               return 0;
-
-       return 1;
-}
-
-/*
  * smb_from_utf16() - convert utf16le string to local charset
  * @to:                destination buffer
  * @from:      source buffer
index bc0f152..6836e93 100644 (file)
@@ -4183,9 +4183,9 @@ out:
        unlock_mount_hash();
 
        if (kattr->propagation) {
-               namespace_unlock();
                if (err)
                        cleanup_group_ids(mnt, NULL);
+               namespace_unlock();
        }
 
        return err;
index 450d6c3..c1c7ed2 100644 (file)
@@ -75,7 +75,6 @@ config NFS_V3_ACL
 config NFS_V4
        tristate "NFS client support for NFS version 4"
        depends on NFS_FS
-       select RPCSEC_GSS_KRB5
        select KEYS
        help
          This option enables support for version 4 of the NFS protocol
index 04697f8..01d7fd1 100644 (file)
@@ -297,6 +297,7 @@ nfsd4_block_get_device_info_scsi(struct super_block *sb,
 
 out_free_dev:
        kfree(dev);
+       gdp->gd_device = NULL;
        return ret;
 }
 
index 2a815f5..4039ffc 100644 (file)
@@ -946,8 +946,8 @@ static const struct cred *get_backchannel_cred(struct nfs4_client *clp, struct r
                if (!kcred)
                        return NULL;
 
-               kcred->uid = ses->se_cb_sec.uid;
-               kcred->gid = ses->se_cb_sec.gid;
+               kcred->fsuid = ses->se_cb_sec.uid;
+               kcred->fsgid = ses->se_cb_sec.gid;
                return kcred;
        }
 }
index e12e5a4..e2e4851 100644 (file)
@@ -2476,10 +2476,12 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
        for (i = 0; i < argp->opcnt; i++) {
                op = &argp->ops[i];
                op->replay = NULL;
+               op->opdesc = NULL;
 
                if (xdr_stream_decode_u32(argp->xdr, &op->opnum) < 0)
                        return false;
                if (nfsd4_opnum_in_range(argp, op)) {
+                       op->opdesc = OPDESC(op);
                        op->status = nfsd4_dec_ops[op->opnum](argp, &op->u);
                        if (op->status != nfs_ok)
                                trace_nfsd_compound_decode_err(argp->rqstp,
@@ -2490,7 +2492,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
                        op->opnum = OP_ILLEGAL;
                        op->status = nfserr_op_illegal;
                }
-               op->opdesc = OPDESC(op);
+
                /*
                 * We'll try to cache the result in the DRC if any one
                 * op in the compound wants to be cached:
@@ -5400,10 +5402,8 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
        __be32 *p;
 
        p = xdr_reserve_space(xdr, 8);
-       if (!p) {
-               WARN_ON_ONCE(1);
-               return;
-       }
+       if (!p)
+               goto release;
        *p++ = cpu_to_be32(op->opnum);
        post_err_offset = xdr->buf->len;
 
@@ -5418,8 +5418,6 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
        op->status = encoder(resp, op->status, &op->u);
        if (op->status)
                trace_nfsd_compound_encode_err(rqstp, op->opnum, op->status);
-       if (opdesc && opdesc->op_release)
-               opdesc->op_release(&op->u);
        xdr_commit_encode(xdr);
 
        /* nfsd4_check_resp_size guarantees enough room for error status */
@@ -5460,6 +5458,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
        }
 status:
        *p = op->status;
+release:
+       if (opdesc && opdesc->op_release)
+               opdesc->op_release(&op->u);
 }
 
 /* 
index 2681a44..13592e8 100644 (file)
@@ -2219,6 +2219,7 @@ static int nilfs_btree_assign_p(struct nilfs_bmap *btree,
        /* on-disk format */
        binfo->bi_dat.bi_blkoff = cpu_to_le64(key);
        binfo->bi_dat.bi_level = level;
+       memset(binfo->bi_dat.bi_pad, 0, sizeof(binfo->bi_dat.bi_pad));
 
        return 0;
 }
index a35f279..4c85914 100644 (file)
@@ -314,6 +314,7 @@ static int nilfs_direct_assign_p(struct nilfs_bmap *direct,
 
        binfo->bi_dat.bi_blkoff = cpu_to_le64(key);
        binfo->bi_dat.bi_level = 0;
+       memset(binfo->bi_dat.bi_pad, 0, sizeof(binfo->bi_dat.bi_pad));
 
        return 0;
 }
index 19446a8..6ad4139 100644 (file)
@@ -2609,11 +2609,10 @@ static int nilfs_segctor_thread(void *arg)
        goto loop;
 
  end_thread:
-       spin_unlock(&sci->sc_state_lock);
-
        /* end sync. */
        sci->sc_task = NULL;
        wake_up(&sci->sc_wait_task); /* for nilfs_segctor_kill_thread() */
+       spin_unlock(&sci->sc_state_lock);
        return 0;
 }
 
index 1422b8b..77f1e57 100644 (file)
@@ -482,6 +482,7 @@ static void nilfs_put_super(struct super_block *sb)
                up_write(&nilfs->ns_sem);
        }
 
+       nilfs_sysfs_delete_device_group(nilfs);
        iput(nilfs->ns_sufile);
        iput(nilfs->ns_cpfile);
        iput(nilfs->ns_dat);
@@ -1105,6 +1106,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent)
        nilfs_put_root(fsroot);
 
  failed_unload:
+       nilfs_sysfs_delete_device_group(nilfs);
        iput(nilfs->ns_sufile);
        iput(nilfs->ns_cpfile);
        iput(nilfs->ns_dat);
index 3a4c9c1..2894152 100644 (file)
@@ -87,7 +87,6 @@ void destroy_nilfs(struct the_nilfs *nilfs)
 {
        might_sleep();
        if (nilfs_init(nilfs)) {
-               nilfs_sysfs_delete_device_group(nilfs);
                brelse(nilfs->ns_sbh[0]);
                brelse(nilfs->ns_sbh[1]);
        }
@@ -305,6 +304,10 @@ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
                goto failed;
        }
 
+       err = nilfs_sysfs_create_device_group(sb);
+       if (unlikely(err))
+               goto sysfs_error;
+
        if (valid_fs)
                goto skip_recovery;
 
@@ -366,6 +369,9 @@ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
        goto failed;
 
  failed_unload:
+       nilfs_sysfs_delete_device_group(nilfs);
+
+ sysfs_error:
        iput(nilfs->ns_cpfile);
        iput(nilfs->ns_sufile);
        iput(nilfs->ns_dat);
@@ -697,10 +703,6 @@ int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data)
        if (err)
                goto failed_sbh;
 
-       err = nilfs_sysfs_create_device_group(sb);
-       if (err)
-               goto failed_sbh;
-
        set_nilfs_init(nilfs);
        err = 0;
  out:
index 8ed9bec..ff5a8da 100644 (file)
@@ -59,8 +59,6 @@ extern void acpi_video_unregister(void);
 extern void acpi_video_register_backlight(void);
 extern int acpi_video_get_edid(struct acpi_device *device, int type,
                               int device_id, void **edid);
-extern enum acpi_backlight_type acpi_video_get_backlight_type(void);
-extern bool acpi_video_backlight_use_native(void);
 /*
  * Note: The value returned by acpi_video_handles_brightness_key_presses()
  * may change over time and should not be cached.
@@ -69,6 +67,19 @@ extern bool acpi_video_handles_brightness_key_presses(void);
 extern int acpi_video_get_levels(struct acpi_device *device,
                                 struct acpi_video_device_brightness **dev_br,
                                 int *pmax_level);
+
+extern enum acpi_backlight_type __acpi_video_get_backlight_type(bool native,
+                                                               bool *auto_detect);
+
+static inline enum acpi_backlight_type acpi_video_get_backlight_type(void)
+{
+       return __acpi_video_get_backlight_type(false, NULL);
+}
+
+static inline bool acpi_video_backlight_use_native(void)
+{
+       return __acpi_video_get_backlight_type(true, NULL) == acpi_backlight_native;
+}
 #else
 static inline void acpi_video_report_nolcd(void) { return; };
 static inline int acpi_video_register(void) { return -ENODEV; }
index 04b8be9..e271d67 100644 (file)
@@ -130,7 +130,7 @@ ATOMIC_OP(xor, ^)
 #define arch_atomic_read(v)                    READ_ONCE((v)->counter)
 #define arch_atomic_set(v, i)                  WRITE_ONCE(((v)->counter), (i))
 
-#define arch_atomic_xchg(ptr, v)               (arch_xchg(&(ptr)->counter, (v)))
-#define arch_atomic_cmpxchg(v, old, new)       (arch_cmpxchg(&((v)->counter), (old), (new)))
+#define arch_atomic_xchg(ptr, v)               (arch_xchg(&(ptr)->counter, (u32)(v)))
+#define arch_atomic_cmpxchg(v, old, new)       (arch_cmpxchg(&((v)->counter), (u32)(old), (u32)(new)))
 
 #endif /* __ASM_GENERIC_ATOMIC_H */
index c3e7315..3df9f59 100644 (file)
@@ -26,16 +26,16 @@ static inline unsigned long __generic_cmpxchg_local(volatile void *ptr,
        raw_local_irq_save(flags);
        switch (size) {
        case 1: prev = *(u8 *)ptr;
-               if (prev == (u8)old)
-                       *(u8 *)ptr = (u8)new;
+               if (prev == (old & 0xffu))
+                       *(u8 *)ptr = (new & 0xffu);
                break;
        case 2: prev = *(u16 *)ptr;
-               if (prev == (u16)old)
-                       *(u16 *)ptr = (u16)new;
+               if (prev == (old & 0xffffu))
+                       *(u16 *)ptr = (new & 0xffffu);
                break;
        case 4: prev = *(u32 *)ptr;
-               if (prev == (u32)old)
-                       *(u32 *)ptr = (u32)new;
+               if (prev == (old & 0xffffffffffu))
+                       *(u32 *)ptr = (new & 0xffffffffu);
                break;
        case 8: prev = *(u64 *)ptr;
                if (prev == old)
index dca4419..848de25 100644 (file)
@@ -32,7 +32,7 @@ unsigned long __generic_xchg(unsigned long x, volatile void *ptr, int size)
 #else
                local_irq_save(flags);
                ret = *(volatile u8 *)ptr;
-               *(volatile u8 *)ptr = x;
+               *(volatile u8 *)ptr = (x & 0xffu);
                local_irq_restore(flags);
                return ret;
 #endif /* __xchg_u8 */
@@ -43,7 +43,7 @@ unsigned long __generic_xchg(unsigned long x, volatile void *ptr, int size)
 #else
                local_irq_save(flags);
                ret = *(volatile u16 *)ptr;
-               *(volatile u16 *)ptr = x;
+               *(volatile u16 *)ptr = (x & 0xffffu);
                local_irq_restore(flags);
                return ret;
 #endif /* __xchg_u16 */
@@ -54,7 +54,7 @@ unsigned long __generic_xchg(unsigned long x, volatile void *ptr, int size)
 #else
                local_irq_save(flags);
                ret = *(volatile u32 *)ptr;
-               *(volatile u32 *)ptr = x;
+               *(volatile u32 *)ptr = (x & 0xffffffffu);
                local_irq_restore(flags);
                return ret;
 #endif /* __xchg_u32 */
index 4c44a29..587e7e9 100644 (file)
@@ -236,7 +236,7 @@ static inline u64 readq(const volatile void __iomem *addr)
 
        log_read_mmio(64, addr, _THIS_IP_, _RET_IP_);
        __io_br();
-       val = __le64_to_cpu(__raw_readq(addr));
+       val = __le64_to_cpu((__le64 __force)__raw_readq(addr));
        __io_ar(val);
        log_post_read_mmio(val, 64, addr, _THIS_IP_, _RET_IP_);
        return val;
@@ -287,7 +287,7 @@ static inline void writeq(u64 value, volatile void __iomem *addr)
 {
        log_write_mmio(value, 64, addr, _THIS_IP_, _RET_IP_);
        __io_bw();
-       __raw_writeq(__cpu_to_le64(value), addr);
+       __raw_writeq((u64 __force)__cpu_to_le64(value), addr);
        __io_aw();
        log_post_write_mmio(value, 64, addr, _THIS_IP_, _RET_IP_);
 }
@@ -319,7 +319,7 @@ static inline u16 readw_relaxed(const volatile void __iomem *addr)
        u16 val;
 
        log_read_mmio(16, addr, _THIS_IP_, _RET_IP_);
-       val = __le16_to_cpu(__raw_readw(addr));
+       val = __le16_to_cpu((__le16 __force)__raw_readw(addr));
        log_post_read_mmio(val, 16, addr, _THIS_IP_, _RET_IP_);
        return val;
 }
@@ -332,7 +332,7 @@ static inline u32 readl_relaxed(const volatile void __iomem *addr)
        u32 val;
 
        log_read_mmio(32, addr, _THIS_IP_, _RET_IP_);
-       val = __le32_to_cpu(__raw_readl(addr));
+       val = __le32_to_cpu((__le32 __force)__raw_readl(addr));
        log_post_read_mmio(val, 32, addr, _THIS_IP_, _RET_IP_);
        return val;
 }
@@ -345,7 +345,7 @@ static inline u64 readq_relaxed(const volatile void __iomem *addr)
        u64 val;
 
        log_read_mmio(64, addr, _THIS_IP_, _RET_IP_);
-       val = __le64_to_cpu(__raw_readq(addr));
+       val = __le64_to_cpu((__le64 __force)__raw_readq(addr));
        log_post_read_mmio(val, 64, addr, _THIS_IP_, _RET_IP_);
        return val;
 }
@@ -366,7 +366,7 @@ static inline void writeb_relaxed(u8 value, volatile void __iomem *addr)
 static inline void writew_relaxed(u16 value, volatile void __iomem *addr)
 {
        log_write_mmio(value, 16, addr, _THIS_IP_, _RET_IP_);
-       __raw_writew(cpu_to_le16(value), addr);
+       __raw_writew((u16 __force)cpu_to_le16(value), addr);
        log_post_write_mmio(value, 16, addr, _THIS_IP_, _RET_IP_);
 }
 #endif
@@ -376,7 +376,7 @@ static inline void writew_relaxed(u16 value, volatile void __iomem *addr)
 static inline void writel_relaxed(u32 value, volatile void __iomem *addr)
 {
        log_write_mmio(value, 32, addr, _THIS_IP_, _RET_IP_);
-       __raw_writel(__cpu_to_le32(value), addr);
+       __raw_writel((u32 __force)__cpu_to_le32(value), addr);
        log_post_write_mmio(value, 32, addr, _THIS_IP_, _RET_IP_);
 }
 #endif
@@ -386,7 +386,7 @@ static inline void writel_relaxed(u32 value, volatile void __iomem *addr)
 static inline void writeq_relaxed(u64 value, volatile void __iomem *addr)
 {
        log_write_mmio(value, 64, addr, _THIS_IP_, _RET_IP_);
-       __raw_writeq(__cpu_to_le64(value), addr);
+       __raw_writeq((u64 __force)__cpu_to_le64(value), addr);
        log_post_write_mmio(value, 64, addr, _THIS_IP_, _RET_IP_);
 }
 #endif
index 366c730..402fc06 100644 (file)
@@ -980,7 +980,7 @@ static inline void __ftrace_enabled_restore(int enabled)
 #define CALLER_ADDR5 ((unsigned long)ftrace_return_address(5))
 #define CALLER_ADDR6 ((unsigned long)ftrace_return_address(6))
 
-static inline unsigned long get_lock_parent_ip(void)
+static __always_inline unsigned long get_lock_parent_ip(void)
 {
        unsigned long addr = CALLER_ADDR0;
 
index 8ada237..a9adf75 100644 (file)
@@ -755,6 +755,7 @@ struct kvm {
        struct {
                spinlock_t        lock;
                struct list_head  items;
+               /* resampler_list update side is protected by resampler_lock. */
                struct list_head  resampler_list;
                struct mutex      resampler_lock;
        } irqfds;
@@ -1986,6 +1987,9 @@ int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args);
 #ifdef CONFIG_HAVE_KVM_IRQFD
 int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args);
 void kvm_irqfd_release(struct kvm *kvm);
+bool kvm_notify_irqfd_resampler(struct kvm *kvm,
+                               unsigned int irqchip,
+                               unsigned int pin);
 void kvm_irq_routing_update(struct kvm *);
 #else
 static inline int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args)
@@ -1994,6 +1998,13 @@ static inline int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args)
 }
 
 static inline void kvm_irqfd_release(struct kvm *kvm) {}
+
+static inline bool kvm_notify_irqfd_resampler(struct kvm *kvm,
+                                             unsigned int irqchip,
+                                             unsigned int pin)
+{
+       return false;
+}
 #endif
 
 #else
index dac047a..8ad4369 100644 (file)
@@ -31,7 +31,7 @@ struct kvm_kernel_irqfd_resampler {
        /*
         * Entry in list of kvm->irqfd.resampler_list.  Use for sharing
         * resamplers among irqfds on the same gsi.
-        * Accessed and modified under kvm->irqfds.resampler_lock
+        * RCU list modified under kvm->irqfds.resampler_lock
         */
        struct list_head link;
 };
index 0722859..a57e6ae 100644 (file)
@@ -774,7 +774,8 @@ struct mm_struct {
        unsigned long cpu_bitmap[];
 };
 
-#define MM_MT_FLAGS    (MT_FLAGS_ALLOC_RANGE | MT_FLAGS_LOCK_EXTERN)
+#define MM_MT_FLAGS    (MT_FLAGS_ALLOC_RANGE | MT_FLAGS_LOCK_EXTERN | \
+                        MT_FLAGS_USE_RCU)
 extern struct mm_struct init_mm;
 
 /* Pointer magic because the dynamic array size confuses some compilers. */
index ed9b4df..43765ea 100644 (file)
@@ -34,6 +34,10 @@ struct pci_doe_mb;
  * @work: Used internally by the mailbox
  * @doe_mb: Used internally by the mailbox
  *
+ * Payloads are treated as opaque byte streams which are transmitted verbatim,
+ * without byte-swapping.  If payloads contain little-endian register values,
+ * the caller is responsible for conversion with cpu_to_le32() / le32_to_cpu().
+ *
  * The payload sizes and rv are specified in bytes with the following
  * restrictions concerning the protocol.
  *
@@ -45,9 +49,9 @@ struct pci_doe_mb;
  */
 struct pci_doe_task {
        struct pci_doe_protocol prot;
-       u32 *request_pl;
+       __le32 *request_pl;
        size_t request_pl_sz;
-       u32 *response_pl;
+       __le32 *response_pl;
        size_t response_pl_sz;
        int rv;
        void (*complete)(struct pci_doe_task *task);
index c492c26..637698e 100644 (file)
@@ -574,6 +574,7 @@ struct phylink *phylink_create(struct phylink_config *, struct fwnode_handle *,
                               phy_interface_t iface,
                               const struct phylink_mac_ops *mac_ops);
 void phylink_destroy(struct phylink *);
+bool phylink_expects_phy(struct phylink *pl);
 
 int phylink_connect_phy(struct phylink *, struct phy_device *);
 int phylink_of_phy_connect(struct phylink *, struct device_node *, u32 flags);
index 2c004c2..3af5289 100644 (file)
@@ -37,7 +37,7 @@ int raw_rcv(struct sock *, struct sk_buff *);
 struct raw_hashinfo {
        spinlock_t lock;
 
-       struct hlist_nulls_head ht[RAW_HTABLE_SIZE] ____cacheline_aligned;
+       struct hlist_head ht[RAW_HTABLE_SIZE] ____cacheline_aligned;
 };
 
 static inline u32 raw_hashfunc(const struct net *net, u32 proto)
@@ -51,7 +51,7 @@ static inline void raw_hashinfo_init(struct raw_hashinfo *hashinfo)
 
        spin_lock_init(&hashinfo->lock);
        for (i = 0; i < RAW_HTABLE_SIZE; i++)
-               INIT_HLIST_NULLS_HEAD(&hashinfo->ht[i], i);
+               INIT_HLIST_HEAD(&hashinfo->ht[i]);
 }
 
 #ifdef CONFIG_PROC_FS
index ac5c24d..e30a13b 100644 (file)
@@ -9,17 +9,30 @@
 #undef __entry
 #define __entry entry
 
+/*
+ * Fields should never declare an array: i.e. __field(int, arr[5])
+ * If they do, it will cause issues in parsing and possibly corrupt the
+ * events. To prevent that from happening, test the sizeof() a fictitious
+ * type called "struct _test_no_array_##item" which will fail if "item"
+ * contains array elements (like "arr[5]").
+ *
+ * If you hit this, use __array(int, arr, 5) instead.
+ */
 #undef __field
-#define __field(type, item)
+#define __field(type, item)                                    \
+       { (void)sizeof(struct _test_no_array_##item *); }
 
 #undef __field_ext
-#define __field_ext(type, item, filter_type)
+#define __field_ext(type, item, filter_type)                   \
+       { (void)sizeof(struct _test_no_array_##item *); }
 
 #undef __field_struct
-#define __field_struct(type, item)
+#define __field_struct(type, item)                             \
+       { (void)sizeof(struct _test_no_array_##item *); }
 
 #undef __field_struct_ext
-#define __field_struct_ext(type, item, filter_type)
+#define __field_struct_ext(type, item, filter_type)            \
+       { (void)sizeof(struct _test_no_array_##item *); }
 
 #undef __array
 #define __array(type, item, len)
index 5af2a03..3744e4d 100644 (file)
@@ -140,11 +140,11 @@ struct virtio_blk_config {
 
        /* Zoned block device characteristics (if VIRTIO_BLK_F_ZONED) */
        struct virtio_blk_zoned_characteristics {
-               __le32 zone_sectors;
-               __le32 max_open_zones;
-               __le32 max_active_zones;
-               __le32 max_append_sectors;
-               __le32 write_granularity;
+               __virtio32 zone_sectors;
+               __virtio32 max_open_zones;
+               __virtio32 max_active_zones;
+               __virtio32 max_append_sectors;
+               __virtio32 write_granularity;
                __u8 model;
                __u8 unused2[3];
        } zoned;
@@ -241,11 +241,11 @@ struct virtio_blk_outhdr {
  */
 struct virtio_blk_zone_descriptor {
        /* Zone capacity */
-       __le64 z_cap;
+       __virtio64 z_cap;
        /* The starting sector of the zone */
-       __le64 z_start;
+       __virtio64 z_start;
        /* Zone write pointer position in sectors */
-       __le64 z_wp;
+       __virtio64 z_wp;
        /* Zone type */
        __u8 z_type;
        /* Zone state */
@@ -254,7 +254,7 @@ struct virtio_blk_zone_descriptor {
 };
 
 struct virtio_blk_zone_report {
-       __le64 nr_zones;
+       __virtio64 nr_zones;
        __u8 reserved[56];
        struct virtio_blk_zone_descriptor zones[];
 };
index 25aab8e..431c3af 100644 (file)
@@ -979,7 +979,6 @@ struct ufs_hba {
        struct completion *uic_async_done;
 
        enum ufshcd_state ufshcd_state;
-       bool logical_unit_scan_finished;
        u32 eh_flags;
        u32 intr_mask;
        u16 ee_ctrl_mask;
index 722624b..2a8b8c3 100644 (file)
@@ -2789,8 +2789,8 @@ static __cold void io_ring_ctx_free(struct io_ring_ctx *ctx)
        io_eventfd_unregister(ctx);
        io_alloc_cache_free(&ctx->apoll_cache, io_apoll_cache_free);
        io_alloc_cache_free(&ctx->netmsg_cache, io_netmsg_cache_free);
-       mutex_unlock(&ctx->uring_lock);
        io_destroy_buffers(ctx);
+       mutex_unlock(&ctx->uring_lock);
        if (ctx->sq_creds)
                put_cred(ctx->sq_creds);
        if (ctx->submitter_task)
index 3002dc8..a90c820 100644 (file)
@@ -228,17 +228,18 @@ static int __io_remove_buffers(struct io_ring_ctx *ctx,
                return i;
        }
 
-       /* the head kbuf is the list itself */
+       /* protects io_buffers_cache */
+       lockdep_assert_held(&ctx->uring_lock);
+
        while (!list_empty(&bl->buf_list)) {
                struct io_buffer *nxt;
 
                nxt = list_first_entry(&bl->buf_list, struct io_buffer, list);
-               list_del(&nxt->list);
+               list_move(&nxt->list, &ctx->io_buffers_cache);
                if (++i == nbufs)
                        return i;
                cond_resched();
        }
-       i++;
 
        return i;
 }
index 5b919ef..dac42a2 100644 (file)
@@ -623,7 +623,7 @@ static int swiotlb_do_find_slots(struct device *dev, int area_index,
                phys_to_dma_unencrypted(dev, mem->start) & boundary_mask;
        unsigned long max_slots = get_max_slots(boundary_mask);
        unsigned int iotlb_align_mask =
-               dma_get_min_align_mask(dev) & ~(IO_TLB_SIZE - 1);
+               dma_get_min_align_mask(dev) | alloc_align_mask;
        unsigned int nslots = nr_slots(alloc_size), stride;
        unsigned int offset = swiotlb_align_offset(dev, orig_addr);
        unsigned int index, slots_checked, count = 0, i;
@@ -639,8 +639,8 @@ static int swiotlb_do_find_slots(struct device *dev, int area_index,
         * allocations.
         */
        if (alloc_size >= PAGE_SIZE)
-               iotlb_align_mask &= PAGE_MASK;
-       iotlb_align_mask &= alloc_align_mask;
+               iotlb_align_mask |= ~PAGE_MASK;
+       iotlb_align_mask &= ~(IO_TLB_SIZE - 1);
 
        /*
         * For mappings with an alignment requirement don't bother looping to
index fb3e436..435815d 100644 (file)
@@ -12173,7 +12173,7 @@ perf_event_set_output(struct perf_event *event, struct perf_event *output_event)
        /*
         * If its not a per-cpu rb, it must be the same task.
         */
-       if (output_event->cpu == -1 && output_event->ctx != event->ctx)
+       if (output_event->cpu == -1 && output_event->hw.target != event->hw.target)
                goto out;
 
        /*
@@ -12893,12 +12893,14 @@ void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu)
        __perf_pmu_remove(src_ctx, src_cpu, pmu, &src_ctx->pinned_groups, &events);
        __perf_pmu_remove(src_ctx, src_cpu, pmu, &src_ctx->flexible_groups, &events);
 
-       /*
-        * Wait for the events to quiesce before re-instating them.
-        */
-       synchronize_rcu();
+       if (!list_empty(&events)) {
+               /*
+                * Wait for the events to quiesce before re-instating them.
+                */
+               synchronize_rcu();
 
-       __perf_pmu_install(dst_ctx, dst_cpu, pmu, &events);
+               __perf_pmu_install(dst_ctx, dst_cpu, pmu, &events);
+       }
 
        mutex_unlock(&dst_ctx->mutex);
        mutex_unlock(&src_ctx->mutex);
index c0257cb..0c92f22 100644 (file)
@@ -617,6 +617,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
        if (retval)
                goto out;
 
+       mt_clear_in_rcu(vmi.mas.tree);
        for_each_vma(old_vmi, mpnt) {
                struct file *file;
 
@@ -700,6 +701,8 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
        retval = arch_dup_mmap(oldmm, mm);
 loop_out:
        vma_iter_free(&vmi);
+       if (!retval)
+               mt_set_in_rcu(vmi.mas.tree);
 out:
        mmap_write_unlock(mm);
        flush_tlb_mm(oldmm);
index 8e880c0..7b95ee9 100644 (file)
@@ -3024,6 +3024,18 @@ need_offload_krc(struct kfree_rcu_cpu *krcp)
        return !!READ_ONCE(krcp->head);
 }
 
+static bool
+need_wait_for_krwp_work(struct kfree_rcu_cpu_work *krwp)
+{
+       int i;
+
+       for (i = 0; i < FREE_N_CHANNELS; i++)
+               if (!list_empty(&krwp->bulk_head_free[i]))
+                       return true;
+
+       return !!krwp->head_free;
+}
+
 static int krc_count(struct kfree_rcu_cpu *krcp)
 {
        int sum = atomic_read(&krcp->head_count);
@@ -3107,15 +3119,14 @@ static void kfree_rcu_monitor(struct work_struct *work)
        for (i = 0; i < KFREE_N_BATCHES; i++) {
                struct kfree_rcu_cpu_work *krwp = &(krcp->krw_arr[i]);
 
-               // Try to detach bulk_head or head and attach it over any
-               // available corresponding free channel. It can be that
-               // a previous RCU batch is in progress, it means that
-               // immediately to queue another one is not possible so
-               // in that case the monitor work is rearmed.
-               if ((!list_empty(&krcp->bulk_head[0]) && list_empty(&krwp->bulk_head_free[0])) ||
-                       (!list_empty(&krcp->bulk_head[1]) && list_empty(&krwp->bulk_head_free[1])) ||
-                               (READ_ONCE(krcp->head) && !krwp->head_free)) {
+               // Try to detach bulk_head or head and attach it, only when
+               // all channels are free.  Any channel is not free means at krwp
+               // there is on-going rcu work to handle krwp's free business.
+               if (need_wait_for_krwp_work(krwp))
+                       continue;
 
+               // kvfree_rcu_drain_ready() might handle this krcp, if so give up.
+               if (need_offload_krc(krcp)) {
                        // Channel 1 corresponds to the SLAB-pointer bulk path.
                        // Channel 2 corresponds to vmalloc-pointer bulk path.
                        for (j = 0; j < FREE_N_CHANNELS; j++) {
index 0feea14..c67bcc8 100644 (file)
@@ -5667,12 +5667,15 @@ int modify_ftrace_direct(unsigned long ip,
                ret = 0;
        }
 
-       if (unlikely(ret && new_direct)) {
-               direct->count++;
-               list_del_rcu(&new_direct->next);
-               synchronize_rcu_tasks();
-               kfree(new_direct);
-               ftrace_direct_func_count--;
+       if (ret) {
+               direct->addr = old_addr;
+               if (unlikely(new_direct)) {
+                       direct->count++;
+                       list_del_rcu(&new_direct->next);
+                       synchronize_rcu_tasks();
+                       kfree(new_direct);
+                       ftrace_direct_func_count--;
+               }
        }
 
  out_unlock:
index c6f47b6..76a2d91 100644 (file)
@@ -3098,6 +3098,10 @@ rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer)
                if (RB_WARN_ON(cpu_buffer,
                               rb_is_reader_page(cpu_buffer->tail_page)))
                        return;
+               /*
+                * No need for a memory barrier here, as the update
+                * of the tail_page did it for this page.
+                */
                local_set(&cpu_buffer->commit_page->page->commit,
                          rb_page_write(cpu_buffer->commit_page));
                rb_inc_page(&cpu_buffer->commit_page);
@@ -3107,6 +3111,8 @@ rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer)
        while (rb_commit_index(cpu_buffer) !=
               rb_page_write(cpu_buffer->commit_page)) {
 
+               /* Make sure the readers see the content of what is committed. */
+               smp_wmb();
                local_set(&cpu_buffer->commit_page->page->commit,
                          rb_page_write(cpu_buffer->commit_page));
                RB_WARN_ON(cpu_buffer,
@@ -4684,7 +4690,12 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
 
        /*
         * Make sure we see any padding after the write update
-        * (see rb_reset_tail())
+        * (see rb_reset_tail()).
+        *
+        * In addition, a writer may be writing on the reader page
+        * if the page has not been fully filled, so the read barrier
+        * is also needed to make sure we see the content of what is
+        * committed by the writer (see rb_set_commit_to_write()).
         */
        smp_rmb();
 
index 937e967..36a6037 100644 (file)
@@ -1149,22 +1149,22 @@ static void tracing_snapshot_instance_cond(struct trace_array *tr,
        unsigned long flags;
 
        if (in_nmi()) {
-               internal_trace_puts("*** SNAPSHOT CALLED FROM NMI CONTEXT ***\n");
-               internal_trace_puts("*** snapshot is being ignored        ***\n");
+               trace_array_puts(tr, "*** SNAPSHOT CALLED FROM NMI CONTEXT ***\n");
+               trace_array_puts(tr, "*** snapshot is being ignored        ***\n");
                return;
        }
 
        if (!tr->allocated_snapshot) {
-               internal_trace_puts("*** SNAPSHOT NOT ALLOCATED ***\n");
-               internal_trace_puts("*** stopping trace here!   ***\n");
-               tracing_off();
+               trace_array_puts(tr, "*** SNAPSHOT NOT ALLOCATED ***\n");
+               trace_array_puts(tr, "*** stopping trace here!   ***\n");
+               tracer_tracing_off(tr);
                return;
        }
 
        /* Note, snapshot can not be used when the tracer uses it */
        if (tracer->use_max_tr) {
-               internal_trace_puts("*** LATENCY TRACER ACTIVE ***\n");
-               internal_trace_puts("*** Can not use snapshot (sorry) ***\n");
+               trace_array_puts(tr, "*** LATENCY TRACER ACTIVE ***\n");
+               trace_array_puts(tr, "*** Can not use snapshot (sorry) ***\n");
                return;
        }
 
@@ -9516,6 +9516,7 @@ static int __remove_instance(struct trace_array *tr)
        tracefs_remove(tr->dir);
        free_percpu(tr->last_func_repeats);
        free_trace_buffers(tr);
+       clear_tracing_err_log(tr);
 
        for (i = 0; i < tr->nr_topts; i++) {
                kfree(tr->topts[i].topts);
@@ -10393,19 +10394,20 @@ out:
 
 void __init ftrace_boot_snapshot(void)
 {
+#ifdef CONFIG_TRACER_MAX_TRACE
        struct trace_array *tr;
 
-       if (snapshot_at_boot) {
-               tracing_snapshot();
-               internal_trace_puts("** Boot snapshot taken **\n");
-       }
+       if (!snapshot_at_boot)
+               return;
 
        list_for_each_entry(tr, &ftrace_trace_arrays, list) {
-               if (tr == &global_trace)
+               if (!tr->allocated_snapshot)
                        continue;
-               trace_array_puts(tr, "** Boot snapshot taken **\n");
+
                tracing_snapshot_instance(tr);
+               trace_array_puts(tr, "** Boot snapshot taken **\n");
        }
+#endif
 }
 
 void __init early_trace_init(void)
index 46d0abb..d6a70af 100644 (file)
@@ -44,14 +44,21 @@ enum { ERRORS };
 
 static const char *err_text[] = { ERRORS };
 
+static DEFINE_MUTEX(lastcmd_mutex);
 static char *last_cmd;
 
 static int errpos(const char *str)
 {
+       int ret = 0;
+
+       mutex_lock(&lastcmd_mutex);
        if (!str || !last_cmd)
-               return 0;
+               goto out;
 
-       return err_pos(last_cmd, str);
+       ret = err_pos(last_cmd, str);
+ out:
+       mutex_unlock(&lastcmd_mutex);
+       return ret;
 }
 
 static void last_cmd_set(const char *str)
@@ -59,18 +66,22 @@ static void last_cmd_set(const char *str)
        if (!str)
                return;
 
+       mutex_lock(&lastcmd_mutex);
        kfree(last_cmd);
-
        last_cmd = kstrdup(str, GFP_KERNEL);
+       mutex_unlock(&lastcmd_mutex);
 }
 
 static void synth_err(u8 err_type, u16 err_pos)
 {
+       mutex_lock(&lastcmd_mutex);
        if (!last_cmd)
-               return;
+               goto out;
 
        tracing_log_err(NULL, "synthetic_events", last_cmd, err_text,
                        err_type, err_pos);
+ out:
+       mutex_unlock(&lastcmd_mutex);
 }
 
 static int create_synth_event(const char *raw_command);
index 9176bb7..4496975 100644 (file)
@@ -1296,7 +1296,7 @@ static void notify_new_max_latency(u64 latency)
        rcu_read_lock();
        list_for_each_entry_rcu(inst, &osnoise_instances, list) {
                tr = inst->tr;
-               if (tr->max_latency < latency) {
+               if (tracer_tracing_is_on(tr) && tr->max_latency < latency) {
                        tr->max_latency = latency;
                        latency_fsnotify(tr);
                }
@@ -1738,6 +1738,8 @@ static int timerlat_main(void *data)
 
                trace_timerlat_sample(&s);
 
+               notify_new_max_latency(diff);
+
                timerlat_dump_stack(time_to_us(diff));
 
                tlat->tracing_thread = false;
index c8b379e..39d1d93 100644 (file)
@@ -1143,7 +1143,7 @@ menu "Scheduler Debugging"
 
 config SCHED_DEBUG
        bool "Collect scheduler debugging info"
-       depends on DEBUG_KERNEL && PROC_FS
+       depends on DEBUG_KERNEL && DEBUG_FS
        default y
        help
          If you say Y here, the /sys/kernel/debug/sched file will be provided
@@ -1392,7 +1392,7 @@ config LOCKDEP_STACK_TRACE_HASH_BITS
        range 10 30
        default 14
        help
-         Try increasing this value if you need large MAX_STACK_TRACE_ENTRIES.
+         Try increasing this value if you need large STACK_TRACE_HASH_SIZE.
 
 config LOCKDEP_CIRCULAR_QUEUE_BITS
        int "Bitsize for elements in circular_queue struct"
index 9e2735c..db60edb 100644 (file)
@@ -185,7 +185,7 @@ static void mt_free_rcu(struct rcu_head *head)
  */
 static void ma_free_rcu(struct maple_node *node)
 {
-       node->parent = ma_parent_ptr(node);
+       WARN_ON(node->parent != ma_parent_ptr(node));
        call_rcu(&node->rcu, mt_free_rcu);
 }
 
@@ -539,11 +539,14 @@ static inline struct maple_node *mte_parent(const struct maple_enode *enode)
  */
 static inline bool ma_dead_node(const struct maple_node *node)
 {
-       struct maple_node *parent = (void *)((unsigned long)
-                                            node->parent & ~MAPLE_NODE_MASK);
+       struct maple_node *parent;
 
+       /* Do not reorder reads from the node prior to the parent check */
+       smp_rmb();
+       parent = (void *)((unsigned long) node->parent & ~MAPLE_NODE_MASK);
        return (parent == node);
 }
+
 /*
  * mte_dead_node() - check if the @enode is dead.
  * @enode: The encoded maple node
@@ -555,6 +558,8 @@ static inline bool mte_dead_node(const struct maple_enode *enode)
        struct maple_node *parent, *node;
 
        node = mte_to_node(enode);
+       /* Do not reorder reads from the node prior to the parent check */
+       smp_rmb();
        parent = mte_parent(enode);
        return (parent == node);
 }
@@ -625,6 +630,8 @@ static inline unsigned int mas_alloc_req(const struct ma_state *mas)
  * @node - the maple node
  * @type - the node type
  *
+ * In the event of a dead node, this array may be %NULL
+ *
  * Return: A pointer to the maple node pivots
  */
 static inline unsigned long *ma_pivots(struct maple_node *node,
@@ -817,6 +824,11 @@ static inline void *mt_slot(const struct maple_tree *mt,
        return rcu_dereference_check(slots[offset], mt_locked(mt));
 }
 
+static inline void *mt_slot_locked(struct maple_tree *mt, void __rcu **slots,
+                                  unsigned char offset)
+{
+       return rcu_dereference_protected(slots[offset], mt_locked(mt));
+}
 /*
  * mas_slot_locked() - Get the slot value when holding the maple tree lock.
  * @mas: The maple state
@@ -828,7 +840,7 @@ static inline void *mt_slot(const struct maple_tree *mt,
 static inline void *mas_slot_locked(struct ma_state *mas, void __rcu **slots,
                                       unsigned char offset)
 {
-       return rcu_dereference_protected(slots[offset], mt_locked(mas->tree));
+       return mt_slot_locked(mas->tree, slots, offset);
 }
 
 /*
@@ -900,6 +912,45 @@ static inline void ma_set_meta(struct maple_node *mn, enum maple_type mt,
 }
 
 /*
+ * mt_clear_meta() - clear the metadata information of a node, if it exists
+ * @mt: The maple tree
+ * @mn: The maple node
+ * @type: The maple node type
+ * @offset: The offset of the highest sub-gap in this node.
+ * @end: The end of the data in this node.
+ */
+static inline void mt_clear_meta(struct maple_tree *mt, struct maple_node *mn,
+                                 enum maple_type type)
+{
+       struct maple_metadata *meta;
+       unsigned long *pivots;
+       void __rcu **slots;
+       void *next;
+
+       switch (type) {
+       case maple_range_64:
+               pivots = mn->mr64.pivot;
+               if (unlikely(pivots[MAPLE_RANGE64_SLOTS - 2])) {
+                       slots = mn->mr64.slot;
+                       next = mt_slot_locked(mt, slots,
+                                             MAPLE_RANGE64_SLOTS - 1);
+                       if (unlikely((mte_to_node(next) &&
+                                     mte_node_type(next))))
+                               return; /* no metadata, could be node */
+               }
+               fallthrough;
+       case maple_arange_64:
+               meta = ma_meta(mn, type);
+               break;
+       default:
+               return;
+       }
+
+       meta->gap = 0;
+       meta->end = 0;
+}
+
+/*
  * ma_meta_end() - Get the data end of a node from the metadata
  * @mn: The maple node
  * @mt: The maple node type
@@ -1096,8 +1147,11 @@ static int mas_ascend(struct ma_state *mas)
                a_type = mas_parent_enum(mas, p_enode);
                a_node = mte_parent(p_enode);
                a_slot = mte_parent_slot(p_enode);
-               pivots = ma_pivots(a_node, a_type);
                a_enode = mt_mk_node(a_node, a_type);
+               pivots = ma_pivots(a_node, a_type);
+
+               if (unlikely(ma_dead_node(a_node)))
+                       return 1;
 
                if (!set_min && a_slot) {
                        set_min = true;
@@ -1354,12 +1408,16 @@ static inline struct maple_enode *mas_start(struct ma_state *mas)
                mas->max = ULONG_MAX;
                mas->depth = 0;
 
+retry:
                root = mas_root(mas);
                /* Tree with nodes */
                if (likely(xa_is_node(root))) {
                        mas->depth = 1;
                        mas->node = mte_safe_root(root);
                        mas->offset = 0;
+                       if (mte_dead_node(mas->node))
+                               goto retry;
+
                        return NULL;
                }
 
@@ -1401,6 +1459,9 @@ static inline unsigned char ma_data_end(struct maple_node *node,
 {
        unsigned char offset;
 
+       if (!pivots)
+               return 0;
+
        if (type == maple_arange_64)
                return ma_meta_end(node, type);
 
@@ -1436,6 +1497,9 @@ static inline unsigned char mas_data_end(struct ma_state *mas)
                return ma_meta_end(node, type);
 
        pivots = ma_pivots(node, type);
+       if (unlikely(ma_dead_node(node)))
+               return 0;
+
        offset = mt_pivots[type] - 1;
        if (likely(!pivots[offset]))
                return ma_meta_end(node, type);
@@ -1724,8 +1788,10 @@ static inline void mas_replace(struct ma_state *mas, bool advanced)
                rcu_assign_pointer(slots[offset], mas->node);
        }
 
-       if (!advanced)
+       if (!advanced) {
+               mte_set_node_dead(old_enode);
                mas_free(mas, old_enode);
+       }
 }
 
 /*
@@ -3659,10 +3725,9 @@ static inline int mas_root_expand(struct ma_state *mas, void *entry)
                slot++;
        mas->depth = 1;
        mas_set_height(mas);
-
+       ma_set_meta(node, maple_leaf_64, 0, slot);
        /* swap the new root into the tree */
        rcu_assign_pointer(mas->tree->ma_root, mte_mk_root(mas->node));
-       ma_set_meta(node, maple_leaf_64, 0, slot);
        return slot;
 }
 
@@ -3875,18 +3940,13 @@ static inline void *mtree_lookup_walk(struct ma_state *mas)
                end = ma_data_end(node, type, pivots, max);
                if (unlikely(ma_dead_node(node)))
                        goto dead_node;
-
-               if (pivots[offset] >= mas->index)
-                       goto next;
-
                do {
-                       offset++;
-               } while ((offset < end) && (pivots[offset] < mas->index));
-
-               if (likely(offset > end))
-                       max = pivots[offset];
+                       if (pivots[offset] >= mas->index) {
+                               max = pivots[offset];
+                               break;
+                       }
+               } while (++offset < end);
 
-next:
                slots = ma_slots(node, type);
                next = mt_slot(mas->tree, slots, offset);
                if (unlikely(ma_dead_node(node)))
@@ -4164,6 +4224,7 @@ static inline bool mas_wr_node_store(struct ma_wr_state *wr_mas)
 done:
        mas_leaf_set_meta(mas, newnode, dst_pivots, maple_leaf_64, new_end);
        if (in_rcu) {
+               mte_set_node_dead(mas->node);
                mas->node = mt_mk_node(newnode, wr_mas->type);
                mas_replace(mas, false);
        } else {
@@ -4505,6 +4566,9 @@ static inline int mas_prev_node(struct ma_state *mas, unsigned long min)
        node = mas_mn(mas);
        slots = ma_slots(node, mt);
        pivots = ma_pivots(node, mt);
+       if (unlikely(ma_dead_node(node)))
+               return 1;
+
        mas->max = pivots[offset];
        if (offset)
                mas->min = pivots[offset - 1] + 1;
@@ -4526,6 +4590,9 @@ static inline int mas_prev_node(struct ma_state *mas, unsigned long min)
                slots = ma_slots(node, mt);
                pivots = ma_pivots(node, mt);
                offset = ma_data_end(node, mt, pivots, mas->max);
+               if (unlikely(ma_dead_node(node)))
+                       return 1;
+
                if (offset)
                        mas->min = pivots[offset - 1] + 1;
 
@@ -4574,6 +4641,7 @@ static inline int mas_next_node(struct ma_state *mas, struct maple_node *node,
        struct maple_enode *enode;
        int level = 0;
        unsigned char offset;
+       unsigned char node_end;
        enum maple_type mt;
        void __rcu **slots;
 
@@ -4597,7 +4665,11 @@ static inline int mas_next_node(struct ma_state *mas, struct maple_node *node,
                node = mas_mn(mas);
                mt = mte_node_type(mas->node);
                pivots = ma_pivots(node, mt);
-       } while (unlikely(offset == ma_data_end(node, mt, pivots, mas->max)));
+               node_end = ma_data_end(node, mt, pivots, mas->max);
+               if (unlikely(ma_dead_node(node)))
+                       return 1;
+
+       } while (unlikely(offset == node_end));
 
        slots = ma_slots(node, mt);
        pivot = mas_safe_pivot(mas, pivots, ++offset, mt);
@@ -4613,6 +4685,9 @@ static inline int mas_next_node(struct ma_state *mas, struct maple_node *node,
                mt = mte_node_type(mas->node);
                slots = ma_slots(node, mt);
                pivots = ma_pivots(node, mt);
+               if (unlikely(ma_dead_node(node)))
+                       return 1;
+
                offset = 0;
                pivot = pivots[0];
        }
@@ -4659,11 +4734,14 @@ static inline void *mas_next_nentry(struct ma_state *mas,
                return NULL;
        }
 
-       pivots = ma_pivots(node, type);
        slots = ma_slots(node, type);
-       mas->index = mas_safe_min(mas, pivots, mas->offset);
+       pivots = ma_pivots(node, type);
        count = ma_data_end(node, type, pivots, mas->max);
-       if (ma_dead_node(node))
+       if (unlikely(ma_dead_node(node)))
+               return NULL;
+
+       mas->index = mas_safe_min(mas, pivots, mas->offset);
+       if (unlikely(ma_dead_node(node)))
                return NULL;
 
        if (mas->index > max)
@@ -4817,6 +4895,11 @@ retry:
 
        slots = ma_slots(mn, mt);
        pivots = ma_pivots(mn, mt);
+       if (unlikely(ma_dead_node(mn))) {
+               mas_rewalk(mas, index);
+               goto retry;
+       }
+
        if (offset == mt_pivots[mt])
                pivot = mas->max;
        else
@@ -5400,24 +5483,26 @@ no_gap:
 }
 
 /*
- * mas_dead_leaves() - Mark all leaves of a node as dead.
+ * mte_dead_leaves() - Mark all leaves of a node as dead.
  * @mas: The maple state
  * @slots: Pointer to the slot array
+ * @type: The maple node type
  *
  * Must hold the write lock.
  *
  * Return: The number of leaves marked as dead.
  */
 static inline
-unsigned char mas_dead_leaves(struct ma_state *mas, void __rcu **slots)
+unsigned char mte_dead_leaves(struct maple_enode *enode, struct maple_tree *mt,
+                             void __rcu **slots)
 {
        struct maple_node *node;
        enum maple_type type;
        void *entry;
        int offset;
 
-       for (offset = 0; offset < mt_slot_count(mas->node); offset++) {
-               entry = mas_slot_locked(mas, slots, offset);
+       for (offset = 0; offset < mt_slot_count(enode); offset++) {
+               entry = mt_slot(mt, slots, offset);
                type = mte_node_type(entry);
                node = mte_to_node(entry);
                /* Use both node and type to catch LE & BE metadata */
@@ -5425,7 +5510,6 @@ unsigned char mas_dead_leaves(struct ma_state *mas, void __rcu **slots)
                        break;
 
                mte_set_node_dead(entry);
-               smp_wmb(); /* Needed for RCU */
                node->type = type;
                rcu_assign_pointer(slots[offset], node);
        }
@@ -5433,151 +5517,160 @@ unsigned char mas_dead_leaves(struct ma_state *mas, void __rcu **slots)
        return offset;
 }
 
-static void __rcu **mas_dead_walk(struct ma_state *mas, unsigned char offset)
+/**
+ * mte_dead_walk() - Walk down a dead tree to just before the leaves
+ * @enode: The maple encoded node
+ * @offset: The starting offset
+ *
+ * Note: This can only be used from the RCU callback context.
+ */
+static void __rcu **mte_dead_walk(struct maple_enode **enode, unsigned char offset)
 {
        struct maple_node *node, *next;
        void __rcu **slots = NULL;
 
-       next = mas_mn(mas);
+       next = mte_to_node(*enode);
        do {
-               mas->node = ma_enode_ptr(next);
-               node = mas_mn(mas);
+               *enode = ma_enode_ptr(next);
+               node = mte_to_node(*enode);
                slots = ma_slots(node, node->type);
-               next = mas_slot_locked(mas, slots, offset);
+               next = rcu_dereference_protected(slots[offset],
+                                       lock_is_held(&rcu_callback_map));
                offset = 0;
        } while (!ma_is_leaf(next->type));
 
        return slots;
 }
 
+/**
+ * mt_free_walk() - Walk & free a tree in the RCU callback context
+ * @head: The RCU head that's within the node.
+ *
+ * Note: This can only be used from the RCU callback context.
+ */
 static void mt_free_walk(struct rcu_head *head)
 {
        void __rcu **slots;
        struct maple_node *node, *start;
-       struct maple_tree mt;
+       struct maple_enode *enode;
        unsigned char offset;
        enum maple_type type;
-       MA_STATE(mas, &mt, 0, 0);
 
        node = container_of(head, struct maple_node, rcu);
 
        if (ma_is_leaf(node->type))
                goto free_leaf;
 
-       mt_init_flags(&mt, node->ma_flags);
-       mas_lock(&mas);
        start = node;
-       mas.node = mt_mk_node(node, node->type);
-       slots = mas_dead_walk(&mas, 0);
-       node = mas_mn(&mas);
+       enode = mt_mk_node(node, node->type);
+       slots = mte_dead_walk(&enode, 0);
+       node = mte_to_node(enode);
        do {
                mt_free_bulk(node->slot_len, slots);
                offset = node->parent_slot + 1;
-               mas.node = node->piv_parent;
-               if (mas_mn(&mas) == node)
-                       goto start_slots_free;
-
-               type = mte_node_type(mas.node);
-               slots = ma_slots(mte_to_node(mas.node), type);
-               if ((offset < mt_slots[type]) && (slots[offset]))
-                       slots = mas_dead_walk(&mas, offset);
-
-               node = mas_mn(&mas);
+               enode = node->piv_parent;
+               if (mte_to_node(enode) == node)
+                       goto free_leaf;
+
+               type = mte_node_type(enode);
+               slots = ma_slots(mte_to_node(enode), type);
+               if ((offset < mt_slots[type]) &&
+                   rcu_dereference_protected(slots[offset],
+                                             lock_is_held(&rcu_callback_map)))
+                       slots = mte_dead_walk(&enode, offset);
+               node = mte_to_node(enode);
        } while ((node != start) || (node->slot_len < offset));
 
        slots = ma_slots(node, node->type);
        mt_free_bulk(node->slot_len, slots);
 
-start_slots_free:
-       mas_unlock(&mas);
 free_leaf:
        mt_free_rcu(&node->rcu);
 }
 
-static inline void __rcu **mas_destroy_descend(struct ma_state *mas,
-                       struct maple_enode *prev, unsigned char offset)
+static inline void __rcu **mte_destroy_descend(struct maple_enode **enode,
+       struct maple_tree *mt, struct maple_enode *prev, unsigned char offset)
 {
        struct maple_node *node;
-       struct maple_enode *next = mas->node;
+       struct maple_enode *next = *enode;
        void __rcu **slots = NULL;
+       enum maple_type type;
+       unsigned char next_offset = 0;
 
        do {
-               mas->node = next;
-               node = mas_mn(mas);
-               slots = ma_slots(node, mte_node_type(mas->node));
-               next = mas_slot_locked(mas, slots, 0);
+               *enode = next;
+               node = mte_to_node(*enode);
+               type = mte_node_type(*enode);
+               slots = ma_slots(node, type);
+               next = mt_slot_locked(mt, slots, next_offset);
                if ((mte_dead_node(next)))
-                       next = mas_slot_locked(mas, slots, 1);
+                       next = mt_slot_locked(mt, slots, ++next_offset);
 
-               mte_set_node_dead(mas->node);
-               node->type = mte_node_type(mas->node);
+               mte_set_node_dead(*enode);
+               node->type = type;
                node->piv_parent = prev;
                node->parent_slot = offset;
-               offset = 0;
-               prev = mas->node;
+               offset = next_offset;
+               next_offset = 0;
+               prev = *enode;
        } while (!mte_is_leaf(next));
 
        return slots;
 }
 
-static void mt_destroy_walk(struct maple_enode *enode, unsigned char ma_flags,
+static void mt_destroy_walk(struct maple_enode *enode, struct maple_tree *mt,
                            bool free)
 {
        void __rcu **slots;
        struct maple_node *node = mte_to_node(enode);
        struct maple_enode *start;
-       struct maple_tree mt;
 
-       MA_STATE(mas, &mt, 0, 0);
-
-       if (mte_is_leaf(enode))
+       if (mte_is_leaf(enode)) {
+               node->type = mte_node_type(enode);
                goto free_leaf;
+       }
 
-       mt_init_flags(&mt, ma_flags);
-       mas_lock(&mas);
-
-       mas.node = start = enode;
-       slots = mas_destroy_descend(&mas, start, 0);
-       node = mas_mn(&mas);
+       start = enode;
+       slots = mte_destroy_descend(&enode, mt, start, 0);
+       node = mte_to_node(enode); // Updated in the above call.
        do {
                enum maple_type type;
                unsigned char offset;
                struct maple_enode *parent, *tmp;
 
-               node->slot_len = mas_dead_leaves(&mas, slots);
+               node->slot_len = mte_dead_leaves(enode, mt, slots);
                if (free)
                        mt_free_bulk(node->slot_len, slots);
                offset = node->parent_slot + 1;
-               mas.node = node->piv_parent;
-               if (mas_mn(&mas) == node)
-                       goto start_slots_free;
+               enode = node->piv_parent;
+               if (mte_to_node(enode) == node)
+                       goto free_leaf;
 
-               type = mte_node_type(mas.node);
-               slots = ma_slots(mte_to_node(mas.node), type);
+               type = mte_node_type(enode);
+               slots = ma_slots(mte_to_node(enode), type);
                if (offset >= mt_slots[type])
                        goto next;
 
-               tmp = mas_slot_locked(&mas, slots, offset);
+               tmp = mt_slot_locked(mt, slots, offset);
                if (mte_node_type(tmp) && mte_to_node(tmp)) {
-                       parent = mas.node;
-                       mas.node = tmp;
-                       slots = mas_destroy_descend(&mas, parent, offset);
+                       parent = enode;
+                       enode = tmp;
+                       slots = mte_destroy_descend(&enode, mt, parent, offset);
                }
 next:
-               node = mas_mn(&mas);
-       } while (start != mas.node);
+               node = mte_to_node(enode);
+       } while (start != enode);
 
-       node = mas_mn(&mas);
-       node->slot_len = mas_dead_leaves(&mas, slots);
+       node = mte_to_node(enode);
+       node->slot_len = mte_dead_leaves(enode, mt, slots);
        if (free)
                mt_free_bulk(node->slot_len, slots);
 
-start_slots_free:
-       mas_unlock(&mas);
-
 free_leaf:
        if (free)
                mt_free_rcu(&node->rcu);
+       else
+               mt_clear_meta(mt, node, node->type);
 }
 
 /*
@@ -5593,10 +5686,10 @@ static inline void mte_destroy_walk(struct maple_enode *enode,
        struct maple_node *node = mte_to_node(enode);
 
        if (mt_in_rcu(mt)) {
-               mt_destroy_walk(enode, mt->ma_flags, false);
+               mt_destroy_walk(enode, mt, false);
                call_rcu(&node->rcu, mt_free_walk);
        } else {
-               mt_destroy_walk(enode, mt->ma_flags, true);
+               mt_destroy_walk(enode, mt, true);
        }
 }
 
@@ -6617,11 +6710,11 @@ static inline void *mas_first_entry(struct ma_state *mas, struct maple_node *mn,
        while (likely(!ma_is_leaf(mt))) {
                MT_BUG_ON(mas->tree, mte_dead_node(mas->node));
                slots = ma_slots(mn, mt);
-               pivots = ma_pivots(mn, mt);
-               max = pivots[0];
                entry = mas_slot(mas, slots, 0);
+               pivots = ma_pivots(mn, mt);
                if (unlikely(ma_dead_node(mn)))
                        return NULL;
+               max = pivots[0];
                mas->node = entry;
                mn = mas_mn(mas);
                mt = mte_node_type(mas->node);
@@ -6641,13 +6734,13 @@ static inline void *mas_first_entry(struct ma_state *mas, struct maple_node *mn,
        if (likely(entry))
                return entry;
 
-       pivots = ma_pivots(mn, mt);
-       mas->index = pivots[0] + 1;
        mas->offset = 1;
        entry = mas_slot(mas, slots, 1);
+       pivots = ma_pivots(mn, mt);
        if (unlikely(ma_dead_node(mn)))
                return NULL;
 
+       mas->index = pivots[0] + 1;
        if (mas->index > limit)
                goto none;
 
index 07abcb6..245038a 100644 (file)
@@ -5478,7 +5478,7 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma,
                       struct folio *pagecache_folio, spinlock_t *ptl)
 {
        const bool unshare = flags & FAULT_FLAG_UNSHARE;
-       pte_t pte;
+       pte_t pte = huge_ptep_get(ptep);
        struct hstate *h = hstate_vma(vma);
        struct page *old_page;
        struct folio *new_folio;
@@ -5488,6 +5488,17 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma,
        struct mmu_notifier_range range;
 
        /*
+        * Never handle CoW for uffd-wp protected pages.  It should be only
+        * handled when the uffd-wp protection is removed.
+        *
+        * Note that only the CoW optimization path (in hugetlb_no_page())
+        * can trigger this, because hugetlb_fault() will always resolve
+        * uffd-wp bit first.
+        */
+       if (!unshare && huge_pte_uffd_wp(pte))
+               return 0;
+
+       /*
         * hugetlb does not support FOLL_FORCE-style write faults that keep the
         * PTE mapped R/O such as maybe_mkwrite() would do.
         */
@@ -5500,7 +5511,6 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma,
                return 0;
        }
 
-       pte = huge_ptep_get(ptep);
        old_page = pte_page(pte);
 
        delayacct_wpcopy_start();
index 79c94ee..1065e05 100644 (file)
@@ -556,15 +556,11 @@ static unsigned long kfence_init_pool(void)
         * enters __slab_free() slow-path.
         */
        for (i = 0; i < KFENCE_POOL_SIZE / PAGE_SIZE; i++) {
-               struct slab *slab = page_slab(&pages[i]);
+               struct slab *slab = page_slab(nth_page(pages, i));
 
                if (!i || (i % 2))
                        continue;
 
-               /* Verify we do not have a compound head page. */
-               if (WARN_ON(compound_head(&pages[i]) != &pages[i]))
-                       return addr;
-
                __folio_set_slab(slab_folio(slab));
 #ifdef CONFIG_MEMCG
                slab->memcg_data = (unsigned long)&kfence_metadata[i / 2 - 1].objcg |
@@ -597,12 +593,26 @@ static unsigned long kfence_init_pool(void)
 
                /* Protect the right redzone. */
                if (unlikely(!kfence_protect(addr + PAGE_SIZE)))
-                       return addr;
+                       goto reset_slab;
 
                addr += 2 * PAGE_SIZE;
        }
 
        return 0;
+
+reset_slab:
+       for (i = 0; i < KFENCE_POOL_SIZE / PAGE_SIZE; i++) {
+               struct slab *slab = page_slab(nth_page(pages, i));
+
+               if (!i || (i % 2))
+                       continue;
+#ifdef CONFIG_MEMCG
+               slab->memcg_data = 0;
+#endif
+               __folio_clear_slab(slab_folio(slab));
+       }
+
+       return addr;
 }
 
 static bool __init kfence_init_pool_early(void)
@@ -632,16 +642,6 @@ static bool __init kfence_init_pool_early(void)
         * fails for the first page, and therefore expect addr==__kfence_pool in
         * most failure cases.
         */
-       for (char *p = (char *)addr; p < __kfence_pool + KFENCE_POOL_SIZE; p += PAGE_SIZE) {
-               struct slab *slab = virt_to_slab(p);
-
-               if (!slab)
-                       continue;
-#ifdef CONFIG_MEMCG
-               slab->memcg_data = 0;
-#endif
-               __folio_clear_slab(slab_folio(slab));
-       }
        memblock_free_late(__pa(addr), KFENCE_POOL_SIZE - (addr - (unsigned long)__kfence_pool));
        __kfence_pool = NULL;
        return false;
index f456f3b..01a23ad 100644 (file)
@@ -3563,8 +3563,21 @@ static vm_fault_t remove_device_exclusive_entry(struct vm_fault *vmf)
        struct vm_area_struct *vma = vmf->vma;
        struct mmu_notifier_range range;
 
-       if (!folio_lock_or_retry(folio, vma->vm_mm, vmf->flags))
+       /*
+        * We need a reference to lock the folio because we don't hold
+        * the PTL so a racing thread can remove the device-exclusive
+        * entry and unmap it. If the folio is free the entry must
+        * have been removed already. If it happens to have already
+        * been re-allocated after being freed all we do is lock and
+        * unlock it.
+        */
+       if (!folio_try_get(folio))
+               return 0;
+
+       if (!folio_lock_or_retry(folio, vma->vm_mm, vmf->flags)) {
+               folio_put(folio);
                return VM_FAULT_RETRY;
+       }
        mmu_notifier_range_init_owner(&range, MMU_NOTIFY_EXCLUSIVE, 0,
                                vma->vm_mm, vmf->address & PAGE_MASK,
                                (vmf->address & PAGE_MASK) + PAGE_SIZE, NULL);
@@ -3577,6 +3590,7 @@ static vm_fault_t remove_device_exclusive_entry(struct vm_fault *vmf)
 
        pte_unmap_unlock(vmf->pte, vmf->ptl);
        folio_unlock(folio);
+       folio_put(folio);
 
        mmu_notifier_invalidate_range_end(&range);
        return 0;
index ad499f7..ff68a67 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2277,7 +2277,7 @@ do_vmi_align_munmap(struct vma_iterator *vmi, struct vm_area_struct *vma,
        int count = 0;
        int error = -ENOMEM;
        MA_STATE(mas_detach, &mt_detach, 0, 0);
-       mt_init_flags(&mt_detach, MT_FLAGS_LOCK_EXTERN);
+       mt_init_flags(&mt_detach, vmi->mas.tree->ma_flags & MT_FLAGS_LOCK_MASK);
        mt_set_external_lock(&mt_detach, &mm->mmap_lock);
 
        /*
@@ -3037,6 +3037,7 @@ void exit_mmap(struct mm_struct *mm)
         */
        set_bit(MMF_OOM_SKIP, &mm->flags);
        mmap_write_lock(mm);
+       mt_clear_in_rcu(&mm->mm_mt);
        free_pgtables(&tlb, &mm->mm_mt, vma, FIRST_USER_ADDRESS,
                      USER_PGTABLES_CEILING);
        tlb_finish_mmu(&tlb);
index 62ba2bf..2c718f4 100644 (file)
@@ -679,6 +679,7 @@ static void __del_from_avail_list(struct swap_info_struct *p)
 {
        int nid;
 
+       assert_spin_locked(&p->lock);
        for_each_node(nid)
                plist_del(&p->avail_lists[nid], &swap_avail_heads[nid]);
 }
@@ -2434,8 +2435,8 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
                spin_unlock(&swap_lock);
                goto out_dput;
        }
-       del_from_avail_list(p);
        spin_lock(&p->lock);
+       del_from_avail_list(p);
        if (p->prio < 0) {
                struct swap_info_struct *si = p;
                int nid;
index bef6cf2..a500720 100644 (file)
@@ -3042,9 +3042,11 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
         * allocation request, free them via vfree() if any.
         */
        if (area->nr_pages != nr_small_pages) {
-               warn_alloc(gfp_mask, NULL,
-                       "vmalloc error: size %lu, page order %u, failed to allocate pages",
-                       area->nr_pages * PAGE_SIZE, page_order);
+               /* vm_area_alloc_pages() can also fail due to a fatal signal */
+               if (!fatal_signal_pending(current))
+                       warn_alloc(gfp_mask, NULL,
+                               "vmalloc error: size %lu, page order %u, failed to allocate pages",
+                               area->nr_pages * PAGE_SIZE, page_order);
                goto fail;
        }
 
index c64050e..1fffe2b 100644 (file)
@@ -280,6 +280,10 @@ static void xen_9pfs_front_free(struct xen_9pfs_front_priv *priv)
        write_unlock(&xen_9pfs_lock);
 
        for (i = 0; i < priv->num_rings; i++) {
+               struct xen_9pfs_dataring *ring = &priv->rings[i];
+
+               cancel_work_sync(&ring->work);
+
                if (!priv->rings[i].intf)
                        break;
                if (priv->rings[i].irq > 0)
index 9bc3448..5761d4a 100644 (file)
@@ -119,7 +119,8 @@ enum {
        ISOTP_WAIT_FIRST_FC,
        ISOTP_WAIT_FC,
        ISOTP_WAIT_DATA,
-       ISOTP_SENDING
+       ISOTP_SENDING,
+       ISOTP_SHUTDOWN,
 };
 
 struct tpcon {
@@ -880,8 +881,8 @@ static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
                                             txtimer);
        struct sock *sk = &so->sk;
 
-       /* don't handle timeouts in IDLE state */
-       if (so->tx.state == ISOTP_IDLE)
+       /* don't handle timeouts in IDLE or SHUTDOWN state */
+       if (so->tx.state == ISOTP_IDLE || so->tx.state == ISOTP_SHUTDOWN)
                return HRTIMER_NORESTART;
 
        /* we did not get any flow control or echo frame in time */
@@ -918,7 +919,6 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 {
        struct sock *sk = sock->sk;
        struct isotp_sock *so = isotp_sk(sk);
-       u32 old_state = so->tx.state;
        struct sk_buff *skb;
        struct net_device *dev;
        struct canfd_frame *cf;
@@ -928,23 +928,24 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
        int off;
        int err;
 
-       if (!so->bound)
+       if (!so->bound || so->tx.state == ISOTP_SHUTDOWN)
                return -EADDRNOTAVAIL;
 
+wait_free_buffer:
        /* we do not support multiple buffers - for now */
-       if (cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SENDING) != ISOTP_IDLE ||
-           wq_has_sleeper(&so->wait)) {
-               if (msg->msg_flags & MSG_DONTWAIT) {
-                       err = -EAGAIN;
-                       goto err_out;
-               }
+       if (wq_has_sleeper(&so->wait) && (msg->msg_flags & MSG_DONTWAIT))
+               return -EAGAIN;
 
-               /* wait for complete transmission of current pdu */
-               err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
-               if (err)
-                       goto err_out;
+       /* wait for complete transmission of current pdu */
+       err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
+       if (err)
+               goto err_event_drop;
 
-               so->tx.state = ISOTP_SENDING;
+       if (cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SENDING) != ISOTP_IDLE) {
+               if (so->tx.state == ISOTP_SHUTDOWN)
+                       return -EADDRNOTAVAIL;
+
+               goto wait_free_buffer;
        }
 
        if (!size || size > MAX_MSG_LENGTH) {
@@ -1074,7 +1075,9 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 
        if (wait_tx_done) {
                /* wait for complete transmission of current pdu */
-               wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
+               err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
+               if (err)
+                       goto err_event_drop;
 
                if (sk->sk_err)
                        return -sk->sk_err;
@@ -1082,13 +1085,15 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 
        return size;
 
+err_event_drop:
+       /* got signal: force tx state machine to be idle */
+       so->tx.state = ISOTP_IDLE;
+       hrtimer_cancel(&so->txfrtimer);
+       hrtimer_cancel(&so->txtimer);
 err_out_drop:
        /* drop this PDU and unlock a potential wait queue */
-       old_state = ISOTP_IDLE;
-err_out:
-       so->tx.state = old_state;
-       if (so->tx.state == ISOTP_IDLE)
-               wake_up_interruptible(&so->wait);
+       so->tx.state = ISOTP_IDLE;
+       wake_up_interruptible(&so->wait);
 
        return err;
 }
@@ -1120,7 +1125,7 @@ static int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
        if (ret < 0)
                goto out_err;
 
-       sock_recv_timestamp(msg, sk, skb);
+       sock_recv_cmsgs(msg, sk, skb);
 
        if (msg->msg_name) {
                __sockaddr_check_size(ISOTP_MIN_NAMELEN);
@@ -1150,10 +1155,12 @@ static int isotp_release(struct socket *sock)
        net = sock_net(sk);
 
        /* wait for complete transmission of current pdu */
-       wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
+       while (wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE) == 0 &&
+              cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SHUTDOWN) != ISOTP_IDLE)
+               ;
 
        /* force state machines to be idle also when a signal occurred */
-       so->tx.state = ISOTP_IDLE;
+       so->tx.state = ISOTP_SHUTDOWN;
        so->rx.state = ISOTP_IDLE;
 
        spin_lock(&isotp_notifier_lock);
@@ -1608,6 +1615,21 @@ static int isotp_init(struct sock *sk)
        return 0;
 }
 
+static __poll_t isotp_poll(struct file *file, struct socket *sock, poll_table *wait)
+{
+       struct sock *sk = sock->sk;
+       struct isotp_sock *so = isotp_sk(sk);
+
+       __poll_t mask = datagram_poll(file, sock, wait);
+       poll_wait(file, &so->wait, wait);
+
+       /* Check for false positives due to TX state */
+       if ((mask & EPOLLWRNORM) && (so->tx.state != ISOTP_IDLE))
+               mask &= ~(EPOLLOUT | EPOLLWRNORM);
+
+       return mask;
+}
+
 static int isotp_sock_no_ioctlcmd(struct socket *sock, unsigned int cmd,
                                  unsigned long arg)
 {
@@ -1623,7 +1645,7 @@ static const struct proto_ops isotp_ops = {
        .socketpair = sock_no_socketpair,
        .accept = sock_no_accept,
        .getname = isotp_getname,
-       .poll = datagram_poll,
+       .poll = isotp_poll,
        .ioctl = isotp_sock_no_ioctlcmd,
        .gettstamp = sock_gettstamp,
        .listen = sock_no_listen,
index fb92c36..fe3df23 100644 (file)
@@ -604,7 +604,10 @@ sk_buff *j1939_tp_tx_dat_new(struct j1939_priv *priv,
        /* reserve CAN header */
        skb_reserve(skb, offsetof(struct can_frame, data));
 
-       memcpy(skb->cb, re_skcb, sizeof(skb->cb));
+       /* skb->cb must be large enough to hold a j1939_sk_buff_cb structure */
+       BUILD_BUG_ON(sizeof(skb->cb) < sizeof(*re_skcb));
+
+       memcpy(skb->cb, re_skcb, sizeof(*re_skcb));
        skcb = j1939_skb_to_cb(skb);
        if (swap_src_dst)
                j1939_skbcb_swap(skcb);
index a089b70..e6a739b 100644 (file)
@@ -137,6 +137,20 @@ static void queue_process(struct work_struct *work)
        }
 }
 
+static int netif_local_xmit_active(struct net_device *dev)
+{
+       int i;
+
+       for (i = 0; i < dev->num_tx_queues; i++) {
+               struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
+
+               if (READ_ONCE(txq->xmit_lock_owner) == smp_processor_id())
+                       return 1;
+       }
+
+       return 0;
+}
+
 static void poll_one_napi(struct napi_struct *napi)
 {
        int work;
@@ -183,7 +197,10 @@ void netpoll_poll_dev(struct net_device *dev)
        if (!ni || down_trylock(&ni->dev_lock))
                return;
 
-       if (!netif_running(dev)) {
+       /* Some drivers will take the same locks in poll and xmit,
+        * we can't poll if local CPU is already in xmit.
+        */
+       if (!netif_running(dev) || netif_local_xmit_active(dev)) {
                up(&ni->dev_lock);
                return;
        }
index fab66c1..20165e0 100644 (file)
@@ -270,11 +270,12 @@ static int ethnl_update_linkmodes(struct genl_info *info, struct nlattr **tb,
                                            "lanes configuration not supported by device");
                        return -EOPNOTSUPP;
                }
-       } else if (!lsettings->autoneg) {
-               /* If autoneg is off and lanes parameter is not passed from user,
-                * set the lanes parameter to 0.
+       } else if (!lsettings->autoneg && ksettings->lanes) {
+               /* If autoneg is off and lanes parameter is not passed from user but
+                * it was defined previously then set the lanes parameter to 0.
                 */
                ksettings->lanes = 0;
+               *mod = true;
        }
 
        ret = ethnl_update_bitset(ksettings->link_modes.advertising,
index 8cebb47..b860776 100644 (file)
@@ -749,6 +749,11 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
                room = 576;
        room -= sizeof(struct iphdr) + icmp_param.replyopts.opt.opt.optlen;
        room -= sizeof(struct icmphdr);
+       /* Guard against tiny mtu. We need to include at least one
+        * IP network header for this message to make any sense.
+        */
+       if (room <= (int)sizeof(struct iphdr))
+               goto ende;
 
        icmp_param.data_len = skb_in->len - icmp_param.offset;
        if (icmp_param.data_len > room)
index 409ec2a..5178a3f 100644 (file)
@@ -1089,13 +1089,13 @@ static struct sock *ping_get_idx(struct seq_file *seq, loff_t pos)
 }
 
 void *ping_seq_start(struct seq_file *seq, loff_t *pos, sa_family_t family)
-       __acquires(RCU)
+       __acquires(ping_table.lock)
 {
        struct ping_iter_state *state = seq->private;
        state->bucket = 0;
        state->family = family;
 
-       rcu_read_lock();
+       spin_lock(&ping_table.lock);
 
        return *pos ? ping_get_idx(seq, *pos-1) : SEQ_START_TOKEN;
 }
@@ -1121,9 +1121,9 @@ void *ping_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 EXPORT_SYMBOL_GPL(ping_seq_next);
 
 void ping_seq_stop(struct seq_file *seq, void *v)
-       __releases(RCU)
+       __releases(ping_table.lock)
 {
-       rcu_read_unlock();
+       spin_unlock(&ping_table.lock);
 }
 EXPORT_SYMBOL_GPL(ping_seq_stop);
 
index 94df935..8088a50 100644 (file)
@@ -91,12 +91,12 @@ EXPORT_SYMBOL_GPL(raw_v4_hashinfo);
 int raw_hash_sk(struct sock *sk)
 {
        struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;
-       struct hlist_nulls_head *hlist;
+       struct hlist_head *hlist;
 
        hlist = &h->ht[raw_hashfunc(sock_net(sk), inet_sk(sk)->inet_num)];
 
        spin_lock(&h->lock);
-       __sk_nulls_add_node_rcu(sk, hlist);
+       sk_add_node_rcu(sk, hlist);
        sock_set_flag(sk, SOCK_RCU_FREE);
        spin_unlock(&h->lock);
        sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
@@ -110,7 +110,7 @@ void raw_unhash_sk(struct sock *sk)
        struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;
 
        spin_lock(&h->lock);
-       if (__sk_nulls_del_node_init_rcu(sk))
+       if (sk_del_node_init_rcu(sk))
                sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
        spin_unlock(&h->lock);
 }
@@ -163,16 +163,15 @@ static int icmp_filter(const struct sock *sk, const struct sk_buff *skb)
 static int raw_v4_input(struct net *net, struct sk_buff *skb,
                        const struct iphdr *iph, int hash)
 {
-       struct hlist_nulls_head *hlist;
-       struct hlist_nulls_node *hnode;
        int sdif = inet_sdif(skb);
+       struct hlist_head *hlist;
        int dif = inet_iif(skb);
        int delivered = 0;
        struct sock *sk;
 
        hlist = &raw_v4_hashinfo.ht[hash];
        rcu_read_lock();
-       sk_nulls_for_each(sk, hnode, hlist) {
+       sk_for_each_rcu(sk, hlist) {
                if (!raw_v4_match(net, sk, iph->protocol,
                                  iph->saddr, iph->daddr, dif, sdif))
                        continue;
@@ -264,10 +263,9 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info)
 void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info)
 {
        struct net *net = dev_net(skb->dev);
-       struct hlist_nulls_head *hlist;
-       struct hlist_nulls_node *hnode;
        int dif = skb->dev->ifindex;
        int sdif = inet_sdif(skb);
+       struct hlist_head *hlist;
        const struct iphdr *iph;
        struct sock *sk;
        int hash;
@@ -276,7 +274,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info)
        hlist = &raw_v4_hashinfo.ht[hash];
 
        rcu_read_lock();
-       sk_nulls_for_each(sk, hnode, hlist) {
+       sk_for_each_rcu(sk, hlist) {
                iph = (const struct iphdr *)skb->data;
                if (!raw_v4_match(net, sk, iph->protocol,
                                  iph->daddr, iph->saddr, dif, sdif))
@@ -950,14 +948,13 @@ static struct sock *raw_get_first(struct seq_file *seq, int bucket)
 {
        struct raw_hashinfo *h = pde_data(file_inode(seq->file));
        struct raw_iter_state *state = raw_seq_private(seq);
-       struct hlist_nulls_head *hlist;
-       struct hlist_nulls_node *hnode;
+       struct hlist_head *hlist;
        struct sock *sk;
 
        for (state->bucket = bucket; state->bucket < RAW_HTABLE_SIZE;
                        ++state->bucket) {
                hlist = &h->ht[state->bucket];
-               sk_nulls_for_each(sk, hnode, hlist) {
+               sk_for_each(sk, hlist) {
                        if (sock_net(sk) == seq_file_net(seq))
                                return sk;
                }
@@ -970,7 +967,7 @@ static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk)
        struct raw_iter_state *state = raw_seq_private(seq);
 
        do {
-               sk = sk_nulls_next(sk);
+               sk = sk_next(sk);
        } while (sk && sock_net(sk) != seq_file_net(seq));
 
        if (!sk)
@@ -989,9 +986,12 @@ static struct sock *raw_get_idx(struct seq_file *seq, loff_t pos)
 }
 
 void *raw_seq_start(struct seq_file *seq, loff_t *pos)
-       __acquires(RCU)
+       __acquires(&h->lock)
 {
-       rcu_read_lock();
+       struct raw_hashinfo *h = pde_data(file_inode(seq->file));
+
+       spin_lock(&h->lock);
+
        return *pos ? raw_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
 }
 EXPORT_SYMBOL_GPL(raw_seq_start);
@@ -1010,9 +1010,11 @@ void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 EXPORT_SYMBOL_GPL(raw_seq_next);
 
 void raw_seq_stop(struct seq_file *seq, void *v)
-       __releases(RCU)
+       __releases(&h->lock)
 {
-       rcu_read_unlock();
+       struct raw_hashinfo *h = pde_data(file_inode(seq->file));
+
+       spin_unlock(&h->lock);
 }
 EXPORT_SYMBOL_GPL(raw_seq_stop);
 
index 9993218..da3591a 100644 (file)
@@ -57,8 +57,7 @@ static bool raw_lookup(struct net *net, struct sock *sk,
 static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 *r)
 {
        struct raw_hashinfo *hashinfo = raw_get_hashinfo(r);
-       struct hlist_nulls_head *hlist;
-       struct hlist_nulls_node *hnode;
+       struct hlist_head *hlist;
        struct sock *sk;
        int slot;
 
@@ -68,7 +67,7 @@ static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2
        rcu_read_lock();
        for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) {
                hlist = &hashinfo->ht[slot];
-               sk_nulls_for_each(sk, hnode, hlist) {
+               sk_for_each_rcu(sk, hlist) {
                        if (raw_lookup(net, sk, r)) {
                                /*
                                 * Grab it and keep until we fill
@@ -142,9 +141,8 @@ static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
        struct raw_hashinfo *hashinfo = raw_get_hashinfo(r);
        struct net *net = sock_net(skb->sk);
        struct inet_diag_dump_data *cb_data;
-       struct hlist_nulls_head *hlist;
-       struct hlist_nulls_node *hnode;
        int num, s_num, slot, s_slot;
+       struct hlist_head *hlist;
        struct sock *sk = NULL;
        struct nlattr *bc;
 
@@ -161,7 +159,7 @@ static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
                num = 0;
 
                hlist = &hashinfo->ht[slot];
-               sk_nulls_for_each(sk, hnode, hlist) {
+               sk_for_each_rcu(sk, hlist) {
                        struct inet_sock *inet = inet_sk(sk);
 
                        if (!net_eq(sock_net(sk), net))
index c314fdd..95a55c6 100644 (file)
@@ -1965,8 +1965,13 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,
        IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
        if (proto == IPPROTO_ICMPV6) {
                struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
+               u8 icmp6_type;
 
-               ICMP6MSGOUT_INC_STATS(net, idev, icmp6_hdr(skb)->icmp6_type);
+               if (sk->sk_socket->type == SOCK_RAW && !inet_sk(sk)->hdrincl)
+                       icmp6_type = fl6->fl6_icmp_type;
+               else
+                       icmp6_type = icmp6_hdr(skb)->icmp6_type;
+               ICMP6MSGOUT_INC_STATS(net, idev, icmp6_type);
                ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
        }
 
index bac9ba7..a327aa4 100644 (file)
@@ -141,10 +141,9 @@ EXPORT_SYMBOL(rawv6_mh_filter_unregister);
 static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
 {
        struct net *net = dev_net(skb->dev);
-       struct hlist_nulls_head *hlist;
-       struct hlist_nulls_node *hnode;
        const struct in6_addr *saddr;
        const struct in6_addr *daddr;
+       struct hlist_head *hlist;
        struct sock *sk;
        bool delivered = false;
        __u8 hash;
@@ -155,7 +154,7 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
        hash = raw_hashfunc(net, nexthdr);
        hlist = &raw_v6_hashinfo.ht[hash];
        rcu_read_lock();
-       sk_nulls_for_each(sk, hnode, hlist) {
+       sk_for_each_rcu(sk, hlist) {
                int filtered;
 
                if (!raw_v6_match(net, sk, nexthdr, daddr, saddr,
@@ -333,15 +332,14 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr,
                u8 type, u8 code, int inner_offset, __be32 info)
 {
        struct net *net = dev_net(skb->dev);
-       struct hlist_nulls_head *hlist;
-       struct hlist_nulls_node *hnode;
+       struct hlist_head *hlist;
        struct sock *sk;
        int hash;
 
        hash = raw_hashfunc(net, nexthdr);
        hlist = &raw_v6_hashinfo.ht[hash];
        rcu_read_lock();
-       sk_nulls_for_each(sk, hnode, hlist) {
+       sk_for_each_rcu(sk, hlist) {
                /* Note: ipv6_hdr(skb) != skb->data */
                const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data;
 
index 4db5a55..41a74fc 100644 (file)
@@ -677,8 +677,8 @@ MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
 MODULE_DESCRIPTION("L2TP over IP");
 MODULE_VERSION("1.0");
 
-/* Use the value of SOCK_DGRAM (2) directory, because __stringify doesn't like
- * enums
+/* Use the values of SOCK_DGRAM (2) as type and IPPROTO_L2TP (115) as protocol,
+ * because __stringify doesn't like enums
  */
-MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 2, IPPROTO_L2TP);
-MODULE_ALIAS_NET_PF_PROTO(PF_INET, IPPROTO_L2TP);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 115, 2);
+MODULE_ALIAS_NET_PF_PROTO(PF_INET, 115);
index 2478aa6..5137ea1 100644 (file)
@@ -806,8 +806,8 @@ MODULE_AUTHOR("Chris Elston <celston@katalix.com>");
 MODULE_DESCRIPTION("L2TP IP encapsulation for IPv6");
 MODULE_VERSION("1.0");
 
-/* Use the value of SOCK_DGRAM (2) directory, because __stringify doesn't like
- * enums
+/* Use the values of SOCK_DGRAM (2) as type and IPPROTO_L2TP (115) as protocol,
+ * because __stringify doesn't like enums
  */
-MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 2, IPPROTO_L2TP);
-MODULE_ALIAS_NET_PF_PROTO(PF_INET6, IPPROTO_L2TP);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 115, 2);
+MODULE_ALIAS_NET_PF_PROTO(PF_INET6, 115);
index e8de500..af57616 100644 (file)
@@ -2769,14 +2769,6 @@ ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta
        if (sdata->crypto_tx_tailroom_needed_cnt)
                tailroom = IEEE80211_ENCRYPT_TAILROOM;
 
-       if (!--mesh_hdr->ttl) {
-               if (multicast)
-                       goto rx_accept;
-
-               IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
-               return RX_DROP_MONITOR;
-       }
-
        if (mesh_hdr->flags & MESH_FLAGS_AE) {
                struct mesh_path *mppath;
                char *proxied_addr;
@@ -2807,6 +2799,14 @@ ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta
        if (ether_addr_equal(sdata->vif.addr, eth->h_dest))
                goto rx_accept;
 
+       if (!--mesh_hdr->ttl) {
+               if (multicast)
+                       goto rx_accept;
+
+               IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
+               return RX_DROP_MONITOR;
+       }
+
        if (!ifmsh->mshcfg.dot11MeshForwarding) {
                if (is_multicast_ether_addr(eth->h_dest))
                        goto rx_accept;
@@ -2833,6 +2833,9 @@ ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta
 
                if (skb_cow_head(fwd_skb, hdrlen - sizeof(struct ethhdr)))
                        return RX_DROP_UNUSABLE;
+
+               if (skb_linearize(fwd_skb))
+                       return RX_DROP_UNUSABLE;
        }
 
        fwd_hdr = skb_push(fwd_skb, hdrlen - sizeof(struct ethhdr));
@@ -2847,7 +2850,7 @@ ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta
                hdrlen += ETH_ALEN;
        else
                fwd_skb->protocol = htons(fwd_skb->len - hdrlen);
-       skb_set_network_header(fwd_skb, hdrlen);
+       skb_set_network_header(fwd_skb, hdrlen + 2);
 
        info = IEEE80211_SKB_CB(fwd_skb);
        memset(info, 0, sizeof(*info));
@@ -2896,7 +2899,7 @@ __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        __le16 fc = hdr->frame_control;
        struct sk_buff_head frame_list;
-       static ieee80211_rx_result res;
+       ieee80211_rx_result res;
        struct ethhdr ethhdr;
        const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
 
@@ -2930,7 +2933,7 @@ __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset)
                                          data_offset, true))
                return RX_DROP_UNUSABLE;
 
-       if (rx->sta && rx->sta->amsdu_mesh_control < 0) {
+       if (rx->sta->amsdu_mesh_control < 0) {
                bool valid_std = ieee80211_is_valid_amsdu(skb, true);
                bool valid_nonstd = ieee80211_is_valid_amsdu(skb, false);
 
@@ -3006,7 +3009,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
                }
        }
 
-       if (is_multicast_ether_addr(hdr->addr1))
+       if (is_multicast_ether_addr(hdr->addr1) || !rx->sta)
                return RX_DROP_UNUSABLE;
 
        if (rx->key) {
@@ -3037,7 +3040,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
        struct net_device *dev = sdata->dev;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        __le16 fc = hdr->frame_control;
-       static ieee80211_rx_result res;
+       ieee80211_rx_result res;
        bool port_control;
        int err;
 
index 7d68dbc..941bda9 100644 (file)
@@ -1264,7 +1264,8 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta)
        list_del_rcu(&sta->list);
        sta->removed = true;
 
-       drv_sta_pre_rcu_remove(local, sta->sdata, sta);
+       if (sta->uploaded)
+               drv_sta_pre_rcu_remove(local, sta->sdata, sta);
 
        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
            rcu_access_pointer(sdata->u.vlan.sta) == sta)
index 3aceb3b..8c39765 100644 (file)
@@ -4906,7 +4906,7 @@ u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata, u8 iftype)
                                       &eht_cap->eht_cap_elem,
                                       is_ap);
        return 2 + 1 +
-              sizeof(he_cap->he_cap_elem) + n +
+              sizeof(eht_cap->eht_cap_elem) + n +
               ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0],
                                      eht_cap->eht_cap_elem.phy_cap_info);
        return 0;
index c642776..f365dfd 100644 (file)
@@ -1952,7 +1952,7 @@ static int netlink_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
        struct scm_cookie scm;
        struct sock *sk = sock->sk;
        struct netlink_sock *nlk = nlk_sk(sk);
-       size_t copied;
+       size_t copied, max_recvmsg_len;
        struct sk_buff *skb, *data_skb;
        int err, ret;
 
@@ -1985,9 +1985,10 @@ static int netlink_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 #endif
 
        /* Record the max length of recvmsg() calls for future allocations */
-       nlk->max_recvmsg_len = max(nlk->max_recvmsg_len, len);
-       nlk->max_recvmsg_len = min_t(size_t, nlk->max_recvmsg_len,
-                                    SKB_WITH_OVERHEAD(32768));
+       max_recvmsg_len = max(READ_ONCE(nlk->max_recvmsg_len), len);
+       max_recvmsg_len = min_t(size_t, max_recvmsg_len,
+                               SKB_WITH_OVERHEAD(32768));
+       WRITE_ONCE(nlk->max_recvmsg_len, max_recvmsg_len);
 
        copied = data_skb->len;
        if (len < copied) {
@@ -2236,6 +2237,7 @@ static int netlink_dump(struct sock *sk)
        struct netlink_ext_ack extack = {};
        struct netlink_callback *cb;
        struct sk_buff *skb = NULL;
+       size_t max_recvmsg_len;
        struct module *module;
        int err = -ENOBUFS;
        int alloc_min_size;
@@ -2258,8 +2260,9 @@ static int netlink_dump(struct sock *sk)
        cb = &nlk->cb;
        alloc_min_size = max_t(int, cb->min_dump_alloc, NLMSG_GOODSIZE);
 
-       if (alloc_min_size < nlk->max_recvmsg_len) {
-               alloc_size = nlk->max_recvmsg_len;
+       max_recvmsg_len = READ_ONCE(nlk->max_recvmsg_len);
+       if (alloc_min_size < max_recvmsg_len) {
+               alloc_size = max_recvmsg_len;
                skb = alloc_skb(alloc_size,
                                (GFP_KERNEL & ~__GFP_DIRECT_RECLAIM) |
                                __GFP_NOWARN | __GFP_NORETRY);
index 5c2fb99..3a70255 100644 (file)
@@ -393,10 +393,12 @@ static struct qrtr_node *qrtr_node_lookup(unsigned int nid)
        struct qrtr_node *node;
        unsigned long flags;
 
+       mutex_lock(&qrtr_node_lock);
        spin_lock_irqsave(&qrtr_nodes_lock, flags);
        node = radix_tree_lookup(&qrtr_nodes, nid);
        node = qrtr_node_acquire(node);
        spin_unlock_irqrestore(&qrtr_nodes_lock, flags);
+       mutex_unlock(&qrtr_node_lock);
 
        return node;
 }
index 722936f..0f25a38 100644 (file)
@@ -274,7 +274,7 @@ err:
        return NULL;
 }
 
-static int server_del(struct qrtr_node *node, unsigned int port)
+static int server_del(struct qrtr_node *node, unsigned int port, bool bcast)
 {
        struct qrtr_lookup *lookup;
        struct qrtr_server *srv;
@@ -287,7 +287,7 @@ static int server_del(struct qrtr_node *node, unsigned int port)
        radix_tree_delete(&node->servers, port);
 
        /* Broadcast the removal of local servers */
-       if (srv->node == qrtr_ns.local_node)
+       if (srv->node == qrtr_ns.local_node && bcast)
                service_announce_del(&qrtr_ns.bcast_sq, srv);
 
        /* Announce the service's disappearance to observers */
@@ -373,7 +373,7 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
                }
                slot = radix_tree_iter_resume(slot, &iter);
                rcu_read_unlock();
-               server_del(node, srv->port);
+               server_del(node, srv->port, true);
                rcu_read_lock();
        }
        rcu_read_unlock();
@@ -459,10 +459,13 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
                kfree(lookup);
        }
 
-       /* Remove the server belonging to this port */
+       /* Remove the server belonging to this port but don't broadcast
+        * DEL_SERVER. Neighbours would've already removed the server belonging
+        * to this port due to the DEL_CLIENT broadcast from qrtr_port_remove().
+        */
        node = node_get(node_id);
        if (node)
-               server_del(node, port);
+               server_del(node, port, false);
 
        /* Advertise the removal of this client to all local servers */
        local_node = node_get(qrtr_ns.local_node);
@@ -567,7 +570,7 @@ static int ctrl_cmd_del_server(struct sockaddr_qrtr *from,
        if (!node)
                return -ENOENT;
 
-       return server_del(node, port);
+       return server_del(node, port, true);
 }
 
 static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from,
index b91616f..218e098 100644 (file)
@@ -1830,6 +1830,10 @@ static int sctp_sendmsg_to_asoc(struct sctp_association *asoc,
                err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len);
                if (err)
                        goto err;
+               if (unlikely(sinfo->sinfo_stream >= asoc->stream.outcnt)) {
+                       err = -EINVAL;
+                       goto err;
+               }
        }
 
        if (sctp_state(asoc, CLOSED)) {
index 983c589..4246363 100644 (file)
@@ -416,14 +416,23 @@ static int unix_gid_hash(kuid_t uid)
        return hash_long(from_kuid(&init_user_ns, uid), GID_HASHBITS);
 }
 
-static void unix_gid_put(struct kref *kref)
+static void unix_gid_free(struct rcu_head *rcu)
 {
-       struct cache_head *item = container_of(kref, struct cache_head, ref);
-       struct unix_gid *ug = container_of(item, struct unix_gid, h);
+       struct unix_gid *ug = container_of(rcu, struct unix_gid, rcu);
+       struct cache_head *item = &ug->h;
+
        if (test_bit(CACHE_VALID, &item->flags) &&
            !test_bit(CACHE_NEGATIVE, &item->flags))
                put_group_info(ug->gi);
-       kfree_rcu(ug, rcu);
+       kfree(ug);
+}
+
+static void unix_gid_put(struct kref *kref)
+{
+       struct cache_head *item = container_of(kref, struct cache_head, ref);
+       struct unix_gid *ug = container_of(item, struct unix_gid, h);
+
+       call_rcu(&ug->rcu, unix_gid_free);
 }
 
 static int unix_gid_match(struct cache_head *corig, struct cache_head *cnew)
index 37934df..ee78b40 100644 (file)
@@ -94,6 +94,11 @@ virtio_transport_alloc_skb(struct virtio_vsock_pkt_info *info,
                                         info->op,
                                         info->flags);
 
+       if (info->vsk && !skb_set_owner_sk_safe(skb, sk_vsock(info->vsk))) {
+               WARN_ONCE(1, "failed to allocate skb on vsock socket with sk_refcnt == 0\n");
+               goto out;
+       }
+
        return skb;
 
 out:
@@ -1303,6 +1308,11 @@ void virtio_transport_recv_pkt(struct virtio_transport *t,
                goto free_pkt;
        }
 
+       if (!skb_set_owner_sk_safe(skb, sk)) {
+               WARN_ONCE(1, "receiving vsock socket has sk_refcnt == 0\n");
+               goto free_pkt;
+       }
+
        vsk = vsock_sk(sk);
 
        lock_sock(sk);
index 36eb16a..95cc4d7 100644 (file)
@@ -1842,7 +1842,13 @@ static ssize_t vmci_transport_stream_enqueue(
        struct msghdr *msg,
        size_t len)
 {
-       return vmci_qpair_enquev(vmci_trans(vsk)->qpair, msg, len, 0);
+       ssize_t err;
+
+       err = vmci_qpair_enquev(vmci_trans(vsk)->qpair, msg, len, 0);
+       if (err < 0)
+               err = -ENOMEM;
+
+       return err;
 }
 
 static s64 vmci_transport_stream_has_data(struct vsock_sock *vsk)
index 9ea633f..4ffa3a5 100644 (file)
@@ -81,6 +81,7 @@ struct hdmi_spec_per_pin {
        struct delayed_work work;
        struct hdmi_pcm *pcm; /* pointer to spec->pcm_rec[n] dynamically*/
        int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */
+       int prev_pcm_idx; /* previously assigned pcm index */
        int repoll_count;
        bool setup; /* the stream has been set up by prepare callback */
        bool silent_stream;
@@ -1380,9 +1381,17 @@ static void hdmi_attach_hda_pcm(struct hdmi_spec *spec,
        /* pcm already be attached to the pin */
        if (per_pin->pcm)
                return;
+       /* try the previously used slot at first */
+       idx = per_pin->prev_pcm_idx;
+       if (idx >= 0) {
+               if (!test_bit(idx, &spec->pcm_bitmap))
+                       goto found;
+               per_pin->prev_pcm_idx = -1; /* no longer valid, clear it */
+       }
        idx = hdmi_find_pcm_slot(spec, per_pin);
        if (idx == -EBUSY)
                return;
+ found:
        per_pin->pcm_idx = idx;
        per_pin->pcm = get_hdmi_pcm(spec, idx);
        set_bit(idx, &spec->pcm_bitmap);
@@ -1398,6 +1407,7 @@ static void hdmi_detach_hda_pcm(struct hdmi_spec *spec,
                return;
        idx = per_pin->pcm_idx;
        per_pin->pcm_idx = -1;
+       per_pin->prev_pcm_idx = idx; /* remember the previous index */
        per_pin->pcm = NULL;
        if (idx >= 0 && idx < spec->pcm_used)
                clear_bit(idx, &spec->pcm_bitmap);
@@ -1924,6 +1934,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 
                per_pin->pcm = NULL;
                per_pin->pcm_idx = -1;
+               per_pin->prev_pcm_idx = -1;
                per_pin->pin_nid = pin_nid;
                per_pin->pin_nid_idx = spec->num_nids;
                per_pin->dev_id = i;
index a2706fd..26187f5 100644 (file)
@@ -2624,6 +2624,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
        SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
        SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
+       SND_PCI_QUIRK(0x1558, 0x3702, "Clevo X370SN[VW]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
        SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
        SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
        SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
@@ -9443,6 +9444,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8b47, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b5d, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8b5e, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8b66, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8b7a, "HP", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b7d, "HP", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b87, "HP", ALC236_FIXUP_HP_GPIO_LED),
index 4a69ce7..0acdf01 100644 (file)
@@ -269,6 +269,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "8A43"),
                }
        },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+                       DMI_MATCH(DMI_BOARD_NAME, "8A22"),
+               }
+       },
        {}
 };
 
index 0068780..1c1f211 100644 (file)
@@ -2022,6 +2022,11 @@ static int da7213_i2c_probe(struct i2c_client *i2c)
        return ret;
 }
 
+static void da7213_i2c_remove(struct i2c_client *i2c)
+{
+       pm_runtime_disable(&i2c->dev);
+}
+
 static int __maybe_unused da7213_runtime_suspend(struct device *dev)
 {
        struct da7213_priv *da7213 = dev_get_drvdata(dev);
@@ -2065,6 +2070,7 @@ static struct i2c_driver da7213_i2c_driver = {
                .pm = &da7213_pm,
        },
        .probe_new      = da7213_i2c_probe,
+       .remove         = da7213_i2c_remove,
        .id_table       = da7213_i2c_id,
 };
 
index ed4f7cd..8b6b760 100644 (file)
@@ -436,23 +436,28 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_device *hdev,
        return 0;
 }
 
-static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai,
-               unsigned int tx_mask, unsigned int rx_mask,
-               int slots, int slot_width)
+static int hdac_hdmi_set_stream(struct snd_soc_dai *dai,
+                               void *stream, int direction)
 {
        struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
        struct hdac_device *hdev = hdmi->hdev;
        struct hdac_hdmi_dai_port_map *dai_map;
        struct hdac_hdmi_pcm *pcm;
+       struct hdac_stream *hstream;
 
-       dev_dbg(&hdev->dev, "%s: strm_tag: %d\n", __func__, tx_mask);
+       if (!stream)
+               return -EINVAL;
+
+       hstream = (struct hdac_stream *)stream;
+
+       dev_dbg(&hdev->dev, "%s: strm_tag: %d\n", __func__, hstream->stream_tag);
 
        dai_map = &hdmi->dai_map[dai->id];
 
        pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
 
        if (pcm)
-               pcm->stream_tag = (tx_mask << 4);
+               pcm->stream_tag = (hstream->stream_tag << 4);
 
        return 0;
 }
@@ -1544,7 +1549,7 @@ static const struct snd_soc_dai_ops hdmi_dai_ops = {
        .startup = hdac_hdmi_pcm_open,
        .shutdown = hdac_hdmi_pcm_close,
        .hw_params = hdac_hdmi_set_hw_params,
-       .set_tdm_slot = hdac_hdmi_set_tdm_slot,
+       .set_stream = hdac_hdmi_set_stream,
 };
 
 /*
index a73a7d7..faba423 100644 (file)
@@ -3670,9 +3670,9 @@ static int __maybe_unused rx_macro_runtime_suspend(struct device *dev)
        regcache_cache_only(rx->regmap, true);
        regcache_mark_dirty(rx->regmap);
 
-       clk_disable_unprepare(rx->mclk);
-       clk_disable_unprepare(rx->npl);
        clk_disable_unprepare(rx->fsgen);
+       clk_disable_unprepare(rx->npl);
+       clk_disable_unprepare(rx->mclk);
 
        return 0;
 }
index 473d3cd..589c490 100644 (file)
@@ -2098,9 +2098,9 @@ static int __maybe_unused tx_macro_runtime_suspend(struct device *dev)
        regcache_cache_only(tx->regmap, true);
        regcache_mark_dirty(tx->regmap);
 
-       clk_disable_unprepare(tx->mclk);
-       clk_disable_unprepare(tx->npl);
        clk_disable_unprepare(tx->fsgen);
+       clk_disable_unprepare(tx->npl);
+       clk_disable_unprepare(tx->mclk);
 
        return 0;
 }
index ba7480f..3f6f1bd 100644 (file)
@@ -2506,9 +2506,9 @@ static int __maybe_unused wsa_macro_runtime_suspend(struct device *dev)
        regcache_cache_only(wsa->regmap, true);
        regcache_mark_dirty(wsa->regmap);
 
-       clk_disable_unprepare(wsa->mclk);
-       clk_disable_unprepare(wsa->npl);
        clk_disable_unprepare(wsa->fsgen);
+       clk_disable_unprepare(wsa->npl);
+       clk_disable_unprepare(wsa->mclk);
 
        return 0;
 }
index 79e0039..5a12940 100644 (file)
@@ -533,6 +533,18 @@ static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream,
 
 /* Please keep this list alphabetically sorted */
 static const struct dmi_system_id byt_rt5640_quirk_table[] = {
+       {       /* Acer Iconia One 7 B1-750 */
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "VESPA2"),
+               },
+               .driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
+                                       BYT_RT5640_JD_SRC_JD1_IN4P |
+                                       BYT_RT5640_OVCD_TH_1500UA |
+                                       BYT_RT5640_OVCD_SF_0P75 |
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
        {       /* Acer Iconia Tab 8 W1-810 */
                .matches = {
                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
index d2ed807..767fa89 100644 (file)
@@ -213,6 +213,17 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                                        SOF_SDW_PCH_DMIC |
                                        RT711_JD1),
        },
+       {
+               /* NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"),
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       SOF_SDW_PCH_DMIC |
+                                       RT711_JD2_100K),
+       },
        /* TigerLake-SDCA devices */
        {
                .callback = sof_sdw_quirk_cb,
index 28dd204..d8c8004 100644 (file)
@@ -354,6 +354,20 @@ static const struct snd_soc_acpi_link_adr adl_sdw_rt711_link0_rt1316_link3[] = {
        {}
 };
 
+static const struct snd_soc_acpi_link_adr adl_sdw_rt711_link0_rt1316_link2[] = {
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+               .adr_d = rt711_sdca_0_adr,
+       },
+       {
+               .mask = BIT(2),
+               .num_adr = ARRAY_SIZE(rt1316_2_single_adr),
+               .adr_d = rt1316_2_single_adr,
+       },
+       {}
+};
+
 static const struct snd_soc_acpi_adr_device mx8373_2_adr[] = {
        {
                .adr = 0x000223019F837300ull,
@@ -625,6 +639,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
                .sof_tplg_filename = "sof-adl-rt711-l0-rt1316-l3.tplg",
        },
        {
+               .link_mask = 0x5, /* 2 active links required */
+               .links = adl_sdw_rt711_link0_rt1316_link2,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-adl-rt711-l0-rt1316-l2.tplg",
+       },
+       {
                .link_mask = 0x1, /* link0 required */
                .links = adl_rvp,
                .drv_name = "sof_sdw",
index 5eb056b..7958c9d 100644 (file)
@@ -1661,10 +1661,14 @@ static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream)
        struct snd_pcm_hardware *hw = &runtime->hw;
        struct snd_soc_dai *dai;
        int stream = substream->stream;
+       u64 formats = hw->formats;
        int i;
 
        soc_pcm_hw_init(hw);
 
+       if (formats)
+               hw->formats &= formats;
+
        for_each_rtd_cpu_dais(fe, i, dai) {
                struct snd_soc_pcm_stream *cpu_stream;
 
index a623707..669b99a 100644 (file)
@@ -1805,6 +1805,14 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
        u32 header, extension;
        int ret;
 
+       if (!src_fw_module || !sink_fw_module) {
+               /* The NULL module will print as "(efault)" */
+               dev_err(sdev->dev, "source %s or sink %s widget weren't set up properly\n",
+                       src_fw_module->man4_module_entry.name,
+                       sink_fw_module->man4_module_entry.name);
+               return -ENODEV;
+       }
+
        sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
                                                     SOF_PIN_TYPE_SOURCE);
        if (sroute->src_queue_id < 0) {
index 8ede4b9..246b56d 100644 (file)
@@ -405,6 +405,9 @@ static int sof_ipc4_tx_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_
 static int sof_ipc4_set_get_data(struct snd_sof_dev *sdev, void *data,
                                 size_t payload_bytes, bool set)
 {
+       const struct sof_dsp_power_state target_state = {
+                       .state = SOF_DSP_PM_D0,
+       };
        size_t payload_limit = sdev->ipc->max_payload_size;
        struct sof_ipc4_msg *ipc4_msg = data;
        struct sof_ipc4_msg tx = {{ 0 }};
@@ -435,6 +438,11 @@ static int sof_ipc4_set_get_data(struct snd_sof_dev *sdev, void *data,
 
        tx.extension |= SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK(1);
 
+       /* ensure the DSP is in D0i0 before sending IPC */
+       ret = snd_sof_dsp_set_power_state(sdev, &target_state);
+       if (ret < 0)
+               return ret;
+
        /* Serialise IPC TX */
        mutex_lock(&sdev->ipc->tx_mutex);
 
index 958ee9b..4c89ff3 100644 (file)
@@ -108,6 +108,7 @@ static noinline void check_new_node(struct maple_tree *mt)
        MT_BUG_ON(mt, mn->slot[1] != NULL);
        MT_BUG_ON(mt, mas_allocated(&mas) != 0);
 
+       mn->parent = ma_parent_ptr(mn);
        ma_free_rcu(mn);
        mas.node = MAS_START;
        mas_nomem(&mas, GFP_KERNEL);
@@ -160,6 +161,7 @@ static noinline void check_new_node(struct maple_tree *mt)
                MT_BUG_ON(mt, mas_allocated(&mas) != i);
                MT_BUG_ON(mt, !mn);
                MT_BUG_ON(mt, not_empty(mn));
+               mn->parent = ma_parent_ptr(mn);
                ma_free_rcu(mn);
        }
 
@@ -192,6 +194,7 @@ static noinline void check_new_node(struct maple_tree *mt)
                MT_BUG_ON(mt, not_empty(mn));
                MT_BUG_ON(mt, mas_allocated(&mas) != i - 1);
                MT_BUG_ON(mt, !mn);
+               mn->parent = ma_parent_ptr(mn);
                ma_free_rcu(mn);
        }
 
@@ -210,6 +213,7 @@ static noinline void check_new_node(struct maple_tree *mt)
                        mn = mas_pop_node(&mas);
                        MT_BUG_ON(mt, not_empty(mn));
                        MT_BUG_ON(mt, mas_allocated(&mas) != j - 1);
+                       mn->parent = ma_parent_ptr(mn);
                        ma_free_rcu(mn);
                }
                MT_BUG_ON(mt, mas_allocated(&mas) != 0);
@@ -233,6 +237,7 @@ static noinline void check_new_node(struct maple_tree *mt)
                        MT_BUG_ON(mt, mas_allocated(&mas) != i - j);
                        mn = mas_pop_node(&mas);
                        MT_BUG_ON(mt, not_empty(mn));
+                       mn->parent = ma_parent_ptr(mn);
                        ma_free_rcu(mn);
                        MT_BUG_ON(mt, mas_allocated(&mas) != i - j - 1);
                }
@@ -269,6 +274,7 @@ static noinline void check_new_node(struct maple_tree *mt)
                        mn = mas_pop_node(&mas); /* get the next node. */
                        MT_BUG_ON(mt, mn == NULL);
                        MT_BUG_ON(mt, not_empty(mn));
+                       mn->parent = ma_parent_ptr(mn);
                        ma_free_rcu(mn);
                }
                MT_BUG_ON(mt, mas_allocated(&mas) != 0);
@@ -294,6 +300,7 @@ static noinline void check_new_node(struct maple_tree *mt)
                        mn = mas_pop_node(&mas2); /* get the next node. */
                        MT_BUG_ON(mt, mn == NULL);
                        MT_BUG_ON(mt, not_empty(mn));
+                       mn->parent = ma_parent_ptr(mn);
                        ma_free_rcu(mn);
                }
                MT_BUG_ON(mt, mas_allocated(&mas2) != 0);
@@ -334,10 +341,12 @@ static noinline void check_new_node(struct maple_tree *mt)
        MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 2);
        mn = mas_pop_node(&mas);
        MT_BUG_ON(mt, not_empty(mn));
+       mn->parent = ma_parent_ptr(mn);
        ma_free_rcu(mn);
        for (i = 1; i <= MAPLE_ALLOC_SLOTS + 1; i++) {
                mn = mas_pop_node(&mas);
                MT_BUG_ON(mt, not_empty(mn));
+               mn->parent = ma_parent_ptr(mn);
                ma_free_rcu(mn);
        }
        MT_BUG_ON(mt, mas_allocated(&mas) != 0);
@@ -375,6 +384,7 @@ static noinline void check_new_node(struct maple_tree *mt)
                mas_node_count(&mas, i); /* Request */
                mas_nomem(&mas, GFP_KERNEL); /* Fill request */
                mn = mas_pop_node(&mas); /* get the next node. */
+               mn->parent = ma_parent_ptr(mn);
                ma_free_rcu(mn);
                mas_destroy(&mas);
 
@@ -382,10 +392,13 @@ static noinline void check_new_node(struct maple_tree *mt)
                mas_node_count(&mas, i); /* Request */
                mas_nomem(&mas, GFP_KERNEL); /* Fill request */
                mn = mas_pop_node(&mas); /* get the next node. */
+               mn->parent = ma_parent_ptr(mn);
                ma_free_rcu(mn);
                mn = mas_pop_node(&mas); /* get the next node. */
+               mn->parent = ma_parent_ptr(mn);
                ma_free_rcu(mn);
                mn = mas_pop_node(&mas); /* get the next node. */
+               mn->parent = ma_parent_ptr(mn);
                ma_free_rcu(mn);
                mas_destroy(&mas);
        }
@@ -35369,6 +35382,7 @@ static noinline void check_prealloc(struct maple_tree *mt)
        MT_BUG_ON(mt, allocated != 1 + height * 3);
        mn = mas_pop_node(&mas);
        MT_BUG_ON(mt, mas_allocated(&mas) != allocated - 1);
+       mn->parent = ma_parent_ptr(mn);
        ma_free_rcu(mn);
        MT_BUG_ON(mt, mas_preallocate(&mas, GFP_KERNEL) != 0);
        mas_destroy(&mas);
@@ -35386,6 +35400,7 @@ static noinline void check_prealloc(struct maple_tree *mt)
        mas_destroy(&mas);
        allocated = mas_allocated(&mas);
        MT_BUG_ON(mt, allocated != 0);
+       mn->parent = ma_parent_ptr(mn);
        ma_free_rcu(mn);
 
        MT_BUG_ON(mt, mas_preallocate(&mas, GFP_KERNEL) != 0);
@@ -35756,6 +35771,7 @@ void farmer_tests(void)
        tree.ma_root = mt_mk_node(node, maple_leaf_64);
        mt_dump(&tree);
 
+       node->parent = ma_parent_ptr(node);
        ma_free_rcu(node);
 
        /* Check things that will make lockdep angry */
index 582669c..c6a8c73 100644 (file)
@@ -18,6 +18,7 @@
 #include <grp.h>
 #include <stdbool.h>
 #include <stdarg.h>
+#include <linux/mount.h>
 
 #include "../kselftest_harness.h"
 
index 0fd0d2d..a26c562 100755 (executable)
@@ -60,6 +60,7 @@ ip link set dev $VETH up
 ip -n $NETNS link set dev $VETH up
 chk_rps "changing rps_default_mask affect newly created devices" "" $VETH 3
 chk_rps "changing rps_default_mask don't affect newly child netns[II]" $NETNS $VETH 0
+ip link del dev $VETH
 ip netns del $NETNS
 
 setup
index b64845b..4fb9368 100644 (file)
@@ -61,7 +61,7 @@ and
       id=channel0,name=agent-ctl-path\
  ##data path##
      -chardev pipe,id=charchannel1,path=/tmp/virtio-trace/trace-path-cpu0\
-     -device virtserialport,bus=virtio-serial0.0,nr=2,chardev=charchannel0,\
+     -device virtserialport,bus=virtio-serial0.0,nr=2,chardev=charchannel1,\
       id=channel1,name=trace-path-cpu0\
       ...
 
index 2a3ed40..b0af834 100644 (file)
@@ -55,6 +55,15 @@ irqfd_inject(struct work_struct *work)
                            irqfd->gsi, 1, false);
 }
 
+static void irqfd_resampler_notify(struct kvm_kernel_irqfd_resampler *resampler)
+{
+       struct kvm_kernel_irqfd *irqfd;
+
+       list_for_each_entry_srcu(irqfd, &resampler->list, resampler_link,
+                                srcu_read_lock_held(&resampler->kvm->irq_srcu))
+               eventfd_signal(irqfd->resamplefd, 1);
+}
+
 /*
  * Since resampler irqfds share an IRQ source ID, we de-assert once
  * then notify all of the resampler irqfds using this GSI.  We can't
@@ -65,7 +74,6 @@ irqfd_resampler_ack(struct kvm_irq_ack_notifier *kian)
 {
        struct kvm_kernel_irqfd_resampler *resampler;
        struct kvm *kvm;
-       struct kvm_kernel_irqfd *irqfd;
        int idx;
 
        resampler = container_of(kian,
@@ -76,11 +84,7 @@ irqfd_resampler_ack(struct kvm_irq_ack_notifier *kian)
                    resampler->notifier.gsi, 0, false);
 
        idx = srcu_read_lock(&kvm->irq_srcu);
-
-       list_for_each_entry_srcu(irqfd, &resampler->list, resampler_link,
-           srcu_read_lock_held(&kvm->irq_srcu))
-               eventfd_signal(irqfd->resamplefd, 1);
-
+       irqfd_resampler_notify(resampler);
        srcu_read_unlock(&kvm->irq_srcu, idx);
 }
 
@@ -96,8 +100,12 @@ irqfd_resampler_shutdown(struct kvm_kernel_irqfd *irqfd)
        synchronize_srcu(&kvm->irq_srcu);
 
        if (list_empty(&resampler->list)) {
-               list_del(&resampler->link);
+               list_del_rcu(&resampler->link);
                kvm_unregister_irq_ack_notifier(kvm, &resampler->notifier);
+               /*
+                * synchronize_srcu(&kvm->irq_srcu) already called
+                * in kvm_unregister_irq_ack_notifier().
+                */
                kvm_set_irq(kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID,
                            resampler->notifier.gsi, 0, false);
                kfree(resampler);
@@ -369,7 +377,7 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
                        resampler->notifier.irq_acked = irqfd_resampler_ack;
                        INIT_LIST_HEAD(&resampler->link);
 
-                       list_add(&resampler->link, &kvm->irqfds.resampler_list);
+                       list_add_rcu(&resampler->link, &kvm->irqfds.resampler_list);
                        kvm_register_irq_ack_notifier(kvm,
                                                      &resampler->notifier);
                        irqfd->resampler = resampler;
@@ -644,6 +652,31 @@ void kvm_irq_routing_update(struct kvm *kvm)
        spin_unlock_irq(&kvm->irqfds.lock);
 }
 
+bool kvm_notify_irqfd_resampler(struct kvm *kvm,
+                               unsigned int irqchip,
+                               unsigned int pin)
+{
+       struct kvm_kernel_irqfd_resampler *resampler;
+       int gsi, idx;
+
+       idx = srcu_read_lock(&kvm->irq_srcu);
+       gsi = kvm_irq_map_chip_pin(kvm, irqchip, pin);
+       if (gsi != -1) {
+               list_for_each_entry_srcu(resampler,
+                                        &kvm->irqfds.resampler_list, link,
+                                        srcu_read_lock_held(&kvm->irq_srcu)) {
+                       if (resampler->notifier.gsi == gsi) {
+                               irqfd_resampler_notify(resampler);
+                               srcu_read_unlock(&kvm->irq_srcu, idx);
+                               return true;
+                       }
+               }
+       }
+       srcu_read_unlock(&kvm->irq_srcu, idx);
+
+       return false;
+}
+
 /*
  * create a host-wide workqueue for issuing deferred shutdown requests
  * aggregated from all vm* instances. We need our own isolated
index d255964..b1679d0 100644 (file)
@@ -4479,7 +4479,6 @@ static long kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
 #endif
 #ifdef CONFIG_HAVE_KVM_IRQFD
        case KVM_CAP_IRQFD:
-       case KVM_CAP_IRQFD_RESAMPLE:
 #endif
        case KVM_CAP_IOEVENTFD_ANY_LENGTH:
        case KVM_CAP_CHECK_EXTENSION_VM: