Merge tag 'mac80211-for-davem-2020-08-28' of git://git.kernel.org/pub/scm/linux/kerne...
authorDavid S. Miller <davem@davemloft.net>
Fri, 28 Aug 2020 13:16:48 +0000 (06:16 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 28 Aug 2020 13:16:48 +0000 (06:16 -0700)
Johannes Berg says:

====================
We have:
 * fixes for AQL (airtime queue limits)
 * reduce packet loss detection false positives
 * a small channel number fix for the 6 GHz band
 * a fix for 80+80/160 MHz negotiation
 * an nl80211 attribute (NL80211_ATTR_HE_6GHZ_CAPABILITY) fix
 * add a missing sanity check for the regulatory code
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
340 files changed:
.mailmap
Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7
Documentation/admin-guide/ext4.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/devicetree/bindings/clock/imx23-clock.yaml
Documentation/devicetree/bindings/clock/imx28-clock.yaml
Documentation/devicetree/bindings/gpio/gpio-mxs.yaml
Documentation/devicetree/bindings/i2c/i2c-mxs.yaml
Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.yaml
Documentation/devicetree/bindings/mmc/mxs-mmc.yaml
Documentation/devicetree/bindings/net/dsa/dsa.txt
Documentation/devicetree/bindings/net/ethernet-controller.yaml
Documentation/devicetree/bindings/net/renesas,ether.yaml
Documentation/devicetree/bindings/pci/intel-gw-pcie.yaml
Documentation/devicetree/bindings/pwm/mxs-pwm.yaml
Documentation/devicetree/bindings/spi/fsl-imx-cspi.yaml
Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml
Documentation/devicetree/bindings/thermal/imx-thermal.yaml
Documentation/devicetree/bindings/timer/sifive,clint.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/vendor-prefixes.yaml
Documentation/devicetree/writing-schema.rst
Documentation/filesystems/ext4/about.rst
MAINTAINERS
Makefile
arch/arm64/Makefile
arch/arm64/include/asm/kvm_host.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/entry.S
arch/arm64/kernel/process.c
arch/arm64/kernel/vdso32/Makefile
arch/arm64/kvm/arm.c
arch/arm64/kvm/mmu.c
arch/ia64/include/asm/pgtable.h
arch/mips/include/asm/kvm_host.h
arch/mips/kvm/mmu.c
arch/powerpc/include/asm/cputable.h
arch/powerpc/include/asm/fixmap.h
arch/powerpc/include/asm/kasan.h
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/asm/mce.h
arch/powerpc/include/asm/perf_event.h
arch/powerpc/include/asm/perf_event_server.h
arch/powerpc/include/uapi/asm/perf_regs.h
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/dt_cpu_ftrs.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kvm/book3s.c
arch/powerpc/kvm/e500_mmu_host.c
arch/powerpc/mm/book3s32/mmu.c
arch/powerpc/mm/book3s64/hash_utils.c
arch/powerpc/perf/core-book3s.c
arch/powerpc/perf/hv-24x7.c
arch/powerpc/perf/perf_regs.c
arch/powerpc/perf/power10-pmu.c
arch/powerpc/perf/power9-pmu.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/pseries/hotplug-cpu.c
arch/powerpc/platforms/pseries/ras.c
arch/riscv/Kconfig
arch/riscv/Kconfig.socs
arch/riscv/configs/nommu_virt_defconfig
arch/riscv/configs/rv32_defconfig
arch/riscv/include/asm/clint.h [deleted file]
arch/riscv/include/asm/smp.h
arch/riscv/include/asm/timex.h
arch/riscv/kernel/Makefile
arch/riscv/kernel/clint.c [deleted file]
arch/riscv/kernel/sbi.c
arch/riscv/kernel/setup.c
arch/riscv/kernel/smp.c
arch/riscv/kernel/smpboot.c
arch/s390/kernel/ptrace.c
arch/s390/kernel/runtime_instr.c
arch/s390/pci/pci.c
arch/s390/pci/pci_bus.c
arch/s390/pci/pci_bus.h
arch/s390/pci/pci_event.c
arch/x86/boot/compressed/misc.c
arch/x86/boot/string.h
arch/x86/entry/calling.h
arch/x86/events/intel/uncore_snb.c
arch/x86/include/asm/efi.h
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/x86.c
arch/x86/pci/xen.c
arch/x86/platform/efi/efi.c
arch/x86/platform/efi/efi_32.c
arch/x86/platform/efi/efi_64.c
drivers/atm/firestream.c
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/timer-clint.c [new file with mode: 0644]
drivers/clocksource/timer-riscv.c
drivers/edac/i7core_edac.c
drivers/edac/pnd2_edac.c
drivers/edac/sb_edac.c
drivers/edac/skx_common.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/libstub/efi-stub-helper.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
drivers/gpu/drm/amd/display/dc/bios/command_table2.c
drivers/gpu/drm/amd/display/dc/bios/command_table2.h
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/dc_bios_types.h
drivers/gpu/drm/amd/display/dc/dce/dce_panel_cntl.h
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.h
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
drivers/gpu/drm/amd/display/include/bios_parser_types.h
drivers/gpu/drm/amd/display/include/fixed31_32.h
drivers/gpu/drm/amd/display/modules/freesync/freesync.c
drivers/gpu/drm/amd/powerplay/arcturus_ppt.c
drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_display_debugfs.c
drivers/gpu/drm/i915/display/intel_display_power.c
drivers/gpu/drm/i915/gvt/cfg_space.c
drivers/gpu/drm/i915/gvt/gtt.c
drivers/gpu/drm/i915/gvt/gtt.h
drivers/gpu/drm/i915/gvt/gvt.h
drivers/gpu/drm/i915/gvt/vgpu.c
drivers/gpu/drm/i915/i915_pmu.c
drivers/gpu/drm/i915/selftests/i915_buddy.c
drivers/gpu/drm/i915/selftests/mock_gem_device.c
drivers/gpu/drm/virtio/virtgpu_ioctl.c
drivers/gpu/drm/virtio/virtgpu_object.c
drivers/infiniband/core/device.c
drivers/infiniband/hw/bnxt_re/main.c
drivers/infiniband/hw/hfi1/tid_rdma.c
drivers/infiniband/hw/hns/hns_roce_device.h
drivers/infiniband/hw/hns/hns_roce_hw_v1.c
drivers/infiniband/hw/hns/hns_roce_hw_v2.c
drivers/infiniband/hw/hns/hns_roce_hw_v2.h
drivers/infiniband/hw/hns/hns_roce_qp.c
drivers/infiniband/hw/hns/hns_roce_srq.c
drivers/infiniband/hw/usnic/usnic_ib_main.c
drivers/iommu/dma-iommu.c
drivers/net/dsa/b53/b53_common.c
drivers/net/dsa/mt7530.c
drivers/net/dsa/ocelot/felix.c
drivers/net/dsa/sja1105/sja1105_main.c
drivers/net/ethernet/arc/emac_mdio.c
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/hisilicon/hns/hns_enet.c
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
drivers/net/ethernet/renesas/ravb_main.c
drivers/net/ethernet/sfc/ef100.c
drivers/net/ethernet/sfc/ef100_rx.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/cpsw_new.c
drivers/net/gtp.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/phy/dp83869.c
drivers/net/phy/mscc/mscc_main.c
drivers/net/usb/Kconfig
drivers/net/usb/asix_common.c
drivers/net/wan/lapbether.c
drivers/nfc/st95hf/core.c
drivers/of/address.c
drivers/opp/core.c
drivers/pci/hotplug/s390_pci_hpc.c
drivers/pci/p2pdma.c
drivers/s390/cio/css.c
drivers/s390/scsi/zfcp_fsf.c
drivers/scsi/qla2xxx/qla_dbg.h
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_nvme.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/scsi_debug.c
drivers/scsi/ufs/ti-j721e-ufs.c
drivers/scsi/ufs/ufs-mediatek.c
drivers/scsi/ufs/ufshcd-pci.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h
drivers/spi/Kconfig
drivers/spi/spi-stm32.c
drivers/spi/spi.c
drivers/vfio/pci/vfio_pci_private.h
drivers/vfio/pci/vfio_pci_rdwr.c
drivers/vfio/vfio_iommu_type1.c
drivers/video/fbdev/efifb.c
fs/afs/dynroot.c
fs/afs/fs_operation.c
fs/afs/fs_probe.c
fs/afs/internal.h
fs/afs/proc.c
fs/afs/vl_list.c
fs/afs/vl_probe.c
fs/afs/vl_rotate.c
fs/buffer.c
fs/eventpoll.c
fs/ext4/Kconfig
fs/ext4/balloc.c
fs/ext4/block_validity.c
fs/ext4/ext4.h
fs/ext4/ext4_jbd2.c
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/hash.c
fs/ext4/indirect.c
fs/ext4/inline.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/mballoc.h
fs/ext4/move_extent.c
fs/ext4/namei.c
fs/ext4/readpage.c
fs/ext4/super.c
fs/ext4/sysfs.c
fs/ext4/xattr.c
fs/io_uring.c
fs/jbd2/journal.c
fs/jbd2/recovery.c
fs/jbd2/transaction.c
fs/romfs/storage.c
fs/squashfs/block.c
include/linux/cpuhotplug.h
include/linux/dma-direct.h
include/linux/dma-mapping.h
include/linux/jbd2.h
include/linux/netfilter/nf_conntrack_sctp.h
include/linux/pgtable.h
include/linux/skbuff.h
include/net/af_rxrpc.h
include/net/ndisc.h
include/net/netfilter/nf_tables.h
include/trace/events/ext4.h
include/trace/events/rxrpc.h
include/uapi/linux/bpf.h
include/uapi/linux/in.h
include/uapi/linux/netfilter/nf_tables.h
kernel/bpf/bpf_iter.c
kernel/bpf/task_iter.c
kernel/dma/direct.c
kernel/dma/pool.c
kernel/entry/common.c
kernel/events/uprobes.c
kernel/relay.c
lib/Makefile
mm/hugetlb_cgroup.c
mm/khugepaged.c
mm/memory.c
mm/page_alloc.c
mm/rodata_test.c
mm/vmalloc.c
net/batman-adv/bat_v_ogm.c
net/batman-adv/bridge_loop_avoidance.c
net/batman-adv/gateway_client.c
net/caif/cfrfml.c
net/core/dev.c
net/core/netpoll.c
net/core/skbuff.c
net/core/sock.c
net/ipv4/fib_trie.c
net/ipv4/nexthop.c
net/ipv4/raw.c
net/ipv6/ip6_tunnel.c
net/l3mdev/l3mdev.c
net/mptcp/protocol.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_payload.c
net/netfilter/nft_set_rbtree.c
net/netlabel/netlabel_domainhash.c
net/rxrpc/ar-internal.h
net/rxrpc/call_object.c
net/rxrpc/input.c
net/rxrpc/output.c
net/rxrpc/peer_object.c
net/rxrpc/rtt.c
net/rxrpc/rxkad.c
net/sched/act_ct.c
net/sched/sch_taprio.c
net/sctp/socket.c
net/sctp/stream.c
net/smc/smc_diag.c
net/socket.c
net/tipc/crypto.c
scripts/Makefile.extrawarn
scripts/extract-cert.c
scripts/genksyms/keywords.c
scripts/kconfig/qconf.cc
scripts/kconfig/qconf.h
sound/hda/hdac_bus.c
sound/hda/hdac_controller.c
sound/isa/sscape.c
sound/pci/hda/patch_realtek.c
sound/soc/amd/acp3x-rt5682-max9836.c
sound/soc/amd/renoir/acp3x-pdm-dma.c
sound/soc/codecs/msm8916-wcd-analog.c
sound/soc/codecs/wm8958-dsp2.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8994.c
sound/soc/fsl/fsl-asoc-card.c
sound/soc/fsl/mpc5200_dma.c
sound/soc/intel/atom/sst-mfld-platform-pcm.c
sound/soc/qcom/qdsp6/q6afe-dai.c
sound/soc/qcom/qdsp6/q6routing.c
sound/soc/soc-component.c
sound/soc/tegra/tegra186_dspk.c
sound/soc/tegra/tegra210_admaif.c
sound/soc/tegra/tegra210_ahub.c
sound/soc/tegra/tegra210_dmic.c
sound/soc/tegra/tegra210_i2s.c
sound/usb/mixer.c
sound/usb/quirks-table.h
tools/bpf/bpftool/pids.c
tools/bpf/resolve_btfids/main.c
tools/include/uapi/linux/bpf.h
tools/lib/bpf/btf_dump.c
tools/lib/bpf/libbpf.c
tools/testing/selftests/bpf/.gitignore
tools/testing/selftests/bpf/Makefile
tools/testing/selftests/bpf/prog_tests/test_global_funcs.c
tools/testing/selftests/kvm/x86_64/debug_regs.c
virt/kvm/kvm_main.c

index 97fd835..332c783 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -32,6 +32,7 @@ Alex Shi <alex.shi@linux.alibaba.com> <alex.shi@intel.com>
 Alex Shi <alex.shi@linux.alibaba.com> <alex.shi@linaro.org>
 Al Viro <viro@ftp.linux.org.uk>
 Al Viro <viro@zenIV.linux.org.uk>
+Andi Kleen <ak@linux.intel.com> <ak@suse.de>
 Andi Shyti <andi@etezian.org> <andi.shyti@samsung.com>
 Andreas Herrmann <aherrman@de.ibm.com>
 Andrew Morton <akpm@linux-foundation.org>
@@ -132,6 +133,7 @@ Jan Glauber <jan.glauber@gmail.com> <jang@de.ibm.com>
 Jan Glauber <jan.glauber@gmail.com> <jang@linux.vnet.ibm.com>
 Jan Glauber <jan.glauber@gmail.com> <jglauber@cavium.com>
 Jason Gunthorpe <jgg@ziepe.ca> <jgg@mellanox.com>
+Jason Gunthorpe <jgg@ziepe.ca> <jgg@nvidia.com>
 Jason Gunthorpe <jgg@ziepe.ca> <jgunthorpe@obsidianresearch.com>
 <javier@osg.samsung.com> <javier.martinez@collabora.co.uk>
 Javi Merino <javi.merino@kernel.org> <javi.merino@arm.com>
@@ -178,6 +180,7 @@ Leonardo Bras <leobras.c@gmail.com> <leonardo@linux.ibm.com>
 Leonid I Ananiev <leonid.i.ananiev@intel.com>
 Leon Romanovsky <leon@kernel.org> <leon@leon.nu>
 Leon Romanovsky <leon@kernel.org> <leonro@mellanox.com>
+Leon Romanovsky <leon@kernel.org> <leonro@nvidia.com>
 Linas Vepstas <linas@austin.ibm.com>
 Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@ascom.ch>
 Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@web.de>
index f7e32f2..e82fc37 100644 (file)
@@ -43,7 +43,7 @@ Description:  read only
                This sysfs interface exposes the number of cores per chip
                present in the system.
 
-What:          /sys/devices/hv_24x7/interface/cpumask
+What:          /sys/devices/hv_24x7/cpumask
 Date:          July 2020
 Contact:       Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
 Description:   read only
index a683976..d2795ca 100644 (file)
@@ -489,6 +489,9 @@ Files in /sys/fs/ext4/<devname>:
         multiple of this tuning parameter if the stripe size is not set in the
         ext4 superblock
 
+  mb_max_inode_prealloc
+        The maximum length of per-inode ext4_prealloc_space list.
+
   mb_max_to_scan
         The maximum number of extents the multiblock allocator will search to
         find the best extent.
@@ -529,21 +532,21 @@ Files in /sys/fs/ext4/<devname>:
 Ioctls
 ======
 
-There is some Ext4 specific functionality which can be accessed by applications
-through the system call interfaces. The list of all Ext4 specific ioctls are
-shown in the table below.
+Ext4 implements various ioctls which can be used by applications to access
+ext4-specific functionality. An incomplete list of these ioctls is shown in the
+table below. This list includes truly ext4-specific ioctls (``EXT4_IOC_*``) as
+well as ioctls that may have been ext4-specific originally but are now supported
+by some other filesystem(s) too (``FS_IOC_*``).
 
-Table of Ext4 specific ioctls
+Table of Ext4 ioctls
 
-  EXT4_IOC_GETFLAGS
+  FS_IOC_GETFLAGS
         Get additional attributes associated with inode.  The ioctl argument is
-        an integer bitfield, with bit values described in ext4.h. This ioctl is
-        an alias for FS_IOC_GETFLAGS.
+        an integer bitfield, with bit values described in ext4.h.
 
-  EXT4_IOC_SETFLAGS
+  FS_IOC_SETFLAGS
         Set additional attributes associated with inode.  The ioctl argument is
-        an integer bitfield, with bit values described in ext4.h. This ioctl is
-        an alias for FS_IOC_SETFLAGS.
+        an integer bitfield, with bit values described in ext4.h.
 
   EXT4_IOC_GETVERSION, EXT4_IOC_GETVERSION_OLD
         Get the inode i_generation number stored for each inode. The
index bdc1f33..a106874 100644 (file)
        efi=            [EFI]
                        Format: { "debug", "disable_early_pci_dma",
                                  "nochunk", "noruntime", "nosoftreserve",
-                                 "novamap", "no_disable_early_pci_dma",
-                                 "old_map" }
+                                 "novamap", "no_disable_early_pci_dma" }
                        debug: enable misc debug output.
                        disable_early_pci_dma: disable the busmaster bit on all
                        PCI bridges while in the EFI boot stub.
                        novamap: do not call SetVirtualAddressMap().
                        no_disable_early_pci_dma: Leave the busmaster bit set
                        on all PCI bridges while in the EFI boot stub
-                       old_map [X86-64]: switch to the old ioremap-based EFI
-                       runtime services mapping. [Needs CONFIG_X86_UV=y]
 
        efi_no_storage_paranoia [EFI; X86]
                        Using this parameter you can use more than 50% of
index 66cb238..ad21899 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Clock bindings for Freescale i.MX23
 
 maintainers:
-  - Shawn Guo <shawn.guo@linaro.org>
+  - Shawn Guo <shawnguo@kernel.org>
 
 description: |
   The clock consumer should specify the desired clock by having the clock
index 72328d5..f1af110 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Clock bindings for Freescale i.MX28
 
 maintainers:
-  - Shawn Guo <shawn.guo@linaro.org>
+  - Shawn Guo <shawnguo@kernel.org>
 
 description: |
   The clock consumer should specify the desired clock by having the clock
index ccf5b50..dfa1133 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Freescale MXS GPIO controller
 
 maintainers:
-  - Shawn Guo <shawn.guo@linaro.org>
+  - Shawn Guo <shawnguo@kernel.org>
   - Anson Huang <Anson.Huang@nxp.com>
 
 description: |
index d3134ed..21ae7bc 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Freescale MXS Inter IC (I2C) Controller
 
 maintainers:
-  - Shawn Guo <shawn.guo@linaro.org>
+  - Shawn Guo <shawnguo@kernel.org>
 
 properties:
   compatible:
index 75dc116..10b4596 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Freescale Enhanced Secure Digital Host Controller (eSDHC) for i.MX
 
 maintainers:
-  - Shawn Guo <shawn.guo@linaro.org>
+  - Shawn Guo <shawnguo@kernel.org>
 
 allOf:
   - $ref: "mmc-controller.yaml"
index 1cccc04..bec8f8c 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Freescale MXS MMC controller
 
 maintainers:
-  - Shawn Guo <shawn.guo@linaro.org>
+  - Shawn Guo <shawnguo@kernel.org>
 
 description: |
   The Freescale MXS Synchronous Serial Ports (SSP) can act as a MMC controller
index bf7328a..dab208b 100644 (file)
@@ -1,4 +1,4 @@
 Distributed Switch Architecture Device Tree Bindings
 ----------------------------------------------------
 
-See Documentation/devicetree/bindings/net/dsa/dsa.yaml for the documenation.
+See Documentation/devicetree/bindings/net/dsa/dsa.yaml for the documentation.
index 1c44740..fa2baca 100644 (file)
@@ -54,7 +54,8 @@ properties:
 
   phy-connection-type:
     description:
-      Operation mode of the PHY interface
+      Specifies interface type between the Ethernet device and a physical
+      layer (PHY) device.
     enum:
       # There is not a standard bus between the MAC and the PHY,
       # something proprietary is being used to embed the PHY in the
index 08678af..8ce5ed8 100644 (file)
@@ -59,9 +59,15 @@ properties:
   clocks:
     maxItems: 1
 
-  pinctrl-0: true
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
 
-  pinctrl-names: true
+  phy-mode: true
+
+  phy-handle: true
 
   renesas,no-ether-link:
     type: boolean
@@ -74,6 +80,11 @@ properties:
       specify when the Ether LINK signal is active-low instead of normal
       active-high
 
+patternProperties:
+  "^ethernet-phy@[0-9a-f]$":
+    type: object
+    $ref: ethernet-phy.yaml#
+
 required:
   - compatible
   - reg
@@ -83,7 +94,8 @@ required:
   - '#address-cells'
   - '#size-cells'
   - clocks
-  - pinctrl-0
+
+additionalProperties: false
 
 examples:
   # Lager board
@@ -99,8 +111,6 @@ examples:
         clocks = <&mstp8_clks R8A7790_CLK_ETHER>;
         phy-mode = "rmii";
         phy-handle = <&phy1>;
-        pinctrl-0 = <&ether_pins>;
-        pinctrl-names = "default";
         renesas,ether-link-active-low;
         #address-cells = <1>;
         #size-cells = <0>;
@@ -109,7 +119,5 @@ examples:
             reg = <1>;
             interrupt-parent = <&irqc0>;
             interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
-            pinctrl-0 = <&phy1_pins>;
-            pinctrl-names = "default";
         };
     };
index 64b2c64..a1e2be7 100644 (file)
@@ -9,6 +9,14 @@ title: PCIe RC controller on Intel Gateway SoCs
 maintainers:
   - Dilip Kota <eswara.kota@linux.intel.com>
 
+select:
+  properties:
+    compatible:
+      contains:
+        const: intel,lgm-pcie
+  required:
+    - compatible
+
 properties:
   compatible:
     items:
index da68f4a..8740e07 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Freescale MXS PWM controller
 
 maintainers:
-  - Shawn Guo <shawn.guo@linaro.org>
+  - Shawn Guo <shawnguo@kernel.org>
   - Anson Huang <anson.huang@nxp.com>
 
 properties:
index 1b50ced..50df1a4 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Freescale (Enhanced) Configurable Serial Peripheral Interface (CSPI/eCSPI) for i.MX
 
 maintainers:
-  - Shawn Guo <shawn.guo@linaro.org>
+  - Shawn Guo <shawnguo@kernel.org>
 
 allOf:
   - $ref: "/schemas/spi/spi-controller.yaml#"
index 22882e7..312d8fe 100644 (file)
@@ -39,6 +39,7 @@ properties:
       spi common code does not support use of CS signals discontinuously.
       i.MX8DXL-EVK board only uses CS1 without using CS0. Therefore, add
       this property to re-config the chipselect value in the LPSPI driver.
+    type: boolean
 
 required:
   - compatible
index aedac16..16b57f5 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: NXP i.MX Thermal Binding
 
 maintainers:
-  - Shawn Guo <shawn.guo@linaro.org>
+  - Shawn Guo <shawnguo@kernel.org>
   - Anson Huang <Anson.Huang@nxp.com>
 
 properties:
diff --git a/Documentation/devicetree/bindings/timer/sifive,clint.yaml b/Documentation/devicetree/bindings/timer/sifive,clint.yaml
new file mode 100644 (file)
index 0000000..2a0e9cd
--- /dev/null
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/timer/sifive,clint.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SiFive Core Local Interruptor
+
+maintainers:
+  - Palmer Dabbelt <palmer@dabbelt.com>
+  - Anup Patel <anup.patel@wdc.com>
+
+description:
+  SiFive (and other RISC-V) SOCs include an implementation of the SiFive
+  Core Local Interruptor (CLINT) for M-mode timer and M-mode inter-processor
+  interrupts. It directly connects to the timer and inter-processor interrupt
+  lines of various HARTs (or CPUs) so RISC-V per-HART (or per-CPU) local
+  interrupt controller is the parent interrupt controller for CLINT device.
+  The clock frequency of CLINT is specified via "timebase-frequency" DT
+  property of "/cpus" DT node. The "timebase-frequency" DT property is
+  described in Documentation/devicetree/bindings/riscv/cpus.yaml
+
+properties:
+  compatible:
+    items:
+      - const: sifive,fu540-c000-clint
+      - const: sifive,clint0
+
+    description:
+      Should be "sifive,<chip>-clint" and "sifive,clint<version>".
+      Supported compatible strings are -
+      "sifive,fu540-c000-clint" for the SiFive CLINT v0 as integrated
+      onto the SiFive FU540 chip, and "sifive,clint0" for the SiFive
+      CLINT v0 IP block with no chip integration tweaks.
+      Please refer to sifive-blocks-ip-versioning.txt for details
+
+  reg:
+    maxItems: 1
+
+  interrupts-extended:
+    minItems: 1
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts-extended
+
+examples:
+  - |
+    timer@2000000 {
+      compatible = "sifive,fu540-c000-clint", "sifive,clint0";
+      interrupts-extended = <&cpu1intc 3 &cpu1intc 7
+                             &cpu2intc 3 &cpu2intc 7
+                             &cpu3intc 3 &cpu3intc 7
+                             &cpu4intc 3 &cpu4intc 7>;
+       reg = <0x2000000 0x10000>;
+    };
+...
index 2baee2c..63996ab 100644 (file)
@@ -993,7 +993,7 @@ patternProperties:
   "^sst,.*":
     description: Silicon Storage Technology, Inc.
   "^sstar,.*":
-    description: Xiamen Xingchen(SigmaStar) Technology Co., Ltd. 
+    description: Xiamen Xingchen(SigmaStar) Technology Co., Ltd.
       (formerly part of MStar Semiconductor, Inc.)
   "^st,.*":
     description: STMicroelectronics
index 8c74a99..16f21e1 100644 (file)
@@ -5,7 +5,7 @@ Writing DeviceTree Bindings in json-schema
 
 Devicetree bindings are written using json-schema vocabulary. Schema files are
 written in a JSON compatible subset of YAML. YAML is used instead of JSON as it
-considered more human readable and has some advantages such as allowing
+is considered more human readable and has some advantages such as allowing
 comments (Prefixed with '#').
 
 Schema Contents
@@ -19,7 +19,7 @@ $id
   A json-schema unique identifier string. The string must be a valid
   URI typically containing the binding's filename and path. For DT schema, it must
   begin with "http://devicetree.org/schemas/". The URL is used in constructing
-  references to other files specified in schema "$ref" properties. A $ref values
+  references to other files specified in schema "$ref" properties. A $ref value
   with a leading '/' will have the hostname prepended. A $ref value a relative
   path or filename only will be prepended with the hostname and path components
   of the current schema file's '$id' value. A URL is used even for local files,
index 0aadba0..cc76b57 100644 (file)
@@ -39,6 +39,6 @@ entry.
 Other References
 ----------------
 
-Also see http://www.nongnu.org/ext2-doc/ for quite a collection of
+Also see https://www.nongnu.org/ext2-doc/ for quite a collection of
 information about ext2/3. Here's another old reference:
 http://wiki.osdev.org/Ext2
index deaafb6..f8b2991 100644 (file)
@@ -3388,6 +3388,7 @@ M:        Florian Fainelli <f.fainelli@gmail.com>
 L:     netdev@vger.kernel.org
 L:     openwrt-devel@lists.openwrt.org (subscribers-only)
 S:     Supported
+F:     Documentation/devicetree/bindings/net/dsa/b53.txt
 F:     drivers/net/dsa/b53/*
 F:     include/linux/platform_data/b53.h
 
@@ -3573,13 +3574,28 @@ L:      bcm-kernel-feedback-list@broadcom.com
 S:     Maintained
 F:     drivers/phy/broadcom/phy-brcm-usb*
 
+BROADCOM ETHERNET PHY DRIVERS
+M:     Florian Fainelli <f.fainelli@gmail.com>
+L:     bcm-kernel-feedback-list@broadcom.com
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     Documentation/devicetree/bindings/net/broadcom-bcm87xx.txt
+F:     drivers/net/phy/bcm*.[ch]
+F:     drivers/net/phy/broadcom.c
+F:     include/linux/brcmphy.h
+
 BROADCOM GENET ETHERNET DRIVER
 M:     Doug Berger <opendmb@gmail.com>
 M:     Florian Fainelli <f.fainelli@gmail.com>
 L:     bcm-kernel-feedback-list@broadcom.com
 L:     netdev@vger.kernel.org
 S:     Supported
+F:     Documentation/devicetree/bindings/net/brcm,bcmgenet.txt
+F:     Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt
 F:     drivers/net/ethernet/broadcom/genet/
+F:     drivers/net/mdio/mdio-bcm-unimac.c
+F:     include/linux/platform_data/bcmgenet.h
+F:     include/linux/platform_data/mdio-bcm-unimac.h
 
 BROADCOM IPROC ARM ARCHITECTURE
 M:     Ray Jui <rjui@broadcom.com>
@@ -5050,7 +5066,7 @@ F:        include/linux/dm-*.h
 F:     include/uapi/linux/dm-*.h
 
 DEVLINK
-M:     Jiri Pirko <jiri@mellanox.com>
+M:     Jiri Pirko <jiri@nvidia.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     Documentation/networking/devlink
@@ -6081,7 +6097,7 @@ F:        include/linux/dynamic_debug.h
 F:     lib/dynamic_debug.c
 
 DYNAMIC INTERRUPT MODERATION
-M:     Tal Gilboa <talgi@mellanox.com>
+M:     Tal Gilboa <talgi@nvidia.com>
 S:     Maintained
 F:     Documentation/networking/net_dim.rst
 F:     include/linux/dim.h
@@ -6161,7 +6177,7 @@ F:        Documentation/devicetree/bindings/edac/aspeed-sdram-edac.txt
 F:     drivers/edac/aspeed_edac.c
 
 EDAC-BLUEFIELD
-M:     Shravan Kumar Ramani <sramani@mellanox.com>
+M:     Shravan Kumar Ramani <sramani@nvidia.com>
 S:     Supported
 F:     drivers/edac/bluefield_edac.c
 
@@ -6483,8 +6499,8 @@ S:        Odd Fixes
 F:     drivers/net/ethernet/agere/
 
 ETHERNET BRIDGE
-M:     Roopa Prabhu <roopa@cumulusnetworks.com>
-M:     Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
+M:     Roopa Prabhu <roopa@nvidia.com>
+M:     Nikolay Aleksandrov <nikolay@nvidia.com>
 L:     bridge@lists.linux-foundation.org (moderated for non-subscribers)
 L:     netdev@vger.kernel.org
 S:     Maintained
@@ -6494,7 +6510,6 @@ F:        net/bridge/
 
 ETHERNET PHY LIBRARY
 M:     Andrew Lunn <andrew@lunn.ch>
-M:     Florian Fainelli <f.fainelli@gmail.com>
 M:     Heiner Kallweit <hkallweit1@gmail.com>
 R:     Russell King <linux@armlinux.org.uk>
 L:     netdev@vger.kernel.org
@@ -6599,7 +6614,7 @@ F:        drivers/iommu/exynos-iommu.c
 
 EZchip NPS platform support
 M:     Vineet Gupta <vgupta@synopsys.com>
-M:     Ofer Levi <oferle@mellanox.com>
+M:     Ofer Levi <oferle@nvidia.com>
 S:     Supported
 F:     arch/arc/boot/dts/eznps.dts
 F:     arch/arc/plat-eznps
@@ -8563,7 +8578,7 @@ F:        drivers/iio/pressure/dps310.c
 
 INFINIBAND SUBSYSTEM
 M:     Doug Ledford <dledford@redhat.com>
-M:     Jason Gunthorpe <jgg@mellanox.com>
+M:     Jason Gunthorpe <jgg@nvidia.com>
 L:     linux-rdma@vger.kernel.org
 S:     Supported
 W:     https://github.com/linux-rdma/rdma-core
@@ -9226,7 +9241,7 @@ F:        drivers/firmware/iscsi_ibft*
 
 ISCSI EXTENSIONS FOR RDMA (ISER) INITIATOR
 M:     Sagi Grimberg <sagi@grimberg.me>
-M:     Max Gurtovoy <maxg@mellanox.com>
+M:     Max Gurtovoy <maxg@nvidia.com>
 L:     linux-rdma@vger.kernel.org
 S:     Supported
 W:     http://www.openfabrics.org
@@ -11072,7 +11087,7 @@ F:      Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt
 F:     drivers/input/touchscreen/melfas_mip4.c
 
 MELLANOX ETHERNET DRIVER (mlx4_en)
-M:     Tariq Toukan <tariqt@mellanox.com>
+M:     Tariq Toukan <tariqt@nvidia.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 W:     http://www.mellanox.com
@@ -11080,7 +11095,7 @@ Q:      http://patchwork.ozlabs.org/project/netdev/list/
 F:     drivers/net/ethernet/mellanox/mlx4/en_*
 
 MELLANOX ETHERNET DRIVER (mlx5e)
-M:     Saeed Mahameed <saeedm@mellanox.com>
+M:     Saeed Mahameed <saeedm@nvidia.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 W:     http://www.mellanox.com
@@ -11088,7 +11103,7 @@ Q:      http://patchwork.ozlabs.org/project/netdev/list/
 F:     drivers/net/ethernet/mellanox/mlx5/core/en_*
 
 MELLANOX ETHERNET INNOVA DRIVERS
-R:     Boris Pismenny <borisp@mellanox.com>
+R:     Boris Pismenny <borisp@nvidia.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 W:     http://www.mellanox.com
@@ -11099,8 +11114,8 @@ F:      drivers/net/ethernet/mellanox/mlx5/core/fpga/*
 F:     include/linux/mlx5/mlx5_ifc_fpga.h
 
 MELLANOX ETHERNET SWITCH DRIVERS
-M:     Jiri Pirko <jiri@mellanox.com>
-M:     Ido Schimmel <idosch@mellanox.com>
+M:     Jiri Pirko <jiri@nvidia.com>
+M:     Ido Schimmel <idosch@nvidia.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 W:     http://www.mellanox.com
@@ -11109,7 +11124,7 @@ F:      drivers/net/ethernet/mellanox/mlxsw/
 F:     tools/testing/selftests/drivers/net/mlxsw/
 
 MELLANOX FIRMWARE FLASH LIBRARY (mlxfw)
-M:     mlxsw@mellanox.com
+M:     mlxsw@nvidia.com
 L:     netdev@vger.kernel.org
 S:     Supported
 W:     http://www.mellanox.com
@@ -11119,7 +11134,7 @@ F:      drivers/net/ethernet/mellanox/mlxfw/
 MELLANOX HARDWARE PLATFORM SUPPORT
 M:     Andy Shevchenko <andy@infradead.org>
 M:     Darren Hart <dvhart@infradead.org>
-M:     Vadim Pasternak <vadimp@mellanox.com>
+M:     Vadim Pasternak <vadimp@nvidia.com>
 L:     platform-driver-x86@vger.kernel.org
 S:     Supported
 F:     Documentation/ABI/testing/sysfs-platform-mellanox-bootctl
@@ -11127,7 +11142,7 @@ F:      drivers/platform/mellanox/
 F:     include/linux/platform_data/mlxreg.h
 
 MELLANOX MLX4 core VPI driver
-M:     Tariq Toukan <tariqt@mellanox.com>
+M:     Tariq Toukan <tariqt@nvidia.com>
 L:     netdev@vger.kernel.org
 L:     linux-rdma@vger.kernel.org
 S:     Supported
@@ -11137,7 +11152,7 @@ F:      drivers/net/ethernet/mellanox/mlx4/
 F:     include/linux/mlx4/
 
 MELLANOX MLX4 IB driver
-M:     Yishai Hadas <yishaih@mellanox.com>
+M:     Yishai Hadas <yishaih@nvidia.com>
 L:     linux-rdma@vger.kernel.org
 S:     Supported
 W:     http://www.mellanox.com
@@ -11147,8 +11162,8 @@ F:      include/linux/mlx4/
 F:     include/uapi/rdma/mlx4-abi.h
 
 MELLANOX MLX5 core VPI driver
-M:     Saeed Mahameed <saeedm@mellanox.com>
-M:     Leon Romanovsky <leonro@mellanox.com>
+M:     Saeed Mahameed <saeedm@nvidia.com>
+M:     Leon Romanovsky <leonro@nvidia.com>
 L:     netdev@vger.kernel.org
 L:     linux-rdma@vger.kernel.org
 S:     Supported
@@ -11159,7 +11174,7 @@ F:      drivers/net/ethernet/mellanox/mlx5/core/
 F:     include/linux/mlx5/
 
 MELLANOX MLX5 IB driver
-M:     Leon Romanovsky <leonro@mellanox.com>
+M:     Leon Romanovsky <leonro@nvidia.com>
 L:     linux-rdma@vger.kernel.org
 S:     Supported
 W:     http://www.mellanox.com
@@ -11169,8 +11184,8 @@ F:      include/linux/mlx5/
 F:     include/uapi/rdma/mlx5-abi.h
 
 MELLANOX MLXCPLD I2C AND MUX DRIVER
-M:     Vadim Pasternak <vadimp@mellanox.com>
-M:     Michael Shych <michaelsh@mellanox.com>
+M:     Vadim Pasternak <vadimp@nvidia.com>
+M:     Michael Shych <michaelsh@nvidia.com>
 L:     linux-i2c@vger.kernel.org
 S:     Supported
 F:     Documentation/i2c/busses/i2c-mlxcpld.rst
@@ -11178,7 +11193,7 @@ F:      drivers/i2c/busses/i2c-mlxcpld.c
 F:     drivers/i2c/muxes/i2c-mux-mlxcpld.c
 
 MELLANOX MLXCPLD LED DRIVER
-M:     Vadim Pasternak <vadimp@mellanox.com>
+M:     Vadim Pasternak <vadimp@nvidia.com>
 L:     linux-leds@vger.kernel.org
 S:     Supported
 F:     Documentation/leds/leds-mlxcpld.rst
@@ -11186,7 +11201,7 @@ F:      drivers/leds/leds-mlxcpld.c
 F:     drivers/leds/leds-mlxreg.c
 
 MELLANOX PLATFORM DRIVER
-M:     Vadim Pasternak <vadimp@mellanox.com>
+M:     Vadim Pasternak <vadimp@nvidia.com>
 L:     platform-driver-x86@vger.kernel.org
 S:     Supported
 F:     drivers/platform/x86/mlx-platform.c
@@ -12167,8 +12182,8 @@ F:      net/ipv6/syncookies.c
 F:     net/ipv6/tcp*.c
 
 NETWORKING [TLS]
-M:     Boris Pismenny <borisp@mellanox.com>
-M:     Aviad Yehezkel <aviadye@mellanox.com>
+M:     Boris Pismenny <borisp@nvidia.com>
+M:     Aviad Yehezkel <aviadye@nvidia.com>
 M:     John Fastabend <john.fastabend@gmail.com>
 M:     Daniel Borkmann <daniel@iogearbox.net>
 M:     Jakub Kicinski <kuba@kernel.org>
@@ -12468,7 +12483,7 @@ S:      Supported
 F:     drivers/nfc/nxp-nci
 
 OBJAGG
-M:     Jiri Pirko <jiri@mellanox.com>
+M:     Jiri Pirko <jiri@nvidia.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     include/linux/objagg.h
@@ -13110,7 +13125,7 @@ F:      drivers/video/logo/logo_parisc*
 F:     include/linux/hp_sdc.h
 
 PARMAN
-M:     Jiri Pirko <jiri@mellanox.com>
+M:     Jiri Pirko <jiri@nvidia.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     include/linux/parman.h
@@ -16034,7 +16049,7 @@ F:      drivers/infiniband/sw/siw/
 F:     include/uapi/rdma/siw-abi.h
 
 SOFT-ROCE DRIVER (rxe)
-M:     Zhu Yanjun <yanjunz@mellanox.com>
+M:     Zhu Yanjun <yanjunz@nvidia.com>
 L:     linux-rdma@vger.kernel.org
 S:     Supported
 F:     drivers/infiniband/sw/rxe/
index 9cac6fd..c4470a4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -265,8 +265,7 @@ no-dot-config-targets := $(clean-targets) \
                         $(version_h) headers headers_% archheaders archscripts \
                         %asm-generic kernelversion %src-pkg dt_binding_check \
                         outputmakefile
-no-sync-config-targets := $(no-dot-config-targets) install %install \
-                          kernelrelease
+no-sync-config-targets := $(no-dot-config-targets) %install kernelrelease
 single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.s %.symtypes %/
 
 config-build   :=
@@ -292,7 +291,7 @@ ifneq ($(KBUILD_EXTMOD),)
 endif
 
 ifeq ($(KBUILD_EXTMOD),)
-        ifneq ($(filter config %config,$(MAKECMDGOALS)),)
+        ifneq ($(filter %config,$(MAKECMDGOALS)),)
                config-build := 1
                 ifneq ($(words $(MAKECMDGOALS)),1)
                        mixed-build := 1
index 55bc854..b45f012 100644 (file)
@@ -165,6 +165,7 @@ zinstall install:
 PHONY += vdso_install
 vdso_install:
        $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@
+       $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 $@
 
 # We use MRPROPER_FILES and CLEAN_FILES now
 archclean:
index 65568b2..e52c927 100644 (file)
@@ -473,7 +473,7 @@ int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
 
 #define KVM_ARCH_WANT_MMU_NOTIFIER
 int kvm_unmap_hva_range(struct kvm *kvm,
-                       unsigned long start, unsigned long end);
+                       unsigned long start, unsigned long end, unsigned flags);
 int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
 int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
 int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
index 6bd1d3a..c332d49 100644 (file)
@@ -910,6 +910,8 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
                .desc = "ARM erratum 1418040",
                .capability = ARM64_WORKAROUND_1418040,
                ERRATA_MIDR_RANGE_LIST(erratum_1418040_list),
+               .type = (ARM64_CPUCAP_SCOPE_LOCAL_CPU |
+                        ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU),
        },
 #endif
 #ifdef CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT
index 2646178..55af8b5 100644 (file)
@@ -170,19 +170,6 @@ alternative_cb_end
        stp     x28, x29, [sp, #16 * 14]
 
        .if     \el == 0
-       .if     \regsize == 32
-       /*
-        * If we're returning from a 32-bit task on a system affected by
-        * 1418040 then re-enable userspace access to the virtual counter.
-        */
-#ifdef CONFIG_ARM64_ERRATUM_1418040
-alternative_if ARM64_WORKAROUND_1418040
-       mrs     x0, cntkctl_el1
-       orr     x0, x0, #2      // ARCH_TIMER_USR_VCT_ACCESS_EN
-       msr     cntkctl_el1, x0
-alternative_else_nop_endif
-#endif
-       .endif
        clear_gp_regs
        mrs     x21, sp_el0
        ldr_this_cpu    tsk, __entry_task, x20
@@ -294,14 +281,6 @@ alternative_else_nop_endif
        tst     x22, #PSR_MODE32_BIT            // native task?
        b.eq    3f
 
-#ifdef CONFIG_ARM64_ERRATUM_1418040
-alternative_if ARM64_WORKAROUND_1418040
-       mrs     x0, cntkctl_el1
-       bic     x0, x0, #2                      // ARCH_TIMER_USR_VCT_ACCESS_EN
-       msr     cntkctl_el1, x0
-alternative_else_nop_endif
-#endif
-
 #ifdef CONFIG_ARM64_ERRATUM_845719
 alternative_if ARM64_WORKAROUND_845719
 #ifdef CONFIG_PID_IN_CONTEXTIDR
index 84ec630..b63ce4c 100644 (file)
@@ -515,6 +515,39 @@ static void entry_task_switch(struct task_struct *next)
        __this_cpu_write(__entry_task, next);
 }
 
+/*
+ * ARM erratum 1418040 handling, affecting the 32bit view of CNTVCT.
+ * Assuming the virtual counter is enabled at the beginning of times:
+ *
+ * - disable access when switching from a 64bit task to a 32bit task
+ * - enable access when switching from a 32bit task to a 64bit task
+ */
+static void erratum_1418040_thread_switch(struct task_struct *prev,
+                                         struct task_struct *next)
+{
+       bool prev32, next32;
+       u64 val;
+
+       if (!(IS_ENABLED(CONFIG_ARM64_ERRATUM_1418040) &&
+             cpus_have_const_cap(ARM64_WORKAROUND_1418040)))
+               return;
+
+       prev32 = is_compat_thread(task_thread_info(prev));
+       next32 = is_compat_thread(task_thread_info(next));
+
+       if (prev32 == next32)
+               return;
+
+       val = read_sysreg(cntkctl_el1);
+
+       if (!next32)
+               val |= ARCH_TIMER_USR_VCT_ACCESS_EN;
+       else
+               val &= ~ARCH_TIMER_USR_VCT_ACCESS_EN;
+
+       write_sysreg(val, cntkctl_el1);
+}
+
 /*
  * Thread switching.
  */
@@ -530,6 +563,7 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
        entry_task_switch(next);
        uao_thread_switch(next);
        ssbs_thread_switch(next);
+       erratum_1418040_thread_switch(prev, next);
 
        /*
         * Complete any pending TLB or cache maintenance on this CPU in case
index 5139a5f..d6adb46 100644 (file)
@@ -208,7 +208,7 @@ quiet_cmd_vdsosym = VDSOSYM $@
       cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
 
 # Install commands for the unstripped file
-quiet_cmd_vdso_install = INSTALL $@
+quiet_cmd_vdso_install = INSTALL32 $@
       cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/vdso32.so
 
 vdso.so: $(obj)/vdso.so.dbg
index 691d21e..46dc3d7 100644 (file)
@@ -1640,6 +1640,10 @@ int kvm_arch_init(void *opaque)
                return -ENODEV;
        }
 
+       if (cpus_have_final_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE))
+               kvm_info("Guests without required CPU erratum workarounds can deadlock system!\n" \
+                        "Only trusted guests should be used on this system.\n");
+
        for_each_online_cpu(cpu) {
                smp_call_function_single(cpu, check_kvm_target_cpu, &ret, 1);
                if (ret < 0) {
index 0121ef2..ba00bcc 100644 (file)
@@ -343,7 +343,8 @@ static void unmap_stage2_p4ds(struct kvm_s2_mmu *mmu, pgd_t *pgd,
  * destroying the VM), otherwise another faulting VCPU may come in and mess
  * with things behind our backs.
  */
-static void unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 size)
+static void __unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 size,
+                                bool may_block)
 {
        struct kvm *kvm = mmu->kvm;
        pgd_t *pgd;
@@ -369,11 +370,16 @@ static void unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 si
                 * If the range is too large, release the kvm->mmu_lock
                 * to prevent starvation and lockup detector warnings.
                 */
-               if (next != end)
+               if (may_block && next != end)
                        cond_resched_lock(&kvm->mmu_lock);
        } while (pgd++, addr = next, addr != end);
 }
 
+static void unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 size)
+{
+       __unmap_stage2_range(mmu, start, size, true);
+}
+
 static void stage2_flush_ptes(struct kvm_s2_mmu *mmu, pmd_t *pmd,
                              phys_addr_t addr, phys_addr_t end)
 {
@@ -2208,18 +2214,21 @@ static int handle_hva_to_gpa(struct kvm *kvm,
 
 static int kvm_unmap_hva_handler(struct kvm *kvm, gpa_t gpa, u64 size, void *data)
 {
-       unmap_stage2_range(&kvm->arch.mmu, gpa, size);
+       unsigned flags = *(unsigned *)data;
+       bool may_block = flags & MMU_NOTIFIER_RANGE_BLOCKABLE;
+
+       __unmap_stage2_range(&kvm->arch.mmu, gpa, size, may_block);
        return 0;
 }
 
 int kvm_unmap_hva_range(struct kvm *kvm,
-                       unsigned long start, unsigned long end)
+                       unsigned long start, unsigned long end, unsigned flags)
 {
        if (!kvm->arch.mmu.pgd)
                return 0;
 
        trace_kvm_unmap_hva_range(start, end);
-       handle_hva_to_gpa(kvm, start, end, &kvm_unmap_hva_handler, NULL);
+       handle_hva_to_gpa(kvm, start, end, &kvm_unmap_hva_handler, &flags);
        return 0;
 }
 
index 1085089..779b697 100644 (file)
@@ -366,6 +366,15 @@ pgd_index (unsigned long address)
 }
 #define pgd_index pgd_index
 
+/*
+ * In the kernel's mapped region we know everything is in region number 5, so
+ * as an optimisation its PGD already points to the area for that region.
+ * However, this also means that we cannot use pgd_index() and we must
+ * never add the region here.
+ */
+#define pgd_offset_k(addr) \
+       (init_mm.pgd + (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)))
+
 /* Look up a pgd entry in the gate area.  On IA-64, the gate-area
    resides in the kernel-mapped segment, hence we use pgd_offset_k()
    here.  */
index d35eaed..825d337 100644 (file)
@@ -969,7 +969,7 @@ enum kvm_mips_fault_result kvm_trap_emul_gva_fault(struct kvm_vcpu *vcpu,
 
 #define KVM_ARCH_WANT_MMU_NOTIFIER
 int kvm_unmap_hva_range(struct kvm *kvm,
-                       unsigned long start, unsigned long end);
+                       unsigned long start, unsigned long end, unsigned flags);
 int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
 int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
 int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
index 87fa8d8..28c366d 100644 (file)
@@ -486,7 +486,8 @@ static int kvm_unmap_hva_handler(struct kvm *kvm, gfn_t gfn, gfn_t gfn_end,
        return 1;
 }
 
-int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end,
+                       unsigned flags)
 {
        handle_hva_to_gpa(kvm, start, end, &kvm_unmap_hva_handler, NULL);
 
index fdddb82..e005b45 100644 (file)
@@ -9,6 +9,11 @@
 
 #ifndef __ASSEMBLY__
 
+/*
+ * Added to include __machine_check_early_realmode_* functions
+ */
+#include <asm/mce.h>
+
 /* This structure can grow, it's real size is used by head.S code
  * via the mkdefs mechanism.
  */
index 925cf89..6bfc879 100644 (file)
@@ -52,7 +52,7 @@ enum fixed_addresses {
        FIX_HOLE,
        /* reserve the top 128K for early debugging purposes */
        FIX_EARLY_DEBUG_TOP = FIX_HOLE,
-       FIX_EARLY_DEBUG_BASE = FIX_EARLY_DEBUG_TOP+(ALIGN(SZ_128, PAGE_SIZE)/PAGE_SIZE)-1,
+       FIX_EARLY_DEBUG_BASE = FIX_EARLY_DEBUG_TOP+(ALIGN(SZ_128K, PAGE_SIZE)/PAGE_SIZE)-1,
 #ifdef CONFIG_HIGHMEM
        FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
        FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
index d635b96..7355ed0 100644 (file)
 #ifndef __ASSEMBLY__
 
 #include <asm/page.h>
+#include <linux/sizes.h>
 
 #define KASAN_SHADOW_SCALE_SHIFT       3
 
+#if defined(CONFIG_PPC_BOOK3S_32) && defined(CONFIG_MODULES) && defined(CONFIG_STRICT_KERNEL_RWX)
+#define KASAN_KERN_START       ALIGN_DOWN(PAGE_OFFSET - SZ_256M, SZ_256M)
+#else
+#define KASAN_KERN_START       PAGE_OFFSET
+#endif
+
 #define KASAN_SHADOW_START     (KASAN_SHADOW_OFFSET + \
-                                (PAGE_OFFSET >> KASAN_SHADOW_SCALE_SHIFT))
+                                (KASAN_KERN_START >> KASAN_SHADOW_SCALE_SHIFT))
 
 #define KASAN_SHADOW_OFFSET    ASM_CONST(CONFIG_KASAN_SHADOW_OFFSET)
 
index e020d26..10ded83 100644 (file)
@@ -58,7 +58,8 @@
 #define KVM_ARCH_WANT_MMU_NOTIFIER
 
 extern int kvm_unmap_hva_range(struct kvm *kvm,
-                              unsigned long start, unsigned long end);
+                              unsigned long start, unsigned long end,
+                              unsigned flags);
 extern int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
 extern int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
 extern int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
index adf2cda..89aa824 100644 (file)
@@ -210,6 +210,9 @@ struct mce_error_info {
 #define MCE_EVENT_RELEASE      true
 #define MCE_EVENT_DONTRELEASE  false
 
+struct pt_regs;
+struct notifier_block;
+
 extern void save_mce_event(struct pt_regs *regs, long handled,
                           struct mce_error_info *mce_err, uint64_t nip,
                           uint64_t addr, uint64_t phys_addr);
@@ -225,5 +228,9 @@ int mce_register_notifier(struct notifier_block *nb);
 int mce_unregister_notifier(struct notifier_block *nb);
 #ifdef CONFIG_PPC_BOOK3S_64
 void flush_and_reload_slb(void);
+long __machine_check_early_realmode_p7(struct pt_regs *regs);
+long __machine_check_early_realmode_p8(struct pt_regs *regs);
+long __machine_check_early_realmode_p9(struct pt_regs *regs);
+long __machine_check_early_realmode_p10(struct pt_regs *regs);
 #endif /* CONFIG_PPC_BOOK3S_64 */
 #endif /* __ASM_PPC64_MCE_H__ */
index 1e8b2e1..daec64d 100644 (file)
@@ -40,4 +40,7 @@ static inline bool is_sier_available(void) { return false; }
 
 /* To support perf_regs sier update */
 extern bool is_sier_available(void);
+/* To define perf extended regs mask value */
+extern u64 PERF_REG_EXTENDED_MASK;
+#define PERF_REG_EXTENDED_MASK PERF_REG_EXTENDED_MASK
 #endif
index 86c9eb0..f6acabb 100644 (file)
@@ -62,6 +62,11 @@ struct power_pmu {
        int             *blacklist_ev;
        /* BHRB entries in the PMU */
        int             bhrb_nr;
+       /*
+        * set this flag with `PERF_PMU_CAP_EXTENDED_REGS` if
+        * the pmu supports extended perf regs capability
+        */
+       int             capabilities;
 };
 
 /*
index f599064..bdf5f10 100644 (file)
@@ -48,6 +48,24 @@ enum perf_event_powerpc_regs {
        PERF_REG_POWERPC_DSISR,
        PERF_REG_POWERPC_SIER,
        PERF_REG_POWERPC_MMCRA,
-       PERF_REG_POWERPC_MAX,
+       /* Extended registers */
+       PERF_REG_POWERPC_MMCR0,
+       PERF_REG_POWERPC_MMCR1,
+       PERF_REG_POWERPC_MMCR2,
+       PERF_REG_POWERPC_MMCR3,
+       PERF_REG_POWERPC_SIER2,
+       PERF_REG_POWERPC_SIER3,
+       /* Max regs without the extended regs */
+       PERF_REG_POWERPC_MAX = PERF_REG_POWERPC_MMCRA + 1,
 };
+
+#define PERF_REG_PMU_MASK      ((1ULL << PERF_REG_POWERPC_MAX) - 1)
+
+/* PERF_REG_EXTENDED_MASK value for CPU_FTR_ARCH_300 */
+#define PERF_REG_PMU_MASK_300   (((1ULL << (PERF_REG_POWERPC_MMCR2 + 1)) - 1) - PERF_REG_PMU_MASK)
+/* PERF_REG_EXTENDED_MASK value for CPU_FTR_ARCH_31 */
+#define PERF_REG_PMU_MASK_31   (((1ULL << (PERF_REG_POWERPC_SIER3 + 1)) - 1) - PERF_REG_PMU_MASK)
+
+#define PERF_REG_MAX_ISA_300   (PERF_REG_POWERPC_MMCR2 + 1)
+#define PERF_REG_MAX_ISA_31    (PERF_REG_POWERPC_SIER3 + 1)
 #endif /* _UAPI_ASM_POWERPC_PERF_REGS_H */
index 3d406a9..2aa89c6 100644 (file)
@@ -72,9 +72,6 @@ extern void __setup_cpu_power9(unsigned long offset, struct cpu_spec* spec);
 extern void __restore_cpu_power9(void);
 extern void __setup_cpu_power10(unsigned long offset, struct cpu_spec* spec);
 extern void __restore_cpu_power10(void);
-extern long __machine_check_early_realmode_p7(struct pt_regs *regs);
-extern long __machine_check_early_realmode_p8(struct pt_regs *regs);
-extern long __machine_check_early_realmode_p9(struct pt_regs *regs);
 #endif /* CONFIG_PPC64 */
 #if defined(CONFIG_E500)
 extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
@@ -542,6 +539,25 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .machine_check_early    = __machine_check_early_realmode_p9,
                .platform               = "power9",
        },
+       {       /* Power10 */
+               .pvr_mask               = 0xffff0000,
+               .pvr_value              = 0x00800000,
+               .cpu_name               = "POWER10 (raw)",
+               .cpu_features           = CPU_FTRS_POWER10,
+               .cpu_user_features      = COMMON_USER_POWER10,
+               .cpu_user_features2     = COMMON_USER2_POWER10,
+               .mmu_features           = MMU_FTRS_POWER10,
+               .icache_bsize           = 128,
+               .dcache_bsize           = 128,
+               .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_IBM,
+               .oprofile_cpu_type      = "ppc64/power10",
+               .oprofile_type          = PPC_OPROFILE_INVALID,
+               .cpu_setup              = __setup_cpu_power10,
+               .cpu_restore            = __restore_cpu_power10,
+               .machine_check_early    = __machine_check_early_realmode_p10,
+               .platform               = "power10",
+       },
        {       /* Cell Broadband Engine */
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x00700000,
index 6f8c0c6..8dc46f3 100644 (file)
@@ -64,10 +64,6 @@ struct dt_cpu_feature {
  * Set up the base CPU
  */
 
-extern long __machine_check_early_realmode_p8(struct pt_regs *regs);
-extern long __machine_check_early_realmode_p9(struct pt_regs *regs);
-extern long __machine_check_early_realmode_p10(struct pt_regs *regs);
-
 static int hv_mode;
 
 static struct {
index b198b0f..808ec9f 100644 (file)
@@ -311,6 +311,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                                min = pvr & 0xFF;
                                break;
                        case 0x004e: /* POWER9 bits 12-15 give chip type */
+                       case 0x0080: /* POWER10 bit 12 gives SMT8/4 */
                                maj = (pvr >> 8) & 0x0F;
                                min = pvr & 0xFF;
                                break;
index 41fedec..49db50d 100644 (file)
@@ -834,7 +834,8 @@ void kvmppc_core_commit_memory_region(struct kvm *kvm,
        kvm->arch.kvm_ops->commit_memory_region(kvm, mem, old, new, change);
 }
 
-int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end,
+                       unsigned flags)
 {
        return kvm->arch.kvm_ops->unmap_hva_range(kvm, start, end);
 }
index d6c1069..ed0c9c4 100644 (file)
@@ -734,7 +734,8 @@ static int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
        return 0;
 }
 
-int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end,
+                       unsigned flags)
 {
        /* kvm_unmap_hva flushes everything anyways */
        kvm_unmap_hva(kvm, start);
index c016291..d426eaf 100644 (file)
@@ -191,10 +191,17 @@ static bool is_module_segment(unsigned long addr)
 {
        if (!IS_ENABLED(CONFIG_MODULES))
                return false;
+#ifdef MODULES_VADDR
+       if (addr < ALIGN_DOWN(MODULES_VADDR, SZ_256M))
+               return false;
+       if (addr > ALIGN(MODULES_END, SZ_256M) - 1)
+               return false;
+#else
        if (addr < ALIGN_DOWN(VMALLOC_START, SZ_256M))
                return false;
-       if (addr >= ALIGN(VMALLOC_END, SZ_256M))
+       if (addr > ALIGN(VMALLOC_END, SZ_256M) - 1)
                return false;
+#endif
        return true;
 }
 
index 1da9dbb..890a71c 100644 (file)
@@ -1115,8 +1115,10 @@ void hash__early_init_mmu_secondary(void)
                        && cpu_has_feature(CPU_FTR_HVMODE))
                tlbiel_all();
 
-       if (IS_ENABLED(CONFIG_PPC_MEM_KEYS) && mmu_has_feature(MMU_FTR_PKEY))
+#ifdef CONFIG_PPC_MEM_KEYS
+       if (mmu_has_feature(MMU_FTR_PKEY))
                mtspr(SPRN_UAMOR, default_uamor);
+#endif
 }
 #endif /* CONFIG_SMP */
 
index 78fe349..93d20e1 100644 (file)
@@ -2141,6 +2141,10 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
 
                if (perf_event_overflow(event, &data, regs))
                        power_pmu_stop(event, 0);
+       } else if (period) {
+               /* Account for interrupt in case of invalid SIAR */
+               if (perf_event_account_interrupt(event))
+                       power_pmu_stop(event, 0);
        }
 }
 
@@ -2323,6 +2327,7 @@ int register_power_pmu(struct power_pmu *pmu)
                pmu->name);
 
        power_pmu.attr_groups = ppmu->attr_groups;
+       power_pmu.capabilities |= (ppmu->capabilities & PERF_PMU_CAP_EXTENDED_REGS);
 
 #ifdef MSR_HV
        /*
index cdb7bfb..6e7e820 100644 (file)
@@ -1128,6 +1128,15 @@ static struct bin_attribute *if_bin_attrs[] = {
        NULL,
 };
 
+static struct attribute *cpumask_attrs[] = {
+       &dev_attr_cpumask.attr,
+       NULL,
+};
+
+static struct attribute_group cpumask_attr_group = {
+       .attrs = cpumask_attrs,
+};
+
 static struct attribute *if_attrs[] = {
        &dev_attr_catalog_len.attr,
        &dev_attr_catalog_version.attr,
@@ -1135,7 +1144,6 @@ static struct attribute *if_attrs[] = {
        &dev_attr_sockets.attr,
        &dev_attr_chipspersocket.attr,
        &dev_attr_coresperchip.attr,
-       &dev_attr_cpumask.attr,
        NULL,
 };
 
@@ -1151,6 +1159,7 @@ static const struct attribute_group *attr_groups[] = {
        &event_desc_group,
        &event_long_desc_group,
        &if_group,
+       &cpumask_attr_group,
        NULL,
 };
 
index a213a0a..8e53f2f 100644 (file)
 #include <asm/ptrace.h>
 #include <asm/perf_regs.h>
 
+u64 PERF_REG_EXTENDED_MASK;
+
 #define PT_REGS_OFFSET(id, r) [id] = offsetof(struct pt_regs, r)
 
-#define REG_RESERVED (~((1ULL << PERF_REG_POWERPC_MAX) - 1))
+#define REG_RESERVED (~(PERF_REG_EXTENDED_MASK | PERF_REG_PMU_MASK))
 
 static unsigned int pt_regs_offset[PERF_REG_POWERPC_MAX] = {
        PT_REGS_OFFSET(PERF_REG_POWERPC_R0,  gpr[0]),
@@ -69,10 +71,36 @@ static unsigned int pt_regs_offset[PERF_REG_POWERPC_MAX] = {
        PT_REGS_OFFSET(PERF_REG_POWERPC_MMCRA, dsisr),
 };
 
+/* Function to return the extended register values */
+static u64 get_ext_regs_value(int idx)
+{
+       switch (idx) {
+       case PERF_REG_POWERPC_MMCR0:
+               return mfspr(SPRN_MMCR0);
+       case PERF_REG_POWERPC_MMCR1:
+               return mfspr(SPRN_MMCR1);
+       case PERF_REG_POWERPC_MMCR2:
+               return mfspr(SPRN_MMCR2);
+#ifdef CONFIG_PPC64
+       case PERF_REG_POWERPC_MMCR3:
+               return mfspr(SPRN_MMCR3);
+       case PERF_REG_POWERPC_SIER2:
+               return mfspr(SPRN_SIER2);
+       case PERF_REG_POWERPC_SIER3:
+               return mfspr(SPRN_SIER3);
+#endif
+       default: return 0;
+       }
+}
+
 u64 perf_reg_value(struct pt_regs *regs, int idx)
 {
-       if (WARN_ON_ONCE(idx >= PERF_REG_POWERPC_MAX))
-               return 0;
+       u64 perf_reg_extended_max = PERF_REG_POWERPC_MAX;
+
+       if (cpu_has_feature(CPU_FTR_ARCH_31))
+               perf_reg_extended_max = PERF_REG_MAX_ISA_31;
+       else if (cpu_has_feature(CPU_FTR_ARCH_300))
+               perf_reg_extended_max = PERF_REG_MAX_ISA_300;
 
        if (idx == PERF_REG_POWERPC_SIER &&
           (IS_ENABLED(CONFIG_FSL_EMB_PERF_EVENT) ||
@@ -85,6 +113,16 @@ u64 perf_reg_value(struct pt_regs *regs, int idx)
            IS_ENABLED(CONFIG_PPC32)))
                return 0;
 
+       if (idx >= PERF_REG_POWERPC_MAX && idx < perf_reg_extended_max)
+               return get_ext_regs_value(idx);
+
+       /*
+        * If the idx is referring to value beyond the
+        * supported registers, return 0 with a warning
+        */
+       if (WARN_ON_ONCE(idx >= perf_reg_extended_max))
+               return 0;
+
        return regs_get_register(regs, pt_regs_offset[idx]);
 }
 
index f7cff7f..8314865 100644 (file)
@@ -87,6 +87,8 @@
 #define POWER10_MMCRA_IFM3             0x00000000C0000000UL
 #define POWER10_MMCRA_BHRB_MASK                0x00000000C0000000UL
 
+extern u64 PERF_REG_EXTENDED_MASK;
+
 /* Table of alternatives, sorted by column 0 */
 static const unsigned int power10_event_alternatives[][MAX_ALT] = {
        { PM_RUN_CYC_ALT,               PM_RUN_CYC },
@@ -397,6 +399,7 @@ static struct power_pmu power10_pmu = {
        .cache_events           = &power10_cache_events,
        .attr_groups            = power10_pmu_attr_groups,
        .bhrb_nr                = 32,
+       .capabilities           = PERF_PMU_CAP_EXTENDED_REGS,
 };
 
 int init_power10_pmu(void)
@@ -408,6 +411,9 @@ int init_power10_pmu(void)
            strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power10"))
                return -ENODEV;
 
+       /* Set the PERF_REG_EXTENDED_MASK here */
+       PERF_REG_EXTENDED_MASK = PERF_REG_PMU_MASK_31;
+
        rc = register_power_pmu(&power10_pmu);
        if (rc)
                return rc;
index 05dae38..2a57e93 100644 (file)
@@ -90,6 +90,8 @@ enum {
 #define POWER9_MMCRA_IFM3              0x00000000C0000000UL
 #define POWER9_MMCRA_BHRB_MASK         0x00000000C0000000UL
 
+extern u64 PERF_REG_EXTENDED_MASK;
+
 /* Nasty Power9 specific hack */
 #define PVR_POWER9_CUMULUS             0x00002000
 
@@ -434,6 +436,7 @@ static struct power_pmu power9_pmu = {
        .cache_events           = &power9_cache_events,
        .attr_groups            = power9_pmu_attr_groups,
        .bhrb_nr                = 32,
+       .capabilities           = PERF_PMU_CAP_EXTENDED_REGS,
 };
 
 int init_power9_pmu(void)
@@ -457,6 +460,9 @@ int init_power9_pmu(void)
                }
        }
 
+       /* Set the PERF_REG_EXTENDED_MASK here */
+       PERF_REG_EXTENDED_MASK = PERF_REG_PMU_MASK_300;
+
        rc = register_power_pmu(&power9_pmu);
        if (rc)
                return rc;
index c9c25fb..023a4f9 100644 (file)
@@ -2705,7 +2705,7 @@ void pnv_pci_ioda2_release_pe_dma(struct pnv_ioda_pe *pe)
        struct iommu_table *tbl = pe->table_group.tables[0];
        int64_t rc;
 
-       if (pe->dma_setup_done)
+       if (!pe->dma_setup_done)
                return;
 
        rc = pnv_pci_ioda2_unset_window(&pe->table_group, 0);
index c6e0d8a..7a974ed 100644 (file)
@@ -107,22 +107,28 @@ static int pseries_cpu_disable(void)
  */
 static void pseries_cpu_die(unsigned int cpu)
 {
-       int tries;
        int cpu_status = 1;
        unsigned int pcpu = get_hard_smp_processor_id(cpu);
+       unsigned long timeout = jiffies + msecs_to_jiffies(120000);
 
-       for (tries = 0; tries < 25; tries++) {
+       while (true) {
                cpu_status = smp_query_cpu_stopped(pcpu);
                if (cpu_status == QCSS_STOPPED ||
                    cpu_status == QCSS_HARDWARE_ERROR)
                        break;
-               cpu_relax();
 
+               if (time_after(jiffies, timeout)) {
+                       pr_warn("CPU %i (hwid %i) didn't die after 120 seconds\n",
+                               cpu, pcpu);
+                       timeout = jiffies + msecs_to_jiffies(120000);
+               }
+
+               cond_resched();
        }
 
-       if (cpu_status != 0) {
-               printk("Querying DEAD? cpu %i (%i) shows %i\n",
-                      cpu, pcpu, cpu_status);
+       if (cpu_status == QCSS_HARDWARE_ERROR) {
+               pr_warn("CPU %i (hwid %i) reported error while dying\n",
+                       cpu, pcpu);
        }
 
        /* Isolation and deallocation are definitely done by
index f3736fc..13c86a2 100644 (file)
@@ -184,7 +184,6 @@ static void handle_system_shutdown(char event_modifier)
        case EPOW_SHUTDOWN_ON_UPS:
                pr_emerg("Loss of system power detected. System is running on"
                         " UPS/battery. Check RTAS error log for details\n");
-               orderly_poweroff(true);
                break;
 
        case EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS:
index 7b59055..df18372 100644 (file)
@@ -81,7 +81,7 @@ config RISCV
        select PCI_DOMAINS_GENERIC if PCI
        select PCI_MSI if PCI
        select RISCV_INTC
-       select RISCV_TIMER
+       select RISCV_TIMER if RISCV_SBI
        select SPARSEMEM_STATIC if 32BIT
        select SPARSE_IRQ
        select SYSCTL_EXCEPTION_TRACE
index 6c88148..8a55f61 100644 (file)
@@ -12,6 +12,7 @@ config SOC_SIFIVE
 
 config SOC_VIRT
        bool "QEMU Virt Machine"
+       select CLINT_TIMER if RISCV_M_MODE
        select POWER_RESET
        select POWER_RESET_SYSCON
        select POWER_RESET_SYSCON_POWEROFF
@@ -24,6 +25,7 @@ config SOC_VIRT
 config SOC_KENDRYTE
        bool "Kendryte K210 SoC"
        depends on !MMU
+       select CLINT_TIMER if RISCV_M_MODE
        select SERIAL_SIFIVE if TTY
        select SERIAL_SIFIVE_CONSOLE if TTY
        select SIFIVE_PLIC
index f27596e..e046a0b 100644 (file)
@@ -26,6 +26,7 @@ CONFIG_EXPERT=y
 CONFIG_SLOB=y
 # CONFIG_SLAB_MERGE_DEFAULT is not set
 # CONFIG_MMU is not set
+CONFIG_SOC_VIRT=y
 CONFIG_MAXPHYSMEM_2GB=y
 CONFIG_SMP=y
 CONFIG_CMDLINE="root=/dev/vda rw earlycon=uart8250,mmio,0x10000000,115200n8 console=ttyS0"
@@ -49,7 +50,6 @@ CONFIG_VIRTIO_BLK=y
 # CONFIG_SERIO is not set
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_LDISC_AUTOLOAD is not set
-# CONFIG_DEVMEM is not set
 CONFIG_SERIAL_8250=y
 # CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
 CONFIG_SERIAL_8250_CONSOLE=y
@@ -57,16 +57,13 @@ CONFIG_SERIAL_8250_NR_UARTS=1
 CONFIG_SERIAL_8250_RUNTIME_UARTS=1
 CONFIG_SERIAL_OF_PLATFORM=y
 # CONFIG_HW_RANDOM is not set
+# CONFIG_DEVMEM is not set
 # CONFIG_HWMON is not set
-# CONFIG_LCD_CLASS_DEVICE is not set
-# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
 # CONFIG_VGA_CONSOLE is not set
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_VIRTIO_MMIO=y
 CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
-CONFIG_SIFIVE_PLIC=y
-# CONFIG_VALIDATE_FS_PARSER is not set
 CONFIG_EXT2_FS=y
 # CONFIG_DNOTIFY is not set
 # CONFIG_INOTIFY_USER is not set
index 3a55f0e..2c2cda6 100644 (file)
@@ -14,6 +14,7 @@ CONFIG_CHECKPOINT_RESTORE=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 CONFIG_BPF_SYSCALL=y
+CONFIG_SOC_SIFIVE=y
 CONFIG_SOC_VIRT=y
 CONFIG_ARCH_RV32I=y
 CONFIG_SMP=y
@@ -62,6 +63,8 @@ CONFIG_HVC_RISCV_SBI=y
 CONFIG_VIRTIO_CONSOLE=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_SPI=y
+CONFIG_SPI_SIFIVE=y
 # CONFIG_PTP_1588_CLOCK is not set
 CONFIG_POWER_RESET=y
 CONFIG_DRM=y
@@ -77,6 +80,8 @@ CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_HCD_PLATFORM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_UAS=y
+CONFIG_MMC=y
+CONFIG_MMC_SPI=y
 CONFIG_RTC_CLASS=y
 CONFIG_VIRTIO_PCI=y
 CONFIG_VIRTIO_BALLOON=y
diff --git a/arch/riscv/include/asm/clint.h b/arch/riscv/include/asm/clint.h
deleted file mode 100644 (file)
index a279b17..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_RISCV_CLINT_H
-#define _ASM_RISCV_CLINT_H 1
-
-#include <linux/io.h>
-#include <linux/smp.h>
-
-#ifdef CONFIG_RISCV_M_MODE
-extern u32 __iomem *clint_ipi_base;
-
-void clint_init_boot_cpu(void);
-
-static inline void clint_send_ipi_single(unsigned long hartid)
-{
-       writel(1, clint_ipi_base + hartid);
-}
-
-static inline void clint_send_ipi_mask(const struct cpumask *mask)
-{
-       int cpu;
-
-       for_each_cpu(cpu, mask)
-               clint_send_ipi_single(cpuid_to_hartid_map(cpu));
-}
-
-static inline void clint_clear_ipi(unsigned long hartid)
-{
-       writel(0, clint_ipi_base + hartid);
-}
-#else /* CONFIG_RISCV_M_MODE */
-#define clint_init_boot_cpu()  do { } while (0)
-
-/* stubs to for code is only reachable under IS_ENABLED(CONFIG_RISCV_M_MODE): */
-void clint_send_ipi_single(unsigned long hartid);
-void clint_send_ipi_mask(const struct cpumask *hartid_mask);
-void clint_clear_ipi(unsigned long hartid);
-#endif /* CONFIG_RISCV_M_MODE */
-
-#endif /* _ASM_RISCV_CLINT_H */
index 6dfd2a1..df1f7c4 100644 (file)
 struct seq_file;
 extern unsigned long boot_cpu_hartid;
 
+struct riscv_ipi_ops {
+       void (*ipi_inject)(const struct cpumask *target);
+       void (*ipi_clear)(void);
+};
+
 #ifdef CONFIG_SMP
 /*
  * Mapping between linux logical cpu index and hartid.
@@ -40,6 +45,12 @@ void arch_send_call_function_single_ipi(int cpu);
 int riscv_hartid_to_cpuid(int hartid);
 void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out);
 
+/* Set custom IPI operations */
+void riscv_set_ipi_ops(struct riscv_ipi_ops *ops);
+
+/* Clear IPI for current CPU */
+void riscv_clear_ipi(void);
+
 /* Secondary hart entry */
 asmlinkage void smp_callin(void);
 
@@ -81,6 +92,14 @@ static inline void riscv_cpuid_to_hartid_mask(const struct cpumask *in,
        cpumask_set_cpu(boot_cpu_hartid, out);
 }
 
+static inline void riscv_set_ipi_ops(struct riscv_ipi_ops *ops)
+{
+}
+
+static inline void riscv_clear_ipi(void)
+{
+}
+
 #endif /* CONFIG_SMP */
 
 #if defined(CONFIG_HOTPLUG_CPU) && (CONFIG_SMP)
index bad2a7c..a3fb85d 100644 (file)
@@ -7,41 +7,27 @@
 #define _ASM_RISCV_TIMEX_H
 
 #include <asm/csr.h>
-#include <asm/mmio.h>
 
 typedef unsigned long cycles_t;
 
-extern u64 __iomem *riscv_time_val;
-extern u64 __iomem *riscv_time_cmp;
-
-#ifdef CONFIG_64BIT
-#define mmio_get_cycles()      readq_relaxed(riscv_time_val)
-#else
-#define mmio_get_cycles()      readl_relaxed(riscv_time_val)
-#define mmio_get_cycles_hi()   readl_relaxed(((u32 *)riscv_time_val) + 1)
-#endif
-
 static inline cycles_t get_cycles(void)
 {
-       if (IS_ENABLED(CONFIG_RISCV_SBI))
-               return csr_read(CSR_TIME);
-       return mmio_get_cycles();
+       return csr_read(CSR_TIME);
 }
 #define get_cycles get_cycles
 
+static inline u32 get_cycles_hi(void)
+{
+       return csr_read(CSR_TIMEH);
+}
+#define get_cycles_hi get_cycles_hi
+
 #ifdef CONFIG_64BIT
 static inline u64 get_cycles64(void)
 {
        return get_cycles();
 }
 #else /* CONFIG_64BIT */
-static inline u32 get_cycles_hi(void)
-{
-       if (IS_ENABLED(CONFIG_RISCV_SBI))
-               return csr_read(CSR_TIMEH);
-       return mmio_get_cycles_hi();
-}
-
 static inline u64 get_cycles64(void)
 {
        u32 hi, lo;
index a5287ab..dc93710 100644 (file)
@@ -31,7 +31,7 @@ obj-y += cacheinfo.o
 obj-y  += patch.o
 obj-$(CONFIG_MMU) += vdso.o vdso/
 
-obj-$(CONFIG_RISCV_M_MODE)     += clint.o traps_misaligned.o
+obj-$(CONFIG_RISCV_M_MODE)     += traps_misaligned.o
 obj-$(CONFIG_FPU)              += fpu.o
 obj-$(CONFIG_SMP)              += smpboot.o
 obj-$(CONFIG_SMP)              += smp.o
diff --git a/arch/riscv/kernel/clint.c b/arch/riscv/kernel/clint.c
deleted file mode 100644 (file)
index 3647980..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2019 Christoph Hellwig.
- */
-
-#include <linux/io.h>
-#include <linux/of_address.h>
-#include <linux/types.h>
-#include <asm/clint.h>
-#include <asm/csr.h>
-#include <asm/timex.h>
-#include <asm/smp.h>
-
-/*
- * This is the layout used by the SiFive clint, which is also shared by the qemu
- * virt platform, and the Kendryte KD210 at least.
- */
-#define CLINT_IPI_OFF          0
-#define CLINT_TIME_CMP_OFF     0x4000
-#define CLINT_TIME_VAL_OFF     0xbff8
-
-u32 __iomem *clint_ipi_base;
-
-void clint_init_boot_cpu(void)
-{
-       struct device_node *np;
-       void __iomem *base;
-
-       np = of_find_compatible_node(NULL, NULL, "riscv,clint0");
-       if (!np) {
-               panic("clint not found");
-               return;
-       }
-
-       base = of_iomap(np, 0);
-       if (!base)
-               panic("could not map CLINT");
-
-       clint_ipi_base = base + CLINT_IPI_OFF;
-       riscv_time_cmp = base + CLINT_TIME_CMP_OFF;
-       riscv_time_val = base + CLINT_TIME_VAL_OFF;
-
-       clint_clear_ipi(boot_cpu_hartid);
-}
index f383ef5..226ccce 100644 (file)
@@ -547,6 +547,18 @@ static inline long sbi_get_firmware_version(void)
        return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_VERSION);
 }
 
+static void sbi_send_cpumask_ipi(const struct cpumask *target)
+{
+       struct cpumask hartid_mask;
+
+       riscv_cpuid_to_hartid_mask(target, &hartid_mask);
+
+       sbi_send_ipi(cpumask_bits(&hartid_mask));
+}
+
+static struct riscv_ipi_ops sbi_ipi_ops = {
+       .ipi_inject = sbi_send_cpumask_ipi
+};
 
 int __init sbi_init(void)
 {
@@ -587,5 +599,7 @@ int __init sbi_init(void)
                __sbi_rfence    = __sbi_rfence_v01;
        }
 
+       riscv_set_ipi_ops(&sbi_ipi_ops);
+
        return 0;
 }
index f04373b..2c6dd32 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/swiotlb.h>
 #include <linux/smp.h>
 
-#include <asm/clint.h>
 #include <asm/cpu_ops.h>
 #include <asm/setup.h>
 #include <asm/sections.h>
@@ -79,7 +78,6 @@ void __init setup_arch(char **cmdline_p)
 #else
        unflatten_device_tree();
 #endif
-       clint_init_boot_cpu();
 
 #ifdef CONFIG_SWIOTLB
        swiotlb_init(1);
index 554b0fb..ea028d9 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/delay.h>
 #include <linux/irq_work.h>
 
-#include <asm/clint.h>
 #include <asm/sbi.h>
 #include <asm/tlbflush.h>
 #include <asm/cacheflush.h>
@@ -86,9 +85,25 @@ static void ipi_stop(void)
                wait_for_interrupt();
 }
 
+static struct riscv_ipi_ops *ipi_ops;
+
+void riscv_set_ipi_ops(struct riscv_ipi_ops *ops)
+{
+       ipi_ops = ops;
+}
+EXPORT_SYMBOL_GPL(riscv_set_ipi_ops);
+
+void riscv_clear_ipi(void)
+{
+       if (ipi_ops && ipi_ops->ipi_clear)
+               ipi_ops->ipi_clear();
+
+       csr_clear(CSR_IP, IE_SIE);
+}
+EXPORT_SYMBOL_GPL(riscv_clear_ipi);
+
 static void send_ipi_mask(const struct cpumask *mask, enum ipi_message_type op)
 {
-       struct cpumask hartid_mask;
        int cpu;
 
        smp_mb__before_atomic();
@@ -96,33 +111,22 @@ static void send_ipi_mask(const struct cpumask *mask, enum ipi_message_type op)
                set_bit(op, &ipi_data[cpu].bits);
        smp_mb__after_atomic();
 
-       riscv_cpuid_to_hartid_mask(mask, &hartid_mask);
-       if (IS_ENABLED(CONFIG_RISCV_SBI))
-               sbi_send_ipi(cpumask_bits(&hartid_mask));
+       if (ipi_ops && ipi_ops->ipi_inject)
+               ipi_ops->ipi_inject(mask);
        else
-               clint_send_ipi_mask(mask);
+               pr_warn("SMP: IPI inject method not available\n");
 }
 
 static void send_ipi_single(int cpu, enum ipi_message_type op)
 {
-       int hartid = cpuid_to_hartid_map(cpu);
-
        smp_mb__before_atomic();
        set_bit(op, &ipi_data[cpu].bits);
        smp_mb__after_atomic();
 
-       if (IS_ENABLED(CONFIG_RISCV_SBI))
-               sbi_send_ipi(cpumask_bits(cpumask_of(hartid)));
-       else
-               clint_send_ipi_single(hartid);
-}
-
-static inline void clear_ipi(void)
-{
-       if (IS_ENABLED(CONFIG_RISCV_SBI))
-               csr_clear(CSR_IP, IE_SIE);
+       if (ipi_ops && ipi_ops->ipi_inject)
+               ipi_ops->ipi_inject(cpumask_of(cpu));
        else
-               clint_clear_ipi(cpuid_to_hartid_map(smp_processor_id()));
+               pr_warn("SMP: IPI inject method not available\n");
 }
 
 #ifdef CONFIG_IRQ_WORK
@@ -140,7 +144,7 @@ void handle_IPI(struct pt_regs *regs)
 
        irq_enter();
 
-       clear_ipi();
+       riscv_clear_ipi();
 
        while (true) {
                unsigned long ops;
index 356825a..96167d5 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/of.h>
 #include <linux/sched/task_stack.h>
 #include <linux/sched/mm.h>
-#include <asm/clint.h>
 #include <asm/cpu_ops.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
@@ -147,8 +146,7 @@ asmlinkage __visible void smp_callin(void)
        struct mm_struct *mm = &init_mm;
        unsigned int curr_cpuid = smp_processor_id();
 
-       if (!IS_ENABLED(CONFIG_RISCV_SBI))
-               clint_clear_ipi(cpuid_to_hartid_map(smp_processor_id()));
+       riscv_clear_ipi();
 
        /* All kernel threads share the same mm context.  */
        mmgrab(mm);
index 11d2f7d..a76dd27 100644 (file)
@@ -1268,7 +1268,6 @@ static bool is_ri_cb_valid(struct runtime_instr_cb *cb)
                cb->pc == 1 &&
                cb->qc == 0 &&
                cb->reserved2 == 0 &&
-               cb->key == PAGE_DEFAULT_KEY &&
                cb->reserved3 == 0 &&
                cb->reserved4 == 0 &&
                cb->reserved5 == 0 &&
@@ -1330,7 +1329,11 @@ static int s390_runtime_instr_set(struct task_struct *target,
                kfree(data);
                return -EINVAL;
        }
-
+       /*
+        * Override access key in any case, since user space should
+        * not be able to set it, nor should it care about it.
+        */
+       ri_cb.key = PAGE_DEFAULT_KEY >> 4;
        preempt_disable();
        if (!target->thread.ri_cb)
                target->thread.ri_cb = data;
index 125c7f6..1788a54 100644 (file)
@@ -57,7 +57,7 @@ static void init_runtime_instr_cb(struct runtime_instr_cb *cb)
        cb->k = 1;
        cb->ps = 1;
        cb->pc = 1;
-       cb->key = PAGE_DEFAULT_KEY;
+       cb->key = PAGE_DEFAULT_KEY >> 4;
        cb->v = 1;
 }
 
index 3902c9f..4b62d6b 100644 (file)
@@ -672,6 +672,19 @@ int zpci_disable_device(struct zpci_dev *zdev)
 }
 EXPORT_SYMBOL_GPL(zpci_disable_device);
 
+void zpci_remove_device(struct zpci_dev *zdev)
+{
+       struct zpci_bus *zbus = zdev->zbus;
+       struct pci_dev *pdev;
+
+       pdev = pci_get_slot(zbus->bus, zdev->devfn);
+       if (pdev) {
+               if (pdev->is_virtfn)
+                       return zpci_remove_virtfn(pdev, zdev->vfn);
+               pci_stop_and_remove_bus_device_locked(pdev);
+       }
+}
+
 int zpci_create_device(struct zpci_dev *zdev)
 {
        int rc;
@@ -716,13 +729,8 @@ void zpci_release_device(struct kref *kref)
 {
        struct zpci_dev *zdev = container_of(kref, struct zpci_dev, kref);
 
-       if (zdev->zbus->bus) {
-               struct pci_dev *pdev;
-
-               pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
-               if (pdev)
-                       pci_stop_and_remove_bus_device_locked(pdev);
-       }
+       if (zdev->zbus->bus)
+               zpci_remove_device(zdev);
 
        switch (zdev->state) {
        case ZPCI_FN_STATE_ONLINE:
index 642a993..5967f30 100644 (file)
@@ -132,13 +132,14 @@ static int zpci_bus_link_virtfn(struct pci_dev *pdev,
 {
        int rc;
 
-       virtfn->physfn = pci_dev_get(pdev);
        rc = pci_iov_sysfs_link(pdev, virtfn, vfid);
-       if (rc) {
-               pci_dev_put(pdev);
-               virtfn->physfn = NULL;
+       if (rc)
                return rc;
-       }
+
+       virtfn->is_virtfn = 1;
+       virtfn->multifunction = 0;
+       virtfn->physfn = pci_dev_get(pdev);
+
        return 0;
 }
 
@@ -151,9 +152,9 @@ static int zpci_bus_setup_virtfn(struct zpci_bus *zbus,
        int vfid = vfn - 1; /* Linux' vfid's start at 0 vfn at 1*/
        int rc = 0;
 
-       virtfn->is_virtfn = 1;
-       virtfn->multifunction = 0;
-       WARN_ON(vfid < 0);
+       if (!zbus->multifunction)
+               return 0;
+
        /* If the parent PF for the given VF is also configured in the
         * instance, it must be on the same zbus.
         * We can then identify the parent PF by checking what
@@ -165,11 +166,17 @@ static int zpci_bus_setup_virtfn(struct zpci_bus *zbus,
                zdev = zbus->function[i];
                if (zdev && zdev->is_physfn) {
                        pdev = pci_get_slot(zbus->bus, zdev->devfn);
+                       if (!pdev)
+                               continue;
                        cand_devfn = pci_iov_virtfn_devfn(pdev, vfid);
                        if (cand_devfn == virtfn->devfn) {
                                rc = zpci_bus_link_virtfn(pdev, virtfn, vfid);
+                               /* balance pci_get_slot() */
+                               pci_dev_put(pdev);
                                break;
                        }
+                       /* balance pci_get_slot() */
+                       pci_dev_put(pdev);
                }
        }
        return rc;
@@ -178,12 +185,23 @@ static int zpci_bus_setup_virtfn(struct zpci_bus *zbus,
 static inline int zpci_bus_setup_virtfn(struct zpci_bus *zbus,
                struct pci_dev *virtfn, int vfn)
 {
-       virtfn->is_virtfn = 1;
-       virtfn->multifunction = 0;
        return 0;
 }
 #endif
 
+void pcibios_bus_add_device(struct pci_dev *pdev)
+{
+       struct zpci_dev *zdev = to_zpci(pdev);
+
+       /*
+        * With pdev->no_vf_scan the common PCI probing code does not
+        * perform PF/VF linking.
+        */
+       if (zdev->vfn)
+               zpci_bus_setup_virtfn(zdev->zbus, pdev, zdev->vfn);
+
+}
+
 static int zpci_bus_add_device(struct zpci_bus *zbus, struct zpci_dev *zdev)
 {
        struct pci_bus *bus;
@@ -214,20 +232,10 @@ static int zpci_bus_add_device(struct zpci_bus *zbus, struct zpci_dev *zdev)
        }
 
        pdev = pci_scan_single_device(bus, zdev->devfn);
-       if (pdev) {
-               if (!zdev->is_physfn) {
-                       rc = zpci_bus_setup_virtfn(zbus, pdev, zdev->vfn);
-                       if (rc)
-                               goto failed_with_pdev;
-               }
+       if (pdev)
                pci_bus_add_device(pdev);
-       }
-       return 0;
 
-failed_with_pdev:
-       pci_stop_and_remove_bus_device(pdev);
-       pci_dev_put(pdev);
-       return rc;
+       return 0;
 }
 
 static void zpci_bus_add_devices(struct zpci_bus *zbus)
index 89be3c3..4972433 100644 (file)
@@ -29,3 +29,16 @@ static inline struct zpci_dev *get_zdev_by_bus(struct pci_bus *bus,
 
        return (devfn >= ZPCI_FUNCTIONS_PER_BUS) ? NULL : zbus->function[devfn];
 }
+
+#ifdef CONFIG_PCI_IOV
+static inline void zpci_remove_virtfn(struct pci_dev *pdev, int vfn)
+{
+
+       pci_lock_rescan_remove();
+       /* Linux' vfid's start at 0 vfn at 1 */
+       pci_iov_remove_virtfn(pdev->physfn, vfn - 1);
+       pci_unlock_rescan_remove();
+}
+#else /* CONFIG_PCI_IOV */
+static inline void zpci_remove_virtfn(struct pci_dev *pdev, int vfn) {}
+#endif /* CONFIG_PCI_IOV */
index fdebd28..9a3a291 100644 (file)
@@ -92,6 +92,9 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
                        ret = clp_add_pci_device(ccdf->fid, ccdf->fh, 1);
                        break;
                }
+               /* the configuration request may be stale */
+               if (zdev->state != ZPCI_FN_STATE_STANDBY)
+                       break;
                zdev->fh = ccdf->fh;
                zdev->state = ZPCI_FN_STATE_CONFIGURED;
                ret = zpci_enable_device(zdev);
@@ -118,7 +121,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
                if (!zdev)
                        break;
                if (pdev)
-                       pci_stop_and_remove_bus_device_locked(pdev);
+                       zpci_remove_device(zdev);
 
                ret = zpci_disable_device(zdev);
                if (ret)
@@ -137,7 +140,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
                        /* Give the driver a hint that the function is
                         * already unusable. */
                        pdev->error_state = pci_channel_io_perm_failure;
-                       pci_stop_and_remove_bus_device_locked(pdev);
+                       zpci_remove_device(zdev);
                }
 
                zdev->state = ZPCI_FN_STATE_STANDBY;
index 39e592d..e478e40 100644 (file)
 #define STATIC         static
 
 /*
- * Use normal definitions of mem*() from string.c. There are already
- * included header files which expect a definition of memset() and by
- * the time we define memset macro, it is too late.
+ * Provide definitions of memzero and memmove as some of the decompressors will
+ * try to define their own functions if these are not defined as macros.
  */
-#undef memcpy
-#undef memset
 #define memzero(s, n)  memset((s), 0, (n))
 #define memmove                memmove
 
index 995f7b7..a232da4 100644 (file)
@@ -11,10 +11,7 @@ void *memcpy(void *dst, const void *src, size_t len);
 void *memset(void *dst, int c, size_t len);
 int memcmp(const void *s1, const void *s2, size_t len);
 
-/*
- * Access builtin version by default. If one needs to use optimized version,
- * do "undef memcpy" in .c file and link against right string.c
- */
+/* Access builtin version by default. */
 #define memcpy(d,s,l) __builtin_memcpy(d,s,l)
 #define memset(d,c,l) __builtin_memset(d,c,l)
 #define memcmp __builtin_memcmp
index 98e4d88..ae9b0d4 100644 (file)
@@ -374,12 +374,14 @@ For 32-bit we have the following conventions - kernel is built with
  * Fetch the per-CPU GSBASE value for this processor and put it in @reg.
  * We normally use %gs for accessing per-CPU data, but we are setting up
  * %gs here and obviously can not use %gs itself to access per-CPU data.
+ *
+ * Do not use RDPID, because KVM loads guest's TSC_AUX on vm-entry and
+ * may not restore the host's value until the CPU returns to userspace.
+ * Thus the kernel would consume a guest's TSC_AUX if an NMI arrives
+ * while running KVM's run loop.
  */
 .macro GET_PERCPU_BASE reg:req
-       ALTERNATIVE \
-               "LOAD_CPU_AND_NODE_SEG_LIMIT \reg", \
-               "RDPID  \reg", \
-               X86_FEATURE_RDPID
+       LOAD_CPU_AND_NODE_SEG_LIMIT \reg
        andq    $VDSO_CPUNODE_MASK, \reg
        movq    __per_cpu_offset(, \reg, 8), \reg
 .endm
index cb94ba8..6a4ca27 100644 (file)
@@ -390,6 +390,18 @@ static struct uncore_event_desc snb_uncore_imc_events[] = {
        INTEL_UNCORE_EVENT_DESC(data_writes.scale, "6.103515625e-5"),
        INTEL_UNCORE_EVENT_DESC(data_writes.unit, "MiB"),
 
+       INTEL_UNCORE_EVENT_DESC(gt_requests, "event=0x03"),
+       INTEL_UNCORE_EVENT_DESC(gt_requests.scale, "6.103515625e-5"),
+       INTEL_UNCORE_EVENT_DESC(gt_requests.unit, "MiB"),
+
+       INTEL_UNCORE_EVENT_DESC(ia_requests, "event=0x04"),
+       INTEL_UNCORE_EVENT_DESC(ia_requests.scale, "6.103515625e-5"),
+       INTEL_UNCORE_EVENT_DESC(ia_requests.unit, "MiB"),
+
+       INTEL_UNCORE_EVENT_DESC(io_requests, "event=0x05"),
+       INTEL_UNCORE_EVENT_DESC(io_requests.scale, "6.103515625e-5"),
+       INTEL_UNCORE_EVENT_DESC(io_requests.unit, "MiB"),
+
        { /* end: all zeroes */ },
 };
 
@@ -405,13 +417,35 @@ static struct uncore_event_desc snb_uncore_imc_events[] = {
 #define SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE    0x5054
 #define SNB_UNCORE_PCI_IMC_CTR_BASE            SNB_UNCORE_PCI_IMC_DATA_READS_BASE
 
+/* BW break down- legacy counters */
+#define SNB_UNCORE_PCI_IMC_GT_REQUESTS         0x3
+#define SNB_UNCORE_PCI_IMC_GT_REQUESTS_BASE    0x5040
+#define SNB_UNCORE_PCI_IMC_IA_REQUESTS         0x4
+#define SNB_UNCORE_PCI_IMC_IA_REQUESTS_BASE    0x5044
+#define SNB_UNCORE_PCI_IMC_IO_REQUESTS         0x5
+#define SNB_UNCORE_PCI_IMC_IO_REQUESTS_BASE    0x5048
+
 enum perf_snb_uncore_imc_freerunning_types {
-       SNB_PCI_UNCORE_IMC_DATA         = 0,
+       SNB_PCI_UNCORE_IMC_DATA_READS           = 0,
+       SNB_PCI_UNCORE_IMC_DATA_WRITES,
+       SNB_PCI_UNCORE_IMC_GT_REQUESTS,
+       SNB_PCI_UNCORE_IMC_IA_REQUESTS,
+       SNB_PCI_UNCORE_IMC_IO_REQUESTS,
+
        SNB_PCI_UNCORE_IMC_FREERUNNING_TYPE_MAX,
 };
 
 static struct freerunning_counters snb_uncore_imc_freerunning[] = {
-       [SNB_PCI_UNCORE_IMC_DATA]     = { SNB_UNCORE_PCI_IMC_DATA_READS_BASE, 0x4, 0x0, 2, 32 },
+       [SNB_PCI_UNCORE_IMC_DATA_READS]         = { SNB_UNCORE_PCI_IMC_DATA_READS_BASE,
+                                                       0x0, 0x0, 1, 32 },
+       [SNB_PCI_UNCORE_IMC_DATA_READS]         = { SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE,
+                                                       0x0, 0x0, 1, 32 },
+       [SNB_PCI_UNCORE_IMC_GT_REQUESTS]        = { SNB_UNCORE_PCI_IMC_GT_REQUESTS_BASE,
+                                                       0x0, 0x0, 1, 32 },
+       [SNB_PCI_UNCORE_IMC_IA_REQUESTS]        = { SNB_UNCORE_PCI_IMC_IA_REQUESTS_BASE,
+                                                       0x0, 0x0, 1, 32 },
+       [SNB_PCI_UNCORE_IMC_IO_REQUESTS]        = { SNB_UNCORE_PCI_IMC_IO_REQUESTS_BASE,
+                                                       0x0, 0x0, 1, 32 },
 };
 
 static struct attribute *snb_uncore_imc_formats_attr[] = {
@@ -525,6 +559,18 @@ static int snb_uncore_imc_event_init(struct perf_event *event)
                base = SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE;
                idx = UNCORE_PMC_IDX_FREERUNNING;
                break;
+       case SNB_UNCORE_PCI_IMC_GT_REQUESTS:
+               base = SNB_UNCORE_PCI_IMC_GT_REQUESTS_BASE;
+               idx = UNCORE_PMC_IDX_FREERUNNING;
+               break;
+       case SNB_UNCORE_PCI_IMC_IA_REQUESTS:
+               base = SNB_UNCORE_PCI_IMC_IA_REQUESTS_BASE;
+               idx = UNCORE_PMC_IDX_FREERUNNING;
+               break;
+       case SNB_UNCORE_PCI_IMC_IO_REQUESTS:
+               base = SNB_UNCORE_PCI_IMC_IO_REQUESTS_BASE;
+               idx = UNCORE_PMC_IDX_FREERUNNING;
+               break;
        default:
                return -EINVAL;
        }
@@ -598,7 +644,7 @@ static struct intel_uncore_ops snb_uncore_imc_ops = {
 
 static struct intel_uncore_type snb_uncore_imc = {
        .name           = "imc",
-       .num_counters   = 2,
+       .num_counters   = 5,
        .num_boxes      = 1,
        .num_freerunning_types  = SNB_PCI_UNCORE_IMC_FREERUNNING_TYPE_MAX,
        .mmio_map_size  = SNB_UNCORE_PCI_IMC_MAP_SIZE,
index b9c2667..bc9758e 100644 (file)
@@ -81,11 +81,8 @@ extern unsigned long efi_fw_vendor, efi_config_table;
        kernel_fpu_end();                                               \
 })
 
-
 #define arch_efi_call_virt(p, f, args...)      p->f(args)
 
-#define efi_ioremap(addr, size, type, attr)    ioremap_cache(addr, size)
-
 #else /* !CONFIG_X86_32 */
 
 #define EFI_LOADER_SIGNATURE   "EL64"
@@ -125,9 +122,6 @@ struct efi_scratch {
        kernel_fpu_end();                                               \
 })
 
-extern void __iomem *__init efi_ioremap(unsigned long addr, unsigned long size,
-                                       u32 type, u64 attribute);
-
 #ifdef CONFIG_KASAN
 /*
  * CONFIG_KASAN may redefine memset to __memset.  __memset function is present
@@ -143,17 +137,13 @@ extern void __iomem *__init efi_ioremap(unsigned long addr, unsigned long size,
 #endif /* CONFIG_X86_32 */
 
 extern struct efi_scratch efi_scratch;
-extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable);
 extern int __init efi_memblock_x86_reserve_range(void);
 extern void __init efi_print_memmap(void);
-extern void __init efi_memory_uc(u64 addr, unsigned long size);
 extern void __init efi_map_region(efi_memory_desc_t *md);
 extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
 extern void efi_sync_low_kernel_mappings(void);
 extern int __init efi_alloc_page_tables(void);
 extern int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages);
-extern void __init old_map_region(efi_memory_desc_t *md);
-extern void __init runtime_code_page_mkexec(void);
 extern void __init efi_runtime_update_mappings(void);
 extern void __init efi_dump_pagetable(void);
 extern void __init efi_apply_memmap_quirks(void);
index 5ab3af7..5303dbc 100644 (file)
@@ -1596,7 +1596,8 @@ asmlinkage void kvm_spurious_fault(void);
        _ASM_EXTABLE(666b, 667b)
 
 #define KVM_ARCH_WANT_MMU_NOTIFIER
-int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end);
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end,
+                       unsigned flags);
 int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
 int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
 int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
index 4e03841..a5d0207 100644 (file)
@@ -1916,7 +1916,8 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
        return kvm_handle_hva_range(kvm, hva, hva + 1, data, handler);
 }
 
-int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end,
+                       unsigned flags)
 {
        return kvm_handle_hva_range(kvm, start, end, 0, kvm_unmap_rmapp);
 }
index 599d732..3394528 100644 (file)
@@ -975,7 +975,7 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 {
        unsigned long old_cr4 = kvm_read_cr4(vcpu);
        unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE |
-                                  X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_PKE;
+                                  X86_CR4_SMEP;
 
        if (kvm_valid_cr4(vcpu, cr4))
                return 1;
@@ -10751,9 +10751,11 @@ EXPORT_SYMBOL_GPL(kvm_spec_ctrl_test_value);
 void kvm_fixup_and_inject_pf_error(struct kvm_vcpu *vcpu, gva_t gva, u16 error_code)
 {
        struct x86_exception fault;
+       u32 access = error_code &
+               (PFERR_WRITE_MASK | PFERR_FETCH_MASK | PFERR_USER_MASK);
 
        if (!(error_code & PFERR_PRESENT_MASK) ||
-           vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, error_code, &fault) != UNMAPPED_GVA) {
+           vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, &fault) != UNMAPPED_GVA) {
                /*
                 * If vcpu->arch.walk_mmu->gva_to_gpa succeeded, the page
                 * tables probably do not match the TLB.  Just proceed
index 9f9aad4..89395a5 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/xen/pci.h>
 #include <asm/xen/cpuid.h>
 #include <asm/apic.h>
+#include <asm/acpi.h>
 #include <asm/i8259.h>
 
 static int xen_pcifront_enable_irq(struct pci_dev *dev)
index f6ea8f1..d37ebe6 100644 (file)
@@ -49,7 +49,6 @@
 #include <asm/efi.h>
 #include <asm/e820/api.h>
 #include <asm/time.h>
-#include <asm/set_memory.h>
 #include <asm/tlbflush.h>
 #include <asm/x86_init.h>
 #include <asm/uv/uv.h>
@@ -496,74 +495,6 @@ void __init efi_init(void)
                efi_print_memmap();
 }
 
-#if defined(CONFIG_X86_32)
-
-void __init efi_set_executable(efi_memory_desc_t *md, bool executable)
-{
-       u64 addr, npages;
-
-       addr = md->virt_addr;
-       npages = md->num_pages;
-
-       memrange_efi_to_native(&addr, &npages);
-
-       if (executable)
-               set_memory_x(addr, npages);
-       else
-               set_memory_nx(addr, npages);
-}
-
-void __init runtime_code_page_mkexec(void)
-{
-       efi_memory_desc_t *md;
-
-       /* Make EFI runtime service code area executable */
-       for_each_efi_memory_desc(md) {
-               if (md->type != EFI_RUNTIME_SERVICES_CODE)
-                       continue;
-
-               efi_set_executable(md, true);
-       }
-}
-
-void __init efi_memory_uc(u64 addr, unsigned long size)
-{
-       unsigned long page_shift = 1UL << EFI_PAGE_SHIFT;
-       u64 npages;
-
-       npages = round_up(size, page_shift) / page_shift;
-       memrange_efi_to_native(&addr, &npages);
-       set_memory_uc(addr, npages);
-}
-
-void __init old_map_region(efi_memory_desc_t *md)
-{
-       u64 start_pfn, end_pfn, end;
-       unsigned long size;
-       void *va;
-
-       start_pfn = PFN_DOWN(md->phys_addr);
-       size      = md->num_pages << PAGE_SHIFT;
-       end       = md->phys_addr + size;
-       end_pfn   = PFN_UP(end);
-
-       if (pfn_range_is_mapped(start_pfn, end_pfn)) {
-               va = __va(md->phys_addr);
-
-               if (!(md->attribute & EFI_MEMORY_WB))
-                       efi_memory_uc((u64)(unsigned long)va, size);
-       } else
-               va = efi_ioremap(md->phys_addr, size,
-                                md->type, md->attribute);
-
-       md->virt_addr = (u64) (unsigned long) va;
-       if (!va)
-               pr_err("ioremap of 0x%llX failed!\n",
-                      (unsigned long long)md->phys_addr);
-}
-
-#endif
-
 /* Merge contiguous regions of the same type and attribute */
 static void __init efi_merge_regions(void)
 {
index 826ead6..e06a199 100644 (file)
 #include <asm/io.h>
 #include <asm/desc.h>
 #include <asm/page.h>
+#include <asm/set_memory.h>
 #include <asm/tlbflush.h>
 #include <asm/efi.h>
 
+void __init efi_map_region(efi_memory_desc_t *md)
+{
+       u64 start_pfn, end_pfn, end;
+       unsigned long size;
+       void *va;
+
+       start_pfn       = PFN_DOWN(md->phys_addr);
+       size            = md->num_pages << PAGE_SHIFT;
+       end             = md->phys_addr + size;
+       end_pfn         = PFN_UP(end);
+
+       if (pfn_range_is_mapped(start_pfn, end_pfn)) {
+               va = __va(md->phys_addr);
+
+               if (!(md->attribute & EFI_MEMORY_WB))
+                       set_memory_uc((unsigned long)va, md->num_pages);
+       } else {
+               va = ioremap_cache(md->phys_addr, size);
+       }
+
+       md->virt_addr = (unsigned long)va;
+       if (!va)
+               pr_err("ioremap of 0x%llX failed!\n", md->phys_addr);
+}
+
 /*
  * To make EFI call EFI runtime service in physical addressing mode we need
  * prolog/epilog before/after the invocation to claim the EFI runtime service
@@ -58,11 +84,6 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
        return 0;
 }
 
-void __init efi_map_region(efi_memory_desc_t *md)
-{
-       old_map_region(md);
-}
-
 void __init efi_map_region_fixed(efi_memory_desc_t *md) {}
 void __init parse_efi_setup(u64 phys_addr, u32 data_len) {}
 
@@ -107,6 +128,15 @@ efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size,
 
 void __init efi_runtime_update_mappings(void)
 {
-       if (__supported_pte_mask & _PAGE_NX)
-               runtime_code_page_mkexec();
+       if (__supported_pte_mask & _PAGE_NX) {
+               efi_memory_desc_t *md;
+
+               /* Make EFI runtime service code area executable */
+               for_each_efi_memory_desc(md) {
+                       if (md->type != EFI_RUNTIME_SERVICES_CODE)
+                               continue;
+
+                       set_memory_x(md->virt_addr, md->num_pages);
+               }
+       }
 }
index 413583f..6af4da1 100644 (file)
@@ -259,6 +259,8 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
        npages = (__end_rodata - __start_rodata) >> PAGE_SHIFT;
        rodata = __pa(__start_rodata);
        pfn = rodata >> PAGE_SHIFT;
+
+       pf = _PAGE_NX | _PAGE_ENC;
        if (kernel_map_pages_in_pgd(pgd, pfn, rodata, npages, pf)) {
                pr_err("Failed to map kernel rodata 1:1\n");
                return 1;
index 2ca9ec8..510250c 100644 (file)
@@ -998,6 +998,7 @@ static int fs_open(struct atm_vcc *atm_vcc)
                                error = make_rate (pcr, r, &tmc0, NULL);
                                if (error) {
                                        kfree(tc);
+                                       kfree(vcc);
                                        return error;
                                }
                        }
index 3576ad7..68b087b 100644 (file)
@@ -653,9 +653,8 @@ config ATCPIT100_TIMER
          This option enables support for the Andestech ATCPIT100 timers.
 
 config RISCV_TIMER
-       bool "Timer for the RISC-V platform"
+       bool "Timer for the RISC-V platform" if COMPILE_TEST
        depends on GENERIC_SCHED_CLOCK && RISCV
-       default y
        select TIMER_PROBE
        select TIMER_OF
        help
@@ -663,6 +662,15 @@ config RISCV_TIMER
          is accessed via both the SBI and the rdcycle instruction.  This is
          required for all RISC-V systems.
 
+config CLINT_TIMER
+       bool "CLINT Timer for the RISC-V platform" if COMPILE_TEST
+       depends on GENERIC_SCHED_CLOCK && RISCV
+       select TIMER_PROBE
+       select TIMER_OF
+       help
+         This option enables the CLINT timer for RISC-V systems.  The CLINT
+         driver is usually used for NoMMU RISC-V systems.
+
 config CSKY_MP_TIMER
        bool "SMP Timer for the C-SKY platform" if COMPILE_TEST
        depends on CSKY
index eaedb72..1c444cc 100644 (file)
@@ -89,6 +89,7 @@ obj-$(CONFIG_CLKSRC_ST_LPC)           += clksrc_st_lpc.o
 obj-$(CONFIG_X86_NUMACHIP)             += numachip.o
 obj-$(CONFIG_ATCPIT100_TIMER)          += timer-atcpit100.o
 obj-$(CONFIG_RISCV_TIMER)              += timer-riscv.o
+obj-$(CONFIG_CLINT_TIMER)              += timer-clint.o
 obj-$(CONFIG_CSKY_MP_TIMER)            += timer-mp-csky.o
 obj-$(CONFIG_GX6605S_TIMER)            += timer-gx6605s.o
 obj-$(CONFIG_HYPERV_TIMER)             += hyperv_timer.o
diff --git a/drivers/clocksource/timer-clint.c b/drivers/clocksource/timer-clint.c
new file mode 100644 (file)
index 0000000..8eeafa8
--- /dev/null
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Most of the M-mode (i.e. NoMMU) RISC-V systems usually have a
+ * CLINT MMIO timer device.
+ */
+
+#define pr_fmt(fmt) "clint: " fmt
+#include <linux/bitops.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/sched_clock.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/interrupt.h>
+#include <linux/of_irq.h>
+#include <linux/smp.h>
+
+#define CLINT_IPI_OFF          0
+#define CLINT_TIMER_CMP_OFF    0x4000
+#define CLINT_TIMER_VAL_OFF    0xbff8
+
+/* CLINT manages IPI and Timer for RISC-V M-mode  */
+static u32 __iomem *clint_ipi_base;
+static u64 __iomem *clint_timer_cmp;
+static u64 __iomem *clint_timer_val;
+static unsigned long clint_timer_freq;
+static unsigned int clint_timer_irq;
+
+static void clint_send_ipi(const struct cpumask *target)
+{
+       unsigned int cpu;
+
+       for_each_cpu(cpu, target)
+               writel(1, clint_ipi_base + cpuid_to_hartid_map(cpu));
+}
+
+static void clint_clear_ipi(void)
+{
+       writel(0, clint_ipi_base + cpuid_to_hartid_map(smp_processor_id()));
+}
+
+static struct riscv_ipi_ops clint_ipi_ops = {
+       .ipi_inject = clint_send_ipi,
+       .ipi_clear = clint_clear_ipi,
+};
+
+#ifdef CONFIG_64BIT
+#define clint_get_cycles()     readq_relaxed(clint_timer_val)
+#else
+#define clint_get_cycles()     readl_relaxed(clint_timer_val)
+#define clint_get_cycles_hi()  readl_relaxed(((u32 *)clint_timer_val) + 1)
+#endif
+
+#ifdef CONFIG_64BIT
+static u64 notrace clint_get_cycles64(void)
+{
+       return clint_get_cycles();
+}
+#else /* CONFIG_64BIT */
+static u64 notrace clint_get_cycles64(void)
+{
+       u32 hi, lo;
+
+       do {
+               hi = clint_get_cycles_hi();
+               lo = clint_get_cycles();
+       } while (hi != clint_get_cycles_hi());
+
+       return ((u64)hi << 32) | lo;
+}
+#endif /* CONFIG_64BIT */
+
+static u64 clint_rdtime(struct clocksource *cs)
+{
+       return clint_get_cycles64();
+}
+
+static struct clocksource clint_clocksource = {
+       .name           = "clint_clocksource",
+       .rating         = 300,
+       .mask           = CLOCKSOURCE_MASK(64),
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+       .read           = clint_rdtime,
+};
+
+static int clint_clock_next_event(unsigned long delta,
+                                  struct clock_event_device *ce)
+{
+       void __iomem *r = clint_timer_cmp +
+                         cpuid_to_hartid_map(smp_processor_id());
+
+       csr_set(CSR_IE, IE_TIE);
+       writeq_relaxed(clint_get_cycles64() + delta, r);
+       return 0;
+}
+
+static DEFINE_PER_CPU(struct clock_event_device, clint_clock_event) = {
+       .name           = "clint_clockevent",
+       .features       = CLOCK_EVT_FEAT_ONESHOT,
+       .rating         = 100,
+       .set_next_event = clint_clock_next_event,
+};
+
+static int clint_timer_starting_cpu(unsigned int cpu)
+{
+       struct clock_event_device *ce = per_cpu_ptr(&clint_clock_event, cpu);
+
+       ce->cpumask = cpumask_of(cpu);
+       clockevents_config_and_register(ce, clint_timer_freq, 100, 0x7fffffff);
+
+       enable_percpu_irq(clint_timer_irq,
+                         irq_get_trigger_type(clint_timer_irq));
+       return 0;
+}
+
+static int clint_timer_dying_cpu(unsigned int cpu)
+{
+       disable_percpu_irq(clint_timer_irq);
+       return 0;
+}
+
+static irqreturn_t clint_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *evdev = this_cpu_ptr(&clint_clock_event);
+
+       csr_clear(CSR_IE, IE_TIE);
+       evdev->event_handler(evdev);
+
+       return IRQ_HANDLED;
+}
+
+static int __init clint_timer_init_dt(struct device_node *np)
+{
+       int rc;
+       u32 i, nr_irqs;
+       void __iomem *base;
+       struct of_phandle_args oirq;
+
+       /*
+        * Ensure that CLINT device interrupts are either RV_IRQ_TIMER or
+        * RV_IRQ_SOFT. If it's anything else then we ignore the device.
+        */
+       nr_irqs = of_irq_count(np);
+       for (i = 0; i < nr_irqs; i++) {
+               if (of_irq_parse_one(np, i, &oirq)) {
+                       pr_err("%pOFP: failed to parse irq %d.\n", np, i);
+                       continue;
+               }
+
+               if ((oirq.args_count != 1) ||
+                   (oirq.args[0] != RV_IRQ_TIMER &&
+                    oirq.args[0] != RV_IRQ_SOFT)) {
+                       pr_err("%pOFP: invalid irq %d (hwirq %d)\n",
+                              np, i, oirq.args[0]);
+                       return -ENODEV;
+               }
+
+               /* Find parent irq domain and map timer irq */
+               if (!clint_timer_irq &&
+                   oirq.args[0] == RV_IRQ_TIMER &&
+                   irq_find_host(oirq.np))
+                       clint_timer_irq = irq_of_parse_and_map(np, i);
+       }
+
+       /* If CLINT timer irq not found then fail */
+       if (!clint_timer_irq) {
+               pr_err("%pOFP: timer irq not found\n", np);
+               return -ENODEV;
+       }
+
+       base = of_iomap(np, 0);
+       if (!base) {
+               pr_err("%pOFP: could not map registers\n", np);
+               return -ENODEV;
+       }
+
+       clint_ipi_base = base + CLINT_IPI_OFF;
+       clint_timer_cmp = base + CLINT_TIMER_CMP_OFF;
+       clint_timer_val = base + CLINT_TIMER_VAL_OFF;
+       clint_timer_freq = riscv_timebase;
+
+       pr_info("%pOFP: timer running at %ld Hz\n", np, clint_timer_freq);
+
+       rc = clocksource_register_hz(&clint_clocksource, clint_timer_freq);
+       if (rc) {
+               pr_err("%pOFP: clocksource register failed [%d]\n", np, rc);
+               goto fail_iounmap;
+       }
+
+       sched_clock_register(clint_get_cycles64, 64, clint_timer_freq);
+
+       rc = request_percpu_irq(clint_timer_irq, clint_timer_interrupt,
+                                "clint-timer", &clint_clock_event);
+       if (rc) {
+               pr_err("registering percpu irq failed [%d]\n", rc);
+               goto fail_iounmap;
+       }
+
+       rc = cpuhp_setup_state(CPUHP_AP_CLINT_TIMER_STARTING,
+                               "clockevents/clint/timer:starting",
+                               clint_timer_starting_cpu,
+                               clint_timer_dying_cpu);
+       if (rc) {
+               pr_err("%pOFP: cpuhp setup state failed [%d]\n", np, rc);
+               goto fail_free_irq;
+       }
+
+       riscv_set_ipi_ops(&clint_ipi_ops);
+       clint_clear_ipi();
+
+       return 0;
+
+fail_free_irq:
+       free_irq(clint_timer_irq, &clint_clock_event);
+fail_iounmap:
+       iounmap(base);
+       return rc;
+}
+
+TIMER_OF_DECLARE(clint_timer, "riscv,clint0", clint_timer_init_dt);
+TIMER_OF_DECLARE(clint_timer1, "sifive,clint0", clint_timer_init_dt);
index 9de1dab..c51c5ed 100644 (file)
 #include <linux/of_irq.h>
 #include <asm/smp.h>
 #include <asm/sbi.h>
-
-u64 __iomem *riscv_time_cmp;
-u64 __iomem *riscv_time_val;
-
-static inline void mmio_set_timer(u64 val)
-{
-       void __iomem *r;
-
-       r = riscv_time_cmp + cpuid_to_hartid_map(smp_processor_id());
-       writeq_relaxed(val, r);
-}
+#include <asm/timex.h>
 
 static int riscv_clock_next_event(unsigned long delta,
                struct clock_event_device *ce)
 {
        csr_set(CSR_IE, IE_TIE);
-       if (IS_ENABLED(CONFIG_RISCV_SBI))
-               sbi_set_timer(get_cycles64() + delta);
-       else
-               mmio_set_timer(get_cycles64() + delta);
+       sbi_set_timer(get_cycles64() + delta);
        return 0;
 }
 
index 5860ca4..2acd9f9 100644 (file)
@@ -1710,9 +1710,9 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
        if (uncorrected_error) {
                core_err_cnt = 1;
                if (ripv)
-                       tp_event = HW_EVENT_ERR_FATAL;
-               else
                        tp_event = HW_EVENT_ERR_UNCORRECTED;
+               else
+                       tp_event = HW_EVENT_ERR_FATAL;
        } else {
                tp_event = HW_EVENT_ERR_CORRECTED;
        }
index fd36374..b8fc4b8 100644 (file)
@@ -1155,7 +1155,7 @@ static void pnd2_mce_output_error(struct mem_ctl_info *mci, const struct mce *m,
        u32 optypenum = GET_BITFIELD(m->status, 4, 6);
        int rc;
 
-       tp_event = uc_err ? (ripv ? HW_EVENT_ERR_FATAL : HW_EVENT_ERR_UNCORRECTED) :
+       tp_event = uc_err ? (ripv ? HW_EVENT_ERR_UNCORRECTED : HW_EVENT_ERR_FATAL) :
                                                 HW_EVENT_ERR_CORRECTED;
 
        /*
index d414698..c5ab634 100644 (file)
@@ -2982,9 +2982,9 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
        if (uncorrected_error) {
                core_err_cnt = 1;
                if (ripv) {
-                       tp_event = HW_EVENT_ERR_FATAL;
-               } else {
                        tp_event = HW_EVENT_ERR_UNCORRECTED;
+               } else {
+                       tp_event = HW_EVENT_ERR_FATAL;
                }
        } else {
                tp_event = HW_EVENT_ERR_CORRECTED;
index 6d8d6dc..2b4ce8e 100644 (file)
@@ -493,9 +493,9 @@ static void skx_mce_output_error(struct mem_ctl_info *mci,
        if (uncorrected_error) {
                core_err_cnt = 1;
                if (ripv) {
-                       tp_event = HW_EVENT_ERR_FATAL;
-               } else {
                        tp_event = HW_EVENT_ERR_UNCORRECTED;
+               } else {
+                       tp_event = HW_EVENT_ERR_FATAL;
                }
        } else {
                tp_event = HW_EVENT_ERR_CORRECTED;
index fdd1db0..3aa07c3 100644 (file)
@@ -381,6 +381,7 @@ static int __init efisubsys_init(void)
        efi_kobj = kobject_create_and_add("efi", firmware_kobj);
        if (!efi_kobj) {
                pr_err("efi: Firmware registration failed.\n");
+               destroy_workqueue(efi_rts_wq);
                return -ENOMEM;
        }
 
@@ -424,6 +425,7 @@ err_unregister:
                generic_ops_unregister();
 err_put:
        kobject_put(efi_kobj);
+       destroy_workqueue(efi_rts_wq);
        return error;
 }
 
index 6bca70b..f735db5 100644 (file)
@@ -187,20 +187,28 @@ int efi_printk(const char *fmt, ...)
  */
 efi_status_t efi_parse_options(char const *cmdline)
 {
-       size_t len = strlen(cmdline) + 1;
+       size_t len;
        efi_status_t status;
        char *str, *buf;
 
+       if (!cmdline)
+               return EFI_SUCCESS;
+
+       len = strnlen(cmdline, COMMAND_LINE_SIZE - 1) + 1;
        status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, len, (void **)&buf);
        if (status != EFI_SUCCESS)
                return status;
 
-       str = skip_spaces(memcpy(buf, cmdline, len));
+       memcpy(buf, cmdline, len - 1);
+       buf[len - 1] = '\0';
+       str = skip_spaces(buf);
 
        while (*str) {
                char *param, *val;
 
                str = next_arg(str, &param, &val);
+               if (!val && !strcmp(param, "--"))
+                       break;
 
                if (!strcmp(param, "nokaslr")) {
                        efi_nokaslr = true;
index c7fd0c4..1102de7 100644 (file)
@@ -195,19 +195,32 @@ static uint32_t get_sdma_rlc_reg_offset(struct amdgpu_device *adev,
                                unsigned int engine_id,
                                unsigned int queue_id)
 {
-       uint32_t sdma_engine_reg_base[2] = {
-               SOC15_REG_OFFSET(SDMA0, 0,
-                                mmSDMA0_RLC0_RB_CNTL) - mmSDMA0_RLC0_RB_CNTL,
-               SOC15_REG_OFFSET(SDMA1, 0,
-                                mmSDMA1_RLC0_RB_CNTL) - mmSDMA1_RLC0_RB_CNTL
-       };
-       uint32_t retval = sdma_engine_reg_base[engine_id]
+       uint32_t sdma_engine_reg_base = 0;
+       uint32_t sdma_rlc_reg_offset;
+
+       switch (engine_id) {
+       default:
+               dev_warn(adev->dev,
+                        "Invalid sdma engine id (%d), using engine id 0\n",
+                        engine_id);
+               fallthrough;
+       case 0:
+               sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA0, 0,
+                               mmSDMA0_RLC0_RB_CNTL) - mmSDMA0_RLC0_RB_CNTL;
+               break;
+       case 1:
+               sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA1, 0,
+                               mmSDMA1_RLC0_RB_CNTL) - mmSDMA0_RLC0_RB_CNTL;
+               break;
+       }
+
+       sdma_rlc_reg_offset = sdma_engine_reg_base
                + queue_id * (mmSDMA0_RLC1_RB_CNTL - mmSDMA0_RLC0_RB_CNTL);
 
        pr_debug("RLC register offset for SDMA%d RLC%d: 0x%x\n", engine_id,
-                       queue_id, retval);
+                queue_id, sdma_rlc_reg_offset);
 
-       return retval;
+       return sdma_rlc_reg_offset;
 }
 
 static inline struct v9_mqd *get_mqd(void *mqd)
index bcce4c0..1bedb41 100644 (file)
@@ -1243,7 +1243,6 @@ void amdgpu_ras_debugfs_remove(struct amdgpu_device *adev,
        if (!obj || !obj->ent)
                return;
 
-       debugfs_remove(obj->ent);
        obj->ent = NULL;
        put_obj(obj);
 }
@@ -1257,7 +1256,6 @@ static void amdgpu_ras_debugfs_remove_all(struct amdgpu_device *adev)
                amdgpu_ras_debugfs_remove(adev, &obj->head);
        }
 
-       debugfs_remove_recursive(con->dir);
        con->dir = NULL;
 }
 /* debugfs end */
index 134cc36..0739e25 100644 (file)
@@ -462,7 +462,7 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
        unsigned int pages;
        int i, r;
 
-       *sgt = kmalloc(sizeof(*sg), GFP_KERNEL);
+       *sgt = kmalloc(sizeof(**sgt), GFP_KERNEL);
        if (!*sgt)
                return -ENOMEM;
 
index cb9d60a..b95f222 100644 (file)
@@ -691,6 +691,7 @@ static const struct soc15_reg_golden golden_settings_gc_9_4_1_arct[] =
        SOC15_REG_GOLDEN_VALUE(GC, 0, mmTCP_CHAN_STEER_5_ARCT, 0x3ff, 0x135),
        SOC15_REG_GOLDEN_VALUE(GC, 0, mmSQ_CONFIG, 0xffffffff, 0x011A0000),
        SOC15_REG_GOLDEN_VALUE(GC, 0, mmSQ_FIFO_SIZES, 0xffffffff, 0x00000f00),
+       SOC15_REG_GOLDEN_VALUE(GC, 0, mmTCP_UTCL1_CNTL1, 0x30000000, 0x30000000)
 };
 
 static const struct soc15_reg_rlcg rlcg_access_gc_9_0[] = {
index fa0bca3..5d25059 100644 (file)
@@ -135,6 +135,12 @@ static void gfxhub_v2_1_init_cache_regs(struct amdgpu_device *adev)
 {
        uint32_t tmp;
 
+       /* These registers are not accessible to VF-SRIOV.
+        * The PF will program them instead.
+        */
+       if (amdgpu_sriov_vf(adev))
+               return;
+
        /* Setup L2 cache */
        tmp = RREG32_SOC15(GC, 0, mmGCVM_L2_CNTL);
        tmp = REG_SET_FIELD(tmp, GCVM_L2_CNTL, ENABLE_L2_CACHE, 1);
@@ -190,6 +196,12 @@ static void gfxhub_v2_1_enable_system_domain(struct amdgpu_device *adev)
 
 static void gfxhub_v2_1_disable_identity_aperture(struct amdgpu_device *adev)
 {
+       /* These registers are not accessible to VF-SRIOV.
+        * The PF will program them instead.
+        */
+       if (amdgpu_sriov_vf(adev))
+               return;
+
        WREG32_SOC15(GC, 0, mmGCVM_L2_CONTEXT1_IDENTITY_APERTURE_LOW_ADDR_LO32,
                     0xFFFFFFFF);
        WREG32_SOC15(GC, 0, mmGCVM_L2_CONTEXT1_IDENTITY_APERTURE_LOW_ADDR_HI32,
@@ -326,6 +338,13 @@ void gfxhub_v2_1_set_fault_enable_default(struct amdgpu_device *adev,
                                          bool value)
 {
        u32 tmp;
+
+       /* These registers are not accessible to VF-SRIOV.
+        * The PF will program them instead.
+        */
+       if (amdgpu_sriov_vf(adev))
+               return;
+
        tmp = RREG32_SOC15(GC, 0, mmGCVM_L2_PROTECTION_FAULT_CNTL);
        tmp = REG_SET_FIELD(tmp, GCVM_L2_PROTECTION_FAULT_CNTL,
                            RANGE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
index 757fa8e..c79fc54 100644 (file)
@@ -134,6 +134,12 @@ static void mmhub_v2_0_init_cache_regs(struct amdgpu_device *adev)
 {
        uint32_t tmp;
 
+       /* These registers are not accessible to VF-SRIOV.
+        * The PF will program them instead.
+        */
+       if (amdgpu_sriov_vf(adev))
+               return;
+
        /* Setup L2 cache */
        tmp = RREG32_SOC15(MMHUB, 0, mmMMVM_L2_CNTL);
        tmp = REG_SET_FIELD(tmp, MMVM_L2_CNTL, ENABLE_L2_CACHE, 1);
@@ -189,6 +195,12 @@ static void mmhub_v2_0_enable_system_domain(struct amdgpu_device *adev)
 
 static void mmhub_v2_0_disable_identity_aperture(struct amdgpu_device *adev)
 {
+       /* These registers are not accessible to VF-SRIOV.
+        * The PF will program them instead.
+        */
+       if (amdgpu_sriov_vf(adev))
+               return;
+
        WREG32_SOC15(MMHUB, 0,
                     mmMMVM_L2_CONTEXT1_IDENTITY_APERTURE_LOW_ADDR_LO32,
                     0xFFFFFFFF);
@@ -318,6 +330,13 @@ void mmhub_v2_0_gart_disable(struct amdgpu_device *adev)
 void mmhub_v2_0_set_fault_enable_default(struct amdgpu_device *adev, bool value)
 {
        u32 tmp;
+
+       /* These registers are not accessible to VF-SRIOV.
+        * The PF will program them instead.
+        */
+       if (amdgpu_sriov_vf(adev))
+               return;
+
        tmp = RREG32_SOC15(MMHUB, 0, mmMMVM_L2_PROTECTION_FAULT_CNTL);
        tmp = REG_SET_FIELD(tmp, MMVM_L2_PROTECTION_FAULT_CNTL,
                            RANGE_PROTECTION_FAULT_ENABLE_DEFAULT, value);
index d488d25..e16874f 100644 (file)
@@ -179,12 +179,11 @@ static int psp_v11_0_init_microcode(struct psp_context *psp)
                }
                break;
        case CHIP_SIENNA_CICHLID:
+       case CHIP_NAVY_FLOUNDER:
                err = psp_init_ta_microcode(&adev->psp, chip_name);
                if (err)
                        return err;
                break;
-       case CHIP_NAVY_FLOUNDER:
-               break;
        default:
                BUG();
        }
index e4b33c6..df93382 100644 (file)
@@ -2196,6 +2196,7 @@ void amdgpu_dm_update_connector_after_detect(
 
                        drm_connector_update_edid_property(connector,
                                                           aconnector->edid);
+                       drm_add_edid_modes(connector, aconnector->edid);
 
                        if (aconnector->dc_link->aux_mode)
                                drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
index 078b7e3..2d5c7da 100644 (file)
@@ -1108,6 +1108,18 @@ static enum bp_result bios_parser_enable_disp_power_gating(
                action);
 }
 
+static enum bp_result bios_parser_enable_lvtma_control(
+       struct dc_bios *dcb,
+       uint8_t uc_pwr_on)
+{
+       struct bios_parser *bp = BP_FROM_DCB(dcb);
+
+       if (!bp->cmd_tbl.enable_lvtma_control)
+               return BP_RESULT_FAILURE;
+
+       return bp->cmd_tbl.enable_lvtma_control(bp, uc_pwr_on);
+}
+
 static bool bios_parser_is_accelerated_mode(
        struct dc_bios *dcb)
 {
@@ -2208,7 +2220,9 @@ static const struct dc_vbios_funcs vbios_funcs = {
        .get_board_layout_info = bios_get_board_layout_info,
        .pack_data_tables = bios_parser_pack_data_tables,
 
-       .get_atom_dc_golden_table = bios_get_atom_dc_golden_table
+       .get_atom_dc_golden_table = bios_get_atom_dc_golden_table,
+
+       .enable_lvtma_control = bios_parser_enable_lvtma_control
 };
 
 static bool bios_parser2_construct(
index bed9157..eb3ae5c 100644 (file)
@@ -904,6 +904,33 @@ static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp, uint8_t id)
        return 0;
 }
 
+/******************************************************************************
+ ******************************************************************************
+ **
+ **                  LVTMA CONTROL
+ **
+ ******************************************************************************
+ *****************************************************************************/
+
+static enum bp_result enable_lvtma_control(
+       struct bios_parser *bp,
+       uint8_t uc_pwr_on);
+
+static void init_enable_lvtma_control(struct bios_parser *bp)
+{
+       /* TODO add switch for table vrsion */
+       bp->cmd_tbl.enable_lvtma_control = enable_lvtma_control;
+
+}
+
+static enum bp_result enable_lvtma_control(
+       struct bios_parser *bp,
+       uint8_t uc_pwr_on)
+{
+       enum bp_result result = BP_RESULT_FAILURE;
+       return result;
+}
+
 void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp)
 {
        init_dig_encoder_control(bp);
@@ -919,4 +946,5 @@ void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp)
        init_set_dce_clock(bp);
        init_get_smu_clock_info(bp);
 
+       init_enable_lvtma_control(bp);
 }
index 7a2af24..7bdce01 100644 (file)
@@ -94,7 +94,8 @@ struct cmd_tbl {
                struct bp_set_dce_clock_parameters *bp_params);
        unsigned int (*get_smu_clock_info)(
                        struct bios_parser *bp, uint8_t id);
-
+       enum bp_result (*enable_lvtma_control)(struct bios_parser *bp,
+                       uint8_t uc_pwr_on);
 };
 
 void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp);
index 4bd6e03..117d8aa 100644 (file)
@@ -3286,12 +3286,11 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx)
                core_link_set_avmute(pipe_ctx, true);
        }
 
+       dc->hwss.blank_stream(pipe_ctx);
 #if defined(CONFIG_DRM_AMD_DC_HDCP)
        update_psp_stream_config(pipe_ctx, true);
 #endif
 
-       dc->hwss.blank_stream(pipe_ctx);
-
        if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
                deallocate_mst_payload(pipe_ctx);
 
index d06d070..0811f94 100644 (file)
@@ -136,6 +136,10 @@ struct dc_vbios_funcs {
 
        enum bp_result (*get_atom_dc_golden_table)(
                        struct dc_bios *dcb);
+
+       enum bp_result (*enable_lvtma_control)(
+               struct dc_bios *bios,
+               uint8_t uc_pwr_on);
 };
 
 struct bios_registers {
index 70ec691..99c68ca 100644 (file)
@@ -49,7 +49,7 @@
 #define DCN_PANEL_CNTL_REG_LIST()\
        DCN_PANEL_CNTL_SR(PWRSEQ_CNTL, LVTMA), \
        DCN_PANEL_CNTL_SR(PWRSEQ_STATE, LVTMA), \
-       DCE_PANEL_CNTL_SR(PWRSEQ_REF_DIV, LVTMA), \
+       DCN_PANEL_CNTL_SR(PWRSEQ_REF_DIV, LVTMA), \
        SR(BL_PWM_CNTL), \
        SR(BL_PWM_CNTL2), \
        SR(BL_PWM_PERIOD_CNTL), \
index 49380ed..45c9e90 100644 (file)
@@ -842,6 +842,17 @@ void dce110_edp_power_control(
                cntl.coherent = false;
                cntl.lanes_number = LANE_COUNT_FOUR;
                cntl.hpd_sel = link->link_enc->hpd_source;
+
+               if (ctx->dc->ctx->dmub_srv &&
+                               ctx->dc->debug.dmub_command_table) {
+                       if (cntl.action == TRANSMITTER_CONTROL_POWER_ON)
+                               bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
+                                               LVTMA_CONTROL_POWER_ON);
+                       else
+                               bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
+                                               LVTMA_CONTROL_POWER_OFF);
+               }
+
                bp_result = link_transmitter_control(ctx->dc_bios, &cntl);
 
                if (!power_up)
@@ -919,8 +930,21 @@ void dce110_edp_backlight_control(
                /*edp 1.2*/
        if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON)
                edp_receiver_ready_T7(link);
+
+       if (ctx->dc->ctx->dmub_srv &&
+                       ctx->dc->debug.dmub_command_table) {
+               if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON)
+                       ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
+                                       LVTMA_CONTROL_LCD_BLON);
+               else
+                       ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
+                                       LVTMA_CONTROL_LCD_BLOFF);
+       }
+
        link_transmitter_control(ctx->dc_bios, &cntl);
 
+
+
        if (enable && link->dpcd_sink_ext_caps.bits.oled)
                msleep(OLED_POST_T7_DELAY);
 
index 07b2f93..842abb4 100644 (file)
@@ -121,35 +121,35 @@ void enc1_update_generic_info_packet(
        switch (packet_index) {
        case 0:
                REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-                               AFMT_GENERIC0_FRAME_UPDATE, 1);
+                               AFMT_GENERIC0_IMMEDIATE_UPDATE, 1);
                break;
        case 1:
                REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-                               AFMT_GENERIC1_FRAME_UPDATE, 1);
+                               AFMT_GENERIC1_IMMEDIATE_UPDATE, 1);
                break;
        case 2:
                REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-                               AFMT_GENERIC2_FRAME_UPDATE, 1);
+                               AFMT_GENERIC2_IMMEDIATE_UPDATE, 1);
                break;
        case 3:
                REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-                               AFMT_GENERIC3_FRAME_UPDATE, 1);
+                               AFMT_GENERIC3_IMMEDIATE_UPDATE, 1);
                break;
        case 4:
                REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-                               AFMT_GENERIC4_FRAME_UPDATE, 1);
+                               AFMT_GENERIC4_IMMEDIATE_UPDATE, 1);
                break;
        case 5:
                REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-                               AFMT_GENERIC5_FRAME_UPDATE, 1);
+                               AFMT_GENERIC5_IMMEDIATE_UPDATE, 1);
                break;
        case 6:
                REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-                               AFMT_GENERIC6_FRAME_UPDATE, 1);
+                               AFMT_GENERIC6_IMMEDIATE_UPDATE, 1);
                break;
        case 7:
                REG_UPDATE(AFMT_VBI_PACKET_CONTROL1,
-                               AFMT_GENERIC7_FRAME_UPDATE, 1);
+                               AFMT_GENERIC7_IMMEDIATE_UPDATE, 1);
                break;
        default:
                break;
index ed385b1..30eae74 100644 (file)
@@ -281,7 +281,14 @@ struct dcn10_stream_enc_registers {
        SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC2_FRAME_UPDATE, mask_sh),\
        SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC3_FRAME_UPDATE, mask_sh),\
        SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC4_FRAME_UPDATE, mask_sh),\
+       SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC0_IMMEDIATE_UPDATE, mask_sh),\
+       SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC1_IMMEDIATE_UPDATE, mask_sh),\
+       SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC2_IMMEDIATE_UPDATE, mask_sh),\
+       SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC3_IMMEDIATE_UPDATE, mask_sh),\
        SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC4_IMMEDIATE_UPDATE, mask_sh),\
+       SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC5_IMMEDIATE_UPDATE, mask_sh),\
+       SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC6_IMMEDIATE_UPDATE, mask_sh),\
+       SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC7_IMMEDIATE_UPDATE, mask_sh),\
        SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC5_FRAME_UPDATE, mask_sh),\
        SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC6_FRAME_UPDATE, mask_sh),\
        SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC7_FRAME_UPDATE, mask_sh),\
@@ -345,7 +352,14 @@ struct dcn10_stream_enc_registers {
        type AFMT_GENERIC2_FRAME_UPDATE;\
        type AFMT_GENERIC3_FRAME_UPDATE;\
        type AFMT_GENERIC4_FRAME_UPDATE;\
+       type AFMT_GENERIC0_IMMEDIATE_UPDATE;\
+       type AFMT_GENERIC1_IMMEDIATE_UPDATE;\
+       type AFMT_GENERIC2_IMMEDIATE_UPDATE;\
+       type AFMT_GENERIC3_IMMEDIATE_UPDATE;\
        type AFMT_GENERIC4_IMMEDIATE_UPDATE;\
+       type AFMT_GENERIC5_IMMEDIATE_UPDATE;\
+       type AFMT_GENERIC6_IMMEDIATE_UPDATE;\
+       type AFMT_GENERIC7_IMMEDIATE_UPDATE;\
        type AFMT_GENERIC5_FRAME_UPDATE;\
        type AFMT_GENERIC6_FRAME_UPDATE;\
        type AFMT_GENERIC7_FRAME_UPDATE;\
index 66180b4..c8cfd3b 100644 (file)
@@ -1457,8 +1457,8 @@ static void dcn20_update_dchubp_dpp(
 
        /* Any updates are handled in dc interface, just need to apply existing for plane enable */
        if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
-                       pipe_ctx->update_flags.bits.scaler || pipe_ctx->update_flags.bits.viewport)
-                       && pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
+                       pipe_ctx->update_flags.bits.scaler || viewport_changed == true) &&
+                       pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
                dc->hwss.set_cursor_position(pipe_ctx);
                dc->hwss.set_cursor_attribute(pipe_ctx);
 
index bf0044f..dcbf28d 100644 (file)
        LE_SF(DCIO_SOFT_RESET, UNIPHYB_SOFT_RESET, mask_sh),\
        LE_SF(DCIO_SOFT_RESET, UNIPHYC_SOFT_RESET, mask_sh),\
        LE_SF(DCIO_SOFT_RESET, UNIPHYD_SOFT_RESET, mask_sh),\
-       LE_SF(DCIO_SOFT_RESET, UNIPHYE_SOFT_RESET, mask_sh)
+       LE_SF(DCIO_SOFT_RESET, UNIPHYE_SOFT_RESET, mask_sh),\
+       LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, mask_sh),\
+       LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, mask_sh)
 
 #define LINK_ENCODER_MASK_SH_LIST_DCN20(mask_sh)\
        LINK_ENCODER_MASK_SH_LIST_DCN10(mask_sh),\
index 790baf5..9140b3f 100644 (file)
@@ -3141,7 +3141,7 @@ static bool dcn20_validate_bandwidth_internal(struct dc *dc, struct dc_state *co
        int vlevel = 0;
        int pipe_split_from[MAX_PIPES];
        int pipe_cnt = 0;
-       display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_KERNEL);
+       display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_ATOMIC);
        DC_LOGGER_INIT(dc->ctx->logger);
 
        BW_VAL_TRACE_COUNT();
index 8e9fd59..2fbf879 100644 (file)
        DPCS_DCN2_MASK_SH_LIST(mask_sh),\
        LE_SF(DPCSTX0_DPCSTX_TX_CNTL, DPCS_TX_DATA_ORDER_INVERT_18_BIT, mask_sh),\
        LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL0, RDPCS_PHY_TX_VBOOST_LVL, mask_sh),\
-       LE_SF(RDPCSTX0_RDPCSTX_CLOCK_CNTL, RDPCS_TX_CLK_EN, mask_sh)
+       LE_SF(RDPCSTX0_RDPCSTX_CLOCK_CNTL, RDPCS_TX_CLK_EN, mask_sh),\
+       LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, mask_sh),\
+       LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, mask_sh)
+
 
 void dcn30_link_encoder_construct(
        struct dcn20_link_encoder *enc20,
index 653a571..ebe0cc5 100644 (file)
@@ -491,6 +491,7 @@ static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = {
 [id] = {\
        LE_DCN3_REG_LIST(id), \
        UNIPHY_DCN2_REG_LIST(phyid), \
+       SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \
 }
 
 static const struct dce110_aux_registers_shift aux_shift = {
index b54814f..2beb284 100644 (file)
@@ -63,6 +63,7 @@ typedef struct {
 
 #define BPP_INVALID 0
 #define BPP_BLENDED_PIPE 0xffffffff
+#define DCN30_MAX_DSC_IMAGE_WIDTH 5184
 
 static void DisplayPipeConfiguration(struct display_mode_lib *mode_lib);
 static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation(
@@ -3984,6 +3985,9 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
                                } else if (v->PlaneRequiredDISPCLKWithoutODMCombine > v->MaxDispclkRoundedDownToDFSGranularity) {
                                        v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1;
                                        v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine2To1;
+                               } else if (v->DSCEnabled[k] && (v->HActive[k] > DCN30_MAX_DSC_IMAGE_WIDTH)) {
+                                       v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1;
+                                       v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithODMCombine2To1;
                                } else {
                                        v->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_disabled;
                                        v->PlaneRequiredDISPCLK = v->PlaneRequiredDISPCLKWithoutODMCombine;
index c30437a..21011ed 100644 (file)
@@ -101,6 +101,13 @@ enum bp_pipe_control_action {
        ASIC_PIPE_INIT
 };
 
+enum bp_lvtma_control_action {
+       LVTMA_CONTROL_LCD_BLOFF = 2,
+       LVTMA_CONTROL_LCD_BLON = 3,
+       LVTMA_CONTROL_POWER_ON = 12,
+       LVTMA_CONTROL_POWER_OFF = 13
+};
+
 struct bp_encoder_control {
        enum bp_encoder_control_action action;
        enum engine_id engine_id;
index 89ef9f6..16df2a4 100644 (file)
@@ -431,6 +431,9 @@ struct fixed31_32 dc_fixpt_log(struct fixed31_32 arg);
  */
 static inline struct fixed31_32 dc_fixpt_pow(struct fixed31_32 arg1, struct fixed31_32 arg2)
 {
+       if (arg1.value == 0)
+               return arg2.value == 0 ? dc_fixpt_one : dc_fixpt_zero;
+
        return dc_fixpt_exp(
                dc_fixpt_mul(
                        dc_fixpt_log(arg1),
index 81820f3..d988533 100644 (file)
@@ -324,22 +324,44 @@ static void apply_below_the_range(struct core_freesync *core_freesync,
 
                /* Choose number of frames to insert based on how close it
                 * can get to the mid point of the variable range.
+                *  - Delta for CEIL: delta_from_mid_point_in_us_1
+                *  - Delta for FLOOR: delta_from_mid_point_in_us_2
                 */
-               if ((frame_time_in_us / mid_point_frames_ceil) > in_out_vrr->min_duration_in_us &&
-                               (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2 ||
-                                               mid_point_frames_floor < 2)) {
+               if ((last_render_time_in_us / mid_point_frames_ceil) < in_out_vrr->min_duration_in_us) {
+                       /* Check for out of range.
+                        * If using CEIL produces a value that is out of range,
+                        * then we are forced to use FLOOR.
+                        */
+                       frames_to_insert = mid_point_frames_floor;
+               } else if (mid_point_frames_floor < 2) {
+                       /* Check if FLOOR would result in non-LFC. In this case
+                        * choose to use CEIL
+                        */
+                       frames_to_insert = mid_point_frames_ceil;
+               } else if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
+                       /* If choosing CEIL results in a frame duration that is
+                        * closer to the mid point of the range.
+                        * Choose CEIL
+                        */
                        frames_to_insert = mid_point_frames_ceil;
-                       delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 -
-                                       delta_from_mid_point_in_us_1;
                } else {
+                       /* If choosing FLOOR results in a frame duration that is
+                        * closer to the mid point of the range.
+                        * Choose FLOOR
+                        */
                        frames_to_insert = mid_point_frames_floor;
-                       delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 -
-                                       delta_from_mid_point_in_us_2;
                }
 
                /* Prefer current frame multiplier when BTR is enabled unless it drifts
                 * too far from the midpoint
                 */
+               if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) {
+                       delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 -
+                                       delta_from_mid_point_in_us_1;
+               } else {
+                       delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_1 -
+                                       delta_from_mid_point_in_us_2;
+               }
                if (in_out_vrr->btr.frames_to_insert != 0 &&
                                delta_from_mid_point_delta_in_us < BTR_DRIFT_MARGIN) {
                        if (((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) <
index 6c991de..fb962b9 100644 (file)
@@ -2204,14 +2204,17 @@ static const struct throttling_logging_label {
 };
 static void arcturus_log_thermal_throttling_event(struct smu_context *smu)
 {
+       int ret;
        int throttler_idx, throtting_events = 0, buf_idx = 0;
        struct amdgpu_device *adev = smu->adev;
        uint32_t throttler_status;
        char log_buf[256];
 
-       arcturus_get_smu_metrics_data(smu,
-                                     METRICS_THROTTLER_STATUS,
-                                     &throttler_status);
+       ret = arcturus_get_smu_metrics_data(smu,
+                                           METRICS_THROTTLER_STATUS,
+                                           &throttler_status);
+       if (ret)
+               return;
 
        memset(log_buf, 0, sizeof(log_buf));
        for (throttler_idx = 0; throttler_idx < ARRAY_SIZE(logging_label);
index 3b88396..ea70d73 100644 (file)
@@ -979,10 +979,7 @@ static int vega20_disable_all_smu_features(struct pp_hwmgr *hwmgr)
 {
        struct vega20_hwmgr *data =
                        (struct vega20_hwmgr *)(hwmgr->backend);
-       uint64_t features_enabled;
-       int i;
-       bool enabled;
-       int ret = 0;
+       int i, ret = 0;
 
        PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr,
                        PPSMC_MSG_DisableAllSmuFeatures,
@@ -990,17 +987,8 @@ static int vega20_disable_all_smu_features(struct pp_hwmgr *hwmgr)
                        "[DisableAllSMUFeatures] Failed to disable all smu features!",
                        return ret);
 
-       ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
-       PP_ASSERT_WITH_CODE(!ret,
-                       "[DisableAllSMUFeatures] Failed to get enabled smc features!",
-                       return ret);
-
-       for (i = 0; i < GNLD_FEATURES_MAX; i++) {
-               enabled = (features_enabled & data->smu_features[i].smu_feature_bitmap) ?
-                       true : false;
-               data->smu_features[i].enabled = enabled;
-               data->smu_features[i].supported = enabled;
-       }
+       for (i = 0; i < GNLD_FEATURES_MAX; i++)
+               data->smu_features[i].enabled = 0;
 
        return 0;
 }
@@ -1652,12 +1640,6 @@ static void vega20_init_powergate_state(struct pp_hwmgr *hwmgr)
 
        data->uvd_power_gated = true;
        data->vce_power_gated = true;
-
-       if (data->smu_features[GNLD_DPM_UVD].enabled)
-               data->uvd_power_gated = false;
-
-       if (data->smu_features[GNLD_DPM_VCE].enabled)
-               data->vce_power_gated = false;
 }
 
 static int vega20_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
@@ -3230,10 +3212,11 @@ static int vega20_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf)
 
 static int vega20_set_ppfeature_status(struct pp_hwmgr *hwmgr, uint64_t new_ppfeature_masks)
 {
-       uint64_t features_enabled;
-       uint64_t features_to_enable;
-       uint64_t features_to_disable;
-       int ret = 0;
+       struct vega20_hwmgr *data =
+                       (struct vega20_hwmgr *)(hwmgr->backend);
+       uint64_t features_enabled, features_to_enable, features_to_disable;
+       int i, ret = 0;
+       bool enabled;
 
        if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX))
                return -EINVAL;
@@ -3262,6 +3245,17 @@ static int vega20_set_ppfeature_status(struct pp_hwmgr *hwmgr, uint64_t new_ppfe
                        return ret;
        }
 
+       /* Update the cached feature enablement state */
+       ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < GNLD_FEATURES_MAX; i++) {
+               enabled = (features_enabled & data->smu_features[i].smu_feature_bitmap) ?
+                       true : false;
+               data->smu_features[i].enabled = enabled;
+       }
+
        return 0;
 }
 
index 729ec6e..b2ec3a5 100644 (file)
@@ -14930,7 +14930,7 @@ static int intel_atomic_check(struct drm_device *dev,
        if (any_ms && !check_digital_port_conflicts(state)) {
                drm_dbg_kms(&dev_priv->drm,
                            "rejecting conflicting digital port configuration\n");
-               ret = EINVAL;
+               ret = -EINVAL;
                goto fail;
        }
 
index 3644752..5a5cfe2 100644 (file)
@@ -2044,9 +2044,12 @@ DEFINE_SHOW_ATTRIBUTE(i915_hdcp_sink_capability);
 static int i915_lpsp_capability_show(struct seq_file *m, void *data)
 {
        struct drm_connector *connector = m->private;
-       struct intel_encoder *encoder =
-                       intel_attached_encoder(to_intel_connector(connector));
        struct drm_i915_private *i915 = to_i915(connector->dev);
+       struct intel_encoder *encoder;
+
+       encoder = intel_attached_encoder(to_intel_connector(connector));
+       if (!encoder)
+               return -ENODEV;
 
        if (connector->status != connector_status_connected)
                return -ENODEV;
index 0c713e8..e0fcb89 100644 (file)
@@ -4146,6 +4146,12 @@ static const struct i915_power_well_desc tgl_power_wells[] = {
                        .hsw.idx = TGL_PW_CTL_IDX_DDI_TC6,
                },
        },
+       {
+               .name = "TC cold off",
+               .domains = TGL_TC_COLD_OFF_POWER_DOMAINS,
+               .ops = &tgl_tc_cold_off_ops,
+               .id = DISP_PW_ID_NONE,
+       },
        {
                .name = "AUX A",
                .domains = TGL_AUX_A_IO_POWER_DOMAINS,
@@ -4332,12 +4338,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = {
                        .hsw.irq_pipe_mask = BIT(PIPE_D),
                },
        },
-       {
-               .name = "TC cold off",
-               .domains = TGL_TC_COLD_OFF_POWER_DOMAINS,
-               .ops = &tgl_tc_cold_off_ops,
-               .id = DISP_PW_ID_NONE,
-       },
 };
 
 static const struct i915_power_well_desc rkl_power_wells[] = {
@@ -5240,10 +5240,10 @@ struct buddy_page_mask {
 };
 
 static const struct buddy_page_mask tgl_buddy_page_masks[] = {
-       { .num_channels = 1, .type = INTEL_DRAM_LPDDR4, .page_mask = 0xE },
        { .num_channels = 1, .type = INTEL_DRAM_DDR4,   .page_mask = 0xF },
        { .num_channels = 2, .type = INTEL_DRAM_LPDDR4, .page_mask = 0x1C },
        { .num_channels = 2, .type = INTEL_DRAM_DDR4,   .page_mask = 0x1F },
+       { .num_channels = 4, .type = INTEL_DRAM_LPDDR4, .page_mask = 0x38 },
        {}
 };
 
index 072725a..ad86c5e 100644 (file)
@@ -70,6 +70,7 @@ static void vgpu_pci_cfg_mem_write(struct intel_vgpu *vgpu, unsigned int off,
 {
        u8 *cfg_base = vgpu_cfg_space(vgpu);
        u8 mask, new, old;
+       pci_power_t pwr;
        int i = 0;
 
        for (; i < bytes && (off + i < sizeof(pci_cfg_space_rw_bmp)); i++) {
@@ -91,6 +92,15 @@ static void vgpu_pci_cfg_mem_write(struct intel_vgpu *vgpu, unsigned int off,
        /* For other configuration space directly copy as it is. */
        if (i < bytes)
                memcpy(cfg_base + off + i, src + i, bytes - i);
+
+       if (off == vgpu->cfg_space.pmcsr_off && vgpu->cfg_space.pmcsr_off) {
+               pwr = (pci_power_t __force)(*(u16*)(&vgpu_cfg_space(vgpu)[off])
+                       & PCI_PM_CTRL_STATE_MASK);
+               if (pwr == PCI_D3hot)
+                       vgpu->d3_entered = true;
+               gvt_dbg_core("vgpu-%d power status changed to %d\n",
+                            vgpu->id, pwr);
+       }
 }
 
 /**
@@ -366,6 +376,7 @@ void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu,
        struct intel_gvt *gvt = vgpu->gvt;
        const struct intel_gvt_device_info *info = &gvt->device_info;
        u16 *gmch_ctl;
+       u8 next;
 
        memcpy(vgpu_cfg_space(vgpu), gvt->firmware.cfg_space,
               info->cfg_space_size);
@@ -401,6 +412,19 @@ void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu,
                pci_resource_len(gvt->gt->i915->drm.pdev, 2);
 
        memset(vgpu_cfg_space(vgpu) + PCI_ROM_ADDRESS, 0, 4);
+
+       /* PM Support */
+       vgpu->cfg_space.pmcsr_off = 0;
+       if (vgpu_cfg_space(vgpu)[PCI_STATUS] & PCI_STATUS_CAP_LIST) {
+               next = vgpu_cfg_space(vgpu)[PCI_CAPABILITY_LIST];
+               do {
+                       if (vgpu_cfg_space(vgpu)[next + PCI_CAP_LIST_ID] == PCI_CAP_ID_PM) {
+                               vgpu->cfg_space.pmcsr_off = next + PCI_PM_CTRL;
+                               break;
+                       }
+                       next = vgpu_cfg_space(vgpu)[next + PCI_CAP_LIST_NEXT];
+               } while (next);
+       }
 }
 
 /**
index 2100161..a3a4305 100644 (file)
@@ -2501,7 +2501,7 @@ int intel_vgpu_init_gtt(struct intel_vgpu *vgpu)
        return create_scratch_page_tree(vgpu);
 }
 
-static void intel_vgpu_destroy_all_ppgtt_mm(struct intel_vgpu *vgpu)
+void intel_vgpu_destroy_all_ppgtt_mm(struct intel_vgpu *vgpu)
 {
        struct list_head *pos, *n;
        struct intel_vgpu_mm *mm;
index 320b8d6..52d0d88 100644 (file)
@@ -279,4 +279,6 @@ int intel_vgpu_emulate_ggtt_mmio_read(struct intel_vgpu *vgpu,
 int intel_vgpu_emulate_ggtt_mmio_write(struct intel_vgpu *vgpu,
        unsigned int off, void *p_data, unsigned int bytes);
 
+void intel_vgpu_destroy_all_ppgtt_mm(struct intel_vgpu *vgpu);
+
 #endif /* _GVT_GTT_H_ */
index a4a6db6..ff7f251 100644 (file)
@@ -106,6 +106,7 @@ struct intel_vgpu_pci_bar {
 struct intel_vgpu_cfg_space {
        unsigned char virtual_cfg_space[PCI_CFG_SPACE_EXP_SIZE];
        struct intel_vgpu_pci_bar bar[INTEL_GVT_MAX_BAR_NUM];
+       u32 pmcsr_off;
 };
 
 #define vgpu_cfg_space(vgpu) ((vgpu)->cfg_space.virtual_cfg_space)
@@ -198,6 +199,8 @@ struct intel_vgpu {
        struct intel_vgpu_submission submission;
        struct radix_tree_root page_track_tree;
        u32 hws_pga[I915_NUM_ENGINES];
+       /* Set on PCI_D3, reset on DMLR, not reflecting the actual PM state */
+       bool d3_entered;
 
        struct dentry *debugfs;
 
index 7d36162..8fa9b31 100644 (file)
@@ -257,6 +257,7 @@ void intel_gvt_release_vgpu(struct intel_vgpu *vgpu)
        intel_gvt_deactivate_vgpu(vgpu);
 
        mutex_lock(&vgpu->vgpu_lock);
+       vgpu->d3_entered = false;
        intel_vgpu_clean_workloads(vgpu, ALL_ENGINES);
        intel_vgpu_dmabuf_cleanup(vgpu);
        mutex_unlock(&vgpu->vgpu_lock);
@@ -393,6 +394,7 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
        INIT_RADIX_TREE(&vgpu->page_track_tree, GFP_KERNEL);
        idr_init(&vgpu->object_idr);
        intel_vgpu_init_cfg_space(vgpu, param->primary);
+       vgpu->d3_entered = false;
 
        ret = intel_vgpu_init_mmio(vgpu);
        if (ret)
@@ -557,10 +559,15 @@ void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr,
        /* full GPU reset or device model level reset */
        if (engine_mask == ALL_ENGINES || dmlr) {
                intel_vgpu_select_submission_ops(vgpu, ALL_ENGINES, 0);
-               intel_vgpu_invalidate_ppgtt(vgpu);
+               if (engine_mask == ALL_ENGINES)
+                       intel_vgpu_invalidate_ppgtt(vgpu);
                /*fence will not be reset during virtual reset */
                if (dmlr) {
-                       intel_vgpu_reset_gtt(vgpu);
+                       if(!vgpu->d3_entered) {
+                               intel_vgpu_invalidate_ppgtt(vgpu);
+                               intel_vgpu_destroy_all_ppgtt_mm(vgpu);
+                       }
+                       intel_vgpu_reset_ggtt(vgpu, true);
                        intel_vgpu_reset_resource(vgpu);
                }
 
@@ -572,7 +579,14 @@ void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr,
                        intel_vgpu_reset_cfg_space(vgpu);
                        /* only reset the failsafe mode when dmlr reset */
                        vgpu->failsafe = false;
-                       vgpu->pv_notified = false;
+                       /*
+                        * PCI_D0 is set before dmlr, so reset d3_entered here
+                        * after done using.
+                        */
+                       if(vgpu->d3_entered)
+                               vgpu->d3_entered = false;
+                       else
+                               vgpu->pv_notified = false;
                }
        }
 
index 28bc5f1..0569942 100644 (file)
@@ -445,8 +445,6 @@ static void i915_pmu_event_destroy(struct perf_event *event)
                container_of(event->pmu, typeof(*i915), pmu.base);
 
        drm_WARN_ON(&i915->drm, event->parent);
-
-       module_put(THIS_MODULE);
 }
 
 static int
@@ -538,10 +536,8 @@ static int i915_pmu_event_init(struct perf_event *event)
        if (ret)
                return ret;
 
-       if (!event->parent) {
-               __module_get(THIS_MODULE);
+       if (!event->parent)
                event->destroy = i915_pmu_event_destroy;
-       }
 
        return 0;
 }
@@ -1130,6 +1126,7 @@ void i915_pmu_register(struct drm_i915_private *i915)
        if (!pmu->base.attr_groups)
                goto err_attr;
 
+       pmu->base.module        = THIS_MODULE;
        pmu->base.task_ctx_nr   = perf_invalid_context;
        pmu->base.event_init    = i915_pmu_event_init;
        pmu->base.add           = i915_pmu_event_add;
index 939a6ca..632b912 100644 (file)
@@ -8,8 +8,6 @@
 #include "../i915_selftest.h"
 #include "i915_random.h"
 
-#define SZ_8G (1ULL << 33)
-
 static void __igt_dump_block(struct i915_buddy_mm *mm,
                             struct i915_buddy_block *block,
                             bool buddy)
@@ -281,18 +279,22 @@ static int igt_check_mm(struct i915_buddy_mm *mm)
 static void igt_mm_config(u64 *size, u64 *chunk_size)
 {
        I915_RND_STATE(prng);
-       u64 s, ms;
+       u32 s, ms;
 
        /* Nothing fancy, just try to get an interesting bit pattern */
 
        prandom_seed_state(&prng, i915_selftest.random_seed);
 
-       s = i915_prandom_u64_state(&prng) & (SZ_8G - 1);
-       ms = BIT_ULL(12 + (prandom_u32_state(&prng) % ilog2(s >> 12)));
-       s = max(s & -ms, ms);
+       /* Let size be a random number of pages up to 8 GB (2M pages) */
+       s = 1 + i915_prandom_u32_max_state((BIT(33 - 12)) - 1, &prng);
+       /* Let the chunk size be a random power of 2 less than size */
+       ms = BIT(i915_prandom_u32_max_state(ilog2(s), &prng));
+       /* Round size down to the chunk size */
+       s &= -ms;
 
-       *chunk_size = ms;
-       *size = s;
+       /* Convert from pages to bytes */
+       *chunk_size = (u64)ms << 12;
+       *size = (u64)s << 12;
 }
 
 static int igt_buddy_alloc_smoke(void *arg)
index b9810bf..f127e63 100644 (file)
@@ -78,6 +78,7 @@ static void mock_device_release(struct drm_device *dev)
        drm_mode_config_cleanup(&i915->drm);
 
 out:
+       i915_params_free(&i915->params);
        put_device(&i915->drm.pdev->dev);
        i915->drm.pdev = NULL;
 }
@@ -165,6 +166,8 @@ struct drm_i915_private *mock_gem_device(void)
        i915->drm.pdev = pdev;
        drmm_add_final_kfree(&i915->drm, i915);
 
+       i915_params_copy(&i915->params, &i915_modparams);
+
        intel_runtime_pm_init_early(&i915->runtime_pm);
 
        /* Using the global GTT may ask questions about KMS users, so prepare */
index 7a2430e..c8da7ad 100644 (file)
@@ -179,6 +179,7 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
 
        virtio_gpu_cmd_submit(vgdev, buf, exbuf->size,
                              vfpriv->ctx_id, buflist, out_fence);
+       dma_fence_put(&out_fence->f);
        virtio_gpu_notify(vgdev);
        return 0;
 
index 2cdd3cd..e83651b 100644 (file)
@@ -79,6 +79,7 @@ void virtio_gpu_cleanup_object(struct virtio_gpu_object *bo)
                        }
 
                        sg_free_table(shmem->pages);
+                       kfree(shmem->pages);
                        shmem->pages = NULL;
                        drm_gem_shmem_unpin(&bo->base.base);
                }
index ef0cd29..c36b4d2 100644 (file)
@@ -2751,7 +2751,7 @@ static int __init ib_core_init(void)
 
        ret = addr_init();
        if (ret) {
-               pr_warn("Could't init IB address resolution\n");
+               pr_warn("Couldn't init IB address resolution\n");
                goto err_ibnl;
        }
 
index dad0df8..17ac8b7 100644 (file)
@@ -821,7 +821,8 @@ static int bnxt_re_handle_qp_async_event(struct creq_qp_event *qp_event,
        struct ib_event event;
        unsigned int flags;
 
-       if (qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR) {
+       if (qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR &&
+           rdma_is_kernel_res(&qp->ib_qp.res)) {
                flags = bnxt_re_lock_cqs(qp);
                bnxt_qplib_add_flush_qp(&qp->qplib_qp);
                bnxt_re_unlock_cqs(qp, flags);
index 9af82ff..73d197e 100644 (file)
@@ -3215,6 +3215,7 @@ bool hfi1_tid_rdma_wqe_interlock(struct rvt_qp *qp, struct rvt_swqe *wqe)
        case IB_WR_ATOMIC_CMP_AND_SWP:
        case IB_WR_ATOMIC_FETCH_AND_ADD:
        case IB_WR_RDMA_WRITE:
+       case IB_WR_RDMA_WRITE_WITH_IMM:
                switch (prev->wr.opcode) {
                case IB_WR_TID_RDMA_WRITE:
                        req = wqe_to_tid_req(prev);
index da9888d..6edcbdc 100644 (file)
@@ -65,8 +65,6 @@
 #define HNS_ROCE_CQE_WCMD_EMPTY_BIT            0x2
 #define HNS_ROCE_MIN_CQE_CNT                   16
 
-#define HNS_ROCE_RESERVED_SGE                  1
-
 #define HNS_ROCE_MAX_IRQ_NUM                   128
 
 #define HNS_ROCE_SGE_IN_WQE                    2
index 07b4c85..aeb3a6f 100644 (file)
@@ -535,7 +535,7 @@ static void hns_roce_set_sdb_ext(struct hns_roce_dev *hr_dev, u32 ext_sdb_alept,
        roce_write(hr_dev, ROCEE_EXT_DB_SQ_H_REG, val);
 
        dev_dbg(dev, "ext SDB depth: 0x%x\n", db->ext_db->esdb_dep);
-       dev_dbg(dev, "ext SDB threshold: epmty: 0x%x, ful: 0x%x\n",
+       dev_dbg(dev, "ext SDB threshold: empty: 0x%x, ful: 0x%x\n",
                ext_sdb_alept, ext_sdb_alful);
 }
 
index d296859..4cda95e 100644 (file)
@@ -633,7 +633,7 @@ static int hns_roce_v2_post_recv(struct ib_qp *ibqp,
 
                wqe_idx = (hr_qp->rq.head + nreq) & (hr_qp->rq.wqe_cnt - 1);
 
-               if (unlikely(wr->num_sge >= hr_qp->rq.max_gs)) {
+               if (unlikely(wr->num_sge > hr_qp->rq.max_gs)) {
                        ibdev_err(ibdev, "rq:num_sge=%d >= qp->sq.max_gs=%d\n",
                                  wr->num_sge, hr_qp->rq.max_gs);
                        ret = -EINVAL;
@@ -653,7 +653,6 @@ static int hns_roce_v2_post_recv(struct ib_qp *ibqp,
                if (wr->num_sge < hr_qp->rq.max_gs) {
                        dseg->lkey = cpu_to_le32(HNS_ROCE_INVALID_LKEY);
                        dseg->addr = 0;
-                       dseg->len = cpu_to_le32(HNS_ROCE_INVALID_SGE_LENGTH);
                }
 
                /* rq support inline data */
@@ -787,8 +786,8 @@ static int hns_roce_v2_post_srq_recv(struct ib_srq *ibsrq,
                }
 
                if (wr->num_sge < srq->max_gs) {
-                       dseg[i].len = cpu_to_le32(HNS_ROCE_INVALID_SGE_LENGTH);
-                       dseg[i].lkey = cpu_to_le32(HNS_ROCE_INVALID_LKEY);
+                       dseg[i].len = 0;
+                       dseg[i].lkey = cpu_to_le32(0x100);
                        dseg[i].addr = 0;
                }
 
@@ -5070,7 +5069,7 @@ static int hns_roce_v2_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr)
 
        attr->srq_limit = limit_wl;
        attr->max_wr = srq->wqe_cnt - 1;
-       attr->max_sge = srq->max_gs - HNS_ROCE_RESERVED_SGE;
+       attr->max_sge = srq->max_gs;
 
 out:
        hns_roce_free_cmd_mailbox(hr_dev, mailbox);
index 1fb1c58..ac29be4 100644 (file)
@@ -92,9 +92,7 @@
 #define HNS_ROCE_V2_CQC_TIMER_ENTRY_SZ         PAGE_SIZE
 #define HNS_ROCE_V2_PAGE_SIZE_SUPPORTED                0xFFFFF000
 #define HNS_ROCE_V2_MAX_INNER_MTPT_NUM         2
-#define HNS_ROCE_INVALID_LKEY                  0x0
-#define HNS_ROCE_INVALID_SGE_LENGTH            0x80000000
-
+#define HNS_ROCE_INVALID_LKEY                  0x100
 #define HNS_ROCE_CMQ_TX_TIMEOUT                        30000
 #define HNS_ROCE_V2_UC_RC_SGE_NUM_IN_WQE       2
 #define HNS_ROCE_V2_RSV_QPS                    8
index e94ca13..c063c45 100644 (file)
@@ -386,8 +386,7 @@ static int set_rq_size(struct hns_roce_dev *hr_dev, struct ib_qp_cap *cap,
                return -EINVAL;
        }
 
-       hr_qp->rq.max_gs = roundup_pow_of_two(max(1U, cap->max_recv_sge) +
-                                             HNS_ROCE_RESERVED_SGE);
+       hr_qp->rq.max_gs = roundup_pow_of_two(max(1U, cap->max_recv_sge));
 
        if (hr_dev->caps.max_rq_sg <= HNS_ROCE_SGE_IN_WQE)
                hr_qp->rq.wqe_shift = ilog2(hr_dev->caps.max_rq_desc_sz);
@@ -402,7 +401,7 @@ static int set_rq_size(struct hns_roce_dev *hr_dev, struct ib_qp_cap *cap,
                hr_qp->rq_inl_buf.wqe_cnt = 0;
 
        cap->max_recv_wr = cnt;
-       cap->max_recv_sge = hr_qp->rq.max_gs - HNS_ROCE_RESERVED_SGE;
+       cap->max_recv_sge = hr_qp->rq.max_gs;
 
        return 0;
 }
index f40a000..b9e2dbd 100644 (file)
@@ -297,7 +297,7 @@ int hns_roce_create_srq(struct ib_srq *ib_srq,
        spin_lock_init(&srq->lock);
 
        srq->wqe_cnt = roundup_pow_of_two(init_attr->attr.max_wr + 1);
-       srq->max_gs = init_attr->attr.max_sge + HNS_ROCE_RESERVED_SGE;
+       srq->max_gs = init_attr->attr.max_sge;
 
        if (udata) {
                ret = ib_copy_from_udata(&ucmd, udata, sizeof(ucmd));
index c9abe1c..662e7fc 100644 (file)
@@ -120,7 +120,7 @@ static void usnic_ib_qp_grp_modify_active_to_err(struct usnic_ib_dev *us_ibdev)
                                                                IB_QPS_ERR,
                                                                NULL);
                                if (status) {
-                                       usnic_err("Failed to transistion qp grp %u from %s to %s\n",
+                                       usnic_err("Failed to transition qp grp %u from %s to %s\n",
                                                qp_grp->grp_id,
                                                usnic_ib_qp_grp_state_to_string
                                                (cur_state),
index 4959f5d..5141d49 100644 (file)
@@ -1035,8 +1035,8 @@ static void *iommu_dma_alloc(struct device *dev, size_t size,
 
        if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
            !gfpflags_allow_blocking(gfp) && !coherent)
-               cpu_addr = dma_alloc_from_pool(dev, PAGE_ALIGN(size), &page,
-                                              gfp);
+               page = dma_alloc_from_pool(dev, PAGE_ALIGN(size), &cpu_addr,
+                                              gfp, NULL);
        else
                cpu_addr = iommu_dma_alloc_pages(dev, size, &page, gfp, attrs);
        if (!cpu_addr)
index 6500179..0837ae0 100644 (file)
@@ -1554,6 +1554,8 @@ static int b53_arl_op(struct b53_device *dev, int op, int port,
                return ret;
 
        switch (ret) {
+       case -ETIMEDOUT:
+               return ret;
        case -ENOSPC:
                dev_dbg(dev->dev, "{%pM,%.4d} no space left in ARL\n",
                        addr, vid);
index 8dcb8a4..4b4701c 100644 (file)
@@ -1326,14 +1326,17 @@ mt7530_setup(struct dsa_switch *ds)
 
                        if (phy_node->parent == priv->dev->of_node->parent) {
                                ret = of_get_phy_mode(mac_np, &interface);
-                               if (ret && ret != -ENODEV)
+                               if (ret && ret != -ENODEV) {
+                                       of_node_put(mac_np);
                                        return ret;
+                               }
                                id = of_mdio_parse_addr(ds->dev, phy_node);
                                if (id == 0)
                                        priv->p5_intf_sel = P5_INTF_SEL_PHY_P0;
                                if (id == 4)
                                        priv->p5_intf_sel = P5_INTF_SEL_PHY_P4;
                        }
+                       of_node_put(mac_np);
                        of_node_put(phy_node);
                        break;
                }
index c69d959..04bfa6e 100644 (file)
@@ -400,6 +400,7 @@ static int felix_parse_ports_node(struct felix *felix,
                if (err < 0) {
                        dev_err(dev, "Unsupported PHY mode %s on port %d\n",
                                phy_modes(phy_mode), port);
+                       of_node_put(child);
                        return err;
                }
 
index c3f6f12..5a28dfb 100644 (file)
@@ -3415,7 +3415,7 @@ static int sja1105_check_device_id(struct sja1105_private *priv)
 
        sja1105_unpack(prod_id, &part_no, 19, 4, SJA1105_SIZE_DEVICE_ID);
 
-       for (match = sja1105_dt_ids; match->compatible; match++) {
+       for (match = sja1105_dt_ids; match->compatible[0]; match++) {
                const struct sja1105_info *info = match->data;
 
                /* Is what's been probed in our match table at all? */
index 0187dbf..54cdafd 100644 (file)
@@ -153,6 +153,7 @@ int arc_mdio_probe(struct arc_emac_priv *priv)
        if (IS_ERR(data->reset_gpio)) {
                error = PTR_ERR(data->reset_gpio);
                dev_err(priv->dev, "Failed to request gpio: %d\n", error);
+               mdiobus_free(bus);
                return error;
        }
 
index dfed9ad..0762d5d 100644 (file)
@@ -2491,8 +2491,10 @@ static int bcm_sysport_probe(struct platform_device *pdev)
        priv->tx_rings = devm_kcalloc(&pdev->dev, txq,
                                      sizeof(struct bcm_sysport_tx_ring),
                                      GFP_KERNEL);
-       if (!priv->tx_rings)
-               return -ENOMEM;
+       if (!priv->tx_rings) {
+               ret = -ENOMEM;
+               goto err_free_netdev;
+       }
 
        priv->is_lite = params->is_lite;
        priv->num_rx_desc_words = params->num_rx_desc_words;
index 31fb5a2..57d0e19 100644 (file)
@@ -1141,6 +1141,9 @@ static int bnxt_discard_rx(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
 
 static void bnxt_queue_fw_reset_work(struct bnxt *bp, unsigned long delay)
 {
+       if (!(test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)))
+               return;
+
        if (BNXT_PF(bp))
                queue_delayed_work(bnxt_pf_wq, &bp->fw_reset_task, delay);
        else
@@ -1157,10 +1160,12 @@ static void bnxt_queue_sp_work(struct bnxt *bp)
 
 static void bnxt_cancel_sp_work(struct bnxt *bp)
 {
-       if (BNXT_PF(bp))
+       if (BNXT_PF(bp)) {
                flush_workqueue(bnxt_pf_wq);
-       else
+       } else {
                cancel_work_sync(&bp->sp_task);
+               cancel_delayed_work_sync(&bp->fw_reset_task);
+       }
 }
 
 static void bnxt_sched_reset(struct bnxt *bp, struct bnxt_rx_ring_info *rxr)
@@ -6102,6 +6107,21 @@ static int bnxt_get_func_stat_ctxs(struct bnxt *bp)
        return cp + ulp_stat;
 }
 
+/* Check if a default RSS map needs to be setup.  This function is only
+ * used on older firmware that does not require reserving RX rings.
+ */
+static void bnxt_check_rss_tbl_no_rmgr(struct bnxt *bp)
+{
+       struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
+
+       /* The RSS map is valid for RX rings set to resv_rx_rings */
+       if (hw_resc->resv_rx_rings != bp->rx_nr_rings) {
+               hw_resc->resv_rx_rings = bp->rx_nr_rings;
+               if (!netif_is_rxfh_configured(bp->dev))
+                       bnxt_set_dflt_rss_indir_tbl(bp);
+       }
+}
+
 static bool bnxt_need_reserve_rings(struct bnxt *bp)
 {
        struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
@@ -6110,22 +6130,28 @@ static bool bnxt_need_reserve_rings(struct bnxt *bp)
        int rx = bp->rx_nr_rings, stat;
        int vnic = 1, grp = rx;
 
-       if (bp->hwrm_spec_code < 0x10601)
-               return false;
-
-       if (hw_resc->resv_tx_rings != bp->tx_nr_rings)
+       if (hw_resc->resv_tx_rings != bp->tx_nr_rings &&
+           bp->hwrm_spec_code >= 0x10601)
                return true;
 
+       /* Old firmware does not need RX ring reservations but we still
+        * need to setup a default RSS map when needed.  With new firmware
+        * we go through RX ring reservations first and then set up the
+        * RSS map for the successfully reserved RX rings when needed.
+        */
+       if (!BNXT_NEW_RM(bp)) {
+               bnxt_check_rss_tbl_no_rmgr(bp);
+               return false;
+       }
        if ((bp->flags & BNXT_FLAG_RFS) && !(bp->flags & BNXT_FLAG_CHIP_P5))
                vnic = rx + 1;
        if (bp->flags & BNXT_FLAG_AGG_RINGS)
                rx <<= 1;
        stat = bnxt_get_func_stat_ctxs(bp);
-       if (BNXT_NEW_RM(bp) &&
-           (hw_resc->resv_rx_rings != rx || hw_resc->resv_cp_rings != cp ||
-            hw_resc->resv_vnics != vnic || hw_resc->resv_stat_ctxs != stat ||
-            (hw_resc->resv_hw_ring_grps != grp &&
-             !(bp->flags & BNXT_FLAG_CHIP_P5))))
+       if (hw_resc->resv_rx_rings != rx || hw_resc->resv_cp_rings != cp ||
+           hw_resc->resv_vnics != vnic || hw_resc->resv_stat_ctxs != stat ||
+           (hw_resc->resv_hw_ring_grps != grp &&
+            !(bp->flags & BNXT_FLAG_CHIP_P5)))
                return true;
        if ((bp->flags & BNXT_FLAG_CHIP_P5) && BNXT_PF(bp) &&
            hw_resc->resv_irqs != nq)
@@ -6214,6 +6240,9 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
        if (!tx || !rx || !cp || !grp || !vnic || !stat)
                return -ENOMEM;
 
+       if (!netif_is_rxfh_configured(bp->dev))
+               bnxt_set_dflt_rss_indir_tbl(bp);
+
        return rc;
 }
 
@@ -8495,9 +8524,6 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
                        rc = bnxt_init_int_mode(bp);
                bnxt_ulp_irq_restart(bp, rc);
        }
-       if (!netif_is_rxfh_configured(bp->dev))
-               bnxt_set_dflt_rss_indir_tbl(bp);
-
        if (rc) {
                netdev_err(bp->dev, "ring reservation/IRQ init failure rc: %d\n", rc);
                return rc;
@@ -9284,16 +9310,19 @@ static ssize_t bnxt_show_temp(struct device *dev,
        struct hwrm_temp_monitor_query_input req = {0};
        struct hwrm_temp_monitor_query_output *resp;
        struct bnxt *bp = dev_get_drvdata(dev);
-       u32 temp = 0;
+       u32 len = 0;
 
        resp = bp->hwrm_cmd_resp_addr;
        bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_TEMP_MONITOR_QUERY, -1, -1);
        mutex_lock(&bp->hwrm_cmd_lock);
-       if (!_hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT))
-               temp = resp->temp * 1000; /* display millidegree */
+       if (!_hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT))
+               len = sprintf(buf, "%u\n", resp->temp * 1000); /* display millidegree */
        mutex_unlock(&bp->hwrm_cmd_lock);
 
-       return sprintf(buf, "%u\n", temp);
+       if (len)
+               return len;
+
+       return sprintf(buf, "unknown\n");
 }
 static SENSOR_DEVICE_ATTR(temp1_input, 0444, bnxt_show_temp, NULL, 0);
 
@@ -9475,15 +9504,15 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
                }
        }
 
-       bnxt_enable_napi(bp);
-       bnxt_debug_dev_init(bp);
-
        rc = bnxt_init_nic(bp, irq_re_init);
        if (rc) {
                netdev_err(bp->dev, "bnxt_init_nic err: %x\n", rc);
-               goto open_err;
+               goto open_err_irq;
        }
 
+       bnxt_enable_napi(bp);
+       bnxt_debug_dev_init(bp);
+
        if (link_re_init) {
                mutex_lock(&bp->link_lock);
                rc = bnxt_update_phy_setting(bp);
@@ -9514,10 +9543,6 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
                bnxt_vf_reps_open(bp);
        return 0;
 
-open_err:
-       bnxt_debug_dev_exit(bp);
-       bnxt_disable_napi(bp);
-
 open_err_irq:
        bnxt_del_napi(bp);
 
@@ -11761,6 +11786,7 @@ static void bnxt_remove_one(struct pci_dev *pdev)
        unregister_netdev(dev);
        bnxt_dl_unregister(bp);
        bnxt_shutdown_tc(bp);
+       clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
        bnxt_cancel_sp_work(bp);
        bp->sp_event = 0;
 
@@ -12200,6 +12226,10 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (BNXT_CHIP_P5(bp))
                bp->flags |= BNXT_FLAG_CHIP_P5;
 
+       rc = bnxt_alloc_rss_indir_tbl(bp);
+       if (rc)
+               goto init_err_pci_clean;
+
        rc = bnxt_fw_init_one_p2(bp);
        if (rc)
                goto init_err_pci_clean;
@@ -12304,11 +12334,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
         */
        bp->tx_nr_rings_per_tc = bp->tx_nr_rings;
 
-       rc = bnxt_alloc_rss_indir_tbl(bp);
-       if (rc)
-               goto init_err_pci_clean;
-       bnxt_set_dflt_rss_indir_tbl(bp);
-
        if (BNXT_PF(bp)) {
                if (!bnxt_pf_wq) {
                        bnxt_pf_wq =
@@ -12339,6 +12364,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                    (long)pci_resource_start(pdev, 0), dev->dev_addr);
        pcie_print_link_status(pdev);
 
+       pci_save_state(pdev);
        return 0;
 
 init_err_cleanup:
@@ -12536,6 +12562,8 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev)
                        "Cannot re-enable PCI device after reset.\n");
        } else {
                pci_set_master(pdev);
+               pci_restore_state(pdev);
+               pci_save_state(pdev);
 
                err = bnxt_hwrm_func_reset(bp);
                if (!err) {
index 64da654..1bc5130 100644 (file)
@@ -472,20 +472,13 @@ static int bnxt_get_num_tpa_ring_stats(struct bnxt *bp)
 static int bnxt_get_num_ring_stats(struct bnxt *bp)
 {
        int rx, tx, cmn;
-       bool sh = false;
-
-       if (bp->flags & BNXT_FLAG_SHARED_RINGS)
-               sh = true;
 
        rx = NUM_RING_RX_HW_STATS + NUM_RING_RX_SW_STATS +
             bnxt_get_num_tpa_ring_stats(bp);
        tx = NUM_RING_TX_HW_STATS;
        cmn = NUM_RING_CMN_SW_STATS;
-       if (sh)
-               return (rx + tx + cmn) * bp->cp_nr_rings;
-       else
-               return rx * bp->rx_nr_rings + tx * bp->tx_nr_rings +
-                      cmn * bp->cp_nr_rings;
+       return rx * bp->rx_nr_rings + tx * bp->tx_nr_rings +
+              cmn * bp->cp_nr_rings;
 }
 
 static int bnxt_get_num_stats(struct bnxt *bp)
@@ -806,7 +799,7 @@ static void bnxt_get_channels(struct net_device *dev,
        int max_tx_sch_inputs;
 
        /* Get the most up-to-date max_tx_sch_inputs. */
-       if (BNXT_NEW_RM(bp))
+       if (netif_running(dev) && BNXT_NEW_RM(bp))
                bnxt_hwrm_func_resc_qcaps(bp, false);
        max_tx_sch_inputs = hw_resc->max_tx_sch_inputs;
 
@@ -2323,6 +2316,9 @@ static int bnxt_get_nvram_directory(struct net_device *dev, u32 len, u8 *data)
        if (rc != 0)
                return rc;
 
+       if (!dir_entries || !entry_length)
+               return -EIO;
+
        /* Insert 2 bytes of directory info (count and size of entries) */
        if (len < 2)
                return -EINVAL;
index 23f278e..22522f8 100644 (file)
@@ -2282,8 +2282,10 @@ static int hns_nic_dev_probe(struct platform_device *pdev)
                        priv->enet_ver = AE_VERSION_1;
                else if (acpi_dev_found(hns_enet_acpi_match[1].id))
                        priv->enet_ver = AE_VERSION_2;
-               else
-                       return -ENXIO;
+               else {
+                       ret = -ENXIO;
+                       goto out_read_prop_fail;
+               }
 
                /* try to find port-idx-in-ae first */
                ret = acpi_node_get_property_reference(dev->fwnode,
@@ -2299,7 +2301,8 @@ static int hns_nic_dev_probe(struct platform_device *pdev)
                priv->fwnode = args.fwnode;
        } else {
                dev_err(dev, "cannot read cfg data from OF or acpi\n");
-               return -ENXIO;
+               ret = -ENXIO;
+               goto out_read_prop_fail;
        }
 
        ret = device_property_read_u32(dev, "port-idx-in-ae", &port_id);
index 87776ce..7d83c45 100644 (file)
@@ -21,6 +21,7 @@
 #include <net/pkt_cls.h>
 #include <net/tcp.h>
 #include <net/vxlan.h>
+#include <net/geneve.h>
 
 #include "hnae3.h"
 #include "hns3_enet.h"
@@ -780,7 +781,7 @@ static int hns3_get_l4_protocol(struct sk_buff *skb, u8 *ol4_proto,
  * and it is udp packet, which has a dest port as the IANA assigned.
  * the hardware is expected to do the checksum offload, but the
  * hardware will not do the checksum offload when udp dest port is
- * 4789.
+ * 4789 or 6081.
  */
 static bool hns3_tunnel_csum_bug(struct sk_buff *skb)
 {
@@ -789,7 +790,8 @@ static bool hns3_tunnel_csum_bug(struct sk_buff *skb)
        l4.hdr = skb_transport_header(skb);
 
        if (!(!skb->encapsulation &&
-             l4.udp->dest == htons(IANA_VXLAN_UDP_PORT)))
+             (l4.udp->dest == htons(IANA_VXLAN_UDP_PORT) ||
+             l4.udp->dest == htons(GENEVE_UDP_PORT))))
                return false;
 
        skb_checksum_help(skb);
index 5afb3c9..d3a7743 100644 (file)
@@ -479,6 +479,9 @@ static int reset_rx_pools(struct ibmvnic_adapter *adapter)
        int i, j, rc;
        u64 *size_array;
 
+       if (!adapter->rx_pool)
+               return -1;
+
        size_array = (u64 *)((u8 *)(adapter->login_rsp_buf) +
                be32_to_cpu(adapter->login_rsp_buf->off_rxadd_buff_size));
 
@@ -649,6 +652,9 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter)
        int tx_scrqs;
        int i, rc;
 
+       if (!adapter->tx_pool)
+               return -1;
+
        tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
        for (i = 0; i < tx_scrqs; i++) {
                rc = reset_one_tx_pool(adapter, &adapter->tso_pool[i]);
@@ -2011,7 +2017,10 @@ static int do_reset(struct ibmvnic_adapter *adapter,
                    adapter->req_rx_add_entries_per_subcrq !=
                    old_num_rx_slots ||
                    adapter->req_tx_entries_per_subcrq !=
-                   old_num_tx_slots) {
+                   old_num_tx_slots ||
+                   !adapter->rx_pool ||
+                   !adapter->tso_pool ||
+                   !adapter->tx_pool) {
                        release_rx_pools(adapter);
                        release_tx_pools(adapter);
                        release_napi(adapter);
@@ -2024,10 +2033,14 @@ static int do_reset(struct ibmvnic_adapter *adapter,
                } else {
                        rc = reset_tx_pools(adapter);
                        if (rc)
+                               netdev_dbg(adapter->netdev, "reset tx pools failed (%d)\n",
+                                               rc);
                                goto out;
 
                        rc = reset_rx_pools(adapter);
                        if (rc)
+                               netdev_dbg(adapter->netdev, "reset rx pools failed (%d)\n",
+                                               rc);
                                goto out;
                }
                ibmvnic_disable_irqs(adapter);
index e67b1a5..0fcd820 100644 (file)
@@ -193,7 +193,7 @@ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid,
        }
 
        /* alloc the udl from per cpu ddp pool */
-       ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_KERNEL, &ddp->udp);
+       ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_ATOMIC, &ddp->udp);
        if (!ddp->udl) {
                e_err(drv, "failed allocated ddp context\n");
                goto out_noddp_unmap;
index 99f7aae..df89d09 100644 (file)
@@ -1342,6 +1342,51 @@ static inline int ravb_hook_irq(unsigned int irq, irq_handler_t handler,
        return error;
 }
 
+/* MDIO bus init function */
+static int ravb_mdio_init(struct ravb_private *priv)
+{
+       struct platform_device *pdev = priv->pdev;
+       struct device *dev = &pdev->dev;
+       int error;
+
+       /* Bitbang init */
+       priv->mdiobb.ops = &bb_ops;
+
+       /* MII controller setting */
+       priv->mii_bus = alloc_mdio_bitbang(&priv->mdiobb);
+       if (!priv->mii_bus)
+               return -ENOMEM;
+
+       /* Hook up MII support for ethtool */
+       priv->mii_bus->name = "ravb_mii";
+       priv->mii_bus->parent = dev;
+       snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+                pdev->name, pdev->id);
+
+       /* Register MDIO bus */
+       error = of_mdiobus_register(priv->mii_bus, dev->of_node);
+       if (error)
+               goto out_free_bus;
+
+       return 0;
+
+out_free_bus:
+       free_mdio_bitbang(priv->mii_bus);
+       return error;
+}
+
+/* MDIO bus release function */
+static int ravb_mdio_release(struct ravb_private *priv)
+{
+       /* Unregister mdio bus */
+       mdiobus_unregister(priv->mii_bus);
+
+       /* Free bitbang info */
+       free_mdio_bitbang(priv->mii_bus);
+
+       return 0;
+}
+
 /* Network device open function for Ethernet AVB */
 static int ravb_open(struct net_device *ndev)
 {
@@ -1350,6 +1395,13 @@ static int ravb_open(struct net_device *ndev)
        struct device *dev = &pdev->dev;
        int error;
 
+       /* MDIO bus init */
+       error = ravb_mdio_init(priv);
+       if (error) {
+               netdev_err(ndev, "failed to initialize MDIO\n");
+               return error;
+       }
+
        napi_enable(&priv->napi[RAVB_BE]);
        napi_enable(&priv->napi[RAVB_NC]);
 
@@ -1427,6 +1479,7 @@ out_free_irq:
 out_napi_off:
        napi_disable(&priv->napi[RAVB_NC]);
        napi_disable(&priv->napi[RAVB_BE]);
+       ravb_mdio_release(priv);
        return error;
 }
 
@@ -1736,6 +1789,8 @@ static int ravb_close(struct net_device *ndev)
        ravb_ring_free(ndev, RAVB_BE);
        ravb_ring_free(ndev, RAVB_NC);
 
+       ravb_mdio_release(priv);
+
        return 0;
 }
 
@@ -1887,51 +1942,6 @@ static const struct net_device_ops ravb_netdev_ops = {
        .ndo_set_features       = ravb_set_features,
 };
 
-/* MDIO bus init function */
-static int ravb_mdio_init(struct ravb_private *priv)
-{
-       struct platform_device *pdev = priv->pdev;
-       struct device *dev = &pdev->dev;
-       int error;
-
-       /* Bitbang init */
-       priv->mdiobb.ops = &bb_ops;
-
-       /* MII controller setting */
-       priv->mii_bus = alloc_mdio_bitbang(&priv->mdiobb);
-       if (!priv->mii_bus)
-               return -ENOMEM;
-
-       /* Hook up MII support for ethtool */
-       priv->mii_bus->name = "ravb_mii";
-       priv->mii_bus->parent = dev;
-       snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
-                pdev->name, pdev->id);
-
-       /* Register MDIO bus */
-       error = of_mdiobus_register(priv->mii_bus, dev->of_node);
-       if (error)
-               goto out_free_bus;
-
-       return 0;
-
-out_free_bus:
-       free_mdio_bitbang(priv->mii_bus);
-       return error;
-}
-
-/* MDIO bus release function */
-static int ravb_mdio_release(struct ravb_private *priv)
-{
-       /* Unregister mdio bus */
-       mdiobus_unregister(priv->mii_bus);
-
-       /* Free bitbang info */
-       free_mdio_bitbang(priv->mii_bus);
-
-       return 0;
-}
-
 static const struct of_device_id ravb_match_table[] = {
        { .compatible = "renesas,etheravb-r8a7790", .data = (void *)RCAR_GEN2 },
        { .compatible = "renesas,etheravb-r8a7794", .data = (void *)RCAR_GEN2 },
@@ -2174,13 +2184,6 @@ static int ravb_probe(struct platform_device *pdev)
                eth_hw_addr_random(ndev);
        }
 
-       /* MDIO bus init */
-       error = ravb_mdio_init(priv);
-       if (error) {
-               dev_err(&pdev->dev, "failed to initialize MDIO\n");
-               goto out_dma_free;
-       }
-
        netif_napi_add(ndev, &priv->napi[RAVB_BE], ravb_poll, 64);
        netif_napi_add(ndev, &priv->napi[RAVB_NC], ravb_poll, 64);
 
@@ -2202,8 +2205,6 @@ static int ravb_probe(struct platform_device *pdev)
 out_napi_del:
        netif_napi_del(&priv->napi[RAVB_NC]);
        netif_napi_del(&priv->napi[RAVB_BE]);
-       ravb_mdio_release(priv);
-out_dma_free:
        dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
                          priv->desc_bat_dma);
 
@@ -2235,7 +2236,6 @@ static int ravb_remove(struct platform_device *pdev)
        unregister_netdev(ndev);
        netif_napi_del(&priv->napi[RAVB_NC]);
        netif_napi_del(&priv->napi[RAVB_BE]);
-       ravb_mdio_release(priv);
        pm_runtime_disable(&pdev->dev);
        free_netdev(ndev);
        platform_set_drvdata(pdev, NULL);
index 9729983..c54b7f8 100644 (file)
@@ -142,7 +142,7 @@ static int ef100_pci_parse_continue_entry(struct efx_nic *efx, int entry_locatio
 
                /* Temporarily map new BAR. */
                rc = efx_init_io(efx, bar,
-                                DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
+                                (dma_addr_t)DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
                                 pci_resource_len(efx->pci_dev, bar));
                if (rc) {
                        netif_err(efx, probe, efx->net_dev,
@@ -160,7 +160,7 @@ static int ef100_pci_parse_continue_entry(struct efx_nic *efx, int entry_locatio
 
                /* Put old BAR back. */
                rc = efx_init_io(efx, previous_bar,
-                                DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
+                                (dma_addr_t)DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
                                 pci_resource_len(efx->pci_dev, previous_bar));
                if (rc) {
                        netif_err(efx, probe, efx->net_dev,
@@ -334,7 +334,7 @@ static int ef100_pci_parse_xilinx_cap(struct efx_nic *efx, int vndr_cap,
 
        /* Temporarily map BAR. */
        rc = efx_init_io(efx, bar,
-                        DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
+                        (dma_addr_t)DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
                         pci_resource_len(efx->pci_dev, bar));
        if (rc) {
                netif_err(efx, probe, efx->net_dev,
@@ -495,7 +495,7 @@ static int ef100_pci_probe(struct pci_dev *pci_dev,
 
        /* Set up basic I/O (BAR mappings etc) */
        rc = efx_init_io(efx, fcw.bar,
-                        DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
+                        (dma_addr_t)DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
                         pci_resource_len(efx->pci_dev, fcw.bar));
        if (rc)
                goto fail;
index 012925e..85207ac 100644 (file)
@@ -36,7 +36,7 @@ bool ef100_rx_buf_hash_valid(const u8 *prefix)
        return PREFIX_FIELD(prefix, RSS_HASH_VALID);
 }
 
-static bool check_fcs(struct efx_channel *channel, u32 *prefix)
+static bool ef100_has_fcs_error(struct efx_channel *channel, u32 *prefix)
 {
        u16 rxclass;
        u8 l2status;
@@ -46,11 +46,11 @@ static bool check_fcs(struct efx_channel *channel, u32 *prefix)
 
        if (likely(l2status == ESE_GZ_RH_HCLASS_L2_STATUS_OK))
                /* Everything is ok */
-               return 0;
+               return false;
 
        if (l2status == ESE_GZ_RH_HCLASS_L2_STATUS_FCS_ERR)
                channel->n_rx_eth_crc_err++;
-       return 1;
+       return true;
 }
 
 void __ef100_rx_packet(struct efx_channel *channel)
@@ -63,7 +63,7 @@ void __ef100_rx_packet(struct efx_channel *channel)
 
        prefix = (u32 *)(eh - ESE_GZ_RX_PKT_PREFIX_LEN);
 
-       if (check_fcs(channel, prefix) &&
+       if (ef100_has_fcs_error(channel, prefix) &&
            unlikely(!(efx->net_dev->features & NETIF_F_RXALL)))
                goto out;
 
index 9b17bbb..4a65edc 100644 (file)
@@ -1116,7 +1116,7 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
                                  HOST_PORT_NUM, ALE_VLAN, vid);
        ret |= cpsw_ale_del_mcast(cpsw->ale, priv->ndev->broadcast,
                                  0, ALE_VLAN, vid);
-       ret |= cpsw_ale_flush_multicast(cpsw->ale, 0, vid);
+       ret |= cpsw_ale_flush_multicast(cpsw->ale, ALE_PORT_HOST, vid);
 err:
        pm_runtime_put(cpsw->dev);
        return ret;
index 1247d35..8ed7857 100644 (file)
@@ -1032,19 +1032,34 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
                return ret;
        }
 
+       /* reset the return code as pm_runtime_get_sync() can return
+        * non zero values as well.
+        */
+       ret = 0;
        for (i = 0; i < cpsw->data.slaves; i++) {
                if (cpsw->slaves[i].ndev &&
-                   vid == cpsw->slaves[i].port_vlan)
+                   vid == cpsw->slaves[i].port_vlan) {
+                       ret = -EINVAL;
                        goto err;
+               }
        }
 
        dev_dbg(priv->dev, "removing vlanid %d from vlan filter\n", vid);
-       cpsw_ale_del_vlan(cpsw->ale, vid, 0);
-       cpsw_ale_del_ucast(cpsw->ale, priv->mac_addr,
-                          HOST_PORT_NUM, ALE_VLAN, vid);
-       cpsw_ale_del_mcast(cpsw->ale, priv->ndev->broadcast,
-                          0, ALE_VLAN, vid);
-       cpsw_ale_flush_multicast(cpsw->ale, 0, vid);
+       ret = cpsw_ale_del_vlan(cpsw->ale, vid, 0);
+       if (ret)
+               dev_err(priv->dev, "cpsw_ale_del_vlan() failed: ret %d\n", ret);
+       ret = cpsw_ale_del_ucast(cpsw->ale, priv->mac_addr,
+                                HOST_PORT_NUM, ALE_VLAN, vid);
+       if (ret)
+               dev_err(priv->dev, "cpsw_ale_del_ucast() failed: ret %d\n",
+                       ret);
+       ret = cpsw_ale_del_mcast(cpsw->ale, priv->ndev->broadcast,
+                                0, ALE_VLAN, vid);
+       if (ret)
+               dev_err(priv->dev, "cpsw_ale_del_mcast failed. ret %d\n",
+                       ret);
+       cpsw_ale_flush_multicast(cpsw->ale, ALE_PORT_HOST, vid);
+       ret = 0;
 err:
        pm_runtime_put(cpsw->dev);
        return ret;
index 21640a0..8e47d01 100644 (file)
@@ -1179,6 +1179,7 @@ static int gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq,
                goto nlmsg_failure;
 
        if (nla_put_u32(skb, GTPA_VERSION, pctx->gtp_version) ||
+           nla_put_u32(skb, GTPA_LINK, pctx->dev->ifindex) ||
            nla_put_be32(skb, GTPA_PEER_ADDRESS, pctx->peer_addr_ip4.s_addr) ||
            nla_put_be32(skb, GTPA_MS_ADDRESS, pctx->ms_addr_ip4.s_addr))
                goto nla_put_failure;
index 787f17e..64b0a74 100644 (file)
@@ -367,7 +367,7 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb,
        }
        rcu_read_unlock();
 
-       while (unlikely(txq >= ndev->real_num_tx_queues))
+       while (txq >= ndev->real_num_tx_queues)
                txq -= ndev->real_num_tx_queues;
 
        return txq;
@@ -502,7 +502,7 @@ static int netvsc_vf_xmit(struct net_device *net, struct net_device *vf_netdev,
        int rc;
 
        skb->dev = vf_netdev;
-       skb->queue_mapping = qdisc_skb_cb(skb)->slave_dev_queue_mapping;
+       skb_record_rx_queue(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping);
 
        rc = dev_queue_xmit(skb);
        if (likely(rc == NET_XMIT_SUCCESS || rc == NET_XMIT_CN)) {
index 5810315..6b98d74 100644 (file)
@@ -427,18 +427,18 @@ static int dp83869_config_init(struct phy_device *phydev)
                        return ret;
 
                val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIICTL);
-               val &= ~(DP83869_RGMII_TX_CLK_DELAY_EN |
-                        DP83869_RGMII_RX_CLK_DELAY_EN);
+               val |= (DP83869_RGMII_TX_CLK_DELAY_EN |
+                       DP83869_RGMII_RX_CLK_DELAY_EN);
 
                if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
-                       val |= (DP83869_RGMII_TX_CLK_DELAY_EN |
-                               DP83869_RGMII_RX_CLK_DELAY_EN);
+                       val &= ~(DP83869_RGMII_TX_CLK_DELAY_EN |
+                                DP83869_RGMII_RX_CLK_DELAY_EN);
 
                if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
-                       val |= DP83869_RGMII_TX_CLK_DELAY_EN;
+                       val &= ~DP83869_RGMII_TX_CLK_DELAY_EN;
 
                if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
-                       val |= DP83869_RGMII_RX_CLK_DELAY_EN;
+                       val &= ~DP83869_RGMII_RX_CLK_DELAY_EN;
 
                ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIICTL,
                                    val);
index a4fbf3a..6bc7406 100644 (file)
@@ -1738,13 +1738,13 @@ static int __phy_write_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb,
        return 0;
 }
 
-/* Trigger a read to the spcified MCB */
+/* Trigger a read to the specified MCB */
 static int phy_update_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb)
 {
        return __phy_write_mcb_s6g(phydev, reg, mcb, PHY_MCB_S6G_READ);
 }
 
-/* Trigger a write to the spcified MCB */
+/* Trigger a write to the specified MCB */
 static int phy_commit_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb)
 {
        return __phy_write_mcb_s6g(phydev, reg, mcb, PHY_MCB_S6G_WRITE);
index a7fbc3c..c7bcfca 100644 (file)
@@ -252,6 +252,7 @@ config USB_NET_CDC_EEM
 config USB_NET_CDC_NCM
        tristate "CDC NCM support"
        depends on USB_USBNET
+       select USB_NET_CDCETHER
        default y
        help
          This driver provides support for CDC NCM (Network Control Model
index e39f41e..7bc6e8f 100644 (file)
@@ -296,7 +296,7 @@ int asix_read_phy_addr(struct usbnet *dev, int internal)
 
        netdev_dbg(dev->net, "asix_get_phy_addr()\n");
 
-       if (ret < 0) {
+       if (ret < 2) {
                netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret);
                goto out;
        }
index 1ea15f2..e61616b 100644 (file)
@@ -210,6 +210,8 @@ static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb)
 
        skb->dev = dev = lapbeth->ethdev;
 
+       skb_reset_network_header(skb);
+
        dev_hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
 
        dev_queue_xmit(skb);
@@ -340,6 +342,7 @@ static int lapbeth_new_device(struct net_device *dev)
         */
        ndev->needed_headroom = -1 + 3 + 2 + dev->hard_header_len
                                           + dev->needed_headroom;
+       ndev->needed_tailroom = dev->needed_tailroom;
 
        lapbeth = netdev_priv(ndev);
        lapbeth->axdev = ndev;
index 9642971..4578547 100644 (file)
@@ -966,7 +966,7 @@ static int st95hf_in_send_cmd(struct nfc_digital_dev *ddev,
        rc = down_killable(&stcontext->exchange_lock);
        if (rc) {
                WARN(1, "Semaphore is not found up in st95hf_in_send_cmd\n");
-               return rc;
+               goto free_skb_resp;
        }
 
        rc = st95hf_spi_send(&stcontext->spicontext, skb->data,
index 590493e..da4f734 100644 (file)
@@ -128,15 +128,29 @@ static unsigned int of_bus_pci_get_flags(const __be32 *addr)
  * PCI bus specific translator
  */
 
+static bool of_node_is_pcie(struct device_node *np)
+{
+       bool is_pcie = of_node_name_eq(np, "pcie");
+
+       if (is_pcie)
+               pr_warn_once("%pOF: Missing device_type\n", np);
+
+       return is_pcie;
+}
+
 static int of_bus_pci_match(struct device_node *np)
 {
        /*
         * "pciex" is PCI Express
         * "vci" is for the /chaos bridge on 1st-gen PCI powermacs
         * "ht" is hypertransport
+        *
+        * If none of the device_type match, and that the node name is
+        * "pcie", accept the device as PCI (with a warning).
         */
        return of_node_is_type(np, "pci") || of_node_is_type(np, "pciex") ||
-               of_node_is_type(np, "vci") || of_node_is_type(np, "ht");
+               of_node_is_type(np, "vci") || of_node_is_type(np, "ht") ||
+               of_node_is_pcie(np);
 }
 
 static void of_bus_pci_count_cells(struct device_node *np,
@@ -985,6 +999,11 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
                        /* Don't error out as we'd break some existing DTs */
                        continue;
                }
+               if (range.cpu_addr == OF_BAD_ADDR) {
+                       pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n",
+                              range.bus_addr, node);
+                       continue;
+               }
                dma_offset = range.cpu_addr - range.bus_addr;
 
                /* Take lower and upper limits */
index 9d7fb45..9668ea0 100644 (file)
@@ -893,8 +893,10 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
                 * have OPP table for the device, while others don't and
                 * opp_set_rate() just needs to behave like clk_set_rate().
                 */
-               if (!_get_opp_count(opp_table))
-                       return 0;
+               if (!_get_opp_count(opp_table)) {
+                       ret = 0;
+                       goto put_opp_table;
+               }
 
                if (!opp_table->required_opp_tables && !opp_table->regulators &&
                    !opp_table->paths) {
@@ -905,7 +907,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 
                ret = _set_opp_bw(opp_table, NULL, dev, true);
                if (ret)
-                       return ret;
+                       goto put_opp_table;
 
                if (opp_table->regulator_enabled) {
                        regulator_disable(opp_table->regulators[0]);
@@ -932,10 +934,13 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 
        /* Return early if nothing to do */
        if (old_freq == freq) {
-               dev_dbg(dev, "%s: old/new frequencies (%lu Hz) are same, nothing to do\n",
-                       __func__, freq);
-               ret = 0;
-               goto put_opp_table;
+               if (!opp_table->required_opp_tables && !opp_table->regulators &&
+                   !opp_table->paths) {
+                       dev_dbg(dev, "%s: old/new frequencies (%lu Hz) are same, nothing to do\n",
+                               __func__, freq);
+                       ret = 0;
+                       goto put_opp_table;
+               }
        }
 
        /*
index b59f849..c9e790c 100644 (file)
@@ -83,21 +83,19 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
        struct zpci_dev *zdev = container_of(hotplug_slot, struct zpci_dev,
                                             hotplug_slot);
        struct pci_dev *pdev;
-       struct zpci_bus *zbus = zdev->zbus;
        int rc;
 
        if (!zpci_fn_configured(zdev->state))
                return -EIO;
 
-       pdev = pci_get_slot(zbus->bus, zdev->devfn);
-       if (pdev) {
-               if (pci_num_vf(pdev))
-                       return -EBUSY;
-
-               pci_stop_and_remove_bus_device_locked(pdev);
+       pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
+       if (pdev && pci_num_vf(pdev)) {
                pci_dev_put(pdev);
+               return -EBUSY;
        }
 
+       zpci_remove_device(zdev);
+
        rc = zpci_disable_device(zdev);
        if (rc)
                return rc;
index 64ebed1..f357f9a 100644 (file)
@@ -556,13 +556,14 @@ int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients,
                return -1;
 
        for (i = 0; i < num_clients; i++) {
-               if (IS_ENABLED(CONFIG_DMA_VIRT_OPS) &&
-                   clients[i]->dma_ops == &dma_virt_ops) {
+#ifdef CONFIG_DMA_VIRT_OPS
+               if (clients[i]->dma_ops == &dma_virt_ops) {
                        if (verbose)
                                dev_warn(clients[i],
                                         "cannot be used for peer-to-peer DMA because the driver makes use of dma_virt_ops\n");
                        return -1;
                }
+#endif
 
                pci_client = find_parent_pci_dev(clients[i]);
                if (!pci_client) {
@@ -842,9 +843,10 @@ static int __pci_p2pdma_map_sg(struct pci_p2pdma_pagemap *p2p_pgmap,
         * this should never happen because it will be prevented
         * by the check in pci_p2pdma_distance_many()
         */
-       if (WARN_ON_ONCE(IS_ENABLED(CONFIG_DMA_VIRT_OPS) &&
-                        dev->dma_ops == &dma_virt_ops))
+#ifdef CONFIG_DMA_VIRT_OPS
+       if (WARN_ON_ONCE(dev->dma_ops == &dma_virt_ops))
                return 0;
+#endif
 
        for_each_sg(sg, s, nents, i) {
                paddr = sg_phys(s);
index 94edbb3..aca0222 100644 (file)
@@ -677,6 +677,11 @@ static int slow_eval_known_fn(struct subchannel *sch, void *data)
                rc = css_evaluate_known_subchannel(sch, 1);
                if (rc == -EAGAIN)
                        css_schedule_eval(sch->schid);
+               /*
+                * The loop might take long time for platforms with lots of
+                * known devices. Allow scheduling here.
+                */
+               cond_resched();
        }
        return 0;
 }
index c795f22..140186f 100644 (file)
@@ -434,7 +434,7 @@ static void zfcp_fsf_req_complete(struct zfcp_fsf_req *req)
                return;
        }
 
-       del_timer(&req->timer);
+       del_timer_sync(&req->timer);
        zfcp_fsf_protstatus_eval(req);
        zfcp_fsf_fsfstatus_eval(req);
        req->handler(req);
@@ -867,7 +867,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
        req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q_free);
        req->issued = get_tod_clock();
        if (zfcp_qdio_send(qdio, &req->qdio_req)) {
-               del_timer(&req->timer);
+               del_timer_sync(&req->timer);
                /* lookup request again, list might have changed */
                zfcp_reqlist_find_rm(adapter->req_list, req_id);
                zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1");
index 91eb690..e1d7de6 100644 (file)
@@ -380,5 +380,8 @@ extern int qla24xx_soft_reset(struct qla_hw_data *);
 static inline int
 ql_mask_match(uint level)
 {
+       if (ql2xextended_error_logging == 1)
+               ql2xextended_error_logging = QL_DBG_DEFAULT1_MASK;
+
        return (level & ql2xextended_error_logging) == level;
 }
index 8c92af5..1bc090d 100644 (file)
@@ -3880,6 +3880,7 @@ struct qla_hw_data {
                uint32_t        scm_supported_f:1;
                                /* Enabled in Driver */
                uint32_t        scm_enabled:1;
+               uint32_t        max_req_queue_warned:1;
        } flags;
 
        uint16_t max_exchg;
index df670fb..de9fd7f 100644 (file)
@@ -1505,11 +1505,11 @@ qla2x00_prep_ct_fdmi_req(struct ct_sns_pkt *p, uint16_t cmd,
 static uint
 qla25xx_fdmi_port_speed_capability(struct qla_hw_data *ha)
 {
+       uint speeds = 0;
+
        if (IS_CNA_CAPABLE(ha))
                return FDMI_PORT_SPEED_10GB;
        if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) {
-               uint speeds = 0;
-
                if (ha->max_supported_speed == 2) {
                        if (ha->min_supported_speed <= 6)
                                speeds |= FDMI_PORT_SPEED_64GB;
@@ -1536,9 +1536,16 @@ qla25xx_fdmi_port_speed_capability(struct qla_hw_data *ha)
                }
                return speeds;
        }
-       if (IS_QLA2031(ha))
-               return FDMI_PORT_SPEED_16GB|FDMI_PORT_SPEED_8GB|
-                       FDMI_PORT_SPEED_4GB;
+       if (IS_QLA2031(ha)) {
+               if ((ha->pdev->subsystem_vendor == 0x103C) &&
+                   (ha->pdev->subsystem_device == 0x8002)) {
+                       speeds = FDMI_PORT_SPEED_16GB;
+               } else {
+                       speeds = FDMI_PORT_SPEED_16GB|FDMI_PORT_SPEED_8GB|
+                               FDMI_PORT_SPEED_4GB;
+               }
+               return speeds;
+       }
        if (IS_QLA25XX(ha))
                return FDMI_PORT_SPEED_8GB|FDMI_PORT_SPEED_4GB|
                        FDMI_PORT_SPEED_2GB|FDMI_PORT_SPEED_1GB;
@@ -3436,7 +3443,6 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
                        list_for_each_entry(fcport, &vha->vp_fcports, list) {
                                if ((fcport->flags & FCF_FABRIC_DEVICE) != 0) {
                                        fcport->scan_state = QLA_FCPORT_SCAN;
-                                       fcport->logout_on_delete = 0;
                                }
                        }
                        goto login_logout;
@@ -3532,10 +3538,22 @@ login_logout:
                }
 
                if (fcport->scan_state != QLA_FCPORT_FOUND) {
+                       bool do_delete = false;
+
+                       if (fcport->scan_needed &&
+                           fcport->disc_state == DSC_LOGIN_PEND) {
+                               /* Cable got disconnected after we sent
+                                * a login. Do delete to prevent timeout.
+                                */
+                               fcport->logout_on_delete = 1;
+                               do_delete = true;
+                       }
+
                        fcport->scan_needed = 0;
-                       if ((qla_dual_mode_enabled(vha) ||
-                               qla_ini_mode_enabled(vha)) &&
-                           atomic_read(&fcport->state) == FCS_ONLINE) {
+                       if (((qla_dual_mode_enabled(vha) ||
+                             qla_ini_mode_enabled(vha)) &&
+                           atomic_read(&fcport->state) == FCS_ONLINE) ||
+                               do_delete) {
                                if (fcport->loop_id != FC_NO_LOOP_ID) {
                                        if (fcport->flags & FCF_FCP2_DEVICE)
                                                fcport->logout_on_delete = 0;
@@ -3736,6 +3754,18 @@ static void qla2x00_async_gpnft_gnnft_sp_done(srb_t *sp, int res)
                unsigned long flags;
                const char *name = sp->name;
 
+               if (res == QLA_OS_TIMER_EXPIRED) {
+                       /* switch is ignoring all commands.
+                        * This might be a zone disable behavior.
+                        * This means we hit 64s timeout.
+                        * 22s GPNFT + 44s Abort = 64s
+                        */
+                       ql_dbg(ql_dbg_disc, vha, 0xffff,
+                              "%s: Switch Zone check please .\n",
+                              name);
+                       qla2x00_mark_all_devices_lost(vha);
+               }
+
                /*
                 * We are in an Interrupt context, queue up this
                 * sp for GNNFT_DONE work. This will allow all
index 27bcd34..ab5275d 100644 (file)
@@ -2024,8 +2024,8 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
                                res = DID_ERROR << 16;
                        }
                }
-               ql_dbg(ql_dbg_user, vha, 0x503f,
-                   "ELS IOCB Done -%s error hdl=%x comp_status=0x%x error subcode 1=0x%x error subcode 2=0x%x total_byte=0x%x\n",
+               ql_dbg(ql_dbg_disc, vha, 0x503f,
+                   "ELS IOCB Done -%s hdl=%x comp_status=0x%x error subcode 1=0x%x error subcode 2=0x%x total_byte=0x%x\n",
                    type, sp->handle, comp_status, fw_status[1], fw_status[2],
                    le32_to_cpu(ese->total_byte_count));
                goto els_ct_done;
index 7388343..226f142 100644 (file)
@@ -334,14 +334,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                        if (time_after(jiffies, wait_time))
                                break;
 
-                       /*
-                        * Check if it's UNLOADING, cause we cannot poll in
-                        * this case, or else a NULL pointer dereference
-                        * is triggered.
-                        */
-                       if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags)))
-                               return QLA_FUNCTION_TIMEOUT;
-
                        /* Check for pending interrupts. */
                        qla2x00_poll(ha->rsp_q_map[0]);
 
@@ -5240,7 +5232,7 @@ qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data)
        mcp->mb[8] = MSW(risc_addr);
        mcp->out_mb = MBX_8|MBX_1|MBX_0;
        mcp->in_mb = MBX_3|MBX_2|MBX_0;
-       mcp->tov = 30;
+       mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
@@ -5428,7 +5420,7 @@ qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data)
        mcp->mb[8] = MSW(risc_addr);
        mcp->out_mb = MBX_8|MBX_3|MBX_2|MBX_1|MBX_0;
        mcp->in_mb = MBX_1|MBX_0;
-       mcp->tov = 30;
+       mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
@@ -5700,7 +5692,7 @@ qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority,
        mcp->mb[9] = vha->vp_idx;
        mcp->out_mb = MBX_9|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
        mcp->in_mb = MBX_4|MBX_3|MBX_1|MBX_0;
-       mcp->tov = 30;
+       mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (mb != NULL) {
@@ -5787,7 +5779,7 @@ qla82xx_mbx_intr_enable(scsi_qla_host_t *vha)
 
        mcp->out_mb = MBX_1|MBX_0;
        mcp->in_mb = MBX_0;
-       mcp->tov = 30;
+       mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = 0;
 
        rval = qla2x00_mailbox_command(vha, mcp);
@@ -5822,7 +5814,7 @@ qla82xx_mbx_intr_disable(scsi_qla_host_t *vha)
 
        mcp->out_mb = MBX_1|MBX_0;
        mcp->in_mb = MBX_0;
-       mcp->tov = 30;
+       mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = 0;
 
        rval = qla2x00_mailbox_command(vha, mcp);
@@ -6014,7 +6006,7 @@ qla81xx_set_led_config(scsi_qla_host_t *vha, uint16_t *led_cfg)
        if (IS_QLA8031(ha))
                mcp->out_mb |= MBX_6|MBX_5|MBX_4|MBX_3;
        mcp->in_mb = MBX_0;
-       mcp->tov = 30;
+       mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = 0;
 
        rval = qla2x00_mailbox_command(vha, mcp);
@@ -6050,7 +6042,7 @@ qla81xx_get_led_config(scsi_qla_host_t *vha, uint16_t *led_cfg)
        mcp->in_mb = MBX_2|MBX_1|MBX_0;
        if (IS_QLA8031(ha))
                mcp->in_mb |= MBX_6|MBX_5|MBX_4|MBX_3;
-       mcp->tov = 30;
+       mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = 0;
 
        rval = qla2x00_mailbox_command(vha, mcp);
index fa695a4..90bbc61 100644 (file)
@@ -536,6 +536,11 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
        struct nvme_private *priv = fd->private;
        struct qla_nvme_rport *qla_rport = rport->private;
 
+       if (!priv) {
+               /* nvme association has been torn down */
+               return rval;
+       }
+
        fcport = qla_rport->fcport;
 
        if (!qpair || !fcport || (qpair && !qpair->fw_started) ||
@@ -687,7 +692,15 @@ int qla_nvme_register_hba(struct scsi_qla_host *vha)
        tmpl = &qla_nvme_fc_transport;
 
        WARN_ON(vha->nvme_local_port);
-       WARN_ON(ha->max_req_queues < 3);
+
+       if (ha->max_req_queues < 3) {
+               if (!ha->flags.max_req_queue_warned)
+                       ql_log(ql_log_info, vha, 0x2120,
+                              "%s: Disabling FC-NVME due to lack of free queue pairs (%d).\n",
+                              __func__, ha->max_req_queues);
+               ha->flags.max_req_queue_warned = 1;
+               return ret;
+       }
 
        qla_nvme_fc_transport.max_hw_queues =
            min((uint8_t)(qla_nvme_fc_transport.max_hw_queues),
index 9b59f03..8da00ba 100644 (file)
@@ -2017,6 +2017,11 @@ skip_pio:
        /* Determine queue resources */
        ha->max_req_queues = ha->max_rsp_queues = 1;
        ha->msix_count = QLA_BASE_VECTORS;
+
+       /* Check if FW supports MQ or not */
+       if (!(ha->fw_attributes & BIT_6))
+               goto mqiobase_exit;
+
        if (!ql2xmqsupport || !ql2xnvmeenable ||
            (!IS_QLA25XX(ha) && !IS_QLA81XX(ha)))
                goto mqiobase_exit;
@@ -2829,10 +2834,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        /* This may fail but that's ok */
        pci_enable_pcie_error_reporting(pdev);
 
-       /* Turn off T10-DIF when FC-NVMe is enabled */
-       if (ql2xnvmeenable)
-               ql2xenabledif = 0;
-
        ha = kzalloc(sizeof(struct qla_hw_data), GFP_KERNEL);
        if (!ha) {
                ql_log_pci(ql_log_fatal, pdev, 0x0009,
index fbb80a0..9028916 100644 (file)
@@ -1270,7 +1270,7 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess)
 
        qla24xx_chk_fcp_state(sess);
 
-       ql_dbg(ql_dbg_tgt, sess->vha, 0xe001,
+       ql_dbg(ql_dbg_disc, sess->vha, 0xe001,
            "Scheduling sess %p for deletion %8phC\n",
            sess, sess->port_name);
 
index 064ed68..139f007 100644 (file)
@@ -5490,9 +5490,11 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
                                u64 d = ktime_get_boottime_ns() - ns_from_boot;
 
                                if (kt <= d) {  /* elapsed duration >= kt */
+                                       spin_lock_irqsave(&sqp->qc_lock, iflags);
                                        sqcp->a_cmnd = NULL;
                                        atomic_dec(&devip->num_in_q);
                                        clear_bit(k, sqp->in_use_bm);
+                                       spin_unlock_irqrestore(&sqp->qc_lock, iflags);
                                        if (new_sd_dp)
                                                kfree(sd_dp);
                                        /* call scsi_done() from this thread */
index 46bb905..eafe0db 100644 (file)
@@ -38,6 +38,7 @@ static int ti_j721e_ufs_probe(struct platform_device *pdev)
        /* Select MPHY refclk frequency */
        clk = devm_clk_get(dev, NULL);
        if (IS_ERR(clk)) {
+               ret = PTR_ERR(clk);
                dev_err(dev, "Cannot claim MPHY clock.\n");
                goto clk_err;
        }
index 29cd017..1755dd6 100644 (file)
@@ -212,7 +212,7 @@ static int ufs_mtk_wait_link_state(struct ufs_hba *hba, u32 state,
        ktime_t timeout, time_checked;
        u32 val;
 
-       timeout = ktime_add_us(ktime_get(), ms_to_ktime(max_wait_ms));
+       timeout = ktime_add_ms(ktime_get(), max_wait_ms);
        do {
                time_checked = ktime_get();
                ufshcd_writel(hba, 0x20, REG_UFS_DEBUG_SEL);
index f407b13..5a95a7b 100644 (file)
@@ -44,11 +44,23 @@ static int ufs_intel_link_startup_notify(struct ufs_hba *hba,
        return err;
 }
 
+static int ufs_intel_ehl_init(struct ufs_hba *hba)
+{
+       hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8;
+       return 0;
+}
+
 static struct ufs_hba_variant_ops ufs_intel_cnl_hba_vops = {
        .name                   = "intel-pci",
        .link_startup_notify    = ufs_intel_link_startup_notify,
 };
 
+static struct ufs_hba_variant_ops ufs_intel_ehl_hba_vops = {
+       .name                   = "intel-pci",
+       .init                   = ufs_intel_ehl_init,
+       .link_startup_notify    = ufs_intel_link_startup_notify,
+};
+
 #ifdef CONFIG_PM_SLEEP
 /**
  * ufshcd_pci_suspend - suspend power management function
@@ -177,8 +189,8 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = {
 static const struct pci_device_id ufshcd_pci_tbl[] = {
        { PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { PCI_VDEVICE(INTEL, 0x9DFA), (kernel_ulong_t)&ufs_intel_cnl_hba_vops },
-       { PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_cnl_hba_vops },
-       { PCI_VDEVICE(INTEL, 0x4B43), (kernel_ulong_t)&ufs_intel_cnl_hba_vops },
+       { PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_ehl_hba_vops },
+       { PCI_VDEVICE(INTEL, 0x4B43), (kernel_ulong_t)&ufs_intel_ehl_hba_vops },
        { }     /* terminate list */
 };
 
index 3076222..da199fa 100644 (file)
@@ -1561,6 +1561,7 @@ unblock_reqs:
 int ufshcd_hold(struct ufs_hba *hba, bool async)
 {
        int rc = 0;
+       bool flush_result;
        unsigned long flags;
 
        if (!ufshcd_is_clkgating_allowed(hba))
@@ -1592,7 +1593,9 @@ start:
                                break;
                        }
                        spin_unlock_irqrestore(hba->host->host_lock, flags);
-                       flush_work(&hba->clk_gating.ungate_work);
+                       flush_result = flush_work(&hba->clk_gating.ungate_work);
+                       if (hba->clk_gating.is_suspended && !flush_result)
+                               goto out;
                        spin_lock_irqsave(hba->host->host_lock, flags);
                        goto start;
                }
@@ -5941,7 +5944,7 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
  */
 static irqreturn_t ufshcd_intr(int irq, void *__hba)
 {
-       u32 intr_status, enabled_intr_status;
+       u32 intr_status, enabled_intr_status = 0;
        irqreturn_t retval = IRQ_NONE;
        struct ufs_hba *hba = __hba;
        int retries = hba->nutrs;
@@ -5955,7 +5958,7 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
         * read, make sure we handle them by checking the interrupt status
         * again in a loop until we process all of the reqs before returning.
         */
-       do {
+       while (intr_status && retries--) {
                enabled_intr_status =
                        intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
                if (intr_status)
@@ -5964,9 +5967,9 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
                        retval |= ufshcd_sl_intr(hba, enabled_intr_status);
 
                intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
-       } while (intr_status && --retries);
+       }
 
-       if (retval == IRQ_NONE) {
+       if (enabled_intr_status && retval == IRQ_NONE) {
                dev_err(hba->dev, "%s: Unhandled interrupt 0x%08x\n",
                                        __func__, intr_status);
                ufshcd_dump_regs(hba, 0, UFSHCI_REG_SPACE_SIZE, "host_regs: ");
@@ -6434,14 +6437,8 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
                goto out;
        }
 
-       if (!(reg & (1 << tag))) {
-               dev_err(hba->dev,
-               "%s: cmd was completed, but without a notifying intr, tag = %d",
-               __func__, tag);
-       }
-
        /* Print Transfer Request of aborted task */
-       dev_err(hba->dev, "%s: Device abort task at tag %d\n", __func__, tag);
+       dev_info(hba->dev, "%s: Device abort task at tag %d\n", __func__, tag);
 
        /*
         * Print detailed info about aborted request.
@@ -6462,6 +6459,13 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
        }
        hba->req_abort_count++;
 
+       if (!(reg & (1 << tag))) {
+               dev_err(hba->dev,
+               "%s: cmd was completed, but without a notifying intr, tag = %d",
+               __func__, tag);
+               goto cleanup;
+       }
+
        /* Skip task abort in case previous aborts failed and report failure */
        if (lrbp->req_abort_skip) {
                err = -EIO;
@@ -6492,7 +6496,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
                        /* command completed already */
                        dev_err(hba->dev, "%s: cmd at tag %d successfully cleared from DB.\n",
                                __func__, tag);
-                       goto out;
+                       goto cleanup;
                } else {
                        dev_err(hba->dev,
                                "%s: no response from device. tag = %d, err %d\n",
@@ -6526,6 +6530,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
                goto out;
        }
 
+cleanup:
        scsi_dma_unmap(cmd);
 
        spin_lock_irqsave(host->host_lock, flags);
index b2ef18f..363589c 100644 (file)
@@ -520,6 +520,12 @@ enum ufshcd_quirks {
         * OCS FATAL ERROR with device error through sense data
         */
        UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR             = 1 << 10,
+
+       /*
+        * This quirk needs to be enabled if the host controller has
+        * auto-hibernate capability but it doesn't work.
+        */
+       UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8                = 1 << 11,
 };
 
 enum ufshcd_caps {
@@ -803,7 +809,8 @@ return true;
 
 static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba)
 {
-       return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT);
+       return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) &&
+               !(hba->quirks & UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8);
 }
 
 static inline bool ufshcd_is_auto_hibern8_enabled(struct ufs_hba *hba)
index c3008e4..c6ea760 100644 (file)
@@ -1017,4 +1017,7 @@ config SPI_SLAVE_SYSTEM_CONTROL
 
 endif # SPI_SLAVE
 
+config SPI_DYNAMIC
+       def_bool ACPI || OF_DYNAMIC || SPI_SLAVE
+
 endif # SPI
index 4c643df..d4b33b3 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/of_platform.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/pm_runtime.h>
 #include <linux/reset.h>
 #include <linux/spi/spi.h>
@@ -441,7 +442,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz,
 {
        u32 div, mbrdiv;
 
-       div = DIV_ROUND_UP(spi->clk_rate, speed_hz);
+       /* Ensure spi->clk_rate is even */
+       div = DIV_ROUND_UP(spi->clk_rate & ~0x1, speed_hz);
 
        /*
         * SPI framework set xfer->speed_hz to master->max_speed_hz if
@@ -467,20 +469,27 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz,
 /**
  * stm32h7_spi_prepare_fthlv - Determine FIFO threshold level
  * @spi: pointer to the spi controller data structure
+ * @xfer_len: length of the message to be transferred
  */
-static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi)
+static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi, u32 xfer_len)
 {
-       u32 fthlv, half_fifo;
+       u32 fthlv, half_fifo, packet;
 
        /* data packet should not exceed 1/2 of fifo space */
        half_fifo = (spi->fifo_size / 2);
 
+       /* data_packet should not exceed transfer length */
+       if (half_fifo > xfer_len)
+               packet = xfer_len;
+       else
+               packet = half_fifo;
+
        if (spi->cur_bpw <= 8)
-               fthlv = half_fifo;
+               fthlv = packet;
        else if (spi->cur_bpw <= 16)
-               fthlv = half_fifo / 2;
+               fthlv = packet / 2;
        else
-               fthlv = half_fifo / 4;
+               fthlv = packet / 4;
 
        /* align packet size with data registers access */
        if (spi->cur_bpw > 8)
@@ -488,6 +497,9 @@ static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi)
        else
                fthlv -= (fthlv % 4); /* multiple of 4 */
 
+       if (!fthlv)
+               fthlv = 1;
+
        return fthlv;
 }
 
@@ -966,13 +978,13 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
                if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0)))
                        stm32h7_spi_read_rxfifo(spi, false);
 
-       writel_relaxed(mask, spi->base + STM32H7_SPI_IFCR);
+       writel_relaxed(sr & mask, spi->base + STM32H7_SPI_IFCR);
 
        spin_unlock_irqrestore(&spi->lock, flags);
 
        if (end) {
-               spi_finalize_current_transfer(master);
                stm32h7_spi_disable(spi);
+               spi_finalize_current_transfer(master);
        }
 
        return IRQ_HANDLED;
@@ -1393,7 +1405,7 @@ static void stm32h7_spi_set_bpw(struct stm32_spi *spi)
        cfg1_setb |= (bpw << STM32H7_SPI_CFG1_DSIZE_SHIFT) &
                     STM32H7_SPI_CFG1_DSIZE;
 
-       spi->cur_fthlv = stm32h7_spi_prepare_fthlv(spi);
+       spi->cur_fthlv = stm32h7_spi_prepare_fthlv(spi, spi->cur_xferlen);
        fthlv = spi->cur_fthlv - 1;
 
        cfg1_clrb |= STM32H7_SPI_CFG1_FTHLV;
@@ -1585,39 +1597,33 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
        unsigned long flags;
        unsigned int comm_type;
        int nb_words, ret = 0;
+       int mbr;
 
        spin_lock_irqsave(&spi->lock, flags);
 
-       if (spi->cur_bpw != transfer->bits_per_word) {
-               spi->cur_bpw = transfer->bits_per_word;
-               spi->cfg->set_bpw(spi);
-       }
-
-       if (spi->cur_speed != transfer->speed_hz) {
-               int mbr;
+       spi->cur_xferlen = transfer->len;
 
-               /* Update spi->cur_speed with real clock speed */
-               mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz,
-                                           spi->cfg->baud_rate_div_min,
-                                           spi->cfg->baud_rate_div_max);
-               if (mbr < 0) {
-                       ret = mbr;
-                       goto out;
-               }
+       spi->cur_bpw = transfer->bits_per_word;
+       spi->cfg->set_bpw(spi);
 
-               transfer->speed_hz = spi->cur_speed;
-               stm32_spi_set_mbr(spi, mbr);
+       /* Update spi->cur_speed with real clock speed */
+       mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz,
+                                   spi->cfg->baud_rate_div_min,
+                                   spi->cfg->baud_rate_div_max);
+       if (mbr < 0) {
+               ret = mbr;
+               goto out;
        }
 
+       transfer->speed_hz = spi->cur_speed;
+       stm32_spi_set_mbr(spi, mbr);
+
        comm_type = stm32_spi_communication_type(spi_dev, transfer);
-       if (spi->cur_comm != comm_type) {
-               ret = spi->cfg->set_mode(spi, comm_type);
+       ret = spi->cfg->set_mode(spi, comm_type);
+       if (ret < 0)
+               goto out;
 
-               if (ret < 0)
-                       goto out;
-
-               spi->cur_comm = comm_type;
-       }
+       spi->cur_comm = comm_type;
 
        if (spi->cfg->set_data_idleness)
                spi->cfg->set_data_idleness(spi, transfer->len);
@@ -1635,8 +1641,6 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
                        goto out;
        }
 
-       spi->cur_xferlen = transfer->len;
-
        dev_dbg(spi->dev, "transfer communication mode set to %d\n",
                spi->cur_comm);
        dev_dbg(spi->dev,
@@ -1996,6 +2000,8 @@ static int stm32_spi_remove(struct platform_device *pdev)
 
        pm_runtime_disable(&pdev->dev);
 
+       pinctrl_pm_select_sleep_state(&pdev->dev);
+
        return 0;
 }
 
@@ -2007,13 +2013,18 @@ static int stm32_spi_runtime_suspend(struct device *dev)
 
        clk_disable_unprepare(spi->clk);
 
-       return 0;
+       return pinctrl_pm_select_sleep_state(dev);
 }
 
 static int stm32_spi_runtime_resume(struct device *dev)
 {
        struct spi_master *master = dev_get_drvdata(dev);
        struct stm32_spi *spi = spi_master_get_devdata(master);
+       int ret;
+
+       ret = pinctrl_pm_select_default_state(dev);
+       if (ret)
+               return ret;
 
        return clk_prepare_enable(spi->clk);
 }
@@ -2043,10 +2054,23 @@ static int stm32_spi_resume(struct device *dev)
                return ret;
 
        ret = spi_master_resume(master);
-       if (ret)
+       if (ret) {
                clk_disable_unprepare(spi->clk);
+               return ret;
+       }
 
-       return ret;
+       ret = pm_runtime_get_sync(dev);
+       if (ret) {
+               dev_err(dev, "Unable to power device:%d\n", ret);
+               return ret;
+       }
+
+       spi->cfg->config(spi);
+
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+
+       return 0;
 }
 #endif
 
index 6626587..dc12af0 100644 (file)
@@ -475,6 +475,12 @@ static LIST_HEAD(spi_controller_list);
  */
 static DEFINE_MUTEX(board_lock);
 
+/*
+ * Prevents addition of devices with same chip select and
+ * addition of devices below an unregistering controller.
+ */
+static DEFINE_MUTEX(spi_add_lock);
+
 /**
  * spi_alloc_device - Allocate a new SPI device
  * @ctlr: Controller to which device is connected
@@ -554,7 +560,6 @@ static int spi_dev_check(struct device *dev, void *data)
  */
 int spi_add_device(struct spi_device *spi)
 {
-       static DEFINE_MUTEX(spi_add_lock);
        struct spi_controller *ctlr = spi->controller;
        struct device *dev = ctlr->dev.parent;
        int status;
@@ -582,6 +587,13 @@ int spi_add_device(struct spi_device *spi)
                goto done;
        }
 
+       /* Controller may unregister concurrently */
+       if (IS_ENABLED(CONFIG_SPI_DYNAMIC) &&
+           !device_is_registered(&ctlr->dev)) {
+               status = -ENODEV;
+               goto done;
+       }
+
        /* Descriptors take precedence */
        if (ctlr->cs_gpiods)
                spi->cs_gpiod = ctlr->cs_gpiods[spi->chip_select];
@@ -2795,6 +2807,10 @@ void spi_unregister_controller(struct spi_controller *ctlr)
        struct spi_controller *found;
        int id = ctlr->bus_num;
 
+       /* Prevent addition of new devices, unregister existing ones */
+       if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
+               mutex_lock(&spi_add_lock);
+
        device_for_each_child(&ctlr->dev, NULL, __unregister);
 
        /* First make sure that this controller was ever added */
@@ -2815,6 +2831,9 @@ void spi_unregister_controller(struct spi_controller *ctlr)
        if (found == ctlr)
                idr_remove(&spi_master_idr, id);
        mutex_unlock(&board_lock);
+
+       if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
+               mutex_unlock(&spi_add_lock);
 }
 EXPORT_SYMBOL_GPL(spi_unregister_controller);
 
index 86a02af..61ca8ab 100644 (file)
 
 struct vfio_pci_ioeventfd {
        struct list_head        next;
+       struct vfio_pci_device  *vdev;
        struct virqfd           *virqfd;
        void __iomem            *addr;
        uint64_t                data;
        loff_t                  pos;
        int                     bar;
        int                     count;
+       bool                    test_mem;
 };
 
 struct vfio_pci_irq_ctx {
index 916b184..9e353c4 100644 (file)
 #define vfio_ioread8   ioread8
 #define vfio_iowrite8  iowrite8
 
+#define VFIO_IOWRITE(size) \
+static int vfio_pci_iowrite##size(struct vfio_pci_device *vdev,                \
+                       bool test_mem, u##size val, void __iomem *io)   \
+{                                                                      \
+       if (test_mem) {                                                 \
+               down_read(&vdev->memory_lock);                          \
+               if (!__vfio_pci_memory_enabled(vdev)) {                 \
+                       up_read(&vdev->memory_lock);                    \
+                       return -EIO;                                    \
+               }                                                       \
+       }                                                               \
+                                                                       \
+       vfio_iowrite##size(val, io);                                    \
+                                                                       \
+       if (test_mem)                                                   \
+               up_read(&vdev->memory_lock);                            \
+                                                                       \
+       return 0;                                                       \
+}
+
+VFIO_IOWRITE(8)
+VFIO_IOWRITE(16)
+VFIO_IOWRITE(32)
+#ifdef iowrite64
+VFIO_IOWRITE(64)
+#endif
+
+#define VFIO_IOREAD(size) \
+static int vfio_pci_ioread##size(struct vfio_pci_device *vdev,         \
+                       bool test_mem, u##size *val, void __iomem *io)  \
+{                                                                      \
+       if (test_mem) {                                                 \
+               down_read(&vdev->memory_lock);                          \
+               if (!__vfio_pci_memory_enabled(vdev)) {                 \
+                       up_read(&vdev->memory_lock);                    \
+                       return -EIO;                                    \
+               }                                                       \
+       }                                                               \
+                                                                       \
+       *val = vfio_ioread##size(io);                                   \
+                                                                       \
+       if (test_mem)                                                   \
+               up_read(&vdev->memory_lock);                            \
+                                                                       \
+       return 0;                                                       \
+}
+
+VFIO_IOREAD(8)
+VFIO_IOREAD(16)
+VFIO_IOREAD(32)
+
 /*
  * Read or write from an __iomem region (MMIO or I/O port) with an excluded
  * range which is inaccessible.  The excluded range drops writes and fills
  * reads with -1.  This is intended for handling MSI-X vector tables and
  * leftover space for ROM BARs.
  */
-static ssize_t do_io_rw(void __iomem *io, char __user *buf,
+static ssize_t do_io_rw(struct vfio_pci_device *vdev, bool test_mem,
+                       void __iomem *io, char __user *buf,
                        loff_t off, size_t count, size_t x_start,
                        size_t x_end, bool iswrite)
 {
        ssize_t done = 0;
+       int ret;
 
        while (count) {
                size_t fillable, filled;
@@ -66,9 +119,15 @@ static ssize_t do_io_rw(void __iomem *io, char __user *buf,
                                if (copy_from_user(&val, buf, 4))
                                        return -EFAULT;
 
-                               vfio_iowrite32(val, io + off);
+                               ret = vfio_pci_iowrite32(vdev, test_mem,
+                                                        val, io + off);
+                               if (ret)
+                                       return ret;
                        } else {
-                               val = vfio_ioread32(io + off);
+                               ret = vfio_pci_ioread32(vdev, test_mem,
+                                                       &val, io + off);
+                               if (ret)
+                                       return ret;
 
                                if (copy_to_user(buf, &val, 4))
                                        return -EFAULT;
@@ -82,9 +141,15 @@ static ssize_t do_io_rw(void __iomem *io, char __user *buf,
                                if (copy_from_user(&val, buf, 2))
                                        return -EFAULT;
 
-                               vfio_iowrite16(val, io + off);
+                               ret = vfio_pci_iowrite16(vdev, test_mem,
+                                                        val, io + off);
+                               if (ret)
+                                       return ret;
                        } else {
-                               val = vfio_ioread16(io + off);
+                               ret = vfio_pci_ioread16(vdev, test_mem,
+                                                       &val, io + off);
+                               if (ret)
+                                       return ret;
 
                                if (copy_to_user(buf, &val, 2))
                                        return -EFAULT;
@@ -98,9 +163,15 @@ static ssize_t do_io_rw(void __iomem *io, char __user *buf,
                                if (copy_from_user(&val, buf, 1))
                                        return -EFAULT;
 
-                               vfio_iowrite8(val, io + off);
+                               ret = vfio_pci_iowrite8(vdev, test_mem,
+                                                       val, io + off);
+                               if (ret)
+                                       return ret;
                        } else {
-                               val = vfio_ioread8(io + off);
+                               ret = vfio_pci_ioread8(vdev, test_mem,
+                                                      &val, io + off);
+                               if (ret)
+                                       return ret;
 
                                if (copy_to_user(buf, &val, 1))
                                        return -EFAULT;
@@ -178,14 +249,6 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_device *vdev, char __user *buf,
 
        count = min(count, (size_t)(end - pos));
 
-       if (res->flags & IORESOURCE_MEM) {
-               down_read(&vdev->memory_lock);
-               if (!__vfio_pci_memory_enabled(vdev)) {
-                       up_read(&vdev->memory_lock);
-                       return -EIO;
-               }
-       }
-
        if (bar == PCI_ROM_RESOURCE) {
                /*
                 * The ROM can fill less space than the BAR, so we start the
@@ -213,7 +276,8 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_device *vdev, char __user *buf,
                x_end = vdev->msix_offset + vdev->msix_size;
        }
 
-       done = do_io_rw(io, buf, pos, count, x_start, x_end, iswrite);
+       done = do_io_rw(vdev, res->flags & IORESOURCE_MEM, io, buf, pos,
+                       count, x_start, x_end, iswrite);
 
        if (done >= 0)
                *ppos += done;
@@ -221,9 +285,6 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_device *vdev, char __user *buf,
        if (bar == PCI_ROM_RESOURCE)
                pci_unmap_rom(pdev, io);
 out:
-       if (res->flags & IORESOURCE_MEM)
-               up_read(&vdev->memory_lock);
-
        return done;
 }
 
@@ -278,7 +339,12 @@ ssize_t vfio_pci_vga_rw(struct vfio_pci_device *vdev, char __user *buf,
                return ret;
        }
 
-       done = do_io_rw(iomem, buf, off, count, 0, 0, iswrite);
+       /*
+        * VGA MMIO is a legacy, non-BAR resource that hopefully allows
+        * probing, so we don't currently worry about access in relation
+        * to the memory enable bit in the command register.
+        */
+       done = do_io_rw(vdev, false, iomem, buf, off, count, 0, 0, iswrite);
 
        vga_put(vdev->pdev, rsrc);
 
@@ -296,17 +362,21 @@ static int vfio_pci_ioeventfd_handler(void *opaque, void *unused)
 
        switch (ioeventfd->count) {
        case 1:
-               vfio_iowrite8(ioeventfd->data, ioeventfd->addr);
+               vfio_pci_iowrite8(ioeventfd->vdev, ioeventfd->test_mem,
+                                 ioeventfd->data, ioeventfd->addr);
                break;
        case 2:
-               vfio_iowrite16(ioeventfd->data, ioeventfd->addr);
+               vfio_pci_iowrite16(ioeventfd->vdev, ioeventfd->test_mem,
+                                  ioeventfd->data, ioeventfd->addr);
                break;
        case 4:
-               vfio_iowrite32(ioeventfd->data, ioeventfd->addr);
+               vfio_pci_iowrite32(ioeventfd->vdev, ioeventfd->test_mem,
+                                  ioeventfd->data, ioeventfd->addr);
                break;
 #ifdef iowrite64
        case 8:
-               vfio_iowrite64(ioeventfd->data, ioeventfd->addr);
+               vfio_pci_iowrite64(ioeventfd->vdev, ioeventfd->test_mem,
+                                  ioeventfd->data, ioeventfd->addr);
                break;
 #endif
        }
@@ -378,11 +448,13 @@ long vfio_pci_ioeventfd(struct vfio_pci_device *vdev, loff_t offset,
                goto out_unlock;
        }
 
+       ioeventfd->vdev = vdev;
        ioeventfd->addr = vdev->barmap[bar] + pos;
        ioeventfd->data = data;
        ioeventfd->pos = pos;
        ioeventfd->bar = bar;
        ioeventfd->count = count;
+       ioeventfd->test_mem = vdev->pdev->resource[bar].flags & IORESOURCE_MEM;
 
        ret = vfio_virqfd_enable(ioeventfd, vfio_pci_ioeventfd_handler,
                                 NULL, NULL, &ioeventfd->virqfd, fd);
index 6990fc7..c992973 100644 (file)
@@ -1424,13 +1424,16 @@ static int vfio_bus_type(struct device *dev, void *data)
 static int vfio_iommu_replay(struct vfio_iommu *iommu,
                             struct vfio_domain *domain)
 {
-       struct vfio_domain *d;
+       struct vfio_domain *d = NULL;
        struct rb_node *n;
        unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
        int ret;
 
        /* Arbitrarily pick the first domain in the list for lookups */
-       d = list_first_entry(&iommu->domain_list, struct vfio_domain, next);
+       if (!list_empty(&iommu->domain_list))
+               d = list_first_entry(&iommu->domain_list,
+                                    struct vfio_domain, next);
+
        n = rb_first(&iommu->dma_list);
 
        for (; n; n = rb_next(n)) {
@@ -1448,6 +1451,11 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
                                phys_addr_t p;
                                dma_addr_t i;
 
+                               if (WARN_ON(!d)) { /* mapped w/o a domain?! */
+                                       ret = -EINVAL;
+                                       goto unwind;
+                               }
+
                                phys = iommu_iova_to_phys(d->domain, iova);
 
                                if (WARN_ON(!phys)) {
@@ -1477,7 +1485,7 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
                                if (npage <= 0) {
                                        WARN_ON(!npage);
                                        ret = (int)npage;
-                                       return ret;
+                                       goto unwind;
                                }
 
                                phys = pfn << PAGE_SHIFT;
@@ -1486,14 +1494,67 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
 
                        ret = iommu_map(domain->domain, iova, phys,
                                        size, dma->prot | domain->prot);
-                       if (ret)
-                               return ret;
+                       if (ret) {
+                               if (!dma->iommu_mapped)
+                                       vfio_unpin_pages_remote(dma, iova,
+                                                       phys >> PAGE_SHIFT,
+                                                       size >> PAGE_SHIFT,
+                                                       true);
+                               goto unwind;
+                       }
 
                        iova += size;
                }
+       }
+
+       /* All dmas are now mapped, defer to second tree walk for unwind */
+       for (n = rb_first(&iommu->dma_list); n; n = rb_next(n)) {
+               struct vfio_dma *dma = rb_entry(n, struct vfio_dma, node);
+
                dma->iommu_mapped = true;
        }
+
        return 0;
+
+unwind:
+       for (; n; n = rb_prev(n)) {
+               struct vfio_dma *dma = rb_entry(n, struct vfio_dma, node);
+               dma_addr_t iova;
+
+               if (dma->iommu_mapped) {
+                       iommu_unmap(domain->domain, dma->iova, dma->size);
+                       continue;
+               }
+
+               iova = dma->iova;
+               while (iova < dma->iova + dma->size) {
+                       phys_addr_t phys, p;
+                       size_t size;
+                       dma_addr_t i;
+
+                       phys = iommu_iova_to_phys(domain->domain, iova);
+                       if (!phys) {
+                               iova += PAGE_SIZE;
+                               continue;
+                       }
+
+                       size = PAGE_SIZE;
+                       p = phys + size;
+                       i = iova + size;
+                       while (i < dma->iova + dma->size &&
+                              p == iommu_iova_to_phys(domain->domain, i)) {
+                               size += PAGE_SIZE;
+                               p += PAGE_SIZE;
+                               i += PAGE_SIZE;
+                       }
+
+                       iommu_unmap(domain->domain, iova, size);
+                       vfio_unpin_pages_remote(dma, iova, phys >> PAGE_SHIFT,
+                                               size >> PAGE_SHIFT, true);
+               }
+       }
+
+       return ret;
 }
 
 /*
index 65491ae..e57c008 100644 (file)
@@ -453,7 +453,7 @@ static int efifb_probe(struct platform_device *dev)
        info->apertures->ranges[0].base = efifb_fix.smem_start;
        info->apertures->ranges[0].size = size_remap;
 
-       if (efi_enabled(EFI_BOOT) &&
+       if (efi_enabled(EFI_MEMMAP) &&
            !efi_mem_desc_lookup(efifb_fix.smem_start, &md)) {
                if ((efifb_fix.smem_start + efifb_fix.smem_len) >
                    (md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT))) {
index b79879a..7b784af 100644 (file)
@@ -382,15 +382,17 @@ void afs_dynroot_depopulate(struct super_block *sb)
                net->dynroot_sb = NULL;
        mutex_unlock(&net->proc_cells_lock);
 
-       inode_lock(root->d_inode);
-
-       /* Remove all the pins for dirs created for manually added cells */
-       list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) {
-               if (subdir->d_fsdata) {
-                       subdir->d_fsdata = NULL;
-                       dput(subdir);
+       if (root) {
+               inode_lock(root->d_inode);
+
+               /* Remove all the pins for dirs created for manually added cells */
+               list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) {
+                       if (subdir->d_fsdata) {
+                               subdir->d_fsdata = NULL;
+                               dput(subdir);
+                       }
                }
-       }
 
-       inode_unlock(root->d_inode);
+               inode_unlock(root->d_inode);
+       }
 }
index 24fd163..97cab12 100644 (file)
@@ -235,6 +235,7 @@ int afs_put_operation(struct afs_operation *op)
        afs_end_cursor(&op->ac);
        afs_put_serverlist(op->net, op->server_list);
        afs_put_volume(op->net, op->volume, afs_volume_trace_put_put_op);
+       key_put(op->key);
        kfree(op);
        return ret;
 }
index 5d9ef51..e7e98ad 100644 (file)
@@ -161,8 +161,8 @@ responded:
                }
        }
 
-       rtt_us = rxrpc_kernel_get_srtt(call->net->socket, call->rxcall);
-       if (rtt_us < server->probe.rtt) {
+       if (rxrpc_kernel_get_srtt(call->net->socket, call->rxcall, &rtt_us) &&
+           rtt_us < server->probe.rtt) {
                server->probe.rtt = rtt_us;
                server->rtt = rtt_us;
                alist->preferred = index;
index 792ac71..18042b7 100644 (file)
@@ -401,22 +401,24 @@ struct afs_vlserver {
 #define AFS_VLSERVER_FL_PROBED 0               /* The VL server has been probed */
 #define AFS_VLSERVER_FL_PROBING        1               /* VL server is being probed */
 #define AFS_VLSERVER_FL_IS_YFS 2               /* Server is YFS not AFS */
+#define AFS_VLSERVER_FL_RESPONDING 3           /* VL server is responding */
        rwlock_t                lock;           /* Lock on addresses */
        atomic_t                usage;
+       unsigned int            rtt;            /* Server's current RTT in uS */
 
        /* Probe state */
        wait_queue_head_t       probe_wq;
        atomic_t                probe_outstanding;
        spinlock_t              probe_lock;
        struct {
-               unsigned int    rtt;            /* RTT as ktime/64 */
+               unsigned int    rtt;            /* RTT in uS */
                u32             abort_code;
                short           error;
-               bool            have_result;
-               bool            responded:1;
-               bool            is_yfs:1;
-               bool            not_yfs:1;
-               bool            local_failure:1;
+               unsigned short  flags;
+#define AFS_VLSERVER_PROBE_RESPONDED           0x01 /* At least once response (may be abort) */
+#define AFS_VLSERVER_PROBE_IS_YFS              0x02 /* The peer appears to be YFS */
+#define AFS_VLSERVER_PROBE_NOT_YFS             0x04 /* The peer appears not to be YFS */
+#define AFS_VLSERVER_PROBE_LOCAL_FAILURE       0x08 /* A local failure prevented a probe */
        } probe;
 
        u16                     port;
index e817fc7..e8babb6 100644 (file)
@@ -310,6 +310,11 @@ static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
                                   alist->preferred == i ? '>' : '-',
                                   &alist->addrs[i].transport);
        }
+       seq_printf(m, " info: fl=%lx rtt=%d\n", vlserver->flags, vlserver->rtt);
+       seq_printf(m, " probe: fl=%x e=%d ac=%d out=%d\n",
+                  vlserver->probe.flags, vlserver->probe.error,
+                  vlserver->probe.abort_code,
+                  atomic_read(&vlserver->probe_outstanding));
        return 0;
 }
 
index 8fea54e..38b2ba1 100644 (file)
@@ -21,6 +21,7 @@ struct afs_vlserver *afs_alloc_vlserver(const char *name, size_t name_len,
                rwlock_init(&vlserver->lock);
                init_waitqueue_head(&vlserver->probe_wq);
                spin_lock_init(&vlserver->probe_lock);
+               vlserver->rtt = UINT_MAX;
                vlserver->name_len = name_len;
                vlserver->port = port;
                memcpy(vlserver->name, name, name_len);
index e3aa013..d1c7068 100644 (file)
 #include "internal.h"
 #include "protocol_yfs.h"
 
-static bool afs_vl_probe_done(struct afs_vlserver *server)
+
+/*
+ * Handle the completion of a set of probes.
+ */
+static void afs_finished_vl_probe(struct afs_vlserver *server)
 {
-       if (!atomic_dec_and_test(&server->probe_outstanding))
-               return false;
+       if (!(server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)) {
+               server->rtt = UINT_MAX;
+               clear_bit(AFS_VLSERVER_FL_RESPONDING, &server->flags);
+       }
 
-       wake_up_var(&server->probe_outstanding);
        clear_bit_unlock(AFS_VLSERVER_FL_PROBING, &server->flags);
        wake_up_bit(&server->flags, AFS_VLSERVER_FL_PROBING);
-       return true;
+}
+
+/*
+ * Handle the completion of a probe RPC call.
+ */
+static void afs_done_one_vl_probe(struct afs_vlserver *server, bool wake_up)
+{
+       if (atomic_dec_and_test(&server->probe_outstanding)) {
+               afs_finished_vl_probe(server);
+               wake_up = true;
+       }
+
+       if (wake_up)
+               wake_up_all(&server->probe_wq);
 }
 
 /*
@@ -45,15 +63,20 @@ void afs_vlserver_probe_result(struct afs_call *call)
                server->probe.error = 0;
                goto responded;
        case -ECONNABORTED:
-               if (!server->probe.responded) {
+               if (!(server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)) {
                        server->probe.abort_code = call->abort_code;
                        server->probe.error = ret;
                }
                goto responded;
        case -ENOMEM:
        case -ENONET:
-               server->probe.local_failure = true;
-               afs_io_error(call, afs_io_error_vl_probe_fail);
+       case -EKEYEXPIRED:
+       case -EKEYREVOKED:
+       case -EKEYREJECTED:
+               server->probe.flags |= AFS_VLSERVER_PROBE_LOCAL_FAILURE;
+               if (server->probe.error == 0)
+                       server->probe.error = ret;
+               trace_afs_io_error(call->debug_id, ret, afs_io_error_vl_probe_fail);
                goto out;
        case -ECONNRESET: /* Responded, but call expired. */
        case -ERFKILL:
@@ -67,12 +90,12 @@ void afs_vlserver_probe_result(struct afs_call *call)
        default:
                clear_bit(index, &alist->responded);
                set_bit(index, &alist->failed);
-               if (!server->probe.responded &&
+               if (!(server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED) &&
                    (server->probe.error == 0 ||
                     server->probe.error == -ETIMEDOUT ||
                     server->probe.error == -ETIME))
                        server->probe.error = ret;
-               afs_io_error(call, afs_io_error_vl_probe_fail);
+               trace_afs_io_error(call->debug_id, ret, afs_io_error_vl_probe_fail);
                goto out;
        }
 
@@ -81,39 +104,36 @@ responded:
        clear_bit(index, &alist->failed);
 
        if (call->service_id == YFS_VL_SERVICE) {
-               server->probe.is_yfs = true;
+               server->probe.flags |= AFS_VLSERVER_PROBE_IS_YFS;
                set_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags);
                alist->addrs[index].srx_service = call->service_id;
        } else {
-               server->probe.not_yfs = true;
-               if (!server->probe.is_yfs) {
+               server->probe.flags |= AFS_VLSERVER_PROBE_NOT_YFS;
+               if (!(server->probe.flags & AFS_VLSERVER_PROBE_IS_YFS)) {
                        clear_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags);
                        alist->addrs[index].srx_service = call->service_id;
                }
        }
 
-       rtt_us = rxrpc_kernel_get_srtt(call->net->socket, call->rxcall);
-       if (rtt_us < server->probe.rtt) {
+       if (rxrpc_kernel_get_srtt(call->net->socket, call->rxcall, &rtt_us) &&
+           rtt_us < server->probe.rtt) {
                server->probe.rtt = rtt_us;
+               server->rtt = rtt_us;
                alist->preferred = index;
-               have_result = true;
        }
 
        smp_wmb(); /* Set rtt before responded. */
-       server->probe.responded = true;
+       server->probe.flags |= AFS_VLSERVER_PROBE_RESPONDED;
        set_bit(AFS_VLSERVER_FL_PROBED, &server->flags);
+       set_bit(AFS_VLSERVER_FL_RESPONDING, &server->flags);
+       have_result = true;
 out:
        spin_unlock(&server->probe_lock);
 
        _debug("probe [%u][%u] %pISpc rtt=%u ret=%d",
               server_index, index, &alist->addrs[index].transport, rtt_us, ret);
 
-       have_result |= afs_vl_probe_done(server);
-       if (have_result) {
-               server->probe.have_result = true;
-               wake_up_var(&server->probe.have_result);
-               wake_up_all(&server->probe_wq);
-       }
+       afs_done_one_vl_probe(server, have_result);
 }
 
 /*
@@ -151,11 +171,10 @@ static bool afs_do_probe_vlserver(struct afs_net *net,
                        in_progress = true;
                } else {
                        afs_prioritise_error(_e, PTR_ERR(call), ac.abort_code);
+                       afs_done_one_vl_probe(server, false);
                }
        }
 
-       if (!in_progress)
-               afs_vl_probe_done(server);
        return in_progress;
 }
 
@@ -193,7 +212,7 @@ int afs_wait_for_vl_probes(struct afs_vlserver_list *vllist,
 {
        struct wait_queue_entry *waits;
        struct afs_vlserver *server;
-       unsigned int rtt = UINT_MAX;
+       unsigned int rtt = UINT_MAX, rtt_s;
        bool have_responders = false;
        int pref = -1, i;
 
@@ -205,7 +224,7 @@ int afs_wait_for_vl_probes(struct afs_vlserver_list *vllist,
                        server = vllist->servers[i].server;
                        if (!test_bit(AFS_VLSERVER_FL_PROBING, &server->flags))
                                __clear_bit(i, &untried);
-                       if (server->probe.responded)
+                       if (server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)
                                have_responders = true;
                }
        }
@@ -231,7 +250,7 @@ int afs_wait_for_vl_probes(struct afs_vlserver_list *vllist,
                for (i = 0; i < vllist->nr_servers; i++) {
                        if (test_bit(i, &untried)) {
                                server = vllist->servers[i].server;
-                               if (server->probe.responded)
+                               if (server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)
                                        goto stop;
                                if (test_bit(AFS_VLSERVER_FL_PROBING, &server->flags))
                                        still_probing = true;
@@ -249,10 +268,11 @@ stop:
        for (i = 0; i < vllist->nr_servers; i++) {
                if (test_bit(i, &untried)) {
                        server = vllist->servers[i].server;
-                       if (server->probe.responded &&
-                           server->probe.rtt < rtt) {
+                       rtt_s = READ_ONCE(server->rtt);
+                       if (test_bit(AFS_VLSERVER_FL_RESPONDING, &server->flags) &&
+                           rtt_s < rtt) {
                                pref = i;
-                               rtt = server->probe.rtt;
+                               rtt = rtt_s;
                        }
 
                        remove_wait_queue(&server->probe_wq, &waits[i]);
index f405ca8..c0458c9 100644 (file)
@@ -192,7 +192,8 @@ pick_server:
        for (i = 0; i < vc->server_list->nr_servers; i++) {
                struct afs_vlserver *s = vc->server_list->servers[i].server;
 
-               if (!test_bit(i, &vc->untried) || !s->probe.responded)
+               if (!test_bit(i, &vc->untried) ||
+                   !test_bit(AFS_VLSERVER_FL_RESPONDING, &s->flags))
                        continue;
                if (s->probe.rtt < rtt) {
                        vc->index = i;
@@ -262,10 +263,14 @@ no_more_servers:
        for (i = 0; i < vc->server_list->nr_servers; i++) {
                struct afs_vlserver *s = vc->server_list->servers[i].server;
 
+               if (test_bit(AFS_VLSERVER_FL_RESPONDING, &s->flags))
+                       e.responded = true;
                afs_prioritise_error(&e, READ_ONCE(s->probe.error),
                                     s->probe.abort_code);
        }
 
+       error = e.error;
+
 failed_set_error:
        vc->error = error;
 failed:
index 061dd20..d468ed9 100644 (file)
@@ -3157,6 +3157,15 @@ int __sync_dirty_buffer(struct buffer_head *bh, int op_flags)
        WARN_ON(atomic_read(&bh->b_count) < 1);
        lock_buffer(bh);
        if (test_clear_buffer_dirty(bh)) {
+               /*
+                * The bh should be mapped, but it might not be if the
+                * device was hot-removed. Not much we can do but fail the I/O.
+                */
+               if (!buffer_mapped(bh)) {
+                       unlock_buffer(bh);
+                       return -EIO;
+               }
+
                get_bh(bh);
                bh->b_end_io = end_buffer_write_sync;
                ret = submit_bh(REQ_OP_WRITE, op_flags, bh);
index 12eebcd..e0decff 100644 (file)
@@ -1994,9 +1994,11 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests)
                         * not already there, and calling reverse_path_check()
                         * during ep_insert().
                         */
-                       if (list_empty(&epi->ffd.file->f_tfile_llink))
+                       if (list_empty(&epi->ffd.file->f_tfile_llink)) {
+                               get_file(epi->ffd.file);
                                list_add(&epi->ffd.file->f_tfile_llink,
                                         &tfile_check_list);
+                       }
                }
        }
        mutex_unlock(&ep->mtx);
@@ -2040,6 +2042,7 @@ static void clear_tfile_check_list(void)
                file = list_first_entry(&tfile_check_list, struct file,
                                        f_tfile_llink);
                list_del_init(&file->f_tfile_llink);
+               fput(file);
        }
        INIT_LIST_HEAD(&tfile_check_list);
 }
@@ -2200,25 +2203,22 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
                        full_check = 1;
                        if (is_file_epoll(tf.file)) {
                                error = -ELOOP;
-                               if (ep_loop_check(ep, tf.file) != 0) {
-                                       clear_tfile_check_list();
+                               if (ep_loop_check(ep, tf.file) != 0)
                                        goto error_tgt_fput;
-                               }
-                       } else
+                       } else {
+                               get_file(tf.file);
                                list_add(&tf.file->f_tfile_llink,
                                                        &tfile_check_list);
+                       }
                        error = epoll_mutex_lock(&ep->mtx, 0, nonblock);
-                       if (error) {
-out_del:
-                               list_del(&tf.file->f_tfile_llink);
+                       if (error)
                                goto error_tgt_fput;
-                       }
                        if (is_file_epoll(tf.file)) {
                                tep = tf.file->private_data;
                                error = epoll_mutex_lock(&tep->mtx, 1, nonblock);
                                if (error) {
                                        mutex_unlock(&ep->mtx);
-                                       goto out_del;
+                                       goto error_tgt_fput;
                                }
                        }
                }
@@ -2239,8 +2239,6 @@ out_del:
                        error = ep_insert(ep, epds, tf.file, fd, full_check);
                } else
                        error = -EEXIST;
-               if (full_check)
-                       clear_tfile_check_list();
                break;
        case EPOLL_CTL_DEL:
                if (epi)
@@ -2263,8 +2261,10 @@ out_del:
        mutex_unlock(&ep->mtx);
 
 error_tgt_fput:
-       if (full_check)
+       if (full_check) {
+               clear_tfile_check_list();
                mutex_unlock(&epmutex);
+       }
 
        fdput(tf);
 error_fput:
index 1afa5a4..619dd35 100644 (file)
@@ -110,7 +110,7 @@ config EXT4_KUNIT_TESTS
          This builds the ext4 KUnit tests.
 
          KUnit tests run during boot and output the results to the debug log
-         in TAP format (http://testanything.org/). Only useful for kernel devs
+         in TAP format (https://testanything.org/). Only useful for kernel devs
          running KUnit test harness and are not for inclusion into a production
          build.
 
index 1ba46d8..48c3df4 100644 (file)
@@ -413,7 +413,8 @@ verified:
  * Return buffer_head on success or an ERR_PTR in case of failure.
  */
 struct buffer_head *
-ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
+ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group,
+                             bool ignore_locked)
 {
        struct ext4_group_desc *desc;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -441,6 +442,12 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
                return ERR_PTR(-ENOMEM);
        }
 
+       if (ignore_locked && buffer_locked(bh)) {
+               /* buffer under IO already, return if called for prefetching */
+               put_bh(bh);
+               return NULL;
+       }
+
        if (bitmap_uptodate(bh))
                goto verify;
 
@@ -487,10 +494,11 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
         * submit the buffer_head for reading
         */
        set_buffer_new(bh);
-       trace_ext4_read_block_bitmap_load(sb, block_group);
+       trace_ext4_read_block_bitmap_load(sb, block_group, ignore_locked);
        bh->b_end_io = ext4_end_bitmap_read;
        get_bh(bh);
-       submit_bh(REQ_OP_READ, REQ_META | REQ_PRIO, bh);
+       submit_bh(REQ_OP_READ, REQ_META | REQ_PRIO |
+                 (ignore_locked ? REQ_RAHEAD : 0), bh);
        return bh;
 verify:
        err = ext4_validate_block_bitmap(sb, desc, block_group, bh);
@@ -534,7 +542,7 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
        struct buffer_head *bh;
        int err;
 
-       bh = ext4_read_block_bitmap_nowait(sb, block_group);
+       bh = ext4_read_block_bitmap_nowait(sb, block_group, false);
        if (IS_ERR(bh))
                return bh;
        err = ext4_wait_block_bitmap(sb, block_group, bh);
index 16e9b2f..c54ba52 100644 (file)
@@ -24,6 +24,7 @@ struct ext4_system_zone {
        struct rb_node  node;
        ext4_fsblk_t    start_blk;
        unsigned int    count;
+       u32             ino;
 };
 
 static struct kmem_cache *ext4_system_zone_cachep;
@@ -45,7 +46,8 @@ void ext4_exit_system_zone(void)
 static inline int can_merge(struct ext4_system_zone *entry1,
                     struct ext4_system_zone *entry2)
 {
-       if ((entry1->start_blk + entry1->count) == entry2->start_blk)
+       if ((entry1->start_blk + entry1->count) == entry2->start_blk &&
+           entry1->ino == entry2->ino)
                return 1;
        return 0;
 }
@@ -66,9 +68,9 @@ static void release_system_zone(struct ext4_system_blocks *system_blks)
  */
 static int add_system_zone(struct ext4_system_blocks *system_blks,
                           ext4_fsblk_t start_blk,
-                          unsigned int count)
+                          unsigned int count, u32 ino)
 {
-       struct ext4_system_zone *new_entry = NULL, *entry;
+       struct ext4_system_zone *new_entry, *entry;
        struct rb_node **n = &system_blks->root.rb_node, *node;
        struct rb_node *parent = NULL, *new_node = NULL;
 
@@ -79,30 +81,21 @@ static int add_system_zone(struct ext4_system_blocks *system_blks,
                        n = &(*n)->rb_left;
                else if (start_blk >= (entry->start_blk + entry->count))
                        n = &(*n)->rb_right;
-               else {
-                       if (start_blk + count > (entry->start_blk +
-                                                entry->count))
-                               entry->count = (start_blk + count -
-                                               entry->start_blk);
-                       new_node = *n;
-                       new_entry = rb_entry(new_node, struct ext4_system_zone,
-                                            node);
-                       break;
-               }
+               else    /* Unexpected overlap of system zones. */
+                       return -EFSCORRUPTED;
        }
 
-       if (!new_entry) {
-               new_entry = kmem_cache_alloc(ext4_system_zone_cachep,
-                                            GFP_KERNEL);
-               if (!new_entry)
-                       return -ENOMEM;
-               new_entry->start_blk = start_blk;
-               new_entry->count = count;
-               new_node = &new_entry->node;
-
-               rb_link_node(new_node, parent, n);
-               rb_insert_color(new_node, &system_blks->root);
-       }
+       new_entry = kmem_cache_alloc(ext4_system_zone_cachep,
+                                    GFP_KERNEL);
+       if (!new_entry)
+               return -ENOMEM;
+       new_entry->start_blk = start_blk;
+       new_entry->count = count;
+       new_entry->ino = ino;
+       new_node = &new_entry->node;
+
+       rb_link_node(new_node, parent, n);
+       rb_insert_color(new_node, &system_blks->root);
 
        /* Can we merge to the left? */
        node = rb_prev(new_node);
@@ -151,40 +144,6 @@ static void debug_print_tree(struct ext4_sb_info *sbi)
        printk(KERN_CONT "\n");
 }
 
-/*
- * Returns 1 if the passed-in block region (start_blk,
- * start_blk+count) is valid; 0 if some part of the block region
- * overlaps with filesystem metadata blocks.
- */
-static int ext4_data_block_valid_rcu(struct ext4_sb_info *sbi,
-                                    struct ext4_system_blocks *system_blks,
-                                    ext4_fsblk_t start_blk,
-                                    unsigned int count)
-{
-       struct ext4_system_zone *entry;
-       struct rb_node *n;
-
-       if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
-           (start_blk + count < start_blk) ||
-           (start_blk + count > ext4_blocks_count(sbi->s_es)))
-               return 0;
-
-       if (system_blks == NULL)
-               return 1;
-
-       n = system_blks->root.rb_node;
-       while (n) {
-               entry = rb_entry(n, struct ext4_system_zone, node);
-               if (start_blk + count - 1 < entry->start_blk)
-                       n = n->rb_left;
-               else if (start_blk >= (entry->start_blk + entry->count))
-                       n = n->rb_right;
-               else
-                       return 0;
-       }
-       return 1;
-}
-
 static int ext4_protect_reserved_inode(struct super_block *sb,
                                       struct ext4_system_blocks *system_blks,
                                       u32 ino)
@@ -214,19 +173,18 @@ static int ext4_protect_reserved_inode(struct super_block *sb,
                if (n == 0) {
                        i++;
                } else {
-                       if (!ext4_data_block_valid_rcu(sbi, system_blks,
-                                               map.m_pblk, n)) {
-                               err = -EFSCORRUPTED;
-                               __ext4_error(sb, __func__, __LINE__, -err,
-                                            map.m_pblk, "blocks %llu-%llu "
-                                            "from inode %u overlap system zone",
-                                            map.m_pblk,
-                                            map.m_pblk + map.m_len - 1, ino);
+                       err = add_system_zone(system_blks, map.m_pblk, n, ino);
+                       if (err < 0) {
+                               if (err == -EFSCORRUPTED) {
+                                       __ext4_error(sb, __func__, __LINE__,
+                                                    -err, map.m_pblk,
+                                                    "blocks %llu-%llu from inode %u overlap system zone",
+                                                    map.m_pblk,
+                                                    map.m_pblk + map.m_len - 1,
+                                                    ino);
+                               }
                                break;
                        }
-                       err = add_system_zone(system_blks, map.m_pblk, n);
-                       if (err < 0)
-                               break;
                        i += n;
                }
        }
@@ -262,14 +220,6 @@ int ext4_setup_system_zone(struct super_block *sb)
        int flex_size = ext4_flex_bg_size(sbi);
        int ret;
 
-       if (!test_opt(sb, BLOCK_VALIDITY)) {
-               if (sbi->system_blks)
-                       ext4_release_system_zone(sb);
-               return 0;
-       }
-       if (sbi->system_blks)
-               return 0;
-
        system_blks = kzalloc(sizeof(*system_blks), GFP_KERNEL);
        if (!system_blks)
                return -ENOMEM;
@@ -277,22 +227,25 @@ int ext4_setup_system_zone(struct super_block *sb)
        for (i=0; i < ngroups; i++) {
                cond_resched();
                if (ext4_bg_has_super(sb, i) &&
-                   ((i < 5) || ((i % flex_size) == 0)))
-                       add_system_zone(system_blks,
+                   ((i < 5) || ((i % flex_size) == 0))) {
+                       ret = add_system_zone(system_blks,
                                        ext4_group_first_block_no(sb, i),
-                                       ext4_bg_num_gdb(sb, i) + 1);
+                                       ext4_bg_num_gdb(sb, i) + 1, 0);
+                       if (ret)
+                               goto err;
+               }
                gdp = ext4_get_group_desc(sb, i, NULL);
                ret = add_system_zone(system_blks,
-                               ext4_block_bitmap(sb, gdp), 1);
+                               ext4_block_bitmap(sb, gdp), 1, 0);
                if (ret)
                        goto err;
                ret = add_system_zone(system_blks,
-                               ext4_inode_bitmap(sb, gdp), 1);
+                               ext4_inode_bitmap(sb, gdp), 1, 0);
                if (ret)
                        goto err;
                ret = add_system_zone(system_blks,
                                ext4_inode_table(sb, gdp),
-                               sbi->s_itb_per_group);
+                               sbi->s_itb_per_group, 0);
                if (ret)
                        goto err;
        }
@@ -341,11 +294,24 @@ void ext4_release_system_zone(struct super_block *sb)
                call_rcu(&system_blks->rcu, ext4_destroy_system_zone);
 }
 
-int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk,
+/*
+ * Returns 1 if the passed-in block region (start_blk,
+ * start_blk+count) is valid; 0 if some part of the block region
+ * overlaps with some other filesystem metadata blocks.
+ */
+int ext4_inode_block_valid(struct inode *inode, ext4_fsblk_t start_blk,
                          unsigned int count)
 {
+       struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
        struct ext4_system_blocks *system_blks;
-       int ret;
+       struct ext4_system_zone *entry;
+       struct rb_node *n;
+       int ret = 1;
+
+       if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
+           (start_blk + count < start_blk) ||
+           (start_blk + count > ext4_blocks_count(sbi->s_es)))
+               return 0;
 
        /*
         * Lock the system zone to prevent it being released concurrently
@@ -354,8 +320,22 @@ int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk,
         */
        rcu_read_lock();
        system_blks = rcu_dereference(sbi->system_blks);
-       ret = ext4_data_block_valid_rcu(sbi, system_blks, start_blk,
-                                       count);
+       if (system_blks == NULL)
+               goto out_rcu;
+
+       n = system_blks->root.rb_node;
+       while (n) {
+               entry = rb_entry(n, struct ext4_system_zone, node);
+               if (start_blk + count - 1 < entry->start_blk)
+                       n = n->rb_left;
+               else if (start_blk >= (entry->start_blk + entry->count))
+                       n = n->rb_right;
+               else {
+                       ret = (entry->ino == inode->i_ino);
+                       break;
+               }
+       }
+out_rcu:
        rcu_read_unlock();
        return ret;
 }
@@ -374,8 +354,7 @@ int ext4_check_blockref(const char *function, unsigned int line,
        while (bref < p+max) {
                blk = le32_to_cpu(*bref++);
                if (blk &&
-                   unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb),
-                                                   blk, 1))) {
+                   unlikely(!ext4_inode_block_valid(inode, blk, 1))) {
                        ext4_error_inode(inode, function, line, blk,
                                         "invalid block");
                        return -EFSCORRUPTED;
index 42f5060..523e00d 100644 (file)
@@ -434,10 +434,36 @@ struct flex_groups {
 #define EXT4_CASEFOLD_FL               0x40000000 /* Casefolded directory */
 #define EXT4_RESERVED_FL               0x80000000 /* reserved for ext4 lib */
 
-#define EXT4_FL_USER_VISIBLE           0x725BDFFF /* User visible flags */
-#define EXT4_FL_USER_MODIFIABLE                0x624BC0FF /* User modifiable flags */
-
-/* Flags we can manipulate with through EXT4_IOC_FSSETXATTR */
+/* User modifiable flags */
+#define EXT4_FL_USER_MODIFIABLE                (EXT4_SECRM_FL | \
+                                        EXT4_UNRM_FL | \
+                                        EXT4_COMPR_FL | \
+                                        EXT4_SYNC_FL | \
+                                        EXT4_IMMUTABLE_FL | \
+                                        EXT4_APPEND_FL | \
+                                        EXT4_NODUMP_FL | \
+                                        EXT4_NOATIME_FL | \
+                                        EXT4_JOURNAL_DATA_FL | \
+                                        EXT4_NOTAIL_FL | \
+                                        EXT4_DIRSYNC_FL | \
+                                        EXT4_TOPDIR_FL | \
+                                        EXT4_EXTENTS_FL | \
+                                        0x00400000 /* EXT4_EOFBLOCKS_FL */ | \
+                                        EXT4_DAX_FL | \
+                                        EXT4_PROJINHERIT_FL | \
+                                        EXT4_CASEFOLD_FL)
+
+/* User visible flags */
+#define EXT4_FL_USER_VISIBLE           (EXT4_FL_USER_MODIFIABLE | \
+                                        EXT4_DIRTY_FL | \
+                                        EXT4_COMPRBLK_FL | \
+                                        EXT4_NOCOMPR_FL | \
+                                        EXT4_ENCRYPT_FL | \
+                                        EXT4_INDEX_FL | \
+                                        EXT4_VERITY_FL | \
+                                        EXT4_INLINE_DATA_FL)
+
+/* Flags we can manipulate with through FS_IOC_FSSETXATTR */
 #define EXT4_FL_XFLAG_VISIBLE          (EXT4_SYNC_FL | \
                                         EXT4_IMMUTABLE_FL | \
                                         EXT4_APPEND_FL | \
@@ -669,8 +695,6 @@ enum {
 /*
  * ioctl commands
  */
-#define        EXT4_IOC_GETFLAGS               FS_IOC_GETFLAGS
-#define        EXT4_IOC_SETFLAGS               FS_IOC_SETFLAGS
 #define        EXT4_IOC_GETVERSION             _IOR('f', 3, long)
 #define        EXT4_IOC_SETVERSION             _IOW('f', 4, long)
 #define        EXT4_IOC_GETVERSION_OLD         FS_IOC_GETVERSION
@@ -687,17 +711,11 @@ enum {
 #define EXT4_IOC_RESIZE_FS             _IOW('f', 16, __u64)
 #define EXT4_IOC_SWAP_BOOT             _IO('f', 17)
 #define EXT4_IOC_PRECACHE_EXTENTS      _IO('f', 18)
-#define EXT4_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY
-#define EXT4_IOC_GET_ENCRYPTION_PWSALT FS_IOC_GET_ENCRYPTION_PWSALT
-#define EXT4_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY
 /* ioctl codes 19--39 are reserved for fscrypt */
 #define EXT4_IOC_CLEAR_ES_CACHE                _IO('f', 40)
 #define EXT4_IOC_GETSTATE              _IOW('f', 41, __u32)
 #define EXT4_IOC_GET_ES_CACHE          _IOWR('f', 42, struct fiemap)
 
-#define EXT4_IOC_FSGETXATTR            FS_IOC_FSGETXATTR
-#define EXT4_IOC_FSSETXATTR            FS_IOC_FSSETXATTR
-
 #define EXT4_IOC_SHUTDOWN _IOR ('X', 125, __u32)
 
 /*
@@ -722,8 +740,6 @@ enum {
 /*
  * ioctl commands in 32 bit emulation
  */
-#define EXT4_IOC32_GETFLAGS            FS_IOC32_GETFLAGS
-#define EXT4_IOC32_SETFLAGS            FS_IOC32_SETFLAGS
 #define EXT4_IOC32_GETVERSION          _IOR('f', 3, int)
 #define EXT4_IOC32_SETVERSION          _IOW('f', 4, int)
 #define EXT4_IOC32_GETRSVSZ            _IOR('f', 5, int)
@@ -1054,6 +1070,7 @@ struct ext4_inode_info {
        struct timespec64 i_crtime;
 
        /* mballoc */
+       atomic_t i_prealloc_active;
        struct list_head i_prealloc_list;
        spinlock_t i_prealloc_lock;
 
@@ -1172,6 +1189,7 @@ struct ext4_inode_info {
 #define EXT4_MOUNT_JOURNAL_CHECKSUM    0x800000 /* Journal checksums */
 #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT        0x1000000 /* Journal Async Commit */
 #define EXT4_MOUNT_WARN_ON_ERROR       0x2000000 /* Trigger WARN_ON on error */
+#define EXT4_MOUNT_PREFETCH_BLOCK_BITMAPS 0x4000000
 #define EXT4_MOUNT_DELALLOC            0x8000000 /* Delalloc support */
 #define EXT4_MOUNT_DATA_ERR_ABORT      0x10000000 /* Abort on file data write */
 #define EXT4_MOUNT_BLOCK_VALIDITY      0x20000000 /* Block validity checking */
@@ -1501,10 +1519,13 @@ struct ext4_sb_info {
        unsigned int s_mb_stats;
        unsigned int s_mb_order2_reqs;
        unsigned int s_mb_group_prealloc;
+       unsigned int s_mb_max_inode_prealloc;
        unsigned int s_max_dir_size_kb;
        /* where last allocation was done - for stream allocation */
        unsigned long s_mb_last_group;
        unsigned long s_mb_last_start;
+       unsigned int s_mb_prefetch;
+       unsigned int s_mb_prefetch_limit;
 
        /* stats for buddy allocator */
        atomic_t s_bal_reqs;    /* number of reqs with len > 1 */
@@ -1572,6 +1593,8 @@ struct ext4_sb_info {
        struct ratelimit_state s_err_ratelimit_state;
        struct ratelimit_state s_warning_ratelimit_state;
        struct ratelimit_state s_msg_ratelimit_state;
+       atomic_t s_warning_count;
+       atomic_t s_msg_count;
 
        /* Encryption context for '-o test_dummy_encryption' */
        struct fscrypt_dummy_context s_dummy_enc_ctx;
@@ -1585,6 +1608,9 @@ struct ext4_sb_info {
 #ifdef CONFIG_EXT4_DEBUG
        unsigned long s_simulate_fail;
 #endif
+       /* Record the errseq of the backing block device */
+       errseq_t s_bdev_wb_err;
+       spinlock_t s_bdev_wb_lock;
 };
 
 static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
@@ -2313,9 +2339,15 @@ struct ext4_lazy_init {
        struct mutex            li_list_mtx;
 };
 
+enum ext4_li_mode {
+       EXT4_LI_MODE_PREFETCH_BBITMAP,
+       EXT4_LI_MODE_ITABLE,
+};
+
 struct ext4_li_request {
        struct super_block      *lr_super;
-       struct ext4_sb_info     *lr_sbi;
+       enum ext4_li_mode       lr_mode;
+       ext4_group_t            lr_first_not_zeroed;
        ext4_group_t            lr_next_group;
        struct list_head        lr_request;
        unsigned long           lr_next_sched;
@@ -2446,7 +2478,8 @@ extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
 extern int ext4_should_retry_alloc(struct super_block *sb, int *retries);
 
 extern struct buffer_head *ext4_read_block_bitmap_nowait(struct super_block *sb,
-                                               ext4_group_t block_group);
+                                               ext4_group_t block_group,
+                                               bool ignore_locked);
 extern int ext4_wait_block_bitmap(struct super_block *sb,
                                  ext4_group_t block_group,
                                  struct buffer_head *bh);
@@ -2651,9 +2684,15 @@ extern int ext4_mb_release(struct super_block *);
 extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *,
                                struct ext4_allocation_request *, int *);
 extern int ext4_mb_reserve_blocks(struct super_block *, int);
-extern void ext4_discard_preallocations(struct inode *);
+extern void ext4_discard_preallocations(struct inode *, unsigned int);
 extern int __init ext4_init_mballoc(void);
 extern void ext4_exit_mballoc(void);
+extern ext4_group_t ext4_mb_prefetch(struct super_block *sb,
+                                    ext4_group_t group,
+                                    unsigned int nr, int *cnt);
+extern void ext4_mb_prefetch_fini(struct super_block *sb, ext4_group_t group,
+                                 unsigned int nr);
+
 extern void ext4_free_blocks(handle_t *handle, struct inode *inode,
                             struct buffer_head *bh, ext4_fsblk_t block,
                             unsigned long count, int flags);
@@ -2765,8 +2804,7 @@ extern int ext4_search_dir(struct buffer_head *bh,
                           struct ext4_filename *fname,
                           unsigned int offset,
                           struct ext4_dir_entry_2 **res_dir);
-extern int ext4_generic_delete_entry(handle_t *handle,
-                                    struct inode *dir,
+extern int ext4_generic_delete_entry(struct inode *dir,
                                     struct ext4_dir_entry_2 *de_del,
                                     struct buffer_head *bh,
                                     void *entry_buf,
@@ -2924,12 +2962,6 @@ do {                                                                     \
 
 #endif
 
-extern int ext4_update_compat_feature(handle_t *handle, struct super_block *sb,
-                                       __u32 compat);
-extern int ext4_update_rocompat_feature(handle_t *handle,
-                                       struct super_block *sb, __u32 rocompat);
-extern int ext4_update_incompat_feature(handle_t *handle,
-                                       struct super_block *sb, __u32 incompat);
 extern ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
                                      struct ext4_group_desc *bg);
 extern ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
@@ -3145,6 +3177,7 @@ struct ext4_group_info {
        (1 << EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT)
 #define EXT4_GROUP_INFO_IBITMAP_CORRUPT                \
        (1 << EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT)
+#define EXT4_GROUP_INFO_BBITMAP_READ_BIT       4
 
 #define EXT4_MB_GRP_NEED_INIT(grp)     \
        (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
@@ -3159,6 +3192,8 @@ struct ext4_group_info {
        (set_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))
 #define EXT4_MB_GRP_CLEAR_TRIMMED(grp) \
        (clear_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))
+#define EXT4_MB_GRP_TEST_AND_SET_READ(grp)     \
+       (test_and_set_bit(EXT4_GROUP_INFO_BBITMAP_READ_BIT, &((grp)->bb_state)))
 
 #define EXT4_MAX_CONTENTION            8
 #define EXT4_CONTENTION_THRESHOLD      2
@@ -3363,9 +3398,9 @@ extern void ext4_release_system_zone(struct super_block *sb);
 extern int ext4_setup_system_zone(struct super_block *sb);
 extern int __init ext4_init_system_zone(void);
 extern void ext4_exit_system_zone(void);
-extern int ext4_data_block_valid(struct ext4_sb_info *sbi,
-                                ext4_fsblk_t start_blk,
-                                unsigned int count);
+extern int ext4_inode_block_valid(struct inode *inode,
+                                 ext4_fsblk_t start_blk,
+                                 unsigned int count);
 extern int ext4_check_blockref(const char *, unsigned int,
                               struct inode *, __le32 *, unsigned int);
 
index 0c76cdd..760b9ee 100644 (file)
@@ -195,6 +195,28 @@ static void ext4_journal_abort_handle(const char *caller, unsigned int line,
        jbd2_journal_abort_handle(handle);
 }
 
+static void ext4_check_bdev_write_error(struct super_block *sb)
+{
+       struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       int err;
+
+       /*
+        * If the block device has write error flag, it may have failed to
+        * async write out metadata buffers in the background. In this case,
+        * we could read old data from disk and write it out again, which
+        * may lead to on-disk filesystem inconsistency.
+        */
+       if (errseq_check(&mapping->wb_err, READ_ONCE(sbi->s_bdev_wb_err))) {
+               spin_lock(&sbi->s_bdev_wb_lock);
+               err = errseq_check_and_advance(&mapping->wb_err, &sbi->s_bdev_wb_err);
+               spin_unlock(&sbi->s_bdev_wb_lock);
+               if (err)
+                       ext4_error_err(sb, -err,
+                                      "Error while async write back metadata");
+       }
+}
+
 int __ext4_journal_get_write_access(const char *where, unsigned int line,
                                    handle_t *handle, struct buffer_head *bh)
 {
@@ -202,6 +224,9 @@ int __ext4_journal_get_write_access(const char *where, unsigned int line,
 
        might_sleep();
 
+       if (bh->b_bdev->bd_super)
+               ext4_check_bdev_write_error(bh->b_bdev->bd_super);
+
        if (ext4_handle_valid(handle)) {
                err = jbd2_journal_get_write_access(handle, bh);
                if (err)
index 221f240..a048158 100644 (file)
@@ -100,7 +100,7 @@ static int ext4_ext_trunc_restart_fn(struct inode *inode, int *dropped)
         * i_mutex. So we can safely drop the i_data_sem here.
         */
        BUG_ON(EXT4_JOURNAL(inode) == NULL);
-       ext4_discard_preallocations(inode);
+       ext4_discard_preallocations(inode, 0);
        up_write(&EXT4_I(inode)->i_data_sem);
        *dropped = 1;
        return 0;
@@ -340,7 +340,7 @@ static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext)
         */
        if (lblock + len <= lblock)
                return 0;
-       return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len);
+       return ext4_inode_block_valid(inode, block, len);
 }
 
 static int ext4_valid_extent_idx(struct inode *inode,
@@ -348,7 +348,7 @@ static int ext4_valid_extent_idx(struct inode *inode,
 {
        ext4_fsblk_t block = ext4_idx_pblock(ext_idx);
 
-       return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, 1);
+       return ext4_inode_block_valid(inode, block, 1);
 }
 
 static int ext4_valid_extent_entries(struct inode *inode,
@@ -507,14 +507,10 @@ __read_extent_tree_block(const char *function, unsigned int line,
        }
        if (buffer_verified(bh) && !(flags & EXT4_EX_FORCE_CACHE))
                return bh;
-       if (!ext4_has_feature_journal(inode->i_sb) ||
-           (inode->i_ino !=
-            le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum))) {
-               err = __ext4_ext_check(function, line, inode,
-                                      ext_block_hdr(bh), depth, pblk);
-               if (err)
-                       goto errout;
-       }
+       err = __ext4_ext_check(function, line, inode,
+                              ext_block_hdr(bh), depth, pblk);
+       if (err)
+               goto errout;
        set_buffer_verified(bh);
        /*
         * If this is a leaf block, cache all of its entries
@@ -693,10 +689,8 @@ void ext4_ext_drop_refs(struct ext4_ext_path *path)
                return;
        depth = path->p_depth;
        for (i = 0; i <= depth; i++, path++) {
-               if (path->p_bh) {
-                       brelse(path->p_bh);
-                       path->p_bh = NULL;
-               }
+               brelse(path->p_bh);
+               path->p_bh = NULL;
        }
 }
 
@@ -1915,7 +1909,7 @@ out:
 
 /*
  * ext4_ext_insert_extent:
- * tries to merge requsted extent into the existing extent or
+ * tries to merge requested extent into the existing extent or
  * inserts requested extent as new one into the tree,
  * creating new leaf in the no-space case.
  */
@@ -3125,7 +3119,7 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
  *
  *
  * Splits extent [a, b] into two extents [a, @split) and [@split, b], states
- * of which are deterimined by split_flag.
+ * of which are determined by split_flag.
  *
  * There are two cases:
  *  a> the extent are splitted into two extent.
@@ -3650,7 +3644,7 @@ static int ext4_split_convert_extents(handle_t *handle,
                eof_block = map->m_lblk + map->m_len;
        /*
         * It is safe to convert extent to initialized via explicit
-        * zeroout only if extent is fully insde i_size or new_size.
+        * zeroout only if extent is fully inside i_size or new_size.
         */
        depth = ext_depth(inode);
        ex = path[depth].p_ext;
@@ -4272,7 +4266,7 @@ got_allocated_blocks:
                         * not a good idea to call discard here directly,
                         * but otherwise we'd need to call it every free().
                         */
-                       ext4_discard_preallocations(inode);
+                       ext4_discard_preallocations(inode, 0);
                        if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)
                                fb_flags = EXT4_FREE_BLOCKS_NO_QUOT_UPDATE;
                        ext4_free_blocks(handle, inode, NULL, newblock,
@@ -4495,7 +4489,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
        }
 
        /*
-        * Round up offset. This is not fallocate, we neet to zero out
+        * Round up offset. This is not fallocate, we need to zero out
         * blocks, so convert interior block aligned part of the range to
         * unwritten and possibly manually zero out unaligned parts of the
         * range.
@@ -5299,7 +5293,7 @@ static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
        }
 
        down_write(&EXT4_I(inode)->i_data_sem);
-       ext4_discard_preallocations(inode);
+       ext4_discard_preallocations(inode, 0);
 
        ret = ext4_es_remove_extent(inode, punch_start,
                                    EXT_MAX_BLOCKS - punch_start);
@@ -5313,7 +5307,7 @@ static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
                up_write(&EXT4_I(inode)->i_data_sem);
                goto out_stop;
        }
-       ext4_discard_preallocations(inode);
+       ext4_discard_preallocations(inode, 0);
 
        ret = ext4_ext_shift_extents(inode, handle, punch_stop,
                                     punch_stop - punch_start, SHIFT_LEFT);
@@ -5445,7 +5439,7 @@ static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
                goto out_stop;
 
        down_write(&EXT4_I(inode)->i_data_sem);
-       ext4_discard_preallocations(inode);
+       ext4_discard_preallocations(inode, 0);
 
        path = ext4_find_extent(inode, offset_lblk, NULL, 0);
        if (IS_ERR(path)) {
@@ -5579,7 +5573,7 @@ ext4_swap_extents(handle_t *handle, struct inode *inode1,
                }
                ex1 = path1[path1->p_depth].p_ext;
                ex2 = path2[path2->p_depth].p_ext;
-               /* Do we have somthing to swap ? */
+               /* Do we have something to swap ? */
                if (unlikely(!ex2 || !ex1))
                        goto finish;
 
index 129cc1d..7d61069 100644 (file)
@@ -145,10 +145,9 @@ static int ext4_release_file(struct inode *inode, struct file *filp)
        /* if we are the last writer on the inode, drop the block reservation */
        if ((filp->f_mode & FMODE_WRITE) &&
                        (atomic_read(&inode->i_writecount) == 1) &&
-                       !EXT4_I(inode)->i_reserved_data_blocks)
-       {
+                       !EXT4_I(inode)->i_reserved_data_blocks) {
                down_write(&EXT4_I(inode)->i_data_sem);
-               ext4_discard_preallocations(inode);
+               ext4_discard_preallocations(inode, 0);
                up_write(&EXT4_I(inode)->i_data_sem);
        }
        if (is_dx(inode) && filp->private_data)
@@ -428,6 +427,10 @@ restart:
         */
        if (*ilock_shared && (!IS_NOSEC(inode) || *extend ||
             !ext4_overwrite_io(inode, offset, count))) {
+               if (iocb->ki_flags & IOCB_NOWAIT) {
+                       ret = -EAGAIN;
+                       goto out;
+               }
                inode_unlock_shared(inode);
                *ilock_shared = false;
                inode_lock(inode);
@@ -812,7 +815,7 @@ out:
        return err;
 }
 
-static int ext4_file_open(struct inode * inode, struct file * filp)
+static int ext4_file_open(struct inode *inode, struct file *filp)
 {
        int ret;
 
index 3e13379..2924261 100644 (file)
@@ -233,7 +233,7 @@ static int __ext4fs_dirhash(const char *name, int len,
                break;
        case DX_HASH_HALF_MD4_UNSIGNED:
                str2hashbuf = str2hashbuf_unsigned;
-               /* fall through */
+               fallthrough;
        case DX_HASH_HALF_MD4:
                p = name;
                while (len > 0) {
@@ -247,7 +247,7 @@ static int __ext4fs_dirhash(const char *name, int len,
                break;
        case DX_HASH_TEA_UNSIGNED:
                str2hashbuf = str2hashbuf_unsigned;
-               /* fall through */
+               fallthrough;
        case DX_HASH_TEA:
                p = name;
                while (len > 0) {
index be2b66e..80c9f33 100644 (file)
@@ -696,7 +696,7 @@ static int ext4_ind_trunc_restart_fn(handle_t *handle, struct inode *inode,
         * i_mutex. So we can safely drop the i_data_sem here.
         */
        BUG_ON(EXT4_JOURNAL(inode) == NULL);
-       ext4_discard_preallocations(inode);
+       ext4_discard_preallocations(inode, 0);
        up_write(&EXT4_I(inode)->i_data_sem);
        *dropped = 1;
        return 0;
@@ -858,8 +858,7 @@ static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
        else if (ext4_should_journal_data(inode))
                flags |= EXT4_FREE_BLOCKS_FORGET;
 
-       if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), block_to_free,
-                                  count)) {
+       if (!ext4_inode_block_valid(inode, block_to_free, count)) {
                EXT4_ERROR_INODE(inode, "attempt to clear invalid "
                                 "blocks %llu len %lu",
                                 (unsigned long long) block_to_free, count);
@@ -1004,8 +1003,7 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
                        if (!nr)
                                continue;               /* A hole */
 
-                       if (!ext4_data_block_valid(EXT4_SB(inode->i_sb),
-                                                  nr, 1)) {
+                       if (!ext4_inode_block_valid(inode, nr, 1)) {
                                EXT4_ERROR_INODE(inode,
                                                 "invalid indirect mapped "
                                                 "block %lu (level %d)",
@@ -1182,21 +1180,21 @@ do_indirects:
                        ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1);
                        i_data[EXT4_IND_BLOCK] = 0;
                }
-               /* fall through */
+               fallthrough;
        case EXT4_IND_BLOCK:
                nr = i_data[EXT4_DIND_BLOCK];
                if (nr) {
                        ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2);
                        i_data[EXT4_DIND_BLOCK] = 0;
                }
-               /* fall through */
+               fallthrough;
        case EXT4_DIND_BLOCK:
                nr = i_data[EXT4_TIND_BLOCK];
                if (nr) {
                        ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3);
                        i_data[EXT4_TIND_BLOCK] = 0;
                }
-               /* fall through */
+               fallthrough;
        case EXT4_TIND_BLOCK:
                ;
        }
@@ -1436,7 +1434,7 @@ do_indirects:
                        ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1);
                        i_data[EXT4_IND_BLOCK] = 0;
                }
-               /* fall through */
+               fallthrough;
        case EXT4_IND_BLOCK:
                if (++n >= n2)
                        break;
@@ -1445,7 +1443,7 @@ do_indirects:
                        ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2);
                        i_data[EXT4_DIND_BLOCK] = 0;
                }
-               /* fall through */
+               fallthrough;
        case EXT4_DIND_BLOCK:
                if (++n >= n2)
                        break;
@@ -1454,7 +1452,7 @@ do_indirects:
                        ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3);
                        i_data[EXT4_TIND_BLOCK] = 0;
                }
-               /* fall through */
+               fallthrough;
        case EXT4_TIND_BLOCK:
                ;
        }
index c3a1ad2..75c97bc 100644 (file)
@@ -276,7 +276,7 @@ static int ext4_create_inline_data(handle_t *handle,
                len = 0;
        }
 
-       /* Insert the the xttr entry. */
+       /* Insert the xttr entry. */
        i.value = value;
        i.value_len = len;
 
@@ -1706,7 +1706,7 @@ int ext4_delete_inline_entry(handle_t *handle,
        if (err)
                goto out;
 
-       err = ext4_generic_delete_entry(handle, dir, de_del, bh,
+       err = ext4_generic_delete_entry(dir, de_del, bh,
                                        inline_start, inline_size, 0);
        if (err)
                goto out;
index 44bad4b..3a196d8 100644 (file)
@@ -383,7 +383,7 @@ void ext4_da_update_reserve_space(struct inode *inode,
         */
        if ((ei->i_reserved_data_blocks == 0) &&
            !inode_is_open_for_write(inode))
-               ext4_discard_preallocations(inode);
+               ext4_discard_preallocations(inode, 0);
 }
 
 static int __check_block_validity(struct inode *inode, const char *func,
@@ -394,8 +394,7 @@ static int __check_block_validity(struct inode *inode, const char *func,
            (inode->i_ino ==
             le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum)))
                return 0;
-       if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk,
-                                  map->m_len)) {
+       if (!ext4_inode_block_valid(inode, map->m_pblk, map->m_len)) {
                ext4_error_inode(inode, func, line, map->m_pblk,
                                 "lblock %lu mapped to illegal pblock %llu "
                                 "(length %d)", (unsigned long) map->m_lblk,
@@ -3288,7 +3287,7 @@ static int ext4_releasepage(struct page *page, gfp_t wait)
        if (PageChecked(page))
                return 0;
        if (journal)
-               return jbd2_journal_try_to_free_buffers(journal, page, wait);
+               return jbd2_journal_try_to_free_buffers(journal, page);
        else
                return try_to_free_buffers(page);
 }
@@ -4056,7 +4055,7 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
        if (stop_block > first_block) {
 
                down_write(&EXT4_I(inode)->i_data_sem);
-               ext4_discard_preallocations(inode);
+               ext4_discard_preallocations(inode, 0);
 
                ret = ext4_es_remove_extent(inode, first_block,
                                            stop_block - first_block);
@@ -4163,7 +4162,7 @@ int ext4_truncate(struct inode *inode)
        trace_ext4_truncate_enter(inode);
 
        if (!ext4_can_truncate(inode))
-               return 0;
+               goto out_trace;
 
        if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC))
                ext4_set_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE);
@@ -4172,16 +4171,14 @@ int ext4_truncate(struct inode *inode)
                int has_inline = 1;
 
                err = ext4_inline_data_truncate(inode, &has_inline);
-               if (err)
-                       return err;
-               if (has_inline)
-                       return 0;
+               if (err || has_inline)
+                       goto out_trace;
        }
 
        /* If we zero-out tail of the page, we have to create jinode for jbd2 */
        if (inode->i_size & (inode->i_sb->s_blocksize - 1)) {
                if (ext4_inode_attach_jinode(inode) < 0)
-                       return 0;
+                       goto out_trace;
        }
 
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
@@ -4190,8 +4187,10 @@ int ext4_truncate(struct inode *inode)
                credits = ext4_blocks_for_truncate(inode);
 
        handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
-       if (IS_ERR(handle))
-               return PTR_ERR(handle);
+       if (IS_ERR(handle)) {
+               err = PTR_ERR(handle);
+               goto out_trace;
+       }
 
        if (inode->i_size & (inode->i_sb->s_blocksize - 1))
                ext4_block_truncate_page(handle, mapping, inode->i_size);
@@ -4211,7 +4210,7 @@ int ext4_truncate(struct inode *inode)
 
        down_write(&EXT4_I(inode)->i_data_sem);
 
-       ext4_discard_preallocations(inode);
+       ext4_discard_preallocations(inode, 0);
 
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
                err = ext4_ext_truncate(handle, inode);
@@ -4242,6 +4241,7 @@ out_stop:
                err = err2;
        ext4_journal_stop(handle);
 
+out_trace:
        trace_ext4_truncate_exit(inode);
        return err;
 }
@@ -4760,7 +4760,7 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
 
        ret = 0;
        if (ei->i_file_acl &&
-           !ext4_data_block_valid(EXT4_SB(sb), ei->i_file_acl, 1)) {
+           !ext4_inode_block_valid(inode, ei->i_file_acl, 1)) {
                ext4_error_inode(inode, function, line, 0,
                                 "iget: bad extended attribute block %llu",
                                 ei->i_file_acl);
index 999cf6a..36eca3b 100644 (file)
@@ -202,7 +202,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
        reset_inode_seed(inode);
        reset_inode_seed(inode_bl);
 
-       ext4_discard_preallocations(inode);
+       ext4_discard_preallocations(inode, 0);
 
        err = ext4_mark_inode_dirty(handle, inode);
        if (err < 0) {
@@ -819,12 +819,12 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        switch (cmd) {
        case FS_IOC_GETFSMAP:
                return ext4_ioc_getfsmap(sb, (void __user *)arg);
-       case EXT4_IOC_GETFLAGS:
+       case FS_IOC_GETFLAGS:
                flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
                if (S_ISREG(inode->i_mode))
                        flags &= ~EXT4_PROJINHERIT_FL;
                return put_user(flags, (int __user *) arg);
-       case EXT4_IOC_SETFLAGS: {
+       case FS_IOC_SETFLAGS: {
                int err;
 
                if (!inode_owner_or_capable(inode))
@@ -1129,12 +1129,12 @@ resizefs_out:
        case EXT4_IOC_PRECACHE_EXTENTS:
                return ext4_ext_precache(inode);
 
-       case EXT4_IOC_SET_ENCRYPTION_POLICY:
+       case FS_IOC_SET_ENCRYPTION_POLICY:
                if (!ext4_has_feature_encrypt(sb))
                        return -EOPNOTSUPP;
                return fscrypt_ioctl_set_policy(filp, (const void __user *)arg);
 
-       case EXT4_IOC_GET_ENCRYPTION_PWSALT: {
+       case FS_IOC_GET_ENCRYPTION_PWSALT: {
 #ifdef CONFIG_FS_ENCRYPTION
                int err, err2;
                struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -1174,7 +1174,7 @@ resizefs_out:
                return -EOPNOTSUPP;
 #endif
        }
-       case EXT4_IOC_GET_ENCRYPTION_POLICY:
+       case FS_IOC_GET_ENCRYPTION_POLICY:
                if (!ext4_has_feature_encrypt(sb))
                        return -EOPNOTSUPP;
                return fscrypt_ioctl_get_policy(filp, (void __user *)arg);
@@ -1236,7 +1236,7 @@ resizefs_out:
        case EXT4_IOC_GET_ES_CACHE:
                return ext4_ioctl_get_es_cache(filp, arg);
 
-       case EXT4_IOC_FSGETXATTR:
+       case FS_IOC_FSGETXATTR:
        {
                struct fsxattr fa;
 
@@ -1247,7 +1247,7 @@ resizefs_out:
                        return -EFAULT;
                return 0;
        }
-       case EXT4_IOC_FSSETXATTR:
+       case FS_IOC_FSSETXATTR:
        {
                struct fsxattr fa, old_fa;
                int err;
@@ -1313,11 +1313,11 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        /* These are just misnamed, they actually get/put from/to user an int */
        switch (cmd) {
-       case EXT4_IOC32_GETFLAGS:
-               cmd = EXT4_IOC_GETFLAGS;
+       case FS_IOC32_GETFLAGS:
+               cmd = FS_IOC_GETFLAGS;
                break;
-       case EXT4_IOC32_SETFLAGS:
-               cmd = EXT4_IOC_SETFLAGS;
+       case FS_IOC32_SETFLAGS:
+               cmd = FS_IOC_SETFLAGS;
                break;
        case EXT4_IOC32_GETVERSION:
                cmd = EXT4_IOC_GETVERSION;
@@ -1361,9 +1361,9 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case EXT4_IOC_RESIZE_FS:
        case FITRIM:
        case EXT4_IOC_PRECACHE_EXTENTS:
-       case EXT4_IOC_SET_ENCRYPTION_POLICY:
-       case EXT4_IOC_GET_ENCRYPTION_PWSALT:
-       case EXT4_IOC_GET_ENCRYPTION_POLICY:
+       case FS_IOC_SET_ENCRYPTION_POLICY:
+       case FS_IOC_GET_ENCRYPTION_PWSALT:
+       case FS_IOC_GET_ENCRYPTION_POLICY:
        case FS_IOC_GET_ENCRYPTION_POLICY_EX:
        case FS_IOC_ADD_ENCRYPTION_KEY:
        case FS_IOC_REMOVE_ENCRYPTION_KEY:
@@ -1377,8 +1377,8 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case EXT4_IOC_CLEAR_ES_CACHE:
        case EXT4_IOC_GETSTATE:
        case EXT4_IOC_GET_ES_CACHE:
-       case EXT4_IOC_FSGETXATTR:
-       case EXT4_IOC_FSSETXATTR:
+       case FS_IOC_FSGETXATTR:
+       case FS_IOC_FSSETXATTR:
                break;
        default:
                return -ENOIOCTLCMD;
index c0a331e..132c118 100644 (file)
@@ -922,7 +922,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore, gfp_t gfp)
                        bh[i] = NULL;
                        continue;
                }
-               bh[i] = ext4_read_block_bitmap_nowait(sb, group);
+               bh[i] = ext4_read_block_bitmap_nowait(sb, group, false);
                if (IS_ERR(bh[i])) {
                        err = PTR_ERR(bh[i]);
                        bh[i] = NULL;
@@ -1279,9 +1279,6 @@ ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,
        e4b->bd_buddy_page = page;
        e4b->bd_buddy = page_address(page) + (poff * sb->s_blocksize);
 
-       BUG_ON(e4b->bd_bitmap_page == NULL);
-       BUG_ON(e4b->bd_buddy_page == NULL);
-
        return 0;
 
 err:
@@ -1743,10 +1740,6 @@ static void ext4_mb_use_best_found(struct ext4_allocation_context *ac,
 
 }
 
-/*
- * regular allocator, for general purposes allocation
- */
-
 static void ext4_mb_check_limits(struct ext4_allocation_context *ac,
                                        struct ext4_buddy *e4b,
                                        int finish_group)
@@ -2119,13 +2112,11 @@ static bool ext4_mb_good_group(struct ext4_allocation_context *ac,
 
        BUG_ON(cr < 0 || cr >= 4);
 
-       free = grp->bb_free;
-       if (free == 0)
-               return false;
-       if (cr <= 2 && free < ac->ac_g_ex.fe_len)
+       if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(grp)))
                return false;
 
-       if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(grp)))
+       free = grp->bb_free;
+       if (free == 0)
                return false;
 
        fragments = grp->bb_fragments;
@@ -2142,8 +2133,10 @@ static bool ext4_mb_good_group(struct ext4_allocation_context *ac,
                    ((group % flex_size) == 0))
                        return false;
 
-               if ((ac->ac_2order > ac->ac_sb->s_blocksize_bits+1) ||
-                   (free / fragments) >= ac->ac_g_ex.fe_len)
+               if (free < ac->ac_g_ex.fe_len)
+                       return false;
+
+               if (ac->ac_2order > ac->ac_sb->s_blocksize_bits+1)
                        return true;
 
                if (grp->bb_largest_free_order < ac->ac_2order)
@@ -2177,6 +2170,7 @@ static int ext4_mb_good_group_nolock(struct ext4_allocation_context *ac,
 {
        struct ext4_group_info *grp = ext4_get_group_info(ac->ac_sb, group);
        struct super_block *sb = ac->ac_sb;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
        bool should_lock = ac->ac_flags & EXT4_MB_STRICT_CHECK;
        ext4_grpblk_t free;
        int ret = 0;
@@ -2195,7 +2189,25 @@ static int ext4_mb_good_group_nolock(struct ext4_allocation_context *ac,
 
        /* We only do this if the grp has never been initialized */
        if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) {
-               ret = ext4_mb_init_group(ac->ac_sb, group, GFP_NOFS);
+               struct ext4_group_desc *gdp =
+                       ext4_get_group_desc(sb, group, NULL);
+               int ret;
+
+               /* cr=0/1 is a very optimistic search to find large
+                * good chunks almost for free.  If buddy data is not
+                * ready, then this optimization makes no sense.  But
+                * we never skip the first block group in a flex_bg,
+                * since this gets used for metadata block allocation,
+                * and we want to make sure we locate metadata blocks
+                * in the first block group in the flex_bg if possible.
+                */
+               if (cr < 2 &&
+                   (!sbi->s_log_groups_per_flex ||
+                    ((group & ((1 << sbi->s_log_groups_per_flex) - 1)) != 0)) &&
+                   !(ext4_has_group_desc_csum(sb) &&
+                     (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))))
+                       return 0;
+               ret = ext4_mb_init_group(sb, group, GFP_NOFS);
                if (ret)
                        return ret;
        }
@@ -2209,15 +2221,95 @@ out:
        return ret;
 }
 
+/*
+ * Start prefetching @nr block bitmaps starting at @group.
+ * Return the next group which needs to be prefetched.
+ */
+ext4_group_t ext4_mb_prefetch(struct super_block *sb, ext4_group_t group,
+                             unsigned int nr, int *cnt)
+{
+       ext4_group_t ngroups = ext4_get_groups_count(sb);
+       struct buffer_head *bh;
+       struct blk_plug plug;
+
+       blk_start_plug(&plug);
+       while (nr-- > 0) {
+               struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group,
+                                                                 NULL);
+               struct ext4_group_info *grp = ext4_get_group_info(sb, group);
+
+               /*
+                * Prefetch block groups with free blocks; but don't
+                * bother if it is marked uninitialized on disk, since
+                * it won't require I/O to read.  Also only try to
+                * prefetch once, so we avoid getblk() call, which can
+                * be expensive.
+                */
+               if (!EXT4_MB_GRP_TEST_AND_SET_READ(grp) &&
+                   EXT4_MB_GRP_NEED_INIT(grp) &&
+                   ext4_free_group_clusters(sb, gdp) > 0 &&
+                   !(ext4_has_group_desc_csum(sb) &&
+                     (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)))) {
+                       bh = ext4_read_block_bitmap_nowait(sb, group, true);
+                       if (bh && !IS_ERR(bh)) {
+                               if (!buffer_uptodate(bh) && cnt)
+                                       (*cnt)++;
+                               brelse(bh);
+                       }
+               }
+               if (++group >= ngroups)
+                       group = 0;
+       }
+       blk_finish_plug(&plug);
+       return group;
+}
+
+/*
+ * Prefetching reads the block bitmap into the buffer cache; but we
+ * need to make sure that the buddy bitmap in the page cache has been
+ * initialized.  Note that ext4_mb_init_group() will block if the I/O
+ * is not yet completed, or indeed if it was not initiated by
+ * ext4_mb_prefetch did not start the I/O.
+ *
+ * TODO: We should actually kick off the buddy bitmap setup in a work
+ * queue when the buffer I/O is completed, so that we don't block
+ * waiting for the block allocation bitmap read to finish when
+ * ext4_mb_prefetch_fini is called from ext4_mb_regular_allocator().
+ */
+void ext4_mb_prefetch_fini(struct super_block *sb, ext4_group_t group,
+                          unsigned int nr)
+{
+       while (nr-- > 0) {
+               struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group,
+                                                                 NULL);
+               struct ext4_group_info *grp = ext4_get_group_info(sb, group);
+
+               if (!group)
+                       group = ext4_get_groups_count(sb);
+               group--;
+               grp = ext4_get_group_info(sb, group);
+
+               if (EXT4_MB_GRP_NEED_INIT(grp) &&
+                   ext4_free_group_clusters(sb, gdp) > 0 &&
+                   !(ext4_has_group_desc_csum(sb) &&
+                     (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)))) {
+                       if (ext4_mb_init_group(sb, group, GFP_NOFS))
+                               break;
+               }
+       }
+}
+
 static noinline_for_stack int
 ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
 {
-       ext4_group_t ngroups, group, i;
+       ext4_group_t prefetch_grp = 0, ngroups, group, i;
        int cr = -1;
        int err = 0, first_err = 0;
+       unsigned int nr = 0, prefetch_ios = 0;
        struct ext4_sb_info *sbi;
        struct super_block *sb;
        struct ext4_buddy e4b;
+       int lost;
 
        sb = ac->ac_sb;
        sbi = EXT4_SB(sb);
@@ -2237,8 +2329,8 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
                goto out;
 
        /*
-        * ac->ac2_order is set only if the fe_len is a power of 2
-        * if ac2_order is set we also set criteria to 0 so that we
+        * ac->ac_2order is set only if the fe_len is a power of 2
+        * if ac->ac_2order is set we also set criteria to 0 so that we
         * try exact allocation using buddy.
         */
        i = fls(ac->ac_g_ex.fe_len);
@@ -2282,6 +2374,7 @@ repeat:
                 * from the goal value specified
                 */
                group = ac->ac_g_ex.fe_group;
+               prefetch_grp = group;
 
                for (i = 0; i < ngroups; group++, i++) {
                        int ret = 0;
@@ -2293,6 +2386,29 @@ repeat:
                        if (group >= ngroups)
                                group = 0;
 
+                       /*
+                        * Batch reads of the block allocation bitmaps
+                        * to get multiple READs in flight; limit
+                        * prefetching at cr=0/1, otherwise mballoc can
+                        * spend a lot of time loading imperfect groups
+                        */
+                       if ((prefetch_grp == group) &&
+                           (cr > 1 ||
+                            prefetch_ios < sbi->s_mb_prefetch_limit)) {
+                               unsigned int curr_ios = prefetch_ios;
+
+                               nr = sbi->s_mb_prefetch;
+                               if (ext4_has_feature_flex_bg(sb)) {
+                                       nr = (group / sbi->s_mb_prefetch) *
+                                               sbi->s_mb_prefetch;
+                                       nr = nr + sbi->s_mb_prefetch - group;
+                               }
+                               prefetch_grp = ext4_mb_prefetch(sb, group,
+                                                       nr, &prefetch_ios);
+                               if (prefetch_ios == curr_ios)
+                                       nr = 0;
+                       }
+
                        /* This now checks without needing the buddy page */
                        ret = ext4_mb_good_group_nolock(ac, group, cr);
                        if (ret <= 0) {
@@ -2341,22 +2457,24 @@ repeat:
                 * We've been searching too long. Let's try to allocate
                 * the best chunk we've found so far
                 */
-
                ext4_mb_try_best_found(ac, &e4b);
                if (ac->ac_status != AC_STATUS_FOUND) {
                        /*
                         * Someone more lucky has already allocated it.
                         * The only thing we can do is just take first
                         * found block(s)
-                       printk(KERN_DEBUG "EXT4-fs: someone won our chunk\n");
                         */
+                       lost = atomic_inc_return(&sbi->s_mb_lost_chunks);
+                       mb_debug(sb, "lost chunk, group: %u, start: %d, len: %d, lost: %d\n",
+                                ac->ac_b_ex.fe_group, ac->ac_b_ex.fe_start,
+                                ac->ac_b_ex.fe_len, lost);
+
                        ac->ac_b_ex.fe_group = 0;
                        ac->ac_b_ex.fe_start = 0;
                        ac->ac_b_ex.fe_len = 0;
                        ac->ac_status = AC_STATUS_CONTINUE;
                        ac->ac_flags |= EXT4_MB_HINT_FIRST;
                        cr = 3;
-                       atomic_inc(&sbi->s_mb_lost_chunks);
                        goto repeat;
                }
        }
@@ -2367,6 +2485,10 @@ out:
        mb_debug(sb, "Best len %d, origin len %d, ac_status %u, ac_flags 0x%x, cr %d ret %d\n",
                 ac->ac_b_ex.fe_len, ac->ac_o_ex.fe_len, ac->ac_status,
                 ac->ac_flags, cr, err);
+
+       if (nr)
+               ext4_mb_prefetch_fini(sb, prefetch_grp, nr);
+
        return err;
 }
 
@@ -2439,7 +2561,7 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
        for (i = 0; i <= 13; i++)
                seq_printf(seq, " %-5u", i <= blocksize_bits + 1 ?
                                sg.info.bb_counters[i] : 0);
-       seq_printf(seq, " ]\n");
+       seq_puts(seq, " ]\n");
 
        return 0;
 }
@@ -2613,6 +2735,26 @@ static int ext4_mb_init_backend(struct super_block *sb)
                        goto err_freebuddy;
        }
 
+       if (ext4_has_feature_flex_bg(sb)) {
+               /* a single flex group is supposed to be read by a single IO */
+               sbi->s_mb_prefetch = 1 << sbi->s_es->s_log_groups_per_flex;
+               sbi->s_mb_prefetch *= 8; /* 8 prefetch IOs in flight at most */
+       } else {
+               sbi->s_mb_prefetch = 32;
+       }
+       if (sbi->s_mb_prefetch > ext4_get_groups_count(sb))
+               sbi->s_mb_prefetch = ext4_get_groups_count(sb);
+       /* now many real IOs to prefetch within a single allocation at cr=0
+        * given cr=0 is an CPU-related optimization we shouldn't try to
+        * load too many groups, at some point we should start to use what
+        * we've got in memory.
+        * with an average random access time 5ms, it'd take a second to get
+        * 200 groups (* N with flex_bg), so let's make this limit 4
+        */
+       sbi->s_mb_prefetch_limit = sbi->s_mb_prefetch * 4;
+       if (sbi->s_mb_prefetch_limit > ext4_get_groups_count(sb))
+               sbi->s_mb_prefetch_limit = ext4_get_groups_count(sb);
+
        return 0;
 
 err_freebuddy:
@@ -2736,6 +2878,7 @@ int ext4_mb_init(struct super_block *sb)
        sbi->s_mb_stats = MB_DEFAULT_STATS;
        sbi->s_mb_stream_request = MB_DEFAULT_STREAM_THRESHOLD;
        sbi->s_mb_order2_reqs = MB_DEFAULT_ORDER2_REQS;
+       sbi->s_mb_max_inode_prealloc = MB_DEFAULT_MAX_INODE_PREALLOC;
        /*
         * The default group preallocation is 512, which for 4k block
         * sizes translates to 2 megabytes.  However for bigalloc file
@@ -3090,7 +3233,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
        block = ext4_grp_offs_to_block(sb, &ac->ac_b_ex);
 
        len = EXT4_C2B(sbi, ac->ac_b_ex.fe_len);
-       if (!ext4_data_block_valid(sbi, block, len)) {
+       if (!ext4_inode_block_valid(ac->ac_inode, block, len)) {
                ext4_error(sb, "Allocating blocks %llu-%llu which overlap "
                           "fs metadata", block, block+len);
                /* File system mounted not to panic on error
@@ -3674,6 +3817,26 @@ void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
        mb_debug(sb, "preallocated %d for group %u\n", preallocated, group);
 }
 
+static void ext4_mb_mark_pa_deleted(struct super_block *sb,
+                                   struct ext4_prealloc_space *pa)
+{
+       struct ext4_inode_info *ei;
+
+       if (pa->pa_deleted) {
+               ext4_warning(sb, "deleted pa, type:%d, pblk:%llu, lblk:%u, len:%d\n",
+                            pa->pa_type, pa->pa_pstart, pa->pa_lstart,
+                            pa->pa_len);
+               return;
+       }
+
+       pa->pa_deleted = 1;
+
+       if (pa->pa_type == MB_INODE_PA) {
+               ei = EXT4_I(pa->pa_inode);
+               atomic_dec(&ei->i_prealloc_active);
+       }
+}
+
 static void ext4_mb_pa_callback(struct rcu_head *head)
 {
        struct ext4_prealloc_space *pa;
@@ -3706,7 +3869,7 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *ac,
                return;
        }
 
-       pa->pa_deleted = 1;
+       ext4_mb_mark_pa_deleted(sb, pa);
        spin_unlock(&pa->pa_lock);
 
        grp_blk = pa->pa_pstart;
@@ -3830,6 +3993,7 @@ ext4_mb_new_inode_pa(struct ext4_allocation_context *ac)
        spin_lock(pa->pa_obj_lock);
        list_add_rcu(&pa->pa_inode_list, &ei->i_prealloc_list);
        spin_unlock(pa->pa_obj_lock);
+       atomic_inc(&ei->i_prealloc_active);
 }
 
 /*
@@ -4040,7 +4204,7 @@ repeat:
                }
 
                /* seems this one can be freed ... */
-               pa->pa_deleted = 1;
+               ext4_mb_mark_pa_deleted(sb, pa);
 
                /* we can trust pa_free ... */
                free += pa->pa_free;
@@ -4103,7 +4267,7 @@ out_dbg:
  *
  * FIXME!! Make sure it is valid at all the call sites
  */
-void ext4_discard_preallocations(struct inode *inode)
+void ext4_discard_preallocations(struct inode *inode, unsigned int needed)
 {
        struct ext4_inode_info *ei = EXT4_I(inode);
        struct super_block *sb = inode->i_sb;
@@ -4121,15 +4285,19 @@ void ext4_discard_preallocations(struct inode *inode)
 
        mb_debug(sb, "discard preallocation for inode %lu\n",
                 inode->i_ino);
-       trace_ext4_discard_preallocations(inode);
+       trace_ext4_discard_preallocations(inode,
+                       atomic_read(&ei->i_prealloc_active), needed);
 
        INIT_LIST_HEAD(&list);
 
+       if (needed == 0)
+               needed = UINT_MAX;
+
 repeat:
        /* first, collect all pa's in the inode */
        spin_lock(&ei->i_prealloc_lock);
-       while (!list_empty(&ei->i_prealloc_list)) {
-               pa = list_entry(ei->i_prealloc_list.next,
+       while (!list_empty(&ei->i_prealloc_list) && needed) {
+               pa = list_entry(ei->i_prealloc_list.prev,
                                struct ext4_prealloc_space, pa_inode_list);
                BUG_ON(pa->pa_obj_lock != &ei->i_prealloc_lock);
                spin_lock(&pa->pa_lock);
@@ -4146,10 +4314,11 @@ repeat:
 
                }
                if (pa->pa_deleted == 0) {
-                       pa->pa_deleted = 1;
+                       ext4_mb_mark_pa_deleted(sb, pa);
                        spin_unlock(&pa->pa_lock);
                        list_del_rcu(&pa->pa_inode_list);
                        list_add(&pa->u.pa_tmp_list, &list);
+                       needed--;
                        continue;
                }
 
@@ -4399,7 +4568,7 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac,
        ac->ac_g_ex = ac->ac_o_ex;
        ac->ac_flags = ar->flags;
 
-       /* we have to define context: we'll we work with a file or
+       /* we have to define context: we'll work with a file or
         * locality group. this is a policy, actually */
        ext4_mb_group_or_file(ac);
 
@@ -4450,7 +4619,7 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
                BUG_ON(pa->pa_type != MB_GROUP_PA);
 
                /* seems this one can be freed ... */
-               pa->pa_deleted = 1;
+               ext4_mb_mark_pa_deleted(sb, pa);
                spin_unlock(&pa->pa_lock);
 
                list_del_rcu(&pa->pa_inode_list);
@@ -4548,11 +4717,30 @@ static void ext4_mb_add_n_trim(struct ext4_allocation_context *ac)
        return ;
 }
 
+/*
+ * if per-inode prealloc list is too long, trim some PA
+ */
+static void ext4_mb_trim_inode_pa(struct inode *inode)
+{
+       struct ext4_inode_info *ei = EXT4_I(inode);
+       struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+       int count, delta;
+
+       count = atomic_read(&ei->i_prealloc_active);
+       delta = (sbi->s_mb_max_inode_prealloc >> 2) + 1;
+       if (count > sbi->s_mb_max_inode_prealloc + delta) {
+               count -= sbi->s_mb_max_inode_prealloc;
+               ext4_discard_preallocations(inode, count);
+       }
+}
+
 /*
  * release all resource we used in allocation
  */
 static int ext4_mb_release_context(struct ext4_allocation_context *ac)
 {
+       struct inode *inode = ac->ac_inode;
+       struct ext4_inode_info *ei = EXT4_I(inode);
        struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb);
        struct ext4_prealloc_space *pa = ac->ac_pa;
        if (pa) {
@@ -4564,21 +4752,31 @@ static int ext4_mb_release_context(struct ext4_allocation_context *ac)
                        pa->pa_free -= ac->ac_b_ex.fe_len;
                        pa->pa_len -= ac->ac_b_ex.fe_len;
                        spin_unlock(&pa->pa_lock);
+
+                       /*
+                        * We want to add the pa to the right bucket.
+                        * Remove it from the list and while adding
+                        * make sure the list to which we are adding
+                        * doesn't grow big.
+                        */
+                       if (likely(pa->pa_free)) {
+                               spin_lock(pa->pa_obj_lock);
+                               list_del_rcu(&pa->pa_inode_list);
+                               spin_unlock(pa->pa_obj_lock);
+                               ext4_mb_add_n_trim(ac);
+                       }
                }
-       }
-       if (pa) {
-               /*
-                * We want to add the pa to the right bucket.
-                * Remove it from the list and while adding
-                * make sure the list to which we are adding
-                * doesn't grow big.
-                */
-               if ((pa->pa_type == MB_GROUP_PA) && likely(pa->pa_free)) {
+
+               if (pa->pa_type == MB_INODE_PA) {
+                       /*
+                        * treat per-inode prealloc list as a lru list, then try
+                        * to trim the least recently used PA.
+                        */
                        spin_lock(pa->pa_obj_lock);
-                       list_del_rcu(&pa->pa_inode_list);
+                       list_move(&pa->pa_inode_list, &ei->i_prealloc_list);
                        spin_unlock(pa->pa_obj_lock);
-                       ext4_mb_add_n_trim(ac);
                }
+
                ext4_mb_put_pa(ac, ac->ac_sb, pa);
        }
        if (ac->ac_bitmap_page)
@@ -4588,6 +4786,7 @@ static int ext4_mb_release_context(struct ext4_allocation_context *ac)
        if (ac->ac_flags & EXT4_MB_HINT_GROUP_ALLOC)
                mutex_unlock(&ac->ac_lg->lg_mutex);
        ext4_mb_collect_stats(ac);
+       ext4_mb_trim_inode_pa(inode);
        return 0;
 }
 
@@ -4915,7 +5114,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
 
        sbi = EXT4_SB(sb);
        if (!(flags & EXT4_FREE_BLOCKS_VALIDATED) &&
-           !ext4_data_block_valid(sbi, block, count)) {
+           !ext4_inode_block_valid(inode, block, count)) {
                ext4_error(sb, "Freeing blocks not in datazone - "
                           "block = %llu, count = %lu", block, count);
                goto error_return;
index 6b4d17c..e75b474 100644 (file)
  */
 #define MB_DEFAULT_GROUP_PREALLOC      512
 
+/*
+ * maximum length of inode prealloc list
+ */
+#define MB_DEFAULT_MAX_INODE_PREALLOC  512
 
 struct ext4_free_data {
        /* this links the free block information from sb_info */
index 1ed86fb..0d601b8 100644 (file)
@@ -686,8 +686,8 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk,
 
 out:
        if (*moved_len) {
-               ext4_discard_preallocations(orig_inode);
-               ext4_discard_preallocations(donor_inode);
+               ext4_discard_preallocations(orig_inode, 0);
+               ext4_discard_preallocations(donor_inode, 0);
        }
 
        ext4_ext_drop_refs(path);
index 56738b5..153a9fb 100644 (file)
@@ -1396,8 +1396,8 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
                    ext4_match(dir, fname, de)) {
                        /* found a match - just to be sure, do
                         * a full check */
-                       if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data,
-                                                bh->b_size, offset))
+                       if (ext4_check_dir_entry(dir, NULL, de, bh, search_buf,
+                                                buf_size, offset))
                                return -1;
                        *res_dir = de;
                        return 1;
@@ -1858,7 +1858,7 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
                             blocksize, hinfo, map);
        map -= count;
        dx_sort_map(map, count);
-       /* Split the existing block in the middle, size-wise */
+       /* Ensure that neither split block is over half full */
        size = 0;
        move = 0;
        for (i = count-1; i >= 0; i--) {
@@ -1868,8 +1868,18 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
                size += map[i].size;
                move++;
        }
-       /* map index at which we will split */
-       split = count - move;
+       /*
+        * map index at which we will split
+        *
+        * If the sum of active entries didn't exceed half the block size, just
+        * split it in half by count; each resulting block will have at least
+        * half the space free.
+        */
+       if (i > 0)
+               split = count - move;
+       else
+               split = count/2;
+
        hash2 = map[split].hash;
        continued = hash2 == map[split - 1].hash;
        dxtrace(printk(KERN_INFO "Split block %lu at %x, %i/%i\n",
@@ -2455,8 +2465,7 @@ cleanup:
  * ext4_generic_delete_entry deletes a directory entry by merging it
  * with the previous entry
  */
-int ext4_generic_delete_entry(handle_t *handle,
-                             struct inode *dir,
+int ext4_generic_delete_entry(struct inode *dir,
                              struct ext4_dir_entry_2 *de_del,
                              struct buffer_head *bh,
                              void *entry_buf,
@@ -2472,7 +2481,7 @@ int ext4_generic_delete_entry(handle_t *handle,
        de = (struct ext4_dir_entry_2 *)entry_buf;
        while (i < buf_size - csum_size) {
                if (ext4_check_dir_entry(dir, NULL, de, bh,
-                                        bh->b_data, bh->b_size, i))
+                                        entry_buf, buf_size, i))
                        return -EFSCORRUPTED;
                if (de == de_del)  {
                        if (pde)
@@ -2517,8 +2526,7 @@ static int ext4_delete_entry(handle_t *handle,
        if (unlikely(err))
                goto out;
 
-       err = ext4_generic_delete_entry(handle, dir, de_del,
-                                       bh, bh->b_data,
+       err = ext4_generic_delete_entry(dir, de_del, bh, bh->b_data,
                                        dir->i_sb->s_blocksize, csum_size);
        if (err)
                goto out;
@@ -3193,30 +3201,33 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
         * in separate transaction */
        retval = dquot_initialize(dir);
        if (retval)
-               return retval;
+               goto out_trace;
        retval = dquot_initialize(d_inode(dentry));
        if (retval)
-               return retval;
+               goto out_trace;
 
-       retval = -ENOENT;
        bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
-       if (IS_ERR(bh))
-               return PTR_ERR(bh);
-       if (!bh)
-               goto end_unlink;
+       if (IS_ERR(bh)) {
+               retval = PTR_ERR(bh);
+               goto out_trace;
+       }
+       if (!bh) {
+               retval = -ENOENT;
+               goto out_trace;
+       }
 
        inode = d_inode(dentry);
 
-       retval = -EFSCORRUPTED;
-       if (le32_to_cpu(de->inode) != inode->i_ino)
-               goto end_unlink;
+       if (le32_to_cpu(de->inode) != inode->i_ino) {
+               retval = -EFSCORRUPTED;
+               goto out_bh;
+       }
 
        handle = ext4_journal_start(dir, EXT4_HT_DIR,
                                    EXT4_DATA_TRANS_BLOCKS(dir->i_sb));
        if (IS_ERR(handle)) {
                retval = PTR_ERR(handle);
-               handle = NULL;
-               goto end_unlink;
+               goto out_bh;
        }
 
        if (IS_DIRSYNC(dir))
@@ -3224,12 +3235,12 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 
        retval = ext4_delete_entry(handle, dir, de, bh);
        if (retval)
-               goto end_unlink;
+               goto out_handle;
        dir->i_ctime = dir->i_mtime = current_time(dir);
        ext4_update_dx_flag(dir);
        retval = ext4_mark_inode_dirty(handle, dir);
        if (retval)
-               goto end_unlink;
+               goto out_handle;
        if (inode->i_nlink == 0)
                ext4_warning_inode(inode, "Deleting file '%.*s' with no links",
                                   dentry->d_name.len, dentry->d_name.name);
@@ -3251,10 +3262,11 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
                d_invalidate(dentry);
 #endif
 
-end_unlink:
+out_handle:
+       ext4_journal_stop(handle);
+out_bh:
        brelse(bh);
-       if (handle)
-               ext4_journal_stop(handle);
+out_trace:
        trace_ext4_unlink_exit(dentry, retval);
        return retval;
 }
index f2df2db..f014c5e 100644 (file)
@@ -140,7 +140,7 @@ static void bio_post_read_processing(struct bio_post_read_ctx *ctx)
                        return;
                }
                ctx->cur_step++;
-               /* fall-through */
+               fallthrough;
        case STEP_VERITY:
                if (ctx->enabled_steps & (1 << STEP_VERITY)) {
                        INIT_WORK(&ctx->work, verity_work);
@@ -148,7 +148,7 @@ static void bio_post_read_processing(struct bio_post_read_ctx *ctx)
                        return;
                }
                ctx->cur_step++;
-               /* fall-through */
+               fallthrough;
        default:
                __read_end_io(ctx->bio);
        }
index 0907f90..ea425b4 100644 (file)
@@ -66,10 +66,10 @@ static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
                             unsigned long journal_devnum);
 static int ext4_show_options(struct seq_file *seq, struct dentry *root);
 static int ext4_commit_super(struct super_block *sb, int sync);
-static void ext4_mark_recovery_complete(struct super_block *sb,
+static int ext4_mark_recovery_complete(struct super_block *sb,
                                        struct ext4_super_block *es);
-static void ext4_clear_journal_err(struct super_block *sb,
-                                  struct ext4_super_block *es);
+static int ext4_clear_journal_err(struct super_block *sb,
+                                 struct ext4_super_block *es);
 static int ext4_sync_fs(struct super_block *sb, int wait);
 static int ext4_remount(struct super_block *sb, int *flags, char *data);
 static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf);
@@ -744,6 +744,7 @@ void __ext4_msg(struct super_block *sb,
        struct va_format vaf;
        va_list args;
 
+       atomic_inc(&EXT4_SB(sb)->s_msg_count);
        if (!___ratelimit(&(EXT4_SB(sb)->s_msg_ratelimit_state), "EXT4-fs"))
                return;
 
@@ -754,9 +755,12 @@ void __ext4_msg(struct super_block *sb,
        va_end(args);
 }
 
-#define ext4_warning_ratelimit(sb)                                     \
-               ___ratelimit(&(EXT4_SB(sb)->s_warning_ratelimit_state), \
-                            "EXT4-fs warning")
+static int ext4_warning_ratelimit(struct super_block *sb)
+{
+       atomic_inc(&EXT4_SB(sb)->s_warning_count);
+       return ___ratelimit(&(EXT4_SB(sb)->s_warning_ratelimit_state),
+                           "EXT4-fs warning");
+}
 
 void __ext4_warning(struct super_block *sb, const char *function,
                    unsigned int line, const char *fmt, ...)
@@ -1123,6 +1127,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        inode_set_iversion(&ei->vfs_inode, 1);
        spin_lock_init(&ei->i_raw_lock);
        INIT_LIST_HEAD(&ei->i_prealloc_list);
+       atomic_set(&ei->i_prealloc_active, 0);
        spin_lock_init(&ei->i_prealloc_lock);
        ext4_es_init_tree(&ei->i_es_tree);
        rwlock_init(&ei->i_es_lock);
@@ -1216,7 +1221,7 @@ void ext4_clear_inode(struct inode *inode)
 {
        invalidate_inode_buffers(inode);
        clear_inode(inode);
-       ext4_discard_preallocations(inode);
+       ext4_discard_preallocations(inode, 0);
        ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
        dquot_drop(inode);
        if (EXT4_I(inode)->jinode) {
@@ -1288,8 +1293,8 @@ static int bdev_try_to_free_page(struct super_block *sb, struct page *page,
        if (!page_has_buffers(page))
                return 0;
        if (journal)
-               return jbd2_journal_try_to_free_buffers(journal, page,
-                                               wait & ~__GFP_DIRECT_RECLAIM);
+               return jbd2_journal_try_to_free_buffers(journal, page);
+
        return try_to_free_buffers(page);
 }
 
@@ -1522,6 +1527,7 @@ enum {
        Opt_dioread_nolock, Opt_dioread_lock,
        Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
        Opt_max_dir_size_kb, Opt_nojournal_checksum, Opt_nombcache,
+       Opt_prefetch_block_bitmaps,
 };
 
 static const match_table_t tokens = {
@@ -1614,6 +1620,7 @@ static const match_table_t tokens = {
        {Opt_inlinecrypt, "inlinecrypt"},
        {Opt_nombcache, "nombcache"},
        {Opt_nombcache, "no_mbcache"},  /* for backward compatibility */
+       {Opt_prefetch_block_bitmaps, "prefetch_block_bitmaps"},
        {Opt_removed, "check=none"},    /* mount option from ext2/3 */
        {Opt_removed, "nocheck"},       /* mount option from ext2/3 */
        {Opt_removed, "reservation"},   /* mount option from ext2/3 */
@@ -1831,6 +1838,8 @@ static const struct mount_opts {
        {Opt_max_dir_size_kb, 0, MOPT_GTE0},
        {Opt_test_dummy_encryption, 0, MOPT_STRING},
        {Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET},
+       {Opt_prefetch_block_bitmaps, EXT4_MOUNT_PREFETCH_BLOCK_BITMAPS,
+        MOPT_SET},
        {Opt_err, 0, 0}
 };
 
@@ -3213,15 +3222,34 @@ static void print_daily_error_info(struct timer_list *t)
 static int ext4_run_li_request(struct ext4_li_request *elr)
 {
        struct ext4_group_desc *gdp = NULL;
-       ext4_group_t group, ngroups;
-       struct super_block *sb;
+       struct super_block *sb = elr->lr_super;
+       ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
+       ext4_group_t group = elr->lr_next_group;
        unsigned long timeout = 0;
+       unsigned int prefetch_ios = 0;
        int ret = 0;
 
-       sb = elr->lr_super;
-       ngroups = EXT4_SB(sb)->s_groups_count;
+       if (elr->lr_mode == EXT4_LI_MODE_PREFETCH_BBITMAP) {
+               elr->lr_next_group = ext4_mb_prefetch(sb, group,
+                               EXT4_SB(sb)->s_mb_prefetch, &prefetch_ios);
+               if (prefetch_ios)
+                       ext4_mb_prefetch_fini(sb, elr->lr_next_group,
+                                             prefetch_ios);
+               trace_ext4_prefetch_bitmaps(sb, group, elr->lr_next_group,
+                                           prefetch_ios);
+               if (group >= elr->lr_next_group) {
+                       ret = 1;
+                       if (elr->lr_first_not_zeroed != ngroups &&
+                           !sb_rdonly(sb) && test_opt(sb, INIT_INODE_TABLE)) {
+                               elr->lr_next_group = elr->lr_first_not_zeroed;
+                               elr->lr_mode = EXT4_LI_MODE_ITABLE;
+                               ret = 0;
+                       }
+               }
+               return ret;
+       }
 
-       for (group = elr->lr_next_group; group < ngroups; group++) {
+       for (; group < ngroups; group++) {
                gdp = ext4_get_group_desc(sb, group, NULL);
                if (!gdp) {
                        ret = 1;
@@ -3239,9 +3267,10 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
                timeout = jiffies;
                ret = ext4_init_inode_table(sb, group,
                                            elr->lr_timeout ? 0 : 1);
+               trace_ext4_lazy_itable_init(sb, group);
                if (elr->lr_timeout == 0) {
                        timeout = (jiffies - timeout) *
-                                 elr->lr_sbi->s_li_wait_mult;
+                               EXT4_SB(elr->lr_super)->s_li_wait_mult;
                        elr->lr_timeout = timeout;
                }
                elr->lr_next_sched = jiffies + elr->lr_timeout;
@@ -3256,15 +3285,11 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
  */
 static void ext4_remove_li_request(struct ext4_li_request *elr)
 {
-       struct ext4_sb_info *sbi;
-
        if (!elr)
                return;
 
-       sbi = elr->lr_sbi;
-
        list_del(&elr->lr_request);
-       sbi->s_li_request = NULL;
+       EXT4_SB(elr->lr_super)->s_li_request = NULL;
        kfree(elr);
 }
 
@@ -3473,7 +3498,6 @@ static int ext4_li_info_new(void)
 static struct ext4_li_request *ext4_li_request_new(struct super_block *sb,
                                            ext4_group_t start)
 {
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct ext4_li_request *elr;
 
        elr = kzalloc(sizeof(*elr), GFP_KERNEL);
@@ -3481,8 +3505,13 @@ static struct ext4_li_request *ext4_li_request_new(struct super_block *sb,
                return NULL;
 
        elr->lr_super = sb;
-       elr->lr_sbi = sbi;
-       elr->lr_next_group = start;
+       elr->lr_first_not_zeroed = start;
+       if (test_opt(sb, PREFETCH_BLOCK_BITMAPS))
+               elr->lr_mode = EXT4_LI_MODE_PREFETCH_BBITMAP;
+       else {
+               elr->lr_mode = EXT4_LI_MODE_ITABLE;
+               elr->lr_next_group = start;
+       }
 
        /*
         * Randomize first schedule time of the request to
@@ -3512,8 +3541,9 @@ int ext4_register_li_request(struct super_block *sb,
                goto out;
        }
 
-       if (first_not_zeroed == ngroups || sb_rdonly(sb) ||
-           !test_opt(sb, INIT_INODE_TABLE))
+       if (!test_opt(sb, PREFETCH_BLOCK_BITMAPS) &&
+           (first_not_zeroed == ngroups || sb_rdonly(sb) ||
+            !test_opt(sb, INIT_INODE_TABLE)))
                goto out;
 
        elr = ext4_li_request_new(sb, first_not_zeroed);
@@ -4710,11 +4740,13 @@ no_journal:
 
        ext4_set_resv_clusters(sb);
 
-       err = ext4_setup_system_zone(sb);
-       if (err) {
-               ext4_msg(sb, KERN_ERR, "failed to initialize system "
-                        "zone (%d)", err);
-               goto failed_mount4a;
+       if (test_opt(sb, BLOCK_VALIDITY)) {
+               err = ext4_setup_system_zone(sb);
+               if (err) {
+                       ext4_msg(sb, KERN_ERR, "failed to initialize system "
+                                "zone (%d)", err);
+                       goto failed_mount4a;
+               }
        }
 
        ext4_ext_init(sb);
@@ -4777,12 +4809,23 @@ no_journal:
        }
 #endif  /* CONFIG_QUOTA */
 
+       /*
+        * Save the original bdev mapping's wb_err value which could be
+        * used to detect the metadata async write error.
+        */
+       spin_lock_init(&sbi->s_bdev_wb_lock);
+       if (!sb_rdonly(sb))
+               errseq_check_and_advance(&sb->s_bdev->bd_inode->i_mapping->wb_err,
+                                        &sbi->s_bdev_wb_err);
+       sb->s_bdev->bd_super = sb;
        EXT4_SB(sb)->s_mount_state |= EXT4_ORPHAN_FS;
        ext4_orphan_cleanup(sb, es);
        EXT4_SB(sb)->s_mount_state &= ~EXT4_ORPHAN_FS;
        if (needs_recovery) {
                ext4_msg(sb, KERN_INFO, "recovery complete");
-               ext4_mark_recovery_complete(sb, es);
+               err = ext4_mark_recovery_complete(sb, es);
+               if (err)
+                       goto failed_mount8;
        }
        if (EXT4_SB(sb)->s_journal) {
                if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
@@ -4816,6 +4859,8 @@ no_journal:
        ratelimit_state_init(&sbi->s_err_ratelimit_state, 5 * HZ, 10);
        ratelimit_state_init(&sbi->s_warning_ratelimit_state, 5 * HZ, 10);
        ratelimit_state_init(&sbi->s_msg_ratelimit_state, 5 * HZ, 10);
+       atomic_set(&sbi->s_warning_count, 0);
+       atomic_set(&sbi->s_msg_count, 0);
 
        kfree(orig_data);
        return 0;
@@ -4825,10 +4870,8 @@ cantfind_ext4:
                ext4_msg(sb, KERN_ERR, "VFS: Can't find ext4 filesystem");
        goto failed_mount;
 
-#ifdef CONFIG_QUOTA
 failed_mount8:
        ext4_unregister_sysfs(sb);
-#endif
 failed_mount7:
        ext4_unregister_li_request(sb);
 failed_mount6:
@@ -4968,7 +5011,8 @@ static journal_t *ext4_get_journal(struct super_block *sb,
        struct inode *journal_inode;
        journal_t *journal;
 
-       BUG_ON(!ext4_has_feature_journal(sb));
+       if (WARN_ON_ONCE(!ext4_has_feature_journal(sb)))
+               return NULL;
 
        journal_inode = ext4_get_journal_inode(sb, journal_inum);
        if (!journal_inode)
@@ -4998,7 +5042,8 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
        struct ext4_super_block *es;
        struct block_device *bdev;
 
-       BUG_ON(!ext4_has_feature_journal(sb));
+       if (WARN_ON_ONCE(!ext4_has_feature_journal(sb)))
+               return NULL;
 
        bdev = ext4_blkdev_get(j_dev, sb);
        if (bdev == NULL)
@@ -5089,8 +5134,10 @@ static int ext4_load_journal(struct super_block *sb,
        dev_t journal_dev;
        int err = 0;
        int really_read_only;
+       int journal_dev_ro;
 
-       BUG_ON(!ext4_has_feature_journal(sb));
+       if (WARN_ON_ONCE(!ext4_has_feature_journal(sb)))
+               return -EFSCORRUPTED;
 
        if (journal_devnum &&
            journal_devnum != le32_to_cpu(es->s_journal_dev)) {
@@ -5100,7 +5147,31 @@ static int ext4_load_journal(struct super_block *sb,
        } else
                journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev));
 
-       really_read_only = bdev_read_only(sb->s_bdev);
+       if (journal_inum && journal_dev) {
+               ext4_msg(sb, KERN_ERR,
+                        "filesystem has both journal inode and journal device!");
+               return -EINVAL;
+       }
+
+       if (journal_inum) {
+               journal = ext4_get_journal(sb, journal_inum);
+               if (!journal)
+                       return -EINVAL;
+       } else {
+               journal = ext4_get_dev_journal(sb, journal_dev);
+               if (!journal)
+                       return -EINVAL;
+       }
+
+       journal_dev_ro = bdev_read_only(journal->j_dev);
+       really_read_only = bdev_read_only(sb->s_bdev) | journal_dev_ro;
+
+       if (journal_dev_ro && !sb_rdonly(sb)) {
+               ext4_msg(sb, KERN_ERR,
+                        "journal device read-only, try mounting with '-o ro'");
+               err = -EROFS;
+               goto err_out;
+       }
 
        /*
         * Are we loading a blank journal or performing recovery after a
@@ -5115,27 +5186,14 @@ static int ext4_load_journal(struct super_block *sb,
                                ext4_msg(sb, KERN_ERR, "write access "
                                        "unavailable, cannot proceed "
                                        "(try mounting with noload)");
-                               return -EROFS;
+                               err = -EROFS;
+                               goto err_out;
                        }
                        ext4_msg(sb, KERN_INFO, "write access will "
                               "be enabled during recovery");
                }
        }
 
-       if (journal_inum && journal_dev) {
-               ext4_msg(sb, KERN_ERR, "filesystem has both journal "
-                      "and inode journals!");
-               return -EINVAL;
-       }
-
-       if (journal_inum) {
-               if (!(journal = ext4_get_journal(sb, journal_inum)))
-                       return -EINVAL;
-       } else {
-               if (!(journal = ext4_get_dev_journal(sb, journal_dev)))
-                       return -EINVAL;
-       }
-
        if (!(journal->j_flags & JBD2_BARRIER))
                ext4_msg(sb, KERN_INFO, "barriers disabled");
 
@@ -5155,12 +5213,16 @@ static int ext4_load_journal(struct super_block *sb,
 
        if (err) {
                ext4_msg(sb, KERN_ERR, "error loading journal");
-               jbd2_journal_destroy(journal);
-               return err;
+               goto err_out;
        }
 
        EXT4_SB(sb)->s_journal = journal;
-       ext4_clear_journal_err(sb, es);
+       err = ext4_clear_journal_err(sb, es);
+       if (err) {
+               EXT4_SB(sb)->s_journal = NULL;
+               jbd2_journal_destroy(journal);
+               return err;
+       }
 
        if (!really_read_only && journal_devnum &&
            journal_devnum != le32_to_cpu(es->s_journal_dev)) {
@@ -5171,6 +5233,10 @@ static int ext4_load_journal(struct super_block *sb,
        }
 
        return 0;
+
+err_out:
+       jbd2_journal_destroy(journal);
+       return err;
 }
 
 static int ext4_commit_super(struct super_block *sb, int sync)
@@ -5182,13 +5248,6 @@ static int ext4_commit_super(struct super_block *sb, int sync)
        if (!sbh || block_device_ejected(sb))
                return error;
 
-       /*
-        * The superblock bh should be mapped, but it might not be if the
-        * device was hot-removed. Not much we can do but fail the I/O.
-        */
-       if (!buffer_mapped(sbh))
-               return error;
-
        /*
         * If the file system is mounted read-only, don't update the
         * superblock write time.  This avoids updating the superblock
@@ -5256,26 +5315,32 @@ static int ext4_commit_super(struct super_block *sb, int sync)
  * remounting) the filesystem readonly, then we will end up with a
  * consistent fs on disk.  Record that fact.
  */
-static void ext4_mark_recovery_complete(struct super_block *sb,
-                                       struct ext4_super_block *es)
+static int ext4_mark_recovery_complete(struct super_block *sb,
+                                      struct ext4_super_block *es)
 {
+       int err;
        journal_t *journal = EXT4_SB(sb)->s_journal;
 
        if (!ext4_has_feature_journal(sb)) {
-               BUG_ON(journal != NULL);
-               return;
+               if (journal != NULL) {
+                       ext4_error(sb, "Journal got removed while the fs was "
+                                  "mounted!");
+                       return -EFSCORRUPTED;
+               }
+               return 0;
        }
        jbd2_journal_lock_updates(journal);
-       if (jbd2_journal_flush(journal) < 0)
+       err = jbd2_journal_flush(journal);
+       if (err < 0)
                goto out;
 
        if (ext4_has_feature_journal_needs_recovery(sb) && sb_rdonly(sb)) {
                ext4_clear_feature_journal_needs_recovery(sb);
                ext4_commit_super(sb, 1);
        }
-
 out:
        jbd2_journal_unlock_updates(journal);
+       return err;
 }
 
 /*
@@ -5283,14 +5348,17 @@ out:
  * has recorded an error from a previous lifetime, move that error to the
  * main filesystem now.
  */
-static void ext4_clear_journal_err(struct super_block *sb,
+static int ext4_clear_journal_err(struct super_block *sb,
                                   struct ext4_super_block *es)
 {
        journal_t *journal;
        int j_errno;
        const char *errstr;
 
-       BUG_ON(!ext4_has_feature_journal(sb));
+       if (!ext4_has_feature_journal(sb)) {
+               ext4_error(sb, "Journal got removed while the fs was mounted!");
+               return -EFSCORRUPTED;
+       }
 
        journal = EXT4_SB(sb)->s_journal;
 
@@ -5315,6 +5383,7 @@ static void ext4_clear_journal_err(struct super_block *sb,
                jbd2_journal_clear_err(journal);
                jbd2_journal_update_sb_errno(journal);
        }
+       return 0;
 }
 
 /*
@@ -5457,7 +5526,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 {
        struct ext4_super_block *es;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       unsigned long old_sb_flags;
+       unsigned long old_sb_flags, vfs_flags;
        struct ext4_mount_options old_opts;
        int enable_quota = 0;
        ext4_group_t g;
@@ -5500,6 +5569,14 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
        if (sbi->s_journal && sbi->s_journal->j_task->io_context)
                journal_ioprio = sbi->s_journal->j_task->io_context->ioprio;
 
+       /*
+        * Some options can be enabled by ext4 and/or by VFS mount flag
+        * either way we need to make sure it matches in both *flags and
+        * s_flags. Copy those selected flags from *flags to s_flags
+        */
+       vfs_flags = SB_LAZYTIME | SB_I_VERSION;
+       sb->s_flags = (sb->s_flags & ~vfs_flags) | (*flags & vfs_flags);
+
        if (!parse_options(data, sb, NULL, &journal_ioprio, 1)) {
                err = -EINVAL;
                goto restore_opts;
@@ -5553,9 +5630,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
        }
 
-       if (*flags & SB_LAZYTIME)
-               sb->s_flags |= SB_LAZYTIME;
-
        if ((bool)(*flags & SB_RDONLY) != sb_rdonly(sb)) {
                if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) {
                        err = -EROFS;
@@ -5585,8 +5659,13 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                            (sbi->s_mount_state & EXT4_VALID_FS))
                                es->s_state = cpu_to_le16(sbi->s_mount_state);
 
-                       if (sbi->s_journal)
+                       if (sbi->s_journal) {
+                               /*
+                                * We let remount-ro finish even if marking fs
+                                * as clean failed...
+                                */
                                ext4_mark_recovery_complete(sb, es);
+                       }
                        if (sbi->s_mmp_tsk)
                                kthread_stop(sbi->s_mmp_tsk);
                } else {
@@ -5628,14 +5707,25 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                                goto restore_opts;
                        }
 
+                       /*
+                        * Update the original bdev mapping's wb_err value
+                        * which could be used to detect the metadata async
+                        * write error.
+                        */
+                       errseq_check_and_advance(&sb->s_bdev->bd_inode->i_mapping->wb_err,
+                                                &sbi->s_bdev_wb_err);
+
                        /*
                         * Mounting a RDONLY partition read-write, so reread
                         * and store the current valid flag.  (It may have
                         * been changed by e2fsck since we originally mounted
                         * the partition.)
                         */
-                       if (sbi->s_journal)
-                               ext4_clear_journal_err(sb, es);
+                       if (sbi->s_journal) {
+                               err = ext4_clear_journal_err(sb, es);
+                               if (err)
+                                       goto restore_opts;
+                       }
                        sbi->s_mount_state = le16_to_cpu(es->s_state);
 
                        err = ext4_setup_super(sb, es, 0);
@@ -5665,7 +5755,17 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                ext4_register_li_request(sb, first_not_zeroed);
        }
 
-       ext4_setup_system_zone(sb);
+       /*
+        * Handle creation of system zone data early because it can fail.
+        * Releasing of existing data is done when we are sure remount will
+        * succeed.
+        */
+       if (test_opt(sb, BLOCK_VALIDITY) && !sbi->system_blks) {
+               err = ext4_setup_system_zone(sb);
+               if (err)
+                       goto restore_opts;
+       }
+
        if (sbi->s_journal == NULL && !(old_sb_flags & SB_RDONLY)) {
                err = ext4_commit_super(sb, 1);
                if (err)
@@ -5686,8 +5786,16 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                }
        }
 #endif
+       if (!test_opt(sb, BLOCK_VALIDITY) && sbi->system_blks)
+               ext4_release_system_zone(sb);
+
+       /*
+        * Some options can be enabled by ext4 and/or by VFS mount flag
+        * either way we need to make sure it matches in both *flags and
+        * s_flags. Copy those selected flags from s_flags to *flags
+        */
+       *flags = (*flags & ~vfs_flags) | (sb->s_flags & vfs_flags);
 
-       *flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME);
        ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data);
        kfree(orig_data);
        return 0;
@@ -5701,6 +5809,8 @@ restore_opts:
        sbi->s_commit_interval = old_opts.s_commit_interval;
        sbi->s_min_batch_time = old_opts.s_min_batch_time;
        sbi->s_max_batch_time = old_opts.s_max_batch_time;
+       if (!test_opt(sb, BLOCK_VALIDITY) && sbi->system_blks)
+               ext4_release_system_zone(sb);
 #ifdef CONFIG_QUOTA
        sbi->s_jquota_fmt = old_opts.s_jquota_fmt;
        for (i = 0; i < EXT4_MAXQUOTAS; i++) {
index 6c9fc9e..bfabb79 100644 (file)
@@ -189,6 +189,9 @@ static struct ext4_attr ext4_attr_##_name = {                       \
 #define EXT4_RW_ATTR_SBI_UL(_name,_elname)     \
        EXT4_ATTR_OFFSET(_name, 0644, pointer_ul, ext4_sb_info, _elname)
 
+#define EXT4_RO_ATTR_SBI_ATOMIC(_name,_elname) \
+       EXT4_ATTR_OFFSET(_name, 0444, pointer_atomic, ext4_sb_info, _elname)
+
 #define EXT4_ATTR_PTR(_name,_mode,_id,_ptr) \
 static struct ext4_attr ext4_attr_##_name = {                  \
        .attr = {.name = __stringify(_name), .mode = _mode },   \
@@ -215,6 +218,7 @@ EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan);
 EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs);
 EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request);
 EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc);
+EXT4_RW_ATTR_SBI_UI(mb_max_inode_prealloc, s_mb_max_inode_prealloc);
 EXT4_RW_ATTR_SBI_UI(extent_max_zeroout_kb, s_extent_max_zeroout_kb);
 EXT4_ATTR(trigger_fs_error, 0200, trigger_test_error);
 EXT4_RW_ATTR_SBI_UI(err_ratelimit_interval_ms, s_err_ratelimit_state.interval);
@@ -226,6 +230,8 @@ EXT4_RW_ATTR_SBI_UI(msg_ratelimit_burst, s_msg_ratelimit_state.burst);
 #ifdef CONFIG_EXT4_DEBUG
 EXT4_RW_ATTR_SBI_UL(simulate_fail, s_simulate_fail);
 #endif
+EXT4_RO_ATTR_SBI_ATOMIC(warning_count, s_warning_count);
+EXT4_RO_ATTR_SBI_ATOMIC(msg_count, s_msg_count);
 EXT4_RO_ATTR_ES_UI(errors_count, s_error_count);
 EXT4_RO_ATTR_ES_U8(first_error_errcode, s_first_error_errcode);
 EXT4_RO_ATTR_ES_U8(last_error_errcode, s_last_error_errcode);
@@ -240,6 +246,8 @@ EXT4_RO_ATTR_ES_STRING(last_error_func, s_last_error_func, 32);
 EXT4_ATTR(first_error_time, 0444, first_error_time);
 EXT4_ATTR(last_error_time, 0444, last_error_time);
 EXT4_ATTR(journal_task, 0444, journal_task);
+EXT4_RW_ATTR_SBI_UI(mb_prefetch, s_mb_prefetch);
+EXT4_RW_ATTR_SBI_UI(mb_prefetch_limit, s_mb_prefetch_limit);
 
 static unsigned int old_bump_val = 128;
 EXT4_ATTR_PTR(max_writeback_mb_bump, 0444, pointer_ui, &old_bump_val);
@@ -257,6 +265,7 @@ static struct attribute *ext4_attrs[] = {
        ATTR_LIST(mb_order2_req),
        ATTR_LIST(mb_stream_req),
        ATTR_LIST(mb_group_prealloc),
+       ATTR_LIST(mb_max_inode_prealloc),
        ATTR_LIST(max_writeback_mb_bump),
        ATTR_LIST(extent_max_zeroout_kb),
        ATTR_LIST(trigger_fs_error),
@@ -267,6 +276,8 @@ static struct attribute *ext4_attrs[] = {
        ATTR_LIST(msg_ratelimit_interval_ms),
        ATTR_LIST(msg_ratelimit_burst),
        ATTR_LIST(errors_count),
+       ATTR_LIST(warning_count),
+       ATTR_LIST(msg_count),
        ATTR_LIST(first_error_ino),
        ATTR_LIST(last_error_ino),
        ATTR_LIST(first_error_block),
@@ -283,6 +294,8 @@ static struct attribute *ext4_attrs[] = {
 #ifdef CONFIG_EXT4_DEBUG
        ATTR_LIST(simulate_fail),
 #endif
+       ATTR_LIST(mb_prefetch),
+       ATTR_LIST(mb_prefetch_limit),
        NULL,
 };
 ATTRIBUTE_GROUPS(ext4);
index 7d2f657..cba4b87 100644 (file)
@@ -1356,8 +1356,7 @@ retry:
 
        block = 0;
        while (wsize < bufsize) {
-               if (bh != NULL)
-                       brelse(bh);
+               brelse(bh);
                csize = (bufsize - wsize) > blocksize ? blocksize :
                                                                bufsize - wsize;
                bh = ext4_getblk(handle, ea_inode, block, 0);
index dc506b7..91e2cc8 100644 (file)
@@ -540,7 +540,6 @@ enum {
        REQ_F_ISREG_BIT,
        REQ_F_COMP_LOCKED_BIT,
        REQ_F_NEED_CLEANUP_BIT,
-       REQ_F_OVERFLOW_BIT,
        REQ_F_POLLED_BIT,
        REQ_F_BUFFER_SELECTED_BIT,
        REQ_F_NO_FILE_TABLE_BIT,
@@ -583,8 +582,6 @@ enum {
        REQ_F_COMP_LOCKED       = BIT(REQ_F_COMP_LOCKED_BIT),
        /* needs cleanup */
        REQ_F_NEED_CLEANUP      = BIT(REQ_F_NEED_CLEANUP_BIT),
-       /* in overflow list */
-       REQ_F_OVERFLOW          = BIT(REQ_F_OVERFLOW_BIT),
        /* already went through poll handler */
        REQ_F_POLLED            = BIT(REQ_F_POLLED_BIT),
        /* buffer already selected */
@@ -946,7 +943,8 @@ static void io_get_req_task(struct io_kiocb *req)
 
 static inline void io_clean_op(struct io_kiocb *req)
 {
-       if (req->flags & (REQ_F_NEED_CLEANUP | REQ_F_BUFFER_SELECTED))
+       if (req->flags & (REQ_F_NEED_CLEANUP | REQ_F_BUFFER_SELECTED |
+                         REQ_F_INFLIGHT))
                __io_clean_op(req);
 }
 
@@ -1366,7 +1364,6 @@ static bool io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force)
                req = list_first_entry(&ctx->cq_overflow_list, struct io_kiocb,
                                                compl.list);
                list_move(&req->compl.list, &list);
-               req->flags &= ~REQ_F_OVERFLOW;
                if (cqe) {
                        WRITE_ONCE(cqe->user_data, req->user_data);
                        WRITE_ONCE(cqe->res, req->result);
@@ -1419,7 +1416,6 @@ static void __io_cqring_fill_event(struct io_kiocb *req, long res, long cflags)
                        ctx->rings->sq_flags |= IORING_SQ_CQ_OVERFLOW;
                }
                io_clean_op(req);
-               req->flags |= REQ_F_OVERFLOW;
                req->result = res;
                req->compl.cflags = cflags;
                refcount_inc(&req->refs);
@@ -1563,17 +1559,6 @@ static bool io_dismantle_req(struct io_kiocb *req)
        if (req->file)
                io_put_file(req, req->file, (req->flags & REQ_F_FIXED_FILE));
 
-       if (req->flags & REQ_F_INFLIGHT) {
-               struct io_ring_ctx *ctx = req->ctx;
-               unsigned long flags;
-
-               spin_lock_irqsave(&ctx->inflight_lock, flags);
-               list_del(&req->inflight_entry);
-               if (waitqueue_active(&ctx->inflight_wait))
-                       wake_up(&ctx->inflight_wait);
-               spin_unlock_irqrestore(&ctx->inflight_lock, flags);
-       }
-
        return io_req_clean_work(req);
 }
 
@@ -2819,22 +2804,15 @@ static ssize_t io_iov_buffer_select(struct io_kiocb *req, struct iovec *iov,
        return __io_iov_buffer_select(req, iov, needs_lock);
 }
 
-static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
-                              struct iovec **iovec, struct iov_iter *iter,
-                              bool needs_lock)
+static ssize_t __io_import_iovec(int rw, struct io_kiocb *req,
+                                struct iovec **iovec, struct iov_iter *iter,
+                                bool needs_lock)
 {
        void __user *buf = u64_to_user_ptr(req->rw.addr);
        size_t sqe_len = req->rw.len;
        ssize_t ret;
        u8 opcode;
 
-       if (req->io) {
-               struct io_async_rw *iorw = &req->io->rw;
-
-               *iovec = NULL;
-               return iov_iter_count(&iorw->iter);
-       }
-
        opcode = req->opcode;
        if (opcode == IORING_OP_READ_FIXED || opcode == IORING_OP_WRITE_FIXED) {
                *iovec = NULL;
@@ -2848,10 +2826,8 @@ static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
        if (opcode == IORING_OP_READ || opcode == IORING_OP_WRITE) {
                if (req->flags & REQ_F_BUFFER_SELECT) {
                        buf = io_rw_buffer_select(req, &sqe_len, needs_lock);
-                       if (IS_ERR(buf)) {
-                               *iovec = NULL;
+                       if (IS_ERR(buf))
                                return PTR_ERR(buf);
-                       }
                        req->rw.len = sqe_len;
                }
 
@@ -2879,6 +2855,16 @@ static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
        return import_iovec(rw, buf, sqe_len, UIO_FASTIOV, iovec, iter);
 }
 
+static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
+                              struct iovec **iovec, struct iov_iter *iter,
+                              bool needs_lock)
+{
+       if (!req->io)
+               return __io_import_iovec(rw, req, iovec, iter, needs_lock);
+       *iovec = NULL;
+       return iov_iter_count(&req->io->rw.iter);
+}
+
 /*
  * For files that don't have ->read_iter() and ->write_iter(), handle them
  * by looping over ->read() or ->write() manually.
@@ -3001,11 +2987,8 @@ static inline int io_rw_prep_async(struct io_kiocb *req, int rw,
        ssize_t ret;
 
        iorw->iter.iov = iorw->fast_iov;
-       /* reset ->io around the iovec import, we don't want to use it */
-       req->io = NULL;
-       ret = io_import_iovec(rw, req, (struct iovec **) &iorw->iter.iov,
+       ret = __io_import_iovec(rw, req, (struct iovec **) &iorw->iter.iov,
                                &iorw->iter, !force_nonblock);
-       req->io = container_of(iorw, struct io_async_ctx, rw);
        if (unlikely(ret < 0))
                return ret;
 
@@ -3074,27 +3057,6 @@ static int io_async_buf_func(struct wait_queue_entry *wait, unsigned mode,
        return 1;
 }
 
-static inline int kiocb_wait_page_queue_init(struct kiocb *kiocb,
-                                            struct wait_page_queue *wait,
-                                            wait_queue_func_t func,
-                                            void *data)
-{
-       /* Can't support async wakeup with polled IO */
-       if (kiocb->ki_flags & IOCB_HIPRI)
-               return -EINVAL;
-       if (kiocb->ki_filp->f_mode & FMODE_BUF_RASYNC) {
-               wait->wait.func = func;
-               wait->wait.private = data;
-               wait->wait.flags = 0;
-               INIT_LIST_HEAD(&wait->wait.entry);
-               kiocb->ki_flags |= IOCB_WAITQ;
-               kiocb->ki_waitq = wait;
-               return 0;
-       }
-
-       return -EOPNOTSUPP;
-}
-
 /*
  * This controls whether a given IO request should be armed for async page
  * based retry. If we return false here, the request is handed to the async
@@ -3109,16 +3071,17 @@ static inline int kiocb_wait_page_queue_init(struct kiocb *kiocb,
  */
 static bool io_rw_should_retry(struct io_kiocb *req)
 {
+       struct wait_page_queue *wait = &req->io->rw.wpq;
        struct kiocb *kiocb = &req->rw.kiocb;
-       int ret;
 
        /* never retry for NOWAIT, we just complete with -EAGAIN */
        if (req->flags & REQ_F_NOWAIT)
                return false;
 
        /* Only for buffered IO */
-       if (kiocb->ki_flags & IOCB_DIRECT)
+       if (kiocb->ki_flags & (IOCB_DIRECT | IOCB_HIPRI))
                return false;
+
        /*
         * just use poll if we can, and don't attempt if the fs doesn't
         * support callback based unlocks
@@ -3126,14 +3089,15 @@ static bool io_rw_should_retry(struct io_kiocb *req)
        if (file_can_poll(req->file) || !(req->file->f_mode & FMODE_BUF_RASYNC))
                return false;
 
-       ret = kiocb_wait_page_queue_init(kiocb, &req->io->rw.wpq,
-                                               io_async_buf_func, req);
-       if (!ret) {
-               io_get_req_task(req);
-               return true;
-       }
+       wait->wait.func = io_async_buf_func;
+       wait->wait.private = req;
+       wait->wait.flags = 0;
+       INIT_LIST_HEAD(&wait->wait.entry);
+       kiocb->ki_flags |= IOCB_WAITQ;
+       kiocb->ki_waitq = wait;
 
-       return false;
+       io_get_req_task(req);
+       return true;
 }
 
 static int io_iter_do_read(struct io_kiocb *req, struct iov_iter *iter)
@@ -3238,6 +3202,7 @@ done:
        kiocb_done(kiocb, ret, cs);
        ret = 0;
 out_free:
+       /* it's reportedly faster than delegating the null check to kfree() */
        if (iovec)
                kfree(iovec);
        return ret;
@@ -3334,6 +3299,7 @@ copy_iov:
                        return -EAGAIN;
        }
 out_free:
+       /* it's reportedly faster than delegating the null check to kfree() */
        if (iovec)
                kfree(iovec);
        return ret;
@@ -5653,6 +5619,18 @@ static void __io_clean_op(struct io_kiocb *req)
                }
                req->flags &= ~REQ_F_NEED_CLEANUP;
        }
+
+       if (req->flags & REQ_F_INFLIGHT) {
+               struct io_ring_ctx *ctx = req->ctx;
+               unsigned long flags;
+
+               spin_lock_irqsave(&ctx->inflight_lock, flags);
+               list_del(&req->inflight_entry);
+               if (waitqueue_active(&ctx->inflight_wait))
+                       wake_up(&ctx->inflight_wait);
+               spin_unlock_irqrestore(&ctx->inflight_lock, flags);
+               req->flags &= ~REQ_F_INFLIGHT;
+       }
 }
 
 static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
@@ -7979,7 +7957,13 @@ static void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
                         ACCT_LOCKED);
 
        INIT_WORK(&ctx->exit_work, io_ring_exit_work);
-       queue_work(system_wq, &ctx->exit_work);
+       /*
+        * Use system_unbound_wq to avoid spawning tons of event kworkers
+        * if we're exiting a ton of rings at the same time. It just adds
+        * noise and overhead, there's no discernable change in runtime
+        * over using system_wq.
+        */
+       queue_work(system_unbound_wq, &ctx->exit_work);
 }
 
 static int io_uring_release(struct inode *inode, struct file *file)
@@ -8063,6 +8047,33 @@ static bool io_timeout_remove_link(struct io_ring_ctx *ctx,
        return found;
 }
 
+static bool io_cancel_link_cb(struct io_wq_work *work, void *data)
+{
+       return io_match_link(container_of(work, struct io_kiocb, work), data);
+}
+
+static void io_attempt_cancel(struct io_ring_ctx *ctx, struct io_kiocb *req)
+{
+       enum io_wq_cancel cret;
+
+       /* cancel this particular work, if it's running */
+       cret = io_wq_cancel_work(ctx->io_wq, &req->work);
+       if (cret != IO_WQ_CANCEL_NOTFOUND)
+               return;
+
+       /* find links that hold this pending, cancel those */
+       cret = io_wq_cancel_cb(ctx->io_wq, io_cancel_link_cb, req, true);
+       if (cret != IO_WQ_CANCEL_NOTFOUND)
+               return;
+
+       /* if we have a poll link holding this pending, cancel that */
+       if (io_poll_remove_link(ctx, req))
+               return;
+
+       /* final option, timeout link is holding this req pending */
+       io_timeout_remove_link(ctx, req);
+}
+
 static void io_uring_cancel_files(struct io_ring_ctx *ctx,
                                  struct files_struct *files)
 {
@@ -8094,35 +8105,9 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx,
                /* We need to keep going until we don't find a matching req */
                if (!cancel_req)
                        break;
-
-               if (cancel_req->flags & REQ_F_OVERFLOW) {
-                       spin_lock_irq(&ctx->completion_lock);
-                       list_del(&cancel_req->compl.list);
-                       cancel_req->flags &= ~REQ_F_OVERFLOW;
-
-                       io_cqring_mark_overflow(ctx);
-                       WRITE_ONCE(ctx->rings->cq_overflow,
-                               atomic_inc_return(&ctx->cached_cq_overflow));
-                       io_commit_cqring(ctx);
-                       spin_unlock_irq(&ctx->completion_lock);
-
-                       /*
-                        * Put inflight ref and overflow ref. If that's
-                        * all we had, then we're done with this request.
-                        */
-                       if (refcount_sub_and_test(2, &cancel_req->refs)) {
-                               io_free_req(cancel_req);
-                               finish_wait(&ctx->inflight_wait, &wait);
-                               continue;
-                       }
-               } else {
-                       io_wq_cancel_work(ctx->io_wq, &cancel_req->work);
-                       /* could be a link, check and remove if it is */
-                       if (!io_poll_remove_link(ctx, cancel_req))
-                               io_timeout_remove_link(ctx, cancel_req);
-                       io_put_req(cancel_req);
-               }
-
+               /* cancel this request, or head link requests */
+               io_attempt_cancel(ctx, cancel_req);
+               io_put_req(cancel_req);
                schedule();
                finish_wait(&ctx->inflight_wait, &wait);
        }
index e494443..17fdc48 100644 (file)
@@ -1285,7 +1285,7 @@ journal_t *jbd2_journal_init_inode(struct inode *inode)
  * superblock as being NULL to prevent the journal destroy from writing
  * back a bogus superblock.
  */
-static void journal_fail_superblock (journal_t *journal)
+static void journal_fail_superblock(journal_t *journal)
 {
        struct buffer_head *bh = journal->j_sb_buffer;
        brelse(bh);
@@ -1367,8 +1367,10 @@ static int jbd2_write_superblock(journal_t *journal, int write_flags)
        int ret;
 
        /* Buffer got discarded which means block device got invalidated */
-       if (!buffer_mapped(bh))
+       if (!buffer_mapped(bh)) {
+               unlock_buffer(bh);
                return -EIO;
+       }
 
        trace_jbd2_write_superblock(journal, write_flags);
        if (!(journal->j_flags & JBD2_BARRIER))
@@ -1815,7 +1817,7 @@ int jbd2_journal_destroy(journal_t *journal)
 
 
 /**
- *int jbd2_journal_check_used_features () - Check if features specified are used.
+ *int jbd2_journal_check_used_features() - Check if features specified are used.
  * @journal: Journal to check.
  * @compat: bitmask of compatible features
  * @ro: bitmask of features that force read-only mount
@@ -1825,7 +1827,7 @@ int jbd2_journal_destroy(journal_t *journal)
  * features.  Return true (non-zero) if it does.
  **/
 
-int jbd2_journal_check_used_features (journal_t *journal, unsigned long compat,
+int jbd2_journal_check_used_features(journal_t *journal, unsigned long compat,
                                 unsigned long ro, unsigned long incompat)
 {
        journal_superblock_t *sb;
@@ -1860,7 +1862,7 @@ int jbd2_journal_check_used_features (journal_t *journal, unsigned long compat,
  * all of a given set of features on this journal.  Return true
  * (non-zero) if it can. */
 
-int jbd2_journal_check_available_features (journal_t *journal, unsigned long compat,
+int jbd2_journal_check_available_features(journal_t *journal, unsigned long compat,
                                      unsigned long ro, unsigned long incompat)
 {
        if (!compat && !ro && !incompat)
@@ -1882,7 +1884,7 @@ int jbd2_journal_check_available_features (journal_t *journal, unsigned long com
 }
 
 /**
- * int jbd2_journal_set_features () - Mark a given journal feature in the superblock
+ * int jbd2_journal_set_features() - Mark a given journal feature in the superblock
  * @journal: Journal to act on.
  * @compat: bitmask of compatible features
  * @ro: bitmask of features that force read-only mount
@@ -1893,7 +1895,7 @@ int jbd2_journal_check_available_features (journal_t *journal, unsigned long com
  *
  */
 
-int jbd2_journal_set_features (journal_t *journal, unsigned long compat,
+int jbd2_journal_set_features(journal_t *journal, unsigned long compat,
                          unsigned long ro, unsigned long incompat)
 {
 #define INCOMPAT_FEATURE_ON(f) \
index 2ed278f..faa97d7 100644 (file)
@@ -690,14 +690,11 @@ static int do_one_pass(journal_t *journal,
                         * number. */
                        if (pass == PASS_SCAN &&
                            jbd2_has_feature_checksum(journal)) {
-                               int chksum_err, chksum_seen;
                                struct commit_header *cbh =
                                        (struct commit_header *)bh->b_data;
                                unsigned found_chksum =
                                        be32_to_cpu(cbh->h_chksum[0]);
 
-                               chksum_err = chksum_seen = 0;
-
                                if (info->end_transaction) {
                                        journal->j_failed_commit =
                                                info->end_transaction;
@@ -705,42 +702,23 @@ static int do_one_pass(journal_t *journal,
                                        break;
                                }
 
-                               if (crc32_sum == found_chksum &&
-                                   cbh->h_chksum_type == JBD2_CRC32_CHKSUM &&
-                                   cbh->h_chksum_size ==
-                                               JBD2_CRC32_CHKSUM_SIZE)
-                                      chksum_seen = 1;
-                               else if (!(cbh->h_chksum_type == 0 &&
-                                            cbh->h_chksum_size == 0 &&
-                                            found_chksum == 0 &&
-                                            !chksum_seen))
-                               /*
-                                * If fs is mounted using an old kernel and then
-                                * kernel with journal_chksum is used then we
-                                * get a situation where the journal flag has
-                                * checksum flag set but checksums are not
-                                * present i.e chksum = 0, in the individual
-                                * commit blocks.
-                                * Hence to avoid checksum failures, in this
-                                * situation, this extra check is added.
-                                */
-                                               chksum_err = 1;
-
-                               if (chksum_err) {
-                                       info->end_transaction = next_commit_ID;
-
-                                       if (!jbd2_has_feature_async_commit(journal)) {
-                                               journal->j_failed_commit =
-                                                       next_commit_ID;
-                                               brelse(bh);
-                                               break;
-                                       }
-                               }
+                               /* Neither checksum match nor unused? */
+                               if (!((crc32_sum == found_chksum &&
+                                      cbh->h_chksum_type ==
+                                               JBD2_CRC32_CHKSUM &&
+                                      cbh->h_chksum_size ==
+                                               JBD2_CRC32_CHKSUM_SIZE) ||
+                                     (cbh->h_chksum_type == 0 &&
+                                      cbh->h_chksum_size == 0 &&
+                                      found_chksum == 0)))
+                                       goto chksum_error;
+
                                crc32_sum = ~0;
                        }
                        if (pass == PASS_SCAN &&
                            !jbd2_commit_block_csum_verify(journal,
                                                           bh->b_data)) {
+                       chksum_error:
                                info->end_transaction = next_commit_ID;
 
                                if (!jbd2_has_feature_async_commit(journal)) {
index e91aad3..4398573 100644 (file)
@@ -2026,6 +2026,9 @@ static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh)
  */
 static void __jbd2_journal_unfile_buffer(struct journal_head *jh)
 {
+       J_ASSERT_JH(jh, jh->b_transaction != NULL);
+       J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
+
        __jbd2_journal_temp_unlink_buffer(jh);
        jh->b_transaction = NULL;
 }
@@ -2078,10 +2081,6 @@ out:
  * int jbd2_journal_try_to_free_buffers() - try to free page buffers.
  * @journal: journal for operation
  * @page: to try and free
- * @gfp_mask: we use the mask to detect how hard should we try to release
- * buffers. If __GFP_DIRECT_RECLAIM and __GFP_FS is set, we wait for commit
- * code to release the buffers.
- *
  *
  * For all the buffers on this page,
  * if they are fully written out ordered data, move them onto BUF_CLEAN
@@ -2112,11 +2111,11 @@ out:
  *
  * Return 0 on failure, 1 on success
  */
-int jbd2_journal_try_to_free_buffers(journal_t *journal,
-                               struct page *page, gfp_t gfp_mask)
+int jbd2_journal_try_to_free_buffers(journal_t *journal, struct page *page)
 {
        struct buffer_head *head;
        struct buffer_head *bh;
+       bool has_write_io_error = false;
        int ret = 0;
 
        J_ASSERT(PageLocked(page));
@@ -2141,11 +2140,26 @@ int jbd2_journal_try_to_free_buffers(journal_t *journal,
                jbd2_journal_put_journal_head(jh);
                if (buffer_jbd(bh))
                        goto busy;
+
+               /*
+                * If we free a metadata buffer which has been failed to
+                * write out, the jbd2 checkpoint procedure will not detect
+                * this failure and may lead to filesystem inconsistency
+                * after cleanup journal tail.
+                */
+               if (buffer_write_io_error(bh)) {
+                       pr_err("JBD2: Error while async write back metadata bh %llu.",
+                              (unsigned long long)bh->b_blocknr);
+                       has_write_io_error = true;
+               }
        } while ((bh = bh->b_this_page) != head);
 
        ret = try_to_free_buffers(page);
 
 busy:
+       if (has_write_io_error)
+               jbd2_journal_abort(journal, -EIO);
+
        return ret;
 }
 
@@ -2572,6 +2586,13 @@ bool __jbd2_journal_refile_buffer(struct journal_head *jh)
 
        was_dirty = test_clear_buffer_jbddirty(bh);
        __jbd2_journal_temp_unlink_buffer(jh);
+
+       /*
+        * b_transaction must be set, otherwise the new b_transaction won't
+        * be holding jh reference
+        */
+       J_ASSERT_JH(jh, jh->b_transaction != NULL);
+
        /*
         * We set b_transaction here because b_next_transaction will inherit
         * our jh reference and thus __jbd2_journal_file_buffer() must not
index 6b2b436..b57b3ff 100644 (file)
@@ -217,10 +217,8 @@ int romfs_dev_read(struct super_block *sb, unsigned long pos,
        size_t limit;
 
        limit = romfs_maxsize(sb);
-       if (pos >= limit)
+       if (pos >= limit || buflen > limit - pos)
                return -EIO;
-       if (buflen > limit - pos)
-               buflen = limit - pos;
 
 #ifdef CONFIG_ROMFS_ON_MTD
        if (sb->s_mtd)
index 76bb1c8..8a19773 100644 (file)
@@ -87,7 +87,11 @@ static int squashfs_bio_read(struct super_block *sb, u64 index, int length,
        int error, i;
        struct bio *bio;
 
-       bio = bio_alloc(GFP_NOIO, page_count);
+       if (page_count <= BIO_MAX_PAGES)
+               bio = bio_alloc(GFP_NOIO, page_count);
+       else
+               bio = bio_kmalloc(GFP_NOIO, page_count);
+
        if (!bio)
                return -ENOMEM;
 
index a2710e6..3215023 100644 (file)
@@ -132,6 +132,7 @@ enum cpuhp_state {
        CPUHP_AP_MIPS_GIC_TIMER_STARTING,
        CPUHP_AP_ARC_TIMER_STARTING,
        CPUHP_AP_RISCV_TIMER_STARTING,
+       CPUHP_AP_CLINT_TIMER_STARTING,
        CPUHP_AP_CSKY_TIMER_STARTING,
        CPUHP_AP_HYPERV_TIMER_STARTING,
        CPUHP_AP_KVM_STARTING,
index 5a3ce2a..6e87225 100644 (file)
@@ -73,9 +73,6 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size,
 }
 
 u64 dma_direct_get_required_mask(struct device *dev);
-gfp_t dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
-                                 u64 *phys_mask);
-bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size);
 void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
                gfp_t gfp, unsigned long attrs);
 void dma_direct_free(struct device *dev, size_t size, void *cpu_addr,
index 016b96b..52635e9 100644 (file)
@@ -522,8 +522,9 @@ void *dma_common_pages_remap(struct page **pages, size_t size,
                        pgprot_t prot, const void *caller);
 void dma_common_free_remap(void *cpu_addr, size_t size);
 
-void *dma_alloc_from_pool(struct device *dev, size_t size,
-                         struct page **ret_page, gfp_t flags);
+struct page *dma_alloc_from_pool(struct device *dev, size_t size,
+               void **cpu_addr, gfp_t flags,
+               bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t));
 bool dma_free_from_pool(struct device *dev, void *start, size_t size);
 
 int
index 4aaa297..08f9049 100644 (file)
@@ -1381,7 +1381,7 @@ extern int         jbd2_journal_dirty_metadata (handle_t *, struct buffer_head *);
 extern int      jbd2_journal_forget (handle_t *, struct buffer_head *);
 extern int      jbd2_journal_invalidatepage(journal_t *,
                                struct page *, unsigned int, unsigned int);
-extern int      jbd2_journal_try_to_free_buffers(journal_t *, struct page *, gfp_t);
+extern int      jbd2_journal_try_to_free_buffers(journal_t *journal, struct page *page);
 extern int      jbd2_journal_stop(handle_t *);
 extern int      jbd2_journal_flush (journal_t *);
 extern void     jbd2_journal_lock_updates (journal_t *);
index 9a33f17..625f491 100644 (file)
@@ -9,6 +9,8 @@ struct ip_ct_sctp {
        enum sctp_conntrack state;
 
        __be32 vtag[IP_CT_DIR_MAX];
+       u8 last_dir;
+       u8 flags;
 };
 
 #endif /* _NF_CONNTRACK_SCTP_H */
index a124c21..e8cbc2e 100644 (file)
@@ -117,7 +117,9 @@ static inline pgd_t *pgd_offset_pgd(pgd_t *pgd, unsigned long address)
  * a shortcut which implies the use of the kernel's pgd, instead
  * of a process's
  */
+#ifndef pgd_offset_k
 #define pgd_offset_k(address)          pgd_offset(&init_mm, (address))
+#endif
 
 /*
  * In many cases it is known that a virtual address is mapped at PMD or PTE
index 46881d9..8d9ab50 100644 (file)
@@ -71,7 +71,7 @@
  *     NETIF_F_IPV6_CSUM - Driver (device) is only able to checksum plain
  *                       TCP or UDP packets over IPv6. These are specifically
  *                       unencapsulated packets of the form IPv6|TCP or
- *                       IPv4|UDP where the Next Header field in the IPv6
+ *                       IPv6|UDP where the Next Header field in the IPv6
  *                       header is either TCP or UDP. IPv6 extension headers
  *                       are not supported with this feature. This feature
  *                       cannot be set in features for a device with
@@ -1056,7 +1056,16 @@ void kfree_skb(struct sk_buff *skb);
 void kfree_skb_list(struct sk_buff *segs);
 void skb_dump(const char *level, const struct sk_buff *skb, bool full_pkt);
 void skb_tx_error(struct sk_buff *skb);
+
+#ifdef CONFIG_TRACEPOINTS
 void consume_skb(struct sk_buff *skb);
+#else
+static inline void consume_skb(struct sk_buff *skb)
+{
+       return kfree_skb(skb);
+}
+#endif
+
 void __consume_stateless_skb(struct sk_buff *skb);
 void  __kfree_skb(struct sk_buff *skb);
 extern struct kmem_cache *skbuff_head_cache;
@@ -2658,7 +2667,7 @@ static inline int pskb_network_may_pull(struct sk_buff *skb, unsigned int len)
  *
  * Using max(32, L1_CACHE_BYTES) makes sense (especially with RPS)
  * to reduce average number of cache lines per packet.
- * get_rps_cpus() for example only access one 64 bytes aligned block :
+ * get_rps_cpu() for example only access one 64 bytes aligned block :
  * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8)
  */
 #ifndef NET_SKB_PAD
index 91eacbd..f6abcc0 100644 (file)
@@ -59,7 +59,7 @@ bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *,
 void rxrpc_kernel_end_call(struct socket *, struct rxrpc_call *);
 void rxrpc_kernel_get_peer(struct socket *, struct rxrpc_call *,
                           struct sockaddr_rxrpc *);
-u32 rxrpc_kernel_get_srtt(struct socket *, struct rxrpc_call *);
+bool rxrpc_kernel_get_srtt(struct socket *, struct rxrpc_call *, u32 *);
 int rxrpc_kernel_charge_accept(struct socket *, rxrpc_notify_rx_t,
                               rxrpc_user_attach_call_t, unsigned long, gfp_t,
                               unsigned int);
index 9205a76..38e4094 100644 (file)
@@ -494,7 +494,7 @@ int igmp6_event_report(struct sk_buff *skb);
 
 #ifdef CONFIG_SYSCTL
 int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write,
-                              void __user *buffer, size_t *lenp, loff_t *ppos);
+                              void *buffer, size_t *lenp, loff_t *ppos);
 int ndisc_ifinfo_sysctl_strategy(struct ctl_table *ctl,
                                 void __user *oldval, size_t __user *oldlenp,
                                 void __user *newval, size_t newlen);
index bf9491b..224d194 100644 (file)
@@ -143,6 +143,8 @@ static inline u64 nft_reg_load64(const u32 *sreg)
 static inline void nft_data_copy(u32 *dst, const struct nft_data *src,
                                 unsigned int len)
 {
+       if (len % NFT_REG32_SIZE)
+               dst[len / NFT_REG32_SIZE] = 0;
        memcpy(dst, src, len);
 }
 
index cc41d69..4c8b99e 100644 (file)
@@ -746,24 +746,29 @@ TRACE_EVENT(ext4_mb_release_group_pa,
 );
 
 TRACE_EVENT(ext4_discard_preallocations,
-       TP_PROTO(struct inode *inode),
+       TP_PROTO(struct inode *inode, unsigned int len, unsigned int needed),
 
-       TP_ARGS(inode),
+       TP_ARGS(inode, len, needed),
 
        TP_STRUCT__entry(
-               __field(        dev_t,  dev                     )
-               __field(        ino_t,  ino                     )
+               __field(        dev_t,          dev             )
+               __field(        ino_t,          ino             )
+               __field(        unsigned int,   len             )
+               __field(        unsigned int,   needed          )
 
        ),
 
        TP_fast_assign(
                __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
+               __entry->len    = len;
+               __entry->needed = needed;
        ),
 
-       TP_printk("dev %d,%d ino %lu",
+       TP_printk("dev %d,%d ino %lu len: %u needed %u",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
-                 (unsigned long) __entry->ino)
+                 (unsigned long) __entry->ino, __entry->len,
+                 __entry->needed)
 );
 
 TRACE_EVENT(ext4_mb_discard_preallocations,
@@ -1312,18 +1317,34 @@ DEFINE_EVENT(ext4__bitmap_load, ext4_mb_buddy_bitmap_load,
        TP_ARGS(sb, group)
 );
 
-DEFINE_EVENT(ext4__bitmap_load, ext4_read_block_bitmap_load,
+DEFINE_EVENT(ext4__bitmap_load, ext4_load_inode_bitmap,
 
        TP_PROTO(struct super_block *sb, unsigned long group),
 
        TP_ARGS(sb, group)
 );
 
-DEFINE_EVENT(ext4__bitmap_load, ext4_load_inode_bitmap,
+TRACE_EVENT(ext4_read_block_bitmap_load,
+       TP_PROTO(struct super_block *sb, unsigned long group, bool prefetch),
 
-       TP_PROTO(struct super_block *sb, unsigned long group),
+       TP_ARGS(sb, group, prefetch),
 
-       TP_ARGS(sb, group)
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        __u32,  group                   )
+               __field(        bool,   prefetch                )
+
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = sb->s_dev;
+               __entry->group  = group;
+               __entry->prefetch = prefetch;
+       ),
+
+       TP_printk("dev %d,%d group %u prefetch %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->group, __entry->prefetch)
 );
 
 TRACE_EVENT(ext4_direct_IO_enter,
@@ -2726,6 +2747,50 @@ TRACE_EVENT(ext4_error,
                  __entry->function, __entry->line)
 );
 
+TRACE_EVENT(ext4_prefetch_bitmaps,
+           TP_PROTO(struct super_block *sb, ext4_group_t group,
+                    ext4_group_t next, unsigned int prefetch_ios),
+
+       TP_ARGS(sb, group, next, prefetch_ios),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        __u32,  group                   )
+               __field(        __u32,  next                    )
+               __field(        __u32,  ios                     )
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = sb->s_dev;
+               __entry->group  = group;
+               __entry->next   = next;
+               __entry->ios    = prefetch_ios;
+       ),
+
+       TP_printk("dev %d,%d group %u next %u ios %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->group, __entry->next, __entry->ios)
+);
+
+TRACE_EVENT(ext4_lazy_itable_init,
+           TP_PROTO(struct super_block *sb, ext4_group_t group),
+
+       TP_ARGS(sb, group),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        __u32,  group                   )
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = sb->s_dev;
+               __entry->group  = group;
+       ),
+
+       TP_printk("dev %d,%d group %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->group)
+);
+
 #endif /* _TRACE_EXT4_H */
 
 /* This part must be outside protection */
index 059b6e4..c33079b 100644 (file)
@@ -138,11 +138,16 @@ enum rxrpc_recvmsg_trace {
 };
 
 enum rxrpc_rtt_tx_trace {
+       rxrpc_rtt_tx_cancel,
        rxrpc_rtt_tx_data,
+       rxrpc_rtt_tx_no_slot,
        rxrpc_rtt_tx_ping,
 };
 
 enum rxrpc_rtt_rx_trace {
+       rxrpc_rtt_rx_cancel,
+       rxrpc_rtt_rx_lost,
+       rxrpc_rtt_rx_obsolete,
        rxrpc_rtt_rx_ping_response,
        rxrpc_rtt_rx_requested_ack,
 };
@@ -339,10 +344,15 @@ enum rxrpc_tx_point {
        E_(rxrpc_recvmsg_wait,                  "WAIT")
 
 #define rxrpc_rtt_tx_traces \
+       EM(rxrpc_rtt_tx_cancel,                 "CNCE") \
        EM(rxrpc_rtt_tx_data,                   "DATA") \
+       EM(rxrpc_rtt_tx_no_slot,                "FULL") \
        E_(rxrpc_rtt_tx_ping,                   "PING")
 
 #define rxrpc_rtt_rx_traces \
+       EM(rxrpc_rtt_rx_cancel,                 "CNCL") \
+       EM(rxrpc_rtt_rx_obsolete,               "OBSL") \
+       EM(rxrpc_rtt_rx_lost,                   "LOST") \
        EM(rxrpc_rtt_rx_ping_response,          "PONG") \
        E_(rxrpc_rtt_rx_requested_ack,          "RACK")
 
@@ -1087,38 +1097,43 @@ TRACE_EVENT(rxrpc_recvmsg,
 
 TRACE_EVENT(rxrpc_rtt_tx,
            TP_PROTO(struct rxrpc_call *call, enum rxrpc_rtt_tx_trace why,
-                    rxrpc_serial_t send_serial),
+                    int slot, rxrpc_serial_t send_serial),
 
-           TP_ARGS(call, why, send_serial),
+           TP_ARGS(call, why, slot, send_serial),
 
            TP_STRUCT__entry(
                    __field(unsigned int,               call            )
                    __field(enum rxrpc_rtt_tx_trace,    why             )
+                   __field(int,                        slot            )
                    __field(rxrpc_serial_t,             send_serial     )
                             ),
 
            TP_fast_assign(
                    __entry->call = call->debug_id;
                    __entry->why = why;
+                   __entry->slot = slot;
                    __entry->send_serial = send_serial;
                           ),
 
-           TP_printk("c=%08x %s sr=%08x",
+           TP_printk("c=%08x [%d] %s sr=%08x",
                      __entry->call,
+                     __entry->slot,
                      __print_symbolic(__entry->why, rxrpc_rtt_tx_traces),
                      __entry->send_serial)
            );
 
 TRACE_EVENT(rxrpc_rtt_rx,
            TP_PROTO(struct rxrpc_call *call, enum rxrpc_rtt_rx_trace why,
+                    int slot,
                     rxrpc_serial_t send_serial, rxrpc_serial_t resp_serial,
                     u32 rtt, u32 rto),
 
-           TP_ARGS(call, why, send_serial, resp_serial, rtt, rto),
+           TP_ARGS(call, why, slot, send_serial, resp_serial, rtt, rto),
 
            TP_STRUCT__entry(
                    __field(unsigned int,               call            )
                    __field(enum rxrpc_rtt_rx_trace,    why             )
+                   __field(int,                        slot            )
                    __field(rxrpc_serial_t,             send_serial     )
                    __field(rxrpc_serial_t,             resp_serial     )
                    __field(u32,                        rtt             )
@@ -1128,14 +1143,16 @@ TRACE_EVENT(rxrpc_rtt_rx,
            TP_fast_assign(
                    __entry->call = call->debug_id;
                    __entry->why = why;
+                   __entry->slot = slot;
                    __entry->send_serial = send_serial;
                    __entry->resp_serial = resp_serial;
                    __entry->rtt = rtt;
                    __entry->rto = rto;
                           ),
 
-           TP_printk("c=%08x %s sr=%08x rr=%08x rtt=%u rto=%u",
+           TP_printk("c=%08x [%d] %s sr=%08x rr=%08x rtt=%u rto=%u",
                      __entry->call,
+                     __entry->slot,
                      __print_symbolic(__entry->why, rxrpc_rtt_rx_traces),
                      __entry->send_serial,
                      __entry->resp_serial,
index 0480f89..b6238b2 100644 (file)
@@ -767,7 +767,7 @@ union bpf_attr {
  *
  *             Also, note that **bpf_trace_printk**\ () is slow, and should
  *             only be used for debugging purposes. For this reason, a notice
- *             bloc (spanning several lines) is printed to kernel logs and
+ *             block (spanning several lines) is printed to kernel logs and
  *             states that the helper should not be used "for production use"
  *             the first time this helper is used (or more precisely, when
  *             **trace_printk**\ () buffers are allocated). For passing values
@@ -1033,14 +1033,14 @@ union bpf_attr {
  *
  *                     int ret;
  *                     struct bpf_tunnel_key key = {};
- *                     
+ *
  *                     ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
  *                     if (ret < 0)
  *                             return TC_ACT_SHOT;     // drop packet
- *                     
+ *
  *                     if (key.remote_ipv4 != 0x0a000001)
  *                             return TC_ACT_SHOT;     // drop packet
- *                     
+ *
  *                     return TC_ACT_OK;               // accept packet
  *
  *             This interface can also be used with all encapsulation devices
@@ -1147,7 +1147,7 @@ union bpf_attr {
  *     Description
  *             Retrieve the realm or the route, that is to say the
  *             **tclassid** field of the destination for the *skb*. The
- *             indentifier retrieved is a user-provided tag, similar to the
+ *             identifier retrieved is a user-provided tag, similar to the
  *             one used with the net_cls cgroup (see description for
  *             **bpf_get_cgroup_classid**\ () helper), but here this tag is
  *             held by a route (a destination entry), not by a task.
index 3d0d823..7d66876 100644 (file)
@@ -135,7 +135,7 @@ struct in_addr {
  * this socket to prevent accepting spoofed ones.
  */
 #define IP_PMTUDISC_INTERFACE          4
-/* weaker version of IP_PMTUDISC_INTERFACE, which allos packets to get
+/* weaker version of IP_PMTUDISC_INTERFACE, which allows packets to get
  * fragmented if they exeed the interface mtu
  */
 #define IP_PMTUDISC_OMIT               5
index 42f351c..2b8e12f 100644 (file)
@@ -133,7 +133,7 @@ enum nf_tables_msg_types {
  * @NFTA_LIST_ELEM: list element (NLA_NESTED)
  */
 enum nft_list_attributes {
-       NFTA_LIST_UNPEC,
+       NFTA_LIST_UNSPEC,
        NFTA_LIST_ELEM,
        __NFTA_LIST_MAX
 };
index b671596..8faa2ce 100644 (file)
@@ -67,6 +67,9 @@ static void bpf_iter_done_stop(struct seq_file *seq)
        iter_priv->done_stop = true;
 }
 
+/* maximum visited objects before bailing out */
+#define MAX_ITER_OBJECTS       1000000
+
 /* bpf_seq_read, a customized and simpler version for bpf iterator.
  * no_llseek is assumed for this file.
  * The following are differences from seq_read():
@@ -79,7 +82,7 @@ static ssize_t bpf_seq_read(struct file *file, char __user *buf, size_t size,
 {
        struct seq_file *seq = file->private_data;
        size_t n, offs, copied = 0;
-       int err = 0;
+       int err = 0, num_objs = 0;
        void *p;
 
        mutex_lock(&seq->lock);
@@ -135,6 +138,7 @@ static ssize_t bpf_seq_read(struct file *file, char __user *buf, size_t size,
        while (1) {
                loff_t pos = seq->index;
 
+               num_objs++;
                offs = seq->count;
                p = seq->op->next(seq, p, &seq->index);
                if (pos == seq->index) {
@@ -153,6 +157,15 @@ static ssize_t bpf_seq_read(struct file *file, char __user *buf, size_t size,
                if (seq->count >= size)
                        break;
 
+               if (num_objs >= MAX_ITER_OBJECTS) {
+                       if (offs == 0) {
+                               err = -EAGAIN;
+                               seq->op->stop(seq, p);
+                               goto done;
+                       }
+                       break;
+               }
+
                err = seq->op->show(seq, p);
                if (err > 0) {
                        bpf_iter_dec_seq_num(seq);
index 232df29..99af4ce 100644 (file)
@@ -29,8 +29,9 @@ static struct task_struct *task_seq_get_next(struct pid_namespace *ns,
 
        rcu_read_lock();
 retry:
-       pid = idr_get_next(&ns->idr, tid);
+       pid = find_ge_pid(*tid, ns);
        if (pid) {
+               *tid = pid_nr_ns(pid, ns);
                task = get_pid_task(pid, PIDTYPE_PID);
                if (!task) {
                        ++*tid;
@@ -178,10 +179,11 @@ again:
                f = fcheck_files(curr_files, curr_fd);
                if (!f)
                        continue;
+               if (!get_file_rcu(f))
+                       continue;
 
                /* set info->fd */
                info->fd = curr_fd;
-               get_file(f);
                rcu_read_unlock();
                return f;
        }
index bb0041e..db6ef07 100644 (file)
@@ -43,7 +43,7 @@ u64 dma_direct_get_required_mask(struct device *dev)
        return (1ULL << (fls64(max_dma) - 1)) * 2 - 1;
 }
 
-gfp_t dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
+static gfp_t dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
                                  u64 *phys_limit)
 {
        u64 dma_limit = min_not_zero(dma_mask, dev->bus_dma_limit);
@@ -68,7 +68,7 @@ gfp_t dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
        return 0;
 }
 
-bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
+static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
 {
        return phys_to_dma_direct(dev, phys) + size - 1 <=
                        min_not_zero(dev->coherent_dma_mask, dev->bus_dma_limit);
@@ -161,8 +161,13 @@ void *dma_direct_alloc_pages(struct device *dev, size_t size,
        size = PAGE_ALIGN(size);
 
        if (dma_should_alloc_from_pool(dev, gfp, attrs)) {
-               ret = dma_alloc_from_pool(dev, size, &page, gfp);
-               if (!ret)
+               u64 phys_mask;
+
+               gfp |= dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask,
+                               &phys_mask);
+               page = dma_alloc_from_pool(dev, size, &ret, gfp,
+                               dma_coherent_ok);
+               if (!page)
                        return NULL;
                goto done;
        }
index 6bc74a2..06582b4 100644 (file)
@@ -3,7 +3,9 @@
  * Copyright (C) 2012 ARM Ltd.
  * Copyright (C) 2020 Google LLC
  */
+#include <linux/cma.h>
 #include <linux/debugfs.h>
+#include <linux/dma-contiguous.h>
 #include <linux/dma-direct.h>
 #include <linux/dma-noncoherent.h>
 #include <linux/init.h>
@@ -55,6 +57,29 @@ static void dma_atomic_pool_size_add(gfp_t gfp, size_t size)
                pool_size_kernel += size;
 }
 
+static bool cma_in_zone(gfp_t gfp)
+{
+       unsigned long size;
+       phys_addr_t end;
+       struct cma *cma;
+
+       cma = dev_get_cma_area(NULL);
+       if (!cma)
+               return false;
+
+       size = cma_get_size(cma);
+       if (!size)
+               return false;
+
+       /* CMA can't cross zone boundaries, see cma_activate_area() */
+       end = cma_get_base(cma) + size - 1;
+       if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp & GFP_DMA))
+               return end <= DMA_BIT_MASK(zone_dma_bits);
+       if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp & GFP_DMA32))
+               return end <= DMA_BIT_MASK(32);
+       return true;
+}
+
 static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
                              gfp_t gfp)
 {
@@ -68,7 +93,11 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
 
        do {
                pool_size = 1 << (PAGE_SHIFT + order);
-               page = alloc_pages(gfp, order);
+               if (cma_in_zone(gfp))
+                       page = dma_alloc_from_contiguous(NULL, 1 << order,
+                                                        order, false);
+               if (!page)
+                       page = alloc_pages(gfp, order);
        } while (!page && order-- > 0);
        if (!page)
                goto out;
@@ -196,93 +225,75 @@ static int __init dma_atomic_pool_init(void)
 }
 postcore_initcall(dma_atomic_pool_init);
 
-static inline struct gen_pool *dma_guess_pool_from_device(struct device *dev)
+static inline struct gen_pool *dma_guess_pool(struct gen_pool *prev, gfp_t gfp)
 {
-       u64 phys_mask;
-       gfp_t gfp;
-
-       gfp = dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask,
-                                         &phys_mask);
-       if (IS_ENABLED(CONFIG_ZONE_DMA) && gfp == GFP_DMA)
+       if (prev == NULL) {
+               if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp & GFP_DMA32))
+                       return atomic_pool_dma32;
+               if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp & GFP_DMA))
+                       return atomic_pool_dma;
+               return atomic_pool_kernel;
+       }
+       if (prev == atomic_pool_kernel)
+               return atomic_pool_dma32 ? atomic_pool_dma32 : atomic_pool_dma;
+       if (prev == atomic_pool_dma32)
                return atomic_pool_dma;
-       if (IS_ENABLED(CONFIG_ZONE_DMA32) && gfp == GFP_DMA32)
-               return atomic_pool_dma32;
-       return atomic_pool_kernel;
+       return NULL;
 }
 
-static inline struct gen_pool *dma_get_safer_pool(struct gen_pool *bad_pool)
+static struct page *__dma_alloc_from_pool(struct device *dev, size_t size,
+               struct gen_pool *pool, void **cpu_addr,
+               bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t))
 {
-       if (bad_pool == atomic_pool_kernel)
-               return atomic_pool_dma32 ? : atomic_pool_dma;
+       unsigned long addr;
+       phys_addr_t phys;
 
-       if (bad_pool == atomic_pool_dma32)
-               return atomic_pool_dma;
+       addr = gen_pool_alloc(pool, size);
+       if (!addr)
+               return NULL;
 
-       return NULL;
-}
+       phys = gen_pool_virt_to_phys(pool, addr);
+       if (phys_addr_ok && !phys_addr_ok(dev, phys, size)) {
+               gen_pool_free(pool, addr, size);
+               return NULL;
+       }
 
-static inline struct gen_pool *dma_guess_pool(struct device *dev,
-                                             struct gen_pool *bad_pool)
-{
-       if (bad_pool)
-               return dma_get_safer_pool(bad_pool);
+       if (gen_pool_avail(pool) < atomic_pool_size)
+               schedule_work(&atomic_pool_work);
 
-       return dma_guess_pool_from_device(dev);
+       *cpu_addr = (void *)addr;
+       memset(*cpu_addr, 0, size);
+       return pfn_to_page(__phys_to_pfn(phys));
 }
 
-void *dma_alloc_from_pool(struct device *dev, size_t size,
-                         struct page **ret_page, gfp_t flags)
+struct page *dma_alloc_from_pool(struct device *dev, size_t size,
+               void **cpu_addr, gfp_t gfp,
+               bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t))
 {
        struct gen_pool *pool = NULL;
-       unsigned long val = 0;
-       void *ptr = NULL;
-       phys_addr_t phys;
-
-       while (1) {
-               pool = dma_guess_pool(dev, pool);
-               if (!pool) {
-                       WARN(1, "Failed to get suitable pool for %s\n",
-                            dev_name(dev));
-                       break;
-               }
-
-               val = gen_pool_alloc(pool, size);
-               if (!val)
-                       continue;
-
-               phys = gen_pool_virt_to_phys(pool, val);
-               if (dma_coherent_ok(dev, phys, size))
-                       break;
-
-               gen_pool_free(pool, val, size);
-               val = 0;
-       }
-
-
-       if (val) {
-               *ret_page = pfn_to_page(__phys_to_pfn(phys));
-               ptr = (void *)val;
-               memset(ptr, 0, size);
+       struct page *page;
 
-               if (gen_pool_avail(pool) < atomic_pool_size)
-                       schedule_work(&atomic_pool_work);
+       while ((pool = dma_guess_pool(pool, gfp))) {
+               page = __dma_alloc_from_pool(dev, size, pool, cpu_addr,
+                                            phys_addr_ok);
+               if (page)
+                       return page;
        }
 
-       return ptr;
+       WARN(1, "Failed to get suitable pool for %s\n", dev_name(dev));
+       return NULL;
 }
 
 bool dma_free_from_pool(struct device *dev, void *start, size_t size)
 {
        struct gen_pool *pool = NULL;
 
-       while (1) {
-               pool = dma_guess_pool(dev, pool);
-               if (!pool)
-                       return false;
-
-               if (gen_pool_has_addr(pool, (unsigned long)start, size)) {
-                       gen_pool_free(pool, (unsigned long)start, size);
-                       return true;
-               }
+       while ((pool = dma_guess_pool(pool, 0))) {
+               if (!gen_pool_has_addr(pool, (unsigned long)start, size))
+                       continue;
+               gen_pool_free(pool, (unsigned long)start, size);
+               return true;
        }
+
+       return false;
 }
index 9852e0d..fcae019 100644 (file)
@@ -65,7 +65,8 @@ static long syscall_trace_enter(struct pt_regs *regs, long syscall,
 
        syscall_enter_audit(regs, syscall);
 
-       return ret ? : syscall;
+       /* The above might have changed the syscall number */
+       return ret ? : syscall_get_nr(current, regs);
 }
 
 noinstr long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
index 649fd53..0e18aaf 100644 (file)
@@ -205,7 +205,7 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
                try_to_free_swap(old_page);
        page_vma_mapped_walk_done(&pvmw);
 
-       if (vma->vm_flags & VM_LOCKED)
+       if ((vma->vm_flags & VM_LOCKED) && !PageCompound(old_page))
                munlock_vma_page(old_page);
        put_page(old_page);
 
index 72fe443..fb4e0c5 100644 (file)
@@ -197,6 +197,7 @@ free_buf:
 static void relay_destroy_channel(struct kref *kref)
 {
        struct rchan *chan = container_of(kref, struct rchan, kref);
+       free_percpu(chan->buf);
        kfree(chan);
 }
 
index e290fc5..a4a4c68 100644 (file)
@@ -15,11 +15,16 @@ KCOV_INSTRUMENT_debugobjects.o := n
 KCOV_INSTRUMENT_dynamic_debug.o := n
 KCOV_INSTRUMENT_fault-inject.o := n
 
+# string.o implements standard library functions like memset/memcpy etc.
+# Use -ffreestanding to ensure that the compiler does not try to "optimize"
+# them into calls to themselves.
+CFLAGS_string.o := -ffreestanding
+
 # Early boot use of cmdline, don't instrument it
 ifdef CONFIG_AMD_MEM_ENCRYPT
 KASAN_SANITIZE_string.o := n
 
-CFLAGS_string.o := -fno-stack-protector
+CFLAGS_string.o += -fno-stack-protector
 endif
 
 # Used by KCSAN while enabled, avoid recursion.
index aabf65d..1f87aec 100644 (file)
@@ -655,7 +655,7 @@ static void __init __hugetlb_cgroup_file_dfl_init(int idx)
        snprintf(cft->name, MAX_CFTYPE_NAME, "%s.events", buf);
        cft->private = MEMFILE_PRIVATE(idx, 0);
        cft->seq_show = hugetlb_events_show;
-       cft->file_offset = offsetof(struct hugetlb_cgroup, events_file[idx]),
+       cft->file_offset = offsetof(struct hugetlb_cgroup, events_file[idx]);
        cft->flags = CFTYPE_NOT_ON_ROOT;
 
        /* Add the events.local file */
@@ -664,7 +664,7 @@ static void __init __hugetlb_cgroup_file_dfl_init(int idx)
        cft->private = MEMFILE_PRIVATE(idx, 0);
        cft->seq_show = hugetlb_events_local_show;
        cft->file_offset = offsetof(struct hugetlb_cgroup,
-                                   events_local_file[idx]),
+                                   events_local_file[idx]);
        cft->flags = CFTYPE_NOT_ON_ROOT;
 
        /* NULL terminate the last cft */
index 15a9af7..e749e56 100644 (file)
@@ -466,7 +466,7 @@ int __khugepaged_enter(struct mm_struct *mm)
                return -ENOMEM;
 
        /* __khugepaged_exit() must not run from under us */
-       VM_BUG_ON_MM(khugepaged_test_exit(mm), mm);
+       VM_BUG_ON_MM(atomic_read(&mm->mm_users) == 0, mm);
        if (unlikely(test_and_set_bit(MMF_VM_HUGEPAGE, &mm->flags))) {
                free_mm_slot(mm_slot);
                return 0;
index 3a7779d..602f428 100644 (file)
@@ -4247,6 +4247,9 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf)
                                vmf->flags & FAULT_FLAG_WRITE)) {
                update_mmu_cache(vmf->vma, vmf->address, vmf->pte);
        } else {
+               /* Skip spurious TLB flush for retried page fault */
+               if (vmf->flags & FAULT_FLAG_TRIED)
+                       goto unlock;
                /*
                 * This is needed only for protection faults but the arch code
                 * is not yet telling us if this is a protection fault or not.
index 0e2bab4..fab5e97 100644 (file)
@@ -1302,6 +1302,11 @@ static void free_pcppages_bulk(struct zone *zone, int count,
        struct page *page, *tmp;
        LIST_HEAD(head);
 
+       /*
+        * Ensure proper count is passed which otherwise would stuck in the
+        * below while (list_empty(list)) loop.
+        */
+       count = min(pcp->count, count);
        while (count) {
                struct list_head *list;
 
@@ -7888,7 +7893,7 @@ int __meminit init_per_zone_wmark_min(void)
 
        return 0;
 }
-core_initcall(init_per_zone_wmark_min)
+postcore_initcall(init_per_zone_wmark_min)
 
 /*
  * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so
index 2a99df7..2613371 100644 (file)
@@ -7,6 +7,7 @@
  */
 #define pr_fmt(fmt) "rodata_test: " fmt
 
+#include <linux/rodata_test.h>
 #include <linux/uaccess.h>
 #include <asm/sections.h>
 
index b482d24..be4724b 100644 (file)
@@ -104,6 +104,8 @@ static void vunmap_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
                if (pmd_none_or_clear_bad(pmd))
                        continue;
                vunmap_pte_range(pmd, addr, next, mask);
+
+               cond_resched();
        } while (pmd++, addr = next, addr != end);
 }
 
index 0f8495b..717fe65 100644 (file)
@@ -881,6 +881,12 @@ static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset,
                   ntohl(ogm_packet->seqno), ogm_throughput, ogm_packet->ttl,
                   ogm_packet->version, ntohs(ogm_packet->tvlv_len));
 
+       if (batadv_is_my_mac(bat_priv, ogm_packet->orig)) {
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "Drop packet: originator packet from ourself\n");
+               return;
+       }
+
        /* If the throughput metric is 0, immediately drop the packet. No need
         * to create orig_node / neigh_node for an unusable route.
         */
@@ -1008,11 +1014,6 @@ int batadv_v_ogm_packet_recv(struct sk_buff *skb,
        if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
                goto free_skb;
 
-       ogm_packet = (struct batadv_ogm2_packet *)skb->data;
-
-       if (batadv_is_my_mac(bat_priv, ogm_packet->orig))
-               goto free_skb;
-
        batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX);
        batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
                           skb->len + ETH_HLEN);
index 91a04ca..8500f56 100644 (file)
@@ -437,7 +437,10 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac,
        batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES,
                           skb->len + ETH_HLEN);
 
-       netif_rx(skb);
+       if (in_interrupt())
+               netif_rx(skb);
+       else
+               netif_rx_ni(skb);
 out:
        if (primary_if)
                batadv_hardif_put(primary_if);
index a18dcc6..ef3f85b 100644 (file)
@@ -703,8 +703,10 @@ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
 
        chaddr_offset = *header_len + BATADV_DHCP_CHADDR_OFFSET;
        /* store the client address if the message is going to a client */
-       if (ret == BATADV_DHCP_TO_CLIENT &&
-           pskb_may_pull(skb, chaddr_offset + ETH_ALEN)) {
+       if (ret == BATADV_DHCP_TO_CLIENT) {
+               if (!pskb_may_pull(skb, chaddr_offset + ETH_ALEN))
+                       return BATADV_DHCP_NO;
+
                /* check if the DHCP packet carries an Ethernet DHCP */
                p = skb->data + *header_len + BATADV_DHCP_HTYPE_OFFSET;
                if (*p != BATADV_DHCP_HTYPE_ETHERNET)
index ce2767e..7b0af33 100644 (file)
@@ -116,7 +116,7 @@ static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt)
        if (segmented) {
                if (rfml->incomplete_frm == NULL) {
                        /* Initial Segment */
-                       if (cfpkt_peek_head(pkt, rfml->seghead, 6) < 0)
+                       if (cfpkt_peek_head(pkt, rfml->seghead, 6) != 0)
                                goto out;
 
                        rfml->pdu_size = get_unaligned_le16(rfml->seghead+4);
@@ -233,7 +233,7 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
        if (cfpkt_getlen(pkt) > rfml->fragment_size + RFM_HEAD_SIZE)
                err = cfpkt_peek_head(pkt, head, 6);
 
-       if (err < 0)
+       if (err != 0)
                goto out;
 
        while (cfpkt_getlen(frontpkt) > rfml->fragment_size + RFM_HEAD_SIZE) {
index b5d1129..95ac756 100644 (file)
@@ -6612,12 +6612,13 @@ void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
                netdev_err_once(dev, "%s() called with weight %d\n", __func__,
                                weight);
        napi->weight = weight;
-       list_add(&napi->dev_list, &dev->napi_list);
        napi->dev = dev;
 #ifdef CONFIG_NETPOLL
        napi->poll_owner = -1;
 #endif
        set_bit(NAPI_STATE_SCHED, &napi->state);
+       set_bit(NAPI_STATE_NPSVC, &napi->state);
+       list_add_rcu(&napi->dev_list, &dev->napi_list);
        napi_hash_add(napi);
 }
 EXPORT_SYMBOL(netif_napi_add);
@@ -8742,13 +8743,15 @@ struct bpf_xdp_link {
        int flags;
 };
 
-static enum bpf_xdp_mode dev_xdp_mode(u32 flags)
+static enum bpf_xdp_mode dev_xdp_mode(struct net_device *dev, u32 flags)
 {
        if (flags & XDP_FLAGS_HW_MODE)
                return XDP_MODE_HW;
        if (flags & XDP_FLAGS_DRV_MODE)
                return XDP_MODE_DRV;
-       return XDP_MODE_SKB;
+       if (flags & XDP_FLAGS_SKB_MODE)
+               return XDP_MODE_SKB;
+       return dev->netdev_ops->ndo_bpf ? XDP_MODE_DRV : XDP_MODE_SKB;
 }
 
 static bpf_op_t dev_xdp_bpf_op(struct net_device *dev, enum bpf_xdp_mode mode)
@@ -8896,7 +8899,7 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
                return -EINVAL;
        }
 
-       mode = dev_xdp_mode(flags);
+       mode = dev_xdp_mode(dev, flags);
        /* can't replace attached link */
        if (dev_xdp_link(dev, mode)) {
                NL_SET_ERR_MSG(extack, "Can't replace active BPF XDP link");
@@ -8984,7 +8987,7 @@ static int dev_xdp_detach_link(struct net_device *dev,
 
        ASSERT_RTNL();
 
-       mode = dev_xdp_mode(link->flags);
+       mode = dev_xdp_mode(dev, link->flags);
        if (dev_xdp_link(dev, mode) != link)
                return -EINVAL;
 
@@ -9080,7 +9083,7 @@ static int bpf_xdp_link_update(struct bpf_link *link, struct bpf_prog *new_prog,
                goto out_unlock;
        }
 
-       mode = dev_xdp_mode(xdp_link->flags);
+       mode = dev_xdp_mode(xdp_link->dev, xdp_link->flags);
        bpf_op = dev_xdp_bpf_op(xdp_link->dev, mode);
        err = dev_xdp_install(xdp_link->dev, mode, bpf_op, NULL,
                              xdp_link->flags, new_prog);
@@ -9164,7 +9167,7 @@ out_put_dev:
 int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
                      int fd, int expected_fd, u32 flags)
 {
-       enum bpf_xdp_mode mode = dev_xdp_mode(flags);
+       enum bpf_xdp_mode mode = dev_xdp_mode(dev, flags);
        struct bpf_prog *new_prog = NULL, *old_prog = NULL;
        int err;
 
index 093e90e..2338753 100644 (file)
@@ -162,7 +162,7 @@ static void poll_napi(struct net_device *dev)
        struct napi_struct *napi;
        int cpu = smp_processor_id();
 
-       list_for_each_entry(napi, &dev->napi_list, dev_list) {
+       list_for_each_entry_rcu(napi, &dev->napi_list, dev_list) {
                if (cmpxchg(&napi->poll_owner, -1, cpu) == -1) {
                        poll_one_napi(napi);
                        smp_store_release(&napi->poll_owner, -1);
index e18184f..6faf73d 100644 (file)
@@ -820,6 +820,7 @@ void skb_tx_error(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(skb_tx_error);
 
+#ifdef CONFIG_TRACEPOINTS
 /**
  *     consume_skb - free an skbuff
  *     @skb: buffer to free
@@ -837,6 +838,7 @@ void consume_skb(struct sk_buff *skb)
        __kfree_skb(skb);
 }
 EXPORT_SYMBOL(consume_skb);
+#endif
 
 /**
  *     consume_stateless_skb - free an skbuff, assuming it is stateless
index e4f40b1..8eb2c92 100644 (file)
@@ -3254,7 +3254,7 @@ void sk_common_release(struct sock *sk)
                sk->sk_prot->destroy(sk);
 
        /*
-        * Observation: when sock_common_release is called, processes have
+        * Observation: when sk_common_release is called, processes have
         * no access to socket. But net still has.
         * Step one, detach it from networking:
         *
index c89b46f..ffc5332 100644 (file)
@@ -2121,7 +2121,8 @@ void fib_info_notify_update(struct net *net, struct nl_info *info)
                struct hlist_head *head = &net->ipv4.fib_table_hash[h];
                struct fib_table *tb;
 
-               hlist_for_each_entry_rcu(tb, head, tb_hlist)
+               hlist_for_each_entry_rcu(tb, head, tb_hlist,
+                                        lockdep_rtnl_is_held())
                        __fib_info_notify_update(net, tb, info);
        }
 }
index cc8049b..134e923 100644 (file)
@@ -446,7 +446,7 @@ static int nh_check_attr_group(struct net *net, struct nlattr *tb[],
        unsigned int i, j;
        u8 nhg_fdb = 0;
 
-       if (len & (sizeof(struct nexthop_grp) - 1)) {
+       if (!len || len & (sizeof(struct nexthop_grp) - 1)) {
                NL_SET_ERR_MSG(extack,
                               "Invalid length for nexthop group attribute");
                return -EINVAL;
@@ -1187,6 +1187,9 @@ static struct nexthop *nexthop_create_group(struct net *net,
        struct nexthop *nh;
        int i;
 
+       if (WARN_ON(!num_nh))
+               return ERR_PTR(-EINVAL);
+
        nh = nexthop_alloc();
        if (!nh)
                return ERR_PTR(-ENOMEM);
index 6fd4330..407956b 100644 (file)
@@ -610,7 +610,7 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        } else if (!ipc.oif) {
                ipc.oif = inet->uc_index;
        } else if (ipv4_is_lbcast(daddr) && inet->uc_index) {
-               /* oif is set, packet is to local broadcast and
+               /* oif is set, packet is to local broadcast
                 * and uc_index is set. oif is most likely set
                 * by sk_bound_dev_if. If uc_index != oif check if the
                 * oif is an L3 master and uc_index is an L3 slave.
index f635914..a0217e5 100644 (file)
@@ -915,7 +915,15 @@ int ip6_tnl_rcv(struct ip6_tnl *t, struct sk_buff *skb,
                struct metadata_dst *tun_dst,
                bool log_ecn_err)
 {
-       return __ip6_tnl_rcv(t, skb, tpi, tun_dst, ip6ip6_dscp_ecn_decapsulate,
+       int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
+                                   const struct ipv6hdr *ipv6h,
+                                   struct sk_buff *skb);
+
+       dscp_ecn_decapsulate = ip6ip6_dscp_ecn_decapsulate;
+       if (tpi->proto == htons(ETH_P_IP))
+               dscp_ecn_decapsulate = ip4ip6_dscp_ecn_decapsulate;
+
+       return __ip6_tnl_rcv(t, skb, tpi, tun_dst, dscp_ecn_decapsulate,
                             log_ecn_err);
 }
 EXPORT_SYMBOL(ip6_tnl_rcv);
index e71ca5a..864326f 100644 (file)
@@ -154,7 +154,7 @@ int l3mdev_master_upper_ifindex_by_index_rcu(struct net *net, int ifindex)
 EXPORT_SYMBOL_GPL(l3mdev_master_upper_ifindex_by_index_rcu);
 
 /**
- *     l3mdev_fib_table - get FIB table id associated with an L3
+ *     l3mdev_fib_table_rcu - get FIB table id associated with an L3
  *                             master interface
  *     @dev: targeted interface
  */
index 1aad411..8ccd4a1 100644 (file)
@@ -892,7 +892,6 @@ restart:
                goto out;
        }
 
-wait_for_sndbuf:
        __mptcp_flush_join_list(msk);
        ssk = mptcp_subflow_get_send(msk);
        while (!sk_stream_memory_free(sk) ||
@@ -982,7 +981,7 @@ wait_for_sndbuf:
                                 */
                                mptcp_set_timeout(sk, ssk);
                                release_sock(ssk);
-                               goto wait_for_sndbuf;
+                               goto restart;
                        }
                }
        }
index 4f897b1..810cca2 100644 (file)
@@ -62,6 +62,8 @@ static const unsigned int sctp_timeouts[SCTP_CONNTRACK_MAX] = {
        [SCTP_CONNTRACK_HEARTBEAT_ACKED]        = 210 SECS,
 };
 
+#define        SCTP_FLAG_HEARTBEAT_VTAG_FAILED 1
+
 #define sNO SCTP_CONNTRACK_NONE
 #define        sCL SCTP_CONNTRACK_CLOSED
 #define        sCW SCTP_CONNTRACK_COOKIE_WAIT
@@ -369,6 +371,7 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
        u_int32_t offset, count;
        unsigned int *timeouts;
        unsigned long map[256 / sizeof(unsigned long)] = { 0 };
+       bool ignore = false;
 
        if (sctp_error(skb, dataoff, state))
                return -NF_ACCEPT;
@@ -427,15 +430,39 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
                        /* Sec 8.5.1 (D) */
                        if (sh->vtag != ct->proto.sctp.vtag[dir])
                                goto out_unlock;
-               } else if (sch->type == SCTP_CID_HEARTBEAT ||
-                          sch->type == SCTP_CID_HEARTBEAT_ACK) {
+               } else if (sch->type == SCTP_CID_HEARTBEAT) {
+                       if (ct->proto.sctp.vtag[dir] == 0) {
+                               pr_debug("Setting %d vtag %x for dir %d\n", sch->type, sh->vtag, dir);
+                               ct->proto.sctp.vtag[dir] = sh->vtag;
+                       } else if (sh->vtag != ct->proto.sctp.vtag[dir]) {
+                               if (test_bit(SCTP_CID_DATA, map) || ignore)
+                                       goto out_unlock;
+
+                               ct->proto.sctp.flags |= SCTP_FLAG_HEARTBEAT_VTAG_FAILED;
+                               ct->proto.sctp.last_dir = dir;
+                               ignore = true;
+                               continue;
+                       } else if (ct->proto.sctp.flags & SCTP_FLAG_HEARTBEAT_VTAG_FAILED) {
+                               ct->proto.sctp.flags &= ~SCTP_FLAG_HEARTBEAT_VTAG_FAILED;
+                       }
+               } else if (sch->type == SCTP_CID_HEARTBEAT_ACK) {
                        if (ct->proto.sctp.vtag[dir] == 0) {
                                pr_debug("Setting vtag %x for dir %d\n",
                                         sh->vtag, dir);
                                ct->proto.sctp.vtag[dir] = sh->vtag;
                        } else if (sh->vtag != ct->proto.sctp.vtag[dir]) {
-                               pr_debug("Verification tag check failed\n");
-                               goto out_unlock;
+                               if (test_bit(SCTP_CID_DATA, map) || ignore)
+                                       goto out_unlock;
+
+                               if ((ct->proto.sctp.flags & SCTP_FLAG_HEARTBEAT_VTAG_FAILED) == 0 ||
+                                   ct->proto.sctp.last_dir == dir)
+                                       goto out_unlock;
+
+                               ct->proto.sctp.flags &= ~SCTP_FLAG_HEARTBEAT_VTAG_FAILED;
+                               ct->proto.sctp.vtag[dir] = sh->vtag;
+                               ct->proto.sctp.vtag[!dir] = 0;
+                       } else if (ct->proto.sctp.flags & SCTP_FLAG_HEARTBEAT_VTAG_FAILED) {
+                               ct->proto.sctp.flags &= ~SCTP_FLAG_HEARTBEAT_VTAG_FAILED;
                        }
                }
 
@@ -470,6 +497,10 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
        }
        spin_unlock_bh(&ct->lock);
 
+       /* allow but do not refresh timeout */
+       if (ignore)
+               return NF_ACCEPT;
+
        timeouts = nf_ct_timeout_lookup(ct);
        if (!timeouts)
                timeouts = nf_sctp_pernet(nf_ct_net(ct))->timeouts;
index fd814e5..71e501c 100644 (file)
@@ -3770,7 +3770,8 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
                        goto nla_put_failure;
        }
 
-       if (nla_put(skb, NFTA_SET_USERDATA, set->udlen, set->udata))
+       if (set->udata &&
+           nla_put(skb, NFTA_SET_USERDATA, set->udlen, set->udata))
                goto nla_put_failure;
 
        nest = nla_nest_start_noflag(skb, NFTA_SET_DESC);
index ed7cb9f..7a2e596 100644 (file)
@@ -87,7 +87,9 @@ void nft_payload_eval(const struct nft_expr *expr,
        u32 *dest = &regs->data[priv->dreg];
        int offset;
 
-       dest[priv->len / NFT_REG32_SIZE] = 0;
+       if (priv->len % NFT_REG32_SIZE)
+               dest[priv->len / NFT_REG32_SIZE] = 0;
+
        switch (priv->base) {
        case NFT_PAYLOAD_LL_HEADER:
                if (!skb_mac_header_was_set(skb))
index 4b2834f..217ab36 100644 (file)
@@ -218,11 +218,11 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
                               struct nft_rbtree_elem *new,
                               struct nft_set_ext **ext)
 {
+       bool overlap = false, dup_end_left = false, dup_end_right = false;
        struct nft_rbtree *priv = nft_set_priv(set);
        u8 genmask = nft_genmask_next(net);
        struct nft_rbtree_elem *rbe;
        struct rb_node *parent, **p;
-       bool overlap = false;
        int d;
 
        /* Detect overlaps as we descend the tree. Set the flag in these cases:
@@ -238,24 +238,44 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
         *
         * b1. _ _ __>|  !_ _ __|  (insert end before existing start)
         * b2. _ _ ___|  !_ _ _>|  (insert end after existing start)
-        * b3. _ _ ___! >|_ _ __|  (insert start after existing end)
+        * b3. _ _ ___! >|_ _ __|  (insert start after existing end, as a leaf)
+        *            '--' no nodes falling in this range
+        * b4.          >|_ _   !  (insert start before existing start)
         *
         * Case a3. resolves to b3.:
         * - if the inserted start element is the leftmost, because the '0'
         *   element in the tree serves as end element
-        * - otherwise, if an existing end is found. Note that end elements are
-        *   always inserted after corresponding start elements.
+        * - otherwise, if an existing end is found immediately to the left. If
+        *   there are existing nodes in between, we need to further descend the
+        *   tree before we can conclude the new start isn't causing an overlap
+        *
+        * or to b4., which, preceded by a3., means we already traversed one or
+        * more existing intervals entirely, from the right.
         *
         * For a new, rightmost pair of elements, we'll hit cases b3. and b2.,
         * in that order.
         *
         * The flag is also cleared in two special cases:
         *
-        * b4. |__ _ _!|<_ _ _   (insert start right before existing end)
-        * b5. |__ _ >|!__ _ _   (insert end right after existing start)
+        * b5. |__ _ _!|<_ _ _   (insert start right before existing end)
+        * b6. |__ _ >|!__ _ _   (insert end right after existing start)
         *
         * which always happen as last step and imply that no further
         * overlapping is possible.
+        *
+        * Another special case comes from the fact that start elements matching
+        * an already existing start element are allowed: insertion is not
+        * performed but we return -EEXIST in that case, and the error will be
+        * cleared by the caller if NLM_F_EXCL is not present in the request.
+        * This way, request for insertion of an exact overlap isn't reported as
+        * error to userspace if not desired.
+        *
+        * However, if the existing start matches a pre-existing start, but the
+        * end element doesn't match the corresponding pre-existing end element,
+        * we need to report a partial overlap. This is a local condition that
+        * can be noticed without need for a tracking flag, by checking for a
+        * local duplicated end for a corresponding start, from left and right,
+        * separately.
         */
 
        parent = NULL;
@@ -272,26 +292,41 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
                        if (nft_rbtree_interval_start(new)) {
                                if (nft_rbtree_interval_end(rbe) &&
                                    nft_set_elem_active(&rbe->ext, genmask) &&
-                                   !nft_set_elem_expired(&rbe->ext))
+                                   !nft_set_elem_expired(&rbe->ext) && !*p)
                                        overlap = false;
                        } else {
+                               if (dup_end_left && !*p)
+                                       return -ENOTEMPTY;
+
                                overlap = nft_rbtree_interval_end(rbe) &&
                                          nft_set_elem_active(&rbe->ext,
                                                              genmask) &&
                                          !nft_set_elem_expired(&rbe->ext);
+
+                               if (overlap) {
+                                       dup_end_right = true;
+                                       continue;
+                               }
                        }
                } else if (d > 0) {
                        p = &parent->rb_right;
 
                        if (nft_rbtree_interval_end(new)) {
+                               if (dup_end_right && !*p)
+                                       return -ENOTEMPTY;
+
                                overlap = nft_rbtree_interval_end(rbe) &&
                                          nft_set_elem_active(&rbe->ext,
                                                              genmask) &&
                                          !nft_set_elem_expired(&rbe->ext);
-                       } else if (nft_rbtree_interval_end(rbe) &&
-                                  nft_set_elem_active(&rbe->ext, genmask) &&
+
+                               if (overlap) {
+                                       dup_end_left = true;
+                                       continue;
+                               }
+                       } else if (nft_set_elem_active(&rbe->ext, genmask) &&
                                   !nft_set_elem_expired(&rbe->ext)) {
-                               overlap = true;
+                               overlap = nft_rbtree_interval_end(rbe);
                        }
                } else {
                        if (nft_rbtree_interval_end(rbe) &&
@@ -316,6 +351,8 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
                                p = &parent->rb_left;
                        }
                }
+
+               dup_end_left = dup_end_right = false;
        }
 
        if (overlap)
index d07de2c..f73a838 100644 (file)
@@ -85,6 +85,7 @@ static void netlbl_domhsh_free_entry(struct rcu_head *entry)
                        kfree(netlbl_domhsh_addr6_entry(iter6));
                }
 #endif /* IPv6 */
+               kfree(ptr->def.addrsel);
        }
        kfree(ptr->domain);
        kfree(ptr);
@@ -537,6 +538,8 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                                goto add_return;
                }
 #endif /* IPv6 */
+               /* cleanup the new entry since we've moved everything over */
+               netlbl_domhsh_free_entry(&entry->rcu);
        } else
                ret_val = -EINVAL;
 
@@ -580,6 +583,12 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
 {
        int ret_val = 0;
        struct audit_buffer *audit_buf;
+       struct netlbl_af4list *iter4;
+       struct netlbl_domaddr4_map *map4;
+#if IS_ENABLED(CONFIG_IPV6)
+       struct netlbl_af6list *iter6;
+       struct netlbl_domaddr6_map *map6;
+#endif /* IPv6 */
 
        if (entry == NULL)
                return -ENOENT;
@@ -597,6 +606,9 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
                ret_val = -ENOENT;
        spin_unlock(&netlbl_domhsh_lock);
 
+       if (ret_val)
+               return ret_val;
+
        audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
        if (audit_buf != NULL) {
                audit_log_format(audit_buf,
@@ -606,40 +618,29 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
                audit_log_end(audit_buf);
        }
 
-       if (ret_val == 0) {
-               struct netlbl_af4list *iter4;
-               struct netlbl_domaddr4_map *map4;
-#if IS_ENABLED(CONFIG_IPV6)
-               struct netlbl_af6list *iter6;
-               struct netlbl_domaddr6_map *map6;
-#endif /* IPv6 */
-
-               switch (entry->def.type) {
-               case NETLBL_NLTYPE_ADDRSELECT:
-                       netlbl_af4list_foreach_rcu(iter4,
-                                            &entry->def.addrsel->list4) {
-                               map4 = netlbl_domhsh_addr4_entry(iter4);
-                               cipso_v4_doi_putdef(map4->def.cipso);
-                       }
+       switch (entry->def.type) {
+       case NETLBL_NLTYPE_ADDRSELECT:
+               netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
+                       map4 = netlbl_domhsh_addr4_entry(iter4);
+                       cipso_v4_doi_putdef(map4->def.cipso);
+               }
 #if IS_ENABLED(CONFIG_IPV6)
-                       netlbl_af6list_foreach_rcu(iter6,
-                                            &entry->def.addrsel->list6) {
-                               map6 = netlbl_domhsh_addr6_entry(iter6);
-                               calipso_doi_putdef(map6->def.calipso);
-                       }
+               netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
+                       map6 = netlbl_domhsh_addr6_entry(iter6);
+                       calipso_doi_putdef(map6->def.calipso);
+               }
 #endif /* IPv6 */
-                       break;
-               case NETLBL_NLTYPE_CIPSOV4:
-                       cipso_v4_doi_putdef(entry->def.cipso);
-                       break;
+               break;
+       case NETLBL_NLTYPE_CIPSOV4:
+               cipso_v4_doi_putdef(entry->def.cipso);
+               break;
 #if IS_ENABLED(CONFIG_IPV6)
-               case NETLBL_NLTYPE_CALIPSO:
-                       calipso_doi_putdef(entry->def.calipso);
-                       break;
+       case NETLBL_NLTYPE_CALIPSO:
+               calipso_doi_putdef(entry->def.calipso);
+               break;
 #endif /* IPv6 */
-               }
-               call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
        }
+       call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
 
        return ret_val;
 }
index 6d29a36..884cff7 100644 (file)
@@ -488,7 +488,6 @@ enum rxrpc_call_flag {
        RXRPC_CALL_RX_LAST,             /* Received the last packet (at rxtx_top) */
        RXRPC_CALL_TX_LAST,             /* Last packet in Tx buffer (at rxtx_top) */
        RXRPC_CALL_SEND_PING,           /* A ping will need to be sent */
-       RXRPC_CALL_PINGING,             /* Ping in process */
        RXRPC_CALL_RETRANS_TIMEOUT,     /* Retransmission due to timeout occurred */
        RXRPC_CALL_BEGAN_RX_TIMER,      /* We began the expect_rx_by timer */
        RXRPC_CALL_RX_HEARD,            /* The peer responded at least once to this call */
@@ -673,9 +672,13 @@ struct rxrpc_call {
        rxrpc_seq_t             ackr_consumed;  /* Highest packet shown consumed */
        rxrpc_seq_t             ackr_seen;      /* Highest packet shown seen */
 
-       /* ping management */
-       rxrpc_serial_t          ping_serial;    /* Last ping sent */
-       ktime_t                 ping_time;      /* Time last ping sent */
+       /* RTT management */
+       rxrpc_serial_t          rtt_serial[4];  /* Serial number of DATA or PING sent */
+       ktime_t                 rtt_sent_at[4]; /* Time packet sent */
+       unsigned long           rtt_avail;      /* Mask of available slots in bits 0-3,
+                                                * Mask of pending samples in 8-11 */
+#define RXRPC_CALL_RTT_AVAIL_MASK      0xf
+#define RXRPC_CALL_RTT_PEND_SHIFT      8
 
        /* transmission-phase ACK management */
        ktime_t                 acks_latest_ts; /* Timestamp of latest ACK received */
@@ -1037,7 +1040,7 @@ static inline bool __rxrpc_abort_eproto(struct rxrpc_call *call,
 /*
  * rtt.c
  */
-void rxrpc_peer_add_rtt(struct rxrpc_call *, enum rxrpc_rtt_rx_trace,
+void rxrpc_peer_add_rtt(struct rxrpc_call *, enum rxrpc_rtt_rx_trace, int,
                        rxrpc_serial_t, rxrpc_serial_t, ktime_t, ktime_t);
 unsigned long rxrpc_get_rto_backoff(struct rxrpc_peer *, bool);
 void rxrpc_peer_init_rtt(struct rxrpc_peer *);
index 38a4616..a40fae0 100644 (file)
@@ -153,6 +153,7 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp,
        call->cong_ssthresh = RXRPC_RXTX_BUFF_SIZE - 1;
 
        call->rxnet = rxnet;
+       call->rtt_avail = RXRPC_CALL_RTT_AVAIL_MASK;
        atomic_inc(&rxnet->nr_calls);
        return call;
 
index 7675793..19ddfc9 100644 (file)
@@ -608,36 +608,57 @@ unlock:
 }
 
 /*
- * Process a requested ACK.
+ * See if there's a cached RTT probe to complete.
  */
-static void rxrpc_input_requested_ack(struct rxrpc_call *call,
-                                     ktime_t resp_time,
-                                     rxrpc_serial_t orig_serial,
-                                     rxrpc_serial_t ack_serial)
+static void rxrpc_complete_rtt_probe(struct rxrpc_call *call,
+                                    ktime_t resp_time,
+                                    rxrpc_serial_t acked_serial,
+                                    rxrpc_serial_t ack_serial,
+                                    enum rxrpc_rtt_rx_trace type)
 {
-       struct rxrpc_skb_priv *sp;
-       struct sk_buff *skb;
+       rxrpc_serial_t orig_serial;
+       unsigned long avail;
        ktime_t sent_at;
-       int ix;
+       bool matched = false;
+       int i;
 
-       for (ix = 0; ix < RXRPC_RXTX_BUFF_SIZE; ix++) {
-               skb = call->rxtx_buffer[ix];
-               if (!skb)
-                       continue;
+       avail = READ_ONCE(call->rtt_avail);
+       smp_rmb(); /* Read avail bits before accessing data. */
 
-               sent_at = skb->tstamp;
-               smp_rmb(); /* Read timestamp before serial. */
-               sp = rxrpc_skb(skb);
-               if (sp->hdr.serial != orig_serial)
+       for (i = 0; i < ARRAY_SIZE(call->rtt_serial); i++) {
+               if (!test_bit(i + RXRPC_CALL_RTT_PEND_SHIFT, &avail))
                        continue;
-               goto found;
-       }
 
-       return;
+               sent_at = call->rtt_sent_at[i];
+               orig_serial = call->rtt_serial[i];
+
+               if (orig_serial == acked_serial) {
+                       clear_bit(i + RXRPC_CALL_RTT_PEND_SHIFT, &call->rtt_avail);
+                       smp_mb(); /* Read data before setting avail bit */
+                       set_bit(i, &call->rtt_avail);
+                       if (type != rxrpc_rtt_rx_cancel)
+                               rxrpc_peer_add_rtt(call, type, i, acked_serial, ack_serial,
+                                                  sent_at, resp_time);
+                       else
+                               trace_rxrpc_rtt_rx(call, rxrpc_rtt_rx_cancel, i,
+                                                  orig_serial, acked_serial, 0, 0);
+                       matched = true;
+               }
+
+               /* If a later serial is being acked, then mark this slot as
+                * being available.
+                */
+               if (after(acked_serial, orig_serial)) {
+                       trace_rxrpc_rtt_rx(call, rxrpc_rtt_rx_obsolete, i,
+                                          orig_serial, acked_serial, 0, 0);
+                       clear_bit(i + RXRPC_CALL_RTT_PEND_SHIFT, &call->rtt_avail);
+                       smp_wmb();
+                       set_bit(i, &call->rtt_avail);
+               }
+       }
 
-found:
-       rxrpc_peer_add_rtt(call, rxrpc_rtt_rx_requested_ack,
-                          orig_serial, ack_serial, sent_at, resp_time);
+       if (!matched)
+               trace_rxrpc_rtt_rx(call, rxrpc_rtt_rx_lost, 9, 0, acked_serial, 0, 0);
 }
 
 /*
@@ -682,27 +703,11 @@ static void rxrpc_input_check_for_lost_ack(struct rxrpc_call *call)
  */
 static void rxrpc_input_ping_response(struct rxrpc_call *call,
                                      ktime_t resp_time,
-                                     rxrpc_serial_t orig_serial,
+                                     rxrpc_serial_t acked_serial,
                                      rxrpc_serial_t ack_serial)
 {
-       rxrpc_serial_t ping_serial;
-       ktime_t ping_time;
-
-       ping_time = call->ping_time;
-       smp_rmb();
-       ping_serial = READ_ONCE(call->ping_serial);
-
-       if (orig_serial == call->acks_lost_ping)
+       if (acked_serial == call->acks_lost_ping)
                rxrpc_input_check_for_lost_ack(call);
-
-       if (before(orig_serial, ping_serial) ||
-           !test_and_clear_bit(RXRPC_CALL_PINGING, &call->flags))
-               return;
-       if (after(orig_serial, ping_serial))
-               return;
-
-       rxrpc_peer_add_rtt(call, rxrpc_rtt_rx_ping_response,
-                          orig_serial, ack_serial, ping_time, resp_time);
 }
 
 /*
@@ -843,7 +848,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
                struct rxrpc_ackinfo info;
                u8 acks[RXRPC_MAXACKS];
        } buf;
-       rxrpc_serial_t acked_serial;
+       rxrpc_serial_t ack_serial, acked_serial;
        rxrpc_seq_t first_soft_ack, hard_ack, prev_pkt;
        int nr_acks, offset, ioffset;
 
@@ -856,6 +861,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
        }
        offset += sizeof(buf.ack);
 
+       ack_serial = sp->hdr.serial;
        acked_serial = ntohl(buf.ack.serial);
        first_soft_ack = ntohl(buf.ack.firstPacket);
        prev_pkt = ntohl(buf.ack.previousPacket);
@@ -864,31 +870,42 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
        summary.ack_reason = (buf.ack.reason < RXRPC_ACK__INVALID ?
                              buf.ack.reason : RXRPC_ACK__INVALID);
 
-       trace_rxrpc_rx_ack(call, sp->hdr.serial, acked_serial,
+       trace_rxrpc_rx_ack(call, ack_serial, acked_serial,
                           first_soft_ack, prev_pkt,
                           summary.ack_reason, nr_acks);
 
-       if (buf.ack.reason == RXRPC_ACK_PING_RESPONSE)
+       switch (buf.ack.reason) {
+       case RXRPC_ACK_PING_RESPONSE:
                rxrpc_input_ping_response(call, skb->tstamp, acked_serial,
-                                         sp->hdr.serial);
-       if (buf.ack.reason == RXRPC_ACK_REQUESTED)
-               rxrpc_input_requested_ack(call, skb->tstamp, acked_serial,
-                                         sp->hdr.serial);
+                                         ack_serial);
+               rxrpc_complete_rtt_probe(call, skb->tstamp, acked_serial, ack_serial,
+                                        rxrpc_rtt_rx_ping_response);
+               break;
+       case RXRPC_ACK_REQUESTED:
+               rxrpc_complete_rtt_probe(call, skb->tstamp, acked_serial, ack_serial,
+                                        rxrpc_rtt_rx_requested_ack);
+               break;
+       default:
+               if (acked_serial != 0)
+                       rxrpc_complete_rtt_probe(call, skb->tstamp, acked_serial, ack_serial,
+                                                rxrpc_rtt_rx_cancel);
+               break;
+       }
 
        if (buf.ack.reason == RXRPC_ACK_PING) {
-               _proto("Rx ACK %%%u PING Request", sp->hdr.serial);
+               _proto("Rx ACK %%%u PING Request", ack_serial);
                rxrpc_propose_ACK(call, RXRPC_ACK_PING_RESPONSE,
-                                 sp->hdr.serial, true, true,
+                                 ack_serial, true, true,
                                  rxrpc_propose_ack_respond_to_ping);
        } else if (sp->hdr.flags & RXRPC_REQUEST_ACK) {
                rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED,
-                                 sp->hdr.serial, true, true,
+                                 ack_serial, true, true,
                                  rxrpc_propose_ack_respond_to_ack);
        }
 
        /* Discard any out-of-order or duplicate ACKs (outside lock). */
        if (!rxrpc_is_ack_valid(call, first_soft_ack, prev_pkt)) {
-               trace_rxrpc_rx_discard_ack(call->debug_id, sp->hdr.serial,
+               trace_rxrpc_rx_discard_ack(call->debug_id, ack_serial,
                                           first_soft_ack, call->ackr_first_seq,
                                           prev_pkt, call->ackr_prev_seq);
                return;
@@ -904,7 +921,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
 
        /* Discard any out-of-order or duplicate ACKs (inside lock). */
        if (!rxrpc_is_ack_valid(call, first_soft_ack, prev_pkt)) {
-               trace_rxrpc_rx_discard_ack(call->debug_id, sp->hdr.serial,
+               trace_rxrpc_rx_discard_ack(call->debug_id, ack_serial,
                                           first_soft_ack, call->ackr_first_seq,
                                           prev_pkt, call->ackr_prev_seq);
                goto out;
@@ -964,7 +981,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
            RXRPC_TX_ANNO_LAST &&
            summary.nr_acks == call->tx_top - hard_ack &&
            rxrpc_is_client_call(call))
-               rxrpc_propose_ACK(call, RXRPC_ACK_PING, sp->hdr.serial,
+               rxrpc_propose_ACK(call, RXRPC_ACK_PING, ack_serial,
                                  false, true,
                                  rxrpc_propose_ack_ping_for_lost_reply);
 
index 1ba43c3..3cfff79 100644 (file)
@@ -123,6 +123,49 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn,
        return top - hard_ack + 3;
 }
 
+/*
+ * Record the beginning of an RTT probe.
+ */
+static int rxrpc_begin_rtt_probe(struct rxrpc_call *call, rxrpc_serial_t serial,
+                                enum rxrpc_rtt_tx_trace why)
+{
+       unsigned long avail = call->rtt_avail;
+       int rtt_slot = 9;
+
+       if (!(avail & RXRPC_CALL_RTT_AVAIL_MASK))
+               goto no_slot;
+
+       rtt_slot = __ffs(avail & RXRPC_CALL_RTT_AVAIL_MASK);
+       if (!test_and_clear_bit(rtt_slot, &call->rtt_avail))
+               goto no_slot;
+
+       call->rtt_serial[rtt_slot] = serial;
+       call->rtt_sent_at[rtt_slot] = ktime_get_real();
+       smp_wmb(); /* Write data before avail bit */
+       set_bit(rtt_slot + RXRPC_CALL_RTT_PEND_SHIFT, &call->rtt_avail);
+
+       trace_rxrpc_rtt_tx(call, why, rtt_slot, serial);
+       return rtt_slot;
+
+no_slot:
+       trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_no_slot, rtt_slot, serial);
+       return -1;
+}
+
+/*
+ * Cancel an RTT probe.
+ */
+static void rxrpc_cancel_rtt_probe(struct rxrpc_call *call,
+                                  rxrpc_serial_t serial, int rtt_slot)
+{
+       if (rtt_slot != -1) {
+               clear_bit(rtt_slot + RXRPC_CALL_RTT_PEND_SHIFT, &call->rtt_avail);
+               smp_wmb(); /* Clear pending bit before setting slot */
+               set_bit(rtt_slot, &call->rtt_avail);
+               trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_cancel, rtt_slot, serial);
+       }
+}
+
 /*
  * Send an ACK call packet.
  */
@@ -136,7 +179,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
        rxrpc_serial_t serial;
        rxrpc_seq_t hard_ack, top;
        size_t len, n;
-       int ret;
+       int ret, rtt_slot = -1;
        u8 reason;
 
        if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags))
@@ -196,18 +239,8 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
        if (_serial)
                *_serial = serial;
 
-       if (ping) {
-               call->ping_serial = serial;
-               smp_wmb();
-               /* We need to stick a time in before we send the packet in case
-                * the reply gets back before kernel_sendmsg() completes - but
-                * asking UDP to send the packet can take a relatively long
-                * time.
-                */
-               call->ping_time = ktime_get_real();
-               set_bit(RXRPC_CALL_PINGING, &call->flags);
-               trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_ping, serial);
-       }
+       if (ping)
+               rtt_slot = rxrpc_begin_rtt_probe(call, serial, rxrpc_rtt_tx_ping);
 
        ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len);
        conn->params.peer->last_tx_at = ktime_get_seconds();
@@ -221,8 +254,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
 
        if (call->state < RXRPC_CALL_COMPLETE) {
                if (ret < 0) {
-                       if (ping)
-                               clear_bit(RXRPC_CALL_PINGING, &call->flags);
+                       rxrpc_cancel_rtt_probe(call, serial, rtt_slot);
                        rxrpc_propose_ACK(call, pkt->ack.reason,
                                          ntohl(pkt->ack.serial),
                                          false, true,
@@ -321,7 +353,7 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb,
        struct kvec iov[2];
        rxrpc_serial_t serial;
        size_t len;
-       int ret;
+       int ret, rtt_slot = -1;
 
        _enter(",{%d}", skb->len);
 
@@ -397,6 +429,8 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb,
        sp->hdr.serial = serial;
        smp_wmb(); /* Set serial before timestamp */
        skb->tstamp = ktime_get_real();
+       if (whdr.flags & RXRPC_REQUEST_ACK)
+               rtt_slot = rxrpc_begin_rtt_probe(call, serial, rxrpc_rtt_tx_data);
 
        /* send the packet by UDP
         * - returns -EMSGSIZE if UDP would have to fragment the packet
@@ -408,12 +442,15 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb,
        conn->params.peer->last_tx_at = ktime_get_seconds();
 
        up_read(&conn->params.local->defrag_sem);
-       if (ret < 0)
+       if (ret < 0) {
+               rxrpc_cancel_rtt_probe(call, serial, rtt_slot);
                trace_rxrpc_tx_fail(call->debug_id, serial, ret,
                                    rxrpc_tx_point_call_data_nofrag);
-       else
+       } else {
                trace_rxrpc_tx_packet(call->debug_id, &whdr,
                                      rxrpc_tx_point_call_data_nofrag);
+       }
+
        rxrpc_tx_backoff(call, ret);
        if (ret == -EMSGSIZE)
                goto send_fragmentable;
@@ -422,7 +459,6 @@ done:
        if (ret >= 0) {
                if (whdr.flags & RXRPC_REQUEST_ACK) {
                        call->peer->rtt_last_req = skb->tstamp;
-                       trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_data, serial);
                        if (call->peer->rtt_count > 1) {
                                unsigned long nowj = jiffies, ack_lost_at;
 
@@ -469,6 +505,8 @@ send_fragmentable:
        sp->hdr.serial = serial;
        smp_wmb(); /* Set serial before timestamp */
        skb->tstamp = ktime_get_real();
+       if (whdr.flags & RXRPC_REQUEST_ACK)
+               rtt_slot = rxrpc_begin_rtt_probe(call, serial, rxrpc_rtt_tx_data);
 
        switch (conn->params.local->srx.transport.family) {
        case AF_INET6:
@@ -487,12 +525,14 @@ send_fragmentable:
                BUG();
        }
 
-       if (ret < 0)
+       if (ret < 0) {
+               rxrpc_cancel_rtt_probe(call, serial, rtt_slot);
                trace_rxrpc_tx_fail(call->debug_id, serial, ret,
                                    rxrpc_tx_point_call_data_frag);
-       else
+       } else {
                trace_rxrpc_tx_packet(call->debug_id, &whdr,
                                      rxrpc_tx_point_call_data_frag);
+       }
        rxrpc_tx_backoff(call, ret);
 
        up_write(&conn->params.local->defrag_sem);
index ca29976..68396d0 100644 (file)
@@ -502,11 +502,21 @@ EXPORT_SYMBOL(rxrpc_kernel_get_peer);
  * rxrpc_kernel_get_srtt - Get a call's peer smoothed RTT
  * @sock: The socket on which the call is in progress.
  * @call: The call to query
+ * @_srtt: Where to store the SRTT value.
  *
- * Get the call's peer smoothed RTT.
+ * Get the call's peer smoothed RTT in uS.
  */
-u32 rxrpc_kernel_get_srtt(struct socket *sock, struct rxrpc_call *call)
+bool rxrpc_kernel_get_srtt(struct socket *sock, struct rxrpc_call *call,
+                          u32 *_srtt)
 {
-       return call->peer->srtt_us >> 3;
+       struct rxrpc_peer *peer = call->peer;
+
+       if (peer->rtt_count == 0) {
+               *_srtt = 1000000; /* 1S */
+               return false;
+       }
+
+       *_srtt = call->peer->srtt_us >> 3;
+       return true;
 }
 EXPORT_SYMBOL(rxrpc_kernel_get_srtt);
index 928d8b3..1221b06 100644 (file)
@@ -146,6 +146,7 @@ static void rxrpc_ack_update_rtt(struct rxrpc_peer *peer, long rtt_us)
  * exclusive access to the peer RTT data.
  */
 void rxrpc_peer_add_rtt(struct rxrpc_call *call, enum rxrpc_rtt_rx_trace why,
+                       int rtt_slot,
                        rxrpc_serial_t send_serial, rxrpc_serial_t resp_serial,
                        ktime_t send_time, ktime_t resp_time)
 {
@@ -162,7 +163,7 @@ void rxrpc_peer_add_rtt(struct rxrpc_call *call, enum rxrpc_rtt_rx_trace why,
                peer->rtt_count++;
        spin_unlock(&peer->rtt_input_lock);
 
-       trace_rxrpc_rtt_rx(call, why, send_serial, resp_serial,
+       trace_rxrpc_rtt_rx(call, why, rtt_slot, send_serial, resp_serial,
                           peer->srtt_us >> 3, peer->rto_j);
 }
 
index 52a24d4..e08130e 100644 (file)
@@ -1137,7 +1137,7 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
        ret = -ENOMEM;
        ticket = kmalloc(ticket_len, GFP_NOFS);
        if (!ticket)
-               goto temporary_error;
+               goto temporary_error_free_resp;
 
        eproto = tracepoint_string("rxkad_tkt_short");
        abort_code = RXKADPACKETSHORT;
@@ -1230,6 +1230,7 @@ protocol_error:
 
 temporary_error_free_ticket:
        kfree(ticket);
+temporary_error_free_resp:
        kfree(response);
 temporary_error:
        /* Ignore the response packet if we got a temporary error such as
index e6ad42b..2c36191 100644 (file)
@@ -704,7 +704,7 @@ static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
                err = ip_defrag(net, skb, user);
                local_bh_enable();
                if (err && err != -EINPROGRESS)
-                       goto out_free;
+                       return err;
 
                if (!err) {
                        *defrag = true;
index e981992..fe53c1e 100644 (file)
@@ -1176,9 +1176,27 @@ static void taprio_offload_config_changed(struct taprio_sched *q)
        spin_unlock(&q->current_entry_lock);
 }
 
-static void taprio_sched_to_offload(struct taprio_sched *q,
+static u32 tc_map_to_queue_mask(struct net_device *dev, u32 tc_mask)
+{
+       u32 i, queue_mask = 0;
+
+       for (i = 0; i < dev->num_tc; i++) {
+               u32 offset, count;
+
+               if (!(tc_mask & BIT(i)))
+                       continue;
+
+               offset = dev->tc_to_txq[i].offset;
+               count = dev->tc_to_txq[i].count;
+
+               queue_mask |= GENMASK(offset + count - 1, offset);
+       }
+
+       return queue_mask;
+}
+
+static void taprio_sched_to_offload(struct net_device *dev,
                                    struct sched_gate_list *sched,
-                                   const struct tc_mqprio_qopt *mqprio,
                                    struct tc_taprio_qopt_offload *offload)
 {
        struct sched_entry *entry;
@@ -1193,7 +1211,8 @@ static void taprio_sched_to_offload(struct taprio_sched *q,
 
                e->command = entry->command;
                e->interval = entry->interval;
-               e->gate_mask = entry->gate_mask;
+               e->gate_mask = tc_map_to_queue_mask(dev, entry->gate_mask);
+
                i++;
        }
 
@@ -1201,7 +1220,6 @@ static void taprio_sched_to_offload(struct taprio_sched *q,
 }
 
 static int taprio_enable_offload(struct net_device *dev,
-                                struct tc_mqprio_qopt *mqprio,
                                 struct taprio_sched *q,
                                 struct sched_gate_list *sched,
                                 struct netlink_ext_ack *extack)
@@ -1223,7 +1241,7 @@ static int taprio_enable_offload(struct net_device *dev,
                return -ENOMEM;
        }
        offload->enable = 1;
-       taprio_sched_to_offload(q, sched, mqprio, offload);
+       taprio_sched_to_offload(dev, sched, offload);
 
        err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_TAPRIO, offload);
        if (err < 0) {
@@ -1485,7 +1503,7 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
        }
 
        if (FULL_OFFLOAD_IS_ENABLED(q->flags))
-               err = taprio_enable_offload(dev, mqprio, q, new_admin, extack);
+               err = taprio_enable_offload(dev, q, new_admin, extack);
        else
                err = taprio_disable_offload(dev, q, extack);
        if (err)
index ec1fba1..836615f 100644 (file)
@@ -8060,8 +8060,6 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
 
        pr_debug("%s: begins, snum:%d\n", __func__, snum);
 
-       local_bh_disable();
-
        if (snum == 0) {
                /* Search for an available port. */
                int low, high, remaining, index;
@@ -8079,20 +8077,21 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                                continue;
                        index = sctp_phashfn(net, rover);
                        head = &sctp_port_hashtable[index];
-                       spin_lock(&head->lock);
+                       spin_lock_bh(&head->lock);
                        sctp_for_each_hentry(pp, &head->chain)
                                if ((pp->port == rover) &&
                                    net_eq(net, pp->net))
                                        goto next;
                        break;
                next:
-                       spin_unlock(&head->lock);
+                       spin_unlock_bh(&head->lock);
+                       cond_resched();
                } while (--remaining > 0);
 
                /* Exhausted local port range during search? */
                ret = 1;
                if (remaining <= 0)
-                       goto fail;
+                       return ret;
 
                /* OK, here is the one we will use.  HEAD (the port
                 * hash table list entry) is non-NULL and we hold it's
@@ -8107,7 +8106,7 @@ static int sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                 * port iterator, pp being NULL.
                 */
                head = &sctp_port_hashtable[sctp_phashfn(net, snum)];
-               spin_lock(&head->lock);
+               spin_lock_bh(&head->lock);
                sctp_for_each_hentry(pp, &head->chain) {
                        if ((pp->port == snum) && net_eq(pp->net, net))
                                goto pp_found;
@@ -8207,10 +8206,7 @@ success:
        ret = 0;
 
 fail_unlock:
-       spin_unlock(&head->lock);
-
-fail:
-       local_bh_enable();
+       spin_unlock_bh(&head->lock);
        return ret;
 }
 
index bda2536..6dc95dc 100644 (file)
@@ -88,12 +88,13 @@ static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt,
        int ret;
 
        if (outcnt <= stream->outcnt)
-               return 0;
+               goto out;
 
        ret = genradix_prealloc(&stream->out, outcnt, gfp);
        if (ret)
                return ret;
 
+out:
        stream->outcnt = outcnt;
        return 0;
 }
@@ -104,12 +105,13 @@ static int sctp_stream_alloc_in(struct sctp_stream *stream, __u16 incnt,
        int ret;
 
        if (incnt <= stream->incnt)
-               return 0;
+               goto out;
 
        ret = genradix_prealloc(&stream->in, incnt, gfp);
        if (ret)
                return ret;
 
+out:
        stream->incnt = incnt;
        return 0;
 }
index e1f64f4..da9ba6d 100644 (file)
@@ -170,13 +170,15 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
            (req->diag_ext & (1 << (SMC_DIAG_DMBINFO - 1))) &&
            !list_empty(&smc->conn.lgr->list)) {
                struct smc_connection *conn = &smc->conn;
-               struct smcd_diag_dmbinfo dinfo = {
-                       .linkid = *((u32 *)conn->lgr->id),
-                       .peer_gid = conn->lgr->peer_gid,
-                       .my_gid = conn->lgr->smcd->local_gid,
-                       .token = conn->rmb_desc->token,
-                       .peer_token = conn->peer_token
-               };
+               struct smcd_diag_dmbinfo dinfo;
+
+               memset(&dinfo, 0, sizeof(dinfo));
+
+               dinfo.linkid = *((u32 *)conn->lgr->id);
+               dinfo.peer_gid = conn->lgr->peer_gid;
+               dinfo.my_gid = conn->lgr->smcd->local_gid;
+               dinfo.token = conn->rmb_desc->token;
+               dinfo.peer_token = conn->peer_token;
 
                if (nla_put(skb, SMC_DIAG_DMBINFO, sizeof(dinfo), &dinfo) < 0)
                        goto errout;
index dbbe8ea..0c01446 100644 (file)
@@ -3610,7 +3610,7 @@ int kernel_getsockname(struct socket *sock, struct sockaddr *addr)
 EXPORT_SYMBOL(kernel_getsockname);
 
 /**
- *     kernel_peername - get the address which the socket is connected (kernel space)
+ *     kernel_getpeername - get the address which the socket is connected (kernel space)
  *     @sock: socket
  *     @addr: address holder
  *
@@ -3671,7 +3671,7 @@ int kernel_sendpage_locked(struct sock *sk, struct page *page, int offset,
 EXPORT_SYMBOL(kernel_sendpage_locked);
 
 /**
- *     kernel_shutdown - shut down part of a full-duplex connection (kernel space)
+ *     kernel_sock_shutdown - shut down part of a full-duplex connection (kernel space)
  *     @sock: socket
  *     @how: connection part
  *
index 001bcb0..c38baba 100644 (file)
@@ -757,10 +757,12 @@ static void tipc_aead_encrypt_done(struct crypto_async_request *base, int err)
        switch (err) {
        case 0:
                this_cpu_inc(tx->stats->stat[STAT_ASYNC_OK]);
+               rcu_read_lock();
                if (likely(test_bit(0, &b->up)))
                        b->media->send_msg(net, skb, b, &tx_ctx->dst);
                else
                        kfree_skb(skb);
+               rcu_read_unlock();
                break;
        case -EINPROGRESS:
                return;
index 62c2756..95e4cdb 100644 (file)
@@ -66,7 +66,6 @@ KBUILD_CFLAGS += -Wnested-externs
 KBUILD_CFLAGS += -Wshadow
 KBUILD_CFLAGS += $(call cc-option, -Wlogical-op)
 KBUILD_CFLAGS += -Wmissing-field-initializers
-KBUILD_CFLAGS += -Wsign-compare
 KBUILD_CFLAGS += -Wtype-limits
 KBUILD_CFLAGS += $(call cc-option, -Wmaybe-uninitialized)
 KBUILD_CFLAGS += $(call cc-option, -Wunused-macros)
@@ -87,6 +86,7 @@ KBUILD_CFLAGS += -Wpacked
 KBUILD_CFLAGS += -Wpadded
 KBUILD_CFLAGS += -Wpointer-arith
 KBUILD_CFLAGS += -Wredundant-decls
+KBUILD_CFLAGS += -Wsign-compare
 KBUILD_CFLAGS += -Wswitch-default
 KBUILD_CFLAGS += $(call cc-option, -Wpacked-bitfield-compat)
 
index b071bf4..3bc48c7 100644 (file)
@@ -71,7 +71,7 @@ static void drain_openssl_errors(void)
 static const char *key_pass;
 static BIO *wb;
 static char *cert_dst;
-int kbuild_verbose;
+static int kbuild_verbose;
 
 static void write_cert(X509 *x509)
 {
index 7a85c4e..057c6ca 100644 (file)
@@ -25,9 +25,9 @@ static struct resword {
        { "__int128_t", BUILTIN_INT_KEYW },
        { "__uint128_t", BUILTIN_INT_KEYW },
 
-       // According to rth, c99 defines "_Bool", __restrict", __restrict__", "restrict".  KAO
+       // According to rth, c99 defines "_Bool", "__restrict", "__restrict__", "restrict".  KAO
        { "_Bool", BOOL_KEYW },
-       { "_restrict", RESTRICT_KEYW },
+       { "__restrict", RESTRICT_KEYW },
        { "__restrict__", RESTRICT_KEYW },
        { "restrict", RESTRICT_KEYW },
        { "asm", ASM_KEYW },
index bc390df..8638785 100644 (file)
@@ -885,7 +885,7 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e)
                connect(action, SIGNAL(toggled(bool)),
                        parent(), SLOT(setShowName(bool)));
                connect(parent(), SIGNAL(showNameChanged(bool)),
-                       action, SLOT(setOn(bool)));
+                       action, SLOT(setChecked(bool)));
                action->setChecked(showName);
                headerPopup->addAction(action);
 
@@ -894,7 +894,7 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e)
                connect(action, SIGNAL(toggled(bool)),
                        parent(), SLOT(setShowRange(bool)));
                connect(parent(), SIGNAL(showRangeChanged(bool)),
-                       action, SLOT(setOn(bool)));
+                       action, SLOT(setChecked(bool)));
                action->setChecked(showRange);
                headerPopup->addAction(action);
 
@@ -903,7 +903,7 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e)
                connect(action, SIGNAL(toggled(bool)),
                        parent(), SLOT(setShowData(bool)));
                connect(parent(), SIGNAL(showDataChanged(bool)),
-                       action, SLOT(setOn(bool)));
+                       action, SLOT(setChecked(bool)));
                action->setChecked(showData);
                headerPopup->addAction(action);
        }
@@ -1012,6 +1012,16 @@ ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
                configSettings->endGroup();
                connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
        }
+
+       contextMenu = createStandardContextMenu();
+       QAction *action = new QAction("Show Debug Info", contextMenu);
+
+       action->setCheckable(true);
+       connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
+       connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setChecked(bool)));
+       action->setChecked(showDebug());
+       contextMenu->addSeparator();
+       contextMenu->addAction(action);
 }
 
 void ConfigInfoView::saveSettings(void)
@@ -1066,80 +1076,80 @@ void ConfigInfoView::symbolInfo(void)
 void ConfigInfoView::menuInfo(void)
 {
        struct symbol* sym;
-       QString head, debug, help;
+       QString info;
+       QTextStream stream(&info);
 
        sym = _menu->sym;
        if (sym) {
                if (_menu->prompt) {
-                       head += "<big><b>";
-                       head += print_filter(_menu->prompt->text);
-                       head += "</b></big>";
+                       stream << "<big><b>";
+                       stream << print_filter(_menu->prompt->text);
+                       stream << "</b></big>";
                        if (sym->name) {
-                               head += " (";
+                               stream << " (";
                                if (showDebug())
-                                       head += QString().sprintf("<a href=\"s%s\">", sym->name);
-                               head += print_filter(sym->name);
+                                       stream << "<a href=\"s" << sym->name << "\">";
+                               stream << print_filter(sym->name);
                                if (showDebug())
-                                       head += "</a>";
-                               head += ")";
+                                       stream << "</a>";
+                               stream << ")";
                        }
                } else if (sym->name) {
-                       head += "<big><b>";
+                       stream << "<big><b>";
                        if (showDebug())
-                               head += QString().sprintf("<a href=\"s%s\">", sym->name);
-                       head += print_filter(sym->name);
+                               stream << "<a href=\"s" << sym->name << "\">";
+                       stream << print_filter(sym->name);
                        if (showDebug())
-                               head += "</a>";
-                       head += "</b></big>";
+                               stream << "</a>";
+                       stream << "</b></big>";
                }
-               head += "<br><br>";
+               stream << "<br><br>";
 
                if (showDebug())
-                       debug = debug_info(sym);
+                       stream << debug_info(sym);
 
-               struct gstr help_gstr = str_new();
-               menu_get_ext_help(_menu, &help_gstr);
-               help = print_filter(str_get(&help_gstr));
-               str_free(&help_gstr);
        } else if (_menu->prompt) {
-               head += "<big><b>";
-               head += print_filter(_menu->prompt->text);
-               head += "</b></big><br><br>";
+               stream << "<big><b>";
+               stream << print_filter(_menu->prompt->text);
+               stream << "</b></big><br><br>";
                if (showDebug()) {
                        if (_menu->prompt->visible.expr) {
-                               debug += "&nbsp;&nbsp;dep: ";
-                               expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
-                               debug += "<br><br>";
+                               stream << "&nbsp;&nbsp;dep: ";
+                               expr_print(_menu->prompt->visible.expr,
+                                          expr_print_help, &stream, E_NONE);
+                               stream << "<br><br>";
                        }
                }
        }
        if (showDebug())
-               debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno);
+               stream << "defined at " << _menu->file->name << ":"
+                      << _menu->lineno << "<br><br>";
 
-       setText(head + debug + help);
+       setText(info);
 }
 
 QString ConfigInfoView::debug_info(struct symbol *sym)
 {
        QString debug;
+       QTextStream stream(&debug);
 
-       debug += "type: ";
-       debug += print_filter(sym_type_name(sym->type));
+       stream << "type: ";
+       stream << print_filter(sym_type_name(sym->type));
        if (sym_is_choice(sym))
-               debug += " (choice)";
+               stream << " (choice)";
        debug += "<br>";
        if (sym->rev_dep.expr) {
-               debug += "reverse dep: ";
-               expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
-               debug += "<br>";
+               stream << "reverse dep: ";
+               expr_print(sym->rev_dep.expr, expr_print_help, &stream, E_NONE);
+               stream << "<br>";
        }
        for (struct property *prop = sym->prop; prop; prop = prop->next) {
                switch (prop->type) {
                case P_PROMPT:
                case P_MENU:
-                       debug += QString().sprintf("prompt: <a href=\"m%s\">", sym->name);
-                       debug += print_filter(prop->text);
-                       debug += "</a><br>";
+                       stream << "prompt: <a href=\"m" << sym->name << "\">";
+                       stream << print_filter(prop->text);
+                       stream << "</a><br>";
                        break;
                case P_DEFAULT:
                case P_SELECT:
@@ -1147,30 +1157,33 @@ QString ConfigInfoView::debug_info(struct symbol *sym)
                case P_COMMENT:
                case P_IMPLY:
                case P_SYMBOL:
-                       debug += prop_get_type_name(prop->type);
-                       debug += ": ";
-                       expr_print(prop->expr, expr_print_help, &debug, E_NONE);
-                       debug += "<br>";
+                       stream << prop_get_type_name(prop->type);
+                       stream << ": ";
+                       expr_print(prop->expr, expr_print_help,
+                                  &stream, E_NONE);
+                       stream << "<br>";
                        break;
                case P_CHOICE:
                        if (sym_is_choice(sym)) {
-                               debug += "choice: ";
-                               expr_print(prop->expr, expr_print_help, &debug, E_NONE);
-                               debug += "<br>";
+                               stream << "choice: ";
+                               expr_print(prop->expr, expr_print_help,
+                                          &stream, E_NONE);
+                               stream << "<br>";
                        }
                        break;
                default:
-                       debug += "unknown property: ";
-                       debug += prop_get_type_name(prop->type);
-                       debug += "<br>";
+                       stream << "unknown property: ";
+                       stream << prop_get_type_name(prop->type);
+                       stream << "<br>";
                }
                if (prop->visible.expr) {
-                       debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
-                       expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
-                       debug += "<br>";
+                       stream << "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
+                       expr_print(prop->visible.expr, expr_print_help,
+                                  &stream, E_NONE);
+                       stream << "<br>";
                }
        }
-       debug += "<br>";
+       stream << "<br>";
 
        return debug;
 }
@@ -1208,15 +1221,15 @@ QString ConfigInfoView::print_filter(const QString &str)
 
 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
 {
-       QString* text = reinterpret_cast<QString*>(data);
-       QString str2 = print_filter(str);
+       QTextStream *stream = reinterpret_cast<QTextStream *>(data);
 
        if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
-               *text += QString().sprintf("<a href=\"s%s\">", sym->name);
-               *text += str2;
-               *text += "</a>";
-       } else
-               *text += str2;
+               *stream << "<a href=\"s" << sym->name << "\">";
+               *stream << print_filter(str);
+               *stream << "</a>";
+       } else {
+               *stream << print_filter(str);
+       }
 }
 
 void ConfigInfoView::clicked(const QUrl &url)
@@ -1228,7 +1241,6 @@ void ConfigInfoView::clicked(const QUrl &url)
        struct menu *m = NULL;
 
        if (count < 1) {
-               qInfo() << "Clicked link is empty";
                delete[] data;
                return;
        }
@@ -1241,7 +1253,6 @@ void ConfigInfoView::clicked(const QUrl &url)
        strcat(data, "$");
        result = sym_re_search(data);
        if (!result) {
-               qInfo() << "Clicked symbol is invalid:" << data;
                delete[] data;
                return;
        }
@@ -1268,23 +1279,10 @@ void ConfigInfoView::clicked(const QUrl &url)
        delete data;
 }
 
-QMenu* ConfigInfoView::createStandardContextMenu(const QPoint & pos)
-{
-       QMenu* popup = Parent::createStandardContextMenu(pos);
-       QAction* action = new QAction("Show Debug Info", popup);
-
-       action->setCheckable(true);
-       connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
-       connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
-       action->setChecked(showDebug());
-       popup->addSeparator();
-       popup->addAction(action);
-       return popup;
-}
-
-void ConfigInfoView::contextMenuEvent(QContextMenuEvent *e)
+void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event)
 {
-       Parent::contextMenuEvent(e);
+       contextMenu->popup(event->globalPos());
+       event->accept();
 }
 
 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
index 461df64..f97376a 100644 (file)
@@ -30,7 +30,7 @@ public:
 };
 
 enum colIdx {
-       promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr
+       promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx
 };
 enum listMode {
        singleMode, menuMode, symbolMode, fullMode, listMode
@@ -215,6 +215,7 @@ public:
 class ConfigInfoView : public QTextBrowser {
        Q_OBJECT
        typedef class QTextBrowser Parent;
+       QMenu *contextMenu;
 public:
        ConfigInfoView(QWidget* parent, const char *name = 0);
        bool showDebug(void) const { return _showDebug; }
@@ -235,8 +236,7 @@ protected:
        QString debug_info(struct symbol *sym);
        static QString print_filter(const QString &str);
        static void expr_print_help(void *data, struct symbol *sym, const char *str);
-       QMenu *createStandardContextMenu(const QPoint & pos);
-       void contextMenuEvent(QContextMenuEvent *e);
+       void contextMenuEvent(QContextMenuEvent *event);
 
        struct symbol *sym;
        struct menu *_menu;
index 09ddab5..9766f6a 100644 (file)
@@ -46,6 +46,18 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
        INIT_LIST_HEAD(&bus->hlink_list);
        init_waitqueue_head(&bus->rirb_wq);
        bus->irq = -1;
+
+       /*
+        * Default value of '8' is as per the HD audio specification (Rev 1.0a).
+        * Following relation is used to derive STRIPE control value.
+        *  For sample rate <= 48K:
+        *   { ((num_channels * bits_per_sample) / number of SDOs) >= 8 }
+        *  For sample rate > 48K:
+        *   { ((num_channels * bits_per_sample * rate/48000) /
+        *      number of SDOs) >= 8 }
+        */
+       bus->sdo_limit = 8;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_bus_init);
index 011b17c..b98449f 100644 (file)
@@ -529,17 +529,6 @@ bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset)
 
        bus->chip_init = true;
 
-       /*
-        * Default value of '8' is as per the HD audio specification (Rev 1.0a).
-        * Following relation is used to derive STRIPE control value.
-        *  For sample rate <= 48K:
-        *   { ((num_channels * bits_per_sample) / number of SDOs) >= 8 }
-        *  For sample rate > 48K:
-        *   { ((num_channels * bits_per_sample * rate/48000) /
-        *      number of SDOs) >= 8 }
-        */
-       bus->sdo_limit = 8;
-
        return true;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_bus_init_chip);
index 5363d88..2e5a5c5 100644 (file)
@@ -308,7 +308,7 @@ static inline int verify_mpu401(const struct snd_mpu401 *mpu)
 }
 
 /*
- * This is apparently the standard way to initailise an MPU-401
+ * This is apparently the standard way to initialise an MPU-401
  */
 static inline void initialise_mpu401(const struct snd_mpu401 *mpu)
 {
@@ -339,7 +339,7 @@ static void soundscape_free(struct snd_card *c)
 }
 
 /*
- * Tell the SoundScape to begin a DMA tranfer using the given channel.
+ * Tell the SoundScape to begin a DMA transfer using the given channel.
  * All locking issues are left to the caller.
  */
 static void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg)
@@ -803,7 +803,7 @@ static int mpu401_open(struct snd_mpu401 *mpu)
 }
 
 /*
- * Initialse an MPU-401 subdevice for MIDI support on the SoundScape.
+ * Initialise an MPU-401 subdevice for MIDI support on the SoundScape.
  */
 static int create_mpu401(struct snd_card *card, int devnum,
                         unsigned long port, int irq)
index 7f9d352..a1fa983 100644 (file)
@@ -7694,6 +7694,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
        SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
+       SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
+       SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
        SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8),
        SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
        SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
@@ -7955,6 +7957,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC299_FIXUP_PREDATOR_SPK, .name = "predator-spk"},
        {.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"},
        {.id = ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name = "alc256-medion-headset"},
+       {.id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc298-samsung-headphone"},
        {}
 };
 #define ALC225_STANDARD_PINS \
index 55815fd..406526e 100644 (file)
@@ -138,7 +138,7 @@ static int acp3x_1015_hw_params(struct snd_pcm_substream *substream,
        srate = params_rate(params);
 
        for_each_rtd_codec_dais(rtd, i, codec_dai) {
-               if (strcmp(codec_dai->component->name, "rt1015-aif"))
+               if (strcmp(codec_dai->name, "rt1015-aif"))
                        continue;
                ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
                if (ret < 0)
index 623dfd3..7b14d9a 100644 (file)
@@ -314,40 +314,30 @@ static int acp_pdm_dma_close(struct snd_soc_component *component,
        return 0;
 }
 
-static int acp_pdm_dai_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *params,
-                                struct snd_soc_dai *dai)
+static int acp_pdm_dai_trigger(struct snd_pcm_substream *substream,
+                              int cmd, struct snd_soc_dai *dai)
 {
        struct pdm_stream_instance *rtd;
+       int ret;
+       bool pdm_status;
        unsigned int ch_mask;
 
        rtd = substream->runtime->private_data;
-       switch (params_channels(params)) {
+       ret = 0;
+       switch (substream->runtime->channels) {
        case TWO_CH:
                ch_mask = 0x00;
                break;
        default:
                return -EINVAL;
        }
-       rn_writel(ch_mask, rtd->acp_base + ACP_WOV_PDM_NO_OF_CHANNELS);
-       rn_writel(PDM_DECIMATION_FACTOR, rtd->acp_base +
-                 ACP_WOV_PDM_DECIMATION_FACTOR);
-       return 0;
-}
-
-static int acp_pdm_dai_trigger(struct snd_pcm_substream *substream,
-                              int cmd, struct snd_soc_dai *dai)
-{
-       struct pdm_stream_instance *rtd;
-       int ret;
-       bool pdm_status;
-
-       rtd = substream->runtime->private_data;
-       ret = 0;
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               rn_writel(ch_mask, rtd->acp_base + ACP_WOV_PDM_NO_OF_CHANNELS);
+               rn_writel(PDM_DECIMATION_FACTOR, rtd->acp_base +
+                         ACP_WOV_PDM_DECIMATION_FACTOR);
                rtd->bytescount = acp_pdm_get_byte_count(rtd,
                                                         substream->stream);
                pdm_status = check_pdm_dma_status(rtd->acp_base);
@@ -369,7 +359,6 @@ static int acp_pdm_dai_trigger(struct snd_pcm_substream *substream,
 }
 
 static struct snd_soc_dai_ops acp_pdm_dai_ops = {
-       .hw_params = acp_pdm_dai_hw_params,
        .trigger   = acp_pdm_dai_trigger,
 };
 
index 4428c62..3ddd822 100644 (file)
@@ -19,8 +19,8 @@
 
 #define CDC_D_REVISION1                        (0xf000)
 #define CDC_D_PERPH_SUBTYPE            (0xf005)
-#define CDC_D_INT_EN_SET               (0x015)
-#define CDC_D_INT_EN_CLR               (0x016)
+#define CDC_D_INT_EN_SET               (0xf015)
+#define CDC_D_INT_EN_CLR               (0xf016)
 #define MBHC_SWITCH_INT                        BIT(7)
 #define MBHC_MIC_ELECTRICAL_INS_REM_DET        BIT(6)
 #define MBHC_BUTTON_PRESS_DET          BIT(5)
index 68a3b48..3bce9a1 100644 (file)
@@ -412,8 +412,12 @@ int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
                  struct snd_kcontrol *kcontrol, int event)
 {
        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct wm8994 *control = dev_get_drvdata(component->dev->parent);
        int i;
 
+       if (control->type != WM8958)
+               return 0;
+
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
        case SND_SOC_DAPM_PRE_PMU:
index 317916c..0623a22 100644 (file)
@@ -151,7 +151,6 @@ static const struct reg_default wm8962_reg[] = {
        { 40, 0x0000 },   /* R40    - SPKOUTL volume */
        { 41, 0x0000 },   /* R41    - SPKOUTR volume */
 
-       { 48, 0x0000 },   /* R48    - Additional control(4) */
        { 49, 0x0010 },   /* R49    - Class D Control 1 */
        { 51, 0x0003 },   /* R51    - Class D Control 2 */
 
@@ -842,6 +841,7 @@ static bool wm8962_readable_register(struct device *dev, unsigned int reg)
        case WM8962_SPKOUTL_VOLUME:
        case WM8962_SPKOUTR_VOLUME:
        case WM8962_THERMAL_SHUTDOWN_STATUS:
+       case WM8962_ADDITIONAL_CONTROL_4:
        case WM8962_CLASS_D_CONTROL_1:
        case WM8962_CLASS_D_CONTROL_2:
        case WM8962_CLOCKING_4:
index a84ae87..038be66 100644 (file)
 #define WM8994_NUM_DRC 3
 #define WM8994_NUM_EQ  3
 
-static struct {
+struct wm8994_reg_mask {
        unsigned int reg;
        unsigned int mask;
-} wm8994_vu_bits[] = {
+};
+
+static struct wm8994_reg_mask wm8994_vu_bits[] = {
        { WM8994_LEFT_LINE_INPUT_1_2_VOLUME, WM8994_IN1_VU },
        { WM8994_RIGHT_LINE_INPUT_1_2_VOLUME, WM8994_IN1_VU },
        { WM8994_LEFT_LINE_INPUT_3_4_VOLUME, WM8994_IN2_VU },
@@ -60,14 +62,10 @@ static struct {
 
        { WM8994_AIF1_DAC1_LEFT_VOLUME, WM8994_AIF1DAC1_VU },
        { WM8994_AIF1_DAC1_RIGHT_VOLUME, WM8994_AIF1DAC1_VU },
-       { WM8994_AIF1_DAC2_LEFT_VOLUME, WM8994_AIF1DAC2_VU },
-       { WM8994_AIF1_DAC2_RIGHT_VOLUME, WM8994_AIF1DAC2_VU },
        { WM8994_AIF2_DAC_LEFT_VOLUME, WM8994_AIF2DAC_VU },
        { WM8994_AIF2_DAC_RIGHT_VOLUME, WM8994_AIF2DAC_VU },
        { WM8994_AIF1_ADC1_LEFT_VOLUME, WM8994_AIF1ADC1_VU },
        { WM8994_AIF1_ADC1_RIGHT_VOLUME, WM8994_AIF1ADC1_VU },
-       { WM8994_AIF1_ADC2_LEFT_VOLUME, WM8994_AIF1ADC2_VU },
-       { WM8994_AIF1_ADC2_RIGHT_VOLUME, WM8994_AIF1ADC2_VU },
        { WM8994_AIF2_ADC_LEFT_VOLUME, WM8994_AIF2ADC_VU },
        { WM8994_AIF2_ADC_RIGHT_VOLUME, WM8994_AIF1ADC2_VU },
        { WM8994_DAC1_LEFT_VOLUME, WM8994_DAC1_VU },
@@ -76,6 +74,14 @@ static struct {
        { WM8994_DAC2_RIGHT_VOLUME, WM8994_DAC2_VU },
 };
 
+/* VU bitfields for ADC2, DAC2 not available on WM1811 */
+static struct wm8994_reg_mask wm8994_adc2_dac2_vu_bits[] = {
+       { WM8994_AIF1_DAC2_LEFT_VOLUME, WM8994_AIF1DAC2_VU },
+       { WM8994_AIF1_DAC2_RIGHT_VOLUME, WM8994_AIF1DAC2_VU },
+       { WM8994_AIF1_ADC2_LEFT_VOLUME, WM8994_AIF1ADC2_VU },
+       { WM8994_AIF1_ADC2_RIGHT_VOLUME, WM8994_AIF1ADC2_VU },
+};
+
 static int wm8994_drc_base[] = {
        WM8994_AIF1_DRC1_1,
        WM8994_AIF1_DRC2_1,
@@ -1030,6 +1036,26 @@ static bool wm8994_check_class_w_digital(struct snd_soc_component *component)
        return true;
 }
 
+static void wm8994_update_vu_bits(struct snd_soc_component *component)
+{
+       struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+       struct wm8994 *control = wm8994->wm8994;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(wm8994_vu_bits); i++)
+               snd_soc_component_write(component, wm8994_vu_bits[i].reg,
+                                       snd_soc_component_read(component,
+                                                      wm8994_vu_bits[i].reg));
+       if (control->type == WM1811)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(wm8994_adc2_dac2_vu_bits); i++)
+               snd_soc_component_write(component,
+                               wm8994_adc2_dac2_vu_bits[i].reg,
+                               snd_soc_component_read(component,
+                                       wm8994_adc2_dac2_vu_bits[i].reg));
+}
+
 static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enable)
 {
        struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
@@ -1076,7 +1102,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
        struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
        struct wm8994 *control = wm8994->wm8994;
        int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA;
-       int ret, i;
+       int ret;
        int dac;
        int adc;
        int val;
@@ -1144,10 +1170,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
                break;
 
        case SND_SOC_DAPM_POST_PMU:
-               for (i = 0; i < ARRAY_SIZE(wm8994_vu_bits); i++)
-                       snd_soc_component_write(component, wm8994_vu_bits[i].reg,
-                                     snd_soc_component_read(component,
-                                                  wm8994_vu_bits[i].reg));
+               wm8994_update_vu_bits(component);
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
@@ -1181,7 +1204,7 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
                      struct snd_kcontrol *kcontrol, int event)
 {
        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
-       int ret, i;
+       int ret;
        int dac;
        int adc;
        int val;
@@ -1237,10 +1260,7 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
                break;
 
        case SND_SOC_DAPM_POST_PMU:
-               for (i = 0; i < ARRAY_SIZE(wm8994_vu_bits); i++)
-                       snd_soc_component_write(component, wm8994_vu_bits[i].reg,
-                                     snd_soc_component_read(component,
-                                                  wm8994_vu_bits[i].reg));
+               wm8994_update_vu_bits(component);
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
@@ -4346,6 +4366,14 @@ static int wm8994_component_probe(struct snd_soc_component *component)
                                    wm8994_vu_bits[i].mask,
                                    wm8994_vu_bits[i].mask);
 
+       if (control->type != WM1811) {
+               for (i = 0; i < ARRAY_SIZE(wm8994_adc2_dac2_vu_bits); i++)
+                       snd_soc_component_update_bits(component,
+                                       wm8994_adc2_dac2_vu_bits[i].reg,
+                                       wm8994_adc2_dac2_vu_bits[i].mask,
+                                       wm8994_adc2_dac2_vu_bits[i].mask);
+       }
+
        /* Set the low bit of the 3D stereo depth so TLV matches */
        snd_soc_component_update_bits(component, WM8994_AIF1_DAC1_FILTERS_2,
                            1 << WM8994_AIF1DAC1_3D_GAIN_SHIFT,
index de136c0..52adedc 100644 (file)
@@ -73,6 +73,7 @@ struct cpu_priv {
  * @codec_priv: CODEC private data
  * @cpu_priv: CPU private data
  * @card: ASoC card structure
+ * @streams: Mask of current active streams
  * @sample_rate: Current sample rate
  * @sample_format: Current sample format
  * @asrc_rate: ASRC sample rate used by Back-Ends
@@ -89,6 +90,7 @@ struct fsl_asoc_card_priv {
        struct codec_priv codec_priv;
        struct cpu_priv cpu_priv;
        struct snd_soc_card card;
+       u8 streams;
        u32 sample_rate;
        snd_pcm_format_t sample_format;
        u32 asrc_rate;
@@ -151,21 +153,17 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       struct codec_priv *codec_priv = &priv->codec_priv;
        struct cpu_priv *cpu_priv = &priv->cpu_priv;
        struct device *dev = rtd->card->dev;
+       unsigned int pll_out;
        int ret;
 
        priv->sample_rate = params_rate(params);
        priv->sample_format = params_format(params);
+       priv->streams |= BIT(substream->stream);
 
-       /*
-        * If codec-dai is DAI Master and all configurations are already in the
-        * set_bias_level(), bypass the remaining settings in hw_params().
-        * Note: (dai_fmt & CBM_CFM) includes CBM_CFM and CBM_CFS.
-        */
-       if ((priv->card.set_bias_level &&
-            priv->dai_fmt & SND_SOC_DAIFMT_CBM_CFM) ||
-           fsl_asoc_card_is_ac97(priv))
+       if (fsl_asoc_card_is_ac97(priv))
                return 0;
 
        /* Specific configurations of DAIs starts from here */
@@ -174,7 +172,7 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
                                     cpu_priv->sysclk_dir[tx]);
        if (ret && ret != -ENOTSUPP) {
                dev_err(dev, "failed to set sysclk for cpu dai\n");
-               return ret;
+               goto fail;
        }
 
        if (cpu_priv->slot_width) {
@@ -182,6 +180,68 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
                                               cpu_priv->slot_width);
                if (ret && ret != -ENOTSUPP) {
                        dev_err(dev, "failed to set TDM slot for cpu dai\n");
+                       goto fail;
+               }
+       }
+
+       /* Specific configuration for PLL */
+       if (codec_priv->pll_id && codec_priv->fll_id) {
+               if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE)
+                       pll_out = priv->sample_rate * 384;
+               else
+                       pll_out = priv->sample_rate * 256;
+
+               ret = snd_soc_dai_set_pll(asoc_rtd_to_codec(rtd, 0),
+                                         codec_priv->pll_id,
+                                         codec_priv->mclk_id,
+                                         codec_priv->mclk_freq, pll_out);
+               if (ret) {
+                       dev_err(dev, "failed to start FLL: %d\n", ret);
+                       goto fail;
+               }
+
+               ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0),
+                                            codec_priv->fll_id,
+                                            pll_out, SND_SOC_CLOCK_IN);
+
+               if (ret && ret != -ENOTSUPP) {
+                       dev_err(dev, "failed to set SYSCLK: %d\n", ret);
+                       goto fail;
+               }
+       }
+
+       return 0;
+
+fail:
+       priv->streams &= ~BIT(substream->stream);
+       return ret;
+}
+
+static int fsl_asoc_card_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct codec_priv *codec_priv = &priv->codec_priv;
+       struct device *dev = rtd->card->dev;
+       int ret;
+
+       priv->streams &= ~BIT(substream->stream);
+
+       if (!priv->streams && codec_priv->pll_id && codec_priv->fll_id) {
+               /* Force freq to be 0 to avoid error message in codec */
+               ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0),
+                                            codec_priv->mclk_id,
+                                            0,
+                                            SND_SOC_CLOCK_IN);
+               if (ret) {
+                       dev_err(dev, "failed to switch away from FLL: %d\n", ret);
+                       return ret;
+               }
+
+               ret = snd_soc_dai_set_pll(asoc_rtd_to_codec(rtd, 0),
+                                         codec_priv->pll_id, 0, 0, 0);
+               if (ret && ret != -ENOTSUPP) {
+                       dev_err(dev, "failed to stop FLL: %d\n", ret);
                        return ret;
                }
        }
@@ -191,6 +251,7 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
 
 static const struct snd_soc_ops fsl_asoc_card_ops = {
        .hw_params = fsl_asoc_card_hw_params,
+       .hw_free = fsl_asoc_card_hw_free,
 };
 
 static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -254,75 +315,6 @@ static struct snd_soc_dai_link fsl_asoc_card_dai[] = {
        },
 };
 
-static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card,
-                                       struct snd_soc_dapm_context *dapm,
-                                       enum snd_soc_bias_level level)
-{
-       struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
-       struct snd_soc_pcm_runtime *rtd;
-       struct snd_soc_dai *codec_dai;
-       struct codec_priv *codec_priv = &priv->codec_priv;
-       struct device *dev = card->dev;
-       unsigned int pll_out;
-       int ret;
-
-       rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
-       codec_dai = asoc_rtd_to_codec(rtd, 0);
-       if (dapm->dev != codec_dai->dev)
-               return 0;
-
-       switch (level) {
-       case SND_SOC_BIAS_PREPARE:
-               if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
-                       break;
-
-               if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE)
-                       pll_out = priv->sample_rate * 384;
-               else
-                       pll_out = priv->sample_rate * 256;
-
-               ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id,
-                                         codec_priv->mclk_id,
-                                         codec_priv->mclk_freq, pll_out);
-               if (ret) {
-                       dev_err(dev, "failed to start FLL: %d\n", ret);
-                       return ret;
-               }
-
-               ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->fll_id,
-                                            pll_out, SND_SOC_CLOCK_IN);
-               if (ret && ret != -ENOTSUPP) {
-                       dev_err(dev, "failed to set SYSCLK: %d\n", ret);
-                       return ret;
-               }
-               break;
-
-       case SND_SOC_BIAS_STANDBY:
-               if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
-                       break;
-
-               ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
-                                            codec_priv->mclk_freq,
-                                            SND_SOC_CLOCK_IN);
-               if (ret && ret != -ENOTSUPP) {
-                       dev_err(dev, "failed to switch away from FLL: %d\n", ret);
-                       return ret;
-               }
-
-               ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id, 0, 0, 0);
-               if (ret) {
-                       dev_err(dev, "failed to stop FLL: %d\n", ret);
-                       return ret;
-               }
-               break;
-
-       default:
-               break;
-       }
-
-       return 0;
-}
-
 static int fsl_asoc_card_audmux_init(struct device_node *np,
                                     struct fsl_asoc_card_priv *priv)
 {
@@ -611,7 +603,6 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
        /* Diversify the card configurations */
        if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) {
                codec_dai_name = "cs42888";
-               priv->card.set_bias_level = NULL;
                priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq;
                priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq;
                priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
@@ -628,26 +619,22 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
                priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
        } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) {
                codec_dai_name = "wm8962";
-               priv->card.set_bias_level = fsl_asoc_card_set_bias_level;
                priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK;
                priv->codec_priv.fll_id = WM8962_SYSCLK_FLL;
                priv->codec_priv.pll_id = WM8962_FLL;
                priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
        } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8960")) {
                codec_dai_name = "wm8960-hifi";
-               priv->card.set_bias_level = fsl_asoc_card_set_bias_level;
                priv->codec_priv.fll_id = WM8960_SYSCLK_AUTO;
                priv->codec_priv.pll_id = WM8960_SYSCLK_AUTO;
                priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
        } else if (of_device_is_compatible(np, "fsl,imx-audio-ac97")) {
                codec_dai_name = "ac97-hifi";
-               priv->card.set_bias_level = NULL;
                priv->dai_fmt = SND_SOC_DAIFMT_AC97;
                priv->card.dapm_routes = audio_map_ac97;
                priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_ac97);
        } else if (of_device_is_compatible(np, "fsl,imx-audio-mqs")) {
                codec_dai_name = "fsl-mqs-dai";
-               priv->card.set_bias_level = NULL;
                priv->dai_fmt = SND_SOC_DAIFMT_LEFT_J |
                                SND_SOC_DAIFMT_CBS_CFS |
                                SND_SOC_DAIFMT_NB_NF;
@@ -657,7 +644,6 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
                priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
        } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8524")) {
                codec_dai_name = "wm8524-hifi";
-               priv->card.set_bias_level = NULL;
                priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
                priv->dai_link[1].dpcm_capture = 0;
                priv->dai_link[2].dpcm_capture = 0;
index 9e4f66b..2319848 100644 (file)
@@ -339,7 +339,6 @@ static int psc_dma_new(struct snd_soc_component *component,
 static void psc_dma_free(struct snd_soc_component *component,
                         struct snd_pcm *pcm)
 {
-       struct snd_soc_pcm_runtime *rtd = pcm->private_data;
        struct snd_pcm_substream *substream;
        int stream;
 
index 49b9f18..b1cac7a 100644 (file)
@@ -331,7 +331,7 @@ static int sst_media_open(struct snd_pcm_substream *substream,
 
        ret_val = power_up_sst(stream);
        if (ret_val < 0)
-               return ret_val;
+               goto out_power_up;
 
        /* Make sure, that the period size is always even */
        snd_pcm_hw_constraint_step(substream->runtime, 0,
@@ -340,8 +340,9 @@ static int sst_media_open(struct snd_pcm_substream *substream,
        return snd_pcm_hw_constraint_integer(runtime,
                         SNDRV_PCM_HW_PARAM_PERIODS);
 out_ops:
-       kfree(stream);
        mutex_unlock(&sst_lock);
+out_power_up:
+       kfree(stream);
        return ret_val;
 }
 
index 2a5302f..0168af8 100644 (file)
@@ -1150,206 +1150,206 @@ static int q6afe_of_xlate_dai_name(struct snd_soc_component *component,
 }
 
 static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
-       SND_SOC_DAPM_AIF_IN("HDMI_RX", NULL, 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_IN("SLIMBUS_0_RX", NULL, 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_IN("SLIMBUS_1_RX", NULL, 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_IN("SLIMBUS_2_RX", NULL, 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_IN("SLIMBUS_3_RX", NULL, 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_IN("SLIMBUS_4_RX", NULL, 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_IN("SLIMBUS_5_RX", NULL, 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_IN("SLIMBUS_6_RX", NULL, 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_TX", NULL, 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_TX", NULL, 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("SLIMBUS_2_TX", NULL, 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("SLIMBUS_3_TX", NULL, 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("SLIMBUS_4_TX", NULL, 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_TX", NULL, 0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("SLIMBUS_6_TX", NULL, 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("HDMI_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SLIMBUS_0_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SLIMBUS_1_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SLIMBUS_2_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SLIMBUS_3_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SLIMBUS_4_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SLIMBUS_5_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("SLIMBUS_6_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("SLIMBUS_2_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("SLIMBUS_3_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("SLIMBUS_4_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("SLIMBUS_6_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUAT_MI2S_RX", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_TX", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("TERT_MI2S_RX", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("TERT_MI2S_TX", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("SEC_MI2S_RX", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("SEC_MI2S_TX", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("SEC_MI2S_RX_SD1",
                        "Secondary MI2S Playback SD1",
-                       0, 0, 0, 0),
+                       0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("PRI_MI2S_RX", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("PRI_MI2S_TX", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
 
        SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_0", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_1", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_2", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_3", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_4", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_5", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_6", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_7", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_0", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_1", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_2", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_3", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_4", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_5", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_6", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_7", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
 
        SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_0", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_1", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_2", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_3", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_4", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_5", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_6", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_7", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_0", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_1", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_2", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_3", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_4", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_5", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_6", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_7", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
 
        SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_0", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_1", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_2", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_3", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_4", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_5", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_6", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_7", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_0", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_1", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_2", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_3", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_4", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_5", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_6", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_7", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
 
        SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_0", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_1", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_2", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_3", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_4", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_5", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_6", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_7", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_0", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_1", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_2", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_3", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_4", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_5", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_6", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_7", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
 
        SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_0", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_1", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_2", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_3", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_4", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_5", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_6", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_7", NULL,
-                            0, 0, 0, 0),
+                            0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_0", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_1", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_2", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_3", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_4", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_5", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_6", NULL,
-                                               0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_7", NULL,
-                                               0, 0, 0, 0),
-       SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT_RX", "NULL", 0, 0, 0, 0),
+                                               0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT_RX", "NULL", 0, SND_SOC_NOPM, 0, 0),
 };
 
 static const struct snd_soc_component_driver q6afe_dai_component = {
index eaa95b5..25d23e0 100644 (file)
@@ -973,6 +973,20 @@ static int msm_routing_probe(struct snd_soc_component *c)
        return 0;
 }
 
+static unsigned int q6routing_reg_read(struct snd_soc_component *component,
+                                      unsigned int reg)
+{
+       /* default value */
+       return 0;
+}
+
+static int q6routing_reg_write(struct snd_soc_component *component,
+                              unsigned int reg, unsigned int val)
+{
+       /* dummy */
+       return 0;
+}
+
 static const struct snd_soc_component_driver msm_soc_routing_component = {
        .probe = msm_routing_probe,
        .name = DRV_NAME,
@@ -981,6 +995,8 @@ static const struct snd_soc_component_driver msm_soc_routing_component = {
        .num_dapm_widgets = ARRAY_SIZE(msm_qdsp6_widgets),
        .dapm_routes = intercon,
        .num_dapm_routes = ARRAY_SIZE(intercon),
+       .read = q6routing_reg_read,
+       .write = q6routing_reg_write,
 };
 
 static int q6pcm_routing_probe(struct platform_device *pdev)
index f0b4f4b..5504b92 100644 (file)
@@ -406,7 +406,7 @@ static unsigned int soc_component_read_no_lock(
                ret = -EIO;
 
        if (ret < 0)
-               soc_component_ret(component, ret);
+               return soc_component_ret(component, ret);
 
        return val;
 }
index fe71171..0cbe31e 100644 (file)
@@ -71,7 +71,7 @@ static int tegra186_dspk_put_control(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static int tegra186_dspk_runtime_suspend(struct device *dev)
+static int __maybe_unused tegra186_dspk_runtime_suspend(struct device *dev)
 {
        struct tegra186_dspk *dspk = dev_get_drvdata(dev);
 
@@ -83,7 +83,7 @@ static int tegra186_dspk_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int tegra186_dspk_runtime_resume(struct device *dev)
+static int __maybe_unused tegra186_dspk_runtime_resume(struct device *dev)
 {
        struct tegra186_dspk *dspk = dev_get_drvdata(dev);
        int err;
index 4894e8e..1268046 100644 (file)
@@ -219,7 +219,7 @@ static const struct regmap_config tegra186_admaif_regmap_config = {
        .cache_type             = REGCACHE_FLAT,
 };
 
-static int tegra_admaif_runtime_suspend(struct device *dev)
+static int __maybe_unused tegra_admaif_runtime_suspend(struct device *dev)
 {
        struct tegra_admaif *admaif = dev_get_drvdata(dev);
 
@@ -229,7 +229,7 @@ static int tegra_admaif_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int tegra_admaif_runtime_resume(struct device *dev)
+static int __maybe_unused tegra_admaif_runtime_resume(struct device *dev)
 {
        struct tegra_admaif *admaif = dev_get_drvdata(dev);
 
index 5123a96..66287a7 100644 (file)
@@ -564,7 +564,7 @@ static const struct of_device_id tegra_ahub_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tegra_ahub_of_match);
 
-static int tegra_ahub_runtime_suspend(struct device *dev)
+static int __maybe_unused tegra_ahub_runtime_suspend(struct device *dev)
 {
        struct tegra_ahub *ahub = dev_get_drvdata(dev);
 
@@ -576,7 +576,7 @@ static int tegra_ahub_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int tegra_ahub_runtime_resume(struct device *dev)
+static int __maybe_unused tegra_ahub_runtime_resume(struct device *dev)
 {
        struct tegra_ahub *ahub = dev_get_drvdata(dev);
        int err;
index d682414..a661f40 100644 (file)
@@ -40,7 +40,7 @@ static const struct reg_default tegra210_dmic_reg_defaults[] = {
        { TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, 0x0 },
 };
 
-static int tegra210_dmic_runtime_suspend(struct device *dev)
+static int __maybe_unused tegra210_dmic_runtime_suspend(struct device *dev)
 {
        struct tegra210_dmic *dmic = dev_get_drvdata(dev);
 
@@ -52,7 +52,7 @@ static int tegra210_dmic_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int tegra210_dmic_runtime_resume(struct device *dev)
+static int __maybe_unused tegra210_dmic_runtime_resume(struct device *dev)
 {
        struct tegra210_dmic *dmic = dev_get_drvdata(dev);
        int err;
index 7220921..a383bd5 100644 (file)
@@ -164,7 +164,7 @@ static int tegra210_i2s_init(struct snd_soc_dapm_widget *w,
        return tegra210_i2s_sw_reset(compnt, is_playback);
 }
 
-static int tegra210_i2s_runtime_suspend(struct device *dev)
+static int __maybe_unused tegra210_i2s_runtime_suspend(struct device *dev)
 {
        struct tegra210_i2s *i2s = dev_get_drvdata(dev);
 
@@ -176,7 +176,7 @@ static int tegra210_i2s_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int tegra210_i2s_runtime_resume(struct device *dev)
+static int __maybe_unused tegra210_i2s_runtime_resume(struct device *dev)
 {
        struct tegra210_i2s *i2s = dev_get_drvdata(dev);
        int err;
index 6b0f3a8..81e987e 100644 (file)
@@ -2371,7 +2371,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
        int num_ins;
        struct usb_mixer_elem_info *cval;
        struct snd_kcontrol *kctl;
-       int i, err, nameid, type, len;
+       int i, err, nameid, type, len, val;
        const struct procunit_info *info;
        const struct procunit_value_info *valinfo;
        const struct usbmix_name_map *map;
@@ -2474,6 +2474,12 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
                        break;
                }
 
+               err = get_cur_ctl_value(cval, cval->control << 8, &val);
+               if (err < 0) {
+                       usb_mixer_elem_info_free(cval);
+                       return -EINVAL;
+               }
+
                kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
                if (!kctl) {
                        usb_mixer_elem_info_free(cval);
index d79e3dd..f4fb002 100644 (file)
@@ -2678,6 +2678,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .ifnum = QUIRK_ANY_INTERFACE,
                .type = QUIRK_COMPOSITE,
                .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_MIXER,
+                       },
                        {
                                .ifnum = 0,
                                .type = QUIRK_AUDIO_FIXED_ENDPOINT,
@@ -2690,6 +2694,32 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                                        .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
                                        .endpoint = 0x01,
                                        .ep_attr = USB_ENDPOINT_XFER_ISOC,
+                                       .datainterval = 1,
+                                       .maxpacksize = 0x024c,
+                                       .rates = SNDRV_PCM_RATE_44100 |
+                                                SNDRV_PCM_RATE_48000,
+                                       .rate_min = 44100,
+                                       .rate_max = 48000,
+                                       .nr_rates = 2,
+                                       .rate_table = (unsigned int[]) {
+                                               44100, 48000
+                                       }
+                               }
+                       },
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 2,
+                                       .iface = 0,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = 0,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC,
+                                       .datainterval = 1,
+                                       .maxpacksize = 0x0126,
                                        .rates = SNDRV_PCM_RATE_44100 |
                                                 SNDRV_PCM_RATE_48000,
                                        .rate_min = 44100,
@@ -3714,8 +3744,8 @@ ALC1220_VB_DESKTOP(0x26ce, 0x0a01), /* Asrock TRX40 Creator */
  * they pretend to be 96kHz mono as a workaround for stereo being broken
  * by that...
  *
- * They also have swapped L-R channels, but that's for userspace to deal
- * with.
+ * They also have an issue with initial stream alignment that causes the
+ * channels to be swapped and out of phase, which is dealt with in quirks.c.
  */
 {
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
index e3b1163..df7d8ec 100644 (file)
@@ -134,6 +134,8 @@ int build_obj_refs_table(struct obj_refs_table *table, enum bpf_obj_type type)
        while (true) {
                ret = read(fd, buf, sizeof(buf));
                if (ret < 0) {
+                       if (errno == EAGAIN)
+                               continue;
                        err = -errno;
                        p_err("failed to read PID iterator output: %d", err);
                        goto out;
index 4d9ecb9..0def0bb 100644 (file)
@@ -233,6 +233,39 @@ static struct btf_id *add_symbol(struct rb_root *root, char *name, size_t size)
        return btf_id__add(root, id, false);
 }
 
+/*
+ * The data of compressed section should be aligned to 4
+ * (for 32bit) or 8 (for 64 bit) bytes. The binutils ld
+ * sets sh_addralign to 1, which makes libelf fail with
+ * misaligned section error during the update:
+ *    FAILED elf_update(WRITE): invalid section alignment
+ *
+ * While waiting for ld fix, we fix the compressed sections
+ * sh_addralign value manualy.
+ */
+static int compressed_section_fix(Elf *elf, Elf_Scn *scn, GElf_Shdr *sh)
+{
+       int expected = gelf_getclass(elf) == ELFCLASS32 ? 4 : 8;
+
+       if (!(sh->sh_flags & SHF_COMPRESSED))
+               return 0;
+
+       if (sh->sh_addralign == expected)
+               return 0;
+
+       pr_debug2(" - fixing wrong alignment sh_addralign %u, expected %u\n",
+                 sh->sh_addralign, expected);
+
+       sh->sh_addralign = expected;
+
+       if (gelf_update_shdr(scn, sh) == 0) {
+               printf("FAILED cannot update section header: %s\n",
+                       elf_errmsg(-1));
+               return -1;
+       }
+       return 0;
+}
+
 static int elf_collect(struct object *obj)
 {
        Elf_Scn *scn = NULL;
@@ -309,6 +342,9 @@ static int elf_collect(struct object *obj)
                        obj->efile.idlist_shndx = idx;
                        obj->efile.idlist_addr  = sh.sh_addr;
                }
+
+               if (compressed_section_fix(elf, scn, &sh))
+                       return -1;
        }
 
        return 0;
index 0480f89..b6238b2 100644 (file)
@@ -767,7 +767,7 @@ union bpf_attr {
  *
  *             Also, note that **bpf_trace_printk**\ () is slow, and should
  *             only be used for debugging purposes. For this reason, a notice
- *             bloc (spanning several lines) is printed to kernel logs and
+ *             block (spanning several lines) is printed to kernel logs and
  *             states that the helper should not be used "for production use"
  *             the first time this helper is used (or more precisely, when
  *             **trace_printk**\ () buffers are allocated). For passing values
@@ -1033,14 +1033,14 @@ union bpf_attr {
  *
  *                     int ret;
  *                     struct bpf_tunnel_key key = {};
- *                     
+ *
  *                     ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
  *                     if (ret < 0)
  *                             return TC_ACT_SHOT;     // drop packet
- *                     
+ *
  *                     if (key.remote_ipv4 != 0x0a000001)
  *                             return TC_ACT_SHOT;     // drop packet
- *                     
+ *
  *                     return TC_ACT_OK;               // accept packet
  *
  *             This interface can also be used with all encapsulation devices
@@ -1147,7 +1147,7 @@ union bpf_attr {
  *     Description
  *             Retrieve the realm or the route, that is to say the
  *             **tclassid** field of the destination for the *skb*. The
- *             indentifier retrieved is a user-provided tag, similar to the
+ *             identifier retrieved is a user-provided tag, similar to the
  *             one used with the net_cls cgroup (see description for
  *             **bpf_get_cgroup_classid**\ () helper), but here this tag is
  *             held by a route (a destination entry), not by a task.
index fe39bd7..57c00fa 100644 (file)
@@ -879,7 +879,7 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
                        btf_dump_printf(d, ": %d", m_sz);
                        off = m_off + m_sz;
                } else {
-                       m_sz = max(0LL, btf__resolve_size(d->btf, m->type));
+                       m_sz = max((__s64)0, btf__resolve_size(d->btf, m->type));
                        off = m_off + m_sz * 8;
                }
                btf_dump_printf(d, ";");
index 5d20b2d..0ad0b04 100644 (file)
@@ -2264,7 +2264,7 @@ static int bpf_object__init_user_btf_maps(struct bpf_object *obj, bool strict,
                data = elf_getdata(scn, NULL);
        if (!scn || !data) {
                pr_warn("failed to get Elf_Data from map section %d (%s)\n",
-                       obj->efile.maps_shndx, MAPS_ELF_SEC);
+                       obj->efile.btf_maps_shndx, MAPS_ELF_SEC);
                return -EINVAL;
        }
 
index 1bb204c..9a0946d 100644 (file)
@@ -6,7 +6,6 @@ test_lpm_map
 test_tag
 FEATURE-DUMP.libbpf
 fixdep
-test_align
 test_dev_cgroup
 /test_progs*
 test_tcpbpf_user
index a83b582..fc946b7 100644 (file)
@@ -32,7 +32,7 @@ LDLIBS += -lcap -lelf -lz -lrt -lpthread
 
 # Order correspond to 'make run_tests' order
 TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \
-       test_align test_verifier_log test_dev_cgroup test_tcpbpf_user \
+       test_verifier_log test_dev_cgroup test_tcpbpf_user \
        test_sock test_btf test_sockmap get_cgroup_id_user test_socket_cookie \
        test_cgroup_storage \
        test_netcnt test_tcpnotify_user test_sock_fields test_sysctl \
index 25b0685..193002b 100644 (file)
@@ -19,7 +19,7 @@ static int libbpf_debug_print(enum libbpf_print_level level,
        log_buf = va_arg(args, char *);
        if (!log_buf)
                goto out;
-       if (strstr(log_buf, err_str) == 0)
+       if (err_str && strstr(log_buf, err_str) == 0)
                found = true;
 out:
        printf(format, log_buf);
index 8162c58..b8d14f9 100644 (file)
@@ -40,11 +40,11 @@ static void guest_code(void)
 
        /* Single step test, covers 2 basic instructions and 2 emulated */
        asm volatile("ss_start: "
-                    "xor %%rax,%%rax\n\t"
+                    "xor %%eax,%%eax\n\t"
                     "cpuid\n\t"
                     "movl $0x1a0,%%ecx\n\t"
                     "rdmsr\n\t"
-                    : : : "rax", "ecx");
+                    : : : "eax", "ebx", "ecx", "edx");
 
        /* DR6.BD test */
        asm volatile("bd_start: mov %%dr0, %%rax" : : : "rax");
index 737666d..67cd0b8 100644 (file)
@@ -482,7 +482,8 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
         * count is also read inside the mmu_lock critical section.
         */
        kvm->mmu_notifier_count++;
-       need_tlb_flush = kvm_unmap_hva_range(kvm, range->start, range->end);
+       need_tlb_flush = kvm_unmap_hva_range(kvm, range->start, range->end,
+                                            range->flags);
        need_tlb_flush |= kvm->tlbs_dirty;
        /* we've to flush the tlb before the pages can be freed */
        if (need_tlb_flush)