Merge tag 'perf-tools-fixes-for-v6.8-1-2024-02-01' of git://git.kernel.org/pub/scm...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 3 Feb 2024 12:52:36 +0000 (12:52 +0000)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 3 Feb 2024 12:52:36 +0000 (12:52 +0000)
Pull perf tools fixes from Arnaldo Carvalho de Melo:
 "Vendor events:

   - Intel Alderlake/Sapphire Rapids metric fixes, the CPU type
     ("cpu_atom", "cpu_core") needs to be used as a prefix to be
     considered on a metric formula, detected via one of the 'perf test'
     entries.

  'perf test' fixes:

   - Fix the creation of event selector lists on 'perf test' entries, by
     initializing the sample ID flag, which is done by 'perf record', so
     this fix affects only the tests, the common case isn't affected

   - Make 'perf list' respect debug settings (-v) to fix its 'perf test'
     entry

   - Fix 'perf script' test when python support isn't enabled

   - Special case 'perf script' tests on s390, where only DWARF call
     graphs are supported and only on software events

   - Make 'perf daemon' signal test less racy

  Compiler warnings/errors:

   - Remove needless malloc(0) call in 'perf top' that triggers
     -Walloc-size

   - Fix calloc() argument order to address error introduced in gcc-14

  Build:

   - Make minimal shellcheck version to v0.6.0, avoiding the build to
     fail with older versions

  Sync kernel header copies:

   - stat.h to pick STATX_MNT_ID_UNIQUE

   - msr-index.h to pick IA32_MKTME_KEYID_PARTITIONING

   - drm.h to pick DRM_IOCTL_MODE_CLOSEFB

   - unistd.h to pick {list,stat}mount,
     lsm_{[gs]et_self_attr,list_modules} syscall numbers

   - x86 cpufeatures to pick TDX, Zen, APIC MSR fence changes

   - x86's mem{cpy,set}_64.S used in 'perf bench'

   - Also, without tooling effects: asm-generic/unaligned.h, mount.h,
     fcntl.h, kvm headers"

* tag 'perf-tools-fixes-for-v6.8-1-2024-02-01' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools: (21 commits)
  perf tools headers: update the asm-generic/unaligned.h copy with the kernel sources
  tools include UAPI: Sync linux/mount.h copy with the kernel sources
  perf evlist: Fix evlist__new_default() for > 1 core PMU
  tools headers: Update the copy of x86's mem{cpy,set}_64.S used in 'perf bench'
  tools headers x86 cpufeatures: Sync with the kernel sources to pick TDX, Zen, APIC MSR fence changes
  tools headers UAPI: Sync unistd.h to pick {list,stat}mount, lsm_{[gs]et_self_attr,list_modules} syscall numbers
  perf vendor events intel: Alderlake/sapphirerapids metric fixes
  tools headers UAPI: Sync kvm headers with the kernel sources
  perf tools: Fix calloc() arguments to address error introduced in gcc-14
  perf top: Remove needless malloc(0) call that triggers -Walloc-size
  perf build: Make minimal shellcheck version to v0.6.0
  tools headers UAPI: Update tools's copy of drm.h headers to pick DRM_IOCTL_MODE_CLOSEFB
  perf test shell daemon: Make signal test less racy
  perf test shell script: Fix test for python being disabled
  perf test: Workaround debug output in list test
  perf list: Add output file option
  perf list: Switch error message to pr_err() to respect debug settings (-v)
  perf test: Fix 'perf script' tests on s390
  tools headers UAPI: Sync linux/fcntl.h with the kernel sources
  tools arch x86: Sync the msr-index.h copy with the kernel sources to pick IA32_MKTME_KEYID_PARTITIONING
  ...

573 files changed:
CREDITS
Documentation/ABI/testing/sysfs-class-net-queues
Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon
Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
Documentation/ABI/testing/sysfs-platform-silicom
Documentation/accel/introduction.rst
Documentation/admin-guide/kernel-parameters.rst
Documentation/admin-guide/kernel-per-CPU-kthreads.rst
Documentation/dev-tools/kunit/usage.rst
Documentation/devicetree/bindings/display/samsung/samsung,exynos-mixer.yaml
Documentation/devicetree/bindings/media/cnm,wave521c.yaml
Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml
Documentation/netlink/specs/rt_link.yaml
Documentation/sphinx/templates/kernel-toc.html
MAINTAINERS
Makefile
arch/Kconfig
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts
arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts
arch/arm/boot/dts/aspeed/aspeed-bmc-opp-tacoma.dts
arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi
arch/arm/boot/dts/nxp/imx/imx6ull-phytec-tauri.dtsi
arch/arm/boot/dts/nxp/imx/imx7d-flex-concentrator.dts
arch/arm/boot/dts/samsung/exynos4212-tab3.dtsi
arch/arm/boot/dts/ti/omap/am335x-moxa-uc-2100-common.dtsi
arch/arm64/Makefile
arch/arm64/boot/dts/exynos/google/gs101.dtsi
arch/arm64/boot/dts/freescale/imx8mm-phygate-tauri-l.dts
arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi
arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi
arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts
arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi
arch/arm64/boot/dts/freescale/imx8mp-venice-gw73xx.dtsi
arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts
arch/arm64/boot/dts/freescale/imx8mq-kontron-pitx-imx8m.dts
arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi
arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi
arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts
arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi
arch/arm64/include/asm/vdso.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/vdso32/Makefile
arch/loongarch/include/asm/kvm_vcpu.h
arch/loongarch/kernel/smp.c
arch/loongarch/kvm/mmu.c
arch/loongarch/mm/tlb.c
arch/m68k/Makefile
arch/mips/alchemy/common/prom.c
arch/mips/alchemy/common/setup.c
arch/mips/bcm63xx/boards/board_bcm963xx.c
arch/mips/bcm63xx/dev-rng.c
arch/mips/bcm63xx/dev-uart.c
arch/mips/bcm63xx/dev-wdt.c
arch/mips/bcm63xx/irq.c
arch/mips/bcm63xx/setup.c
arch/mips/bcm63xx/timer.c
arch/mips/cobalt/setup.c
arch/mips/fw/arc/memory.c
arch/mips/include/asm/mach-au1x00/au1000.h
arch/mips/include/asm/mach-cobalt/cobalt.h
arch/mips/kernel/elf.c
arch/mips/kernel/traps.c
arch/mips/lantiq/prom.c
arch/mips/loongson64/init.c
arch/mips/loongson64/numa.c
arch/mips/sgi-ip27/Makefile
arch/mips/sgi-ip27/ip27-berr.c
arch/mips/sgi-ip27/ip27-common.h
arch/mips/sgi-ip27/ip27-hubio.c [deleted file]
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sgi-ip27/ip27-memory.c
arch/mips/sgi-ip27/ip27-nmi.c
arch/mips/sgi-ip30/ip30-console.c
arch/mips/sgi-ip30/ip30-setup.c
arch/mips/sgi-ip32/crime.c
arch/mips/sgi-ip32/ip32-berr.c
arch/mips/sgi-ip32/ip32-common.h [new file with mode: 0644]
arch/mips/sgi-ip32/ip32-irq.c
arch/mips/sgi-ip32/ip32-memory.c
arch/mips/sgi-ip32/ip32-reset.c
arch/mips/sgi-ip32/ip32-setup.c
arch/parisc/Kconfig
arch/parisc/Makefile
arch/parisc/include/asm/assembly.h
arch/parisc/include/asm/extable.h [new file with mode: 0644]
arch/parisc/include/asm/special_insns.h
arch/parisc/include/asm/uaccess.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/drivers.c
arch/parisc/kernel/unaligned.c
arch/parisc/kernel/vmlinux.lds.S
arch/parisc/mm/fault.c
arch/powerpc/kernel/iommu.c
arch/riscv/boot/dts/sophgo/sg2042.dtsi
arch/um/Makefile
arch/x86/Makefile
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/intel-family.h
arch/x86/include/asm/kmsan.h
arch/x86/include/asm/syscall_wrapper.h
arch/x86/kernel/alternative.c
arch/x86/kernel/cpu/amd.c
block/blk-core.c
block/blk-map.c
block/blk-mq.c
block/ioctl.c
block/partitions/core.c
drivers/accel/ivpu/ivpu_debugfs.c
drivers/accel/ivpu/ivpu_drv.c
drivers/accel/ivpu/ivpu_drv.h
drivers/accel/ivpu/ivpu_gem.c
drivers/accel/ivpu/ivpu_gem.h
drivers/accel/ivpu/ivpu_hw_37xx.c
drivers/accel/ivpu/ivpu_hw_40xx.c
drivers/accel/ivpu/ivpu_ipc.c
drivers/accel/ivpu/ivpu_job.c
drivers/accel/ivpu/ivpu_job.h
drivers/accel/ivpu/ivpu_mmu.c
drivers/accel/ivpu/ivpu_mmu.h
drivers/accel/ivpu/ivpu_mmu_context.c
drivers/accel/ivpu/ivpu_pm.c
drivers/accel/ivpu/ivpu_pm.h
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/libata-sata.c
drivers/block/aoe/aoeblk.c
drivers/cpufreq/amd-pstate.c
drivers/cpufreq/intel_pstate.c
drivers/crypto/caam/caamalg_qi2.c
drivers/crypto/caam/caamhash.c
drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c
drivers/cxl/core/region.c
drivers/cxl/pci.c
drivers/dma-buf/heaps/cma_heap.c
drivers/firewire/core-device.c
drivers/firmware/arm_ffa/driver.c
drivers/firmware/arm_scmi/clock.c
drivers/firmware/arm_scmi/common.h
drivers/firmware/arm_scmi/mailbox.c
drivers/firmware/arm_scmi/perf.c
drivers/firmware/arm_scmi/raw_mode.c
drivers/firmware/arm_scmi/shmem.c
drivers/firmware/sysfb.c
drivers/gpio/gpio-eic-sprd.c
drivers/gpio/gpiolib-acpi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
drivers/gpu/drm/amd/amdgpu/cik_ih.c
drivers/gpu/drm/amd/amdgpu/cz_ih.c
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
drivers/gpu/drm/amd/amdgpu/iceland_ih.c
drivers/gpu/drm/amd/amdgpu/ih_v6_0.c
drivers/gpu/drm/amd/amdgpu/ih_v6_1.c
drivers/gpu/drm/amd/amdgpu/navi10_ih.c
drivers/gpu/drm/amd/amdgpu/si_ih.c
drivers/gpu/drm/amd/amdgpu/tonga_ih.c
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
drivers/gpu/drm/amd/amdgpu/vega10_ih.c
drivers/gpu/drm/amd/amdgpu/vega20_ih.c
drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h
drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm
drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx9.asm
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
drivers/gpu/drm/amd/amdkfd/kfd_priv.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dc_types.h
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_link_encoder.c
drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dio_link_encoder.c
drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c
drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c
drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
drivers/gpu/drm/amd/display/dc/inc/core_types.h
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c
drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
drivers/gpu/drm/amd/display/modules/power/power_helpers.c
drivers/gpu/drm/amd/display/modules/power/power_helpers.h
drivers/gpu/drm/amd/include/amd_shared.h
drivers/gpu/drm/amd/include/amdgpu_reg_state.h
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
drivers/gpu/drm/bridge/analogix/anx7625.c
drivers/gpu/drm/bridge/analogix/anx7625.h
drivers/gpu/drm/bridge/parade-ps8640.c
drivers/gpu/drm/bridge/samsung-dsim.c
drivers/gpu/drm/bridge/sii902x.c
drivers/gpu/drm/display/drm_dp_mst_topology.c
drivers/gpu/drm/exynos/exynos5433_drm_decon.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_gsc.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/display/icl_dsi.c
drivers/gpu/drm/i915/display/intel_psr.c
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_fence.h
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/scheduler/sched_main.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tests/drm_mm_test.c
drivers/gpu/drm/ttm/ttm_device.c
drivers/gpu/drm/v3d/v3d_submit.c
drivers/gpu/drm/virtio/virtgpu_drv.c
drivers/gpu/drm/xe/abi/guc_actions_abi.h
drivers/gpu/drm/xe/abi/guc_actions_slpc_abi.h
drivers/gpu/drm/xe/abi/guc_communication_ctb_abi.h
drivers/gpu/drm/xe/abi/guc_klvs_abi.h
drivers/gpu/drm/xe/abi/guc_messages_abi.h
drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_object.h
drivers/gpu/drm/xe/tests/xe_wa_test.c
drivers/gpu/drm/xe/xe_device.c
drivers/gpu/drm/xe/xe_dma_buf.c
drivers/gpu/drm/xe/xe_exec.c
drivers/gpu/drm/xe/xe_gt_mcr.c
drivers/gpu/drm/xe/xe_gt_pagefault.c
drivers/gpu/drm/xe/xe_guc_pc.c
drivers/gpu/drm/xe/xe_hw_fence.c
drivers/gpu/drm/xe/xe_hwmon.c
drivers/gpu/drm/xe/xe_lrc.c
drivers/gpu/drm/xe/xe_migrate.c
drivers/gpu/drm/xe/xe_mmio.c
drivers/gpu/drm/xe/xe_pt.c
drivers/gpu/drm/xe/xe_query.c
drivers/gpu/drm/xe/xe_sync.h
drivers/gpu/drm/xe/xe_vm.c
drivers/gpu/drm/xe/xe_vm.h
drivers/gpu/drm/xe/xe_vm_types.h
drivers/hid/bpf/hid_bpf_dispatch.c
drivers/hid/bpf/hid_bpf_dispatch.h
drivers/hid/bpf/hid_bpf_jmp_table.c
drivers/hid/hid-ids.h
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-nvidia-shield.c
drivers/hid/hid-steam.c
drivers/hid/hidraw.c
drivers/hid/i2c-hid/i2c-hid-core.c
drivers/hid/i2c-hid/i2c-hid-of.c
drivers/hwmon/gigabyte_waterforce.c
drivers/hwmon/pmbus/mp2975.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/atkbd.c
drivers/input/mouse/bcm5974.c
drivers/input/serio/i8042-acpipnpio.h
drivers/input/touchscreen/goodix.c
drivers/iommu/iommu.c
drivers/md/dm-core.h
drivers/md/dm-crypt.c
drivers/md/dm-ioctl.c
drivers/md/dm-stats.c
drivers/md/dm-table.c
drivers/md/dm-verity-target.c
drivers/md/dm-verity.h
drivers/md/dm-writecache.c
drivers/md/raid1.c
drivers/media/common/videobuf2/videobuf2-core.c
drivers/media/common/videobuf2/videobuf2-v4l2.c
drivers/media/platform/chips-media/wave5/wave5-vpu.c
drivers/net/dsa/mt7530.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/qca/qca8k-8xxx.c
drivers/net/ethernet/amd/pds_core/adminq.c
drivers/net/ethernet/amd/pds_core/core.c
drivers/net/ethernet/amd/pds_core/core.h
drivers/net/ethernet/amd/pds_core/debugfs.c
drivers/net/ethernet/amd/pds_core/dev.c
drivers/net/ethernet/amd/pds_core/devlink.c
drivers/net/ethernet/amd/pds_core/fw.c
drivers/net/ethernet/amd/pds_core/main.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
drivers/net/ethernet/google/gve/gve_rx.c
drivers/net/ethernet/intel/e1000e/e1000.h
drivers/net/ethernet/intel/e1000e/ptp.c
drivers/net/ethernet/intel/idpf/virtchnl2.h
drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
drivers/net/ethernet/mediatek/mtk_eth_soc.c
drivers/net/ethernet/microchip/lan966x/lan966x_port.c
drivers/net/ethernet/netronome/nfp/flower/conntrack.c
drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/hyperv/netvsc.c
drivers/net/phy/mediatek-ge-soc.c
drivers/net/xen-netback/netback.c
drivers/nvme/common/auth.c
drivers/nvme/common/keyring.c
drivers/nvme/host/apple.c
drivers/nvme/host/auth.c
drivers/nvme/host/constants.c
drivers/nvme/host/core.c
drivers/nvme/host/fabrics.c
drivers/nvme/host/fabrics.h
drivers/nvme/host/fc.c
drivers/nvme/host/multipath.c
drivers/nvme/host/nvme.h
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/host/sysfs.c
drivers/nvme/host/tcp.c
drivers/nvme/target/core.c
drivers/nvme/target/discovery.c
drivers/nvme/target/fc.c
drivers/nvme/target/fcloop.c
drivers/nvme/target/loop.c
drivers/nvme/target/rdma.c
drivers/nvme/target/tcp.c
drivers/pci/bus.c
drivers/pci/controller/dwc/pcie-qcom.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aspm.c
drivers/platform/mellanox/mlxbf-pmc.c
drivers/platform/mellanox/mlxbf-tmfifo.c
drivers/platform/x86/amd/pmf/Kconfig
drivers/platform/x86/amd/pmf/spc.c
drivers/platform/x86/amd/pmf/tee-if.c
drivers/platform/x86/intel/ifs/load.c
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h
drivers/platform/x86/intel/wmi/sbl-fw-update.c
drivers/platform/x86/p2sb.c
drivers/platform/x86/touchscreen_dmi.c
drivers/platform/x86/wmi.c
drivers/power/supply/qcom_battmgr.c
drivers/regulator/max5970-regulator.c
drivers/regulator/pwm-regulator.c
drivers/regulator/ti-abb-regulator.c
drivers/scsi/initio.c
drivers/scsi/isci/request.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_priv.h
drivers/scsi/storvsc_drv.c
drivers/scsi/virtio_scsi.c
drivers/soc/apple/mailbox.c
drivers/spi/spi-bcm-qspi.c
drivers/spi/spi-cadence.c
drivers/spi/spi-cs42l43.c
drivers/spi/spi-hisi-sfc-v3xx.c
drivers/spi/spi-imx.c
drivers/spi/spi-intel-pci.c
drivers/spi/spi-sh-msiof.c
drivers/spi/spi.c
drivers/thermal/intel/intel_powerclamp.c
fs/bcachefs/alloc_background.c
fs/bcachefs/btree_locking.c
fs/bcachefs/debug.c
fs/bcachefs/fs-io.c
fs/bcachefs/fsck.c
fs/bcachefs/journal.c
fs/bcachefs/journal_io.c
fs/bcachefs/str_hash.h
fs/bcachefs/util.c
fs/bcachefs/util.h
fs/erofs/compress.h
fs/erofs/decompressor.c
fs/erofs/decompressor_deflate.c
fs/erofs/decompressor_lzma.c
fs/erofs/fscache.c
fs/erofs/inode.c
fs/erofs/utils.c
fs/erofs/zdata.c
fs/exfat/inode.c
fs/gfs2/dentry.c
fs/gfs2/inode.c
fs/hugetlbfs/inode.c
fs/jfs/jfs_dmap.c
fs/smb/client/cached_dir.c
fs/smb/client/cifsencrypt.c
fs/smb/client/cifsfs.c
fs/smb/client/cifsglob.h
fs/smb/client/file.c
fs/smb/client/inode.c
fs/smb/client/readdir.c
fs/smb/client/smb2inode.c
fs/smb/client/smb2ops.c
fs/smb/client/smb2pdu.c
fs/smb/client/smb2proto.h
fs/smb/client/smbencrypt.c
fs/smb/client/transport.c
fs/smb/server/ksmbd_netlink.h
fs/smb/server/transport_ipc.c
fs/smb/server/transport_tcp.c
fs/tracefs/event_inode.c
fs/tracefs/inode.c
fs/tracefs/internal.h
fs/xfs/xfs_super.c
include/linux/hid_bpf.h
include/linux/libata.h
include/linux/lsm_hook_defs.h
include/linux/mman.h
include/linux/mmzone.h
include/linux/netfilter/ipset/ip_set.h
include/linux/nvme.h
include/linux/pci.h
include/linux/spi/spi.h
include/linux/syscalls.h
include/net/af_unix.h
include/net/ip.h
include/net/netfilter/nf_tables.h
include/sound/cs35l56.h
include/uapi/drm/ivpu_accel.h
init/Kconfig
io_uring/io_uring.h
io_uring/net.c
io_uring/opdef.c
io_uring/openclose.c
io_uring/poll.c
io_uring/poll.h
io_uring/rw.c
kernel/events/uprobes.c
kernel/futex/core.c
kernel/futex/pi.c
kernel/irq/irqdesc.c
kernel/time/clocksource.c
kernel/time/tick-sched.c
kernel/trace/ring_buffer.c
kernel/trace/trace_events_trigger.c
kernel/trace/trace_osnoise.c
lib/kunit/device.c
lib/kunit/executor.c
lib/kunit/kunit-test.c
lib/kunit/test.c
lib/stackdepot.c
mm/huge_memory.c
mm/memblock.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/mmap.c
mm/page-writeback.c
mm/readahead.c
mm/userfaultfd.c
net/batman-adv/multicast.c
net/bridge/br_multicast.c
net/bridge/br_private.h
net/devlink/port.c
net/hsr/hsr_device.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ipmr.c
net/ipv4/raw.c
net/ipv4/tcp.c
net/ipv4/udp.c
net/ipv6/addrconf_core.c
net/ipv6/ip6_tunnel.c
net/llc/af_llc.c
net/mptcp/protocol.c
net/netfilter/ipset/ip_set_bitmap_gen.h
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_hash_gen.h
net/netfilter/ipset/ip_set_list_set.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_log.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_ct.c
net/netfilter/nft_tunnel.c
net/nfc/nci/core.c
net/smc/smc_core.c
net/sunrpc/svc.c
net/unix/af_unix.c
net/unix/diag.c
scripts/Makefile.defconf
scripts/kconfig/symbol.c
scripts/mod/modpost.c
scripts/mod/modpost.h
scripts/package/kernel.spec
security/security.c
sound/core/pcm.c
sound/pci/hda/cs35l41_hda_property.c
sound/pci/hda/cs35l56_hda.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_cs8409.c
sound/pci/hda/patch_realtek.c
sound/soc/amd/acp/acp-mach-common.c
sound/soc/amd/acp/acp-sof-mach.c
sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c
sound/soc/amd/yc/acp6x-mach.c
sound/soc/codecs/cs35l56-shared.c
sound/soc/codecs/cs35l56.c
sound/soc/codecs/cs35l56.h
sound/soc/codecs/es8326.c [changed mode: 0755->0644]
sound/soc/codecs/es8326.h
sound/soc/codecs/lpass-wsa-macro.c
sound/soc/codecs/wcd9335.c
sound/soc/codecs/wcd934x.c
sound/soc/codecs/wcd938x.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wsa883x.c
sound/soc/qcom/sc8280xp.c
sound/soc/soc-core.c
sound/soc/sunxi/sun4i-spdif.c
sound/usb/clock.c
sound/usb/format.c
sound/usb/midi2.c
sound/usb/quirks.c
sound/virtio/virtio_card.c
sound/virtio/virtio_ctl_msg.c
sound/virtio/virtio_pcm_msg.c
tools/power/cpupower/bench/Makefile
tools/testing/cxl/Kbuild
tools/testing/cxl/test/Kbuild
tools/testing/nvdimm/Kbuild
tools/testing/selftests/drivers/net/bonding/lag_lib.sh
tools/testing/selftests/drivers/net/team/config
tools/testing/selftests/hid/tests/test_wacom_generic.py
tools/testing/selftests/livepatch/functions.sh
tools/testing/selftests/mm/charge_reserved_hugetlb.sh
tools/testing/selftests/mm/ksm_tests.c
tools/testing/selftests/mm/map_hugetlb.c
tools/testing/selftests/mm/mremap_test.c
tools/testing/selftests/mm/va_high_addr_switch.sh
tools/testing/selftests/mm/write_hugetlb_memory.sh
tools/testing/selftests/net/Makefile
tools/testing/selftests/net/config
tools/testing/selftests/net/forwarding/Makefile
tools/testing/selftests/net/lib.sh
tools/testing/selftests/net/mptcp/config
tools/testing/selftests/net/mptcp/mptcp_join.sh
tools/testing/selftests/net/mptcp/mptcp_lib.sh
tools/testing/selftests/net/mptcp/settings
tools/testing/selftests/net/mptcp/simult_flows.sh
tools/testing/selftests/net/net_helper.sh [changed mode: 0755->0644]
tools/testing/selftests/net/pmtu.sh
tools/testing/selftests/net/setup_loopback.sh [changed mode: 0755->0644]
tools/testing/selftests/net/setup_veth.sh
tools/testing/selftests/net/tcp_ao/config [new file with mode: 0644]
tools/testing/selftests/net/tcp_ao/key-management.c
tools/testing/selftests/net/tcp_ao/lib/sock.c
tools/testing/selftests/net/tcp_ao/rst.c
tools/testing/selftests/net/tcp_ao/settings [new file with mode: 0644]
tools/testing/selftests/net/udpgro.sh
tools/testing/selftests/net/udpgro_bench.sh
tools/testing/selftests/net/udpgro_frglist.sh
tools/testing/selftests/net/udpgro_fwd.sh
tools/testing/selftests/net/veth.sh
tools/testing/selftests/net/xdp_dummy.c [new file with mode: 0644]
tools/testing/selftests/rseq/basic_percpu_ops_test.c
tools/testing/selftests/rseq/param_test.c
tools/testing/selftests/seccomp/seccomp_benchmark.c

diff --git a/CREDITS b/CREDITS
index 5797e8f7e92b06f8736c01c6c191815c4802b6fd..df8d6946739f68655a8b077f0ebcc4bf4612944b 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2161,6 +2161,19 @@ N: Mike Kravetz
 E: mike.kravetz@oracle.com
 D: Maintenance and development of the hugetlb subsystem
 
+N: Seth Jennings
+E: sjenning@redhat.com
+D: Creation and maintenance of zswap
+
+N: Dan Streetman
+E: ddstreet@ieee.org
+D: Maintenance and development of zswap
+D: Creation and maintenance of the zpool API
+
+N: Vitaly Wool
+E: vitaly.wool@konsulko.com
+D: Maintenance and development of zswap
+
 N: Andreas S. Krebs
 E: akrebs@altavista.net
 D: CYPRESS CY82C693 chipset IDE, Digital's PC-Alpha 164SX boards
index 906ff3ca928ac1389567a5f02bdc4e06c3980b38..5bff64d256c207c8a7d2c915e0e8affac191913c 100644 (file)
@@ -1,4 +1,4 @@
-What:          /sys/class/<iface>/queues/rx-<queue>/rps_cpus
+What:          /sys/class/net/<iface>/queues/rx-<queue>/rps_cpus
 Date:          March 2010
 KernelVersion: 2.6.35
 Contact:       netdev@vger.kernel.org
@@ -8,7 +8,7 @@ Description:
                network device queue. Possible values depend on the number
                of available CPU(s) in the system.
 
-What:          /sys/class/<iface>/queues/rx-<queue>/rps_flow_cnt
+What:          /sys/class/net/<iface>/queues/rx-<queue>/rps_flow_cnt
 Date:          April 2010
 KernelVersion: 2.6.35
 Contact:       netdev@vger.kernel.org
@@ -16,7 +16,7 @@ Description:
                Number of Receive Packet Steering flows being currently
                processed by this particular network device receive queue.
 
-What:          /sys/class/<iface>/queues/tx-<queue>/tx_timeout
+What:          /sys/class/net/<iface>/queues/tx-<queue>/tx_timeout
 Date:          November 2011
 KernelVersion: 3.3
 Contact:       netdev@vger.kernel.org
@@ -24,7 +24,7 @@ Description:
                Indicates the number of transmit timeout events seen by this
                network interface transmit queue.
 
-What:          /sys/class/<iface>/queues/tx-<queue>/tx_maxrate
+What:          /sys/class/net/<iface>/queues/tx-<queue>/tx_maxrate
 Date:          March 2015
 KernelVersion: 4.1
 Contact:       netdev@vger.kernel.org
@@ -32,7 +32,7 @@ Description:
                A Mbps max-rate set for the queue, a value of zero means disabled,
                default is disabled.
 
-What:          /sys/class/<iface>/queues/tx-<queue>/xps_cpus
+What:          /sys/class/net/<iface>/queues/tx-<queue>/xps_cpus
 Date:          November 2010
 KernelVersion: 2.6.38
 Contact:       netdev@vger.kernel.org
@@ -42,7 +42,7 @@ Description:
                network device transmit queue. Possible values depend on the
                number of available CPU(s) in the system.
 
-What:          /sys/class/<iface>/queues/tx-<queue>/xps_rxqs
+What:          /sys/class/net/<iface>/queues/tx-<queue>/xps_rxqs
 Date:          June 2018
 KernelVersion: 4.18.0
 Contact:       netdev@vger.kernel.org
@@ -53,7 +53,7 @@ Description:
                number of available receive queue(s) in the network device.
                Default is disabled.
 
-What:          /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/hold_time
+What:          /sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/hold_time
 Date:          November 2011
 KernelVersion: 3.3
 Contact:       netdev@vger.kernel.org
@@ -62,7 +62,7 @@ Description:
                of this particular network device transmit queue.
                Default value is 1000.
 
-What:          /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/inflight
+What:          /sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/inflight
 Date:          November 2011
 KernelVersion: 3.3
 Contact:       netdev@vger.kernel.org
@@ -70,7 +70,7 @@ Description:
                Indicates the number of bytes (objects) in flight on this
                network device transmit queue.
 
-What:          /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/limit
+What:          /sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/limit
 Date:          November 2011
 KernelVersion: 3.3
 Contact:       netdev@vger.kernel.org
@@ -79,7 +79,7 @@ Description:
                on this network device transmit queue. This value is clamped
                to be within the bounds defined by limit_max and limit_min.
 
-What:          /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/limit_max
+What:          /sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/limit_max
 Date:          November 2011
 KernelVersion: 3.3
 Contact:       netdev@vger.kernel.org
@@ -88,7 +88,7 @@ Description:
                queued on this network device transmit queue. See
                include/linux/dynamic_queue_limits.h for the default value.
 
-What:          /sys/class/<iface>/queues/tx-<queue>/byte_queue_limits/limit_min
+What:          /sys/class/net/<iface>/queues/tx-<queue>/byte_queue_limits/limit_min
 Date:          November 2011
 KernelVersion: 3.3
 Contact:       netdev@vger.kernel.org
index 8d7d8f05f6cd0a3d7bb9fa06f0a40730f5bae99b..92fe7c5c5ac1d1d981562d1b441f32a6bafdc1aa 100644 (file)
@@ -1,4 +1,4 @@
-What:          /sys/devices/.../hwmon/hwmon<i>/in0_input
+What:          /sys/bus/pci/drivers/i915/.../hwmon/hwmon<i>/in0_input
 Date:          February 2023
 KernelVersion: 6.2
 Contact:       intel-gfx@lists.freedesktop.org
@@ -6,7 +6,7 @@ Description:    RO. Current Voltage in millivolt.
 
                Only supported for particular Intel i915 graphics platforms.
 
-What:          /sys/devices/.../hwmon/hwmon<i>/power1_max
+What:          /sys/bus/pci/drivers/i915/.../hwmon/hwmon<i>/power1_max
 Date:          February 2023
 KernelVersion: 6.2
 Contact:       intel-gfx@lists.freedesktop.org
@@ -20,7 +20,7 @@ Description:  RW. Card reactive sustained  (PL1/Tau) power limit in microwatts.
 
                Only supported for particular Intel i915 graphics platforms.
 
-What:          /sys/devices/.../hwmon/hwmon<i>/power1_rated_max
+What:          /sys/bus/pci/drivers/i915/.../hwmon/hwmon<i>/power1_rated_max
 Date:          February 2023
 KernelVersion: 6.2
 Contact:       intel-gfx@lists.freedesktop.org
@@ -28,7 +28,7 @@ Description:  RO. Card default power limit (default TDP setting).
 
                Only supported for particular Intel i915 graphics platforms.
 
-What:          /sys/devices/.../hwmon/hwmon<i>/power1_max_interval
+What:          /sys/bus/pci/drivers/i915/.../hwmon/hwmon<i>/power1_max_interval
 Date:          February 2023
 KernelVersion: 6.2
 Contact:       intel-gfx@lists.freedesktop.org
@@ -37,7 +37,7 @@ Description:  RW. Sustained power limit interval (Tau in PL1/Tau) in
 
                Only supported for particular Intel i915 graphics platforms.
 
-What:          /sys/devices/.../hwmon/hwmon<i>/power1_crit
+What:          /sys/bus/pci/drivers/i915/.../hwmon/hwmon<i>/power1_crit
 Date:          February 2023
 KernelVersion: 6.2
 Contact:       intel-gfx@lists.freedesktop.org
@@ -50,7 +50,7 @@ Description:  RW. Card reactive critical (I1) power limit in microwatts.
 
                Only supported for particular Intel i915 graphics platforms.
 
-What:          /sys/devices/.../hwmon/hwmon<i>/curr1_crit
+What:          /sys/bus/pci/drivers/i915/.../hwmon/hwmon<i>/curr1_crit
 Date:          February 2023
 KernelVersion: 6.2
 Contact:       intel-gfx@lists.freedesktop.org
@@ -63,7 +63,7 @@ Description:  RW. Card reactive critical (I1) power limit in milliamperes.
 
                Only supported for particular Intel i915 graphics platforms.
 
-What:          /sys/devices/.../hwmon/hwmon<i>/energy1_input
+What:          /sys/bus/pci/drivers/i915/.../hwmon/hwmon<i>/energy1_input
 Date:          February 2023
 KernelVersion: 6.2
 Contact:       intel-gfx@lists.freedesktop.org
index 8c321bc9dc04401e5b25fb2e4c2e509f0d2eba14..023fd82de3f70a61fb9c58c973690bc0fff38e12 100644 (file)
@@ -1,4 +1,4 @@
-What:          /sys/devices/.../hwmon/hwmon<i>/power1_max
+What:          /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/power1_max
 Date:          September 2023
 KernelVersion: 6.5
 Contact:       intel-xe@lists.freedesktop.org
@@ -12,7 +12,7 @@ Description:  RW. Card reactive sustained  (PL1) power limit in microwatts.
 
                Only supported for particular Intel xe graphics platforms.
 
-What:          /sys/devices/.../hwmon/hwmon<i>/power1_rated_max
+What:          /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/power1_rated_max
 Date:          September 2023
 KernelVersion: 6.5
 Contact:       intel-xe@lists.freedesktop.org
@@ -20,7 +20,7 @@ Description:  RO. Card default power limit (default TDP setting).
 
                Only supported for particular Intel xe graphics platforms.
 
-What:          /sys/devices/.../hwmon/hwmon<i>/power1_crit
+What:          /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/power1_crit
 Date:          September 2023
 KernelVersion: 6.5
 Contact:       intel-xe@lists.freedesktop.org
@@ -33,7 +33,7 @@ Description:  RW. Card reactive critical (I1) power limit in microwatts.
 
                Only supported for particular Intel xe graphics platforms.
 
-What:          /sys/devices/.../hwmon/hwmon<i>/curr1_crit
+What:          /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/curr1_crit
 Date:          September 2023
 KernelVersion: 6.5
 Contact:       intel-xe@lists.freedesktop.org
@@ -44,7 +44,7 @@ Description:  RW. Card reactive critical (I1) power limit in milliamperes.
                the operating frequency if the power averaged over a window
                exceeds this limit.
 
-What:          /sys/devices/.../hwmon/hwmon<i>/in0_input
+What:          /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/in0_input
 Date:          September 2023
 KernelVersion: 6.5
 Contact:       intel-xe@lists.freedesktop.org
@@ -52,7 +52,7 @@ Description:  RO. Current Voltage in millivolt.
 
                Only supported for particular Intel xe graphics platforms.
 
-What:          /sys/devices/.../hwmon/hwmon<i>/energy1_input
+What:          /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/energy1_input
 Date:          September 2023
 KernelVersion: 6.5
 Contact:       intel-xe@lists.freedesktop.org
@@ -60,7 +60,7 @@ Description:  RO. Energy input of device in microjoules.
 
                Only supported for particular Intel xe graphics platforms.
 
-What:          /sys/devices/.../hwmon/hwmon<i>/power1_max_interval
+What:          /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/power1_max_interval
 Date:          October 2023
 KernelVersion: 6.6
 Contact:       intel-xe@lists.freedesktop.org
index 2288b3665d160a87b352def3e122461256a21761..4d1cc5bdbcc5f9f945dd825aed99cad89982fdd4 100644 (file)
@@ -10,6 +10,7 @@ What:         /sys/devices/platform/silicom-platform/power_cycle
 Date:          November 2023
 KernelVersion: 6.7
 Contact:       Henry Shi <henrys@silicom-usa.com>
+Description:
                This file allow user to power cycle the platform.
                Default value is 0; when set to 1, it powers down
                the platform, waits 5 seconds, then powers on the
index 89984dfececf0b0b07a937179808d27b8268cf4b..ae30301366379d067e5cb71b4fcb534bc53c4d40 100644 (file)
@@ -101,8 +101,8 @@ External References
 email threads
 -------------
 
-* `Initial discussion on the New subsystem for acceleration devices <https://lkml.org/lkml/2022/7/31/83>`_ - Oded Gabbay (2022)
-* `patch-set to add the new subsystem <https://lkml.org/lkml/2022/10/22/544>`_ - Oded Gabbay (2022)
+* `Initial discussion on the New subsystem for acceleration devices <https://lore.kernel.org/lkml/CAFCwf11=9qpNAepL7NL+YAV_QO=Wv6pnWPhKHKAepK3fNn+2Dg@mail.gmail.com/>`_ - Oded Gabbay (2022)
+* `patch-set to add the new subsystem <https://lore.kernel.org/lkml/20221022214622.18042-1-ogabbay@kernel.org/>`_ - Oded Gabbay (2022)
 
 Conference talks
 ----------------
index 102937bc8443a23d88b952b4d7278e5e6cd25c21..4410384596a90b0ab26b4cf43bac54aaf78193fe 100644 (file)
@@ -218,8 +218,3 @@ bytes respectively. Such letter suffixes can also be entirely omitted:
 
 .. include:: kernel-parameters.txt
    :literal:
-
-Todo
-----
-
-       Add more DRM drivers.
index 993c2a05f5eeab65f9e3d3a5464ac26513452472..b6aeae3327ceb537b78fdbd86961ae670614395b 100644 (file)
@@ -243,13 +243,9 @@ To reduce its OS jitter, do any of the following:
 3.     Do any of the following needed to avoid jitter that your
        application cannot tolerate:
 
-       a.      Build your kernel with CONFIG_SLUB=y rather than
-               CONFIG_SLAB=y, thus avoiding the slab allocator's periodic
-               use of each CPU's workqueues to run its cache_reap()
-               function.
-       b.      Avoid using oprofile, thus avoiding OS jitter from
+       a.      Avoid using oprofile, thus avoiding OS jitter from
                wq_sync_buffer().
-       c.      Limit your CPU frequency so that a CPU-frequency
+       b.      Limit your CPU frequency so that a CPU-frequency
                governor is not required, possibly enlisting the aid of
                special heatsinks or other cooling technologies.  If done
                correctly, and if you CPU architecture permits, you should
@@ -259,7 +255,7 @@ To reduce its OS jitter, do any of the following:
 
                WARNING:  Please check your CPU specifications to
                make sure that this is safe on your particular system.
-       d.      As of v3.18, Christoph Lameter's on-demand vmstat workers
+       c.      As of v3.18, Christoph Lameter's on-demand vmstat workers
                commit prevents OS jitter due to vmstat_update() on
                CONFIG_SMP=y systems.  Before v3.18, is not possible
                to entirely get rid of the OS jitter, but you can
@@ -274,7 +270,7 @@ To reduce its OS jitter, do any of the following:
                (based on an earlier one from Gilad Ben-Yossef) that
                reduces or even eliminates vmstat overhead for some
                workloads at https://lore.kernel.org/r/00000140e9dfd6bd-40db3d4f-c1be-434f-8132-7820f81bb586-000000@email.amazonses.com.
-       e.      If running on high-end powerpc servers, build with
+       d.      If running on high-end powerpc servers, build with
                CONFIG_PPC_RTAS_DAEMON=n.  This prevents the RTAS
                daemon from running on each CPU every second or so.
                (This will require editing Kconfig files and will defeat
@@ -282,12 +278,12 @@ To reduce its OS jitter, do any of the following:
                due to the rtas_event_scan() function.
                WARNING:  Please check your CPU specifications to
                make sure that this is safe on your particular system.
-       f.      If running on Cell Processor, build your kernel with
+       e.      If running on Cell Processor, build your kernel with
                CBE_CPUFREQ_SPU_GOVERNOR=n to avoid OS jitter from
                spu_gov_work().
                WARNING:  Please check your CPU specifications to
                make sure that this is safe on your particular system.
-       g.      If running on PowerMAC, build your kernel with
+       f.      If running on PowerMAC, build your kernel with
                CONFIG_PMAC_RACKMETER=n to disable the CPU-meter,
                avoiding OS jitter from rackmeter_do_timer().
 
index a9efab50eed83e06a89549aeb1fb4da1b2eba1d9..22955d56b3799bfc3f3b92874b638aa24c1edaa6 100644 (file)
@@ -671,8 +671,23 @@ Testing Static Functions
 ------------------------
 
 If we do not want to expose functions or variables for testing, one option is to
-conditionally ``#include`` the test file at the end of your .c file. For
-example:
+conditionally export the used symbol. For example:
+
+.. code-block:: c
+
+       /* In my_file.c */
+
+       VISIBLE_IF_KUNIT int do_interesting_thing();
+       EXPORT_SYMBOL_IF_KUNIT(do_interesting_thing);
+
+       /* In my_file.h */
+
+       #if IS_ENABLED(CONFIG_KUNIT)
+               int do_interesting_thing(void);
+       #endif
+
+Alternatively, you could conditionally ``#include`` the test file at the end of
+your .c file. For example:
 
 .. code-block:: c
 
index 25d53fde92e1104490e3f8e604184b9449150be3..597c9cc6a312acb66b0355f84f9dd8977dbb2197 100644 (file)
@@ -85,7 +85,7 @@ allOf:
         clocks:
           minItems: 6
           maxItems: 6
-        regs:
+        reg:
           minItems: 2
           maxItems: 2
 
@@ -99,7 +99,7 @@ allOf:
         clocks:
           minItems: 4
           maxItems: 4
-        regs:
+        reg:
           minItems: 2
           maxItems: 2
 
@@ -116,7 +116,7 @@ allOf:
         clocks:
           minItems: 3
           maxItems: 3
-        regs:
+        reg:
           minItems: 1
           maxItems: 1
 
index 6d5569e77b7a1239219c13ef2a163849ce5bfd86..6a11c1d11fb5f9a9ccd343c2cb461bd7f3411121 100644 (file)
@@ -17,7 +17,7 @@ properties:
   compatible:
     items:
       - enum:
-          - ti,k3-j721s2-wave521c
+          - ti,j721s2-wave521c
       - const: cnm,wave521c
 
   reg:
@@ -53,7 +53,7 @@ additionalProperties: false
 examples:
   - |
     vpu: video-codec@12345678 {
-        compatible = "ti,k3-j721s2-wave521c", "cnm,wave521c";
+        compatible = "ti,j721s2-wave521c", "cnm,wave521c";
         reg = <0x12345678 0x1000>;
         clocks = <&clks 42>;
         interrupts = <42>;
index 8108c564dd78a84a1d869a60b975dcb51e6480ff..aa32dc950e72ccdaf7fb1ac7f759d57a855fc9b6 100644 (file)
@@ -22,6 +22,7 @@ properties:
       - const: allwinner,sun6i-a31-spdif
       - const: allwinner,sun8i-h3-spdif
       - const: allwinner,sun50i-h6-spdif
+      - const: allwinner,sun50i-h616-spdif
       - items:
           - const: allwinner,sun8i-a83t-spdif
           - const: allwinner,sun8i-h3-spdif
@@ -62,6 +63,8 @@ allOf:
             enum:
               - allwinner,sun6i-a31-spdif
               - allwinner,sun8i-h3-spdif
+              - allwinner,sun50i-h6-spdif
+              - allwinner,sun50i-h616-spdif
 
     then:
       required:
@@ -73,7 +76,7 @@ allOf:
           contains:
             enum:
               - allwinner,sun8i-h3-spdif
-              - allwinner,sun50i-h6-spdif
+              - allwinner,sun50i-h616-spdif
 
     then:
       properties:
index 1ad01d52a8638dcf6ee8a1c6c3d58698abd0d8e4..8e4d19adee8cd17eae831db73692c9237b5e0ad1 100644 (file)
@@ -942,6 +942,10 @@ attribute-sets:
       -
         name: gro-ipv4-max-size
         type: u32
+      -
+        name: dpll-pin
+        type: nest
+        nested-attributes: link-dpll-pin-attrs
   -
     name: af-spec-attrs
     attributes:
@@ -1627,6 +1631,12 @@ attribute-sets:
       -
         name: used
         type: u8
+  -
+    name: link-dpll-pin-attrs
+    attributes:
+      -
+        name: id
+        type: u32
 
 sub-messages:
   -
index b58efa99df527d3d870d9572e6ee7f18912fe99f..41f1efbe64bb2898f1770deb128630b316a68a08 100644 (file)
@@ -12,5 +12,7 @@
 <script type="text/javascript"> <!--
   var sbar = document.getElementsByClassName("sphinxsidebar")[0];
   let currents = document.getElementsByClassName("current")
-  sbar.scrollTop = currents[currents.length - 1].offsetTop;
+  if (currents.length) {
+    sbar.scrollTop = currents[currents.length - 1].offsetTop;
+  }
   --> </script>
index 92152ac346c8de27da07a57f695c170db771bc61..1dc764bd0fdd02fd4a5d7c6ddace109fe18097e0 100644 (file)
@@ -3168,10 +3168,10 @@ F:      drivers/hwmon/asus-ec-sensors.c
 
 ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS
 M:     Corentin Chary <corentin.chary@gmail.com>
-L:     acpi4asus-user@lists.sourceforge.net
+M:     Luke D. Jones <luke@ljones.dev>
 L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
-W:     http://acpi4asus.sf.net
+W:     https://asus-linux.org/
 F:     drivers/platform/x86/asus*.c
 F:     drivers/platform/x86/eeepc*.c
 
@@ -5958,7 +5958,6 @@ S:        Maintained
 F:     drivers/platform/x86/dell/dell-wmi-descriptor.c
 
 DELL WMI HARDWARE PRIVACY SUPPORT
-M:     Perry Yuan <Perry.Yuan@dell.com>
 L:     Dell.Client.Kernel@dell.com
 L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
@@ -10284,7 +10283,7 @@ F:      drivers/scsi/ibmvscsi/ibmvscsi*
 F:     include/scsi/viosrp.h
 
 IBM Power Virtual SCSI Device Target Driver
-M:     Michael Cyr <mikecyr@linux.ibm.com>
+M:     Tyrel Datwyler <tyreld@linux.ibm.com>
 L:     linux-scsi@vger.kernel.org
 L:     target-devel@vger.kernel.org
 S:     Supported
@@ -11726,6 +11725,7 @@ F:      fs/smb/server/
 KERNEL UNIT TESTING FRAMEWORK (KUnit)
 M:     Brendan Higgins <brendanhiggins@google.com>
 M:     David Gow <davidgow@google.com>
+R:     Rae Moar <rmoar@google.com>
 L:     linux-kselftest@vger.kernel.org
 L:     kunit-dev@googlegroups.com
 S:     Maintained
@@ -12904,6 +12904,8 @@ M:      Alejandro Colomar <alx@kernel.org>
 L:     linux-man@vger.kernel.org
 S:     Maintained
 W:     http://www.kernel.org/doc/man-pages
+T:     git git://git.kernel.org/pub/scm/docs/man-pages/man-pages.git
+T:     git git://www.alejandro-colomar.es/src/alx/linux/man-pages/man-pages.git
 
 MANAGEMENT COMPONENT TRANSPORT PROTOCOL (MCTP)
 M:     Jeremy Kerr <jk@codeconstruct.com.au>
@@ -15179,6 +15181,7 @@ F:      Documentation/networking/net_cachelines/net_device.rst
 F:     drivers/connector/
 F:     drivers/net/
 F:     include/dt-bindings/net/
+F:     include/linux/cn_proc.h
 F:     include/linux/etherdevice.h
 F:     include/linux/fcdevice.h
 F:     include/linux/fddidevice.h
@@ -15186,6 +15189,7 @@ F:      include/linux/hippidevice.h
 F:     include/linux/if_*
 F:     include/linux/inetdevice.h
 F:     include/linux/netdevice.h
+F:     include/uapi/linux/cn_proc.h
 F:     include/uapi/linux/if_*
 F:     include/uapi/linux/netdevice.h
 X:     drivers/net/wireless/
@@ -16858,9 +16862,8 @@ F:      Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml
 F:     drivers/pci/controller/pcie-xilinx-cpm.c
 
 PCI ENDPOINT SUBSYSTEM
-M:     Lorenzo Pieralisi <lpieralisi@kernel.org>
+M:     Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
 M:     Krzysztof Wilczyński <kw@linux.com>
-R:     Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
 R:     Kishon Vijay Abraham I <kishon@kernel.org>
 L:     linux-pci@vger.kernel.org
 S:     Supported
@@ -18083,7 +18086,6 @@ F:      drivers/net/ethernet/qualcomm/emac/
 
 QUALCOMM ETHQOS ETHERNET DRIVER
 M:     Vinod Koul <vkoul@kernel.org>
-R:     Bhupesh Sharma <bhupesh.sharma@linaro.org>
 L:     netdev@vger.kernel.org
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
@@ -20551,6 +20553,7 @@ F:      Documentation/translations/sp_SP/
 
 SPARC + UltraSPARC (sparc/sparc64)
 M:     "David S. Miller" <davem@davemloft.net>
+M:     Andreas Larsson <andreas@gaisler.com>
 L:     sparclinux@vger.kernel.org
 S:     Maintained
 Q:     http://patchwork.ozlabs.org/project/sparclinux/list/
@@ -24341,13 +24344,6 @@ T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/zonefs.git
 F:     Documentation/filesystems/zonefs.rst
 F:     fs/zonefs/
 
-ZPOOL COMPRESSED PAGE STORAGE API
-M:     Dan Streetman <ddstreet@ieee.org>
-L:     linux-mm@kvack.org
-S:     Maintained
-F:     include/linux/zpool.h
-F:     mm/zpool.c
-
 ZR36067 VIDEO FOR LINUX DRIVER
 M:     Corentin Labbe <clabbe@baylibre.com>
 L:     mjpeg-users@lists.sourceforge.net
@@ -24399,7 +24395,9 @@ M:      Nhat Pham <nphamcs@gmail.com>
 L:     linux-mm@kvack.org
 S:     Maintained
 F:     Documentation/admin-guide/mm/zswap.rst
+F:     include/linux/zpool.h
 F:     include/linux/zswap.h
+F:     mm/zpool.c
 F:     mm/zswap.c
 
 THE REST
index 9f9b76d3a4b7de903e02fb6723dd03e9b31867d6..113f7c762f0a0fe2557966dfd111ba1854fe8ed9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 6
 PATCHLEVEL = 8
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc2
 NAME = Hurr durr I'ma ninja sloth
 
 # *DOCUMENTATION*
@@ -294,15 +294,15 @@ may-sync-config   := 1
 single-build   :=
 
 ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
-       ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
+        ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
                need-config :=
-       endif
+        endif
 endif
 
 ifneq ($(filter $(no-sync-config-targets), $(MAKECMDGOALS)),)
-       ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),)
+        ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),)
                may-sync-config :=
-       endif
+        endif
 endif
 
 need-compiler := $(may-sync-config)
@@ -323,9 +323,9 @@ endif
 # We cannot build single targets and the others at the same time
 ifneq ($(filter $(single-targets), $(MAKECMDGOALS)),)
        single-build := 1
-       ifneq ($(filter-out $(single-targets), $(MAKECMDGOALS)),)
+        ifneq ($(filter-out $(single-targets), $(MAKECMDGOALS)),)
                mixed-build := 1
-       endif
+        endif
 endif
 
 # For "make -j clean all", "make -j mrproper defconfig all", etc.
@@ -1666,7 +1666,7 @@ help:
        @echo  '                       (sparse by default)'
        @echo  '  make C=2   [targets] Force check of all c source with $$CHECK'
        @echo  '  make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections'
-       @echo  '  make W=n   [targets] Enable extra build checks, n=1,2,3 where'
+       @echo  '  make W=n   [targets] Enable extra build checks, n=1,2,3,c,e where'
        @echo  '                1: warnings which may be relevant and do not occur too often'
        @echo  '                2: warnings which occur quite often but may still be relevant'
        @echo  '                3: more obscure warnings, can most likely be ignored'
index c91917b508736d1fa0d37d5bf3b1e4bf5550e211..a5af0edd3eb8f3b64e6e51bffb2ac491cb31bc26 100644 (file)
@@ -673,6 +673,7 @@ config SHADOW_CALL_STACK
        bool "Shadow Call Stack"
        depends on ARCH_SUPPORTS_SHADOW_CALL_STACK
        depends on DYNAMIC_FTRACE_WITH_ARGS || DYNAMIC_FTRACE_WITH_REGS || !FUNCTION_GRAPH_TRACER
+       depends on MMU
        help
          This option enables the compiler's Shadow Call Stack, which
          uses a shadow stack to protect function return addresses from
index e899de681f4752d4077b55a0cd4f8858c6e23df0..5be0e8fd2633c20e2d87abc843b53fca437942be 100644 (file)
@@ -45,8 +45,8 @@
                num-chipselects = <1>;
                cs-gpios = <&gpio0 ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
 
-               tpmdev@0 {
-                       compatible = "tcg,tpm_tis-spi";
+               tpm@0 {
+                       compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
                        spi-max-frequency = <33000000>;
                        reg = <0>;
                };
index a677c827e758fe2042fcf14a192832668e3ffbd0..5a8169bbda8792c76c1da960508c8a0c6bdd4b86 100644 (file)
@@ -80,8 +80,8 @@
                gpio-miso = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_HIGH>;
                num-chipselects = <1>;
 
-               tpmdev@0 {
-                       compatible = "tcg,tpm_tis-spi";
+               tpm@0 {
+                       compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
                        spi-max-frequency = <33000000>;
                        reg = <0>;
                };
index 3f6010ef2b86f264fe88935a737b3ce9c60d762b..213023bc5aec4144751c9e7bc8e3e05c156386c8 100644 (file)
        status = "okay";
 
        tpm: tpm@2e {
-               compatible = "tcg,tpm-tis-i2c";
+               compatible = "nuvoton,npct75x", "tcg,tpm-tis-i2c";
                reg = <0x2e>;
        };
 };
index 31590d3186a2e099e44c663c46a87975b60aae27..00e5887c926f181d57bebe6b0b781ad2f2e8a514 100644 (file)
@@ -35,8 +35,8 @@
                gpio-mosi = <&gpio0 ASPEED_GPIO(X, 4) GPIO_ACTIVE_HIGH>;
                gpio-miso = <&gpio0 ASPEED_GPIO(X, 5) GPIO_ACTIVE_HIGH>;
 
-               tpmdev@0 {
-                       compatible = "tcg,tpm_tis-spi";
+               tpm@0 {
+                       compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
                        spi-max-frequency = <33000000>;
                        reg = <0>;
                };
index 44cc4ff1d0df358ab66bb036d127175da1be74b6..d12fb44aeb140cfacf05a5b257d2106c79392279 100644 (file)
        tpm_tis: tpm@1 {
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_tpm>;
-               compatible = "tcg,tpm_tis-spi";
+               compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
                reg = <1>;
                spi-max-frequency = <20000000>;
                interrupt-parent = <&gpio5>;
index 3a723843d5626f6cc4b9ee2750968c01e46306db..9984b343cdf0cad1abd9e0d4d142ded838c47980 100644 (file)
         * TCG specification - Section 6.4.1 Clocking:
         * TPM shall support a SPI clock frequency range of 10-24 MHz.
         */
-       st33htph: tpm-tis@0 {
+       st33htph: tpm@0 {
                compatible = "st,st33htpm-spi", "tcg,tpm_tis-spi";
                reg = <0>;
                spi-max-frequency = <24000000>;
index d7954ff466b491b32acf6962ab5d64f4843f8157..e5254e32aa8fc326dfcabce33705a9b25e272052 100644 (file)
 };
 
 &fimd {
+       samsung,invert-vclk;
        status = "okay";
 };
 
index b8730aa52ce6fe521a1b531be42c4ef891c969b5..a59331aa58e55e3ef514fc06b5a36472c901dcd3 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&spi1_pins>;
 
-       tpm_spi_tis@0 {
+       tpm@0 {
                compatible = "tcg,tpm_tis-spi";
                reg = <0>;
                spi-max-frequency = <500000>;
index 47ecc4cff9d25b7752c94df9ab574ec52cbabd28..a88cdf91068713ebefc031f438b3b22a0247f943 100644 (file)
@@ -195,7 +195,7 @@ vdso_prepare: prepare0
        include/generated/vdso-offsets.h arch/arm64/kernel/vdso/vdso.so
 ifdef CONFIG_COMPAT_VDSO
        $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 \
-       include/generated/vdso32-offsets.h arch/arm64/kernel/vdso32/vdso.so
+       arch/arm64/kernel/vdso32/vdso.so
 endif
 endif
 
index 9747cb3fa03ac5c141b9bf660da3531ca2082def..d838e3a7af6e5ddda3751cc6f0bf4c73bccacc03 100644 (file)
                        #clock-cells = <1>;
                        clocks = <&cmu_top CLK_DOUT_CMU_MISC_BUS>,
                                 <&cmu_top CLK_DOUT_CMU_MISC_SSS>;
-                       clock-names = "dout_cmu_misc_bus", "dout_cmu_misc_sss";
+                       clock-names = "bus", "sss";
                };
 
                watchdog_cl0: watchdog@10060000 {
index 968f475b9a96c3c7334d670fd004ddcde08eed6f..27a902569e2a28434af3b6b15dcdb3a43f7a9606 100644 (file)
        };
 
        tpm: tpm@1 {
-               compatible = "tcg,tpm_tis-spi";
+               compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
                interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
                interrupt-parent = <&gpio2>;
                pinctrl-names = "default";
index 3f3f2a2c89cd504f22548178b0d718ed61d122fa..752caa38eb03bfd6831e61f857b517beb5bfe1a1 100644 (file)
@@ -89,7 +89,7 @@
        status = "okay";
 
        tpm@1 {
-               compatible = "tcg,tpm_tis-spi";
+               compatible = "atmel,attpm20p", "tcg,tpm_tis-spi";
                reg = <0x1>;
                spi-max-frequency = <36000000>;
        };
index 06fed93769966367b02c0a3d5f44f8264c080617..2aa6c1090fc7d7b81f7774354286c13a5463c06b 100644 (file)
        status = "okay";
 
        tpm@1 {
-               compatible = "tcg,tpm_tis-spi";
+               compatible = "atmel,attpm20p", "tcg,tpm_tis-spi";
                reg = <0x1>;
                spi-max-frequency = <36000000>;
        };
index feae77e038354c687d69904fdb5b577f32cfe26d..a08057410bdef5b3a2572cb5c5e2fe6ea35b5522 100644 (file)
        status = "okay";
 
        tpm: tpm@0 {
-               compatible = "infineon,slb9670";
+               compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
                reg = <0>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_tpm>;
index c24587c895e1f9734da4c4f4cf7becb697825f59..41c79d2ebdd6201dc10278204c064a4c01c71709 100644 (file)
        status = "okay";
 
        tpm@1 {
-               compatible = "tcg,tpm_tis-spi";
+               compatible = "atmel,attpm20p", "tcg,tpm_tis-spi";
                reg = <0x1>;
                spi-max-frequency = <36000000>;
        };
index 628ffba69862ad51f2072e88fc812b3a84e1b71c..d5c400b355af564123497cd1805e0b0ad56ded21 100644 (file)
        status = "okay";
 
        tpm@1 {
-               compatible = "tcg,tpm_tis-spi";
+               compatible = "atmel,attpm20p", "tcg,tpm_tis-spi";
                reg = <0x1>;
                spi-max-frequency = <36000000>;
        };
index 9caf7ca25444600a4a7979b3749d5175e32b0bbe..cae586cd45bdd59aa479e70bb290fc50b0392a3c 100644 (file)
        status = "okay";
 
        tpm@0 {
-               compatible = "tcg,tpm_tis-spi";
+               compatible = "atmel,attpm20p", "tcg,tpm_tis-spi";
                reg = <0x0>;
                spi-max-frequency = <36000000>;
        };
index 6376417e918c2083bb67c2f978d53602153d3cb9..d8cf1f27c3ec8a33b7ad527c1fc2b489747a2d84 100644 (file)
@@ -65,7 +65,7 @@
        status = "okay";
 
        tpm@0 {
-               compatible = "infineon,slb9670";
+               compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
                reg = <0>;
                spi-max-frequency = <43000000>;
        };
index 5506de83f61d423634511fba3f783f67a8987792..1b3396b1cee394659d0a77c104f05e1e7762569f 100644 (file)
        status = "okay";
        cs-gpios = <&pio 86 GPIO_ACTIVE_LOW>;
 
-       cr50@0 {
+       tpm@0 {
                compatible = "google,cr50";
                reg = <0>;
                spi-max-frequency = <1000000>;
index f2281250ac35da2514d73191cbcdb2e195afcbcb..d87aab8d7a79ed4ac8365b951f16c370b2efcc91 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&spi5_pins>;
 
-       cr50@0 {
+       tpm@0 {
                compatible = "google,cr50";
                reg = <0>;
                interrupts-extended = <&pio 171 IRQ_TYPE_EDGE_RISING>;
index 0f9cc042d9bf06b3445c2cb125435c823f3b26b4..1cba1d857c96ba06e3f257b8a15f20a99a9250ee 100644 (file)
@@ -70,7 +70,7 @@
 &spi0 {
        status = "okay";
 
-       cr50@0 {
+       tpm@0 {
                compatible = "google,cr50";
                reg = <0>;
                interrupt-parent = <&gpio0>;
index c5e7de60c12140c0dae9789cc338ef5f1b9fac3c..5846a11f0e848fc059446a47b57ff732b45e9f4c 100644 (file)
@@ -706,7 +706,7 @@ camera: &i2c7 {
 &spi2 {
        status = "okay";
 
-       cr50@0 {
+       tpm@0 {
                compatible = "google,cr50";
                reg = <0>;
                interrupt-parent = <&gpio1>;
index b4ae3210993273e8fd709b8f4d17a081bf39ff3d..4305995c8f82f416e6ce11280ac1dd19fbe25eec 100644 (file)
@@ -17,9 +17,6 @@
 #ifndef __ASSEMBLY__
 
 #include <generated/vdso-offsets.h>
-#ifdef CONFIG_COMPAT_VDSO
-#include <generated/vdso32-offsets.h>
-#endif
 
 #define VDSO_SYMBOL(base, name)                                                   \
 ({                                                                        \
index e5d03a7039b4bf9cce893b1ea39712eef3e2f4ad..467cb711727309eb991df38ece1af46b858e6178 100644 (file)
@@ -77,9 +77,9 @@ obj-$(CONFIG_UNWIND_PATCH_PAC_INTO_SCS)       += patch-scs.o
 # We need to prevent the SCS patching code from patching itself. Using
 # -mbranch-protection=none here to avoid the patchable PAC opcodes from being
 # generated triggers an issue with full LTO on Clang, which stops emitting PAC
-# instructions altogether. So instead, omit the unwind tables used by the
-# patching code, so it will not be able to locate its own PAC instructions.
-CFLAGS_patch-scs.o                     += -fno-asynchronous-unwind-tables -fno-unwind-tables
+# instructions altogether. So disable LTO as well for the compilation unit.
+CFLAGS_patch-scs.o                     += -mbranch-protection=none
+CFLAGS_REMOVE_patch-scs.o              += $(CC_FLAGS_LTO)
 
 # Force dependency (vdso*-wrap.S includes vdso.so through incbin)
 $(obj)/vdso-wrap.o: $(obj)/vdso/vdso.so
index 2266fcdff78a0740fcd72a5c8125d17938d88df4..f5f80fdce0fe7aa2ab3b14ce931999b954312162 100644 (file)
@@ -127,9 +127,6 @@ obj-vdso := $(c-obj-vdso) $(c-obj-vdso-gettimeofday) $(asm-obj-vdso)
 targets += vdso.lds
 CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
 
-include/generated/vdso32-offsets.h: $(obj)/vdso32.so.dbg FORCE
-       $(call if_changed,vdsosym)
-
 # Strip rule for vdso.so
 $(obj)/vdso.so: OBJCOPYFLAGS := -S
 $(obj)/vdso.so: $(obj)/vdso32.so.dbg FORCE
@@ -166,9 +163,3 @@ quiet_cmd_vdsoas = AS32    $@
 
 quiet_cmd_vdsomunge = MUNGE   $@
       cmd_vdsomunge = $(obj)/$(munge) $< $@
-
-# Generate vDSO offsets using helper script (borrowed from the 64-bit vDSO)
-gen-vdsosym := $(srctree)/$(src)/../vdso/gen_vdso_offsets.sh
-quiet_cmd_vdsosym = VDSOSYM $@
-# The AArch64 nm should be able to read an AArch32 binary
-      cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
index e71ceb88f29eecdbebe40c407c1a93e4cd433337..0cb4fdb8a9b5970dfefb24a34c82d1451ff27fa9 100644 (file)
@@ -60,7 +60,7 @@ int kvm_own_lsx(struct kvm_vcpu *vcpu);
 void kvm_save_lsx(struct loongarch_fpu *fpu);
 void kvm_restore_lsx(struct loongarch_fpu *fpu);
 #else
-static inline int kvm_own_lsx(struct kvm_vcpu *vcpu) { }
+static inline int kvm_own_lsx(struct kvm_vcpu *vcpu) { return -EINVAL; }
 static inline void kvm_save_lsx(struct loongarch_fpu *fpu) { }
 static inline void kvm_restore_lsx(struct loongarch_fpu *fpu) { }
 #endif
@@ -70,7 +70,7 @@ int kvm_own_lasx(struct kvm_vcpu *vcpu);
 void kvm_save_lasx(struct loongarch_fpu *fpu);
 void kvm_restore_lasx(struct loongarch_fpu *fpu);
 #else
-static inline int kvm_own_lasx(struct kvm_vcpu *vcpu) { }
+static inline int kvm_own_lasx(struct kvm_vcpu *vcpu) { return -EINVAL; }
 static inline void kvm_save_lasx(struct loongarch_fpu *fpu) { }
 static inline void kvm_restore_lasx(struct loongarch_fpu *fpu) { }
 #endif
index a16e3dbe9f09eb2fbf1b239b982b727330f7c233..2b49d30eb7c0185e043e462859e76a4ae64ecd67 100644 (file)
@@ -509,7 +509,6 @@ asmlinkage void start_secondary(void)
        sync_counter();
        cpu = raw_smp_processor_id();
        set_my_cpu_offset(per_cpu_offset(cpu));
-       rcutree_report_cpu_starting(cpu);
 
        cpu_probe();
        constant_clockevent_init();
index 915f175278931f26164c1b970663542cf0661a12..50a6acd7ffe4c94b986c5f7a9802420f090a7d79 100644 (file)
@@ -675,7 +675,7 @@ static bool fault_supports_huge_mapping(struct kvm_memory_slot *memslot,
  *
  * There are several ways to safely use this helper:
  *
- * - Check mmu_invalidate_retry_hva() after grabbing the mapping level, before
+ * - Check mmu_invalidate_retry_gfn() after grabbing the mapping level, before
  *   consuming it.  In this case, mmu_lock doesn't need to be held during the
  *   lookup, but it does need to be held while checking the MMU notifier.
  *
@@ -855,7 +855,7 @@ retry:
 
        /* Check if an invalidation has taken place since we got pfn */
        spin_lock(&kvm->mmu_lock);
-       if (mmu_invalidate_retry_hva(kvm, mmu_seq, hva)) {
+       if (mmu_invalidate_retry_gfn(kvm, mmu_seq, gfn)) {
                /*
                 * This can happen when mappings are changed asynchronously, but
                 * also synchronously if a COW is triggered by
index 2c0a411f23aa778bb62160bd511252736fc987be..0b95d32b30c94704a0108fdffcae68c148403ce7 100644 (file)
@@ -284,12 +284,16 @@ static void setup_tlb_handler(int cpu)
                set_handler(EXCCODE_TLBNR * VECSIZE, handle_tlb_protect, VECSIZE);
                set_handler(EXCCODE_TLBNX * VECSIZE, handle_tlb_protect, VECSIZE);
                set_handler(EXCCODE_TLBPE * VECSIZE, handle_tlb_protect, VECSIZE);
-       }
+       } else {
+               int vec_sz __maybe_unused;
+               void *addr __maybe_unused;
+               struct page *page __maybe_unused;
+
+               /* Avoid lockdep warning */
+               rcutree_report_cpu_starting(cpu);
+
 #ifdef CONFIG_NUMA
-       else {
-               void *addr;
-               struct page *page;
-               const int vec_sz = sizeof(exception_handlers);
+               vec_sz = sizeof(exception_handlers);
 
                if (pcpu_handlers[cpu])
                        return;
@@ -305,8 +309,8 @@ static void setup_tlb_handler(int cpu)
                csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_EENTRY);
                csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_MERRENTRY);
                csr_write64(pcpu_handlers[cpu] + 80*VECSIZE, LOONGARCH_CSR_TLBRENTRY);
-       }
 #endif
+       }
 }
 
 void tlb_init(int cpu)
index 43e39040d3ac6cd38a4bd4fc3dc04e03d5c71bf5..76ef1a67c3611bbcd864d27fe59127c4c27f038a 100644 (file)
 KBUILD_DEFCONFIG := multi_defconfig
 
 ifdef cross_compiling
-       ifeq ($(CROSS_COMPILE),)
+        ifeq ($(CROSS_COMPILE),)
                CROSS_COMPILE := $(call cc-cross-prefix, \
                        m68k-linux-gnu- m68k-linux- m68k-unknown-linux-gnu-)
-       endif
+        endif
 endif
 
 #
index b13d8adf3be47dbfd6f65e1e63ee3217feafe04b..20d30f6265cdce2a915ddffc52d0bb67e6e0edac 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/string.h>
 
 #include <asm/bootinfo.h>
+#include <prom.h>
 
 int prom_argc;
 char **prom_argv;
index 2388d68786f4a7c40dcadfed78fd8ecfc91f4896..a7a6d31a7a4148ada6ad340d0723ef8c7a73f0be 100644 (file)
 #include <linux/mm.h>
 #include <linux/dma-map-ops.h> /* for dma_default_coherent */
 
+#include <asm/bootinfo.h>
 #include <asm/mipsregs.h>
 
 #include <au1000.h>
 
-extern void __init board_setup(void);
-extern void __init alchemy_set_lpj(void);
-
 static bool alchemy_dma_coherent(void)
 {
        switch (alchemy_get_cputype()) {
index 01aff80a59672dee1b675c3625aecb6f70eb52b9..99f321b6e417bd4250ab7cec31ae74ad2d396ec3 100644 (file)
@@ -702,7 +702,7 @@ static struct ssb_sprom bcm63xx_sprom = {
        .boardflags_hi          = 0x0000,
 };
 
-int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
+static int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
 {
        if (bus->bustype == SSB_BUSTYPE_PCI) {
                memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom));
index d277b4dc6c688eb394544b556e0941a54654c1b9..f94151f7c96fe1d988cd3d88f8451bbdf012955c 100644 (file)
@@ -26,7 +26,7 @@ static struct platform_device bcm63xx_rng_device = {
        .resource       = rng_resources,
 };
 
-int __init bcm63xx_rng_register(void)
+static int __init bcm63xx_rng_register(void)
 {
        if (!BCMCPU_IS_6368())
                return -ENODEV;
index 3bc7f3bfc9ad5c5e45737bcf1510bfcd5b5483e7..5d6bf0445b299cf0e91a4f7992f134e5648ca1c2 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <bcm63xx_cpu.h>
+#include <bcm63xx_dev_uart.h>
 
 static struct resource uart0_resources[] = {
        {
index 42130914a3c210993c07d971449a424d40775060..302bf7ed5ad5abfaa6cb94e4a4e0dcdf1ffbceb1 100644 (file)
@@ -34,7 +34,7 @@ static struct platform_device bcm63xx_wdt_device = {
        },
 };
 
-int __init bcm63xx_wdt_register(void)
+static int __init bcm63xx_wdt_register(void)
 {
        wdt_resources[0].start = bcm63xx_regset_address(RSET_WDT);
        wdt_resources[0].end = wdt_resources[0].start;
index 2548013442f6d95bdda071f89cc112d97d8a0d0a..6240a8f88ea366b5d440f6de3416191dead812b8 100644 (file)
@@ -72,7 +72,7 @@ static inline int enable_irq_for_cpu(int cpu, struct irq_data *d,
  */
 
 #define BUILD_IPIC_INTERNAL(width)                                     \
-void __dispatch_internal_##width(int cpu)                              \
+static void __dispatch_internal_##width(int cpu)                       \
 {                                                                      \
        u32 pending[width / 32];                                        \
        unsigned int src, tgt;                                          \
index d811e3e03f819a5005a480d56d5aee5a090fcc3c..c13ddb544a23bf0ebfd6bd627c9ed022a44cda0e 100644 (file)
@@ -159,7 +159,7 @@ void __init plat_mem_setup(void)
        board_setup();
 }
 
-int __init bcm63xx_register_devices(void)
+static int __init bcm63xx_register_devices(void)
 {
        /* register gpiochip */
        bcm63xx_gpio_init();
index a86065854c0c8c6c92254c4d7746fda8e6801250..74b83807df30a7be13f1f9466753b2560ce9b50b 100644 (file)
@@ -178,7 +178,7 @@ int bcm63xx_timer_set(int id, int monotonic, unsigned int countdown_us)
 
 EXPORT_SYMBOL(bcm63xx_timer_set);
 
-int bcm63xx_timer_init(void)
+static int bcm63xx_timer_init(void)
 {
        int ret, irq;
        u32 reg;
index 2e099d55a564a6ecf3dc347ace84ad25e4278dd9..9a266bf7833993b5facbdb63c97e555ad4d9ce27 100644 (file)
@@ -23,9 +23,6 @@
 
 #include <cobalt.h>
 
-extern void cobalt_machine_restart(char *command);
-extern void cobalt_machine_halt(void);
-
 const char *get_system_type(void)
 {
        switch (cobalt_board_id) {
index 66188739f54d20a41ce18acb0a88a4fdf16e8718..fb78e6fd5de4804e221fba63bceeb4dcd4a492a9 100644 (file)
@@ -37,7 +37,7 @@ static unsigned int nr_prom_mem __initdata;
  */
 #define ARC_PAGE_SHIFT 12
 
-struct linux_mdesc * __init ArcGetMemoryDescriptor(struct linux_mdesc *Current)
+static struct linux_mdesc * __init ArcGetMemoryDescriptor(struct linux_mdesc *Current)
 {
        return (struct linux_mdesc *) ARC_CALL1(get_mdesc, Current);
 }
index a7eec3364a64abb60f1dae67ad26c80738878533..41546777902ba0fe25af0f442c688169f9220b48 100644 (file)
 
 #include <asm/cpu.h>
 
+void alchemy_set_lpj(void);
+void board_setup(void);
+
 /* helpers to access the SYS_* registers */
 static inline unsigned long alchemy_rdsys(int regofs)
 {
index 5b9fce73f11d1301fa5724049bfd9f8625ea7061..97f9d5e9446d22e1371b1c9f6fe09d59610d27ed 100644 (file)
@@ -19,4 +19,7 @@ extern int cobalt_board_id;
 #define COBALT_BRD_ID_QUBE2    0x5
 #define COBALT_BRD_ID_RAQ2     0x6
 
+void cobalt_machine_halt(void);
+void cobalt_machine_restart(char *command);
+
 #endif /* __ASM_COBALT_H */
index 5582a4ca1e9e36ad5dac4d23caa4d6c4bfb11a5d..7aa2c2360ff60219bb8fb9f03a8a528edf7f53a1 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <asm/cpu-features.h>
 #include <asm/cpu-info.h>
+#include <asm/fpu.h>
 
 #ifdef CONFIG_MIPS_FP_SUPPORT
 
@@ -309,6 +310,11 @@ void mips_set_personality_nan(struct arch_elf_state *state)
        struct cpuinfo_mips *c = &boot_cpu_data;
        struct task_struct *t = current;
 
+       /* Do this early so t->thread.fpu.fcr31 won't be clobbered in case
+        * we are preempted before the lose_fpu(0) in start_thread.
+        */
+       lose_fpu(0);
+
        t->thread.fpu.fcr31 = c->fpu_csr31;
        switch (state->nan_2008) {
        case 0:
index dec6878b35f627089226618ff4dc4628855c8eb4..a1c1cb5de91321468f338d41a01df2f40efaf293 100644 (file)
@@ -2007,7 +2007,13 @@ unsigned long vi_handlers[64];
 
 void reserve_exception_space(phys_addr_t addr, unsigned long size)
 {
-       memblock_reserve(addr, size);
+       /*
+        * reserve exception space on CPUs other than CPU0
+        * is too late, since memblock is unavailable when APs
+        * up
+        */
+       if (smp_processor_id() == 0)
+               memblock_reserve(addr, size);
 }
 
 void __init *set_except_vector(int n, void *addr)
index a3cf293658581ed6a599da2b870f3c10c67a6be1..0c45767eacf67429ea3910628a2f44c219a4da34 100644 (file)
@@ -108,10 +108,9 @@ void __init prom_init(void)
        prom_init_cmdline();
 
 #if defined(CONFIG_MIPS_MT_SMP)
-       if (cpu_has_mipsmt) {
-               lantiq_smp_ops = vsmp_smp_ops;
+       lantiq_smp_ops = vsmp_smp_ops;
+       if (cpu_has_mipsmt)
                lantiq_smp_ops.init_secondary = lantiq_init_secondary;
-               register_smp_ops(&lantiq_smp_ops);
-       }
+       register_smp_ops(&lantiq_smp_ops);
 #endif
 }
index f25caa6aa9d306e84d719e97ea54f7b8faa449c1..553142c1f14fe2261d963b3784f3ed9e6c086cd2 100644 (file)
@@ -103,6 +103,9 @@ void __init szmem(unsigned int node)
        if (loongson_sysconf.vgabios_addr)
                memblock_reserve(virt_to_phys((void *)loongson_sysconf.vgabios_addr),
                                SZ_256K);
+       /* set nid for reserved memory */
+       memblock_set_node((u64)node << 44, (u64)(node + 1) << 44,
+                       &memblock.reserved, node);
 }
 
 #ifndef CONFIG_NUMA
index 8f61e93c0c5bcf07134cc22a06913c57e5140af4..68dafd6d3e2571f615e9c9e7d9b2c895de80468a 100644 (file)
@@ -132,6 +132,8 @@ static void __init node_mem_init(unsigned int node)
 
                /* Reserve pfn range 0~node[0]->node_start_pfn */
                memblock_reserve(0, PAGE_SIZE * start_pfn);
+               /* set nid for reserved memory on node 0 */
+               memblock_set_node(0, 1ULL << 44, &memblock.reserved, 0);
        }
 }
 
index 27c14ede191eb7b1353e3a2cedd6d9d80bc2b385..9877fcc512b1578731fb6235a35256a61b172afb 100644 (file)
@@ -5,7 +5,7 @@
 
 obj-y  := ip27-berr.o ip27-irq.o ip27-init.o ip27-klconfig.o \
           ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-reset.o ip27-timer.o \
-          ip27-hubio.o ip27-xtalk.o
+          ip27-xtalk.o
 
 obj-$(CONFIG_EARLY_PRINTK)     += ip27-console.o
 obj-$(CONFIG_SMP)              += ip27-smp.o
index 923a63a51cda39482c227936c17f828ceae3227b..9eb497cb5d525c74e775ca741bd4ec664209280b 100644 (file)
@@ -22,6 +22,8 @@
 #include <asm/traps.h>
 #include <linux/uaccess.h>
 
+#include "ip27-common.h"
+
 static void dump_hub_information(unsigned long errst0, unsigned long errst1)
 {
        static char *err_type[2][8] = {
@@ -57,7 +59,7 @@ static void dump_hub_information(unsigned long errst0, unsigned long errst1)
               [st0.pi_stat0_fmt.s0_err_type] ? : "invalid");
 }
 
-int ip27_be_handler(struct pt_regs *regs, int is_fixup)
+static int ip27_be_handler(struct pt_regs *regs, int is_fixup)
 {
        unsigned long errst0, errst1;
        int data = regs->cp0_cause & 4;
index ed008a08464c208cc1944cfbd6fe5de31e14fee4..a0059fa13934539af5fb616120f66b77054a2219 100644 (file)
@@ -10,6 +10,7 @@ extern void hub_rt_clock_event_init(void);
 extern void hub_rtc_init(nasid_t nasid);
 extern void install_cpu_nmi_handler(int slice);
 extern void install_ipi(void);
+extern void ip27_be_init(void);
 extern void ip27_reboot_setup(void);
 extern const struct plat_smp_ops ip27_smp_ops;
 extern unsigned long node_getfirstfree(nasid_t nasid);
@@ -17,4 +18,5 @@ extern void per_cpu_init(void);
 extern void replicate_kernel_text(void);
 extern void setup_replication_mask(void);
 
+
 #endif /* __IP27_COMMON_H */
diff --git a/arch/mips/sgi-ip27/ip27-hubio.c b/arch/mips/sgi-ip27/ip27-hubio.c
deleted file mode 100644 (file)
index c57f0d8..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc.
- * Copyright (C) 2004 Christoph Hellwig.
- *
- * Support functions for the HUB ASIC - mostly PIO mapping related.
- */
-
-#include <linux/bitops.h>
-#include <linux/string.h>
-#include <linux/mmzone.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/agent.h>
-#include <asm/sn/io.h>
-#include <asm/xtalk/xtalk.h>
-
-
-static int force_fire_and_forget = 1;
-
-/**
- * hub_pio_map -  establish a HUB PIO mapping
- *
- * @nasid:     nasid to perform PIO mapping on
- * @widget:    widget ID to perform PIO mapping for
- * @xtalk_addr: xtalk_address that needs to be mapped
- * @size:      size of the PIO mapping
- *
- **/
-unsigned long hub_pio_map(nasid_t nasid, xwidgetnum_t widget,
-                         unsigned long xtalk_addr, size_t size)
-{
-       unsigned i;
-
-       /* use small-window mapping if possible */
-       if ((xtalk_addr % SWIN_SIZE) + size <= SWIN_SIZE)
-               return NODE_SWIN_BASE(nasid, widget) + (xtalk_addr % SWIN_SIZE);
-
-       if ((xtalk_addr % BWIN_SIZE) + size > BWIN_SIZE) {
-               printk(KERN_WARNING "PIO mapping at hub %d widget %d addr 0x%lx"
-                               " too big (%ld)\n",
-                               nasid, widget, xtalk_addr, size);
-               return 0;
-       }
-
-       xtalk_addr &= ~(BWIN_SIZE-1);
-       for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) {
-               if (test_and_set_bit(i, hub_data(nasid)->h_bigwin_used))
-                       continue;
-
-               /*
-                * The code below does a PIO write to setup an ITTE entry.
-                *
-                * We need to prevent other CPUs from seeing our updated
-                * memory shadow of the ITTE (in the piomap) until the ITTE
-                * entry is actually set up; otherwise, another CPU might
-                * attempt a PIO prematurely.
-                *
-                * Also, the only way we can know that an entry has been
-                * received  by the hub and can be used by future PIO reads/
-                * writes is by reading back the ITTE entry after writing it.
-                *
-                * For these two reasons, we PIO read back the ITTE entry
-                * after we write it.
-                */
-               IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr);
-               __raw_readq(IIO_ITTE_GET(nasid, i));
-
-               return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE);
-       }
-
-       printk(KERN_WARNING "unable to establish PIO mapping for at"
-                       " hub %d widget %d addr 0x%lx\n",
-                       nasid, widget, xtalk_addr);
-       return 0;
-}
-
-
-/*
- * hub_setup_prb(nasid, prbnum, credits, conveyor)
- *
- *     Put a PRB into fire-and-forget mode if conveyor isn't set.  Otherwise,
- *     put it into conveyor belt mode with the specified number of credits.
- */
-static void hub_setup_prb(nasid_t nasid, int prbnum, int credits)
-{
-       union iprb_u prb;
-       int prb_offset;
-
-       /*
-        * Get the current register value.
-        */
-       prb_offset = IIO_IOPRB(prbnum);
-       prb.iprb_regval = REMOTE_HUB_L(nasid, prb_offset);
-
-       /*
-        * Clear out some fields.
-        */
-       prb.iprb_ovflow = 1;
-       prb.iprb_bnakctr = 0;
-       prb.iprb_anakctr = 0;
-
-       /*
-        * Enable or disable fire-and-forget mode.
-        */
-       prb.iprb_ff = force_fire_and_forget ? 1 : 0;
-
-       /*
-        * Set the appropriate number of PIO credits for the widget.
-        */
-       prb.iprb_xtalkctr = credits;
-
-       /*
-        * Store the new value to the register.
-        */
-       REMOTE_HUB_S(nasid, prb_offset, prb.iprb_regval);
-}
-
-/**
- * hub_set_piomode  -  set pio mode for a given hub
- *
- * @nasid:     physical node ID for the hub in question
- *
- * Put the hub into either "PIO conveyor belt" mode or "fire-and-forget" mode.
- * To do this, we have to make absolutely sure that no PIOs are in progress
- * so we turn off access to all widgets for the duration of the function.
- *
- * XXX - This code should really check what kind of widget we're talking
- * to. Bridges can only handle three requests, but XG will do more.
- * How many can crossbow handle to widget 0?  We're assuming 1.
- *
- * XXX - There is a bug in the crossbow that link reset PIOs do not
- * return write responses.  The easiest solution to this problem is to
- * leave widget 0 (xbow) in fire-and-forget mode at all times. This
- * only affects pio's to xbow registers, which should be rare.
- **/
-static void hub_set_piomode(nasid_t nasid)
-{
-       u64 ii_iowa;
-       union hubii_wcr_u ii_wcr;
-       unsigned i;
-
-       ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS);
-       REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0);
-
-       ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR);
-
-       if (ii_wcr.iwcr_dir_con) {
-               /*
-                * Assume a bridge here.
-                */
-               hub_setup_prb(nasid, 0, 3);
-       } else {
-               /*
-                * Assume a crossbow here.
-                */
-               hub_setup_prb(nasid, 0, 1);
-       }
-
-       /*
-        * XXX - Here's where we should take the widget type into
-        * when account assigning credits.
-        */
-       for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++)
-               hub_setup_prb(nasid, i, 3);
-
-       REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa);
-}
-
-/*
- * hub_pio_init         -  PIO-related hub initialization
- *
- * @hub:       hubinfo structure for our hub
- */
-void hub_pio_init(nasid_t nasid)
-{
-       unsigned i;
-
-       /* initialize big window piomaps for this hub */
-       bitmap_zero(hub_data(nasid)->h_bigwin_used, HUB_NUM_BIG_WINDOW);
-       for (i = 0; i < HUB_NUM_BIG_WINDOW; i++)
-               IIO_ITTE_DISABLE(nasid, i);
-
-       hub_set_piomode(nasid);
-}
index a0dd3bd2b81b359491b447917486890ebc18fd4b..8f5299b269e7e7d1b104d6fa4616de4f7fdfc34d 100644 (file)
@@ -23,6 +23,8 @@
 #include <asm/sn/intr.h>
 #include <asm/sn/irq_alloc.h>
 
+#include "ip27-common.h"
+
 struct hub_irq_data {
        u64     *irq_mask[2];
        cpuid_t cpu;
index f79c4839371661237141b866d89743a101411c53..b8ca94cfb4fef34b42f9e5307e7dcfc09ef8a6d2 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/sections.h>
+#include <asm/sgialib.h>
 
 #include <asm/sn/arch.h>
 #include <asm/sn/agent.h>
index 84889b57d5ff684e32bc2a1897583a0f4770853e..fc2816398d0cf04a48c1f704ade54a65b97e15f8 100644 (file)
@@ -11,6 +11,8 @@
 #include <asm/sn/arch.h>
 #include <asm/sn/agent.h>
 
+#include "ip27-common.h"
+
 #if 0
 #define NODE_NUM_CPUS(n)       CNODE_NUM_CPUS(n)
 #else
 typedef unsigned long machreg_t;
 
 static arch_spinlock_t nmi_lock = __ARCH_SPIN_LOCK_UNLOCKED;
-
-/*
- * Let's see what else we need to do here. Set up sp, gp?
- */
-void nmi_dump(void)
-{
-       void cont_nmi_dump(void);
-
-       cont_nmi_dump();
-}
+static void nmi_dump(void);
 
 void install_cpu_nmi_handler(int slice)
 {
@@ -53,7 +46,7 @@ void install_cpu_nmi_handler(int slice)
  * into the eframe format for the node under consideration.
  */
 
-void nmi_cpu_eframe_save(nasid_t nasid, int slice)
+static void nmi_cpu_eframe_save(nasid_t nasid, int slice)
 {
        struct reg_struct *nr;
        int             i;
@@ -129,7 +122,7 @@ void nmi_cpu_eframe_save(nasid_t nasid, int slice)
        pr_emerg("\n");
 }
 
-void nmi_dump_hub_irq(nasid_t nasid, int slice)
+static void nmi_dump_hub_irq(nasid_t nasid, int slice)
 {
        u64 mask0, mask1, pend0, pend1;
 
@@ -153,7 +146,7 @@ void nmi_dump_hub_irq(nasid_t nasid, int slice)
  * Copy the cpu registers which have been saved in the IP27prom format
  * into the eframe format for the node under consideration.
  */
-void nmi_node_eframe_save(nasid_t nasid)
+static void nmi_node_eframe_save(nasid_t nasid)
 {
        int slice;
 
@@ -170,8 +163,7 @@ void nmi_node_eframe_save(nasid_t nasid)
 /*
  * Save the nmi cpu registers for all cpus in the system.
  */
-void
-nmi_eframes_save(void)
+static void nmi_eframes_save(void)
 {
        nasid_t nasid;
 
@@ -179,8 +171,7 @@ nmi_eframes_save(void)
                nmi_node_eframe_save(nasid);
 }
 
-void
-cont_nmi_dump(void)
+static void nmi_dump(void)
 {
 #ifndef REAL_NMI_SIGNAL
        static atomic_t nmied_cpus = ATOMIC_INIT(0);
index b91f8c4fdc786011172f8111e7e0dfc3e04705e1..7c6dcf6e73f701c68595bd3b26677ff8d667b56a 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/io.h>
 
 #include <asm/sn/ioc3.h>
+#include <asm/setup.h>
 
 static inline struct ioc3_uartregs *console_uart(void)
 {
index 75a34684e7045977a89faa54b1ec740eb13af5ff..e8547636a7482a4a4c08738bccf7f246b8061d26 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/percpu.h>
 #include <linux/memblock.h>
 
+#include <asm/bootinfo.h>
 #include <asm/smp-ops.h>
 #include <asm/sgialib.h>
 #include <asm/time.h>
index a8e0c776ca6c628faa0b0ef4828de3fb4e9f51a2..b8a0e4cfa9ce882dcba3c0dc4e911716d47a457b 100644 (file)
@@ -18,6 +18,8 @@
 #include <asm/ip32/crime.h>
 #include <asm/ip32/mace.h>
 
+#include "ip32-common.h"
+
 struct sgi_crime __iomem *crime;
 struct sgi_mace __iomem *mace;
 
@@ -39,7 +41,7 @@ void __init crime_init(void)
               id, rev, field, (unsigned long) CRIME_BASE);
 }
 
-irqreturn_t crime_memerr_intr(unsigned int irq, void *dev_id)
+irqreturn_t crime_memerr_intr(int irq, void *dev_id)
 {
        unsigned long stat, addr;
        int fatal = 0;
@@ -90,7 +92,7 @@ irqreturn_t crime_memerr_intr(unsigned int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-irqreturn_t crime_cpuerr_intr(unsigned int irq, void *dev_id)
+irqreturn_t crime_cpuerr_intr(int irq, void *dev_id)
 {
        unsigned long stat = crime->cpu_error_stat & CRIME_CPU_ERROR_MASK;
        unsigned long addr = crime->cpu_error_addr & CRIME_CPU_ERROR_ADDR_MASK;
index 478b63b4c808f35456bb0b4ba69de4450edb7404..7cbc27941f928399c3cd5166741f5495c55b7eaa 100644 (file)
@@ -18,6 +18,8 @@
 #include <asm/ptrace.h>
 #include <asm/tlbdebug.h>
 
+#include "ip32-common.h"
+
 static int ip32_be_handler(struct pt_regs *regs, int is_fixup)
 {
        int data = regs->cp0_cause & 4;
diff --git a/arch/mips/sgi-ip32/ip32-common.h b/arch/mips/sgi-ip32/ip32-common.h
new file mode 100644 (file)
index 0000000..cfc0225
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __IP32_COMMON_H
+#define __IP32_COMMON_H
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+void __init crime_init(void);
+irqreturn_t crime_memerr_intr(int irq, void *dev_id);
+irqreturn_t crime_cpuerr_intr(int irq, void *dev_id);
+void __init ip32_be_init(void);
+void ip32_prepare_poweroff(void);
+
+#endif /* __IP32_COMMON_H */
index e21ea1de05e31953ce51f04122512cd27b2d9c46..29d04468a06b8f5c4004a25a18ad94dcb08013f9 100644 (file)
@@ -28,6 +28,8 @@
 #include <asm/ip32/mace.h>
 #include <asm/ip32/ip32_ints.h>
 
+#include "ip32-common.h"
+
 /* issue a PIO read to make sure no PIO writes are pending */
 static inline void flush_crime_bus(void)
 {
@@ -107,10 +109,6 @@ static inline void flush_mace_bus(void)
  * is quite different anyway.
  */
 
-/* Some initial interrupts to set up */
-extern irqreturn_t crime_memerr_intr(int irq, void *dev_id);
-extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id);
-
 /*
  * This is for pure CRIME interrupts - ie not MACE.  The advantage?
  * We get to split the register in half and do faster lookups.
index 3fc8d0a0bdfa45cc8b3aead0bd31144a874e17bb..5fee33744f674bdbdd777ba63b7d15f92d661a99 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/ip32/crime.h>
 #include <asm/bootinfo.h>
 #include <asm/page.h>
+#include <asm/sgialib.h>
 
 extern void crime_init(void);
 
index 18d1c115cd534a2d78a1ee5f8b53681e46fc021f..6bdc1421cda46cad28b5b253bf53703005ed09bf 100644 (file)
@@ -29,6 +29,8 @@
 #include <asm/ip32/crime.h>
 #include <asm/ip32/ip32_ints.h>
 
+#include "ip32-common.h"
+
 #define POWERDOWN_TIMEOUT      120
 /*
  * Blink frequency during reboot grace period and when panicked.
index 8019dae1721a811cef26fb75430a2b3ca151d6dd..aeb0805aae57bacfef7b95877042a6dc476a14a5 100644 (file)
@@ -26,8 +26,7 @@
 #include <asm/ip32/mace.h>
 #include <asm/ip32/ip32_ints.h>
 
-extern void ip32_be_init(void);
-extern void crime_init(void);
+#include "ip32-common.h"
 
 #ifdef CONFIG_SGI_O2MACE_ETH
 /*
index d14ccc948a29b920854b6c750febffac625619fd..5c845e8d59d92f8cd3594fccf1476503d8957149 100644 (file)
@@ -25,7 +25,6 @@ config PARISC
        select RTC_DRV_GENERIC
        select INIT_ALL_POSSIBLE
        select BUG
-       select BUILDTIME_TABLE_SORT
        select HAVE_KERNEL_UNCOMPRESSED
        select HAVE_PCI
        select HAVE_PERF_EVENTS
index 920db57b6b4cc866018c05dd00ca49142c7f949c..7486b3b3059491490f5626224f9177eb5efd6cdb 100644 (file)
@@ -50,12 +50,12 @@ export CROSS32CC
 
 # Set default cross compiler for kernel build
 ifdef cross_compiling
-       ifeq ($(CROSS_COMPILE),)
+        ifeq ($(CROSS_COMPILE),)
                CC_SUFFIXES = linux linux-gnu unknown-linux-gnu suse-linux
                CROSS_COMPILE := $(call cc-cross-prefix, \
                        $(foreach a,$(CC_ARCHES), \
                        $(foreach s,$(CC_SUFFIXES),$(a)-$(s)-)))
-       endif
+        endif
 endif
 
 ifdef CONFIG_DYNAMIC_FTRACE
index 74d17d7e759da9dfa89aa1a504b94de4554db16d..5937d5edaba1eac5a0c4e4b055c3e77fcbe3bf62 100644 (file)
        .section __ex_table,"aw"                        !       \
        .align 4                                        !       \
        .word (fault_addr - .), (except_addr - .)       !       \
+       or %r0,%r0,%r0                                  !       \
        .previous
 
 
diff --git a/arch/parisc/include/asm/extable.h b/arch/parisc/include/asm/extable.h
new file mode 100644 (file)
index 0000000..4ea23e3
--- /dev/null
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PARISC_EXTABLE_H
+#define __PARISC_EXTABLE_H
+
+#include <asm/ptrace.h>
+#include <linux/compiler.h>
+
+/*
+ * The exception table consists of three addresses:
+ *
+ * - A relative address to the instruction that is allowed to fault.
+ * - A relative address at which the program should continue (fixup routine)
+ * - An asm statement which specifies which CPU register will
+ *   receive -EFAULT when an exception happens if the lowest bit in
+ *   the fixup address is set.
+ *
+ * Note: The register specified in the err_opcode instruction will be
+ * modified at runtime if a fault happens. Register %r0 will be ignored.
+ *
+ * Since relative addresses are used, 32bit values are sufficient even on
+ * 64bit kernel.
+ */
+
+struct pt_regs;
+int fixup_exception(struct pt_regs *regs);
+
+#define ARCH_HAS_RELATIVE_EXTABLE
+struct exception_table_entry {
+       int insn;       /* relative address of insn that is allowed to fault. */
+       int fixup;      /* relative address of fixup routine */
+       int err_opcode; /* sample opcode with register which holds error code */
+};
+
+#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr, opcode )\
+       ".section __ex_table,\"aw\"\n"                     \
+       ".align 4\n"                                       \
+       ".word (" #fault_addr " - .), (" #except_addr " - .)\n" \
+       opcode "\n"                                        \
+       ".previous\n"
+
+/*
+ * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry
+ * (with lowest bit set) for which the fault handler in fixup_exception() will
+ * load -EFAULT on fault into the register specified by the err_opcode instruction,
+ * and zeroes the target register in case of a read fault in get_user().
+ */
+#define ASM_EXCEPTIONTABLE_VAR(__err_var)              \
+       int __err_var = 0
+#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr, register )\
+       ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1, "or %%r0,%%r0," register)
+
+static inline void swap_ex_entry_fixup(struct exception_table_entry *a,
+                                      struct exception_table_entry *b,
+                                      struct exception_table_entry tmp,
+                                      int delta)
+{
+       a->fixup = b->fixup + delta;
+       b->fixup = tmp.fixup - delta;
+       a->err_opcode = b->err_opcode;
+       b->err_opcode = tmp.err_opcode;
+}
+#define swap_ex_entry_fixup swap_ex_entry_fixup
+
+#endif
index c822bd0c0e3c6ccb86b4190d15500589c70f353a..51f40eaf7780659263f37b7c10fa7bd4ecf4ced7 100644 (file)
@@ -8,7 +8,8 @@
                "copy %%r0,%0\n"                        \
                "8:\tlpa %%r0(%1),%0\n"                 \
                "9:\n"                                  \
-               ASM_EXCEPTIONTABLE_ENTRY(8b, 9b)        \
+               ASM_EXCEPTIONTABLE_ENTRY(8b, 9b,        \
+                               "or %%r0,%%r0,%%r0")    \
                : "=&r" (pa)                            \
                : "r" (va)                              \
                : "memory"                              \
@@ -22,7 +23,8 @@
                "copy %%r0,%0\n"                        \
                "8:\tlpa %%r0(%%sr3,%1),%0\n"           \
                "9:\n"                                  \
-               ASM_EXCEPTIONTABLE_ENTRY(8b, 9b)        \
+               ASM_EXCEPTIONTABLE_ENTRY(8b, 9b,        \
+                               "or %%r0,%%r0,%%r0")    \
                : "=&r" (pa)                            \
                : "r" (va)                              \
                : "memory"                              \
index 4165079898d9e7af239a31a1bc77821e6081706a..88d0ae5769dde54e29176e286da359eb6a54e7bf 100644 (file)
@@ -7,6 +7,7 @@
  */
 #include <asm/page.h>
 #include <asm/cache.h>
+#include <asm/extable.h>
 
 #include <linux/bug.h>
 #include <linux/string.h>
 #define STD_USER(sr, x, ptr)   __put_user_asm(sr, "std", x, ptr)
 #endif
 
-/*
- * The exception table contains two values: the first is the relative offset to
- * the address of the instruction that is allowed to fault, and the second is
- * the relative offset to the address of the fixup routine. Since relative
- * addresses are used, 32bit values are sufficient even on 64bit kernel.
- */
-
-#define ARCH_HAS_RELATIVE_EXTABLE
-struct exception_table_entry {
-       int insn;       /* relative address of insn that is allowed to fault. */
-       int fixup;      /* relative address of fixup routine */
-};
-
-#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\
-       ".section __ex_table,\"aw\"\n"                     \
-       ".align 4\n"                                       \
-       ".word (" #fault_addr " - .), (" #except_addr " - .)\n\t" \
-       ".previous\n"
-
-/*
- * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry
- * (with lowest bit set) for which the fault handler in fixup_exception() will
- * load -EFAULT into %r29 for a read or write fault, and zeroes the target
- * register in case of a read fault in get_user().
- */
-#define ASM_EXCEPTIONTABLE_REG 29
-#define ASM_EXCEPTIONTABLE_VAR(__variable)             \
-       register long __variable __asm__ ("r29") = 0
-#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr )\
-       ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1)
-
 #define __get_user_internal(sr, val, ptr)              \
 ({                                                     \
        ASM_EXCEPTIONTABLE_VAR(__gu_err);               \
@@ -83,7 +53,7 @@ struct exception_table_entry {
                                                        \
        __asm__("1: " ldx " 0(%%sr%2,%3),%0\n"          \
                "9:\n"                                  \
-               ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
+               ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%1")   \
                : "=r"(__gu_val), "+r"(__gu_err)        \
                : "i"(sr), "r"(ptr));                   \
                                                        \
@@ -115,8 +85,8 @@ struct exception_table_entry {
                "1: ldw 0(%%sr%2,%3),%0\n"              \
                "2: ldw 4(%%sr%2,%3),%R0\n"             \
                "9:\n"                                  \
-               ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
-               ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \
+               ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%1")   \
+               ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b, "%1")   \
                : "=&r"(__gu_tmp.l), "+r"(__gu_err)     \
                : "i"(sr), "r"(ptr));                   \
                                                        \
@@ -174,7 +144,7 @@ struct exception_table_entry {
        __asm__ __volatile__ (                                  \
                "1: " stx " %1,0(%%sr%2,%3)\n"                  \
                "9:\n"                                          \
-               ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b)         \
+               ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%0")   \
                : "+r"(__pu_err)                                \
                : "r"(x), "i"(sr), "r"(ptr))
 
@@ -186,15 +156,14 @@ struct exception_table_entry {
                "1: stw %1,0(%%sr%2,%3)\n"                      \
                "2: stw %R1,4(%%sr%2,%3)\n"                     \
                "9:\n"                                          \
-               ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b)         \
-               ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b)         \
+               ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%0")   \
+               ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b, "%0")   \
                : "+r"(__pu_err)                                \
                : "r"(__val), "i"(sr), "r"(ptr));               \
 } while (0)
 
 #endif /* !defined(CONFIG_64BIT) */
 
-
 /*
  * Complex access routines -- external declarations
  */
@@ -216,7 +185,4 @@ unsigned long __must_check raw_copy_from_user(void *dst, const void __user *src,
 #define INLINE_COPY_TO_USER
 #define INLINE_COPY_FROM_USER
 
-struct pt_regs;
-int fixup_exception(struct pt_regs *regs);
-
 #endif /* __PARISC_UACCESS_H */
index 268d90a9325b468603b634b86b48980a31b4fba7..422f3e1e6d9cad718c264c7d7c9bd30872846555 100644 (file)
@@ -58,7 +58,7 @@ int pa_serialize_tlb_flushes __ro_after_init;
 
 struct pdc_cache_info cache_info __ro_after_init;
 #ifndef CONFIG_PA20
-struct pdc_btlb_info btlb_info __ro_after_init;
+struct pdc_btlb_info btlb_info;
 #endif
 
 DEFINE_STATIC_KEY_TRUE(parisc_has_cache);
@@ -264,6 +264,10 @@ parisc_cache_init(void)
        icache_stride = CAFL_STRIDE(cache_info.ic_conf);
 #undef CAFL_STRIDE
 
+       /* stride needs to be non-zero, otherwise cache flushes will not work */
+       WARN_ON(cache_info.dc_size && dcache_stride == 0);
+       WARN_ON(cache_info.ic_size && icache_stride == 0);
+
        if ((boot_cpu_data.pdc.capabilities & PDC_MODEL_NVA_MASK) ==
                                                PDC_MODEL_NVA_UNSUPPORTED) {
                printk(KERN_WARNING "parisc_cache_init: Only equivalent aliasing supported!\n");
@@ -850,7 +854,7 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes,
 #endif
                        "   fic,m       %3(%4,%0)\n"
                        "2: sync\n"
-                       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b)
+                       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b, "%1")
                        : "+r" (start), "+r" (error)
                        : "r" (end), "r" (dcache_stride), "i" (SR_USER));
        }
@@ -865,7 +869,7 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes,
 #endif
                        "   fdc,m       %3(%4,%0)\n"
                        "2: sync\n"
-                       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b)
+                       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b, "%1")
                        : "+r" (start), "+r" (error)
                        : "r" (end), "r" (icache_stride), "i" (SR_USER));
        }
index 25f9b9e9d6dfbc70f21787e29a170334cb102dc7..c7ff339732ba5a762eac90e1b3072aef45c58318 100644 (file)
@@ -742,7 +742,7 @@ parse_tree_node(struct device *parent, int index, struct hardware_path *modpath)
        };
 
        if (device_for_each_child(parent, &recurse_data, descend_children))
-               { /* nothing */ };
+               { /* nothing */ }
 
        return d.dev;
 }
@@ -1004,6 +1004,9 @@ static __init int qemu_print_iodc_data(struct device *lin_dev, void *data)
 
        pr_info("\n");
 
+       /* Prevent hung task messages when printing on serial console */
+       cond_resched();
+
        pr_info("#define HPA_%08lx_DESCRIPTION \"%s\"\n",
                hpa, parisc_hardware_description(&dev->id));
 
index ce25acfe4889d0df8048e448a16d76e414ee1262..c520e551a165258609cba5e068037493bd7e57a8 100644 (file)
@@ -120,8 +120,8 @@ static int emulate_ldh(struct pt_regs *regs, int toreg)
 "2:    ldbs    1(%%sr1,%3), %0\n"
 "      depw    %2, 23, 24, %0\n"
 "3:    \n"
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1")
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1")
        : "+r" (val), "+r" (ret), "=&r" (temp1)
        : "r" (saddr), "r" (regs->isr) );
 
@@ -152,8 +152,8 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop)
 "      mtctl   %2,11\n"
 "      vshd    %0,%3,%0\n"
 "3:    \n"
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1")
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1")
        : "+r" (val), "+r" (ret), "=&r" (temp1), "=&r" (temp2)
        : "r" (saddr), "r" (regs->isr) );
 
@@ -189,8 +189,8 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
 "      mtsar   %%r19\n"
 "      shrpd   %0,%%r20,%%sar,%0\n"
 "3:    \n"
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1")
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1")
        : "=r" (val), "+r" (ret)
        : "0" (val), "r" (saddr), "r" (regs->isr)
        : "r19", "r20" );
@@ -209,9 +209,9 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
 "      vshd    %0,%R0,%0\n"
 "      vshd    %R0,%4,%R0\n"
 "4:    \n"
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 4b)
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 4b)
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b)
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 4b, "%1")
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 4b, "%1")
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b, "%1")
        : "+r" (val), "+r" (ret), "+r" (saddr), "=&r" (shift), "=&r" (temp1)
        : "r" (regs->isr) );
     }
@@ -244,8 +244,8 @@ static int emulate_sth(struct pt_regs *regs, int frreg)
 "1:    stb %1, 0(%%sr1, %3)\n"
 "2:    stb %2, 1(%%sr1, %3)\n"
 "3:    \n"
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%0")
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%0")
        : "+r" (ret), "=&r" (temp1)
        : "r" (val), "r" (regs->ior), "r" (regs->isr) );
 
@@ -285,8 +285,8 @@ static int emulate_stw(struct pt_regs *regs, int frreg, int flop)
 "      stw     %%r20,0(%%sr1,%2)\n"
 "      stw     %%r21,4(%%sr1,%2)\n"
 "3:    \n"
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%0")
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%0")
        : "+r" (ret)
        : "r" (val), "r" (regs->ior), "r" (regs->isr)
        : "r19", "r20", "r21", "r22", "r1" );
@@ -329,10 +329,10 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 "3:    std     %%r20,0(%%sr1,%2)\n"
 "4:    std     %%r21,8(%%sr1,%2)\n"
 "5:    \n"
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 5b)
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 5b)
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 5b)
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 5b)
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 5b, "%0")
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 5b, "%0")
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 5b, "%0")
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 5b, "%0")
        : "+r" (ret)
        : "r" (val), "r" (regs->ior), "r" (regs->isr)
        : "r19", "r20", "r21", "r22", "r1" );
@@ -357,11 +357,11 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 "4:    stw     %%r1,4(%%sr1,%2)\n"
 "5:    stw     %R1,8(%%sr1,%2)\n"
 "6:    \n"
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 6b)
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 6b)
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 6b)
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 6b)
-       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(5b, 6b)
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 6b, "%0")
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 6b, "%0")
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 6b, "%0")
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 6b, "%0")
+       ASM_EXCEPTIONTABLE_ENTRY_EFAULT(5b, 6b, "%0")
        : "+r" (ret)
        : "r" (val), "r" (regs->ior), "r" (regs->isr)
        : "r19", "r20", "r21", "r1" );
index 548051b0b4aff692741847a04b09208d1e68d279..b445e47903cfd0b813035c2056f11a4f818cf6d2 100644 (file)
@@ -127,7 +127,7 @@ SECTIONS
        }
 #endif
 
-       RO_DATA(8)
+       RO_DATA(PAGE_SIZE)
 
        /* unwind info */
        . = ALIGN(4);
index 2fe5b44986e0924e3981ebc1edb9d074c08e6fda..c39de84e98b05172bdec0f474261ccde4a06cf00 100644 (file)
@@ -150,11 +150,16 @@ int fixup_exception(struct pt_regs *regs)
                 * Fix up get_user() and put_user().
                 * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() sets the least-significant
                 * bit in the relative address of the fixup routine to indicate
-                * that gr[ASM_EXCEPTIONTABLE_REG] should be loaded with
-                * -EFAULT to report a userspace access error.
+                * that the register encoded in the "or %r0,%r0,register"
+                * opcode should be loaded with -EFAULT to report a userspace
+                * access error.
                 */
                if (fix->fixup & 1) {
-                       regs->gr[ASM_EXCEPTIONTABLE_REG] = -EFAULT;
+                       int fault_error_reg = fix->err_opcode & 0x1f;
+                       if (!WARN_ON(!fault_error_reg))
+                               regs->gr[fault_error_reg] = -EFAULT;
+                       pr_debug("Unalignment fixup of register %d at %pS\n",
+                               fault_error_reg, (void*)regs->iaoq[0]);
 
                        /* zero target register for get_user() */
                        if (parisc_acctyp(0, regs->iir) == VM_READ) {
index ebe259bdd46298e0654fb681b0cf8853c8381079..d71eac3b2887b98ff5ea23ec1874243283524f4c 100644 (file)
@@ -1287,20 +1287,20 @@ spapr_tce_platform_iommu_attach_dev(struct iommu_domain *platform_domain,
        struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
        struct iommu_group *grp = iommu_group_get(dev);
        struct iommu_table_group *table_group;
-       int ret = -EINVAL;
 
        /* At first attach the ownership is already set */
        if (!domain)
                return 0;
 
-       if (!grp)
-               return -ENODEV;
-
        table_group = iommu_group_get_iommudata(grp);
-       ret = table_group->ops->take_ownership(table_group);
+       /*
+        * The domain being set to PLATFORM from earlier
+        * BLOCKED. The table_group ownership has to be released.
+        */
+       table_group->ops->release_ownership(table_group);
        iommu_group_put(grp);
 
-       return ret;
+       return 0;
 }
 
 static const struct iommu_domain_ops spapr_tce_platform_domain_ops = {
@@ -1312,13 +1312,32 @@ static struct iommu_domain spapr_tce_platform_domain = {
        .ops = &spapr_tce_platform_domain_ops,
 };
 
-static struct iommu_domain spapr_tce_blocked_domain = {
-       .type = IOMMU_DOMAIN_BLOCKED,
+static int
+spapr_tce_blocked_iommu_attach_dev(struct iommu_domain *platform_domain,
+                                    struct device *dev)
+{
+       struct iommu_group *grp = iommu_group_get(dev);
+       struct iommu_table_group *table_group;
+       int ret = -EINVAL;
+
        /*
         * FIXME: SPAPR mixes blocked and platform behaviors, the blocked domain
         * also sets the dma_api ops
         */
-       .ops = &spapr_tce_platform_domain_ops,
+       table_group = iommu_group_get_iommudata(grp);
+       ret = table_group->ops->take_ownership(table_group);
+       iommu_group_put(grp);
+
+       return ret;
+}
+
+static const struct iommu_domain_ops spapr_tce_blocked_domain_ops = {
+       .attach_dev = spapr_tce_blocked_iommu_attach_dev,
+};
+
+static struct iommu_domain spapr_tce_blocked_domain = {
+       .type = IOMMU_DOMAIN_BLOCKED,
+       .ops = &spapr_tce_blocked_domain_ops,
 };
 
 static bool spapr_tce_iommu_capable(struct device *dev, enum iommu_cap cap)
index 93256540d07882af2b12a6faf0642d93ddc4970b..ead1cc35d88b2f13bfecf935a6e66e6049a24a75 100644 (file)
                                              <&cpu63_intc 3>;
                };
 
-               clint_mtimer0: timer@70ac000000 {
+               clint_mtimer0: timer@70ac004000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac000000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac004000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu0_intc 7>,
                                              <&cpu1_intc 7>,
                                              <&cpu2_intc 7>,
                                              <&cpu3_intc 7>;
                };
 
-               clint_mtimer1: timer@70ac010000 {
+               clint_mtimer1: timer@70ac014000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac010000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac014000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu4_intc 7>,
                                              <&cpu5_intc 7>,
                                              <&cpu6_intc 7>,
                                              <&cpu7_intc 7>;
                };
 
-               clint_mtimer2: timer@70ac020000 {
+               clint_mtimer2: timer@70ac024000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac020000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac024000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu8_intc 7>,
                                              <&cpu9_intc 7>,
                                              <&cpu10_intc 7>,
                                              <&cpu11_intc 7>;
                };
 
-               clint_mtimer3: timer@70ac030000 {
+               clint_mtimer3: timer@70ac034000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac030000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac034000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu12_intc 7>,
                                              <&cpu13_intc 7>,
                                              <&cpu14_intc 7>,
                                              <&cpu15_intc 7>;
                };
 
-               clint_mtimer4: timer@70ac040000 {
+               clint_mtimer4: timer@70ac044000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac040000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac044000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu16_intc 7>,
                                              <&cpu17_intc 7>,
                                              <&cpu18_intc 7>,
                                              <&cpu19_intc 7>;
                };
 
-               clint_mtimer5: timer@70ac050000 {
+               clint_mtimer5: timer@70ac054000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac050000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac054000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu20_intc 7>,
                                              <&cpu21_intc 7>,
                                              <&cpu22_intc 7>,
                                              <&cpu23_intc 7>;
                };
 
-               clint_mtimer6: timer@70ac060000 {
+               clint_mtimer6: timer@70ac064000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac060000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac064000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu24_intc 7>,
                                              <&cpu25_intc 7>,
                                              <&cpu26_intc 7>,
                                              <&cpu27_intc 7>;
                };
 
-               clint_mtimer7: timer@70ac070000 {
+               clint_mtimer7: timer@70ac074000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac070000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac074000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu28_intc 7>,
                                              <&cpu29_intc 7>,
                                              <&cpu30_intc 7>,
                                              <&cpu31_intc 7>;
                };
 
-               clint_mtimer8: timer@70ac080000 {
+               clint_mtimer8: timer@70ac084000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac080000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac084000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu32_intc 7>,
                                              <&cpu33_intc 7>,
                                              <&cpu34_intc 7>,
                                              <&cpu35_intc 7>;
                };
 
-               clint_mtimer9: timer@70ac090000 {
+               clint_mtimer9: timer@70ac094000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac090000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac094000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu36_intc 7>,
                                              <&cpu37_intc 7>,
                                              <&cpu38_intc 7>,
                                              <&cpu39_intc 7>;
                };
 
-               clint_mtimer10: timer@70ac0a0000 {
+               clint_mtimer10: timer@70ac0a4000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac0a0000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac0a4000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu40_intc 7>,
                                              <&cpu41_intc 7>,
                                              <&cpu42_intc 7>,
                                              <&cpu43_intc 7>;
                };
 
-               clint_mtimer11: timer@70ac0b0000 {
+               clint_mtimer11: timer@70ac0b4000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac0b0000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac0b4000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu44_intc 7>,
                                              <&cpu45_intc 7>,
                                              <&cpu46_intc 7>,
                                              <&cpu47_intc 7>;
                };
 
-               clint_mtimer12: timer@70ac0c0000 {
+               clint_mtimer12: timer@70ac0c4000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac0c0000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac0c4000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu48_intc 7>,
                                              <&cpu49_intc 7>,
                                              <&cpu50_intc 7>,
                                              <&cpu51_intc 7>;
                };
 
-               clint_mtimer13: timer@70ac0d0000 {
+               clint_mtimer13: timer@70ac0d4000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac0d0000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac0d4000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu52_intc 7>,
                                              <&cpu53_intc 7>,
                                              <&cpu54_intc 7>,
                                              <&cpu55_intc 7>;
                };
 
-               clint_mtimer14: timer@70ac0e0000 {
+               clint_mtimer14: timer@70ac0e4000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac0e0000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac0e4000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu56_intc 7>,
                                              <&cpu57_intc 7>,
                                              <&cpu58_intc 7>,
                                              <&cpu59_intc 7>;
                };
 
-               clint_mtimer15: timer@70ac0f0000 {
+               clint_mtimer15: timer@70ac0f4000 {
                        compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer";
-                       reg = <0x00000070 0xac0f0000 0x00000000 0x00007ff8>;
+                       reg = <0x00000070 0xac0f4000 0x00000000 0x0000c000>;
+                       reg-names = "mtimecmp";
                        interrupts-extended = <&cpu60_intc 7>,
                                              <&cpu61_intc 7>,
                                              <&cpu62_intc 7>,
index 82f05f250634807c9f78774bca9213dfd5de2038..34957dcb88b9c31befa3c2b7e08809de73b23a3e 100644 (file)
@@ -115,7 +115,9 @@ archprepare:
        $(Q)$(MAKE) $(build)=$(HOST_DIR)/um include/generated/user_constants.h
 
 LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static
-LINK-$(CONFIG_LD_SCRIPT_DYN) += $(call cc-option, -no-pie)
+ifdef CONFIG_LD_SCRIPT_DYN
+LINK-$(call gcc-min-version, 60100)$(CONFIG_CC_IS_CLANG) += -no-pie
+endif
 LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib
 
 CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) \
index 1a068de12a564fe452cd5c003feb907fd3de42fd..2264db14a25d3b034ffa93685d6353564d4a9225 100644 (file)
@@ -112,13 +112,13 @@ ifeq ($(CONFIG_X86_32),y)
         # temporary until string.h is fixed
         KBUILD_CFLAGS += -ffreestanding
 
-       ifeq ($(CONFIG_STACKPROTECTOR),y)
-               ifeq ($(CONFIG_SMP),y)
+        ifeq ($(CONFIG_STACKPROTECTOR),y)
+                ifeq ($(CONFIG_SMP),y)
                        KBUILD_CFLAGS += -mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard
-               else
+                else
                        KBUILD_CFLAGS += -mstack-protector-guard=global
-               endif
-       endif
+                endif
+        endif
 else
         BITS := 64
         UTS_MACHINE := x86_64
index 29cb275a219d7fb38fa0d16e6ba48e91c9d032b4..fdf723b6f6d0ce9f6742ef3c67adce3c8d57c002 100644 (file)
 #define X86_FEATURE_K6_MTRR            ( 3*32+ 1) /* AMD K6 nonstandard MTRRs */
 #define X86_FEATURE_CYRIX_ARR          ( 3*32+ 2) /* Cyrix ARRs (= MTRRs) */
 #define X86_FEATURE_CENTAUR_MCR                ( 3*32+ 3) /* Centaur MCRs (= MTRRs) */
-
-/* CPU types for specific tunings: */
 #define X86_FEATURE_K8                 ( 3*32+ 4) /* "" Opteron, Athlon64 */
-/* FREE, was #define X86_FEATURE_K7                    ( 3*32+ 5) "" Athlon */
+#define X86_FEATURE_ZEN5               ( 3*32+ 5) /* "" CPU based on Zen5 microarchitecture */
 #define X86_FEATURE_P3                 ( 3*32+ 6) /* "" P3 */
 #define X86_FEATURE_P4                 ( 3*32+ 7) /* "" P4 */
 #define X86_FEATURE_CONSTANT_TSC       ( 3*32+ 8) /* TSC ticks at a constant rate */
index 197316121f04e154dad9ba4d9a7169674c623dd5..b65e9c46b92210293d767ab01434593c2aad27a0 100644 (file)
 #define INTEL_FAM6_ATOM_CRESTMONT_X    0xAF /* Sierra Forest */
 #define INTEL_FAM6_ATOM_CRESTMONT      0xB6 /* Grand Ridge */
 
+#define INTEL_FAM6_ATOM_DARKMONT_X     0xDD /* Clearwater Forest */
+
 /* Xeon Phi */
 
 #define INTEL_FAM6_XEON_PHI_KNL                0x57 /* Knights Landing */
index 8fa6ac0e2d7665f936756748c0e1b4ab08a2c5a7..d91b37f5b4bb45106ee927fcd98b66f1b82a54c1 100644 (file)
@@ -64,6 +64,7 @@ static inline bool kmsan_virt_addr_valid(void *addr)
 {
        unsigned long x = (unsigned long)addr;
        unsigned long y = x - __START_KERNEL_map;
+       bool ret;
 
        /* use the carry flag to determine if x was < __START_KERNEL_map */
        if (unlikely(x > y)) {
@@ -79,7 +80,21 @@ static inline bool kmsan_virt_addr_valid(void *addr)
                        return false;
        }
 
-       return pfn_valid(x >> PAGE_SHIFT);
+       /*
+        * pfn_valid() relies on RCU, and may call into the scheduler on exiting
+        * the critical section. However, this would result in recursion with
+        * KMSAN. Therefore, disable preemption here, and re-enable preemption
+        * below while suppressing reschedules to avoid recursion.
+        *
+        * Note, this sacrifices occasionally breaking scheduling guarantees.
+        * Although, a kernel compiled with KMSAN has already given up on any
+        * performance guarantees due to being heavily instrumented.
+        */
+       preempt_disable();
+       ret = pfn_valid(x >> PAGE_SHIFT);
+       preempt_enable_no_resched();
+
+       return ret;
 }
 
 #endif /* !MODULE */
index 21f9407be5d357a8f4204addc66841dc50d9bf51..7e88705e907f411b416d25e533e06623997555ea 100644 (file)
@@ -58,12 +58,29 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs);
                ,,regs->di,,regs->si,,regs->dx                          \
                ,,regs->r10,,regs->r8,,regs->r9)                        \
 
+
+/* SYSCALL_PT_ARGS is Adapted from s390x */
+#define SYSCALL_PT_ARG6(m, t1, t2, t3, t4, t5, t6)                     \
+       SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5), m(t6, (regs->bp))
+#define SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5)                         \
+       SYSCALL_PT_ARG4(m, t1, t2, t3, t4),  m(t5, (regs->di))
+#define SYSCALL_PT_ARG4(m, t1, t2, t3, t4)                             \
+       SYSCALL_PT_ARG3(m, t1, t2, t3),  m(t4, (regs->si))
+#define SYSCALL_PT_ARG3(m, t1, t2, t3)                                 \
+       SYSCALL_PT_ARG2(m, t1, t2), m(t3, (regs->dx))
+#define SYSCALL_PT_ARG2(m, t1, t2)                                     \
+       SYSCALL_PT_ARG1(m, t1), m(t2, (regs->cx))
+#define SYSCALL_PT_ARG1(m, t1) m(t1, (regs->bx))
+#define SYSCALL_PT_ARGS(x, ...) SYSCALL_PT_ARG##x(__VA_ARGS__)
+
+#define __SC_COMPAT_CAST(t, a)                                         \
+       (__typeof(__builtin_choose_expr(__TYPE_IS_L(t), 0, 0U)))        \
+       (unsigned int)a
+
 /* Mapping of registers to parameters for syscalls on i386 */
 #define SC_IA32_REGS_TO_ARGS(x, ...)                                   \
-       __MAP(x,__SC_ARGS                                               \
-             ,,(unsigned int)regs->bx,,(unsigned int)regs->cx          \
-             ,,(unsigned int)regs->dx,,(unsigned int)regs->si          \
-             ,,(unsigned int)regs->di,,(unsigned int)regs->bp)
+       SYSCALL_PT_ARGS(x, __SC_COMPAT_CAST,                            \
+                       __MAP(x, __SC_TYPE, __VA_ARGS__))               \
 
 #define __SYS_STUB0(abi, name)                                         \
        long __##abi##_##name(const struct pt_regs *regs);              \
index cc130b57542ac4033c1c653809f429306eb3e460..1d85cb7071cb21c84899477ec4a150d2fcc4da43 100644 (file)
@@ -403,7 +403,7 @@ noinstr void BUG_func(void)
 {
        BUG();
 }
-EXPORT_SYMBOL_GPL(BUG_func);
+EXPORT_SYMBOL(BUG_func);
 
 #define CALL_RIP_REL_OPCODE    0xff
 #define CALL_RIP_REL_MODRM     0x15
index 9f42d1c59e095ee6923a78cb2ecb04fbe375a438..f3abca334199d8eae235f1560f99448eb9675a27 100644 (file)
@@ -538,7 +538,7 @@ static void bsp_init_amd(struct cpuinfo_x86 *c)
 
        /* Figure out Zen generations: */
        switch (c->x86) {
-       case 0x17: {
+       case 0x17:
                switch (c->x86_model) {
                case 0x00 ... 0x2f:
                case 0x50 ... 0x5f:
@@ -554,8 +554,8 @@ static void bsp_init_amd(struct cpuinfo_x86 *c)
                        goto warn;
                }
                break;
-       }
-       case 0x19: {
+
+       case 0x19:
                switch (c->x86_model) {
                case 0x00 ... 0x0f:
                case 0x20 ... 0x5f:
@@ -569,7 +569,20 @@ static void bsp_init_amd(struct cpuinfo_x86 *c)
                        goto warn;
                }
                break;
-       }
+
+       case 0x1a:
+               switch (c->x86_model) {
+               case 0x00 ... 0x0f:
+               case 0x20 ... 0x2f:
+               case 0x40 ... 0x4f:
+               case 0x70 ... 0x7f:
+                       setup_force_cpu_cap(X86_FEATURE_ZEN5);
+                       break;
+               default:
+                       goto warn;
+               }
+               break;
+
        default:
                break;
        }
@@ -1039,6 +1052,11 @@ static void init_amd_zen4(struct cpuinfo_x86 *c)
                msr_set_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT);
 }
 
+static void init_amd_zen5(struct cpuinfo_x86 *c)
+{
+       init_amd_zen_common();
+}
+
 static void init_amd(struct cpuinfo_x86 *c)
 {
        u64 vm_cr;
@@ -1084,6 +1102,8 @@ static void init_amd(struct cpuinfo_x86 *c)
                init_amd_zen3(c);
        else if (boot_cpu_has(X86_FEATURE_ZEN4))
                init_amd_zen4(c);
+       else if (boot_cpu_has(X86_FEATURE_ZEN5))
+               init_amd_zen5(c);
 
        /*
         * Enable workaround for FXSAVE leak on CPUs
index 11342af420d0c41d1c98a729471dcd6bfb46da05..de771093b52687ae2431af36bf75b73ccaa1bbf0 100644 (file)
@@ -49,6 +49,7 @@
 #include "blk-pm.h"
 #include "blk-cgroup.h"
 #include "blk-throttle.h"
+#include "blk-ioprio.h"
 
 struct dentry *blk_debugfs_root;
 
@@ -833,6 +834,14 @@ end_io:
 }
 EXPORT_SYMBOL(submit_bio_noacct);
 
+static void bio_set_ioprio(struct bio *bio)
+{
+       /* Nobody set ioprio so far? Initialize it based on task's nice value */
+       if (IOPRIO_PRIO_CLASS(bio->bi_ioprio) == IOPRIO_CLASS_NONE)
+               bio->bi_ioprio = get_current_ioprio();
+       blkcg_set_ioprio(bio);
+}
+
 /**
  * submit_bio - submit a bio to the block device layer for I/O
  * @bio: The &struct bio which describes the I/O
@@ -855,6 +864,7 @@ void submit_bio(struct bio *bio)
                count_vm_events(PGPGOUT, bio_sectors(bio));
        }
 
+       bio_set_ioprio(bio);
        submit_bio_noacct(bio);
 }
 EXPORT_SYMBOL(submit_bio);
index 8584babf3ea0ca2590f30383b9594231266e9437..71210cdb34426d967b5632667cb7579b11e97a2d 100644 (file)
@@ -205,12 +205,19 @@ static int bio_copy_user_iov(struct request *rq, struct rq_map_data *map_data,
        /*
         * success
         */
-       if ((iov_iter_rw(iter) == WRITE &&
-            (!map_data || !map_data->null_mapped)) ||
-           (map_data && map_data->from_user)) {
+       if (iov_iter_rw(iter) == WRITE &&
+            (!map_data || !map_data->null_mapped)) {
                ret = bio_copy_from_iter(bio, iter);
                if (ret)
                        goto cleanup;
+       } else if (map_data && map_data->from_user) {
+               struct iov_iter iter2 = *iter;
+
+               /* This is the copy-in part of SG_DXFER_TO_FROM_DEV. */
+               iter2.data_source = ITER_SOURCE;
+               ret = bio_copy_from_iter(bio, &iter2);
+               if (ret)
+                       goto cleanup;
        } else {
                if (bmd->is_our_pages)
                        zero_fill_bio(bio);
index aa87fcfda1ecfc875c86a0258fe16e707ce3f167..2dc01551e27c7d1e50266e554fe4bb6d378a1482 100644 (file)
@@ -40,7 +40,6 @@
 #include "blk-stat.h"
 #include "blk-mq-sched.h"
 #include "blk-rq-qos.h"
-#include "blk-ioprio.h"
 
 static DEFINE_PER_CPU(struct llist_head, blk_cpu_done);
 static DEFINE_PER_CPU(call_single_data_t, blk_cpu_csd);
@@ -2944,14 +2943,6 @@ static bool blk_mq_use_cached_rq(struct request *rq, struct blk_plug *plug,
        return true;
 }
 
-static void bio_set_ioprio(struct bio *bio)
-{
-       /* Nobody set ioprio so far? Initialize it based on task's nice value */
-       if (IOPRIO_PRIO_CLASS(bio->bi_ioprio) == IOPRIO_CLASS_NONE)
-               bio->bi_ioprio = get_current_ioprio();
-       blkcg_set_ioprio(bio);
-}
-
 /**
  * blk_mq_submit_bio - Create and send a request to block device.
  * @bio: Bio pointer.
@@ -2976,7 +2967,6 @@ void blk_mq_submit_bio(struct bio *bio)
        blk_status_t ret;
 
        bio = blk_queue_bounce(bio, q);
-       bio_set_ioprio(bio);
 
        if (plug) {
                rq = rq_list_peek(&plug->cached_rq);
index 9c73a763ef8838953bd1050b505621c39b8d4cdb..438f79c564cfc05d6f525550417eeee93c7b82bb 100644 (file)
@@ -20,8 +20,6 @@ static int blkpg_do_ioctl(struct block_device *bdev,
        struct blkpg_partition p;
        sector_t start, length;
 
-       if (disk->flags & GENHD_FL_NO_PART)
-               return -EINVAL;
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
        if (copy_from_user(&p, upart, sizeof(struct blkpg_partition)))
index cab0d76a828e37eb90e38d91b4e92a61e703717e..5f5ed5c75f04d91d7bc8bf87ff4c9fa685c62318 100644 (file)
@@ -439,6 +439,11 @@ int bdev_add_partition(struct gendisk *disk, int partno, sector_t start,
                goto out;
        }
 
+       if (disk->flags & GENHD_FL_NO_PART) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        if (partition_overlaps(disk, start, length, -1)) {
                ret = -EBUSY;
                goto out;
index 19035230563d7bf8ca2625a06c241d0eb010c3b7..7cb962e2145349670e4a506c879822a6bb3c6c23 100644 (file)
@@ -102,7 +102,7 @@ static int reset_pending_show(struct seq_file *s, void *v)
 {
        struct ivpu_device *vdev = seq_to_ivpu(s);
 
-       seq_printf(s, "%d\n", atomic_read(&vdev->pm->in_reset));
+       seq_printf(s, "%d\n", atomic_read(&vdev->pm->reset_pending));
        return 0;
 }
 
@@ -130,7 +130,9 @@ dvfs_mode_fops_write(struct file *file, const char __user *user_buf, size_t size
 
        fw->dvfs_mode = dvfs_mode;
 
-       ivpu_pm_schedule_recovery(vdev);
+       ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev));
+       if (ret)
+               return ret;
 
        return size;
 }
@@ -190,7 +192,10 @@ fw_profiling_freq_fops_write(struct file *file, const char __user *user_buf,
                return ret;
 
        ivpu_hw_profiling_freq_drive(vdev, enable);
-       ivpu_pm_schedule_recovery(vdev);
+
+       ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev));
+       if (ret)
+               return ret;
 
        return size;
 }
@@ -301,11 +306,18 @@ static ssize_t
 ivpu_force_recovery_fn(struct file *file, const char __user *user_buf, size_t size, loff_t *pos)
 {
        struct ivpu_device *vdev = file->private_data;
+       int ret;
 
        if (!size)
                return -EINVAL;
 
-       ivpu_pm_schedule_recovery(vdev);
+       ret = ivpu_rpm_get(vdev);
+       if (ret)
+               return ret;
+
+       ivpu_pm_trigger_recovery(vdev, "debugfs");
+       flush_work(&vdev->pm->recovery_work);
+       ivpu_rpm_put(vdev);
        return size;
 }
 
index 64927682161b282e739ef024a0ccff29c49de2cd..9418c73ee8ef8ba025ef896ffe218b61b8058f75 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/firmware.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/pm_runtime.h>
 
 #include <drm/drm_accel.h>
 #include <drm/drm_file.h>
@@ -17,6 +18,7 @@
 #include "ivpu_debugfs.h"
 #include "ivpu_drv.h"
 #include "ivpu_fw.h"
+#include "ivpu_fw_log.h"
 #include "ivpu_gem.h"
 #include "ivpu_hw.h"
 #include "ivpu_ipc.h"
@@ -65,22 +67,20 @@ struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv)
        return file_priv;
 }
 
-struct ivpu_file_priv *ivpu_file_priv_get_by_ctx_id(struct ivpu_device *vdev, unsigned long id)
+static void file_priv_unbind(struct ivpu_device *vdev, struct ivpu_file_priv *file_priv)
 {
-       struct ivpu_file_priv *file_priv;
-
-       xa_lock_irq(&vdev->context_xa);
-       file_priv = xa_load(&vdev->context_xa, id);
-       /* file_priv may still be in context_xa during file_priv_release() */
-       if (file_priv && !kref_get_unless_zero(&file_priv->ref))
-               file_priv = NULL;
-       xa_unlock_irq(&vdev->context_xa);
-
-       if (file_priv)
-               ivpu_dbg(vdev, KREF, "file_priv get by id: ctx %u refcount %u\n",
-                        file_priv->ctx.id, kref_read(&file_priv->ref));
-
-       return file_priv;
+       mutex_lock(&file_priv->lock);
+       if (file_priv->bound) {
+               ivpu_dbg(vdev, FILE, "file_priv unbind: ctx %u\n", file_priv->ctx.id);
+
+               ivpu_cmdq_release_all_locked(file_priv);
+               ivpu_jsm_context_release(vdev, file_priv->ctx.id);
+               ivpu_bo_unbind_all_bos_from_context(vdev, &file_priv->ctx);
+               ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
+               file_priv->bound = false;
+               drm_WARN_ON(&vdev->drm, !xa_erase_irq(&vdev->context_xa, file_priv->ctx.id));
+       }
+       mutex_unlock(&file_priv->lock);
 }
 
 static void file_priv_release(struct kref *ref)
@@ -88,13 +88,15 @@ static void file_priv_release(struct kref *ref)
        struct ivpu_file_priv *file_priv = container_of(ref, struct ivpu_file_priv, ref);
        struct ivpu_device *vdev = file_priv->vdev;
 
-       ivpu_dbg(vdev, FILE, "file_priv release: ctx %u\n", file_priv->ctx.id);
+       ivpu_dbg(vdev, FILE, "file_priv release: ctx %u bound %d\n",
+                file_priv->ctx.id, (bool)file_priv->bound);
+
+       pm_runtime_get_sync(vdev->drm.dev);
+       mutex_lock(&vdev->context_list_lock);
+       file_priv_unbind(vdev, file_priv);
+       mutex_unlock(&vdev->context_list_lock);
+       pm_runtime_put_autosuspend(vdev->drm.dev);
 
-       ivpu_cmdq_release_all(file_priv);
-       ivpu_jsm_context_release(vdev, file_priv->ctx.id);
-       ivpu_bo_remove_all_bos_from_context(vdev, &file_priv->ctx);
-       ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
-       drm_WARN_ON(&vdev->drm, xa_erase_irq(&vdev->context_xa, file_priv->ctx.id) != file_priv);
        mutex_destroy(&file_priv->lock);
        kfree(file_priv);
 }
@@ -176,9 +178,6 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f
        case DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS:
                args->value = vdev->hw->ranges.user.start;
                break;
-       case DRM_IVPU_PARAM_CONTEXT_PRIORITY:
-               args->value = file_priv->priority;
-               break;
        case DRM_IVPU_PARAM_CONTEXT_ID:
                args->value = file_priv->ctx.id;
                break;
@@ -218,17 +217,10 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f
 
 static int ivpu_set_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 {
-       struct ivpu_file_priv *file_priv = file->driver_priv;
        struct drm_ivpu_param *args = data;
        int ret = 0;
 
        switch (args->param) {
-       case DRM_IVPU_PARAM_CONTEXT_PRIORITY:
-               if (args->value <= DRM_IVPU_CONTEXT_PRIORITY_REALTIME)
-                       file_priv->priority = args->value;
-               else
-                       ret = -EINVAL;
-               break;
        default:
                ret = -EINVAL;
        }
@@ -241,50 +233,53 @@ static int ivpu_open(struct drm_device *dev, struct drm_file *file)
        struct ivpu_device *vdev = to_ivpu_device(dev);
        struct ivpu_file_priv *file_priv;
        u32 ctx_id;
-       void *old;
-       int ret;
+       int idx, ret;
 
-       ret = xa_alloc_irq(&vdev->context_xa, &ctx_id, NULL, vdev->context_xa_limit, GFP_KERNEL);
-       if (ret) {
-               ivpu_err(vdev, "Failed to allocate context id: %d\n", ret);
-               return ret;
-       }
+       if (!drm_dev_enter(dev, &idx))
+               return -ENODEV;
 
        file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
        if (!file_priv) {
                ret = -ENOMEM;
-               goto err_xa_erase;
+               goto err_dev_exit;
        }
 
        file_priv->vdev = vdev;
-       file_priv->priority = DRM_IVPU_CONTEXT_PRIORITY_NORMAL;
+       file_priv->bound = true;
        kref_init(&file_priv->ref);
        mutex_init(&file_priv->lock);
 
+       mutex_lock(&vdev->context_list_lock);
+
+       ret = xa_alloc_irq(&vdev->context_xa, &ctx_id, file_priv,
+                          vdev->context_xa_limit, GFP_KERNEL);
+       if (ret) {
+               ivpu_err(vdev, "Failed to allocate context id: %d\n", ret);
+               goto err_unlock;
+       }
+
        ret = ivpu_mmu_user_context_init(vdev, &file_priv->ctx, ctx_id);
        if (ret)
-               goto err_mutex_destroy;
+               goto err_xa_erase;
 
-       old = xa_store_irq(&vdev->context_xa, ctx_id, file_priv, GFP_KERNEL);
-       if (xa_is_err(old)) {
-               ret = xa_err(old);
-               ivpu_err(vdev, "Failed to store context %u: %d\n", ctx_id, ret);
-               goto err_ctx_fini;
-       }
+       mutex_unlock(&vdev->context_list_lock);
+       drm_dev_exit(idx);
+
+       file->driver_priv = file_priv;
 
        ivpu_dbg(vdev, FILE, "file_priv create: ctx %u process %s pid %d\n",
                 ctx_id, current->comm, task_pid_nr(current));
 
-       file->driver_priv = file_priv;
        return 0;
 
-err_ctx_fini:
-       ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
-err_mutex_destroy:
-       mutex_destroy(&file_priv->lock);
-       kfree(file_priv);
 err_xa_erase:
        xa_erase_irq(&vdev->context_xa, ctx_id);
+err_unlock:
+       mutex_unlock(&vdev->context_list_lock);
+       mutex_destroy(&file_priv->lock);
+       kfree(file_priv);
+err_dev_exit:
+       drm_dev_exit(idx);
        return ret;
 }
 
@@ -340,8 +335,6 @@ static int ivpu_wait_for_ready(struct ivpu_device *vdev)
 
        if (!ret)
                ivpu_dbg(vdev, PM, "VPU ready message received successfully\n");
-       else
-               ivpu_hw_diagnose_failure(vdev);
 
        return ret;
 }
@@ -369,6 +362,9 @@ int ivpu_boot(struct ivpu_device *vdev)
        ret = ivpu_wait_for_ready(vdev);
        if (ret) {
                ivpu_err(vdev, "Failed to boot the firmware: %d\n", ret);
+               ivpu_hw_diagnose_failure(vdev);
+               ivpu_mmu_evtq_dump(vdev);
+               ivpu_fw_log_dump(vdev);
                return ret;
        }
 
@@ -540,6 +536,10 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
        lockdep_set_class(&vdev->submitted_jobs_xa.xa_lock, &submitted_jobs_xa_lock_class_key);
        INIT_LIST_HEAD(&vdev->bo_list);
 
+       ret = drmm_mutex_init(&vdev->drm, &vdev->context_list_lock);
+       if (ret)
+               goto err_xa_destroy;
+
        ret = drmm_mutex_init(&vdev->drm, &vdev->bo_list_lock);
        if (ret)
                goto err_xa_destroy;
@@ -611,14 +611,30 @@ err_xa_destroy:
        return ret;
 }
 
+static void ivpu_bo_unbind_all_user_contexts(struct ivpu_device *vdev)
+{
+       struct ivpu_file_priv *file_priv;
+       unsigned long ctx_id;
+
+       mutex_lock(&vdev->context_list_lock);
+
+       xa_for_each(&vdev->context_xa, ctx_id, file_priv)
+               file_priv_unbind(vdev, file_priv);
+
+       mutex_unlock(&vdev->context_list_lock);
+}
+
 static void ivpu_dev_fini(struct ivpu_device *vdev)
 {
        ivpu_pm_disable(vdev);
        ivpu_shutdown(vdev);
        if (IVPU_WA(d3hot_after_power_off))
                pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot);
+
+       ivpu_jobs_abort_all(vdev);
        ivpu_job_done_consumer_fini(vdev);
        ivpu_pm_cancel_recovery(vdev);
+       ivpu_bo_unbind_all_user_contexts(vdev);
 
        ivpu_ipc_fini(vdev);
        ivpu_fw_fini(vdev);
index ebc4b84f27b209df9d653747772e756702cf4601..069ace4adb2d19c1a0544333d0da65632c524ea7 100644 (file)
@@ -56,6 +56,7 @@
 #define IVPU_DBG_JSM    BIT(10)
 #define IVPU_DBG_KREF   BIT(11)
 #define IVPU_DBG_RPM    BIT(12)
+#define IVPU_DBG_MMU_MAP BIT(13)
 
 #define ivpu_err(vdev, fmt, ...) \
        drm_err(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__)
@@ -114,6 +115,7 @@ struct ivpu_device {
 
        struct ivpu_mmu_context gctx;
        struct ivpu_mmu_context rctx;
+       struct mutex context_list_lock; /* Protects user context addition/removal */
        struct xarray context_xa;
        struct xa_limit context_xa_limit;
 
@@ -145,8 +147,8 @@ struct ivpu_file_priv {
        struct mutex lock; /* Protects cmdq */
        struct ivpu_cmdq *cmdq[IVPU_NUM_ENGINES];
        struct ivpu_mmu_context ctx;
-       u32 priority;
        bool has_mmu_faults;
+       bool bound;
 };
 
 extern int ivpu_dbg_mask;
@@ -162,7 +164,6 @@ extern bool ivpu_disable_mmu_cont_pages;
 extern int ivpu_test_mode;
 
 struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv);
-struct ivpu_file_priv *ivpu_file_priv_get_by_ctx_id(struct ivpu_device *vdev, unsigned long id);
 void ivpu_file_priv_put(struct ivpu_file_priv **link);
 
 int ivpu_boot(struct ivpu_device *vdev);
index 1dda4f38ea25cd356cc9efadcaa8d35394c6b19f..e9ddbe9f50ebeffaa3a1617431b864ceec73e2e7 100644 (file)
@@ -24,14 +24,11 @@ static const struct drm_gem_object_funcs ivpu_gem_funcs;
 
 static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, const char *action)
 {
-       if (bo->ctx)
-               ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u ctx %d vpu_addr 0x%llx mmu_mapped %d\n",
-                        action, ivpu_bo_size(bo), (bool)bo->base.pages, (bool)bo->base.sgt,
-                        bo->handle, bo->ctx->id, bo->vpu_addr, bo->mmu_mapped);
-       else
-               ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u (not added to context)\n",
-                        action, ivpu_bo_size(bo), (bool)bo->base.pages, (bool)bo->base.sgt,
-                        bo->handle);
+       ivpu_dbg(vdev, BO,
+                "%6s: bo %8p vpu_addr %9llx size %8zu ctx %d has_pages %d dma_mapped %d mmu_mapped %d wc %d imported %d\n",
+                action, bo, bo->vpu_addr, ivpu_bo_size(bo), bo->ctx ? bo->ctx->id : 0,
+                (bool)bo->base.pages, (bool)bo->base.sgt, bo->mmu_mapped, bo->base.map_wc,
+                (bool)bo->base.base.import_attach);
 }
 
 /*
@@ -49,12 +46,7 @@ int __must_check ivpu_bo_pin(struct ivpu_bo *bo)
        mutex_lock(&bo->lock);
 
        ivpu_dbg_bo(vdev, bo, "pin");
-
-       if (!bo->ctx) {
-               ivpu_err(vdev, "vpu_addr not allocated for BO %d\n", bo->handle);
-               ret = -EINVAL;
-               goto unlock;
-       }
+       drm_WARN_ON(&vdev->drm, !bo->ctx);
 
        if (!bo->mmu_mapped) {
                struct sg_table *sgt = drm_gem_shmem_get_pages_sgt(&bo->base);
@@ -85,7 +77,10 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx,
                       const struct ivpu_addr_range *range)
 {
        struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
-       int ret;
+       int idx, ret;
+
+       if (!drm_dev_enter(&vdev->drm, &idx))
+               return -ENODEV;
 
        mutex_lock(&bo->lock);
 
@@ -101,6 +96,8 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx,
 
        mutex_unlock(&bo->lock);
 
+       drm_dev_exit(idx);
+
        return ret;
 }
 
@@ -108,11 +105,7 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo)
 {
        struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
 
-       lockdep_assert_held(&bo->lock);
-
-       ivpu_dbg_bo(vdev, bo, "unbind");
-
-       /* TODO: dma_unmap */
+       lockdep_assert(lockdep_is_held(&bo->lock) || !kref_read(&bo->base.base.refcount));
 
        if (bo->mmu_mapped) {
                drm_WARN_ON(&vdev->drm, !bo->ctx);
@@ -124,19 +117,23 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo)
 
        if (bo->ctx) {
                ivpu_mmu_context_remove_node(bo->ctx, &bo->mm_node);
-               bo->vpu_addr = 0;
                bo->ctx = NULL;
        }
-}
 
-static void ivpu_bo_unbind(struct ivpu_bo *bo)
-{
-       mutex_lock(&bo->lock);
-       ivpu_bo_unbind_locked(bo);
-       mutex_unlock(&bo->lock);
+       if (bo->base.base.import_attach)
+               return;
+
+       dma_resv_lock(bo->base.base.resv, NULL);
+       if (bo->base.sgt) {
+               dma_unmap_sgtable(vdev->drm.dev, bo->base.sgt, DMA_BIDIRECTIONAL, 0);
+               sg_free_table(bo->base.sgt);
+               kfree(bo->base.sgt);
+               bo->base.sgt = NULL;
+       }
+       dma_resv_unlock(bo->base.base.resv);
 }
 
-void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx)
+void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx)
 {
        struct ivpu_bo *bo;
 
@@ -146,8 +143,10 @@ void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_m
        mutex_lock(&vdev->bo_list_lock);
        list_for_each_entry(bo, &vdev->bo_list, bo_list_node) {
                mutex_lock(&bo->lock);
-               if (bo->ctx == ctx)
+               if (bo->ctx == ctx) {
+                       ivpu_dbg_bo(vdev, bo, "unbind");
                        ivpu_bo_unbind_locked(bo);
+               }
                mutex_unlock(&bo->lock);
        }
        mutex_unlock(&vdev->bo_list_lock);
@@ -199,9 +198,6 @@ ivpu_bo_create(struct ivpu_device *vdev, u64 size, u32 flags)
        list_add_tail(&bo->bo_list_node, &vdev->bo_list);
        mutex_unlock(&vdev->bo_list_lock);
 
-       ivpu_dbg(vdev, BO, "create: vpu_addr 0x%llx size %zu flags 0x%x\n",
-                bo->vpu_addr, bo->base.base.size, flags);
-
        return bo;
 }
 
@@ -212,6 +208,12 @@ static int ivpu_bo_open(struct drm_gem_object *obj, struct drm_file *file)
        struct ivpu_bo *bo = to_ivpu_bo(obj);
        struct ivpu_addr_range *range;
 
+       if (bo->ctx) {
+               ivpu_warn(vdev, "Can't add BO to ctx %u: already in ctx %u\n",
+                         file_priv->ctx.id, bo->ctx->id);
+               return -EALREADY;
+       }
+
        if (bo->flags & DRM_IVPU_BO_SHAVE_MEM)
                range = &vdev->hw->ranges.shave;
        else if (bo->flags & DRM_IVPU_BO_DMA_MEM)
@@ -227,62 +229,24 @@ static void ivpu_bo_free(struct drm_gem_object *obj)
        struct ivpu_device *vdev = to_ivpu_device(obj->dev);
        struct ivpu_bo *bo = to_ivpu_bo(obj);
 
+       ivpu_dbg_bo(vdev, bo, "free");
+
        mutex_lock(&vdev->bo_list_lock);
        list_del(&bo->bo_list_node);
        mutex_unlock(&vdev->bo_list_lock);
 
        drm_WARN_ON(&vdev->drm, !dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ));
 
-       ivpu_dbg_bo(vdev, bo, "free");
-
-       ivpu_bo_unbind(bo);
+       ivpu_bo_unbind_locked(bo);
        mutex_destroy(&bo->lock);
 
        drm_WARN_ON(obj->dev, bo->base.pages_use_count > 1);
        drm_gem_shmem_free(&bo->base);
 }
 
-static const struct dma_buf_ops ivpu_bo_dmabuf_ops =  {
-       .cache_sgt_mapping = true,
-       .attach = drm_gem_map_attach,
-       .detach = drm_gem_map_detach,
-       .map_dma_buf = drm_gem_map_dma_buf,
-       .unmap_dma_buf = drm_gem_unmap_dma_buf,
-       .release = drm_gem_dmabuf_release,
-       .mmap = drm_gem_dmabuf_mmap,
-       .vmap = drm_gem_dmabuf_vmap,
-       .vunmap = drm_gem_dmabuf_vunmap,
-};
-
-static struct dma_buf *ivpu_bo_export(struct drm_gem_object *obj, int flags)
-{
-       struct drm_device *dev = obj->dev;
-       struct dma_buf_export_info exp_info = {
-               .exp_name = KBUILD_MODNAME,
-               .owner = dev->driver->fops->owner,
-               .ops = &ivpu_bo_dmabuf_ops,
-               .size = obj->size,
-               .flags = flags,
-               .priv = obj,
-               .resv = obj->resv,
-       };
-       void *sgt;
-
-       /*
-        * Make sure that pages are allocated and dma-mapped before exporting the bo.
-        * DMA-mapping is required if the bo will be imported to the same device.
-        */
-       sgt = drm_gem_shmem_get_pages_sgt(to_drm_gem_shmem_obj(obj));
-       if (IS_ERR(sgt))
-               return sgt;
-
-       return drm_gem_dmabuf_export(dev, &exp_info);
-}
-
 static const struct drm_gem_object_funcs ivpu_gem_funcs = {
        .free = ivpu_bo_free,
        .open = ivpu_bo_open,
-       .export = ivpu_bo_export,
        .print_info = drm_gem_shmem_object_print_info,
        .pin = drm_gem_shmem_object_pin,
        .unpin = drm_gem_shmem_object_unpin,
@@ -315,11 +279,9 @@ int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fi
                return PTR_ERR(bo);
        }
 
-       ret = drm_gem_handle_create(file, &bo->base.base, &bo->handle);
-       if (!ret) {
+       ret = drm_gem_handle_create(file, &bo->base.base, &args->handle);
+       if (!ret)
                args->vpu_addr = bo->vpu_addr;
-               args->handle = bo->handle;
-       }
 
        drm_gem_object_put(&bo->base.base);
 
@@ -361,7 +323,9 @@ ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 fla
        if (ret)
                goto err_put;
 
+       dma_resv_lock(bo->base.base.resv, NULL);
        ret = drm_gem_shmem_vmap(&bo->base, &map);
+       dma_resv_unlock(bo->base.base.resv);
        if (ret)
                goto err_put;
 
@@ -376,7 +340,10 @@ void ivpu_bo_free_internal(struct ivpu_bo *bo)
 {
        struct iosys_map map = IOSYS_MAP_INIT_VADDR(bo->base.vaddr);
 
+       dma_resv_lock(bo->base.base.resv, NULL);
        drm_gem_shmem_vunmap(&bo->base, &map);
+       dma_resv_unlock(bo->base.base.resv);
+
        drm_gem_object_put(&bo->base.base);
 }
 
@@ -432,19 +399,11 @@ int ivpu_bo_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file
 
 static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p)
 {
-       unsigned long dma_refcount = 0;
-
        mutex_lock(&bo->lock);
 
-       if (bo->base.base.dma_buf && bo->base.base.dma_buf->file)
-               dma_refcount = atomic_long_read(&bo->base.base.dma_buf->file->f_count);
-
-       drm_printf(p, "%-3u %-6d 0x%-12llx %-10lu 0x%-8x %-4u %-8lu",
-                  bo->ctx->id, bo->handle, bo->vpu_addr, bo->base.base.size,
-                  bo->flags, kref_read(&bo->base.base.refcount), dma_refcount);
-
-       if (bo->base.base.import_attach)
-               drm_printf(p, " imported");
+       drm_printf(p, "%-9p %-3u 0x%-12llx %-10lu 0x%-8x %-4u",
+                  bo, bo->ctx->id, bo->vpu_addr, bo->base.base.size,
+                  bo->flags, kref_read(&bo->base.base.refcount));
 
        if (bo->base.pages)
                drm_printf(p, " has_pages");
@@ -452,6 +411,9 @@ static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p)
        if (bo->mmu_mapped)
                drm_printf(p, " mmu_mapped");
 
+       if (bo->base.base.import_attach)
+               drm_printf(p, " imported");
+
        drm_printf(p, "\n");
 
        mutex_unlock(&bo->lock);
@@ -462,8 +424,8 @@ void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p)
        struct ivpu_device *vdev = to_ivpu_device(dev);
        struct ivpu_bo *bo;
 
-       drm_printf(p, "%-3s %-6s %-14s %-10s %-10s %-4s %-8s %s\n",
-                  "ctx", "handle", "vpu_addr", "size", "flags", "refs", "dma_refs", "attribs");
+       drm_printf(p, "%-9s %-3s %-14s %-10s %-10s %-4s %s\n",
+                  "bo", "ctx", "vpu_addr", "size", "flags", "refs", "attribs");
 
        mutex_lock(&vdev->bo_list_lock);
        list_for_each_entry(bo, &vdev->bo_list, bo_list_node)
index d75cad0d3c742db703dbe0812a0df6eaaba24d53..a8559211c70d41ac20bae1da57d846ffd4d7e3b3 100644 (file)
@@ -19,14 +19,13 @@ struct ivpu_bo {
 
        struct mutex lock; /* Protects: ctx, mmu_mapped, vpu_addr */
        u64 vpu_addr;
-       u32 handle;
        u32 flags;
        u32 job_status; /* Valid only for command buffer */
        bool mmu_mapped;
 };
 
 int ivpu_bo_pin(struct ivpu_bo *bo);
-void ivpu_bo_remove_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx);
+void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx);
 
 struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size);
 struct ivpu_bo *ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 flags);
index 574cdeefb66b39af45beda6534a6ac3eb0e57c7b..f15a93d83057822f2414aedb22359063fb99c6a1 100644 (file)
@@ -875,24 +875,18 @@ static void ivpu_hw_37xx_irq_disable(struct ivpu_device *vdev)
 
 static void ivpu_hw_37xx_irq_wdt_nce_handler(struct ivpu_device *vdev)
 {
-       ivpu_err_ratelimited(vdev, "WDT NCE irq\n");
-
-       ivpu_pm_schedule_recovery(vdev);
+       ivpu_pm_trigger_recovery(vdev, "WDT NCE IRQ");
 }
 
 static void ivpu_hw_37xx_irq_wdt_mss_handler(struct ivpu_device *vdev)
 {
-       ivpu_err_ratelimited(vdev, "WDT MSS irq\n");
-
        ivpu_hw_wdt_disable(vdev);
-       ivpu_pm_schedule_recovery(vdev);
+       ivpu_pm_trigger_recovery(vdev, "WDT MSS IRQ");
 }
 
 static void ivpu_hw_37xx_irq_noc_firewall_handler(struct ivpu_device *vdev)
 {
-       ivpu_err_ratelimited(vdev, "NOC Firewall irq\n");
-
-       ivpu_pm_schedule_recovery(vdev);
+       ivpu_pm_trigger_recovery(vdev, "NOC Firewall IRQ");
 }
 
 /* Handler for IRQs from VPU core (irqV) */
@@ -970,7 +964,7 @@ static bool ivpu_hw_37xx_irqb_handler(struct ivpu_device *vdev, int irq)
                REGB_WR32(VPU_37XX_BUTTRESS_INTERRUPT_STAT, status);
 
        if (schedule_recovery)
-               ivpu_pm_schedule_recovery(vdev);
+               ivpu_pm_trigger_recovery(vdev, "Buttress IRQ");
 
        return true;
 }
index eba2fdef2ace1384c93c1cbb30a8e3d9633abba8..704288084f37379eb6c7a1a5beb8f58ec3cea4a2 100644 (file)
@@ -746,7 +746,7 @@ static int ivpu_hw_40xx_info_init(struct ivpu_device *vdev)
        return 0;
 }
 
-static int ivpu_hw_40xx_reset(struct ivpu_device *vdev)
+static int ivpu_hw_40xx_ip_reset(struct ivpu_device *vdev)
 {
        int ret;
        u32 val;
@@ -768,6 +768,23 @@ static int ivpu_hw_40xx_reset(struct ivpu_device *vdev)
        return ret;
 }
 
+static int ivpu_hw_40xx_reset(struct ivpu_device *vdev)
+{
+       int ret = 0;
+
+       if (ivpu_hw_40xx_ip_reset(vdev)) {
+               ivpu_err(vdev, "Failed to reset VPU IP\n");
+               ret = -EIO;
+       }
+
+       if (ivpu_pll_disable(vdev)) {
+               ivpu_err(vdev, "Failed to disable PLL\n");
+               ret = -EIO;
+       }
+
+       return ret;
+}
+
 static int ivpu_hw_40xx_d0i3_enable(struct ivpu_device *vdev)
 {
        int ret;
@@ -913,7 +930,7 @@ static int ivpu_hw_40xx_power_down(struct ivpu_device *vdev)
 
        ivpu_hw_40xx_save_d0i3_entry_timestamp(vdev);
 
-       if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_reset(vdev))
+       if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_ip_reset(vdev))
                ivpu_warn(vdev, "Failed to reset the VPU\n");
 
        if (ivpu_pll_disable(vdev)) {
@@ -1032,18 +1049,18 @@ static void ivpu_hw_40xx_irq_disable(struct ivpu_device *vdev)
 static void ivpu_hw_40xx_irq_wdt_nce_handler(struct ivpu_device *vdev)
 {
        /* TODO: For LNN hang consider engine reset instead of full recovery */
-       ivpu_pm_schedule_recovery(vdev);
+       ivpu_pm_trigger_recovery(vdev, "WDT NCE IRQ");
 }
 
 static void ivpu_hw_40xx_irq_wdt_mss_handler(struct ivpu_device *vdev)
 {
        ivpu_hw_wdt_disable(vdev);
-       ivpu_pm_schedule_recovery(vdev);
+       ivpu_pm_trigger_recovery(vdev, "WDT MSS IRQ");
 }
 
 static void ivpu_hw_40xx_irq_noc_firewall_handler(struct ivpu_device *vdev)
 {
-       ivpu_pm_schedule_recovery(vdev);
+       ivpu_pm_trigger_recovery(vdev, "NOC Firewall IRQ");
 }
 
 /* Handler for IRQs from VPU core (irqV) */
@@ -1137,7 +1154,7 @@ static bool ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq)
        REGB_WR32(VPU_40XX_BUTTRESS_INTERRUPT_STAT, status);
 
        if (schedule_recovery)
-               ivpu_pm_schedule_recovery(vdev);
+               ivpu_pm_trigger_recovery(vdev, "Buttress IRQ");
 
        return true;
 }
index e86621f16f85a8d5d41f0d5dcf1ef99d1e45541d..fa66c39b57ecaaecae036d17f79c3e7683fc5279 100644 (file)
@@ -343,10 +343,8 @@ int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *r
        hb_ret = ivpu_ipc_send_receive_internal(vdev, &hb_req, VPU_JSM_MSG_QUERY_ENGINE_HB_DONE,
                                                &hb_resp, VPU_IPC_CHAN_ASYNC_CMD,
                                                vdev->timeout.jsm);
-       if (hb_ret == -ETIMEDOUT) {
-               ivpu_hw_diagnose_failure(vdev);
-               ivpu_pm_schedule_recovery(vdev);
-       }
+       if (hb_ret == -ETIMEDOUT)
+               ivpu_pm_trigger_recovery(vdev, "IPC timeout");
 
        return ret;
 }
index 7206cf9cdb4a45335b220796621fcd2c55a8ddf0..0440bee3ecafd567da6cbf47584f3daa688b618d 100644 (file)
@@ -112,22 +112,20 @@ static void ivpu_cmdq_release_locked(struct ivpu_file_priv *file_priv, u16 engin
        }
 }
 
-void ivpu_cmdq_release_all(struct ivpu_file_priv *file_priv)
+void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv)
 {
        int i;
 
-       mutex_lock(&file_priv->lock);
+       lockdep_assert_held(&file_priv->lock);
 
        for (i = 0; i < IVPU_NUM_ENGINES; i++)
                ivpu_cmdq_release_locked(file_priv, i);
-
-       mutex_unlock(&file_priv->lock);
 }
 
 /*
  * Mark the doorbell as unregistered and reset job queue pointers.
  * This function needs to be called when the VPU hardware is restarted
- * and FW looses job queue state. The next time job queue is used it
+ * and FW loses job queue state. The next time job queue is used it
  * will be registered again.
  */
 static void ivpu_cmdq_reset_locked(struct ivpu_file_priv *file_priv, u16 engine)
@@ -161,15 +159,13 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev)
        struct ivpu_file_priv *file_priv;
        unsigned long ctx_id;
 
-       xa_for_each(&vdev->context_xa, ctx_id, file_priv) {
-               file_priv = ivpu_file_priv_get_by_ctx_id(vdev, ctx_id);
-               if (!file_priv)
-                       continue;
+       mutex_lock(&vdev->context_list_lock);
 
+       xa_for_each(&vdev->context_xa, ctx_id, file_priv)
                ivpu_cmdq_reset_all(file_priv);
 
-               ivpu_file_priv_put(&file_priv);
-       }
+       mutex_unlock(&vdev->context_list_lock);
+
 }
 
 static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job)
@@ -243,60 +239,32 @@ static struct dma_fence *ivpu_fence_create(struct ivpu_device *vdev)
        return &fence->base;
 }
 
-static void job_get(struct ivpu_job *job, struct ivpu_job **link)
+static void ivpu_job_destroy(struct ivpu_job *job)
 {
        struct ivpu_device *vdev = job->vdev;
-
-       kref_get(&job->ref);
-       *link = job;
-
-       ivpu_dbg(vdev, KREF, "Job get: id %u refcount %u\n", job->job_id, kref_read(&job->ref));
-}
-
-static void job_release(struct kref *ref)
-{
-       struct ivpu_job *job = container_of(ref, struct ivpu_job, ref);
-       struct ivpu_device *vdev = job->vdev;
        u32 i;
 
+       ivpu_dbg(vdev, JOB, "Job destroyed: id %3u ctx %2d engine %d",
+                job->job_id, job->file_priv->ctx.id, job->engine_idx);
+
        for (i = 0; i < job->bo_count; i++)
                if (job->bos[i])
                        drm_gem_object_put(&job->bos[i]->base.base);
 
        dma_fence_put(job->done_fence);
        ivpu_file_priv_put(&job->file_priv);
-
-       ivpu_dbg(vdev, KREF, "Job released: id %u\n", job->job_id);
        kfree(job);
-
-       /* Allow the VPU to get suspended, must be called after ivpu_file_priv_put() */
-       ivpu_rpm_put(vdev);
-}
-
-static void job_put(struct ivpu_job *job)
-{
-       struct ivpu_device *vdev = job->vdev;
-
-       ivpu_dbg(vdev, KREF, "Job put: id %u refcount %u\n", job->job_id, kref_read(&job->ref));
-       kref_put(&job->ref, job_release);
 }
 
 static struct ivpu_job *
-ivpu_create_job(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count)
+ivpu_job_create(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count)
 {
        struct ivpu_device *vdev = file_priv->vdev;
        struct ivpu_job *job;
-       int ret;
-
-       ret = ivpu_rpm_get(vdev);
-       if (ret < 0)
-               return NULL;
 
        job = kzalloc(struct_size(job, bos, bo_count), GFP_KERNEL);
        if (!job)
-               goto err_rpm_put;
-
-       kref_init(&job->ref);
+               return NULL;
 
        job->vdev = vdev;
        job->engine_idx = engine_idx;
@@ -310,17 +278,14 @@ ivpu_create_job(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count)
        job->file_priv = ivpu_file_priv_get(file_priv);
 
        ivpu_dbg(vdev, JOB, "Job created: ctx %2d engine %d", file_priv->ctx.id, job->engine_idx);
-
        return job;
 
 err_free_job:
        kfree(job);
-err_rpm_put:
-       ivpu_rpm_put(vdev);
        return NULL;
 }
 
-static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status)
+static int ivpu_job_signal_and_destroy(struct ivpu_device *vdev, u32 job_id, u32 job_status)
 {
        struct ivpu_job *job;
 
@@ -337,9 +302,10 @@ static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status)
        ivpu_dbg(vdev, JOB, "Job complete:  id %3u ctx %2d engine %d status 0x%x\n",
                 job->job_id, job->file_priv->ctx.id, job->engine_idx, job_status);
 
+       ivpu_job_destroy(job);
        ivpu_stop_job_timeout_detection(vdev);
 
-       job_put(job);
+       ivpu_rpm_put(vdev);
        return 0;
 }
 
@@ -349,10 +315,10 @@ void ivpu_jobs_abort_all(struct ivpu_device *vdev)
        unsigned long id;
 
        xa_for_each(&vdev->submitted_jobs_xa, id, job)
-               ivpu_job_done(vdev, id, VPU_JSM_STATUS_ABORTED);
+               ivpu_job_signal_and_destroy(vdev, id, VPU_JSM_STATUS_ABORTED);
 }
 
-static int ivpu_direct_job_submission(struct ivpu_job *job)
+static int ivpu_job_submit(struct ivpu_job *job)
 {
        struct ivpu_file_priv *file_priv = job->file_priv;
        struct ivpu_device *vdev = job->vdev;
@@ -360,53 +326,65 @@ static int ivpu_direct_job_submission(struct ivpu_job *job)
        struct ivpu_cmdq *cmdq;
        int ret;
 
+       ret = ivpu_rpm_get(vdev);
+       if (ret < 0)
+               return ret;
+
        mutex_lock(&file_priv->lock);
 
        cmdq = ivpu_cmdq_acquire(job->file_priv, job->engine_idx);
        if (!cmdq) {
-               ivpu_warn(vdev, "Failed get job queue, ctx %d engine %d\n",
-                         file_priv->ctx.id, job->engine_idx);
+               ivpu_warn_ratelimited(vdev, "Failed get job queue, ctx %d engine %d\n",
+                                     file_priv->ctx.id, job->engine_idx);
                ret = -EINVAL;
-               goto err_unlock;
+               goto err_unlock_file_priv;
        }
 
        job_id_range.min = FIELD_PREP(JOB_ID_CONTEXT_MASK, (file_priv->ctx.id - 1));
        job_id_range.max = job_id_range.min | JOB_ID_JOB_MASK;
 
-       job_get(job, &job);
-       ret = xa_alloc(&vdev->submitted_jobs_xa, &job->job_id, job, job_id_range, GFP_KERNEL);
+       xa_lock(&vdev->submitted_jobs_xa);
+       ret = __xa_alloc(&vdev->submitted_jobs_xa, &job->job_id, job, job_id_range, GFP_KERNEL);
        if (ret) {
-               ivpu_warn_ratelimited(vdev, "Failed to allocate job id: %d\n", ret);
-               goto err_job_put;
+               ivpu_dbg(vdev, JOB, "Too many active jobs in ctx %d\n",
+                        file_priv->ctx.id);
+               ret = -EBUSY;
+               goto err_unlock_submitted_jobs_xa;
        }
 
        ret = ivpu_cmdq_push_job(cmdq, job);
        if (ret)
-               goto err_xa_erase;
+               goto err_erase_xa;
 
        ivpu_start_job_timeout_detection(vdev);
 
-       ivpu_dbg(vdev, JOB, "Job submitted: id %3u addr 0x%llx ctx %2d engine %d next %d\n",
-                job->job_id, job->cmd_buf_vpu_addr, file_priv->ctx.id,
-                job->engine_idx, cmdq->jobq->header.tail);
-
-       if (ivpu_test_mode & IVPU_TEST_MODE_NULL_HW) {
-               ivpu_job_done(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS);
+       if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_HW)) {
                cmdq->jobq->header.head = cmdq->jobq->header.tail;
                wmb(); /* Flush WC buffer for jobq header */
        } else {
                ivpu_cmdq_ring_db(vdev, cmdq);
        }
 
+       ivpu_dbg(vdev, JOB, "Job submitted: id %3u ctx %2d engine %d addr 0x%llx next %d\n",
+                job->job_id, file_priv->ctx.id, job->engine_idx,
+                job->cmd_buf_vpu_addr, cmdq->jobq->header.tail);
+
+       xa_unlock(&vdev->submitted_jobs_xa);
+
        mutex_unlock(&file_priv->lock);
+
+       if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_HW))
+               ivpu_job_signal_and_destroy(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS);
+
        return 0;
 
-err_xa_erase:
-       xa_erase(&vdev->submitted_jobs_xa, job->job_id);
-err_job_put:
-       job_put(job);
-err_unlock:
+err_erase_xa:
+       __xa_erase(&vdev->submitted_jobs_xa, job->job_id);
+err_unlock_submitted_jobs_xa:
+       xa_unlock(&vdev->submitted_jobs_xa);
+err_unlock_file_priv:
        mutex_unlock(&file_priv->lock);
+       ivpu_rpm_put(vdev);
        return ret;
 }
 
@@ -488,6 +466,9 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
        if (params->engine > DRM_IVPU_ENGINE_COPY)
                return -EINVAL;
 
+       if (params->priority > DRM_IVPU_JOB_PRIORITY_REALTIME)
+               return -EINVAL;
+
        if (params->buffer_count == 0 || params->buffer_count > JOB_MAX_BUFFER_COUNT)
                return -EINVAL;
 
@@ -509,44 +490,49 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
                             params->buffer_count * sizeof(u32));
        if (ret) {
                ret = -EFAULT;
-               goto free_handles;
+               goto err_free_handles;
        }
 
        if (!drm_dev_enter(&vdev->drm, &idx)) {
                ret = -ENODEV;
-               goto free_handles;
+               goto err_free_handles;
        }
 
        ivpu_dbg(vdev, JOB, "Submit ioctl: ctx %u buf_count %u\n",
                 file_priv->ctx.id, params->buffer_count);
 
-       job = ivpu_create_job(file_priv, params->engine, params->buffer_count);
+       job = ivpu_job_create(file_priv, params->engine, params->buffer_count);
        if (!job) {
                ivpu_err(vdev, "Failed to create job\n");
                ret = -ENOMEM;
-               goto dev_exit;
+               goto err_exit_dev;
        }
 
        ret = ivpu_job_prepare_bos_for_submit(file, job, buf_handles, params->buffer_count,
                                              params->commands_offset);
        if (ret) {
-               ivpu_err(vdev, "Failed to prepare job, ret %d\n", ret);
-               goto job_put;
+               ivpu_err(vdev, "Failed to prepare job: %d\n", ret);
+               goto err_destroy_job;
        }
 
-       ret = ivpu_direct_job_submission(job);
-       if (ret) {
-               dma_fence_signal(job->done_fence);
-               ivpu_err(vdev, "Failed to submit job to the HW, ret %d\n", ret);
-       }
+       down_read(&vdev->pm->reset_lock);
+       ret = ivpu_job_submit(job);
+       up_read(&vdev->pm->reset_lock);
+       if (ret)
+               goto err_signal_fence;
 
-job_put:
-       job_put(job);
-dev_exit:
        drm_dev_exit(idx);
-free_handles:
        kfree(buf_handles);
+       return ret;
 
+err_signal_fence:
+       dma_fence_signal(job->done_fence);
+err_destroy_job:
+       ivpu_job_destroy(job);
+err_exit_dev:
+       drm_dev_exit(idx);
+err_free_handles:
+       kfree(buf_handles);
        return ret;
 }
 
@@ -568,7 +554,7 @@ ivpu_job_done_callback(struct ivpu_device *vdev, struct ivpu_ipc_hdr *ipc_hdr,
        }
 
        payload = (struct vpu_ipc_msg_payload_job_done *)&jsm_msg->payload;
-       ret = ivpu_job_done(vdev, payload->job_id, payload->job_status);
+       ret = ivpu_job_signal_and_destroy(vdev, payload->job_id, payload->job_status);
        if (!ret && !xa_empty(&vdev->submitted_jobs_xa))
                ivpu_start_job_timeout_detection(vdev);
 }
index 45a2f2ec82e5ba69110d737e154c38bf6765174a..ca4984071cc76b17d858ae86929a48a9cea39c88 100644 (file)
@@ -43,7 +43,6 @@ struct ivpu_cmdq {
                          will update the job status
  */
 struct ivpu_job {
-       struct kref ref;
        struct ivpu_device *vdev;
        struct ivpu_file_priv *file_priv;
        struct dma_fence *done_fence;
@@ -56,7 +55,7 @@ struct ivpu_job {
 
 int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file);
 
-void ivpu_cmdq_release_all(struct ivpu_file_priv *file_priv);
+void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv);
 void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev);
 
 void ivpu_job_done_consumer_init(struct ivpu_device *vdev);
index 2228c44b115fa0e4d48f36c115e2fdc7b434a8c0..9a3122ffce03c1dc11311ab36f31f775f4fdf6fe 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/highmem.h>
 
 #include "ivpu_drv.h"
+#include "ivpu_hw.h"
 #include "ivpu_hw_reg_io.h"
 #include "ivpu_mmu.h"
 #include "ivpu_mmu_context.h"
@@ -518,6 +519,7 @@ static int ivpu_mmu_cmdq_sync(struct ivpu_device *vdev)
 
                ivpu_err(vdev, "Timed out waiting for MMU consumer: %d, error: %s\n", ret,
                         ivpu_mmu_cmdq_err_to_str(err));
+               ivpu_hw_diagnose_failure(vdev);
        }
 
        return ret;
@@ -885,7 +887,6 @@ static u32 *ivpu_mmu_get_event(struct ivpu_device *vdev)
 
 void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev)
 {
-       bool schedule_recovery = false;
        u32 *event;
        u32 ssid;
 
@@ -895,14 +896,21 @@ void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev)
                ivpu_mmu_dump_event(vdev, event);
 
                ssid = FIELD_GET(IVPU_MMU_EVT_SSID_MASK, event[0]);
-               if (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID)
-                       schedule_recovery = true;
-               else
-                       ivpu_mmu_user_context_mark_invalid(vdev, ssid);
+               if (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID) {
+                       ivpu_pm_trigger_recovery(vdev, "MMU event");
+                       return;
+               }
+
+               ivpu_mmu_user_context_mark_invalid(vdev, ssid);
        }
+}
 
-       if (schedule_recovery)
-               ivpu_pm_schedule_recovery(vdev);
+void ivpu_mmu_evtq_dump(struct ivpu_device *vdev)
+{
+       u32 *event;
+
+       while ((event = ivpu_mmu_get_event(vdev)) != NULL)
+               ivpu_mmu_dump_event(vdev, event);
 }
 
 void ivpu_mmu_irq_gerr_handler(struct ivpu_device *vdev)
index cb551126806baa9bb47a967c7bff916b444c2427..6fa35c240710625670b6879098833c6cd680fb40 100644 (file)
@@ -46,5 +46,6 @@ int ivpu_mmu_invalidate_tlb(struct ivpu_device *vdev, u16 ssid);
 
 void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev);
 void ivpu_mmu_irq_gerr_handler(struct ivpu_device *vdev);
+void ivpu_mmu_evtq_dump(struct ivpu_device *vdev);
 
 #endif /* __IVPU_MMU_H__ */
index 12a8c09d4547d7d9b81cd91d93307e59e648e14f..fe61612992364c65d184eef9c3a3ad3ebb60ce6a 100644 (file)
@@ -355,6 +355,9 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
                dma_addr_t dma_addr = sg_dma_address(sg) - sg->offset;
                size_t size = sg_dma_len(sg) + sg->offset;
 
+               ivpu_dbg(vdev, MMU_MAP, "Map ctx: %u dma_addr: 0x%llx vpu_addr: 0x%llx size: %lu\n",
+                        ctx->id, dma_addr, vpu_addr, size);
+
                ret = ivpu_mmu_context_map_pages(vdev, ctx, vpu_addr, dma_addr, size, prot);
                if (ret) {
                        ivpu_err(vdev, "Failed to map context pages\n");
@@ -366,6 +369,7 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
 
        /* Ensure page table modifications are flushed from wc buffers to memory */
        wmb();
+
        mutex_unlock(&ctx->lock);
 
        ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id);
@@ -388,14 +392,19 @@ ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ct
        mutex_lock(&ctx->lock);
 
        for_each_sgtable_dma_sg(sgt, sg, i) {
+               dma_addr_t dma_addr = sg_dma_address(sg) - sg->offset;
                size_t size = sg_dma_len(sg) + sg->offset;
 
+               ivpu_dbg(vdev, MMU_MAP, "Unmap ctx: %u dma_addr: 0x%llx vpu_addr: 0x%llx size: %lu\n",
+                        ctx->id, dma_addr, vpu_addr, size);
+
                ivpu_mmu_context_unmap_pages(ctx, vpu_addr, size);
                vpu_addr += size;
        }
 
        /* Ensure page table modifications are flushed from wc buffers to memory */
        wmb();
+
        mutex_unlock(&ctx->lock);
 
        ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id);
index 0af8864cb3b55f636bc7418a03dc3c07360e7ac8..f501f27ebafdf6687b5a46ca7e2387faa931af3e 100644 (file)
@@ -13,6 +13,7 @@
 #include "ivpu_drv.h"
 #include "ivpu_hw.h"
 #include "ivpu_fw.h"
+#include "ivpu_fw_log.h"
 #include "ivpu_ipc.h"
 #include "ivpu_job.h"
 #include "ivpu_jsm_msg.h"
@@ -111,6 +112,14 @@ static void ivpu_pm_recovery_work(struct work_struct *work)
        char *evt[2] = {"IVPU_PM_EVENT=IVPU_RECOVER", NULL};
        int ret;
 
+       ivpu_err(vdev, "Recovering the VPU (reset #%d)\n", atomic_read(&vdev->pm->reset_counter));
+
+       ret = pm_runtime_resume_and_get(vdev->drm.dev);
+       if (ret)
+               ivpu_err(vdev, "Failed to resume VPU: %d\n", ret);
+
+       ivpu_fw_log_dump(vdev);
+
 retry:
        ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev));
        if (ret == -EAGAIN && !drm_dev_is_unplugged(&vdev->drm)) {
@@ -122,11 +131,13 @@ retry:
                ivpu_err(vdev, "Failed to reset VPU: %d\n", ret);
 
        kobject_uevent_env(&vdev->drm.dev->kobj, KOBJ_CHANGE, evt);
+       pm_runtime_mark_last_busy(vdev->drm.dev);
+       pm_runtime_put_autosuspend(vdev->drm.dev);
 }
 
-void ivpu_pm_schedule_recovery(struct ivpu_device *vdev)
+void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason)
 {
-       struct ivpu_pm_info *pm = vdev->pm;
+       ivpu_err(vdev, "Recovery triggered by %s\n", reason);
 
        if (ivpu_disable_recovery) {
                ivpu_err(vdev, "Recovery not available when disable_recovery param is set\n");
@@ -138,10 +149,11 @@ void ivpu_pm_schedule_recovery(struct ivpu_device *vdev)
                return;
        }
 
-       /* Schedule recovery if it's not in progress */
-       if (atomic_cmpxchg(&pm->in_reset, 0, 1) == 0) {
-               ivpu_hw_irq_disable(vdev);
-               queue_work(system_long_wq, &pm->recovery_work);
+       /* Trigger recovery if it's not in progress */
+       if (atomic_cmpxchg(&vdev->pm->reset_pending, 0, 1) == 0) {
+               ivpu_hw_diagnose_failure(vdev);
+               ivpu_hw_irq_disable(vdev); /* Disable IRQ early to protect from IRQ storm */
+               queue_work(system_long_wq, &vdev->pm->recovery_work);
        }
 }
 
@@ -149,12 +161,8 @@ static void ivpu_job_timeout_work(struct work_struct *work)
 {
        struct ivpu_pm_info *pm = container_of(work, struct ivpu_pm_info, job_timeout_work.work);
        struct ivpu_device *vdev = pm->vdev;
-       unsigned long timeout_ms = ivpu_tdr_timeout_ms ? ivpu_tdr_timeout_ms : vdev->timeout.tdr;
 
-       ivpu_err(vdev, "TDR detected, timeout %lu ms", timeout_ms);
-       ivpu_hw_diagnose_failure(vdev);
-
-       ivpu_pm_schedule_recovery(vdev);
+       ivpu_pm_trigger_recovery(vdev, "TDR");
 }
 
 void ivpu_start_job_timeout_detection(struct ivpu_device *vdev)
@@ -227,6 +235,9 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev)
        bool hw_is_idle = true;
        int ret;
 
+       drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa));
+       drm_WARN_ON(&vdev->drm, work_pending(&vdev->pm->recovery_work));
+
        ivpu_dbg(vdev, PM, "Runtime suspend..\n");
 
        if (!ivpu_hw_is_idle(vdev) && vdev->pm->suspend_reschedule_counter) {
@@ -247,7 +258,8 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev)
                ivpu_err(vdev, "Failed to set suspend VPU: %d\n", ret);
 
        if (!hw_is_idle) {
-               ivpu_warn(vdev, "VPU failed to enter idle, force suspended.\n");
+               ivpu_err(vdev, "VPU failed to enter idle, force suspended.\n");
+               ivpu_fw_log_dump(vdev);
                ivpu_pm_prepare_cold_boot(vdev);
        } else {
                ivpu_pm_prepare_warm_boot(vdev);
@@ -308,11 +320,12 @@ void ivpu_pm_reset_prepare_cb(struct pci_dev *pdev)
 {
        struct ivpu_device *vdev = pci_get_drvdata(pdev);
 
-       pm_runtime_get_sync(vdev->drm.dev);
-
        ivpu_dbg(vdev, PM, "Pre-reset..\n");
        atomic_inc(&vdev->pm->reset_counter);
-       atomic_set(&vdev->pm->in_reset, 1);
+       atomic_set(&vdev->pm->reset_pending, 1);
+
+       pm_runtime_get_sync(vdev->drm.dev);
+       down_write(&vdev->pm->reset_lock);
        ivpu_prepare_for_reset(vdev);
        ivpu_hw_reset(vdev);
        ivpu_pm_prepare_cold_boot(vdev);
@@ -329,9 +342,11 @@ void ivpu_pm_reset_done_cb(struct pci_dev *pdev)
        ret = ivpu_resume(vdev);
        if (ret)
                ivpu_err(vdev, "Failed to set RESUME state: %d\n", ret);
-       atomic_set(&vdev->pm->in_reset, 0);
+       up_write(&vdev->pm->reset_lock);
+       atomic_set(&vdev->pm->reset_pending, 0);
        ivpu_dbg(vdev, PM, "Post-reset done.\n");
 
+       pm_runtime_mark_last_busy(vdev->drm.dev);
        pm_runtime_put_autosuspend(vdev->drm.dev);
 }
 
@@ -344,7 +359,10 @@ void ivpu_pm_init(struct ivpu_device *vdev)
        pm->vdev = vdev;
        pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT;
 
-       atomic_set(&pm->in_reset, 0);
+       init_rwsem(&pm->reset_lock);
+       atomic_set(&pm->reset_pending, 0);
+       atomic_set(&pm->reset_counter, 0);
+
        INIT_WORK(&pm->recovery_work, ivpu_pm_recovery_work);
        INIT_DELAYED_WORK(&pm->job_timeout_work, ivpu_job_timeout_work);
 
index 97c6e0b0aa42d0a5a071940c5b54a052f99a748c..ec60fbeefefc65bbca4ed619d7265aabffd1bb61 100644 (file)
@@ -6,6 +6,7 @@
 #ifndef __IVPU_PM_H__
 #define __IVPU_PM_H__
 
+#include <linux/rwsem.h>
 #include <linux/types.h>
 
 struct ivpu_device;
@@ -14,8 +15,9 @@ struct ivpu_pm_info {
        struct ivpu_device *vdev;
        struct delayed_work job_timeout_work;
        struct work_struct recovery_work;
-       atomic_t in_reset;
+       struct rw_semaphore reset_lock;
        atomic_t reset_counter;
+       atomic_t reset_pending;
        bool is_warmboot;
        u32 suspend_reschedule_counter;
 };
@@ -37,7 +39,7 @@ int __must_check ivpu_rpm_get(struct ivpu_device *vdev);
 int __must_check ivpu_rpm_get_if_active(struct ivpu_device *vdev);
 void ivpu_rpm_put(struct ivpu_device *vdev);
 
-void ivpu_pm_schedule_recovery(struct ivpu_device *vdev);
+void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason);
 void ivpu_start_job_timeout_detection(struct ivpu_device *vdev);
 void ivpu_stop_job_timeout_detection(struct ivpu_device *vdev);
 
index 3a5f3255f51b39cc4a5b65554e7d55eed8ea2c57..da2e74fce2d995a932914876b44b3fb5d4275d2e 100644 (file)
@@ -48,6 +48,7 @@ enum {
 enum board_ids {
        /* board IDs by feature in alphabetical order */
        board_ahci,
+       board_ahci_43bit_dma,
        board_ahci_ign_iferr,
        board_ahci_low_power,
        board_ahci_no_debounce_delay,
@@ -128,6 +129,13 @@ static const struct ata_port_info ahci_port_info[] = {
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
        },
+       [board_ahci_43bit_dma] = {
+               AHCI_HFLAGS     (AHCI_HFLAG_43BIT_ONLY),
+               .flags          = AHCI_FLAG_COMMON,
+               .pio_mask       = ATA_PIO4,
+               .udma_mask      = ATA_UDMA6,
+               .port_ops       = &ahci_ops,
+       },
        [board_ahci_ign_iferr] = {
                AHCI_HFLAGS     (AHCI_HFLAG_IGN_IRQ_IF_ERR),
                .flags          = AHCI_FLAG_COMMON,
@@ -597,14 +605,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },   /* PDC42819 */
        { PCI_VDEVICE(PROMISE, 0x3781), board_ahci },   /* FastTrak TX8660 ahci-mode */
 
-       /* Asmedia */
-       { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci },   /* ASM1060 */
-       { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci },   /* ASM1060 */
-       { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci },   /* ASM1061 */
-       { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci },   /* ASM1062 */
-       { PCI_VDEVICE(ASMEDIA, 0x0621), board_ahci },   /* ASM1061R */
-       { PCI_VDEVICE(ASMEDIA, 0x0622), board_ahci },   /* ASM1062R */
-       { PCI_VDEVICE(ASMEDIA, 0x0624), board_ahci },   /* ASM1062+JMB575 */
+       /* ASMedia */
+       { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci_43bit_dma }, /* ASM1060 */
+       { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci_43bit_dma }, /* ASM1060 */
+       { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci_43bit_dma }, /* ASM1061 */
+       { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci_43bit_dma }, /* ASM1061/1062 */
+       { PCI_VDEVICE(ASMEDIA, 0x0621), board_ahci_43bit_dma }, /* ASM1061R */
+       { PCI_VDEVICE(ASMEDIA, 0x0622), board_ahci_43bit_dma }, /* ASM1062R */
+       { PCI_VDEVICE(ASMEDIA, 0x0624), board_ahci_43bit_dma }, /* ASM1062+JMB575 */
        { PCI_VDEVICE(ASMEDIA, 0x1062), board_ahci },   /* ASM1062A */
        { PCI_VDEVICE(ASMEDIA, 0x1064), board_ahci },   /* ASM1064 */
        { PCI_VDEVICE(ASMEDIA, 0x1164), board_ahci },   /* ASM1164 */
@@ -663,6 +671,11 @@ MODULE_PARM_DESC(mobile_lpm_policy, "Default LPM policy for mobile chipsets");
 static void ahci_pci_save_initial_config(struct pci_dev *pdev,
                                         struct ahci_host_priv *hpriv)
 {
+       if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && pdev->device == 0x1166) {
+               dev_info(&pdev->dev, "ASM1166 has only six ports\n");
+               hpriv->saved_port_map = 0x3f;
+       }
+
        if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
                dev_info(&pdev->dev, "JMB361 has only one port\n");
                hpriv->saved_port_map = 1;
@@ -949,11 +962,20 @@ static int ahci_pci_device_resume(struct device *dev)
 
 #endif /* CONFIG_PM */
 
-static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
+static int ahci_configure_dma_masks(struct pci_dev *pdev,
+                                   struct ahci_host_priv *hpriv)
 {
-       const int dma_bits = using_dac ? 64 : 32;
+       int dma_bits;
        int rc;
 
+       if (hpriv->cap & HOST_CAP_64) {
+               dma_bits = 64;
+               if (hpriv->flags & AHCI_HFLAG_43BIT_ONLY)
+                       dma_bits = 43;
+       } else {
+               dma_bits = 32;
+       }
+
        /*
         * If the device fixup already set the dma_mask to some non-standard
         * value, don't extend it here. This happens on STA2X11, for example.
@@ -1926,7 +1948,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        ahci_gtf_filter_workaround(host);
 
        /* initialize adapter */
-       rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
+       rc = ahci_configure_dma_masks(pdev, hpriv);
        if (rc)
                return rc;
 
index 4bae95b06ae3c953de7a567c35f9b46dd9e3083f..df8f8a1a3a34c3ee26d0d2b899522a82d220b6c2 100644 (file)
@@ -247,6 +247,7 @@ enum {
        AHCI_HFLAG_SUSPEND_PHYS         = BIT(26), /* handle PHYs during
                                                      suspend/resume */
        AHCI_HFLAG_NO_SXS               = BIT(28), /* SXS not supported */
+       AHCI_HFLAG_43BIT_ONLY           = BIT(29), /* 43bit DMA addr limit */
 
        /* ap->flags bits */
 
index b6656c287175c7653324758ccb5422dc36168e3d..0fb1934875f2084a753216cf54ff443aa601361b 100644 (file)
@@ -784,7 +784,7 @@ bool sata_lpm_ignore_phy_events(struct ata_link *link)
 EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events);
 
 static const char *ata_lpm_policy_names[] = {
-       [ATA_LPM_UNKNOWN]               = "max_performance",
+       [ATA_LPM_UNKNOWN]               = "keep_firmware_settings",
        [ATA_LPM_MAX_POWER]             = "max_performance",
        [ATA_LPM_MED_POWER]             = "medium_power",
        [ATA_LPM_MED_POWER_WITH_DIPM]   = "med_power_with_dipm",
index d2dbf8aaccb5b1320909964b3092ea47df90cc4a..b1b47d88f5db44dd9dcb8fc7468718ac36869130 100644 (file)
@@ -333,6 +333,7 @@ aoeblk_gdalloc(void *vp)
        struct gendisk *gd;
        mempool_t *mp;
        struct blk_mq_tag_set *set;
+       sector_t ssize;
        ulong flags;
        int late = 0;
        int err;
@@ -396,7 +397,7 @@ aoeblk_gdalloc(void *vp)
        gd->minors = AOE_PARTITIONS;
        gd->fops = &aoe_bdops;
        gd->private_data = d;
-       set_capacity(gd, d->ssize);
+       ssize = d->ssize;
        snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d",
                d->aoemajor, d->aoeminor);
 
@@ -405,6 +406,8 @@ aoeblk_gdalloc(void *vp)
 
        spin_unlock_irqrestore(&d->lock, flags);
 
+       set_capacity(gd, ssize);
+
        err = device_add_disk(NULL, gd, aoe_attr_groups);
        if (err)
                goto out_disk_cleanup;
index 1f6186475715e0592df1028ade0a336703338b15..1791d37fbc53c57e0f13469934eee357c0de87cc 100644 (file)
@@ -1232,14 +1232,13 @@ static void amd_pstate_epp_update_limit(struct cpufreq_policy *policy)
        max_limit_perf = div_u64(policy->max * cpudata->highest_perf, cpudata->max_freq);
        min_limit_perf = div_u64(policy->min * cpudata->highest_perf, cpudata->max_freq);
 
+       WRITE_ONCE(cpudata->max_limit_perf, max_limit_perf);
+       WRITE_ONCE(cpudata->min_limit_perf, min_limit_perf);
+
        max_perf = clamp_t(unsigned long, max_perf, cpudata->min_limit_perf,
                        cpudata->max_limit_perf);
        min_perf = clamp_t(unsigned long, min_perf, cpudata->min_limit_perf,
                        cpudata->max_limit_perf);
-
-       WRITE_ONCE(cpudata->max_limit_perf, max_limit_perf);
-       WRITE_ONCE(cpudata->min_limit_perf, min_limit_perf);
-
        value = READ_ONCE(cpudata->cppc_req_cached);
 
        if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE)
index 2ca70b0b5fdc5d39990bb88ba4dcd1f7e7131d31..ca94e60e705a1df435b1dd75a13c0a50dc3f8c27 100644 (file)
@@ -529,6 +529,30 @@ static int intel_pstate_cppc_get_scaling(int cpu)
 }
 #endif /* CONFIG_ACPI_CPPC_LIB */
 
+static int intel_pstate_freq_to_hwp_rel(struct cpudata *cpu, int freq,
+                                       unsigned int relation)
+{
+       if (freq == cpu->pstate.turbo_freq)
+               return cpu->pstate.turbo_pstate;
+
+       if (freq == cpu->pstate.max_freq)
+               return cpu->pstate.max_pstate;
+
+       switch (relation) {
+       case CPUFREQ_RELATION_H:
+               return freq / cpu->pstate.scaling;
+       case CPUFREQ_RELATION_C:
+               return DIV_ROUND_CLOSEST(freq, cpu->pstate.scaling);
+       }
+
+       return DIV_ROUND_UP(freq, cpu->pstate.scaling);
+}
+
+static int intel_pstate_freq_to_hwp(struct cpudata *cpu, int freq)
+{
+       return intel_pstate_freq_to_hwp_rel(cpu, freq, CPUFREQ_RELATION_L);
+}
+
 /**
  * intel_pstate_hybrid_hwp_adjust - Calibrate HWP performance levels.
  * @cpu: Target CPU.
@@ -546,6 +570,7 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu)
        int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
        int perf_ctl_turbo = pstate_funcs.get_turbo(cpu->cpu);
        int scaling = cpu->pstate.scaling;
+       int freq;
 
        pr_debug("CPU%d: perf_ctl_max_phys = %d\n", cpu->cpu, perf_ctl_max_phys);
        pr_debug("CPU%d: perf_ctl_turbo = %d\n", cpu->cpu, perf_ctl_turbo);
@@ -559,16 +584,16 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu)
        cpu->pstate.max_freq = rounddown(cpu->pstate.max_pstate * scaling,
                                         perf_ctl_scaling);
 
-       cpu->pstate.max_pstate_physical =
-                       DIV_ROUND_UP(perf_ctl_max_phys * perf_ctl_scaling,
-                                    scaling);
+       freq = perf_ctl_max_phys * perf_ctl_scaling;
+       cpu->pstate.max_pstate_physical = intel_pstate_freq_to_hwp(cpu, freq);
 
-       cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling;
+       freq = cpu->pstate.min_pstate * perf_ctl_scaling;
+       cpu->pstate.min_freq = freq;
        /*
         * Cast the min P-state value retrieved via pstate_funcs.get_min() to
         * the effective range of HWP performance levels.
         */
-       cpu->pstate.min_pstate = DIV_ROUND_UP(cpu->pstate.min_freq, scaling);
+       cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, freq);
 }
 
 static inline void update_turbo_state(void)
@@ -2528,13 +2553,12 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu,
         * abstract values to represent performance rather than pure ratios.
         */
        if (hwp_active && cpu->pstate.scaling != perf_ctl_scaling) {
-               int scaling = cpu->pstate.scaling;
                int freq;
 
                freq = max_policy_perf * perf_ctl_scaling;
-               max_policy_perf = DIV_ROUND_UP(freq, scaling);
+               max_policy_perf = intel_pstate_freq_to_hwp(cpu, freq);
                freq = min_policy_perf * perf_ctl_scaling;
-               min_policy_perf = DIV_ROUND_UP(freq, scaling);
+               min_policy_perf = intel_pstate_freq_to_hwp(cpu, freq);
        }
 
        pr_debug("cpu:%d min_policy_perf:%d max_policy_perf:%d\n",
@@ -2908,18 +2932,7 @@ static int intel_cpufreq_target(struct cpufreq_policy *policy,
 
        cpufreq_freq_transition_begin(policy, &freqs);
 
-       switch (relation) {
-       case CPUFREQ_RELATION_L:
-               target_pstate = DIV_ROUND_UP(freqs.new, cpu->pstate.scaling);
-               break;
-       case CPUFREQ_RELATION_H:
-               target_pstate = freqs.new / cpu->pstate.scaling;
-               break;
-       default:
-               target_pstate = DIV_ROUND_CLOSEST(freqs.new, cpu->pstate.scaling);
-               break;
-       }
-
+       target_pstate = intel_pstate_freq_to_hwp_rel(cpu, freqs.new, relation);
        target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, false);
 
        freqs.new = target_pstate * cpu->pstate.scaling;
@@ -2937,7 +2950,7 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy,
 
        update_turbo_state();
 
-       target_pstate = DIV_ROUND_UP(target_freq, cpu->pstate.scaling);
+       target_pstate = intel_pstate_freq_to_hwp(cpu, target_freq);
 
        target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, true);
 
index a148ff1f0872c419fc2198f64174d26e45342289..a4f6884416a0486181426c8a22d885f4f0534ea0 100644 (file)
@@ -4545,6 +4545,7 @@ struct caam_hash_alg {
        struct list_head entry;
        struct device *dev;
        int alg_type;
+       bool is_hmac;
        struct ahash_alg ahash_alg;
 };
 
@@ -4571,7 +4572,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm)
 
        ctx->dev = caam_hash->dev;
 
-       if (alg->setkey) {
+       if (caam_hash->is_hmac) {
                ctx->adata.key_dma = dma_map_single_attrs(ctx->dev, ctx->key,
                                                          ARRAY_SIZE(ctx->key),
                                                          DMA_TO_DEVICE,
@@ -4611,7 +4612,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm)
         * For keyed hash algorithms shared descriptors
         * will be created later in setkey() callback
         */
-       return alg->setkey ? 0 : ahash_set_sh_desc(ahash);
+       return caam_hash->is_hmac ? 0 : ahash_set_sh_desc(ahash);
 }
 
 static void caam_hash_cra_exit(struct crypto_tfm *tfm)
@@ -4646,12 +4647,14 @@ static struct caam_hash_alg *caam_hash_alloc(struct device *dev,
                         template->hmac_name);
                snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
                         template->hmac_driver_name);
+               t_alg->is_hmac = true;
        } else {
                snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s",
                         template->name);
                snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
                         template->driver_name);
                t_alg->ahash_alg.setkey = NULL;
+               t_alg->is_hmac = false;
        }
        alg->cra_module = THIS_MODULE;
        alg->cra_init = caam_hash_cra_init;
index 290c8500c247f9cbf20fb055e3715400a5f30646..fdd724228c2fa8accc7c7ebc1244c5ee92423247 100644 (file)
@@ -1753,6 +1753,7 @@ static struct caam_hash_template driver_hash[] = {
 struct caam_hash_alg {
        struct list_head entry;
        int alg_type;
+       bool is_hmac;
        struct ahash_engine_alg ahash_alg;
 };
 
@@ -1804,7 +1805,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm)
        } else {
                if (priv->era >= 6) {
                        ctx->dir = DMA_BIDIRECTIONAL;
-                       ctx->key_dir = alg->setkey ? DMA_TO_DEVICE : DMA_NONE;
+                       ctx->key_dir = caam_hash->is_hmac ? DMA_TO_DEVICE : DMA_NONE;
                } else {
                        ctx->dir = DMA_TO_DEVICE;
                        ctx->key_dir = DMA_NONE;
@@ -1862,7 +1863,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm)
         * For keyed hash algorithms shared descriptors
         * will be created later in setkey() callback
         */
-       return alg->setkey ? 0 : ahash_set_sh_desc(ahash);
+       return caam_hash->is_hmac ? 0 : ahash_set_sh_desc(ahash);
 }
 
 static void caam_hash_cra_exit(struct crypto_tfm *tfm)
@@ -1915,12 +1916,14 @@ caam_hash_alloc(struct caam_hash_template *template,
                         template->hmac_name);
                snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
                         template->hmac_driver_name);
+               t_alg->is_hmac = true;
        } else {
                snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s",
                         template->name);
                snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
                         template->driver_name);
                halg->setkey = NULL;
+               t_alg->is_hmac = false;
        }
        alg->cra_module = THIS_MODULE;
        alg->cra_init = caam_hash_cra_init;
index 479062aa5e6b61c2706ff8b4f4fe912f52ded3dc..94a0ebb03d8c96804b455f73a8d8b3155baab866 100644 (file)
@@ -463,6 +463,7 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data, u32 dev_id)
                hw_data->fw_name = ADF_402XX_FW;
                hw_data->fw_mmp_name = ADF_402XX_MMP;
                hw_data->uof_get_name = uof_get_name_402xx;
+               hw_data->get_ena_thd_mask = get_ena_thd_mask;
                break;
        case ADF_401XX_PCI_DEVICE_ID:
                hw_data->fw_name = ADF_4XXX_FW;
index 0f05692bfec3946841a766c8583bc1a3b526073e..ce0e2d82bb2b4cfdc61761d5e32a8c91cc121d82 100644 (file)
@@ -525,7 +525,7 @@ static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size)
        struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
        struct cxl_region_params *p = &cxlr->params;
        struct resource *res;
-       u32 remainder = 0;
+       u64 remainder = 0;
 
        lockdep_assert_held_write(&cxl_region_rwsem);
 
@@ -545,7 +545,7 @@ static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size)
            (cxlr->mode == CXL_DECODER_PMEM && uuid_is_null(&p->uuid)))
                return -ENXIO;
 
-       div_u64_rem(size, SZ_256M * p->interleave_ways, &remainder);
+       div64_u64_rem(size, (u64)SZ_256M * p->interleave_ways, &remainder);
        if (remainder)
                return -EINVAL;
 
index 4fd1f207c84ee53a857e417a5fc2260fb43b9733..233e7c42c161d8e0b64424776d121f5d08176010 100644 (file)
@@ -382,7 +382,7 @@ static int cxl_pci_mbox_send(struct cxl_memdev_state *mds,
        return rc;
 }
 
-static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds)
+static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds, bool irq_avail)
 {
        struct cxl_dev_state *cxlds = &mds->cxlds;
        const int cap = readl(cxlds->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET);
@@ -441,7 +441,7 @@ static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds)
        INIT_DELAYED_WORK(&mds->security.poll_dwork, cxl_mbox_sanitize_work);
 
        /* background command interrupts are optional */
-       if (!(cap & CXLDEV_MBOX_CAP_BG_CMD_IRQ))
+       if (!(cap & CXLDEV_MBOX_CAP_BG_CMD_IRQ) || !irq_avail)
                return 0;
 
        msgnum = FIELD_GET(CXLDEV_MBOX_CAP_IRQ_MSGNUM_MASK, cap);
@@ -588,7 +588,7 @@ static int cxl_mem_alloc_event_buf(struct cxl_memdev_state *mds)
        return devm_add_action_or_reset(mds->cxlds.dev, free_event_buf, buf);
 }
 
-static int cxl_alloc_irq_vectors(struct pci_dev *pdev)
+static bool cxl_alloc_irq_vectors(struct pci_dev *pdev)
 {
        int nvecs;
 
@@ -605,9 +605,9 @@ static int cxl_alloc_irq_vectors(struct pci_dev *pdev)
                                      PCI_IRQ_MSIX | PCI_IRQ_MSI);
        if (nvecs < 1) {
                dev_dbg(&pdev->dev, "Failed to alloc irq vectors: %d\n", nvecs);
-               return -ENXIO;
+               return false;
        }
-       return 0;
+       return true;
 }
 
 static irqreturn_t cxl_event_thread(int irq, void *id)
@@ -743,7 +743,7 @@ static bool cxl_event_int_is_fw(u8 setting)
 }
 
 static int cxl_event_config(struct pci_host_bridge *host_bridge,
-                           struct cxl_memdev_state *mds)
+                           struct cxl_memdev_state *mds, bool irq_avail)
 {
        struct cxl_event_interrupt_policy policy;
        int rc;
@@ -755,6 +755,11 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge,
        if (!host_bridge->native_cxl_error)
                return 0;
 
+       if (!irq_avail) {
+               dev_info(mds->cxlds.dev, "No interrupt support, disable event processing.\n");
+               return 0;
+       }
+
        rc = cxl_mem_alloc_event_buf(mds);
        if (rc)
                return rc;
@@ -789,6 +794,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        struct cxl_register_map map;
        struct cxl_memdev *cxlmd;
        int i, rc, pmu_count;
+       bool irq_avail;
 
        /*
         * Double check the anonymous union trickery in struct cxl_regs
@@ -846,11 +852,9 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        else
                dev_warn(&pdev->dev, "Media not active (%d)\n", rc);
 
-       rc = cxl_alloc_irq_vectors(pdev);
-       if (rc)
-               return rc;
+       irq_avail = cxl_alloc_irq_vectors(pdev);
 
-       rc = cxl_pci_setup_mailbox(mds);
+       rc = cxl_pci_setup_mailbox(mds, irq_avail);
        if (rc)
                return rc;
 
@@ -909,7 +913,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                }
        }
 
-       rc = cxl_event_config(host_bridge, mds);
+       rc = cxl_event_config(host_bridge, mds, irq_avail);
        if (rc)
                return rc;
 
index ee899f8e67215f6036734795cb5b90ab77a293a3..4a63567e93bae3dd2d5affabeedfd713aaa51460 100644 (file)
@@ -168,10 +168,7 @@ static vm_fault_t cma_heap_vm_fault(struct vm_fault *vmf)
        if (vmf->pgoff > buffer->pagecount)
                return VM_FAULT_SIGBUS;
 
-       vmf->page = buffer->pages[vmf->pgoff];
-       get_page(vmf->page);
-
-       return 0;
+       return vmf_insert_pfn(vma, vmf->address, page_to_pfn(buffer->pages[vmf->pgoff]));
 }
 
 static const struct vm_operations_struct dma_heap_vm_ops = {
@@ -185,6 +182,8 @@ static int cma_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
        if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0)
                return -EINVAL;
 
+       vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
+
        vma->vm_ops = &dma_heap_vm_ops;
        vma->vm_private_data = buffer;
 
index 0547253d16fe5dc5f606a34035473de7f271acf6..7d3346b3a2bf320910c72783ab857415d331ed14 100644 (file)
@@ -118,10 +118,9 @@ static int textual_leaf_to_string(const u32 *block, char *buf, size_t size)
  * @buf:       where to put the string
  * @size:      size of @buf, in bytes
  *
- * The string is taken from a minimal ASCII text descriptor leaf after
- * the immediate entry with @key.  The string is zero-terminated.
- * An overlong string is silently truncated such that it and the
- * zero byte fit into @size.
+ * The string is taken from a minimal ASCII text descriptor leaf just after the entry with the
+ * @key. The string is zero-terminated. An overlong string is silently truncated such that it
+ * and the zero byte fit into @size.
  *
  * Returns strlen(buf) or a negative error code.
  */
@@ -368,8 +367,17 @@ static ssize_t show_text_leaf(struct device *dev,
        for (i = 0; i < ARRAY_SIZE(directories) && !!directories[i]; ++i) {
                int result = fw_csr_string(directories[i], attr->key, buf, bufsize);
                // Detected.
-               if (result >= 0)
+               if (result >= 0) {
                        ret = result;
+               } else if (i == 0 && attr->key == CSR_VENDOR) {
+                       // Sony DVMC-DA1 has configuration ROM such that the descriptor leaf entry
+                       // in the root directory follows to the directory entry for vendor ID
+                       // instead of the immediate value for vendor ID.
+                       result = fw_csr_string(directories[i], CSR_DIRECTORY | attr->key, buf,
+                                              bufsize);
+                       if (result >= 0)
+                               ret = result;
+               }
        }
 
        if (ret >= 0) {
index 6146b2927d5c56af6bc3b9722c1789f29a4498fe..f2556a8e940156bc4f9d34ae5dc92aac837b688a 100644 (file)
@@ -107,12 +107,12 @@ struct ffa_drv_info {
        struct work_struct notif_pcpu_work;
        struct work_struct irq_work;
        struct xarray partition_info;
-       unsigned int partition_count;
        DECLARE_HASHTABLE(notifier_hash, ilog2(FFA_MAX_NOTIFICATIONS));
        struct mutex notify_lock; /* lock to protect notifier hashtable  */
 };
 
 static struct ffa_drv_info *drv_info;
+static void ffa_partitions_cleanup(void);
 
 /*
  * The driver must be able to support all the versions from the earliest
@@ -733,6 +733,11 @@ static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu)
        void *cb_data;
 
        partition = xa_load(&drv_info->partition_info, part_id);
+       if (!partition) {
+               pr_err("%s: Invalid partition ID 0x%x\n", __func__, part_id);
+               return;
+       }
+
        read_lock(&partition->rw_lock);
        callback = partition->callback;
        cb_data = partition->cb_data;
@@ -915,6 +920,11 @@ static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback,
                return -EOPNOTSUPP;
 
        partition = xa_load(&drv_info->partition_info, part_id);
+       if (!partition) {
+               pr_err("%s: Invalid partition ID 0x%x\n", __func__, part_id);
+               return -EINVAL;
+       }
+
        write_lock(&partition->rw_lock);
 
        cb_valid = !!partition->callback;
@@ -1186,9 +1196,9 @@ void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid)
        kfree(pbuf);
 }
 
-static void ffa_setup_partitions(void)
+static int ffa_setup_partitions(void)
 {
-       int count, idx;
+       int count, idx, ret;
        uuid_t uuid;
        struct ffa_device *ffa_dev;
        struct ffa_dev_part_info *info;
@@ -1197,7 +1207,7 @@ static void ffa_setup_partitions(void)
        count = ffa_partition_probe(&uuid_null, &pbuf);
        if (count <= 0) {
                pr_info("%s: No partitions found, error %d\n", __func__, count);
-               return;
+               return -EINVAL;
        }
 
        xa_init(&drv_info->partition_info);
@@ -1226,40 +1236,53 @@ static void ffa_setup_partitions(void)
                        ffa_device_unregister(ffa_dev);
                        continue;
                }
-               xa_store(&drv_info->partition_info, tpbuf->id, info, GFP_KERNEL);
+               rwlock_init(&info->rw_lock);
+               ret = xa_insert(&drv_info->partition_info, tpbuf->id,
+                               info, GFP_KERNEL);
+               if (ret) {
+                       pr_err("%s: failed to save partition ID 0x%x - ret:%d\n",
+                              __func__, tpbuf->id, ret);
+                       ffa_device_unregister(ffa_dev);
+                       kfree(info);
+               }
        }
-       drv_info->partition_count = count;
 
        kfree(pbuf);
 
        /* Allocate for the host */
        info = kzalloc(sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return;
-       xa_store(&drv_info->partition_info, drv_info->vm_id, info, GFP_KERNEL);
-       drv_info->partition_count++;
+       if (!info) {
+               pr_err("%s: failed to alloc Host partition ID 0x%x. Abort.\n",
+                      __func__, drv_info->vm_id);
+               /* Already registered devices are freed on bus_exit */
+               ffa_partitions_cleanup();
+               return -ENOMEM;
+       }
+
+       rwlock_init(&info->rw_lock);
+       ret = xa_insert(&drv_info->partition_info, drv_info->vm_id,
+                       info, GFP_KERNEL);
+       if (ret) {
+               pr_err("%s: failed to save Host partition ID 0x%x - ret:%d. Abort.\n",
+                      __func__, drv_info->vm_id, ret);
+               kfree(info);
+               /* Already registered devices are freed on bus_exit */
+               ffa_partitions_cleanup();
+       }
+
+       return ret;
 }
 
 static void ffa_partitions_cleanup(void)
 {
-       struct ffa_dev_part_info **info;
-       int idx, count = drv_info->partition_count;
-
-       if (!count)
-               return;
-
-       info = kcalloc(count, sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return;
-
-       xa_extract(&drv_info->partition_info, (void **)info, 0, VM_ID_MASK,
-                  count, XA_PRESENT);
+       struct ffa_dev_part_info *info;
+       unsigned long idx;
 
-       for (idx = 0; idx < count; idx++)
-               kfree(info[idx]);
-       kfree(info);
+       xa_for_each(&drv_info->partition_info, idx, info) {
+               xa_erase(&drv_info->partition_info, idx);
+               kfree(info);
+       }
 
-       drv_info->partition_count = 0;
        xa_destroy(&drv_info->partition_info);
 }
 
@@ -1508,7 +1531,11 @@ static int __init ffa_init(void)
 
        ffa_notifications_setup();
 
-       ffa_setup_partitions();
+       ret = ffa_setup_partitions();
+       if (ret) {
+               pr_err("failed to setup partitions\n");
+               goto cleanup_notifs;
+       }
 
        ret = ffa_sched_recv_cb_update(drv_info->vm_id, ffa_self_notif_handle,
                                       drv_info, true);
@@ -1516,6 +1543,9 @@ static int __init ffa_init(void)
                pr_info("Failed to register driver sched callback %d\n", ret);
 
        return 0;
+
+cleanup_notifs:
+       ffa_notifications_cleanup();
 free_pages:
        if (drv_info->tx_buffer)
                free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE);
@@ -1535,7 +1565,6 @@ static void __exit ffa_exit(void)
        ffa_rxtx_unmap(drv_info->vm_id);
        free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE);
        free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE);
-       xa_destroy(&drv_info->partition_info);
        kfree(drv_info);
        arm_ffa_bus_exit();
 }
index c0644558042a06dc1f0c087af4f22264abeee52a..e2050adbf85c6a125fc5ba241fb0c6b133466bfe 100644 (file)
@@ -13,7 +13,7 @@
 #include "notify.h"
 
 /* Updated only after ALL the mandatory features for that version are merged */
-#define SCMI_PROTOCOL_SUPPORTED_VERSION                0x20001
+#define SCMI_PROTOCOL_SUPPORTED_VERSION                0x20000
 
 enum scmi_clock_protocol_cmd {
        CLOCK_ATTRIBUTES = 0x3,
@@ -954,8 +954,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
                        scmi_clock_describe_rates_get(ph, clkid, clk);
        }
 
-       if (PROTOCOL_REV_MAJOR(version) >= 0x2 &&
-           PROTOCOL_REV_MINOR(version) >= 0x1) {
+       if (PROTOCOL_REV_MAJOR(version) >= 0x3) {
                cinfo->clock_config_set = scmi_clock_config_set_v2;
                cinfo->clock_config_get = scmi_clock_config_get_v2;
        } else {
index c46dc5215af7a7c8a78e0fe26c12fac51c8080b7..00b165d1f502df7816527298996f196585d10f5a 100644 (file)
@@ -314,6 +314,7 @@ void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem,
 void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem);
 bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
                     struct scmi_xfer *xfer);
+bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem);
 
 /* declarations for message passing transports */
 struct scmi_msg_payld;
index 19246ed1f01ff7cc3ea7346402c32e02b57b336a..b8d470417e8f99bb6408aba541bc4b89541ddf7c 100644 (file)
@@ -45,6 +45,20 @@ static void rx_callback(struct mbox_client *cl, void *m)
 {
        struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl);
 
+       /*
+        * An A2P IRQ is NOT valid when received while the platform still has
+        * the ownership of the channel, because the platform at first releases
+        * the SMT channel and then sends the completion interrupt.
+        *
+        * This addresses a possible race condition in which a spurious IRQ from
+        * a previous timed-out reply which arrived late could be wrongly
+        * associated with the next pending transaction.
+        */
+       if (cl->knows_txdone && !shmem_channel_free(smbox->shmem)) {
+               dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n");
+               return;
+       }
+
        scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem), NULL);
 }
 
index 8ea2a7b3d35d2029f9731ef3031d575609093d6e..211e8e0aef2c2b4fade048990249c2444afb946a 100644 (file)
@@ -350,8 +350,8 @@ process_response_opp(struct scmi_opp *opp, unsigned int loop_idx,
 }
 
 static inline void
-process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp,
-                       unsigned int loop_idx,
+process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
+                       struct scmi_opp *opp, unsigned int loop_idx,
                        const struct scmi_msg_resp_perf_describe_levels_v4 *r)
 {
        opp->perf = le32_to_cpu(r->opp[loop_idx].perf_val);
@@ -362,10 +362,23 @@ process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp,
        /* Note that PERF v4 reports always five 32-bit words */
        opp->indicative_freq = le32_to_cpu(r->opp[loop_idx].indicative_freq);
        if (dom->level_indexing_mode) {
+               int ret;
+
                opp->level_index = le32_to_cpu(r->opp[loop_idx].level_index);
 
-               xa_store(&dom->opps_by_idx, opp->level_index, opp, GFP_KERNEL);
-               xa_store(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
+               ret = xa_insert(&dom->opps_by_idx, opp->level_index, opp,
+                               GFP_KERNEL);
+               if (ret)
+                       dev_warn(dev,
+                                "Failed to add opps_by_idx at %d - ret:%d\n",
+                                opp->level_index, ret);
+
+               ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
+               if (ret)
+                       dev_warn(dev,
+                                "Failed to add opps_by_lvl at %d - ret:%d\n",
+                                opp->perf, ret);
+
                hash_add(dom->opps_by_freq, &opp->hash, opp->indicative_freq);
        }
 }
@@ -382,7 +395,7 @@ iter_perf_levels_process_response(const struct scmi_protocol_handle *ph,
        if (PROTOCOL_REV_MAJOR(p->version) <= 0x3)
                process_response_opp(opp, st->loop_idx, response);
        else
-               process_response_opp_v4(p->perf_dom, opp, st->loop_idx,
+               process_response_opp_v4(ph->dev, p->perf_dom, opp, st->loop_idx,
                                        response);
        p->perf_dom->opp_count++;
 
index 0493aa3c12bf5363e02c1ecc9b2520d1bd8b3d67..350573518503355f6abaa4d24cbcac6368e8930c 100644 (file)
@@ -1111,7 +1111,6 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw,
                int i;
 
                for (i = 0; i < num_chans; i++) {
-                       void *xret;
                        struct scmi_raw_queue *q;
 
                        q = scmi_raw_queue_init(raw);
@@ -1120,13 +1119,12 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw,
                                goto err_xa;
                        }
 
-                       xret = xa_store(&raw->chans_q, channels[i], q,
+                       ret = xa_insert(&raw->chans_q, channels[i], q,
                                        GFP_KERNEL);
-                       if (xa_err(xret)) {
+                       if (ret) {
                                dev_err(dev,
                                        "Fail to allocate Raw queue 0x%02X\n",
                                        channels[i]);
-                               ret = xa_err(xret);
                                goto err_xa;
                        }
                }
@@ -1322,6 +1320,12 @@ void scmi_raw_message_report(void *r, struct scmi_xfer *xfer,
        dev = raw->handle->dev;
        q = scmi_raw_queue_select(raw, idx,
                                  SCMI_XFER_IS_CHAN_SET(xfer) ? chan_id : 0);
+       if (!q) {
+               dev_warn(dev,
+                        "RAW[%d] - NO queue for chan 0x%X. Dropping report.\n",
+                        idx, chan_id);
+               return;
+       }
 
        /*
         * Grab the msg_q_lock upfront to avoid a possible race between
index 87b4f4d35f06230bc161fc4205c7b199e03c0015..8bf495bcad09b7ba8246c05b4e76086fa1bdaf90 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/processor.h>
 #include <linux/types.h>
 
-#include <asm-generic/bug.h>
+#include <linux/bug.h>
 
 #include "common.h"
 
@@ -122,3 +122,9 @@ bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
                (SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR |
                 SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
 }
+
+bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem)
+{
+       return (ioread32(&shmem->channel_status) &
+                       SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
+}
index 82fcfd29bc4d29116b051c946edb9b6535fd78ac..3c197db42c9d936866f9ff68cf7561e4735cfe1e 100644 (file)
@@ -128,4 +128,4 @@ unlock_mutex:
 }
 
 /* must execute after PCI subsystem for EFI quirks */
-subsys_initcall_sync(sysfb_init);
+device_initcall(sysfb_init);
index be7f2fa5aa7b600a2605084d832e23f24d501c84..806b88d8dfb7bda7d23cae021eb08c3bbf383ab1 100644 (file)
@@ -330,20 +330,27 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
                switch (flow_type) {
                case IRQ_TYPE_LEVEL_HIGH:
                        sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1);
+                       sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1);
                        break;
                case IRQ_TYPE_LEVEL_LOW:
                        sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0);
+                       sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1);
                        break;
                case IRQ_TYPE_EDGE_RISING:
                case IRQ_TYPE_EDGE_FALLING:
                case IRQ_TYPE_EDGE_BOTH:
                        state = sprd_eic_get(chip, offset);
-                       if (state)
+                       if (state) {
                                sprd_eic_update(chip, offset,
                                                SPRD_EIC_DBNC_IEV, 0);
-                       else
+                               sprd_eic_update(chip, offset,
+                                               SPRD_EIC_DBNC_IC, 1);
+                       } else {
                                sprd_eic_update(chip, offset,
                                                SPRD_EIC_DBNC_IEV, 1);
+                               sprd_eic_update(chip, offset,
+                                               SPRD_EIC_DBNC_IC, 1);
+                       }
                        break;
                default:
                        return -ENOTSUPP;
@@ -355,20 +362,27 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
                switch (flow_type) {
                case IRQ_TYPE_LEVEL_HIGH:
                        sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0);
+                       sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1);
                        break;
                case IRQ_TYPE_LEVEL_LOW:
                        sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1);
+                       sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1);
                        break;
                case IRQ_TYPE_EDGE_RISING:
                case IRQ_TYPE_EDGE_FALLING:
                case IRQ_TYPE_EDGE_BOTH:
                        state = sprd_eic_get(chip, offset);
-                       if (state)
+                       if (state) {
                                sprd_eic_update(chip, offset,
                                                SPRD_EIC_LATCH_INTPOL, 0);
-                       else
+                               sprd_eic_update(chip, offset,
+                                               SPRD_EIC_LATCH_INTCLR, 1);
+                       } else {
                                sprd_eic_update(chip, offset,
                                                SPRD_EIC_LATCH_INTPOL, 1);
+                               sprd_eic_update(chip, offset,
+                                               SPRD_EIC_LATCH_INTCLR, 1);
+                       }
                        break;
                default:
                        return -ENOTSUPP;
@@ -382,29 +396,34 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
                        sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
                        sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0);
                        sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1);
+                       sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
                        irq_set_handler_locked(data, handle_edge_irq);
                        break;
                case IRQ_TYPE_EDGE_FALLING:
                        sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
                        sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0);
                        sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0);
+                       sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
                        irq_set_handler_locked(data, handle_edge_irq);
                        break;
                case IRQ_TYPE_EDGE_BOTH:
                        sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0);
                        sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 1);
+                       sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
                        irq_set_handler_locked(data, handle_edge_irq);
                        break;
                case IRQ_TYPE_LEVEL_HIGH:
                        sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
                        sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1);
                        sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1);
+                       sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
                        irq_set_handler_locked(data, handle_level_irq);
                        break;
                case IRQ_TYPE_LEVEL_LOW:
                        sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
                        sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1);
                        sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0);
+                       sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
                        irq_set_handler_locked(data, handle_level_irq);
                        break;
                default:
@@ -417,29 +436,34 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
                        sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
                        sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0);
                        sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1);
+                       sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
                        irq_set_handler_locked(data, handle_edge_irq);
                        break;
                case IRQ_TYPE_EDGE_FALLING:
                        sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
                        sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0);
                        sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0);
+                       sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
                        irq_set_handler_locked(data, handle_edge_irq);
                        break;
                case IRQ_TYPE_EDGE_BOTH:
                        sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0);
                        sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 1);
+                       sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
                        irq_set_handler_locked(data, handle_edge_irq);
                        break;
                case IRQ_TYPE_LEVEL_HIGH:
                        sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
                        sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1);
                        sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1);
+                       sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
                        irq_set_handler_locked(data, handle_level_irq);
                        break;
                case IRQ_TYPE_LEVEL_LOW:
                        sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
                        sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1);
                        sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0);
+                       sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
                        irq_set_handler_locked(data, handle_level_irq);
                        break;
                default:
index 88066826d8e5b629697136b8bb2431b543544977..cd3e9657cc36df59123a571a0ed2ed5332272a5d 100644 (file)
@@ -1651,6 +1651,20 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
                        .ignore_interrupt = "INT33FC:00@3",
                },
        },
+       {
+               /*
+                * Spurious wakeups from TP_ATTN# pin
+                * Found in BIOS 0.35
+                * https://gitlab.freedesktop.org/drm/amd/-/issues/3073
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "GPD"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "G1619-04"),
+               },
+               .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+                       .ignore_wake = "PNP0C50:00@8",
+               },
+       },
        {} /* Terminating entry */
 };
 
index 77e2636602887034c188ec695591d20e5b087b60..41db030ddc4ee9c98ba952b4b91d6292f7c457d6 100644 (file)
@@ -141,11 +141,31 @@ static void amdgpu_amdkfd_reset_work(struct work_struct *work)
 static const struct drm_client_funcs kfd_client_funcs = {
        .unregister     = drm_client_release,
 };
+
+int amdgpu_amdkfd_drm_client_create(struct amdgpu_device *adev)
+{
+       int ret;
+
+       if (!adev->kfd.init_complete)
+               return 0;
+
+       ret = drm_client_init(&adev->ddev, &adev->kfd.client, "kfd",
+                             &kfd_client_funcs);
+       if (ret) {
+               dev_err(adev->dev, "Failed to init DRM client: %d\n",
+                       ret);
+               return ret;
+       }
+
+       drm_client_register(&adev->kfd.client);
+
+       return 0;
+}
+
 void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
 {
        int i;
        int last_valid_bit;
-       int ret;
 
        amdgpu_amdkfd_gpuvm_init_mem_limits();
 
@@ -164,12 +184,6 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
                        .enable_mes = adev->enable_mes,
                };
 
-               ret = drm_client_init(&adev->ddev, &adev->kfd.client, "kfd", &kfd_client_funcs);
-               if (ret) {
-                       dev_err(adev->dev, "Failed to init DRM client: %d\n", ret);
-                       return;
-               }
-
                /* this is going to have a few of the MSBs set that we need to
                 * clear
                 */
@@ -208,10 +222,6 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
 
                adev->kfd.init_complete = kgd2kfd_device_init(adev->kfd.dev,
                                                        &gpu_resources);
-               if (adev->kfd.init_complete)
-                       drm_client_register(&adev->kfd.client);
-               else
-                       drm_client_release(&adev->kfd.client);
 
                amdgpu_amdkfd_total_mem_size += adev->gmc.real_vram_size;
 
index f262b9d89541a8a971a394b5f0da0f6a1368ba65..27c61c535e297931892902f1abb9e56ca6feea5c 100644 (file)
@@ -182,6 +182,8 @@ int amdgpu_queue_mask_bit_to_set_resource_bit(struct amdgpu_device *adev,
 struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context,
                                struct mm_struct *mm,
                                struct svm_range_bo *svm_bo);
+
+int amdgpu_amdkfd_drm_client_create(struct amdgpu_device *adev);
 #if defined(CONFIG_DEBUG_FS)
 int kfd_debugfs_kfd_mem_limits(struct seq_file *m, void *data);
 #endif
@@ -301,7 +303,7 @@ int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(struct amdgpu_device *adev,
                                          struct kgd_mem *mem, void *drm_priv);
 int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(
                struct amdgpu_device *adev, struct kgd_mem *mem, void *drm_priv);
-void amdgpu_amdkfd_gpuvm_dmaunmap_mem(struct kgd_mem *mem, void *drm_priv);
+int amdgpu_amdkfd_gpuvm_dmaunmap_mem(struct kgd_mem *mem, void *drm_priv);
 int amdgpu_amdkfd_gpuvm_sync_memory(
                struct amdgpu_device *adev, struct kgd_mem *mem, bool intr);
 int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem,
index 899e31e3a5e81d2be343a668e295a564efee10af..3a3f3ce09f00dbe77f61455f24fed7bd0db0dec5 100644 (file)
@@ -290,7 +290,7 @@ static int suspend_resume_compute_scheduler(struct amdgpu_device *adev, bool sus
        for (i = 0; i < adev->gfx.num_compute_rings; i++) {
                struct amdgpu_ring *ring = &adev->gfx.compute_ring[i];
 
-               if (!(ring && drm_sched_wqueue_ready(&ring->sched)))
+               if (!amdgpu_ring_sched_ready(ring))
                        continue;
 
                /* stop secheduler and drain ring. */
index f183d7faeeece16cfc7c211f5a6a0232dce37c36..231fd927dcfbee0db07e3a5d28eed2b24ff82b9c 100644 (file)
@@ -2085,21 +2085,35 @@ out:
        return ret;
 }
 
-void amdgpu_amdkfd_gpuvm_dmaunmap_mem(struct kgd_mem *mem, void *drm_priv)
+int amdgpu_amdkfd_gpuvm_dmaunmap_mem(struct kgd_mem *mem, void *drm_priv)
 {
        struct kfd_mem_attachment *entry;
        struct amdgpu_vm *vm;
+       int ret;
 
        vm = drm_priv_to_vm(drm_priv);
 
        mutex_lock(&mem->lock);
 
+       ret = amdgpu_bo_reserve(mem->bo, true);
+       if (ret)
+               goto out;
+
        list_for_each_entry(entry, &mem->attachments, list) {
-               if (entry->bo_va->base.vm == vm)
-                       kfd_mem_dmaunmap_attachment(mem, entry);
+               if (entry->bo_va->base.vm != vm)
+                       continue;
+               if (entry->bo_va->base.bo->tbo.ttm &&
+                   !entry->bo_va->base.bo->tbo.ttm->sg)
+                       continue;
+
+               kfd_mem_dmaunmap_attachment(mem, entry);
        }
 
+       amdgpu_bo_unreserve(mem->bo);
+out:
        mutex_unlock(&mem->lock);
+
+       return ret;
 }
 
 int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(
index e485dd3357c63fd225b3fb7e3847675749f018da..1afbb2e932c6b58a9e26cbabe61370151373a4af 100644 (file)
@@ -1678,7 +1678,7 @@ static int amdgpu_debugfs_test_ib_show(struct seq_file *m, void *unused)
        for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
                struct amdgpu_ring *ring = adev->rings[i];
 
-               if (!ring || !drm_sched_wqueue_ready(&ring->sched))
+               if (!amdgpu_ring_sched_ready(ring))
                        continue;
                drm_sched_wqueue_stop(&ring->sched);
        }
@@ -1694,7 +1694,7 @@ static int amdgpu_debugfs_test_ib_show(struct seq_file *m, void *unused)
        for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
                struct amdgpu_ring *ring = adev->rings[i];
 
-               if (!ring || !drm_sched_wqueue_ready(&ring->sched))
+               if (!amdgpu_ring_sched_ready(ring))
                        continue;
                drm_sched_wqueue_start(&ring->sched);
        }
@@ -1916,8 +1916,8 @@ static int amdgpu_debugfs_ib_preempt(void *data, u64 val)
 
        ring = adev->rings[val];
 
-       if (!ring || !ring->funcs->preempt_ib ||
-           !drm_sched_wqueue_ready(&ring->sched))
+       if (!amdgpu_ring_sched_ready(ring) ||
+           !ring->funcs->preempt_ib)
                return -EINVAL;
 
        /* the last preemption failed */
index b158d27d0a71cbbafb55f0d58657c1ec178fa6c2..fdde7488d0ed9a8ff93f4a4cc58c123b904236c7 100644 (file)
@@ -4121,23 +4121,13 @@ int amdgpu_device_init(struct amdgpu_device *adev,
                                }
                        }
                } else {
-                       switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
-                       case IP_VERSION(13, 0, 0):
-                       case IP_VERSION(13, 0, 7):
-                       case IP_VERSION(13, 0, 10):
-                               r = psp_gpu_reset(adev);
-                               break;
-                       default:
-                               tmp = amdgpu_reset_method;
-                               /* It should do a default reset when loading or reloading the driver,
-                                * regardless of the module parameter reset_method.
-                                */
-                               amdgpu_reset_method = AMD_RESET_METHOD_NONE;
-                               r = amdgpu_asic_reset(adev);
-                               amdgpu_reset_method = tmp;
-                               break;
-                       }
-
+                       tmp = amdgpu_reset_method;
+                       /* It should do a default reset when loading or reloading the driver,
+                        * regardless of the module parameter reset_method.
+                        */
+                       amdgpu_reset_method = AMD_RESET_METHOD_NONE;
+                       r = amdgpu_asic_reset(adev);
+                       amdgpu_reset_method = tmp;
                        if (r) {
                                dev_err(adev->dev, "asic reset on init failed\n");
                                goto failed;
@@ -5031,7 +5021,7 @@ bool amdgpu_device_has_job_running(struct amdgpu_device *adev)
        for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
                struct amdgpu_ring *ring = adev->rings[i];
 
-               if (!ring || !drm_sched_wqueue_ready(&ring->sched))
+               if (!amdgpu_ring_sched_ready(ring))
                        continue;
 
                spin_lock(&ring->sched.job_list_lock);
@@ -5170,7 +5160,7 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
        for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
                struct amdgpu_ring *ring = adev->rings[i];
 
-               if (!ring || !drm_sched_wqueue_ready(&ring->sched))
+               if (!amdgpu_ring_sched_ready(ring))
                        continue;
 
                /* Clear job fence from fence drv to avoid force_completion
@@ -5637,7 +5627,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
                for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
                        struct amdgpu_ring *ring = tmp_adev->rings[i];
 
-                       if (!ring || !drm_sched_wqueue_ready(&ring->sched))
+                       if (!amdgpu_ring_sched_ready(ring))
                                continue;
 
                        drm_sched_stop(&ring->sched, job ? &job->base : NULL);
@@ -5706,7 +5696,7 @@ skip_hw_reset:
                for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
                        struct amdgpu_ring *ring = tmp_adev->rings[i];
 
-                       if (!ring || !drm_sched_wqueue_ready(&ring->sched))
+                       if (!amdgpu_ring_sched_ready(ring))
                                continue;
 
                        drm_sched_start(&ring->sched, true);
@@ -6061,7 +6051,7 @@ pci_ers_result_t amdgpu_pci_error_detected(struct pci_dev *pdev, pci_channel_sta
                for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
                        struct amdgpu_ring *ring = adev->rings[i];
 
-                       if (!ring || !drm_sched_wqueue_ready(&ring->sched))
+                       if (!amdgpu_ring_sched_ready(ring))
                                continue;
 
                        drm_sched_stop(&ring->sched, NULL);
@@ -6189,7 +6179,7 @@ void amdgpu_pci_resume(struct pci_dev *pdev)
        for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
                struct amdgpu_ring *ring = adev->rings[i];
 
-               if (!ring || !drm_sched_wqueue_ready(&ring->sched))
+               if (!amdgpu_ring_sched_ready(ring))
                        continue;
 
                drm_sched_start(&ring->sched, true);
index cc69005f5b46e7b9f06d65db13287a617cc384e2..971acf01bea6063cfcca6275a21b12662cfbd824 100644 (file)
@@ -2255,6 +2255,10 @@ retry_init:
        if (ret)
                goto err_pci;
 
+       ret = amdgpu_amdkfd_drm_client_create(adev);
+       if (ret)
+               goto err_pci;
+
        /*
         * 1. don't init fbdev on hw without DCE
         * 2. don't init fbdev if there are no connectors
index 73b8cca35bab8780d1938a45d035d19648bdd081..c623e23049d1d4bde50991fcddc8b542df0099b7 100644 (file)
@@ -121,6 +121,7 @@ int amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev)
        struct amdgpu_bo_param bp;
        dma_addr_t dma_addr;
        struct page *p;
+       unsigned long x;
        int ret;
 
        if (adev->gart.bo != NULL)
@@ -130,6 +131,10 @@ int amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev)
        if (!p)
                return -ENOMEM;
 
+       /* assign pages to this device */
+       for (x = 0; x < (1UL << order); x++)
+               p[x].mapping = adev->mman.bdev.dev_mapping;
+
        /* If the hardware does not support UTCL2 snooping of the CPU caches
         * then set_memory_wc() could be used as a workaround to mark the pages
         * as write combine memory.
@@ -223,6 +228,7 @@ void amdgpu_gart_table_ram_free(struct amdgpu_device *adev)
        unsigned int order = get_order(adev->gart.table_size);
        struct sg_table *sg = adev->gart.bo->tbo.sg;
        struct page *p;
+       unsigned long x;
        int ret;
 
        ret = amdgpu_bo_reserve(adev->gart.bo, false);
@@ -234,6 +240,8 @@ void amdgpu_gart_table_ram_free(struct amdgpu_device *adev)
        sg_free_table(sg);
        kfree(sg);
        p = virt_to_page(adev->gart.ptr);
+       for (x = 0; x < (1UL << order); x++)
+               p[x].mapping = NULL;
        __free_pages(p, order);
 
        adev->gart.ptr = NULL;
index 45424ebf9681430fefc21bdc33d6aa2c6e5f6c91..5505d646f43aa8f963d8d8732846b00fc612a3a7 100644 (file)
@@ -635,6 +635,7 @@ int amdgpu_ring_test_helper(struct amdgpu_ring *ring)
                              ring->name);
 
        ring->sched.ready = !r;
+
        return r;
 }
 
@@ -717,3 +718,14 @@ void amdgpu_ring_ib_on_emit_de(struct amdgpu_ring *ring)
        if (ring->is_sw_ring)
                amdgpu_sw_ring_ib_mark_offset(ring, AMDGPU_MUX_OFFSET_TYPE_DE);
 }
+
+bool amdgpu_ring_sched_ready(struct amdgpu_ring *ring)
+{
+       if (!ring)
+               return false;
+
+       if (ring->no_scheduler || !drm_sched_wqueue_ready(&ring->sched))
+               return false;
+
+       return true;
+}
index bbb53720a0181d93cf9fdfd6f7721ee006699004..fe1a61eb6e4c0809c1bccd41bc89f32bcd8304f2 100644 (file)
@@ -450,5 +450,5 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
 int amdgpu_ib_pool_init(struct amdgpu_device *adev);
 void amdgpu_ib_pool_fini(struct amdgpu_device *adev);
 int amdgpu_ib_ring_tests(struct amdgpu_device *adev);
-
+bool amdgpu_ring_sched_ready(struct amdgpu_ring *ring);
 #endif
index 08916538a615ff3d072eb5241a97495795c7e32a..8db880244324ff1077ff3d87c20b7387ecd8b74b 100644 (file)
@@ -221,8 +221,23 @@ static struct attribute *amdgpu_vram_mgr_attributes[] = {
        NULL
 };
 
+static umode_t amdgpu_vram_attrs_is_visible(struct kobject *kobj,
+                                           struct attribute *attr, int i)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = drm_to_adev(ddev);
+
+       if (attr == &dev_attr_mem_info_vram_vendor.attr &&
+           !adev->gmc.vram_vendor)
+               return 0;
+
+       return attr->mode;
+}
+
 const struct attribute_group amdgpu_vram_mgr_attr_group = {
-       .attrs = amdgpu_vram_mgr_attributes
+       .attrs = amdgpu_vram_mgr_attributes,
+       .is_visible = amdgpu_vram_attrs_is_visible
 };
 
 /**
index 6f7c031dd197a22e388ddcfaed56ec75e37cafe5..f24e34dc33d1defcd70cab67f1423dffd31e8f08 100644 (file)
@@ -204,6 +204,12 @@ static u32 cik_ih_get_wptr(struct amdgpu_device *adev,
                tmp = RREG32(mmIH_RB_CNTL);
                tmp |= IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK;
                WREG32(mmIH_RB_CNTL, tmp);
+
+               /* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+                * can be detected.
+                */
+               tmp &= ~IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK;
+               WREG32(mmIH_RB_CNTL, tmp);
        }
        return (wptr & ih->ptr_mask);
 }
index b8c47e0cf37ad53bcb3f1afe161e6356b91789e3..c19681492efa748bf7b5d92864dbdc61c0351520 100644 (file)
@@ -216,6 +216,11 @@ static u32 cz_ih_get_wptr(struct amdgpu_device *adev,
        tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
        WREG32(mmIH_RB_CNTL, tmp);
 
+       /* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+        * can be detected.
+        */
+       tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
+       WREG32(mmIH_RB_CNTL, tmp);
 
 out:
        return (wptr & ih->ptr_mask);
index d63cab294883b8b44caa908d5bafaeaf19750ef6..dcdecb18b2306b84ca1b18852837409776707c69 100644 (file)
@@ -4027,8 +4027,6 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev)
                err = 0;
                adev->gfx.mec2_fw = NULL;
        }
-       amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2);
-       amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2_JT);
 
        gfx_v10_0_check_fw_write_wait(adev);
 out:
@@ -6589,7 +6587,7 @@ static int gfx_v10_0_compute_mqd_init(struct amdgpu_device *adev, void *m,
 #ifdef __BIG_ENDIAN
        tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, ENDIAN_SWAP, 1);
 #endif
-       tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 0);
+       tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1);
        tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH,
                            prop->allow_tunneling);
        tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1);
index 0ea0866c261f84e24e8494755387b3d22482a0a2..4f3bfdc75b37d66cbc5d78a5525a8a905eb1e733 100644 (file)
@@ -107,23 +107,6 @@ static const struct soc15_reg_golden golden_settings_gc_11_0_1[] =
        SOC15_REG_GOLDEN_VALUE(GC, 0, regTCP_CNTL2, 0xfcffffff, 0x0000000a)
 };
 
-static const struct soc15_reg_golden golden_settings_gc_11_5_0[] = {
-       SOC15_REG_GOLDEN_VALUE(GC, 0, regDB_DEBUG5, 0xffffffff, 0x00000800),
-       SOC15_REG_GOLDEN_VALUE(GC, 0, regGB_ADDR_CONFIG, 0x0c1807ff, 0x00000242),
-       SOC15_REG_GOLDEN_VALUE(GC, 0, regGCR_GENERAL_CNTL, 0x1ff1ffff, 0x00000500),
-       SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2A_ADDR_MATCH_MASK, 0xffffffff, 0xfffffff3),
-       SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2C_ADDR_MATCH_MASK, 0xffffffff, 0xfffffff3),
-       SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2C_CTRL, 0xffffffff, 0xf37fff3f),
-       SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2C_CTRL3, 0xfffffffb, 0x00f40188),
-       SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2C_CTRL4, 0xf0ffffff, 0x80009007),
-       SOC15_REG_GOLDEN_VALUE(GC, 0, regPA_CL_ENHANCE, 0xf1ffffff, 0x00880007),
-       SOC15_REG_GOLDEN_VALUE(GC, 0, regPC_CONFIG_CNTL_1, 0xffffffff, 0x00010000),
-       SOC15_REG_GOLDEN_VALUE(GC, 0, regTA_CNTL_AUX, 0xf7f7ffff, 0x01030000),
-       SOC15_REG_GOLDEN_VALUE(GC, 0, regTA_CNTL2, 0x007f0000, 0x00000000),
-       SOC15_REG_GOLDEN_VALUE(GC, 0, regTCP_CNTL2, 0xffcfffff, 0x0000200a),
-       SOC15_REG_GOLDEN_VALUE(GC, 0, regUTCL1_CTRL_2, 0xffffffff, 0x0000048f)
-};
-
 #define DEFAULT_SH_MEM_CONFIG \
        ((SH_MEM_ADDRESS_MODE_64 << SH_MEM_CONFIG__ADDRESS_MODE__SHIFT) | \
         (SH_MEM_ALIGNMENT_MODE_UNALIGNED << SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT) | \
@@ -304,11 +287,6 @@ static void gfx_v11_0_init_golden_registers(struct amdgpu_device *adev)
                                                golden_settings_gc_11_0_1,
                                                (const u32)ARRAY_SIZE(golden_settings_gc_11_0_1));
                break;
-       case IP_VERSION(11, 5, 0):
-               soc15_program_register_sequence(adev,
-                                               golden_settings_gc_11_5_0,
-                                               (const u32)ARRAY_SIZE(golden_settings_gc_11_5_0));
-               break;
        default:
                break;
        }
@@ -3846,7 +3824,7 @@ static int gfx_v11_0_compute_mqd_init(struct amdgpu_device *adev, void *m,
                            (order_base_2(prop->queue_size / 4) - 1));
        tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, RPTR_BLOCK_SIZE,
                            (order_base_2(AMDGPU_GPU_PAGE_SIZE / 4) - 1));
-       tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 0);
+       tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1);
        tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH,
                            prop->allow_tunneling);
        tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1);
index 42e103d7077d52d5bbe556f70f2b03bb0d5ae8db..59d9215e555629577b43afcba38e945f5ce90bcd 100644 (file)
@@ -915,8 +915,8 @@ static int gmc_v6_0_hw_init(void *handle)
 
        if (amdgpu_emu_mode == 1)
                return amdgpu_gmc_vram_checking(adev);
-       else
-               return r;
+
+       return 0;
 }
 
 static int gmc_v6_0_hw_fini(void *handle)
index efc16e580f1e27e384b7c80323c72d0e59fba473..45a2f8e031a2c9920f3a68ae690731357f33da0c 100644 (file)
@@ -1099,8 +1099,8 @@ static int gmc_v7_0_hw_init(void *handle)
 
        if (amdgpu_emu_mode == 1)
                return amdgpu_gmc_vram_checking(adev);
-       else
-               return r;
+
+       return 0;
 }
 
 static int gmc_v7_0_hw_fini(void *handle)
index ff4ae73d27ecd26aaf399bdfe158e22c1de3009f..4422b27a3cc2fc069a6ecb3e6d8b9630e9c173cc 100644 (file)
@@ -1219,8 +1219,8 @@ static int gmc_v8_0_hw_init(void *handle)
 
        if (amdgpu_emu_mode == 1)
                return amdgpu_gmc_vram_checking(adev);
-       else
-               return r;
+
+       return 0;
 }
 
 static int gmc_v8_0_hw_fini(void *handle)
index f9039d64ff2d72804556daa16b8ed9632b08b307..40a00ea0009f6aca367c68a43e11ae608f71d416 100644 (file)
@@ -1950,7 +1950,8 @@ static void gmc_v9_4_3_init_vram_info(struct amdgpu_device *adev)
        static const u32 regBIF_BIOS_SCRATCH_4 = 0x50;
        u32 vram_info;
 
-       if (!amdgpu_sriov_vf(adev)) {
+       /* Only for dGPU, vendor informaton is reliable */
+       if (!amdgpu_sriov_vf(adev) && !(adev->flags & AMD_IS_APU)) {
                vram_info = RREG32(regBIF_BIOS_SCRATCH_4);
                adev->gmc.vram_vendor = vram_info & 0xF;
        }
@@ -2340,8 +2341,8 @@ static int gmc_v9_0_hw_init(void *handle)
 
        if (amdgpu_emu_mode == 1)
                return amdgpu_gmc_vram_checking(adev);
-       else
-               return r;
+
+       return 0;
 }
 
 /**
index aecad530b10a61289f9e2413612bbf58a33cec22..2c02ae69883d2bb86bec8e1d1fb521f8481d7ebb 100644 (file)
@@ -215,6 +215,11 @@ static u32 iceland_ih_get_wptr(struct amdgpu_device *adev,
        tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
        WREG32(mmIH_RB_CNTL, tmp);
 
+       /* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+        * can be detected.
+        */
+       tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
+       WREG32(mmIH_RB_CNTL, tmp);
 
 out:
        return (wptr & ih->ptr_mask);
index d9ed7332d805d3fca1bd0343ebc804e69dc44595..ad4ad39f128f7d7f788a866d36cc7c8175743b5d 100644 (file)
@@ -418,6 +418,12 @@ static u32 ih_v6_0_get_wptr(struct amdgpu_device *adev,
        tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl);
        tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
        WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
+
+       /* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+        * can be detected.
+        */
+       tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
+       WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
 out:
        return (wptr & ih->ptr_mask);
 }
index 8fb05eae340ad298653afaca4edccfce86741c84..b8da0fc29378c496ba0392e10105d1c58d53bf5a 100644 (file)
@@ -418,6 +418,13 @@ static u32 ih_v6_1_get_wptr(struct amdgpu_device *adev,
        tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl);
        tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
        WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
+
+       /* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+        * can be detected.
+        */
+       tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
+       WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
+
 out:
        return (wptr & ih->ptr_mask);
 }
index e64b33115848d204a4d81eb9530df5bf95fdf796..de93614726c9a48ccd398c6ac5570a8844fb7618 100644 (file)
@@ -442,6 +442,12 @@ static u32 navi10_ih_get_wptr(struct amdgpu_device *adev,
        tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl);
        tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
        WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
+
+       /* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+        * can be detected.
+        */
+       tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
+       WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
 out:
        return (wptr & ih->ptr_mask);
 }
index 9a24f17a57502edaa744451bd312dfcd8b3d678c..cada9f300a7f510a3f025c3ed17c87aedcbbaeb5 100644 (file)
@@ -119,6 +119,12 @@ static u32 si_ih_get_wptr(struct amdgpu_device *adev,
                tmp = RREG32(IH_RB_CNTL);
                tmp |= IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK;
                WREG32(IH_RB_CNTL, tmp);
+
+               /* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+                * can be detected.
+                */
+               tmp &= ~IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK;
+               WREG32(IH_RB_CNTL, tmp);
        }
        return (wptr & ih->ptr_mask);
 }
index 917707bba7f3624e37b0525d3ec72bf563c1307a..450b6e8315091448c24e2d90dcd4edccc9d4423c 100644 (file)
@@ -219,6 +219,12 @@ static u32 tonga_ih_get_wptr(struct amdgpu_device *adev,
        tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
        WREG32(mmIH_RB_CNTL, tmp);
 
+       /* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+        * can be detected.
+        */
+       tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
+       WREG32(mmIH_RB_CNTL, tmp);
+
 out:
        return (wptr & ih->ptr_mask);
 }
index 169ed400ee7b7413263ab48a2de1e75aa3ed00f7..8ab01ae919d2e36c8ff1c2226227c173223247be 100644 (file)
@@ -2017,22 +2017,6 @@ static int vcn_v4_0_set_powergating_state(void *handle, enum amd_powergating_sta
        return ret;
 }
 
-/**
- * vcn_v4_0_set_interrupt_state - set VCN block interrupt state
- *
- * @adev: amdgpu_device pointer
- * @source: interrupt sources
- * @type: interrupt types
- * @state: interrupt states
- *
- * Set VCN block interrupt state
- */
-static int vcn_v4_0_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source,
-      unsigned type, enum amdgpu_interrupt_state state)
-{
-       return 0;
-}
-
 /**
  * vcn_v4_0_set_ras_interrupt_state - set VCN block RAS interrupt state
  *
@@ -2097,7 +2081,6 @@ static int vcn_v4_0_process_interrupt(struct amdgpu_device *adev, struct amdgpu_
 }
 
 static const struct amdgpu_irq_src_funcs vcn_v4_0_irq_funcs = {
-       .set = vcn_v4_0_set_interrupt_state,
        .process = vcn_v4_0_process_interrupt,
 };
 
index 2eda30e78f61d928984cf57b94337abc7b9cfc0a..49e4c3c09acab8eab12770325f4cf48c8c491b7c 100644 (file)
@@ -269,8 +269,6 @@ static int vcn_v4_0_5_hw_fini(void *handle)
                                vcn_v4_0_5_set_powergating_state(adev, AMD_PG_STATE_GATE);
                        }
                }
-
-               amdgpu_irq_put(adev, &adev->vcn.inst[i].irq, 0);
        }
 
        return 0;
@@ -1668,22 +1666,6 @@ static int vcn_v4_0_5_set_powergating_state(void *handle, enum amd_powergating_s
        return ret;
 }
 
-/**
- * vcn_v4_0_5_set_interrupt_state - set VCN block interrupt state
- *
- * @adev: amdgpu_device pointer
- * @source: interrupt sources
- * @type: interrupt types
- * @state: interrupt states
- *
- * Set VCN block interrupt state
- */
-static int vcn_v4_0_5_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source,
-               unsigned type, enum amdgpu_interrupt_state state)
-{
-       return 0;
-}
-
 /**
  * vcn_v4_0_5_process_interrupt - process VCN block interrupt
  *
@@ -1726,7 +1708,6 @@ static int vcn_v4_0_5_process_interrupt(struct amdgpu_device *adev, struct amdgp
 }
 
 static const struct amdgpu_irq_src_funcs vcn_v4_0_5_irq_funcs = {
-       .set = vcn_v4_0_5_set_interrupt_state,
        .process = vcn_v4_0_5_process_interrupt,
 };
 
index d364c6dd152c33b7fc1fbc614668b2dd4ffe223a..bf68e18e3824b8e492c2451b655bfcf5068910f6 100644 (file)
@@ -373,6 +373,12 @@ static u32 vega10_ih_get_wptr(struct amdgpu_device *adev,
        tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
        WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
 
+       /* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+        * can be detected.
+        */
+       tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
+       WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
+
 out:
        return (wptr & ih->ptr_mask);
 }
index ddfc6941f9d559c916fe2cdb66b4e27394f1d618..db66e6cccaf2aa4e596a8f377eed8030c55159b7 100644 (file)
@@ -421,6 +421,12 @@ static u32 vega20_ih_get_wptr(struct amdgpu_device *adev,
        tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
        WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
 
+       /* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+        * can be detected.
+        */
+       tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
+       WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
+
 out:
        return (wptr & ih->ptr_mask);
 }
index df75863393fcb887613fb4dc054977fb46a49b1e..d1caaf0e6a7c4eaed98fc8f390781719bf28b846 100644 (file)
@@ -674,7 +674,7 @@ static const uint32_t cwsr_trap_gfx9_hex[] = {
        0x86ea6a6a, 0x8f6e837a,
        0xb96ee0c2, 0xbf800002,
        0xb97a0002, 0xbf8a0000,
-       0xbe801f6c, 0xbf810000,
+       0xbe801f6c, 0xbf9b0000,
 };
 
 static const uint32_t cwsr_trap_nv1x_hex[] = {
@@ -1091,7 +1091,7 @@ static const uint32_t cwsr_trap_nv1x_hex[] = {
        0xb9eef807, 0x876dff6d,
        0x0000ffff, 0x87fe7e7e,
        0x87ea6a6a, 0xb9faf802,
-       0xbe80226c, 0xbf810000,
+       0xbe80226c, 0xbf9b0000,
        0xbf9f0000, 0xbf9f0000,
        0xbf9f0000, 0xbf9f0000,
        0xbf9f0000, 0x00000000,
@@ -1574,7 +1574,7 @@ static const uint32_t cwsr_trap_arcturus_hex[] = {
        0x86ea6a6a, 0x8f6e837a,
        0xb96ee0c2, 0xbf800002,
        0xb97a0002, 0xbf8a0000,
-       0xbe801f6c, 0xbf810000,
+       0xbe801f6c, 0xbf9b0000,
 };
 
 static const uint32_t cwsr_trap_aldebaran_hex[] = {
@@ -2065,7 +2065,7 @@ static const uint32_t cwsr_trap_aldebaran_hex[] = {
        0x86ea6a6a, 0x8f6e837a,
        0xb96ee0c2, 0xbf800002,
        0xb97a0002, 0xbf8a0000,
-       0xbe801f6c, 0xbf810000,
+       0xbe801f6c, 0xbf9b0000,
 };
 
 static const uint32_t cwsr_trap_gfx10_hex[] = {
@@ -2500,7 +2500,7 @@ static const uint32_t cwsr_trap_gfx10_hex[] = {
        0x876dff6d, 0x0000ffff,
        0x87fe7e7e, 0x87ea6a6a,
        0xb9faf802, 0xbe80226c,
-       0xbf810000, 0xbf9f0000,
+       0xbf9b0000, 0xbf9f0000,
        0xbf9f0000, 0xbf9f0000,
        0xbf9f0000, 0xbf9f0000,
 };
@@ -2944,7 +2944,7 @@ static const uint32_t cwsr_trap_gfx11_hex[] = {
        0xb8eef802, 0xbf0d866e,
        0xbfa20002, 0xb97af802,
        0xbe80486c, 0xb97af802,
-       0xbe804a6c, 0xbfb00000,
+       0xbe804a6c, 0xbfb10000,
        0xbf9f0000, 0xbf9f0000,
        0xbf9f0000, 0xbf9f0000,
        0xbf9f0000, 0x00000000,
@@ -3436,5 +3436,5 @@ static const uint32_t cwsr_trap_gfx9_4_3_hex[] = {
        0x86ea6a6a, 0x8f6e837a,
        0xb96ee0c2, 0xbf800002,
        0xb97a0002, 0xbf8a0000,
-       0xbe801f6c, 0xbf810000,
+       0xbe801f6c, 0xbf9b0000,
 };
index e0140df0b0ec8086433048adb31a06ca6aca740d..71b3dc0c73634aef86846be3669723590ca55db9 100644 (file)
@@ -1104,7 +1104,7 @@ L_RETURN_WITHOUT_PRIV:
        s_rfe_b64       s_restore_pc_lo                                         //Return to the main shader program and resume execution
 
 L_END_PGM:
-       s_endpgm
+       s_endpgm_saved
 end
 
 function write_hwreg_to_mem(s, s_rsrc, s_mem_offset)
index e506411ad28ab99f474eca96ff37254fb43078de..bb26338204f4ba84b5ae41a781e1becdf9ad72bb 100644 (file)
@@ -921,7 +921,7 @@ L_RESTORE:
 /*                     the END                                           */
 /**************************************************************************/
 L_END_PGM:
-    s_endpgm
+    s_endpgm_saved
 
 end
 
index ce4c52ec34d80eabb7f7664051ccebcd2f0ec64e..80e90fdef291d5b8cdcf7d08c6e319150fcf631b 100644 (file)
@@ -1442,7 +1442,9 @@ static int kfd_ioctl_unmap_memory_from_gpu(struct file *filep,
                        kfd_flush_tlb(peer_pdd, TLB_FLUSH_HEAVYWEIGHT);
 
                /* Remove dma mapping after tlb flush to avoid IO_PAGE_FAULT */
-               amdgpu_amdkfd_gpuvm_dmaunmap_mem(mem, peer_pdd->drm_priv);
+               err = amdgpu_amdkfd_gpuvm_dmaunmap_mem(mem, peer_pdd->drm_priv);
+               if (err)
+                       goto sync_memory_failed;
        }
 
        mutex_unlock(&p->mutex);
index f856901055d34e605cd4ec51fbdfc3be18e2abeb..bdc01ca9609a7e57fac05ee60d6866a5950e2b07 100644 (file)
@@ -574,7 +574,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
        pr_debug("svms 0x%p [0x%lx 0x%lx]\n", prange->svms, prange->start,
                 prange->last);
 
-       addr = prange->start << PAGE_SHIFT;
+       addr = migrate->start;
 
        src = (uint64_t *)(scratch + npages);
        dst = scratch;
index 8b7fed91352696cf2b5cafab0680ad0737fa95ee..22cbfa1bdaddb9a764053421b16159391c1ba56d 100644 (file)
@@ -170,6 +170,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
        m->cp_hqd_pq_control = 5 << CP_HQD_PQ_CONTROL__RPTR_BLOCK_SIZE__SHIFT;
        m->cp_hqd_pq_control |=
                        ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1;
+       m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__UNORD_DISPATCH_MASK;
        pr_debug("cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control);
 
        m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
index 15277f1d5cf0a9d9eb694ccaeec540e467ab774a..d722cbd317834a8a893a0ed5a847feb3a51d6961 100644 (file)
@@ -224,6 +224,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
        m->cp_hqd_pq_control = 5 << CP_HQD_PQ_CONTROL__RPTR_BLOCK_SIZE__SHIFT;
        m->cp_hqd_pq_control |=
                        ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1;
+       m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__UNORD_DISPATCH_MASK;
        pr_debug("cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control);
 
        m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
index 17fbedbf3651388edfcd0109a22d0fe9dfcd331f..677281c0793e23a694eb5a7bba9b5f9fd48f61d8 100644 (file)
@@ -1488,10 +1488,15 @@ void kfd_dec_compute_active(struct kfd_node *dev);
 
 /* Cgroup Support */
 /* Check with device cgroup if @kfd device is accessible */
-static inline int kfd_devcgroup_check_permission(struct kfd_node *kfd)
+static inline int kfd_devcgroup_check_permission(struct kfd_node *node)
 {
 #if defined(CONFIG_CGROUP_DEVICE) || defined(CONFIG_CGROUP_BPF)
-       struct drm_device *ddev = adev_to_drm(kfd->adev);
+       struct drm_device *ddev;
+
+       if (node->xcp)
+               ddev = node->xcp->ddev;
+       else
+               ddev = adev_to_drm(node->adev);
 
        return devcgroup_check_permission(DEVCG_DEV_CHAR, DRM_MAJOR,
                                          ddev->render->index,
index d4f525b66a09055909e163b815beee357f28d19d..d292f290cd6ebbfe4a2174923470a2f60e1eadc7 100644 (file)
@@ -272,6 +272,7 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
 {
        u32 v_blank_start, v_blank_end, h_position, v_position;
        struct amdgpu_crtc *acrtc = NULL;
+       struct dc *dc = adev->dm.dc;
 
        if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc))
                return -EINVAL;
@@ -284,6 +285,9 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
                return 0;
        }
 
+       if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed)
+               dc_allow_idle_optimizations(dc, false);
+
        /*
         * TODO rework base driver to use values directly.
         * for now parse it back into reg-format
@@ -1715,7 +1719,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
        init_data.nbio_reg_offsets = adev->reg_offset[NBIO_HWIP][0];
        init_data.clk_reg_offsets = adev->reg_offset[CLK_HWIP][0];
 
-       init_data.flags.disable_ips = DMUB_IPS_DISABLE_ALL;
+       if (amdgpu_dc_debug_mask & DC_DISABLE_IPS)
+               init_data.flags.disable_ips = DMUB_IPS_DISABLE_ALL;
+
+       init_data.flags.disable_ips_in_vpb = 1;
 
        /* Enable DWB for tested platforms only */
        if (amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 0, 0))
@@ -8976,16 +8983,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
 
        trace_amdgpu_dm_atomic_commit_tail_begin(state);
 
-       if (dm->dc->caps.ips_support) {
-               for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
-                       if (new_con_state->crtc &&
-                               new_con_state->crtc->state->active &&
-                               drm_atomic_crtc_needs_modeset(new_con_state->crtc->state)) {
-                               dc_dmub_srv_apply_idle_power_optimizations(dm->dc, false);
-                               break;
-                       }
-               }
-       }
+       if (dm->dc->caps.ips_support && dm->dc->idle_optimizations_allowed)
+               dc_allow_idle_optimizations(dm->dc, false);
 
        drm_atomic_helper_update_legacy_modeset_state(dev, state);
        drm_dp_mst_atomic_wait_for_dependencies(state);
@@ -9188,6 +9187,10 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                 * To fix this, DC should permit updating only stream properties.
                 */
                dummy_updates = kzalloc(sizeof(struct dc_surface_update) * MAX_SURFACES, GFP_ATOMIC);
+               if (!dummy_updates) {
+                       DRM_ERROR("Failed to allocate memory for dummy_updates.\n");
+                       continue;
+               }
                for (j = 0; j < status->plane_count; j++)
                        dummy_updates[j].surface = status->plane_states[0];
 
index 58b880acb087ae73352e9ac487d5ccd033f03f4d..3390f0d8420a05dc6d9daae1f3d8c4f53de57aed 100644 (file)
@@ -711,7 +711,7 @@ static inline int dm_irq_state(struct amdgpu_device *adev,
 {
        bool st;
        enum dc_irq_source irq_source;
-
+       struct dc *dc = adev->dm.dc;
        struct amdgpu_crtc *acrtc = adev->mode_info.crtcs[crtc_id];
 
        if (!acrtc) {
@@ -729,6 +729,9 @@ static inline int dm_irq_state(struct amdgpu_device *adev,
 
        st = (state == AMDGPU_IRQ_STATE_ENABLE);
 
+       if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed)
+               dc_allow_idle_optimizations(dc, false);
+
        dc_interrupt_set(adev->dm.dc, irq_source, st);
        return 0;
 }
index 9c660d1facc7699d7a1b3f90292ae31d985fd259..14cec1c7b718c4ab48fbd9588f4b6465c13897cd 100644 (file)
@@ -437,32 +437,32 @@ static struct wm_table ddr5_wm_table = {
                        .wm_inst = WM_A,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 14.0,
-                       .sr_enter_plus_exit_time_us = 16.0,
+                       .sr_exit_time_us = 28.0,
+                       .sr_enter_plus_exit_time_us = 30.0,
                        .valid = true,
                },
                {
                        .wm_inst = WM_B,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 14.0,
-                       .sr_enter_plus_exit_time_us = 16.0,
+                       .sr_exit_time_us = 28.0,
+                       .sr_enter_plus_exit_time_us = 30.0,
                        .valid = true,
                },
                {
                        .wm_inst = WM_C,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 14.0,
-                       .sr_enter_plus_exit_time_us = 16.0,
+                       .sr_exit_time_us = 28.0,
+                       .sr_enter_plus_exit_time_us = 30.0,
                        .valid = true,
                },
                {
                        .wm_inst = WM_D,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 14.0,
-                       .sr_enter_plus_exit_time_us = 16.0,
+                       .sr_exit_time_us = 28.0,
+                       .sr_enter_plus_exit_time_us = 30.0,
                        .valid = true,
                },
        }
@@ -474,32 +474,32 @@ static struct wm_table lpddr5_wm_table = {
                        .wm_inst = WM_A,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 14.0,
-                       .sr_enter_plus_exit_time_us = 16.0,
+                       .sr_exit_time_us = 28.0,
+                       .sr_enter_plus_exit_time_us = 30.0,
                        .valid = true,
                },
                {
                        .wm_inst = WM_B,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 14.0,
-                       .sr_enter_plus_exit_time_us = 16.0,
+                       .sr_exit_time_us = 28.0,
+                       .sr_enter_plus_exit_time_us = 30.0,
                        .valid = true,
                },
                {
                        .wm_inst = WM_C,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 14.0,
-                       .sr_enter_plus_exit_time_us = 16.0,
+                       .sr_exit_time_us = 28.0,
+                       .sr_enter_plus_exit_time_us = 30.0,
                        .valid = true,
                },
                {
                        .wm_inst = WM_D,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 14.0,
-                       .sr_enter_plus_exit_time_us = 16.0,
+                       .sr_exit_time_us = 28.0,
+                       .sr_enter_plus_exit_time_us = 30.0,
                        .valid = true,
                },
        }
index 5d7aa882416b3435a5dcfbaf502a9f326981bc81..c9317ea0258ea1cb2f686830fddc7469158966cc 100644 (file)
@@ -434,6 +434,7 @@ struct dc_config {
        bool EnableMinDispClkODM;
        bool enable_auto_dpm_test_logs;
        unsigned int disable_ips;
+       unsigned int disable_ips_in_vpb;
 };
 
 enum visual_confirm {
index b08ccb8c68bc366386e82a566c452459da0aabdc..9900dda2eef5cd2e44e6dbd008cd411194d107af 100644 (file)
@@ -1034,6 +1034,7 @@ enum replay_FW_Message_type {
        Replay_Msg_Not_Support = -1,
        Replay_Set_Timing_Sync_Supported,
        Replay_Set_Residency_Frameupdate_Timer,
+       Replay_Set_Pseudo_VTotal,
 };
 
 union replay_error_status {
@@ -1089,6 +1090,10 @@ struct replay_settings {
        uint16_t coasting_vtotal_table[PR_COASTING_TYPE_NUM];
        /* Maximum link off frame count */
        enum replay_link_off_frame_count_level link_off_frame_count_level;
+       /* Replay pseudo vtotal for abm + ips on full screen video which can improve ips residency */
+       uint16_t abm_with_ips_on_full_screen_video_pseudo_vtotal;
+       /* Replay last pseudo vtotal set to DMUB */
+       uint16_t last_pseudo_vtotal;
 };
 
 /* To split out "global" and "per-panel" config settings.
index 501388014855c5a1f830b6a830d9f6eed9bf3224..d761b0df28784afd5d81dfef193dfc11657ddff2 100644 (file)
@@ -203,12 +203,12 @@ void dcn32_link_encoder_construct(
        enc10->base.hpd_source = init_data->hpd_source;
        enc10->base.connector = init_data->connector;
 
-       if (enc10->base.connector.id == CONNECTOR_ID_USBC)
-               enc10->base.features.flags.bits.DP_IS_USB_C = 1;
 
        enc10->base.preferred_engine = ENGINE_ID_UNKNOWN;
 
        enc10->base.features = *enc_features;
+       if (enc10->base.connector.id == CONNECTOR_ID_USBC)
+               enc10->base.features.flags.bits.DP_IS_USB_C = 1;
 
        enc10->base.transmitter = init_data->transmitter;
 
index da94e5309fbaf0f8e06a4a1aad4ce431a8d9f2cc..81e349d5835bbed499f03ef6eb33e5210c83d64b 100644 (file)
@@ -184,8 +184,6 @@ void dcn35_link_encoder_construct(
        enc10->base.hpd_source = init_data->hpd_source;
        enc10->base.connector = init_data->connector;
 
-       if (enc10->base.connector.id == CONNECTOR_ID_USBC)
-               enc10->base.features.flags.bits.DP_IS_USB_C = 1;
 
        enc10->base.preferred_engine = ENGINE_ID_UNKNOWN;
 
@@ -240,6 +238,8 @@ void dcn35_link_encoder_construct(
        }
 
        enc10->base.features.flags.bits.HDMI_6GB_EN = 1;
+       if (enc10->base.connector.id == CONNECTOR_ID_USBC)
+               enc10->base.features.flags.bits.DP_IS_USB_C = 1;
 
        if (bp_funcs->get_connector_speed_cap_info)
                result = bp_funcs->get_connector_speed_cap_info(enc10->base.ctx->dc_bios,
index 9f37f717a1f86f88c5fa41bc30f477406d70f3b8..dd781a20692ee68847aadccea38fecc69a2e3683 100644 (file)
@@ -1112,7 +1112,7 @@ struct pipe_slice_table {
                struct pipe_ctx *pri_pipe;
                struct dc_plane_state *plane;
                int slice_count;
-       } mpc_combines[MAX_SURFACES];
+       } mpc_combines[MAX_PLANES];
        int mpc_combine_count;
 };
 
@@ -2753,7 +2753,7 @@ static int build_synthetic_soc_states(bool disable_dc_mode_overwrite, struct clk
        struct _vcs_dpi_voltage_scaling_st entry = {0};
        struct clk_limit_table_entry max_clk_data = {0};
 
-       unsigned int min_dcfclk_mhz = 199, min_fclk_mhz = 299;
+       unsigned int min_dcfclk_mhz = 399, min_fclk_mhz = 599;
 
        static const unsigned int num_dcfclk_stas = 5;
        unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {199, 615, 906, 1324, 1564};
index 475c4ec43c013f481a71ad5668a8aef82ac7ba0a..7ea2bd5374d51b138d13179ab7444d0d8d2ef3a7 100644 (file)
@@ -164,8 +164,8 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_5_soc = {
                },
        },
        .num_states = 5,
-       .sr_exit_time_us = 14.0,
-       .sr_enter_plus_exit_time_us = 16.0,
+       .sr_exit_time_us = 28.0,
+       .sr_enter_plus_exit_time_us = 30.0,
        .sr_exit_z8_time_us = 210.0,
        .sr_enter_plus_exit_z8_time_us = 320.0,
        .fclk_change_latency_us = 24.0,
index 64d01a9cd68c859db9bcffbc478ef09090b07fbf..23a608274096f89002e7e5438be18c85d023e442 100644 (file)
@@ -341,9 +341,6 @@ void dml2_init_soc_states(struct dml2_context *dml2, const struct dc *in_dc,
                break;
        }
 
-       if (dml2->config.bbox_overrides.clks_table.num_states)
-                       p->in_states->num_states = dml2->config.bbox_overrides.clks_table.num_states;
-
        /* Override from passed values, if available */
        for (i = 0; i < p->in_states->num_states; i++) {
                if (dml2->config.bbox_overrides.sr_exit_latency_us) {
@@ -400,6 +397,7 @@ void dml2_init_soc_states(struct dml2_context *dml2, const struct dc *in_dc,
        }
        /* Copy clocks tables entries, if available */
        if (dml2->config.bbox_overrides.clks_table.num_states) {
+               p->in_states->num_states = dml2->config.bbox_overrides.clks_table.num_states;
 
                for (i = 0; i < dml2->config.bbox_overrides.clks_table.num_entries_per_clk.num_dcfclk_levels; i++) {
                        p->in_states->state_array[i].dcfclk_mhz = dml2->config.bbox_overrides.clks_table.clk_entries[i].dcfclk_mhz;
@@ -793,35 +791,28 @@ static void populate_dml_surface_cfg_from_plane_state(enum dml_project_id dml2_p
        }
 }
 
-/*TODO no support for mpc combine, need rework - should calculate scaling params based on plane+stream*/
-static struct scaler_data get_scaler_data_for_plane(const struct dc_plane_state *in, const struct dc_state *context)
+static struct scaler_data get_scaler_data_for_plane(const struct dc_plane_state *in, struct dc_state *context)
 {
        int i;
-       struct scaler_data data = { 0 };
+       struct pipe_ctx *temp_pipe = &context->res_ctx.temp_pipe;
+
+       memset(temp_pipe, 0, sizeof(struct pipe_ctx));
 
        for (i = 0; i < MAX_PIPES; i++) {
                const struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
 
                if (pipe->plane_state == in && !pipe->prev_odm_pipe) {
-                       const struct pipe_ctx *next_pipe = pipe->next_odm_pipe;
-
-                       data = context->res_ctx.pipe_ctx[i].plane_res.scl_data;
-                       while (next_pipe) {
-                               data.h_active += next_pipe->plane_res.scl_data.h_active;
-                               data.recout.width += next_pipe->plane_res.scl_data.recout.width;
-                               if (in->rotation == ROTATION_ANGLE_0 || in->rotation == ROTATION_ANGLE_180) {
-                                       data.viewport.width += next_pipe->plane_res.scl_data.viewport.width;
-                               } else {
-                                       data.viewport.height += next_pipe->plane_res.scl_data.viewport.height;
-                               }
-                               next_pipe = next_pipe->next_odm_pipe;
-                       }
+                       temp_pipe->stream = pipe->stream;
+                       temp_pipe->plane_state = pipe->plane_state;
+                       temp_pipe->plane_res.scl_data.taps = pipe->plane_res.scl_data.taps;
+
+                       resource_build_scaling_params(temp_pipe);
                        break;
                }
        }
 
        ASSERT(i < MAX_PIPES);
-       return data;
+       return temp_pipe->plane_res.scl_data;
 }
 
 static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned int location, const struct dc_stream_state *in)
@@ -866,7 +857,7 @@ static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned
        out->ScalerEnabled[location] = false;
 }
 
-static void populate_dml_plane_cfg_from_plane_state(struct dml_plane_cfg_st *out, unsigned int location, const struct dc_plane_state *in, const struct dc_state *context)
+static void populate_dml_plane_cfg_from_plane_state(struct dml_plane_cfg_st *out, unsigned int location, const struct dc_plane_state *in, struct dc_state *context)
 {
        const struct scaler_data scaler_data = get_scaler_data_for_plane(in, context);
 
index 5660f15da291e9de58637c115e315b07f1cee7a3..2352428bcea3cab551aef88fe8bc781c443f6914 100644 (file)
@@ -1183,9 +1183,9 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
                dto_params.timing = &pipe_ctx->stream->timing;
                dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;
                if (dccg) {
-                       dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
                        dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst);
                        dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, dp_hpo_inst);
+                       dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
                }
        } else if (dccg && dccg->funcs->disable_symclk_se) {
                dccg->funcs->disable_symclk_se(dccg, stream_enc->stream_enc_inst,
index e931342fcf4cf1d4f4b0cf41628cd9f855fa6dac..4853ecac53f91f90a774192236e2d74ba6779c08 100644 (file)
@@ -2790,18 +2790,17 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
        }
 
        if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
-               dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;
-               dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, dp_hpo_inst);
-
-               phyd32clk = get_phyd32clk_src(link);
-               dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk);
-
                dto_params.otg_inst = tg->inst;
                dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
                dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx);
                dto_params.timing = &pipe_ctx->stream->timing;
                dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
                dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
+               dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;
+               dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, dp_hpo_inst);
+
+               phyd32clk = get_phyd32clk_src(link);
+               dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk);
        } else {
                if (dccg->funcs->enable_symclk_se)
                        dccg->funcs->enable_symclk_se(dccg, stream_enc->stream_enc_inst,
index 9c806385ecbdcce6c0d14f949ea41879758969f7..8b6c49622f3b63c8e6dae68c507e1e45c5a736a2 100644 (file)
@@ -680,7 +680,7 @@ void dcn35_power_down_on_boot(struct dc *dc)
 bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable)
 {
        struct dc_link *edp_links[MAX_NUM_EDP];
-       int edp_num;
+       int i, edp_num;
        if (dc->debug.dmcub_emulation)
                return true;
 
@@ -688,6 +688,13 @@ bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable)
                dc_get_edp_links(dc, edp_links, &edp_num);
                if (edp_num == 0 || edp_num > 1)
                        return false;
+
+               for (i = 0; i < dc->current_state->stream_count; ++i) {
+                       struct dc_stream_state *stream = dc->current_state->streams[i];
+
+                       if (!stream->dpms_off && !dc_is_embedded_signal(stream->signal))
+                               return false;
+               }
        }
 
        // TODO: review other cases when idle optimization is allowed
index f74ae0d41d3c49cf215d615f336339b773cbbcbc..3a6bf77a68732166d320dbea642929c3201d3e01 100644 (file)
@@ -469,6 +469,8 @@ struct resource_context {
        unsigned int hpo_dp_link_enc_to_link_idx[MAX_HPO_DP2_LINK_ENCODERS];
        int hpo_dp_link_enc_ref_cnts[MAX_HPO_DP2_LINK_ENCODERS];
        bool is_mpc_3dlut_acquired[MAX_PIPES];
+       /* solely used for build scalar data in dml2 */
+       struct pipe_ctx temp_pipe;
 };
 
 struct dce_bw_output {
index dd0d2b206462c927c5f68b355498e71250c154b9..5491b707cec881b9854ab96834503c1e88053380 100644 (file)
@@ -196,7 +196,7 @@ static int get_host_router_total_dp_tunnel_bw(const struct dc *dc, uint8_t hr_in
        struct dc_link *link_dpia_primary, *link_dpia_secondary;
        int total_bw = 0;
 
-       for (uint8_t i = 0; i < MAX_PIPES * 2; ++i) {
+       for (uint8_t i = 0; i < (MAX_PIPES * 2) - 1; ++i) {
 
                if (!dc->links[i] || dc->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA)
                        continue;
index 5c9a30211c109f749ab7e1cceb402bd7a0dcb786..fc50931c2aecbb53d74a2d48913e608134510940 100644 (file)
@@ -205,7 +205,7 @@ enum dc_status core_link_read_dpcd(
        uint32_t extended_size;
        /* size of the remaining partitioned address space */
        uint32_t size_left_to_read;
-       enum dc_status status;
+       enum dc_status status = DC_ERROR_UNEXPECTED;
        /* size of the next partition to be read from */
        uint32_t partition_size;
        uint32_t data_index = 0;
@@ -234,7 +234,7 @@ enum dc_status core_link_write_dpcd(
 {
        uint32_t partition_size;
        uint32_t data_index = 0;
-       enum dc_status status;
+       enum dc_status status = DC_ERROR_UNEXPECTED;
 
        while (size) {
                partition_size = dpcd_get_next_partition_size(address, size);
index c64b6c848ef7219e3ddc44da8d4e56763a9bf7f4..e699731ee68e96388c52ed55c17b34cc8710aaab 100644 (file)
@@ -2832,6 +2832,7 @@ struct dmub_rb_cmd_psr_set_power_opt {
 #define REPLAY_RESIDENCY_MODE_MASK             (0x1 << REPLAY_RESIDENCY_MODE_SHIFT)
 # define REPLAY_RESIDENCY_MODE_PHY             (0x0 << REPLAY_RESIDENCY_MODE_SHIFT)
 # define REPLAY_RESIDENCY_MODE_ALPM            (0x1 << REPLAY_RESIDENCY_MODE_SHIFT)
+# define REPLAY_RESIDENCY_MODE_IPS             0x10
 
 #define REPLAY_RESIDENCY_ENABLE_MASK           (0x1 << REPLAY_RESIDENCY_ENABLE_SHIFT)
 # define REPLAY_RESIDENCY_DISABLE              (0x0 << REPLAY_RESIDENCY_ENABLE_SHIFT)
@@ -2894,6 +2895,10 @@ enum dmub_cmd_replay_type {
         * Set Residency Frameupdate Timer.
         */
        DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER = 6,
+       /**
+        * Set pseudo vtotal
+        */
+       DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL = 7,
 };
 
 /**
@@ -3076,6 +3081,26 @@ struct dmub_cmd_replay_set_timing_sync_data {
        uint8_t pad[2];
 };
 
+/**
+ * Data passed from driver to FW in a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command.
+ */
+struct dmub_cmd_replay_set_pseudo_vtotal {
+       /**
+        * Panel Instance.
+        * Panel isntance to identify which replay_state to use
+        * Currently the support is only for 0 or 1
+        */
+       uint8_t panel_inst;
+       /**
+        * Source Vtotal that Replay + IPS + ABM full screen video src vtotal
+        */
+       uint16_t vtotal;
+       /**
+        * Explicit padding to 4 byte boundary.
+        */
+       uint8_t pad;
+};
+
 /**
  * Definition of a DMUB_CMD__SET_REPLAY_POWER_OPT command.
  */
@@ -3156,6 +3181,20 @@ struct dmub_rb_cmd_replay_set_timing_sync {
        struct dmub_cmd_replay_set_timing_sync_data replay_set_timing_sync_data;
 };
 
+/**
+ * Definition of a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command.
+ */
+struct dmub_rb_cmd_replay_set_pseudo_vtotal {
+       /**
+        * Command header.
+        */
+       struct dmub_cmd_header header;
+       /**
+        * Definition of DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command.
+        */
+       struct dmub_cmd_replay_set_pseudo_vtotal data;
+};
+
 /**
  * Data passed from driver to FW in  DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command.
  */
@@ -3207,6 +3246,10 @@ union dmub_replay_cmd_set {
         * Definition of DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command data.
         */
        struct dmub_cmd_replay_frameupdate_timer_data timer_data;
+       /**
+        * Definition of DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command data.
+        */
+       struct dmub_cmd_replay_set_pseudo_vtotal pseudo_vtotal_data;
 };
 
 /**
@@ -4358,6 +4401,10 @@ union dmub_rb_cmd {
         * Definition of a DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command.
         */
        struct dmub_rb_cmd_replay_set_frameupdate_timer replay_set_frameupdate_timer;
+       /**
+        * Definition of a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command.
+        */
+       struct dmub_rb_cmd_replay_set_pseudo_vtotal replay_set_pseudo_vtotal;
 };
 
 /**
index ad98e504c00de5908ca94a38392ef818e91b2152..e304e8435fb8f1c5e29428f72c20a6097fb57697 100644 (file)
@@ -980,6 +980,11 @@ void set_replay_coasting_vtotal(struct dc_link *link,
        link->replay_settings.coasting_vtotal_table[type] = vtotal;
 }
 
+void set_replay_ips_full_screen_video_src_vtotal(struct dc_link *link, uint16_t vtotal)
+{
+       link->replay_settings.abm_with_ips_on_full_screen_video_pseudo_vtotal = vtotal;
+}
+
 void calculate_replay_link_off_frame_count(struct dc_link *link,
        uint16_t vtotal, uint16_t htotal)
 {
index c17bbc6fb38cafb518777b16c96a99b2116c36eb..bef4815e1703d78cdebc6f49bc160932d08c5272 100644 (file)
@@ -57,6 +57,7 @@ void init_replay_config(struct dc_link *link, struct replay_config *pr_config);
 void set_replay_coasting_vtotal(struct dc_link *link,
        enum replay_coasting_vtotal_type type,
        uint16_t vtotal);
+void set_replay_ips_full_screen_video_src_vtotal(struct dc_link *link, uint16_t vtotal);
 void calculate_replay_link_off_frame_count(struct dc_link *link,
        uint16_t vtotal, uint16_t htotal);
 
index 1dc5dd9b7bf70b10641a76e4c731e3e735aeaeef..df2c7ffe190f4db36050901dce5af89180646f3b 100644 (file)
@@ -258,6 +258,7 @@ enum DC_DEBUG_MASK {
        DC_ENABLE_DML2 = 0x100,
        DC_DISABLE_PSR_SU = 0x200,
        DC_DISABLE_REPLAY = 0x400,
+       DC_DISABLE_IPS = 0x800,
 };
 
 enum amd_dpm_forced_level;
index be519c8edf496fda93f393a077f174454e635a05..335980e2afbfb8e6eae89e7f28fdcc3391d39cde 100644 (file)
@@ -138,7 +138,7 @@ static inline size_t amdgpu_reginst_size(uint16_t num_inst, size_t inst_size,
 }
 
 #define amdgpu_asic_get_reg_state_supported(adev) \
-       ((adev)->asic_funcs->get_reg_state ? 1 : 0)
+       (((adev)->asic_funcs && (adev)->asic_funcs->get_reg_state) ? 1 : 0)
 
 #define amdgpu_asic_get_reg_state(adev, state, buf, size)                  \
        ((adev)->asic_funcs->get_reg_state ?                               \
index c16703868e5ca2a3f0a7f6c7e3757b8e6ba036d0..0ad947df777ab2665a8f0de986a5d39737dd9ded 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <linux/firmware.h>
 #include <linux/pci.h>
+#include <linux/power_supply.h>
 #include <linux/reboot.h>
 
 #include "amdgpu.h"
@@ -733,7 +734,7 @@ static int smu_early_init(void *handle)
        smu->adev = adev;
        smu->pm_enabled = !!amdgpu_dpm;
        smu->is_apu = false;
-       smu->smu_baco.state = SMU_BACO_STATE_NONE;
+       smu->smu_baco.state = SMU_BACO_STATE_EXIT;
        smu->smu_baco.platform_support = false;
        smu->user_dpm_profile.fan_mode = -1;
 
@@ -817,16 +818,8 @@ static int smu_late_init(void *handle)
         * handle the switch automatically. Driver involvement
         * is unnecessary.
         */
-       if (!smu->dc_controlled_by_gpio) {
-               ret = smu_set_power_source(smu,
-                                          adev->pm.ac_power ? SMU_POWER_SOURCE_AC :
-                                          SMU_POWER_SOURCE_DC);
-               if (ret) {
-                       dev_err(adev->dev, "Failed to switch to %s mode!\n",
-                               adev->pm.ac_power ? "AC" : "DC");
-                       return ret;
-               }
-       }
+       adev->pm.ac_power = power_supply_is_system_supplied() > 0;
+       smu_set_ac_dc(smu);
 
        if ((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 1)) ||
            (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 3)))
@@ -1961,31 +1954,10 @@ static int smu_smc_hw_cleanup(struct smu_context *smu)
        return 0;
 }
 
-static int smu_reset_mp1_state(struct smu_context *smu)
-{
-       struct amdgpu_device *adev = smu->adev;
-       int ret = 0;
-
-       if ((!adev->in_runpm) && (!adev->in_suspend) &&
-               (!amdgpu_in_reset(adev)))
-               switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
-               case IP_VERSION(13, 0, 0):
-               case IP_VERSION(13, 0, 7):
-               case IP_VERSION(13, 0, 10):
-                       ret = smu_set_mp1_state(smu, PP_MP1_STATE_UNLOAD);
-                       break;
-               default:
-                       break;
-               }
-
-       return ret;
-}
-
 static int smu_hw_fini(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        struct smu_context *smu = adev->powerplay.pp_handle;
-       int ret;
 
        if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev))
                return 0;
@@ -2003,15 +1975,7 @@ static int smu_hw_fini(void *handle)
 
        adev->pm.dpm_enabled = false;
 
-       ret = smu_smc_hw_cleanup(smu);
-       if (ret)
-               return ret;
-
-       ret = smu_reset_mp1_state(smu);
-       if (ret)
-               return ret;
-
-       return 0;
+       return smu_smc_hw_cleanup(smu);
 }
 
 static void smu_late_fini(void *handle)
@@ -2710,6 +2674,7 @@ int smu_get_power_limit(void *handle,
                case SMU_PPT_LIMIT_CURRENT:
                        switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
                        case IP_VERSION(13, 0, 2):
+                       case IP_VERSION(13, 0, 6):
                        case IP_VERSION(11, 0, 7):
                        case IP_VERSION(11, 0, 11):
                        case IP_VERSION(11, 0, 12):
index 2aa4fea873147516c23fb2fc568a94d907ee1c8a..66e84defd0b6ec2521c230262c34215a14251dfb 100644 (file)
@@ -424,7 +424,6 @@ enum smu_reset_mode {
 enum smu_baco_state {
        SMU_BACO_STATE_ENTER = 0,
        SMU_BACO_STATE_EXIT,
-       SMU_BACO_STATE_NONE,
 };
 
 struct smu_baco_context {
index 5a314d0316c1c8410d1f44281e5cc487e4947e81..c7bfa68bf00f400f3396c9853d2c08c6bf971659 100644 (file)
@@ -1442,10 +1442,12 @@ static int smu_v11_0_irq_process(struct amdgpu_device *adev,
                        case 0x3:
                                dev_dbg(adev->dev, "Switched to AC mode!\n");
                                schedule_work(&smu->interrupt_work);
+                               adev->pm.ac_power = true;
                                break;
                        case 0x4:
                                dev_dbg(adev->dev, "Switched to DC mode!\n");
                                schedule_work(&smu->interrupt_work);
+                               adev->pm.ac_power = false;
                                break;
                        case 0x7:
                                /*
index 771a3d457c335e2cc08582a3e4e3a3ba853d2928..c486182ff275222fedfaa1e27c417f9be80d19d0 100644 (file)
@@ -1379,10 +1379,12 @@ static int smu_v13_0_irq_process(struct amdgpu_device *adev,
                        case 0x3:
                                dev_dbg(adev->dev, "Switched to AC mode!\n");
                                smu_v13_0_ack_ac_dc_interrupt(smu);
+                               adev->pm.ac_power = true;
                                break;
                        case 0x4:
                                dev_dbg(adev->dev, "Switched to DC mode!\n");
                                smu_v13_0_ack_ac_dc_interrupt(smu);
+                               adev->pm.ac_power = false;
                                break;
                        case 0x7:
                                /*
index a9b25faa63e468d0069ea08acfd7b90b1b36f056..a9954ffc02c562b91bf1166bb4bf87208152b36a 100644 (file)
@@ -2357,6 +2357,7 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
        PPTable_t *pptable = table_context->driver_pptable;
        SkuTable_t *skutable = &pptable->SkuTable;
        uint32_t power_limit, od_percent_upper, od_percent_lower;
+       uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
 
        if (smu_v13_0_get_current_power_limit(smu, &power_limit))
                power_limit = smu->adev->pm.ac_power ?
@@ -2380,7 +2381,7 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
                                        od_percent_upper, od_percent_lower, power_limit);
 
        if (max_power_limit) {
-               *max_power_limit = power_limit * (100 + od_percent_upper);
+               *max_power_limit = msg_limit * (100 + od_percent_upper);
                *max_power_limit /= 100;
        }
 
@@ -2747,13 +2748,7 @@ static int smu_v13_0_0_set_mp1_state(struct smu_context *smu,
 
        switch (mp1_state) {
        case PP_MP1_STATE_UNLOAD:
-               ret = smu_cmn_send_smc_msg_with_param(smu,
-                                                                                         SMU_MSG_PrepareMp1ForUnload,
-                                                                                         0x55, NULL);
-
-               if (!ret && smu->smu_baco.state == SMU_BACO_STATE_EXIT)
-                       ret = smu_v13_0_disable_pmfw_state(smu);
-
+               ret = smu_cmn_set_mp1_state(smu, mp1_state);
                break;
        default:
                /* Ignore others */
@@ -2949,7 +2944,7 @@ static bool smu_v13_0_0_wbrf_support_check(struct smu_context *smu)
 {
        struct amdgpu_device *adev = smu->adev;
 
-       switch (adev->ip_versions[MP1_HWIP][0]) {
+       switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
        case IP_VERSION(13, 0, 0):
                return smu->smc_fw_version >= 0x004e6300;
        case IP_VERSION(13, 0, 10):
@@ -2959,6 +2954,55 @@ static bool smu_v13_0_0_wbrf_support_check(struct smu_context *smu)
        }
 }
 
+static int smu_v13_0_0_set_power_limit(struct smu_context *smu,
+                                      enum smu_ppt_limit_type limit_type,
+                                      uint32_t limit)
+{
+       PPTable_t *pptable = smu->smu_table.driver_pptable;
+       SkuTable_t *skutable = &pptable->SkuTable;
+       uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
+       struct smu_table_context *table_context = &smu->smu_table;
+       OverDriveTableExternal_t *od_table =
+               (OverDriveTableExternal_t *)table_context->overdrive_table;
+       int ret = 0;
+
+       if (limit_type != SMU_DEFAULT_PPT_LIMIT)
+               return -EINVAL;
+
+       if (limit <= msg_limit) {
+               if (smu->current_power_limit > msg_limit) {
+                       od_table->OverDriveTable.Ppt = 0;
+                       od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT;
+
+                       ret = smu_v13_0_0_upload_overdrive_table(smu, od_table);
+                       if (ret) {
+                               dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
+                               return ret;
+                       }
+               }
+               return smu_v13_0_set_power_limit(smu, limit_type, limit);
+       } else if (smu->od_enabled) {
+               ret = smu_v13_0_set_power_limit(smu, limit_type, msg_limit);
+               if (ret)
+                       return ret;
+
+               od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100;
+               od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT;
+
+               ret = smu_v13_0_0_upload_overdrive_table(smu, od_table);
+               if (ret) {
+                 dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
+                 return ret;
+               }
+
+               smu->current_power_limit = limit;
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
        .get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask,
        .set_default_dpm_table = smu_v13_0_0_set_default_dpm_table,
@@ -3013,7 +3057,7 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
        .set_fan_control_mode = smu_v13_0_set_fan_control_mode,
        .enable_mgpu_fan_boost = smu_v13_0_0_enable_mgpu_fan_boost,
        .get_power_limit = smu_v13_0_0_get_power_limit,
-       .set_power_limit = smu_v13_0_set_power_limit,
+       .set_power_limit = smu_v13_0_0_set_power_limit,
        .set_power_source = smu_v13_0_set_power_source,
        .get_power_profile_mode = smu_v13_0_0_get_power_profile_mode,
        .set_power_profile_mode = smu_v13_0_0_set_power_profile_mode,
index 3c98a8a0386a2612d0470dd6dbd767a6ecc308b0..7e1941cf17964c594dc8821c3fcda75f64e9f145 100644 (file)
@@ -160,8 +160,8 @@ static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COU
        MSG_MAP(GfxDriverResetRecovery,              PPSMC_MSG_GfxDriverResetRecovery,          0),
        MSG_MAP(GetMinGfxclkFrequency,               PPSMC_MSG_GetMinGfxDpmFreq,                1),
        MSG_MAP(GetMaxGfxclkFrequency,               PPSMC_MSG_GetMaxGfxDpmFreq,                1),
-       MSG_MAP(SetSoftMinGfxclk,                    PPSMC_MSG_SetSoftMinGfxClk,                0),
-       MSG_MAP(SetSoftMaxGfxClk,                    PPSMC_MSG_SetSoftMaxGfxClk,                0),
+       MSG_MAP(SetSoftMinGfxclk,                    PPSMC_MSG_SetSoftMinGfxClk,                1),
+       MSG_MAP(SetSoftMaxGfxClk,                    PPSMC_MSG_SetSoftMaxGfxClk,                1),
        MSG_MAP(PrepareMp1ForUnload,                 PPSMC_MSG_PrepareForDriverUnload,          0),
        MSG_MAP(GetCTFLimit,                         PPSMC_MSG_GetCTFLimit,                     0),
        MSG_MAP(GetThermalLimit,                     PPSMC_MSG_ReadThrottlerLimit,              0),
index 59606a19e3d2b4494885b72f36f6524ec25b5139..0ffdb58af74e654af7ca73acf078415663f41dfe 100644 (file)
@@ -2321,6 +2321,7 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu,
        PPTable_t *pptable = table_context->driver_pptable;
        SkuTable_t *skutable = &pptable->SkuTable;
        uint32_t power_limit, od_percent_upper, od_percent_lower;
+       uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
 
        if (smu_v13_0_get_current_power_limit(smu, &power_limit))
                power_limit = smu->adev->pm.ac_power ?
@@ -2344,7 +2345,7 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu,
                                        od_percent_upper, od_percent_lower, power_limit);
 
        if (max_power_limit) {
-               *max_power_limit = power_limit * (100 + od_percent_upper);
+               *max_power_limit = msg_limit * (100 + od_percent_upper);
                *max_power_limit /= 100;
        }
 
@@ -2504,13 +2505,7 @@ static int smu_v13_0_7_set_mp1_state(struct smu_context *smu,
 
        switch (mp1_state) {
        case PP_MP1_STATE_UNLOAD:
-               ret = smu_cmn_send_smc_msg_with_param(smu,
-                                                                                         SMU_MSG_PrepareMp1ForUnload,
-                                                                                         0x55, NULL);
-
-               if (!ret && smu->smu_baco.state == SMU_BACO_STATE_EXIT)
-                       ret = smu_v13_0_disable_pmfw_state(smu);
-
+               ret = smu_cmn_set_mp1_state(smu, mp1_state);
                break;
        default:
                /* Ignore others */
@@ -2545,6 +2540,55 @@ static bool smu_v13_0_7_wbrf_support_check(struct smu_context *smu)
        return smu->smc_fw_version > 0x00524600;
 }
 
+static int smu_v13_0_7_set_power_limit(struct smu_context *smu,
+                                      enum smu_ppt_limit_type limit_type,
+                                      uint32_t limit)
+{
+       PPTable_t *pptable = smu->smu_table.driver_pptable;
+       SkuTable_t *skutable = &pptable->SkuTable;
+       uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
+       struct smu_table_context *table_context = &smu->smu_table;
+       OverDriveTableExternal_t *od_table =
+               (OverDriveTableExternal_t *)table_context->overdrive_table;
+       int ret = 0;
+
+       if (limit_type != SMU_DEFAULT_PPT_LIMIT)
+               return -EINVAL;
+
+       if (limit <= msg_limit) {
+               if (smu->current_power_limit > msg_limit) {
+                       od_table->OverDriveTable.Ppt = 0;
+                       od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT;
+
+                       ret = smu_v13_0_7_upload_overdrive_table(smu, od_table);
+                       if (ret) {
+                               dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
+                               return ret;
+                       }
+               }
+               return smu_v13_0_set_power_limit(smu, limit_type, limit);
+       } else if (smu->od_enabled) {
+               ret = smu_v13_0_set_power_limit(smu, limit_type, msg_limit);
+               if (ret)
+                       return ret;
+
+               od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100;
+               od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT;
+
+               ret = smu_v13_0_7_upload_overdrive_table(smu, od_table);
+               if (ret) {
+                 dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
+                 return ret;
+               }
+
+               smu->current_power_limit = limit;
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
        .get_allowed_feature_mask = smu_v13_0_7_get_allowed_feature_mask,
        .set_default_dpm_table = smu_v13_0_7_set_default_dpm_table,
@@ -2596,7 +2640,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
        .set_fan_control_mode = smu_v13_0_set_fan_control_mode,
        .enable_mgpu_fan_boost = smu_v13_0_7_enable_mgpu_fan_boost,
        .get_power_limit = smu_v13_0_7_get_power_limit,
-       .set_power_limit = smu_v13_0_set_power_limit,
+       .set_power_limit = smu_v13_0_7_set_power_limit,
        .set_power_source = smu_v13_0_set_power_source,
        .get_power_profile_mode = smu_v13_0_7_get_power_profile_mode,
        .set_power_profile_mode = smu_v13_0_7_set_power_profile_mode,
index ef31033439bc15a896ed8748b7a62a8b46336c13..29d91493b101acb5234c9a2fe76441925b346f55 100644 (file)
@@ -1762,6 +1762,7 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux,
        u8 request = msg->request & ~DP_AUX_I2C_MOT;
        int ret = 0;
 
+       mutex_lock(&ctx->aux_lock);
        pm_runtime_get_sync(dev);
        msg->reply = 0;
        switch (request) {
@@ -1778,6 +1779,7 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux,
                                        msg->size, msg->buffer);
        pm_runtime_mark_last_busy(dev);
        pm_runtime_put_autosuspend(dev);
+       mutex_unlock(&ctx->aux_lock);
 
        return ret;
 }
@@ -2474,7 +2476,9 @@ static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge,
        ctx->connector = NULL;
        anx7625_dp_stop(ctx);
 
-       pm_runtime_put_sync(dev);
+       mutex_lock(&ctx->aux_lock);
+       pm_runtime_put_sync_suspend(dev);
+       mutex_unlock(&ctx->aux_lock);
 }
 
 static enum drm_connector_status
@@ -2668,6 +2672,7 @@ static int anx7625_i2c_probe(struct i2c_client *client)
 
        mutex_init(&platform->lock);
        mutex_init(&platform->hdcp_wq_lock);
+       mutex_init(&platform->aux_lock);
 
        INIT_DELAYED_WORK(&platform->hdcp_work, hdcp_check_work_func);
        platform->hdcp_workqueue = create_workqueue("hdcp workqueue");
index 66ebee7f3d832534ec64b780bdfa985bbfcfc896..39ed35d338363390d2fe37b765d4e0e48dc0118e 100644 (file)
@@ -475,6 +475,8 @@ struct anx7625_data {
        struct workqueue_struct *hdcp_workqueue;
        /* Lock for hdcp work queue */
        struct mutex hdcp_wq_lock;
+       /* Lock for aux transfer and disable */
+       struct mutex aux_lock;
        char edid_block;
        struct display_timing dt;
        u8 display_timing_valid;
index 541e4f5afc4c86a4e87b74a016885d6231afb892..14d4dcf239da835955f1d594579dd165288bd63f 100644 (file)
@@ -107,6 +107,7 @@ struct ps8640 {
        struct device_link *link;
        bool pre_enabled;
        bool need_post_hpd_delay;
+       struct mutex aux_lock;
 };
 
 static const struct regmap_config ps8640_regmap_config[] = {
@@ -345,11 +346,20 @@ static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux,
        struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev;
        int ret;
 
+       mutex_lock(&ps_bridge->aux_lock);
        pm_runtime_get_sync(dev);
+       ret = _ps8640_wait_hpd_asserted(ps_bridge, 200 * 1000);
+       if (ret) {
+               pm_runtime_put_sync_suspend(dev);
+               goto exit;
+       }
        ret = ps8640_aux_transfer_msg(aux, msg);
        pm_runtime_mark_last_busy(dev);
        pm_runtime_put_autosuspend(dev);
 
+exit:
+       mutex_unlock(&ps_bridge->aux_lock);
+
        return ret;
 }
 
@@ -470,7 +480,18 @@ static void ps8640_atomic_post_disable(struct drm_bridge *bridge,
        ps_bridge->pre_enabled = false;
 
        ps8640_bridge_vdo_control(ps_bridge, DISABLE);
+
+       /*
+        * The bridge seems to expect everything to be power cycled at the
+        * disable process, so grab a lock here to make sure
+        * ps8640_aux_transfer() is not holding a runtime PM reference and
+        * preventing the bridge from suspend.
+        */
+       mutex_lock(&ps_bridge->aux_lock);
+
        pm_runtime_put_sync_suspend(&ps_bridge->page[PAGE0_DP_CNTL]->dev);
+
+       mutex_unlock(&ps_bridge->aux_lock);
 }
 
 static int ps8640_bridge_attach(struct drm_bridge *bridge,
@@ -619,6 +640,8 @@ static int ps8640_probe(struct i2c_client *client)
        if (!ps_bridge)
                return -ENOMEM;
 
+       mutex_init(&ps_bridge->aux_lock);
+
        ps_bridge->supplies[0].supply = "vdd12";
        ps_bridge->supplies[1].supply = "vdd33";
        ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
index be5914caa17d546601d11719976161624c1a420f..63a1a0c88be4d98d169996d341de5d0d1b6cae91 100644 (file)
@@ -969,10 +969,6 @@ static int samsung_dsim_init_link(struct samsung_dsim *dsi)
        reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG);
        reg &= ~DSIM_STOP_STATE_CNT_MASK;
        reg |= DSIM_STOP_STATE_CNT(driver_data->reg_values[STOP_STATE_CNT]);
-
-       if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type))
-               reg |= DSIM_FORCE_STOP_STATE;
-
        samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg);
 
        reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff);
@@ -1431,18 +1427,6 @@ static void samsung_dsim_disable_irq(struct samsung_dsim *dsi)
        disable_irq(dsi->irq);
 }
 
-static void samsung_dsim_set_stop_state(struct samsung_dsim *dsi, bool enable)
-{
-       u32 reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG);
-
-       if (enable)
-               reg |= DSIM_FORCE_STOP_STATE;
-       else
-               reg &= ~DSIM_FORCE_STOP_STATE;
-
-       samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg);
-}
-
 static int samsung_dsim_init(struct samsung_dsim *dsi)
 {
        const struct samsung_dsim_driver_data *driver_data = dsi->driver_data;
@@ -1492,9 +1476,6 @@ static void samsung_dsim_atomic_pre_enable(struct drm_bridge *bridge,
                ret = samsung_dsim_init(dsi);
                if (ret)
                        return;
-
-               samsung_dsim_set_display_mode(dsi);
-               samsung_dsim_set_display_enable(dsi, true);
        }
 }
 
@@ -1503,12 +1484,8 @@ static void samsung_dsim_atomic_enable(struct drm_bridge *bridge,
 {
        struct samsung_dsim *dsi = bridge_to_dsi(bridge);
 
-       if (samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) {
-               samsung_dsim_set_display_mode(dsi);
-               samsung_dsim_set_display_enable(dsi, true);
-       } else {
-               samsung_dsim_set_stop_state(dsi, false);
-       }
+       samsung_dsim_set_display_mode(dsi);
+       samsung_dsim_set_display_enable(dsi, true);
 
        dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
 }
@@ -1521,9 +1498,6 @@ static void samsung_dsim_atomic_disable(struct drm_bridge *bridge,
        if (!(dsi->state & DSIM_STATE_ENABLED))
                return;
 
-       if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type))
-               samsung_dsim_set_stop_state(dsi, true);
-
        dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE;
 }
 
@@ -1828,8 +1802,6 @@ static ssize_t samsung_dsim_host_transfer(struct mipi_dsi_host *host,
        if (ret)
                return ret;
 
-       samsung_dsim_set_stop_state(dsi, false);
-
        ret = mipi_dsi_create_packet(&xfer.packet, msg);
        if (ret < 0)
                return ret;
index 2bdc5b439bebd56407af3b5b04892b3ac90678d4..4560ae9cbce15095eddaf6296396960a7887ab06 100644 (file)
@@ -1080,6 +1080,26 @@ static int sii902x_init(struct sii902x *sii902x)
                        return ret;
        }
 
+       ret = sii902x_audio_codec_init(sii902x, dev);
+       if (ret)
+               return ret;
+
+       i2c_set_clientdata(sii902x->i2c, sii902x);
+
+       sii902x->i2cmux = i2c_mux_alloc(sii902x->i2c->adapter, dev,
+                                       1, 0, I2C_MUX_GATE,
+                                       sii902x_i2c_bypass_select,
+                                       sii902x_i2c_bypass_deselect);
+       if (!sii902x->i2cmux) {
+               ret = -ENOMEM;
+               goto err_unreg_audio;
+       }
+
+       sii902x->i2cmux->priv = sii902x;
+       ret = i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0);
+       if (ret)
+               goto err_unreg_audio;
+
        sii902x->bridge.funcs = &sii902x_bridge_funcs;
        sii902x->bridge.of_node = dev->of_node;
        sii902x->bridge.timings = &default_sii902x_timings;
@@ -1090,19 +1110,13 @@ static int sii902x_init(struct sii902x *sii902x)
 
        drm_bridge_add(&sii902x->bridge);
 
-       sii902x_audio_codec_init(sii902x, dev);
-
-       i2c_set_clientdata(sii902x->i2c, sii902x);
+       return 0;
 
-       sii902x->i2cmux = i2c_mux_alloc(sii902x->i2c->adapter, dev,
-                                       1, 0, I2C_MUX_GATE,
-                                       sii902x_i2c_bypass_select,
-                                       sii902x_i2c_bypass_deselect);
-       if (!sii902x->i2cmux)
-               return -ENOMEM;
+err_unreg_audio:
+       if (!PTR_ERR_OR_ZERO(sii902x->audio.pdev))
+               platform_device_unregister(sii902x->audio.pdev);
 
-       sii902x->i2cmux->priv = sii902x;
-       return i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0);
+       return ret;
 }
 
 static int sii902x_probe(struct i2c_client *client)
@@ -1170,12 +1184,14 @@ static int sii902x_probe(struct i2c_client *client)
 }
 
 static void sii902x_remove(struct i2c_client *client)
-
 {
        struct sii902x *sii902x = i2c_get_clientdata(client);
 
-       i2c_mux_del_adapters(sii902x->i2cmux);
        drm_bridge_remove(&sii902x->bridge);
+       i2c_mux_del_adapters(sii902x->i2cmux);
+
+       if (!PTR_ERR_OR_ZERO(sii902x->audio.pdev))
+               platform_device_unregister(sii902x->audio.pdev);
 }
 
 static const struct of_device_id sii902x_dt_ids[] = {
index bd6c24d4213cdf2f6bcb132848330f43e4546efd..f7c6b60629c2ba5b178145977d8490a6e094ce71 100644 (file)
@@ -5491,6 +5491,7 @@ EXPORT_SYMBOL(drm_dp_mst_atomic_enable_dsc);
  *   - 0 if the new state is valid
  *   - %-ENOSPC, if the new state is invalid, because of BW limitation
  *         @failing_port is set to:
+ *
  *         - The non-root port where a BW limit check failed
  *           with all the ports downstream of @failing_port passing
  *           the BW limit check.
@@ -5499,6 +5500,7 @@ EXPORT_SYMBOL(drm_dp_mst_atomic_enable_dsc);
  *         - %NULL if the BW limit check failed at the root port
  *           with all the ports downstream of the root port passing
  *           the BW limit check.
+ *
  *   - %-EINVAL, if the new state is invalid, because the root port has
  *     too many payloads.
  */
index 776f2f0b602debb88a6c820add8d737332f2938e..0ef7bc8848b0798b125f7a65ff04cf4586f13d71 100644 (file)
@@ -319,9 +319,9 @@ static void decon_win_set_bldmod(struct decon_context *ctx, unsigned int win,
 static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
                                 struct drm_framebuffer *fb)
 {
-       struct exynos_drm_plane plane = ctx->planes[win];
+       struct exynos_drm_plane *plane = &ctx->planes[win];
        struct exynos_drm_plane_state *state =
-               to_exynos_plane_state(plane.base.state);
+               to_exynos_plane_state(plane->base.state);
        unsigned int alpha = state->base.alpha;
        unsigned int pixel_alpha;
        unsigned long val;
index a9f1c5c058940178c8318484fcea422f1428de69..f2145227a1e0ce889d2ce0a3926a79e64c832fc9 100644 (file)
@@ -480,7 +480,7 @@ static void fimd_commit(struct exynos_drm_crtc *crtc)
        struct fimd_context *ctx = crtc->ctx;
        struct drm_display_mode *mode = &crtc->base.state->adjusted_mode;
        const struct fimd_driver_data *driver_data = ctx->driver_data;
-       void *timing_base = ctx->regs + driver_data->timing_base;
+       void __iomem *timing_base = ctx->regs + driver_data->timing_base;
        u32 val;
 
        if (ctx->suspended)
@@ -661,9 +661,9 @@ static void fimd_win_set_bldmod(struct fimd_context *ctx, unsigned int win,
 static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win,
                                struct drm_framebuffer *fb, int width)
 {
-       struct exynos_drm_plane plane = ctx->planes[win];
+       struct exynos_drm_plane *plane = &ctx->planes[win];
        struct exynos_drm_plane_state *state =
-               to_exynos_plane_state(plane.base.state);
+               to_exynos_plane_state(plane->base.state);
        uint32_t pixel_format = fb->format->format;
        unsigned int alpha = state->base.alpha;
        u32 val = WINCONx_ENWIN;
index e9a769590415dcd0d7899df16254d7c20cdea8b1..180507a477009d6e424cc5aede8e18255127b3f1 100644 (file)
@@ -1341,7 +1341,7 @@ static int __maybe_unused gsc_runtime_resume(struct device *dev)
        for (i = 0; i < ctx->num_clocks; i++) {
                ret = clk_prepare_enable(ctx->clocks[i]);
                if (ret) {
-                       while (--i > 0)
+                       while (--i >= 0)
                                clk_disable_unprepare(ctx->clocks[i]);
                        return ret;
                }
index e777686190ca241f0ed288b2ad32645d41f1a288..c13f14edb50889baa604b044d2324a371e444ed5 100644 (file)
@@ -17,7 +17,6 @@ subdir-ccflags-y += $(call cc-option, -Wunused-const-variable)
 subdir-ccflags-y += $(call cc-option, -Wpacked-not-aligned)
 subdir-ccflags-y += $(call cc-option, -Wformat-overflow)
 subdir-ccflags-y += $(call cc-option, -Wformat-truncation)
-subdir-ccflags-y += $(call cc-option, -Wstringop-overflow)
 subdir-ccflags-y += $(call cc-option, -Wstringop-truncation)
 # The following turn off the warnings enabled by -Wextra
 ifeq ($(findstring 2, $(KBUILD_EXTRA_WARN)),)
index ac456a2275dbad62cb9a4ac7f706333c73dd03aa..eda4a8b885904de71bb6e3bb1998fa1242a1b9a7 100644 (file)
@@ -1155,6 +1155,7 @@ static void gen11_dsi_powerup_panel(struct intel_encoder *encoder)
        }
 
        intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP);
+       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
 
        /* ensure all panel commands dispatched before enabling transcoder */
        wait_for_cmds_dispatched_to_panel(encoder);
@@ -1255,8 +1256,6 @@ static void gen11_dsi_enable(struct intel_atomic_state *state,
        /* step6d: enable dsi transcoder */
        gen11_dsi_enable_transcoder(encoder);
 
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
-
        /* step7: enable backlight */
        intel_backlight_enable(crtc_state, conn_state);
        intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
index 8f702c3fc62d483e6ba92d4d02537576975441ae..57bbf3e3af92fbb0325d0c41765f7a0f0d0ac806 100644 (file)
@@ -1525,8 +1525,18 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp,
         * can rely on frontbuffer tracking.
         */
        mask = EDP_PSR_DEBUG_MASK_MEMUP |
-              EDP_PSR_DEBUG_MASK_HPD |
-              EDP_PSR_DEBUG_MASK_LPSP;
+              EDP_PSR_DEBUG_MASK_HPD;
+
+       /*
+        * For some unknown reason on HSW non-ULT (or at least on
+        * Dell Latitude E6540) external displays start to flicker
+        * when PSR is enabled on the eDP. SR/PC6 residency is much
+        * higher than should be possible with an external display.
+        * As a workaround leave LPSP unmasked to prevent PSR entry
+        * when external displays are active.
+        */
+       if (DISPLAY_VER(dev_priv) >= 8 || IS_HASWELL_ULT(dev_priv))
+               mask |= EDP_PSR_DEBUG_MASK_LPSP;
 
        if (DISPLAY_VER(dev_priv) < 20)
                mask |= EDP_PSR_DEBUG_MASK_MAX_SLEEP;
index 5057d976fa578cebe2e9e847c6e78634d2b08968..93f08f9479d89bfda87fbeef246c9dd702f047a1 100644 (file)
@@ -62,7 +62,7 @@ nouveau_fence_signal(struct nouveau_fence *fence)
        if (test_bit(DMA_FENCE_FLAG_USER_BITS, &fence->base.flags)) {
                struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
 
-               if (atomic_dec_and_test(&fctx->notify_ref))
+               if (!--fctx->notify_ref)
                        drop = 1;
        }
 
@@ -103,7 +103,7 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error)
 void
 nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
 {
-       cancel_work_sync(&fctx->allow_block_work);
+       cancel_work_sync(&fctx->uevent_work);
        nouveau_fence_context_kill(fctx, 0);
        nvif_event_dtor(&fctx->event);
        fctx->dead = 1;
@@ -146,12 +146,13 @@ nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fc
        return drop;
 }
 
-static int
-nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc)
+static void
+nouveau_fence_uevent_work(struct work_struct *work)
 {
-       struct nouveau_fence_chan *fctx = container_of(event, typeof(*fctx), event);
+       struct nouveau_fence_chan *fctx = container_of(work, struct nouveau_fence_chan,
+                                                      uevent_work);
        unsigned long flags;
-       int ret = NVIF_EVENT_KEEP;
+       int drop = 0;
 
        spin_lock_irqsave(&fctx->lock, flags);
        if (!list_empty(&fctx->pending)) {
@@ -161,23 +162,20 @@ nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc
                fence = list_entry(fctx->pending.next, typeof(*fence), head);
                chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock));
                if (nouveau_fence_update(chan, fctx))
-                       ret = NVIF_EVENT_DROP;
+                       drop = 1;
        }
-       spin_unlock_irqrestore(&fctx->lock, flags);
+       if (drop)
+               nvif_event_block(&fctx->event);
 
-       return ret;
+       spin_unlock_irqrestore(&fctx->lock, flags);
 }
 
-static void
-nouveau_fence_work_allow_block(struct work_struct *work)
+static int
+nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc)
 {
-       struct nouveau_fence_chan *fctx = container_of(work, struct nouveau_fence_chan,
-                                                      allow_block_work);
-
-       if (atomic_read(&fctx->notify_ref) == 0)
-               nvif_event_block(&fctx->event);
-       else
-               nvif_event_allow(&fctx->event);
+       struct nouveau_fence_chan *fctx = container_of(event, typeof(*fctx), event);
+       schedule_work(&fctx->uevent_work);
+       return NVIF_EVENT_KEEP;
 }
 
 void
@@ -191,7 +189,7 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha
        } args;
        int ret;
 
-       INIT_WORK(&fctx->allow_block_work, nouveau_fence_work_allow_block);
+       INIT_WORK(&fctx->uevent_work, nouveau_fence_uevent_work);
        INIT_LIST_HEAD(&fctx->flip);
        INIT_LIST_HEAD(&fctx->pending);
        spin_lock_init(&fctx->lock);
@@ -535,19 +533,15 @@ static bool nouveau_fence_enable_signaling(struct dma_fence *f)
        struct nouveau_fence *fence = from_fence(f);
        struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
        bool ret;
-       bool do_work;
 
-       if (atomic_inc_return(&fctx->notify_ref) == 0)
-               do_work = true;
+       if (!fctx->notify_ref++)
+               nvif_event_allow(&fctx->event);
 
        ret = nouveau_fence_no_signaling(f);
        if (ret)
                set_bit(DMA_FENCE_FLAG_USER_BITS, &fence->base.flags);
-       else if (atomic_dec_and_test(&fctx->notify_ref))
-               do_work = true;
-
-       if (do_work)
-               schedule_work(&fctx->allow_block_work);
+       else if (!--fctx->notify_ref)
+               nvif_event_block(&fctx->event);
 
        return ret;
 }
index 28f5cf013b8983240204d028c8367249a63912e0..8bc065acfe35870f62bd0f2e37df47a35eb8ae38 100644 (file)
@@ -3,7 +3,6 @@
 #define __NOUVEAU_FENCE_H__
 
 #include <linux/dma-fence.h>
-#include <linux/workqueue.h>
 #include <nvif/event.h>
 
 struct nouveau_drm;
@@ -45,10 +44,9 @@ struct nouveau_fence_chan {
        u32 context;
        char name[32];
 
+       struct work_struct uevent_work;
        struct nvif_event event;
-       struct work_struct allow_block_work;
-       atomic_t notify_ref;
-       int dead, killed;
+       int notify_ref, dead, killed;
 };
 
 struct nouveau_fence_priv {
index 9ee58e2a0eb2ad99c198ea7a58e6e1cf02a667d0..5e1fa176aac4a4b9e33562236b8b93889dae58ac 100644 (file)
@@ -1078,7 +1078,6 @@ r535_gsp_rpc_set_registry(struct nvkm_gsp *gsp)
        if (IS_ERR(rpc))
                return PTR_ERR(rpc);
 
-       rpc->size = sizeof(*rpc);
        rpc->numEntries = NV_GSP_REG_NUM_ENTRIES;
 
        str_offset = offsetof(typeof(*rpc), entries[NV_GSP_REG_NUM_ENTRIES]);
@@ -1094,6 +1093,7 @@ r535_gsp_rpc_set_registry(struct nvkm_gsp *gsp)
                strings += name_len;
                str_offset += name_len;
        }
+       rpc->size = str_offset;
 
        return nvkm_gsp_rpc_wr(gsp, rpc, false);
 }
index dad938cf6decfb0658a73439a6ca602c78fce2fb..8f3783742208b60d8b5b9ad7c6e2ceab4e9fc9e4 100644 (file)
@@ -539,6 +539,8 @@ config DRM_PANEL_RAYDIUM_RM692E5
        depends on OF
        depends on DRM_MIPI_DSI
        depends on BACKLIGHT_CLASS_DEVICE
+       select DRM_DISPLAY_DP_HELPER
+       select DRM_DISPLAY_HELPER
        help
          Say Y here if you want to enable support for Raydium RM692E5-based
          display panels, such as the one found in the Fairphone 5 smartphone.
index ea5a857793827af1a0bfe90d88bf2a3a71065f11..f23d8832a1ad055483b1f513557cb3d2807e3692 100644 (file)
@@ -309,7 +309,7 @@ static const struct s6d7aa0_panel_desc s6d7aa0_lsl080al02_desc = {
        .off_func = s6d7aa0_lsl080al02_off,
        .drm_mode = &s6d7aa0_lsl080al02_mode,
        .mode_flags = MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_NO_HFP,
-       .bus_flags = DRM_BUS_FLAG_DE_HIGH,
+       .bus_flags = 0,
 
        .has_backlight = false,
        .use_passwd3 = false,
index 2214cb09678cd6a234359c2cb7972c9beb3f5851..d493ee735c7349b2ae1a21abff870859c0ea2af4 100644 (file)
@@ -3948,6 +3948,7 @@ static const struct panel_desc tianma_tm070jdhg30 = {
        },
        .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
        .connector_type = DRM_MODE_CONNECTOR_LVDS,
+       .bus_flags = DRM_BUS_FLAG_DE_HIGH,
 };
 
 static const struct panel_desc tianma_tm070jvhg33 = {
@@ -3960,6 +3961,7 @@ static const struct panel_desc tianma_tm070jvhg33 = {
        },
        .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
        .connector_type = DRM_MODE_CONNECTOR_LVDS,
+       .bus_flags = DRM_BUS_FLAG_DE_HIGH,
 };
 
 static const struct display_timing tianma_tm070rvhg71_timing = {
index 550492a7a031d7827b2e167098c495908bee82aa..85f082396d42da982589fe69183c71743c69a89b 100644 (file)
@@ -1178,21 +1178,20 @@ static void drm_sched_run_job_work(struct work_struct *w)
        struct drm_sched_entity *entity;
        struct dma_fence *fence;
        struct drm_sched_fence *s_fence;
-       struct drm_sched_job *sched_job;
+       struct drm_sched_job *sched_job = NULL;
        int r;
 
        if (READ_ONCE(sched->pause_submit))
                return;
 
-       entity = drm_sched_select_entity(sched);
+       /* Find entity with a ready job */
+       while (!sched_job && (entity = drm_sched_select_entity(sched))) {
+               sched_job = drm_sched_entity_pop_job(entity);
+               if (!sched_job)
+                       complete_all(&entity->entity_idle);
+       }
        if (!entity)
-               return;
-
-       sched_job = drm_sched_entity_pop_job(entity);
-       if (!sched_job) {
-               complete_all(&entity->entity_idle);
                return; /* No more work */
-       }
 
        s_fence = sched_job->s_fence;
 
index ff36171c8fb700bae9967961220ea7cbb262d193..a73cff7a307082d97ce78e43deaff5547cf55964 100644 (file)
@@ -960,7 +960,8 @@ int host1x_client_iommu_attach(struct host1x_client *client)
         * not the shared IOMMU domain, don't try to attach it to a different
         * domain. This allows using the IOMMU-backed DMA API.
         */
-       if (domain && domain != tegra->domain)
+       if (domain && domain->type != IOMMU_DOMAIN_IDENTITY &&
+           domain != tegra->domain)
                return 0;
 
        if (tegra->domain) {
index 4e9247cf9977f5677126ffbdcf56c97446c769b4..1eb0c304f9607f6ae4034638a2cf8e3ee8da06ca 100644 (file)
@@ -188,13 +188,13 @@ out:
 
 static void drm_test_mm_debug(struct kunit *test)
 {
+       struct drm_printer p = drm_debug_printer(test->name);
        struct drm_mm mm;
        struct drm_mm_node nodes[2];
 
        /* Create a small drm_mm with a couple of nodes and a few holes, and
         * check that the debug iterator doesn't explode over a trivial drm_mm.
         */
-
        drm_mm_init(&mm, 0, 4096);
 
        memset(nodes, 0, sizeof(nodes));
@@ -209,6 +209,9 @@ static void drm_test_mm_debug(struct kunit *test)
        KUNIT_ASSERT_FALSE_MSG(test, drm_mm_reserve_node(&mm, &nodes[1]),
                               "failed to reserve node[0] {start=%lld, size=%lld)\n",
                               nodes[0].start, nodes[0].size);
+
+       drm_mm_print(&mm, &p);
+       KUNIT_SUCCEED(test);
 }
 
 static bool expect_insert(struct kunit *test, struct drm_mm *mm,
index 4130945052ed2a523d50e1d39d028ca3741c6605..76027960054f1140e768ae21b30e5a3015437d02 100644 (file)
@@ -95,11 +95,17 @@ static int ttm_global_init(void)
        ttm_pool_mgr_init(num_pages);
        ttm_tt_mgr_init(num_pages, num_dma32);
 
-       glob->dummy_read_page = alloc_page(__GFP_ZERO | GFP_DMA32);
+       glob->dummy_read_page = alloc_page(__GFP_ZERO | GFP_DMA32 |
+                                          __GFP_NOWARN);
 
+       /* Retry without GFP_DMA32 for platforms DMA32 is not available */
        if (unlikely(glob->dummy_read_page == NULL)) {
-               ret = -ENOMEM;
-               goto out;
+               glob->dummy_read_page = alloc_page(__GFP_ZERO);
+               if (unlikely(glob->dummy_read_page == NULL)) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               pr_warn("Using GFP_DMA32 fallback for dummy_read_page\n");
        }
 
        INIT_LIST_HEAD(&glob->device_list);
index fcff41dd2315b710dc9de6ccdb361922c61d2602..88f63d526b22365b42b90e90d5b451a56e3fda52 100644 (file)
@@ -147,6 +147,13 @@ v3d_job_allocate(void **container, size_t size)
        return 0;
 }
 
+static void
+v3d_job_deallocate(void **container)
+{
+       kfree(*container);
+       *container = NULL;
+}
+
 static int
 v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv,
             struct v3d_job *job, void (*free)(struct kref *ref),
@@ -273,8 +280,10 @@ v3d_setup_csd_jobs_and_bos(struct drm_file *file_priv,
 
        ret = v3d_job_init(v3d, file_priv, &(*job)->base,
                           v3d_job_free, args->in_sync, se, V3D_CSD);
-       if (ret)
+       if (ret) {
+               v3d_job_deallocate((void *)job);
                return ret;
+       }
 
        ret = v3d_job_allocate((void *)clean_job, sizeof(**clean_job));
        if (ret)
@@ -282,8 +291,10 @@ v3d_setup_csd_jobs_and_bos(struct drm_file *file_priv,
 
        ret = v3d_job_init(v3d, file_priv, *clean_job,
                           v3d_job_free, 0, NULL, V3D_CACHE_CLEAN);
-       if (ret)
+       if (ret) {
+               v3d_job_deallocate((void *)clean_job);
                return ret;
+       }
 
        (*job)->args = *args;
 
@@ -860,8 +871,10 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
 
        ret = v3d_job_init(v3d, file_priv, &render->base,
                           v3d_render_job_free, args->in_sync_rcl, &se, V3D_RENDER);
-       if (ret)
+       if (ret) {
+               v3d_job_deallocate((void *)&render);
                goto fail;
+       }
 
        render->start = args->rcl_start;
        render->end = args->rcl_end;
@@ -874,8 +887,10 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
 
                ret = v3d_job_init(v3d, file_priv, &bin->base,
                                   v3d_job_free, args->in_sync_bcl, &se, V3D_BIN);
-               if (ret)
+               if (ret) {
+                       v3d_job_deallocate((void *)&bin);
                        goto fail;
+               }
 
                bin->start = args->bcl_start;
                bin->end = args->bcl_end;
@@ -892,8 +907,10 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
 
                ret = v3d_job_init(v3d, file_priv, clean_job,
                                   v3d_job_free, 0, NULL, V3D_CACHE_CLEAN);
-               if (ret)
+               if (ret) {
+                       v3d_job_deallocate((void *)&clean_job);
                        goto fail;
+               }
 
                last_job = clean_job;
        } else {
@@ -1015,8 +1032,10 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
 
        ret = v3d_job_init(v3d, file_priv, &job->base,
                           v3d_job_free, args->in_sync, &se, V3D_TFU);
-       if (ret)
+       if (ret) {
+               v3d_job_deallocate((void *)&job);
                goto fail;
+       }
 
        job->base.bo = kcalloc(ARRAY_SIZE(args->bo_handles),
                               sizeof(*job->base.bo), GFP_KERNEL);
@@ -1233,8 +1252,10 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data,
 
        ret = v3d_job_init(v3d, file_priv, &cpu_job->base,
                           v3d_job_free, 0, &se, V3D_CPU);
-       if (ret)
+       if (ret) {
+               v3d_job_deallocate((void *)&cpu_job);
                goto fail;
+       }
 
        clean_job = cpu_job->indirect_csd.clean_job;
        csd_job = cpu_job->indirect_csd.job;
index f8e9abe647b927b211abb4bbc0751ea318d80369..9539aa28937fa4cf71fbcd8e252749607617d966 100644 (file)
@@ -94,6 +94,7 @@ static int virtio_gpu_probe(struct virtio_device *vdev)
                        goto err_free;
        }
 
+       dma_set_max_seg_size(dev->dev, dma_max_mapping_size(dev->dev) ?: UINT_MAX);
        ret = virtio_gpu_init(vdev, dev);
        if (ret)
                goto err_free;
index 3062e0e0d467ee0737f0fbf63d3826c9f4013778..79ba98a169f907cc18dcd63c07e9570c623c1608 100644 (file)
@@ -50,8 +50,8 @@
 
 #define HOST2GUC_SELF_CFG_REQUEST_MSG_LEN              (GUC_HXG_REQUEST_MSG_MIN_LEN + 3u)
 #define HOST2GUC_SELF_CFG_REQUEST_MSG_0_MBZ            GUC_HXG_REQUEST_MSG_0_DATA0
-#define HOST2GUC_SELF_CFG_REQUEST_MSG_1_KLV_KEY                (0xffff << 16)
-#define HOST2GUC_SELF_CFG_REQUEST_MSG_1_KLV_LEN                (0xffff << 0)
+#define HOST2GUC_SELF_CFG_REQUEST_MSG_1_KLV_KEY                (0xffffu << 16)
+#define HOST2GUC_SELF_CFG_REQUEST_MSG_1_KLV_LEN                (0xffffu << 0)
 #define HOST2GUC_SELF_CFG_REQUEST_MSG_2_VALUE32                GUC_HXG_REQUEST_MSG_n_DATAn
 #define HOST2GUC_SELF_CFG_REQUEST_MSG_3_VALUE64                GUC_HXG_REQUEST_MSG_n_DATAn
 
index 811add10c30dc21a357841dccd10e6583468978c..c165e26c097669b72e6cfa7f97a7ee5bdada90ff 100644 (file)
@@ -242,8 +242,8 @@ struct slpc_shared_data {
                (HOST2GUC_PC_SLPC_REQUEST_REQUEST_MSG_MIN_LEN + \
                        HOST2GUC_PC_SLPC_EVENT_MAX_INPUT_ARGS)
 #define HOST2GUC_PC_SLPC_REQUEST_MSG_0_MBZ             GUC_HXG_REQUEST_MSG_0_DATA0
-#define HOST2GUC_PC_SLPC_REQUEST_MSG_1_EVENT_ID                (0xff << 8)
-#define HOST2GUC_PC_SLPC_REQUEST_MSG_1_EVENT_ARGC      (0xff << 0)
+#define HOST2GUC_PC_SLPC_REQUEST_MSG_1_EVENT_ID                (0xffu << 8)
+#define HOST2GUC_PC_SLPC_REQUEST_MSG_1_EVENT_ARGC      (0xffu << 0)
 #define HOST2GUC_PC_SLPC_REQUEST_MSG_N_EVENT_DATA_N    GUC_HXG_REQUEST_MSG_n_DATAn
 
 #endif
index 3b83f907ece46165c5bc11f93a3077e6dafd2edf..0b1146d0c997a216c589bb21d86d91f4d0f6841c 100644 (file)
@@ -82,11 +82,11 @@ static_assert(sizeof(struct guc_ct_buffer_desc) == 64);
 #define GUC_CTB_HDR_LEN                                1u
 #define GUC_CTB_MSG_MIN_LEN                    GUC_CTB_HDR_LEN
 #define GUC_CTB_MSG_MAX_LEN                    256u
-#define GUC_CTB_MSG_0_FENCE                    (0xffff << 16)
-#define GUC_CTB_MSG_0_FORMAT                   (0xf << 12)
+#define GUC_CTB_MSG_0_FENCE                    (0xffffu << 16)
+#define GUC_CTB_MSG_0_FORMAT                   (0xfu << 12)
 #define   GUC_CTB_FORMAT_HXG                   0u
-#define GUC_CTB_MSG_0_RESERVED                 (0xf << 8)
-#define GUC_CTB_MSG_0_NUM_DWORDS               (0xff << 0)
+#define GUC_CTB_MSG_0_RESERVED                 (0xfu << 8)
+#define GUC_CTB_MSG_0_NUM_DWORDS               (0xffu << 0)
 
 /**
  * DOC: CTB HXG Message
index 47094b9b044cbbcdd68f51b3cacd6f15e4d97b3c..0400bc0fccdc9b5d5605dafd5f5480ff3983319c 100644 (file)
@@ -31,9 +31,9 @@
  */
 
 #define GUC_KLV_LEN_MIN                                1u
-#define GUC_KLV_0_KEY                          (0xffff << 16)
-#define GUC_KLV_0_LEN                          (0xffff << 0)
-#define GUC_KLV_n_VALUE                                (0xffffffff << 0)
+#define GUC_KLV_0_KEY                          (0xffffu << 16)
+#define GUC_KLV_0_LEN                          (0xffffu << 0)
+#define GUC_KLV_n_VALUE                                (0xffffffffu << 0)
 
 /**
  * DOC: GuC Self Config KLVs
index 3d199016cf881cea10668a010fce5e8b4ea234c1..29e414c82d56cb5a318686e18d3d774c7b9c3d0c 100644 (file)
  */
 
 #define GUC_HXG_MSG_MIN_LEN                    1u
-#define GUC_HXG_MSG_0_ORIGIN                   (0x1 << 31)
+#define GUC_HXG_MSG_0_ORIGIN                   (0x1u << 31)
 #define   GUC_HXG_ORIGIN_HOST                  0u
 #define   GUC_HXG_ORIGIN_GUC                   1u
-#define GUC_HXG_MSG_0_TYPE                     (0x7 << 28)
+#define GUC_HXG_MSG_0_TYPE                     (0x7u << 28)
 #define   GUC_HXG_TYPE_REQUEST                 0u
 #define   GUC_HXG_TYPE_EVENT                   1u
 #define   GUC_HXG_TYPE_NO_RESPONSE_BUSY                3u
 #define   GUC_HXG_TYPE_NO_RESPONSE_RETRY       5u
 #define   GUC_HXG_TYPE_RESPONSE_FAILURE                6u
 #define   GUC_HXG_TYPE_RESPONSE_SUCCESS                7u
-#define GUC_HXG_MSG_0_AUX                      (0xfffffff << 0)
-#define GUC_HXG_MSG_n_PAYLOAD                  (0xffffffff << 0)
+#define GUC_HXG_MSG_0_AUX                      (0xfffffffu << 0)
+#define GUC_HXG_MSG_n_PAYLOAD                  (0xffffffffu << 0)
 
 /**
  * DOC: HXG Request
@@ -85,8 +85,8 @@
  */
 
 #define GUC_HXG_REQUEST_MSG_MIN_LEN            GUC_HXG_MSG_MIN_LEN
-#define GUC_HXG_REQUEST_MSG_0_DATA0            (0xfff << 16)
-#define GUC_HXG_REQUEST_MSG_0_ACTION           (0xffff << 0)
+#define GUC_HXG_REQUEST_MSG_0_DATA0            (0xfffu << 16)
+#define GUC_HXG_REQUEST_MSG_0_ACTION           (0xffffu << 0)
 #define GUC_HXG_REQUEST_MSG_n_DATAn            GUC_HXG_MSG_n_PAYLOAD
 
 /**
  */
 
 #define GUC_HXG_EVENT_MSG_MIN_LEN              GUC_HXG_MSG_MIN_LEN
-#define GUC_HXG_EVENT_MSG_0_DATA0              (0xfff << 16)
-#define GUC_HXG_EVENT_MSG_0_ACTION             (0xffff << 0)
+#define GUC_HXG_EVENT_MSG_0_DATA0              (0xfffu << 16)
+#define GUC_HXG_EVENT_MSG_0_ACTION             (0xffffu << 0)
 #define GUC_HXG_EVENT_MSG_n_DATAn              GUC_HXG_MSG_n_PAYLOAD
 
 /**
  */
 
 #define GUC_HXG_FAILURE_MSG_LEN                        GUC_HXG_MSG_MIN_LEN
-#define GUC_HXG_FAILURE_MSG_0_HINT             (0xfff << 16)
-#define GUC_HXG_FAILURE_MSG_0_ERROR            (0xffff << 0)
+#define GUC_HXG_FAILURE_MSG_0_HINT             (0xfffu << 16)
+#define GUC_HXG_FAILURE_MSG_0_ERROR            (0xffffu << 0)
 
 /**
  * DOC: HXG Response
index 5f19550cc845360ada430477180405fe66bf84b9..68d9f6116bdfc3522ee5d6d94ef2bb763ec81090 100644 (file)
@@ -35,12 +35,10 @@ static inline int i915_gem_object_read_from_page(struct xe_bo *bo,
                                          u32 ofs, u64 *ptr, u32 size)
 {
        struct ttm_bo_kmap_obj map;
-       void *virtual;
+       void *src;
        bool is_iomem;
        int ret;
 
-       XE_WARN_ON(size != 8);
-
        ret = xe_bo_lock(bo, true);
        if (ret)
                return ret;
@@ -50,11 +48,12 @@ static inline int i915_gem_object_read_from_page(struct xe_bo *bo,
                goto out_unlock;
 
        ofs &= ~PAGE_MASK;
-       virtual = ttm_kmap_obj_virtual(&map, &is_iomem);
+       src = ttm_kmap_obj_virtual(&map, &is_iomem);
+       src += ofs;
        if (is_iomem)
-               *ptr = readq((void __iomem *)(virtual + ofs));
+               memcpy_fromio(ptr, (void __iomem *)src, size);
        else
-               *ptr = *(u64 *)(virtual + ofs);
+               memcpy(ptr, src, size);
 
        ttm_bo_kunmap(&map);
 out_unlock:
index a53c22a1958247cbd703264aeb49195620b6754a..b4715b78ef3bf952bacd5ed7e1739c2fe0cfa813 100644 (file)
@@ -74,9 +74,6 @@ static const struct platform_test_case cases[] = {
        SUBPLATFORM_CASE(DG2, G11, B1),
        SUBPLATFORM_CASE(DG2, G12, A0),
        SUBPLATFORM_CASE(DG2, G12, A1),
-       PLATFORM_CASE(PVC, B0),
-       PLATFORM_CASE(PVC, B1),
-       PLATFORM_CASE(PVC, C0),
        GMDID_CASE(METEORLAKE, 1270, A0, 1300, A0),
        GMDID_CASE(METEORLAKE, 1271, A0, 1300, A0),
        GMDID_CASE(LUNARLAKE, 2004, A0, 2000, A0),
index b8d8da5466708c6903ccb3ade3852a7ac9911235..1f0b4b9ce84f585ea599ccaf7f4641c3d139121f 100644 (file)
@@ -613,7 +613,7 @@ void xe_device_wmb(struct xe_device *xe)
 u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size)
 {
        return xe_device_has_flat_ccs(xe) ?
-               DIV_ROUND_UP(size, NUM_BYTES_PER_CCS_BYTE(xe)) : 0;
+               DIV_ROUND_UP_ULL(size, NUM_BYTES_PER_CCS_BYTE(xe)) : 0;
 }
 
 bool xe_device_mem_access_ongoing(struct xe_device *xe)
index 64ed303728fda98d2c4edb2a4a0e1f0b810812d2..da2627ed6ae7a94114ec4e1d0aa6f04495103540 100644 (file)
@@ -175,7 +175,7 @@ static int xe_dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
        return 0;
 }
 
-const struct dma_buf_ops xe_dmabuf_ops = {
+static const struct dma_buf_ops xe_dmabuf_ops = {
        .attach = xe_dma_buf_attach,
        .detach = xe_dma_buf_detach,
        .pin = xe_dma_buf_pin,
index b853feed9ccc15eefab7f0ccdf070096521e6015..17f26952e6656b8a077eb51161acbfd96638db2c 100644 (file)
@@ -111,7 +111,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
        u64 addresses[XE_HW_ENGINE_MAX_INSTANCE];
        struct drm_gpuvm_exec vm_exec = {.extra.fn = xe_exec_fn};
        struct drm_exec *exec = &vm_exec.exec;
-       u32 i, num_syncs = 0;
+       u32 i, num_syncs = 0, num_ufence = 0;
        struct xe_sched_job *job;
        struct dma_fence *rebind_fence;
        struct xe_vm *vm;
@@ -157,6 +157,14 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
                                           SYNC_PARSE_FLAG_LR_MODE : 0));
                if (err)
                        goto err_syncs;
+
+               if (xe_sync_is_ufence(&syncs[i]))
+                       num_ufence++;
+       }
+
+       if (XE_IOCTL_DBG(xe, num_ufence > 1)) {
+               err = -EINVAL;
+               goto err_syncs;
        }
 
        if (xe_exec_queue_is_parallel(q)) {
index 77925b35cf8dcb0ee1d62ba7c579767796c8d807..8546cd3cc50d1f8c4146b2f69c4758bac05aa240 100644 (file)
@@ -480,7 +480,7 @@ static bool xe_gt_mcr_get_nonterminated_steering(struct xe_gt *gt,
  * to synchronize with external clients (e.g., firmware), so a semaphore
  * register will also need to be taken.
  */
-static void mcr_lock(struct xe_gt *gt)
+static void mcr_lock(struct xe_gt *gt) __acquires(&gt->mcr_lock)
 {
        struct xe_device *xe = gt_to_xe(gt);
        int ret = 0;
@@ -500,7 +500,7 @@ static void mcr_lock(struct xe_gt *gt)
        drm_WARN_ON_ONCE(&xe->drm, ret == -ETIMEDOUT);
 }
 
-static void mcr_unlock(struct xe_gt *gt)
+static void mcr_unlock(struct xe_gt *gt) __releases(&gt->mcr_lock)
 {
        /* Release hardware semaphore - this is done by writing 1 to the register */
        if (GRAPHICS_VERx100(gt_to_xe(gt)) >= 1270)
index 59a70d2e0a7a33386fdcfca9cc158919aab1e32c..9c2fe1697d6eef002e9b85ccd89a18648e654fee 100644 (file)
@@ -165,7 +165,8 @@ retry_userptr:
                goto unlock_vm;
        }
 
-       if (!xe_vma_is_userptr(vma) || !xe_vma_userptr_check_repin(vma)) {
+       if (!xe_vma_is_userptr(vma) ||
+           !xe_vma_userptr_check_repin(to_userptr_vma(vma))) {
                downgrade_write(&vm->lock);
                write_locked = false;
        }
@@ -181,11 +182,13 @@ retry_userptr:
        /* TODO: Validate fault */
 
        if (xe_vma_is_userptr(vma) && write_locked) {
+               struct xe_userptr_vma *uvma = to_userptr_vma(vma);
+
                spin_lock(&vm->userptr.invalidated_lock);
-               list_del_init(&vma->userptr.invalidate_link);
+               list_del_init(&uvma->userptr.invalidate_link);
                spin_unlock(&vm->userptr.invalidated_lock);
 
-               ret = xe_vma_userptr_pin_pages(vma);
+               ret = xe_vma_userptr_pin_pages(uvma);
                if (ret)
                        goto unlock_vm;
 
@@ -220,7 +223,7 @@ retry_userptr:
        dma_fence_put(fence);
 
        if (xe_vma_is_userptr(vma))
-               ret = xe_vma_userptr_check_repin(vma);
+               ret = xe_vma_userptr_check_repin(to_userptr_vma(vma));
        vma->usm.tile_invalidated &= ~BIT(tile->id);
 
 unlock_dma_resv:
index f71085228cb33992940622dca2992f4e1ae9fa62..d91702592520af54eea5f8ca4bd56b67719531be 100644 (file)
@@ -963,7 +963,9 @@ void xe_guc_pc_fini(struct xe_guc_pc *pc)
        struct xe_device *xe = pc_to_xe(pc);
 
        if (xe->info.skip_guc_pc) {
+               xe_device_mem_access_get(xe);
                xe_gt_idle_disable_c6(pc_to_gt(pc));
+               xe_device_mem_access_put(xe);
                return;
        }
 
index a6094c81f2ad0fa8a3f1cf1001ceb897a044d3cb..a5de3e7b0bd6ab134557fdfb52a406d4bf199016 100644 (file)
@@ -217,13 +217,13 @@ struct xe_hw_fence *xe_hw_fence_create(struct xe_hw_fence_ctx *ctx,
        if (!fence)
                return ERR_PTR(-ENOMEM);
 
-       dma_fence_init(&fence->dma, &xe_hw_fence_ops, &ctx->irq->lock,
-                      ctx->dma_fence_ctx, ctx->next_seqno++);
-
        fence->ctx = ctx;
        fence->seqno_map = seqno_map;
        INIT_LIST_HEAD(&fence->irq_link);
 
+       dma_fence_init(&fence->dma, &xe_hw_fence_ops, &ctx->irq->lock,
+                      ctx->dma_fence_ctx, ctx->next_seqno++);
+
        trace_xe_hw_fence_create(fence);
 
        return fence;
index 6ef2aa1eae8b095e958e74fda4b5c42e205436bf..174ed2185481e32d568551e62f1839181a1771d4 100644 (file)
@@ -419,7 +419,7 @@ static int xe_hwmon_pcode_read_i1(struct xe_gt *gt, u32 *uval)
 
        return xe_pcode_read(gt, PCODE_MBOX(PCODE_POWER_SETUP,
                             POWER_SETUP_SUBCOMMAND_READ_I1, 0),
-                            uval, 0);
+                            uval, NULL);
 }
 
 static int xe_hwmon_pcode_write_i1(struct xe_gt *gt, u32 uval)
index b7fa3831b68451cb74ae557ca3e7a66d5d4fa6fd..0ec5ad2539f1be6098aa248876a2816f65b91f38 100644 (file)
 #include "xe_map.h"
 #include "xe_vm.h"
 
-#define CTX_VALID                              (1 << 0)
-#define CTX_PRIVILEGE                          (1 << 8)
-#define CTX_ADDRESSING_MODE_SHIFT              3
-#define LEGACY_64B_CONTEXT                     3
+#define LRC_VALID                              (1 << 0)
+#define LRC_PRIVILEGE                          (1 << 8)
+#define LRC_ADDRESSING_MODE_SHIFT              3
+#define LRC_LEGACY_64B_CONTEXT                 3
 
 #define ENGINE_CLASS_SHIFT                     61
 #define ENGINE_INSTANCE_SHIFT                  48
@@ -762,15 +762,15 @@ int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
                                     (q->usm.acc_notify << ACC_NOTIFY_S) |
                                     q->usm.acc_trigger);
 
-       lrc->desc = CTX_VALID;
-       lrc->desc |= LEGACY_64B_CONTEXT << CTX_ADDRESSING_MODE_SHIFT;
+       lrc->desc = LRC_VALID;
+       lrc->desc |= LRC_LEGACY_64B_CONTEXT << LRC_ADDRESSING_MODE_SHIFT;
        /* TODO: Priority */
 
        /* While this appears to have something about privileged batches or
         * some such, it really just means PPGTT mode.
         */
        if (vm)
-               lrc->desc |= CTX_PRIVILEGE;
+               lrc->desc |= LRC_PRIVILEGE;
 
        if (GRAPHICS_VERx100(xe) < 1250) {
                lrc->desc |= (u64)hwe->instance << ENGINE_INSTANCE_SHIFT;
index e05e9e7282b68abdcab839a9134efd09e60750f2..5c6c5462425217c9301560a626d67ec7386bd418 100644 (file)
@@ -472,7 +472,7 @@ static void emit_pte(struct xe_migrate *m,
        /* Indirect access needs compression enabled uncached PAT index */
        if (GRAPHICS_VERx100(xe) >= 2000)
                pat_index = is_comp_pte ? xe->pat.idx[XE_CACHE_NONE_COMPRESSION] :
-                                         xe->pat.idx[XE_CACHE_NONE];
+                                         xe->pat.idx[XE_CACHE_WB];
        else
                pat_index = xe->pat.idx[XE_CACHE_WB];
 
@@ -760,14 +760,14 @@ struct dma_fence *xe_migrate_copy(struct xe_migrate *m,
                if (src_is_vram && xe_migrate_allow_identity(src_L0, &src_it))
                        xe_res_next(&src_it, src_L0);
                else
-                       emit_pte(m, bb, src_L0_pt, src_is_vram, true, &src_it, src_L0,
-                                src);
+                       emit_pte(m, bb, src_L0_pt, src_is_vram, copy_system_ccs,
+                                &src_it, src_L0, src);
 
                if (dst_is_vram && xe_migrate_allow_identity(src_L0, &dst_it))
                        xe_res_next(&dst_it, src_L0);
                else
-                       emit_pte(m, bb, dst_L0_pt, dst_is_vram, true, &dst_it, src_L0,
-                                dst);
+                       emit_pte(m, bb, dst_L0_pt, dst_is_vram, copy_system_ccs,
+                                &dst_it, src_L0, dst);
 
                if (copy_system_ccs)
                        emit_pte(m, bb, ccs_pt, false, false, &ccs_it, ccs_size, src);
@@ -1009,8 +1009,8 @@ struct dma_fence *xe_migrate_clear(struct xe_migrate *m,
                if (clear_vram && xe_migrate_allow_identity(clear_L0, &src_it))
                        xe_res_next(&src_it, clear_L0);
                else
-                       emit_pte(m, bb, clear_L0_pt, clear_vram, true, &src_it, clear_L0,
-                                dst);
+                       emit_pte(m, bb, clear_L0_pt, clear_vram, clear_system_ccs,
+                                &src_it, clear_L0, dst);
 
                bb->cs[bb->len++] = MI_BATCH_BUFFER_END;
                update_idx = bb->len;
index c8c5d74b6e9041ec53c38ba81d184b83037427ab..5f6b53ea5528b2c904ce0c4ee30e39c4a16139b7 100644 (file)
@@ -272,8 +272,8 @@ int xe_mmio_probe_vram(struct xe_device *xe)
                drm_info(&xe->drm, "VRAM[%u, %u]: Actual physical size %pa, usable size exclude stolen %pa, CPU accessible size %pa\n", id,
                         tile->id, &tile->mem.vram.actual_physical_size, &tile->mem.vram.usable_size, &tile->mem.vram.io_size);
                drm_info(&xe->drm, "VRAM[%u, %u]: DPA range: [%pa-%llx], io range: [%pa-%llx]\n", id, tile->id,
-                        &tile->mem.vram.dpa_base, tile->mem.vram.dpa_base + tile->mem.vram.actual_physical_size,
-                        &tile->mem.vram.io_start, tile->mem.vram.io_start + tile->mem.vram.io_size);
+                        &tile->mem.vram.dpa_base, tile->mem.vram.dpa_base + (u64)tile->mem.vram.actual_physical_size,
+                        &tile->mem.vram.io_start, tile->mem.vram.io_start + (u64)tile->mem.vram.io_size);
 
                /* calculate total size using tile size to get the correct HW sizing */
                total_size += tile_size;
index de1030a47588371b0cc71f5b69bee8f0257e2625..e45b37c3f0c262744f960d769eeed29a07ef14e7 100644 (file)
@@ -618,8 +618,8 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma,
 
        if (!xe_vma_is_null(vma)) {
                if (xe_vma_is_userptr(vma))
-                       xe_res_first_sg(vma->userptr.sg, 0, xe_vma_size(vma),
-                                       &curs);
+                       xe_res_first_sg(to_userptr_vma(vma)->userptr.sg, 0,
+                                       xe_vma_size(vma), &curs);
                else if (xe_bo_is_vram(bo) || xe_bo_is_stolen(bo))
                        xe_res_first(bo->ttm.resource, xe_vma_bo_offset(vma),
                                     xe_vma_size(vma), &curs);
@@ -906,17 +906,17 @@ static void xe_vm_dbg_print_entries(struct xe_device *xe,
 
 #ifdef CONFIG_DRM_XE_USERPTR_INVAL_INJECT
 
-static int xe_pt_userptr_inject_eagain(struct xe_vma *vma)
+static int xe_pt_userptr_inject_eagain(struct xe_userptr_vma *uvma)
 {
-       u32 divisor = vma->userptr.divisor ? vma->userptr.divisor : 2;
+       u32 divisor = uvma->userptr.divisor ? uvma->userptr.divisor : 2;
        static u32 count;
 
        if (count++ % divisor == divisor - 1) {
-               struct xe_vm *vm = xe_vma_vm(vma);
+               struct xe_vm *vm = xe_vma_vm(&uvma->vma);
 
-               vma->userptr.divisor = divisor << 1;
+               uvma->userptr.divisor = divisor << 1;
                spin_lock(&vm->userptr.invalidated_lock);
-               list_move_tail(&vma->userptr.invalidate_link,
+               list_move_tail(&uvma->userptr.invalidate_link,
                               &vm->userptr.invalidated);
                spin_unlock(&vm->userptr.invalidated_lock);
                return true;
@@ -927,7 +927,7 @@ static int xe_pt_userptr_inject_eagain(struct xe_vma *vma)
 
 #else
 
-static bool xe_pt_userptr_inject_eagain(struct xe_vma *vma)
+static bool xe_pt_userptr_inject_eagain(struct xe_userptr_vma *uvma)
 {
        return false;
 }
@@ -1000,9 +1000,9 @@ static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update)
 {
        struct xe_pt_migrate_pt_update *userptr_update =
                container_of(pt_update, typeof(*userptr_update), base);
-       struct xe_vma *vma = pt_update->vma;
-       unsigned long notifier_seq = vma->userptr.notifier_seq;
-       struct xe_vm *vm = xe_vma_vm(vma);
+       struct xe_userptr_vma *uvma = to_userptr_vma(pt_update->vma);
+       unsigned long notifier_seq = uvma->userptr.notifier_seq;
+       struct xe_vm *vm = xe_vma_vm(&uvma->vma);
        int err = xe_pt_vm_dependencies(pt_update->job,
                                        &vm->rftree[pt_update->tile_id],
                                        pt_update->start,
@@ -1023,7 +1023,7 @@ static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update)
         */
        do {
                down_read(&vm->userptr.notifier_lock);
-               if (!mmu_interval_read_retry(&vma->userptr.notifier,
+               if (!mmu_interval_read_retry(&uvma->userptr.notifier,
                                             notifier_seq))
                        break;
 
@@ -1032,11 +1032,11 @@ static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update)
                if (userptr_update->bind)
                        return -EAGAIN;
 
-               notifier_seq = mmu_interval_read_begin(&vma->userptr.notifier);
+               notifier_seq = mmu_interval_read_begin(&uvma->userptr.notifier);
        } while (true);
 
        /* Inject errors to test_whether they are handled correctly */
-       if (userptr_update->bind && xe_pt_userptr_inject_eagain(vma)) {
+       if (userptr_update->bind && xe_pt_userptr_inject_eagain(uvma)) {
                up_read(&vm->userptr.notifier_lock);
                return -EAGAIN;
        }
@@ -1297,7 +1297,7 @@ __xe_pt_bind_vma(struct xe_tile *tile, struct xe_vma *vma, struct xe_exec_queue
                vma->tile_present |= BIT(tile->id);
 
                if (bind_pt_update.locked) {
-                       vma->userptr.initial_bind = true;
+                       to_userptr_vma(vma)->userptr.initial_bind = true;
                        up_read(&vm->userptr.notifier_lock);
                        xe_bo_put_commit(&deferred);
                }
@@ -1642,7 +1642,7 @@ __xe_pt_unbind_vma(struct xe_tile *tile, struct xe_vma *vma, struct xe_exec_queu
 
                if (!vma->tile_present) {
                        spin_lock(&vm->userptr.invalidated_lock);
-                       list_del_init(&vma->userptr.invalidate_link);
+                       list_del_init(&to_userptr_vma(vma)->userptr.invalidate_link);
                        spin_unlock(&vm->userptr.invalidated_lock);
                }
                up_read(&vm->userptr.notifier_lock);
index 9b35673b286c80c1c2332d6ece9add9f754f3ca8..7e924faeeea0b0f8ebc2f7fe89ade231412a3892 100644 (file)
@@ -459,21 +459,21 @@ static size_t calc_topo_query_size(struct xe_device *xe)
                 sizeof_field(struct xe_gt, fuse_topo.eu_mask_per_dss));
 }
 
-static void __user *copy_mask(void __user *ptr,
-                             struct drm_xe_query_topology_mask *topo,
-                             void *mask, size_t mask_size)
+static int copy_mask(void __user **ptr,
+                    struct drm_xe_query_topology_mask *topo,
+                    void *mask, size_t mask_size)
 {
        topo->num_bytes = mask_size;
 
-       if (copy_to_user(ptr, topo, sizeof(*topo)))
-               return ERR_PTR(-EFAULT);
-       ptr += sizeof(topo);
+       if (copy_to_user(*ptr, topo, sizeof(*topo)))
+               return -EFAULT;
+       *ptr += sizeof(topo);
 
-       if (copy_to_user(ptr, mask, mask_size))
-               return ERR_PTR(-EFAULT);
-       ptr += mask_size;
+       if (copy_to_user(*ptr, mask, mask_size))
+               return -EFAULT;
+       *ptr += mask_size;
 
-       return ptr;
+       return 0;
 }
 
 static int query_gt_topology(struct xe_device *xe,
@@ -493,28 +493,28 @@ static int query_gt_topology(struct xe_device *xe,
        }
 
        for_each_gt(gt, xe, id) {
+               int err;
+
                topo.gt_id = id;
 
                topo.type = DRM_XE_TOPO_DSS_GEOMETRY;
-               query_ptr = copy_mask(query_ptr, &topo,
-                                     gt->fuse_topo.g_dss_mask,
-                                     sizeof(gt->fuse_topo.g_dss_mask));
-               if (IS_ERR(query_ptr))
-                       return PTR_ERR(query_ptr);
+               err = copy_mask(&query_ptr, &topo, gt->fuse_topo.g_dss_mask,
+                               sizeof(gt->fuse_topo.g_dss_mask));
+               if (err)
+                       return err;
 
                topo.type = DRM_XE_TOPO_DSS_COMPUTE;
-               query_ptr = copy_mask(query_ptr, &topo,
-                                     gt->fuse_topo.c_dss_mask,
-                                     sizeof(gt->fuse_topo.c_dss_mask));
-               if (IS_ERR(query_ptr))
-                       return PTR_ERR(query_ptr);
+               err = copy_mask(&query_ptr, &topo, gt->fuse_topo.c_dss_mask,
+                               sizeof(gt->fuse_topo.c_dss_mask));
+               if (err)
+                       return err;
 
                topo.type = DRM_XE_TOPO_EU_PER_DSS;
-               query_ptr = copy_mask(query_ptr, &topo,
-                                     gt->fuse_topo.eu_mask_per_dss,
-                                     sizeof(gt->fuse_topo.eu_mask_per_dss));
-               if (IS_ERR(query_ptr))
-                       return PTR_ERR(query_ptr);
+               err = copy_mask(&query_ptr, &topo,
+                               gt->fuse_topo.eu_mask_per_dss,
+                               sizeof(gt->fuse_topo.eu_mask_per_dss));
+               if (err)
+                       return err;
        }
 
        return 0;
index d284afbe917c19203473b30d0abc38ca88ffbfa2..f43cdcaca6c5794ec8b42ab3bc77e1942004d046 100644 (file)
@@ -33,4 +33,9 @@ struct dma_fence *
 xe_sync_in_fence_get(struct xe_sync_entry *sync, int num_sync,
                     struct xe_exec_queue *q, struct xe_vm *vm);
 
+static inline bool xe_sync_is_ufence(struct xe_sync_entry *sync)
+{
+       return !!sync->ufence;
+}
+
 #endif
index 10b6995fbf294690a36234dc3c36bf741245b7a9..30db264d34a32315c6fc725c16dc24f6936da8e8 100644 (file)
@@ -46,7 +46,7 @@ static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
 
 /**
  * xe_vma_userptr_check_repin() - Advisory check for repin needed
- * @vma: The userptr vma
+ * @uvma: The userptr vma
  *
  * Check if the userptr vma has been invalidated since last successful
  * repin. The check is advisory only and can the function can be called
@@ -56,15 +56,17 @@ static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
  *
  * Return: 0 if userptr vma is valid, -EAGAIN otherwise; repin recommended.
  */
-int xe_vma_userptr_check_repin(struct xe_vma *vma)
+int xe_vma_userptr_check_repin(struct xe_userptr_vma *uvma)
 {
-       return mmu_interval_check_retry(&vma->userptr.notifier,
-                                       vma->userptr.notifier_seq) ?
+       return mmu_interval_check_retry(&uvma->userptr.notifier,
+                                       uvma->userptr.notifier_seq) ?
                -EAGAIN : 0;
 }
 
-int xe_vma_userptr_pin_pages(struct xe_vma *vma)
+int xe_vma_userptr_pin_pages(struct xe_userptr_vma *uvma)
 {
+       struct xe_userptr *userptr = &uvma->userptr;
+       struct xe_vma *vma = &uvma->vma;
        struct xe_vm *vm = xe_vma_vm(vma);
        struct xe_device *xe = vm->xe;
        const unsigned long num_pages = xe_vma_size(vma) >> PAGE_SHIFT;
@@ -80,30 +82,30 @@ retry:
        if (vma->gpuva.flags & XE_VMA_DESTROYED)
                return 0;
 
-       notifier_seq = mmu_interval_read_begin(&vma->userptr.notifier);
-       if (notifier_seq == vma->userptr.notifier_seq)
+       notifier_seq = mmu_interval_read_begin(&userptr->notifier);
+       if (notifier_seq == userptr->notifier_seq)
                return 0;
 
        pages = kvmalloc_array(num_pages, sizeof(*pages), GFP_KERNEL);
        if (!pages)
                return -ENOMEM;
 
-       if (vma->userptr.sg) {
+       if (userptr->sg) {
                dma_unmap_sgtable(xe->drm.dev,
-                                 vma->userptr.sg,
+                                 userptr->sg,
                                  read_only ? DMA_TO_DEVICE :
                                  DMA_BIDIRECTIONAL, 0);
-               sg_free_table(vma->userptr.sg);
-               vma->userptr.sg = NULL;
+               sg_free_table(userptr->sg);
+               userptr->sg = NULL;
        }
 
        pinned = ret = 0;
        if (in_kthread) {
-               if (!mmget_not_zero(vma->userptr.notifier.mm)) {
+               if (!mmget_not_zero(userptr->notifier.mm)) {
                        ret = -EFAULT;
                        goto mm_closed;
                }
-               kthread_use_mm(vma->userptr.notifier.mm);
+               kthread_use_mm(userptr->notifier.mm);
        }
 
        while (pinned < num_pages) {
@@ -123,32 +125,32 @@ retry:
        }
 
        if (in_kthread) {
-               kthread_unuse_mm(vma->userptr.notifier.mm);
-               mmput(vma->userptr.notifier.mm);
+               kthread_unuse_mm(userptr->notifier.mm);
+               mmput(userptr->notifier.mm);
        }
 mm_closed:
        if (ret)
                goto out;
 
-       ret = sg_alloc_table_from_pages_segment(&vma->userptr.sgt, pages,
+       ret = sg_alloc_table_from_pages_segment(&userptr->sgt, pages,
                                                pinned, 0,
                                                (u64)pinned << PAGE_SHIFT,
                                                xe_sg_segment_size(xe->drm.dev),
                                                GFP_KERNEL);
        if (ret) {
-               vma->userptr.sg = NULL;
+               userptr->sg = NULL;
                goto out;
        }
-       vma->userptr.sg = &vma->userptr.sgt;
+       userptr->sg = &userptr->sgt;
 
-       ret = dma_map_sgtable(xe->drm.dev, vma->userptr.sg,
+       ret = dma_map_sgtable(xe->drm.dev, userptr->sg,
                              read_only ? DMA_TO_DEVICE :
                              DMA_BIDIRECTIONAL,
                              DMA_ATTR_SKIP_CPU_SYNC |
                              DMA_ATTR_NO_KERNEL_MAPPING);
        if (ret) {
-               sg_free_table(vma->userptr.sg);
-               vma->userptr.sg = NULL;
+               sg_free_table(userptr->sg);
+               userptr->sg = NULL;
                goto out;
        }
 
@@ -167,8 +169,8 @@ out:
        kvfree(pages);
 
        if (!(ret < 0)) {
-               vma->userptr.notifier_seq = notifier_seq;
-               if (xe_vma_userptr_check_repin(vma) == -EAGAIN)
+               userptr->notifier_seq = notifier_seq;
+               if (xe_vma_userptr_check_repin(uvma) == -EAGAIN)
                        goto retry;
        }
 
@@ -635,7 +637,9 @@ static bool vma_userptr_invalidate(struct mmu_interval_notifier *mni,
                                   const struct mmu_notifier_range *range,
                                   unsigned long cur_seq)
 {
-       struct xe_vma *vma = container_of(mni, struct xe_vma, userptr.notifier);
+       struct xe_userptr *userptr = container_of(mni, typeof(*userptr), notifier);
+       struct xe_userptr_vma *uvma = container_of(userptr, typeof(*uvma), userptr);
+       struct xe_vma *vma = &uvma->vma;
        struct xe_vm *vm = xe_vma_vm(vma);
        struct dma_resv_iter cursor;
        struct dma_fence *fence;
@@ -651,7 +655,7 @@ static bool vma_userptr_invalidate(struct mmu_interval_notifier *mni,
        mmu_interval_set_seq(mni, cur_seq);
 
        /* No need to stop gpu access if the userptr is not yet bound. */
-       if (!vma->userptr.initial_bind) {
+       if (!userptr->initial_bind) {
                up_write(&vm->userptr.notifier_lock);
                return true;
        }
@@ -663,7 +667,7 @@ static bool vma_userptr_invalidate(struct mmu_interval_notifier *mni,
        if (!xe_vm_in_fault_mode(vm) &&
            !(vma->gpuva.flags & XE_VMA_DESTROYED) && vma->tile_present) {
                spin_lock(&vm->userptr.invalidated_lock);
-               list_move_tail(&vma->userptr.invalidate_link,
+               list_move_tail(&userptr->invalidate_link,
                               &vm->userptr.invalidated);
                spin_unlock(&vm->userptr.invalidated_lock);
        }
@@ -703,7 +707,7 @@ static const struct mmu_interval_notifier_ops vma_userptr_notifier_ops = {
 
 int xe_vm_userptr_pin(struct xe_vm *vm)
 {
-       struct xe_vma *vma, *next;
+       struct xe_userptr_vma *uvma, *next;
        int err = 0;
        LIST_HEAD(tmp_evict);
 
@@ -711,22 +715,23 @@ int xe_vm_userptr_pin(struct xe_vm *vm)
 
        /* Collect invalidated userptrs */
        spin_lock(&vm->userptr.invalidated_lock);
-       list_for_each_entry_safe(vma, next, &vm->userptr.invalidated,
+       list_for_each_entry_safe(uvma, next, &vm->userptr.invalidated,
                                 userptr.invalidate_link) {
-               list_del_init(&vma->userptr.invalidate_link);
-               list_move_tail(&vma->combined_links.userptr,
+               list_del_init(&uvma->userptr.invalidate_link);
+               list_move_tail(&uvma->userptr.repin_link,
                               &vm->userptr.repin_list);
        }
        spin_unlock(&vm->userptr.invalidated_lock);
 
        /* Pin and move to temporary list */
-       list_for_each_entry_safe(vma, next, &vm->userptr.repin_list,
-                                combined_links.userptr) {
-               err = xe_vma_userptr_pin_pages(vma);
+       list_for_each_entry_safe(uvma, next, &vm->userptr.repin_list,
+                                userptr.repin_link) {
+               err = xe_vma_userptr_pin_pages(uvma);
                if (err < 0)
                        return err;
 
-               list_move_tail(&vma->combined_links.userptr, &vm->rebind_list);
+               list_del_init(&uvma->userptr.repin_link);
+               list_move_tail(&uvma->vma.combined_links.rebind, &vm->rebind_list);
        }
 
        return 0;
@@ -782,6 +787,14 @@ struct dma_fence *xe_vm_rebind(struct xe_vm *vm, bool rebind_worker)
        return fence;
 }
 
+static void xe_vma_free(struct xe_vma *vma)
+{
+       if (xe_vma_is_userptr(vma))
+               kfree(to_userptr_vma(vma));
+       else
+               kfree(vma);
+}
+
 #define VMA_CREATE_FLAG_READ_ONLY      BIT(0)
 #define VMA_CREATE_FLAG_IS_NULL                BIT(1)
 
@@ -800,14 +813,26 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
        xe_assert(vm->xe, start < end);
        xe_assert(vm->xe, end < vm->size);
 
-       if (!bo && !is_null)    /* userptr */
+       /*
+        * Allocate and ensure that the xe_vma_is_userptr() return
+        * matches what was allocated.
+        */
+       if (!bo && !is_null) {
+               struct xe_userptr_vma *uvma = kzalloc(sizeof(*uvma), GFP_KERNEL);
+
+               if (!uvma)
+                       return ERR_PTR(-ENOMEM);
+
+               vma = &uvma->vma;
+       } else {
                vma = kzalloc(sizeof(*vma), GFP_KERNEL);
-       else
-               vma = kzalloc(sizeof(*vma) - sizeof(struct xe_userptr),
-                             GFP_KERNEL);
-       if (!vma) {
-               vma = ERR_PTR(-ENOMEM);
-               return vma;
+               if (!vma)
+                       return ERR_PTR(-ENOMEM);
+
+               if (is_null)
+                       vma->gpuva.flags |= DRM_GPUVA_SPARSE;
+               if (bo)
+                       vma->gpuva.gem.obj = &bo->ttm.base;
        }
 
        INIT_LIST_HEAD(&vma->combined_links.rebind);
@@ -818,8 +843,6 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
        vma->gpuva.va.range = end - start + 1;
        if (read_only)
                vma->gpuva.flags |= XE_VMA_READ_ONLY;
-       if (is_null)
-               vma->gpuva.flags |= DRM_GPUVA_SPARSE;
 
        for_each_tile(tile, vm->xe, id)
                vma->tile_mask |= 0x1 << id;
@@ -836,35 +859,35 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
 
                vm_bo = drm_gpuvm_bo_obtain(vma->gpuva.vm, &bo->ttm.base);
                if (IS_ERR(vm_bo)) {
-                       kfree(vma);
+                       xe_vma_free(vma);
                        return ERR_CAST(vm_bo);
                }
 
                drm_gpuvm_bo_extobj_add(vm_bo);
                drm_gem_object_get(&bo->ttm.base);
-               vma->gpuva.gem.obj = &bo->ttm.base;
                vma->gpuva.gem.offset = bo_offset_or_userptr;
                drm_gpuva_link(&vma->gpuva, vm_bo);
                drm_gpuvm_bo_put(vm_bo);
        } else /* userptr or null */ {
                if (!is_null) {
+                       struct xe_userptr *userptr = &to_userptr_vma(vma)->userptr;
                        u64 size = end - start + 1;
                        int err;
 
-                       INIT_LIST_HEAD(&vma->userptr.invalidate_link);
+                       INIT_LIST_HEAD(&userptr->invalidate_link);
+                       INIT_LIST_HEAD(&userptr->repin_link);
                        vma->gpuva.gem.offset = bo_offset_or_userptr;
 
-                       err = mmu_interval_notifier_insert(&vma->userptr.notifier,
+                       err = mmu_interval_notifier_insert(&userptr->notifier,
                                                           current->mm,
                                                           xe_vma_userptr(vma), size,
                                                           &vma_userptr_notifier_ops);
                        if (err) {
-                               kfree(vma);
-                               vma = ERR_PTR(err);
-                               return vma;
+                               xe_vma_free(vma);
+                               return ERR_PTR(err);
                        }
 
-                       vma->userptr.notifier_seq = LONG_MAX;
+                       userptr->notifier_seq = LONG_MAX;
                }
 
                xe_vm_get(vm);
@@ -880,13 +903,15 @@ static void xe_vma_destroy_late(struct xe_vma *vma)
        bool read_only = xe_vma_read_only(vma);
 
        if (xe_vma_is_userptr(vma)) {
-               if (vma->userptr.sg) {
+               struct xe_userptr *userptr = &to_userptr_vma(vma)->userptr;
+
+               if (userptr->sg) {
                        dma_unmap_sgtable(xe->drm.dev,
-                                         vma->userptr.sg,
+                                         userptr->sg,
                                          read_only ? DMA_TO_DEVICE :
                                          DMA_BIDIRECTIONAL, 0);
-                       sg_free_table(vma->userptr.sg);
-                       vma->userptr.sg = NULL;
+                       sg_free_table(userptr->sg);
+                       userptr->sg = NULL;
                }
 
                /*
@@ -894,7 +919,7 @@ static void xe_vma_destroy_late(struct xe_vma *vma)
                 * the notifer until we're sure the GPU is not accessing
                 * them anymore
                 */
-               mmu_interval_notifier_remove(&vma->userptr.notifier);
+               mmu_interval_notifier_remove(&userptr->notifier);
                xe_vm_put(vm);
        } else if (xe_vma_is_null(vma)) {
                xe_vm_put(vm);
@@ -902,7 +927,7 @@ static void xe_vma_destroy_late(struct xe_vma *vma)
                xe_bo_put(xe_vma_bo(vma));
        }
 
-       kfree(vma);
+       xe_vma_free(vma);
 }
 
 static void vma_destroy_work_func(struct work_struct *w)
@@ -933,7 +958,7 @@ static void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence)
                xe_assert(vm->xe, vma->gpuva.flags & XE_VMA_DESTROYED);
 
                spin_lock(&vm->userptr.invalidated_lock);
-               list_del(&vma->userptr.invalidate_link);
+               list_del(&to_userptr_vma(vma)->userptr.invalidate_link);
                spin_unlock(&vm->userptr.invalidated_lock);
        } else if (!xe_vma_is_null(vma)) {
                xe_bo_assert_held(xe_vma_bo(vma));
@@ -1855,10 +1880,8 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data,
        mutex_lock(&xef->vm.lock);
        err = xa_alloc(&xef->vm.xa, &id, vm, xa_limit_32b, GFP_KERNEL);
        mutex_unlock(&xef->vm.lock);
-       if (err) {
-               xe_vm_close_and_put(vm);
-               return err;
-       }
+       if (err)
+               goto err_close_and_put;
 
        if (xe->info.has_asid) {
                mutex_lock(&xe->usm.lock);
@@ -1866,11 +1889,9 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data,
                                      XA_LIMIT(1, XE_MAX_ASID - 1),
                                      &xe->usm.next_asid, GFP_KERNEL);
                mutex_unlock(&xe->usm.lock);
-               if (err < 0) {
-                       xe_vm_close_and_put(vm);
-                       return err;
-               }
-               err = 0;
+               if (err < 0)
+                       goto err_free_id;
+
                vm->usm.asid = asid;
        }
 
@@ -1888,6 +1909,15 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data,
 #endif
 
        return 0;
+
+err_free_id:
+       mutex_lock(&xef->vm.lock);
+       xa_erase(&xef->vm.xa, id);
+       mutex_unlock(&xef->vm.lock);
+err_close_and_put:
+       xe_vm_close_and_put(vm);
+
+       return err;
 }
 
 int xe_vm_destroy_ioctl(struct drm_device *dev, void *data,
@@ -2145,7 +2175,7 @@ static struct xe_vma *new_vma(struct xe_vm *vm, struct drm_gpuva_op_map *op,
                drm_exec_fini(&exec);
 
        if (xe_vma_is_userptr(vma)) {
-               err = xe_vma_userptr_pin_pages(vma);
+               err = xe_vma_userptr_pin_pages(to_userptr_vma(vma));
                if (err) {
                        prep_vma_destroy(vm, vma, false);
                        xe_vma_destroy_unlocked(vma);
@@ -2502,7 +2532,7 @@ retry_userptr:
 
        if (err == -EAGAIN && xe_vma_is_userptr(vma)) {
                lockdep_assert_held_write(&vm->lock);
-               err = xe_vma_userptr_pin_pages(vma);
+               err = xe_vma_userptr_pin_pages(to_userptr_vma(vma));
                if (!err)
                        goto retry_userptr;
 
@@ -2846,7 +2876,7 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
        struct drm_gpuva_ops **ops = NULL;
        struct xe_vm *vm;
        struct xe_exec_queue *q = NULL;
-       u32 num_syncs;
+       u32 num_syncs, num_ufence = 0;
        struct xe_sync_entry *syncs = NULL;
        struct drm_xe_vm_bind_op *bind_ops;
        LIST_HEAD(ops_list);
@@ -2983,6 +3013,14 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
                                           SYNC_PARSE_FLAG_DISALLOW_USER_FENCE : 0));
                if (err)
                        goto free_syncs;
+
+               if (xe_sync_is_ufence(&syncs[num_syncs]))
+                       num_ufence++;
+       }
+
+       if (XE_IOCTL_DBG(xe, num_ufence > 1)) {
+               err = -EINVAL;
+               goto free_syncs;
        }
 
        if (!args->num_binds) {
@@ -3125,8 +3163,8 @@ int xe_vm_invalidate_vma(struct xe_vma *vma)
        if (IS_ENABLED(CONFIG_PROVE_LOCKING)) {
                if (xe_vma_is_userptr(vma)) {
                        WARN_ON_ONCE(!mmu_interval_check_retry
-                                    (&vma->userptr.notifier,
-                                     vma->userptr.notifier_seq));
+                                    (&to_userptr_vma(vma)->userptr.notifier,
+                                     to_userptr_vma(vma)->userptr.notifier_seq));
                        WARN_ON_ONCE(!dma_resv_test_signaled(xe_vm_resv(xe_vma_vm(vma)),
                                                             DMA_RESV_USAGE_BOOKKEEP));
 
@@ -3187,11 +3225,11 @@ int xe_analyze_vm(struct drm_printer *p, struct xe_vm *vm, int gt_id)
                if (is_null) {
                        addr = 0;
                } else if (is_userptr) {
+                       struct sg_table *sg = to_userptr_vma(vma)->userptr.sg;
                        struct xe_res_cursor cur;
 
-                       if (vma->userptr.sg) {
-                               xe_res_first_sg(vma->userptr.sg, 0, XE_PAGE_SIZE,
-                                               &cur);
+                       if (sg) {
+                               xe_res_first_sg(sg, 0, XE_PAGE_SIZE, &cur);
                                addr = xe_res_dma(&cur);
                        } else {
                                addr = 0;
index cf2f96e8c1ab92245b69dd8853c90d5e128262fd..9654a0612fc258d0ba7395ba7c7fd87899caf904 100644 (file)
@@ -160,6 +160,18 @@ static inline bool xe_vma_is_userptr(struct xe_vma *vma)
        return xe_vma_has_no_bo(vma) && !xe_vma_is_null(vma);
 }
 
+/**
+ * to_userptr_vma() - Return a pointer to an embedding userptr vma
+ * @vma: Pointer to the embedded struct xe_vma
+ *
+ * Return: Pointer to the embedding userptr vma
+ */
+static inline struct xe_userptr_vma *to_userptr_vma(struct xe_vma *vma)
+{
+       xe_assert(xe_vma_vm(vma)->xe, xe_vma_is_userptr(vma));
+       return container_of(vma, struct xe_userptr_vma, vma);
+}
+
 u64 xe_vm_pdp4_descriptor(struct xe_vm *vm, struct xe_tile *tile);
 
 int xe_vm_create_ioctl(struct drm_device *dev, void *data,
@@ -224,9 +236,9 @@ static inline void xe_vm_reactivate_rebind(struct xe_vm *vm)
        }
 }
 
-int xe_vma_userptr_pin_pages(struct xe_vma *vma);
+int xe_vma_userptr_pin_pages(struct xe_userptr_vma *uvma);
 
-int xe_vma_userptr_check_repin(struct xe_vma *vma);
+int xe_vma_userptr_check_repin(struct xe_userptr_vma *uvma);
 
 bool xe_vm_validate_should_retry(struct drm_exec *exec, int err, ktime_t *end);
 
index 63e8a50b88e94980d65a0800817235c518adcd69..1fec66ae2eb2dd0309590ec7b84ad34cfa6a1b25 100644 (file)
@@ -37,6 +37,8 @@ struct xe_vm;
 struct xe_userptr {
        /** @invalidate_link: Link for the vm::userptr.invalidated list */
        struct list_head invalidate_link;
+       /** @userptr: link into VM repin list if userptr. */
+       struct list_head repin_link;
        /**
         * @notifier: MMU notifier for user pointer (invalidation call back)
         */
@@ -68,8 +70,6 @@ struct xe_vma {
         * resv.
         */
        union {
-               /** @userptr: link into VM repin list if userptr. */
-               struct list_head userptr;
                /** @rebind: link into VM if this VMA needs rebinding. */
                struct list_head rebind;
                /** @destroy: link to contested list when VM is being closed. */
@@ -105,11 +105,15 @@ struct xe_vma {
         * @pat_index: The pat index to use when encoding the PTEs for this vma.
         */
        u16 pat_index;
+};
 
-       /**
-        * @userptr: user pointer state, only allocated for VMAs that are
-        * user pointers
-        */
+/**
+ * struct xe_userptr_vma - A userptr vma subclass
+ * @vma: The vma.
+ * @userptr: Additional userptr information.
+ */
+struct xe_userptr_vma {
+       struct xe_vma vma;
        struct xe_userptr userptr;
 };
 
index d9ef45fcaeab1380967fe2fa2357411d2bc913d4..470ae2c29c94f25b66127827b725da24b41e101b 100644 (file)
@@ -143,6 +143,9 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *s
 }
 EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup);
 
+/* Disables missing prototype warnings */
+__bpf_kfunc_start_defs();
+
 /**
  * hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx
  *
@@ -152,7 +155,7 @@ EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup);
  *
  * @returns %NULL on error, an %__u8 memory pointer on success
  */
-noinline __u8 *
+__bpf_kfunc __u8 *
 hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)
 {
        struct hid_bpf_ctx_kern *ctx_kern;
@@ -167,6 +170,7 @@ hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr
 
        return ctx_kern->data + offset;
 }
+__bpf_kfunc_end_defs();
 
 /*
  * The following set contains all functions we agree BPF programs
@@ -241,6 +245,42 @@ int hid_bpf_reconnect(struct hid_device *hdev)
        return 0;
 }
 
+static int do_hid_bpf_attach_prog(struct hid_device *hdev, int prog_fd, struct bpf_prog *prog,
+                                 __u32 flags)
+{
+       int fd, err, prog_type;
+
+       prog_type = hid_bpf_get_prog_attach_type(prog);
+       if (prog_type < 0)
+               return prog_type;
+
+       if (prog_type >= HID_BPF_PROG_TYPE_MAX)
+               return -EINVAL;
+
+       if (prog_type == HID_BPF_PROG_TYPE_DEVICE_EVENT) {
+               err = hid_bpf_allocate_event_data(hdev);
+               if (err)
+                       return err;
+       }
+
+       fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fd, prog, flags);
+       if (fd < 0)
+               return fd;
+
+       if (prog_type == HID_BPF_PROG_TYPE_RDESC_FIXUP) {
+               err = hid_bpf_reconnect(hdev);
+               if (err) {
+                       close_fd(fd);
+                       return err;
+               }
+       }
+
+       return fd;
+}
+
+/* Disables missing prototype warnings */
+__bpf_kfunc_start_defs();
+
 /**
  * hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device
  *
@@ -253,22 +293,17 @@ int hid_bpf_reconnect(struct hid_device *hdev)
  * is pinned to the BPF file system).
  */
 /* called from syscall */
-noinline int
+__bpf_kfunc int
 hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
 {
        struct hid_device *hdev;
+       struct bpf_prog *prog;
        struct device *dev;
-       int fd, err, prog_type = hid_bpf_get_prog_attach_type(prog_fd);
+       int err, fd;
 
        if (!hid_bpf_ops)
                return -EINVAL;
 
-       if (prog_type < 0)
-               return prog_type;
-
-       if (prog_type >= HID_BPF_PROG_TYPE_MAX)
-               return -EINVAL;
-
        if ((flags & ~HID_BPF_FLAG_MASK))
                return -EINVAL;
 
@@ -278,25 +313,29 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
 
        hdev = to_hid_device(dev);
 
-       if (prog_type == HID_BPF_PROG_TYPE_DEVICE_EVENT) {
-               err = hid_bpf_allocate_event_data(hdev);
-               if (err)
-                       return err;
+       /*
+        * take a ref on the prog itself, it will be released
+        * on errors or when it'll be detached
+        */
+       prog = bpf_prog_get(prog_fd);
+       if (IS_ERR(prog)) {
+               err = PTR_ERR(prog);
+               goto out_dev_put;
        }
 
-       fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fd, flags);
-       if (fd < 0)
-               return fd;
-
-       if (prog_type == HID_BPF_PROG_TYPE_RDESC_FIXUP) {
-               err = hid_bpf_reconnect(hdev);
-               if (err) {
-                       close_fd(fd);
-                       return err;
-               }
+       fd = do_hid_bpf_attach_prog(hdev, prog_fd, prog, flags);
+       if (fd < 0) {
+               err = fd;
+               goto out_prog_put;
        }
 
        return fd;
+
+ out_prog_put:
+       bpf_prog_put(prog);
+ out_dev_put:
+       put_device(dev);
+       return err;
 }
 
 /**
@@ -306,7 +345,7 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
  *
  * @returns A pointer to &struct hid_bpf_ctx on success, %NULL on error.
  */
-noinline struct hid_bpf_ctx *
+__bpf_kfunc struct hid_bpf_ctx *
 hid_bpf_allocate_context(unsigned int hid_id)
 {
        struct hid_device *hdev;
@@ -323,8 +362,10 @@ hid_bpf_allocate_context(unsigned int hid_id)
        hdev = to_hid_device(dev);
 
        ctx_kern = kzalloc(sizeof(*ctx_kern), GFP_KERNEL);
-       if (!ctx_kern)
+       if (!ctx_kern) {
+               put_device(dev);
                return NULL;
+       }
 
        ctx_kern->ctx.hid = hdev;
 
@@ -337,14 +378,19 @@ hid_bpf_allocate_context(unsigned int hid_id)
  * @ctx: the HID-BPF context to release
  *
  */
-noinline void
+__bpf_kfunc void
 hid_bpf_release_context(struct hid_bpf_ctx *ctx)
 {
        struct hid_bpf_ctx_kern *ctx_kern;
+       struct hid_device *hid;
 
        ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
+       hid = (struct hid_device *)ctx_kern->ctx.hid; /* ignore const */
 
        kfree(ctx_kern);
+
+       /* get_device() is called by bus_find_device() */
+       put_device(&hid->dev);
 }
 
 /**
@@ -358,7 +404,7 @@ hid_bpf_release_context(struct hid_bpf_ctx *ctx)
  *
  * @returns %0 on success, a negative error code otherwise.
  */
-noinline int
+__bpf_kfunc int
 hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
                   enum hid_report_type rtype, enum hid_class_request reqtype)
 {
@@ -426,6 +472,7 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
        kfree(dma_data);
        return ret;
 }
+__bpf_kfunc_end_defs();
 
 /* our HID-BPF entrypoints */
 BTF_SET8_START(hid_bpf_fmodret_ids)
index 63dfc8605cd21efbc5f0bdc1844e4e79d73ab3cb..fbe0639d09f2604d6a8e11833eba82480640e289 100644 (file)
@@ -12,9 +12,9 @@ struct hid_bpf_ctx_kern {
 
 int hid_bpf_preload_skel(void);
 void hid_bpf_free_links_and_skel(void);
-int hid_bpf_get_prog_attach_type(int prog_fd);
+int hid_bpf_get_prog_attach_type(struct bpf_prog *prog);
 int __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type, int prog_fd,
-                         __u32 flags);
+                         struct bpf_prog *prog, __u32 flags);
 void __hid_bpf_destroy_device(struct hid_device *hdev);
 int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
                     struct hid_bpf_ctx_kern *ctx_kern);
index eca34b7372f951fc17e156ec2cc3761282ea61e8..aa8e1c79cdf5518301e73e44038f75e6fb1173e0 100644 (file)
@@ -196,6 +196,7 @@ static void __hid_bpf_do_release_prog(int map_fd, unsigned int idx)
 static void hid_bpf_release_progs(struct work_struct *work)
 {
        int i, j, n, map_fd = -1;
+       bool hdev_destroyed;
 
        if (!jmp_table.map)
                return;
@@ -220,6 +221,12 @@ static void hid_bpf_release_progs(struct work_struct *work)
                if (entry->hdev) {
                        hdev = entry->hdev;
                        type = entry->type;
+                       /*
+                        * hdev is still valid, even if we are called after hid_destroy_device():
+                        * when hid_bpf_attach() gets called, it takes a ref on the dev through
+                        * bus_find_device()
+                        */
+                       hdev_destroyed = hdev->bpf.destroyed;
 
                        hid_bpf_populate_hdev(hdev, type);
 
@@ -232,12 +239,19 @@ static void hid_bpf_release_progs(struct work_struct *work)
                                if (test_bit(next->idx, jmp_table.enabled))
                                        continue;
 
-                               if (next->hdev == hdev && next->type == type)
+                               if (next->hdev == hdev && next->type == type) {
+                                       /*
+                                        * clear the hdev reference and decrement the device ref
+                                        * that was taken during bus_find_device() while calling
+                                        * hid_bpf_attach()
+                                        */
                                        next->hdev = NULL;
+                                       put_device(&hdev->dev);
+                               }
                        }
 
-                       /* if type was rdesc fixup, reconnect device */
-                       if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP)
+                       /* if type was rdesc fixup and the device is not gone, reconnect device */
+                       if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP && !hdev_destroyed)
                                hid_bpf_reconnect(hdev);
                }
        }
@@ -333,15 +347,10 @@ static int hid_bpf_insert_prog(int prog_fd, struct bpf_prog *prog)
        return err;
 }
 
-int hid_bpf_get_prog_attach_type(int prog_fd)
+int hid_bpf_get_prog_attach_type(struct bpf_prog *prog)
 {
-       struct bpf_prog *prog = NULL;
-       int i;
        int prog_type = HID_BPF_PROG_TYPE_UNDEF;
-
-       prog = bpf_prog_get(prog_fd);
-       if (IS_ERR(prog))
-               return PTR_ERR(prog);
+       int i;
 
        for (i = 0; i < HID_BPF_PROG_TYPE_MAX; i++) {
                if (hid_bpf_btf_ids[i] == prog->aux->attach_btf_id) {
@@ -350,8 +359,6 @@ int hid_bpf_get_prog_attach_type(int prog_fd)
                }
        }
 
-       bpf_prog_put(prog);
-
        return prog_type;
 }
 
@@ -388,19 +395,13 @@ static const struct bpf_link_ops hid_bpf_link_lops = {
 /* called from syscall */
 noinline int
 __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type,
-                     int prog_fd, __u32 flags)
+                     int prog_fd, struct bpf_prog *prog, __u32 flags)
 {
        struct bpf_link_primer link_primer;
        struct hid_bpf_link *link;
-       struct bpf_prog *prog = NULL;
        struct hid_bpf_prog_entry *prog_entry;
        int cnt, err = -EINVAL, prog_table_idx = -1;
 
-       /* take a ref on the prog itself */
-       prog = bpf_prog_get(prog_fd);
-       if (IS_ERR(prog))
-               return PTR_ERR(prog);
-
        mutex_lock(&hid_bpf_attach_lock);
 
        link = kzalloc(sizeof(*link), GFP_USER);
@@ -467,7 +468,6 @@ __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type,
  err_unlock:
        mutex_unlock(&hid_bpf_attach_lock);
 
-       bpf_prog_put(prog);
        kfree(link);
 
        return err;
index fb30e228d35f9a91b6bb395845584d9f073be26c..828a5c022c6407add84c44122248e0e1ea9aaa64 100644 (file)
 
 #define USB_VENDOR_ID_CIDC             0x1677
 
+#define I2C_VENDOR_ID_CIRQUE           0x0488
+#define I2C_PRODUCT_ID_CIRQUE_1063     0x1063
+
 #define USB_VENDOR_ID_CJTOUCH          0x24b8
 #define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020 0x0020
 #define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040 0x0040
index fd6d8f1d9b8f61992a69ce651dd379d121c2da49..6ef0c88e3e60a6910eb60f052107dafac9f01d1c 100644 (file)
@@ -4610,6 +4610,8 @@ static const struct hid_device_id hidpp_devices[] = {
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC088) },
        { /* Logitech G Pro X Superlight Gaming Mouse over USB */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC094) },
+       { /* Logitech G Pro X Superlight 2 Gaming Mouse over USB */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC09b) },
 
        { /* G935 Gaming Headset */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0x0a87),
index 82d0a77359c460c9bad772038e1a129e9983e0c0..58b15750dbb0ac2cb2ad333b616dc39cdea8c779 100644 (file)
@@ -800,6 +800,8 @@ static inline int thunderstrike_led_create(struct thunderstrike *ts)
 
        led->name = devm_kasprintf(&ts->base.hdev->dev, GFP_KERNEL,
                                   "thunderstrike%d:blue:led", ts->id);
+       if (!led->name)
+               return -ENOMEM;
        led->max_brightness = 1;
        led->flags = LED_CORE_SUSPENDRESUME | LED_RETAIN_AT_SHUTDOWN;
        led->brightness_get = &thunderstrike_led_get_brightness;
@@ -831,6 +833,8 @@ static inline int thunderstrike_psy_create(struct shield_device *shield_dev)
        shield_dev->battery_dev.desc.name =
                devm_kasprintf(&ts->base.hdev->dev, GFP_KERNEL,
                               "thunderstrike_%d", ts->id);
+       if (!shield_dev->battery_dev.desc.name)
+               return -ENOMEM;
 
        shield_dev->battery_dev.psy = power_supply_register(
                &hdev->dev, &shield_dev->battery_dev.desc, &psy_cfg);
index b3c4e50e248aa7eda08a356187ecea54cc803834..b08a5ab5852884219654ac449f255d9a3e3f1585 100644 (file)
@@ -1109,10 +1109,9 @@ static int steam_probe(struct hid_device *hdev,
                return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 
        steam = devm_kzalloc(&hdev->dev, sizeof(*steam), GFP_KERNEL);
-       if (!steam) {
-               ret = -ENOMEM;
-               goto steam_alloc_fail;
-       }
+       if (!steam)
+               return -ENOMEM;
+
        steam->hdev = hdev;
        hid_set_drvdata(hdev, steam);
        spin_lock_init(&steam->lock);
@@ -1129,14 +1128,14 @@ static int steam_probe(struct hid_device *hdev,
         */
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDRAW);
        if (ret)
-               goto hid_hw_start_fail;
+               goto err_cancel_work;
 
        ret = hid_hw_open(hdev);
        if (ret) {
                hid_err(hdev,
                        "%s:hid_hw_open\n",
                        __func__);
-               goto hid_hw_open_fail;
+               goto err_hw_stop;
        }
 
        if (steam->quirks & STEAM_QUIRK_WIRELESS) {
@@ -1152,36 +1151,37 @@ static int steam_probe(struct hid_device *hdev,
                        hid_err(hdev,
                                "%s:steam_register failed with error %d\n",
                                __func__, ret);
-                       goto input_register_fail;
+                       goto err_hw_close;
                }
        }
 
        steam->client_hdev = steam_create_client_hid(hdev);
        if (IS_ERR(steam->client_hdev)) {
                ret = PTR_ERR(steam->client_hdev);
-               goto client_hdev_fail;
+               goto err_stream_unregister;
        }
        steam->client_hdev->driver_data = steam;
 
        ret = hid_add_device(steam->client_hdev);
        if (ret)
-               goto client_hdev_add_fail;
+               goto err_destroy;
 
        return 0;
 
-client_hdev_add_fail:
-       hid_hw_stop(hdev);
-client_hdev_fail:
+err_destroy:
        hid_destroy_device(steam->client_hdev);
-input_register_fail:
-hid_hw_open_fail:
-hid_hw_start_fail:
+err_stream_unregister:
+       if (steam->connected)
+               steam_unregister(steam);
+err_hw_close:
+       hid_hw_close(hdev);
+err_hw_stop:
+       hid_hw_stop(hdev);
+err_cancel_work:
        cancel_work_sync(&steam->work_connect);
        cancel_delayed_work_sync(&steam->mode_switch);
        cancel_work_sync(&steam->rumble_work);
-steam_alloc_fail:
-       hid_err(hdev, "%s: failed with error %d\n",
-                       __func__, ret);
+
        return ret;
 }
 
index 13c8dd8cd35060731165cd2018f96c6e7bfef512..2bc762d31ac70de9724df166422f31ab1c8687f4 100644 (file)
@@ -357,8 +357,11 @@ static int hidraw_release(struct inode * inode, struct file * file)
        down_write(&minors_rwsem);
 
        spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
-       for (int i = list->tail; i < list->head; i++)
-               kfree(list->buffer[i].value);
+       while (list->tail != list->head) {
+               kfree(list->buffer[list->tail].value);
+               list->buffer[list->tail].value = NULL;
+               list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
+       }
        list_del(&list->node);
        spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
        kfree(list);
index 90f316ae9819af4759720aad86136721f78f5abe..2df1ab3c31cc54da812ee653face224f32e69fc2 100644 (file)
@@ -49,6 +49,7 @@
 #define I2C_HID_QUIRK_RESET_ON_RESUME          BIT(2)
 #define I2C_HID_QUIRK_BAD_INPUT_SIZE           BIT(3)
 #define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET    BIT(4)
+#define I2C_HID_QUIRK_NO_SLEEP_ON_SUSPEND      BIT(5)
 
 /* Command opcodes */
 #define I2C_HID_OPCODE_RESET                   0x01
@@ -131,6 +132,8 @@ static const struct i2c_hid_quirks {
                 I2C_HID_QUIRK_RESET_ON_RESUME },
        { USB_VENDOR_ID_ITE, I2C_DEVICE_ID_ITE_LENOVO_LEGION_Y720,
                I2C_HID_QUIRK_BAD_INPUT_SIZE },
+       { I2C_VENDOR_ID_CIRQUE, I2C_PRODUCT_ID_CIRQUE_1063,
+               I2C_HID_QUIRK_NO_SLEEP_ON_SUSPEND },
        /*
         * Sending the wakeup after reset actually break ELAN touchscreen controller
         */
@@ -956,7 +959,8 @@ static int i2c_hid_core_suspend(struct i2c_hid *ihid, bool force_poweroff)
                return ret;
 
        /* Save some power */
-       i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
+       if (!(ihid->quirks & I2C_HID_QUIRK_NO_SLEEP_ON_SUSPEND))
+               i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
 
        disable_irq(client->irq);
 
index c4e1fa0273c84c3b2e3b438e04673727b05e6f6e..8be4d576da7733d28b8e4a1a07e86a0d11584ae6 100644 (file)
@@ -87,6 +87,7 @@ static int i2c_hid_of_probe(struct i2c_client *client)
        if (!ihid_of)
                return -ENOMEM;
 
+       ihid_of->client = client;
        ihid_of->ops.power_up = i2c_hid_of_power_up;
        ihid_of->ops.power_down = i2c_hid_of_power_down;
 
index 85e5237757142a05b45fdd7006d4c7b2ca61a3c3..8129d7b3ceaf9ae2e851f39af2db7aa6eaca9ce0 100644 (file)
@@ -146,7 +146,7 @@ static int waterforce_get_status(struct waterforce_data *priv)
        /* Send command for getting status */
        ret = waterforce_write_expanded(priv, get_status_cmd, GET_STATUS_CMD_LENGTH);
        if (ret < 0)
-               return ret;
+               goto unlock_and_return;
 
        ret = wait_for_completion_interruptible_timeout(&priv->status_report_received,
                                                        msecs_to_jiffies(STATUS_VALIDITY));
index b9bb469e2d8febe1d056e0b8f7d0a0b743d5ff3e..e5fa10b3b8bc7184e03e6caa0701e34f81bcb7cb 100644 (file)
@@ -126,6 +126,21 @@ static const struct regulator_desc __maybe_unused mp2975_reg_desc[] = {
 
 #define to_mp2975_data(x)  container_of(x, struct mp2975_data, info)
 
+static int mp2975_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+       switch (reg) {
+       case PMBUS_VOUT_MODE:
+               /*
+                * Report direct format as configured by MFR_DC_LOOP_CTRL.
+                * Unlike on MP2971/MP2973 the reported VOUT_MODE isn't automatically
+                * internally updated, but always reads as PB_VOUT_MODE_VID.
+                */
+               return PB_VOUT_MODE_DIRECT;
+       default:
+               return -ENODATA;
+       }
+}
+
 static int
 mp2975_read_word_helper(struct i2c_client *client, int page, int phase, u8 reg,
                        u16 mask)
@@ -869,6 +884,7 @@ static struct pmbus_driver_info mp2975_info = {
                PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
                PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT |
                PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | PMBUS_PHASE_VIRTUAL,
+       .read_byte_data = mp2975_read_byte_data,
        .read_word_data = mp2975_read_word_data,
 #if IS_ENABLED(CONFIG_SENSORS_MP2975_REGULATOR)
        .num_regulators = 1,
index b1244d7df6cc9e097a11257f9bb530b8954e3c12..7c4b2a5cc1b54a1c98a92b38076df6a7b0424b49 100644 (file)
@@ -294,6 +294,7 @@ static const struct xpad_device {
        { 0x1689, 0xfd00, "Razer Onza Tournament Edition", 0, XTYPE_XBOX360 },
        { 0x1689, 0xfd01, "Razer Onza Classic Edition", 0, XTYPE_XBOX360 },
        { 0x1689, 0xfe00, "Razer Sabertooth", 0, XTYPE_XBOX360 },
+       { 0x17ef, 0x6182, "Lenovo Legion Controller for Windows", 0, XTYPE_XBOX360 },
        { 0x1949, 0x041a, "Amazon Game Controller", 0, XTYPE_XBOX360 },
        { 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
        { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
@@ -491,6 +492,7 @@ static const struct usb_device_id xpad_table[] = {
        XPAD_XBOX360_VENDOR(0x15e4),            /* Numark Xbox 360 controllers */
        XPAD_XBOX360_VENDOR(0x162e),            /* Joytech Xbox 360 controllers */
        XPAD_XBOX360_VENDOR(0x1689),            /* Razer Onza */
+       XPAD_XBOX360_VENDOR(0x17ef),            /* Lenovo */
        XPAD_XBOX360_VENDOR(0x1949),            /* Amazon controllers */
        XPAD_XBOX360_VENDOR(0x1bad),            /* Harmonix Rock Band guitar and drums */
        XPAD_XBOX360_VENDOR(0x20d6),            /* PowerA controllers */
index 13ef6284223da30940e5a37802d04a104d2692f6..7f67f9f2946b484317575d529ee35a385fc2882e 100644 (file)
@@ -811,7 +811,6 @@ static int atkbd_probe(struct atkbd *atkbd)
 {
        struct ps2dev *ps2dev = &atkbd->ps2dev;
        unsigned char param[2];
-       bool skip_getid;
 
 /*
  * Some systems, where the bit-twiddling when testing the io-lines of the
@@ -825,6 +824,11 @@ static int atkbd_probe(struct atkbd *atkbd)
                                 "keyboard reset failed on %s\n",
                                 ps2dev->serio->phys);
 
+       if (atkbd_skip_getid(atkbd)) {
+               atkbd->id = 0xab83;
+               goto deactivate_kbd;
+       }
+
 /*
  * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
  * Some keyboards report different values, but the first byte is always 0xab or
@@ -833,18 +837,17 @@ static int atkbd_probe(struct atkbd *atkbd)
  */
 
        param[0] = param[1] = 0xa5;     /* initialize with invalid values */
-       skip_getid = atkbd_skip_getid(atkbd);
-       if (skip_getid || ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
+       if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
 
 /*
- * If the get ID command was skipped or failed, we check if we can at least set
+ * If the get ID command failed, we check if we can at least set
  * the LEDs on the keyboard. This should work on every keyboard out there.
  * It also turns the LEDs off, which we want anyway.
  */
                param[0] = 0;
                if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
                        return -1;
-               atkbd->id = skip_getid ? 0xab83 : 0xabba;
+               atkbd->id = 0xabba;
                return 0;
        }
 
@@ -860,6 +863,7 @@ static int atkbd_probe(struct atkbd *atkbd)
                return -1;
        }
 
+deactivate_kbd:
 /*
  * Make sure nothing is coming from the keyboard and disturbs our
  * internal state.
index ca150618d32f1863795f390b4ebf4687ea0e36c1..953992b458e9f2c46900204e926da7c665468709 100644 (file)
@@ -19,6 +19,7 @@
  * Copyright (C) 2006     Nicolas Boichat (nicolas@boichat.ch)
  */
 
+#include "linux/usb.h"
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
@@ -193,6 +194,8 @@ enum tp_type {
 
 /* list of device capability bits */
 #define HAS_INTEGRATED_BUTTON  1
+/* maximum number of supported endpoints (currently trackpad and button) */
+#define MAX_ENDPOINTS  2
 
 /* trackpad finger data block size */
 #define FSIZE_TYPE1            (14 * sizeof(__le16))
@@ -891,6 +894,18 @@ static int bcm5974_resume(struct usb_interface *iface)
        return error;
 }
 
+static bool bcm5974_check_endpoints(struct usb_interface *iface,
+                                   const struct bcm5974_config *cfg)
+{
+       u8 ep_addr[MAX_ENDPOINTS + 1] = {0};
+
+       ep_addr[0] = cfg->tp_ep;
+       if (cfg->tp_type == TYPE1)
+               ep_addr[1] = cfg->bt_ep;
+
+       return usb_check_int_endpoints(iface, ep_addr);
+}
+
 static int bcm5974_probe(struct usb_interface *iface,
                         const struct usb_device_id *id)
 {
@@ -903,6 +918,11 @@ static int bcm5974_probe(struct usb_interface *iface,
        /* find the product index */
        cfg = bcm5974_get_config(udev);
 
+       if (!bcm5974_check_endpoints(iface, cfg)) {
+               dev_err(&iface->dev, "Unexpected non-int endpoint\n");
+               return -ENODEV;
+       }
+
        /* allocate memory for our device state and initialize it */
        dev = kzalloc(sizeof(struct bcm5974), GFP_KERNEL);
        input_dev = input_allocate_device();
index b585b1dab870e0725daa62d7b52d2c9ca406798a..dfc6c581873b7d45da63d88a216295a24fa2c13b 100644 (file)
@@ -634,6 +634,14 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
                },
                .driver_data = (void *)(SERIO_QUIRK_NOAUX)
        },
+       {
+               /* Fujitsu Lifebook U728 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U728"),
+               },
+               .driver_data = (void *)(SERIO_QUIRK_NOAUX)
+       },
        {
                /* Gigabyte M912 */
                .matches = {
@@ -1208,6 +1216,12 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
                                        SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOLOOP |
                                        SERIO_QUIRK_NOPNP)
        },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "NS5x_7xPU"),
+               },
+               .driver_data = (void *)(SERIO_QUIRK_NOAUX)
+       },
        {
                .matches = {
                        DMI_MATCH(DMI_BOARD_NAME, "NJ50_70CU"),
index af32fbe57b630373f6fd8b67e3129be1d54de1d1..b068ff8afbc9ad3ba62b70cbbee20feb572c3855 100644 (file)
@@ -884,7 +884,8 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
                }
        }
 
-       if (ts->gpio_count == 2 && ts->gpio_int_idx == 0) {
+       /* Some devices with gpio_int_idx 0 list a third unused GPIO */
+       if ((ts->gpio_count == 2 || ts->gpio_count == 3) && ts->gpio_int_idx == 0) {
                ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
                gpio_mapping = acpi_goodix_int_first_gpios;
        } else if (ts->gpio_count == 2 && ts->gpio_int_idx == 1) {
index 68e648b55767060204a8f42d1927c09ebacad39a..d14413916f93a01626e850aa72ee0c919c1f72bd 100644 (file)
@@ -1799,7 +1799,7 @@ iommu_group_alloc_default_domain(struct iommu_group *group, int req_type)
         * domain. Do not use in new drivers.
         */
        if (ops->default_domain) {
-               if (req_type)
+               if (req_type != ops->default_domain->type)
                        return ERR_PTR(-EINVAL);
                return ops->default_domain;
        }
@@ -1871,10 +1871,18 @@ static int iommu_get_def_domain_type(struct iommu_group *group,
        const struct iommu_ops *ops = dev_iommu_ops(dev);
        int type;
 
-       if (!ops->def_domain_type)
-               return cur_type;
-
-       type = ops->def_domain_type(dev);
+       if (ops->default_domain) {
+               /*
+                * Drivers that declare a global static default_domain will
+                * always choose that.
+                */
+               type = ops->default_domain->type;
+       } else {
+               if (ops->def_domain_type)
+                       type = ops->def_domain_type(dev);
+               else
+                       return cur_type;
+       }
        if (!type || cur_type == type)
                return cur_type;
        if (!cur_type)
index 095b9b49aa8250a1f56c531883cce5f6e8a24727..e6757a30dccad1fa1a6ae060b33d41a6a120dda3 100644 (file)
@@ -22,6 +22,8 @@
 #include "dm-ima.h"
 
 #define DM_RESERVED_MAX_IOS            1024
+#define DM_MAX_TARGETS                 1048576
+#define DM_MAX_TARGET_PARAMS           1024
 
 struct dm_io;
 
index 855b482cbff1f072912e957e8c1cc1d3b4e1b319..f745f85082434dca8fb6d6bf9efe30db79b2a81e 100644 (file)
@@ -73,10 +73,8 @@ struct dm_crypt_io {
        struct bio *base_bio;
        u8 *integrity_metadata;
        bool integrity_metadata_from_pool:1;
-       bool in_tasklet:1;
 
        struct work_struct work;
-       struct tasklet_struct tasklet;
 
        struct convert_context ctx;
 
@@ -1762,7 +1760,6 @@ static void crypt_io_init(struct dm_crypt_io *io, struct crypt_config *cc,
        io->ctx.r.req = NULL;
        io->integrity_metadata = NULL;
        io->integrity_metadata_from_pool = false;
-       io->in_tasklet = false;
        atomic_set(&io->io_pending, 0);
 }
 
@@ -1771,13 +1768,6 @@ static void crypt_inc_pending(struct dm_crypt_io *io)
        atomic_inc(&io->io_pending);
 }
 
-static void kcryptd_io_bio_endio(struct work_struct *work)
-{
-       struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
-
-       bio_endio(io->base_bio);
-}
-
 /*
  * One of the bios was finished. Check for completion of
  * the whole request and correctly clean up the buffer.
@@ -1801,20 +1791,6 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
 
        base_bio->bi_status = error;
 
-       /*
-        * If we are running this function from our tasklet,
-        * we can't call bio_endio() here, because it will call
-        * clone_endio() from dm.c, which in turn will
-        * free the current struct dm_crypt_io structure with
-        * our tasklet. In this case we need to delay bio_endio()
-        * execution to after the tasklet is done and dequeued.
-        */
-       if (io->in_tasklet) {
-               INIT_WORK(&io->work, kcryptd_io_bio_endio);
-               queue_work(cc->io_queue, &io->work);
-               return;
-       }
-
        bio_endio(base_bio);
 }
 
@@ -2246,11 +2222,6 @@ static void kcryptd_crypt(struct work_struct *work)
                kcryptd_crypt_write_convert(io);
 }
 
-static void kcryptd_crypt_tasklet(unsigned long work)
-{
-       kcryptd_crypt((struct work_struct *)work);
-}
-
 static void kcryptd_queue_crypt(struct dm_crypt_io *io)
 {
        struct crypt_config *cc = io->cc;
@@ -2262,15 +2233,10 @@ static void kcryptd_queue_crypt(struct dm_crypt_io *io)
                 * irqs_disabled(): the kernel may run some IO completion from the idle thread, but
                 * it is being executed with irqs disabled.
                 */
-               if (in_hardirq() || irqs_disabled()) {
-                       io->in_tasklet = true;
-                       tasklet_init(&io->tasklet, kcryptd_crypt_tasklet, (unsigned long)&io->work);
-                       tasklet_schedule(&io->tasklet);
+               if (!(in_hardirq() || irqs_disabled())) {
+                       kcryptd_crypt(&io->work);
                        return;
                }
-
-               kcryptd_crypt(&io->work);
-               return;
        }
 
        INIT_WORK(&io->work, kcryptd_crypt);
index e65058e0ed06ab73b9d20d26dfbf7aca55829572..3b1ad7127cb846a1b50059921241f2abe63eaf53 100644 (file)
@@ -1941,7 +1941,8 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kern
                           minimum_data_size - sizeof(param_kernel->version)))
                return -EFAULT;
 
-       if (param_kernel->data_size < minimum_data_size) {
+       if (unlikely(param_kernel->data_size < minimum_data_size) ||
+           unlikely(param_kernel->data_size > DM_MAX_TARGETS * DM_MAX_TARGET_PARAMS)) {
                DMERR("Invalid data size in the ioctl structure: %u",
                      param_kernel->data_size);
                return -EINVAL;
index bdc14ec9981414c60e1dee432b97d50e82dbbc88..1e5d988f44da6919da6de094c6744bf1bb2a89be 100644 (file)
@@ -66,6 +66,9 @@ struct dm_stats_last_position {
        unsigned int last_rw;
 };
 
+#define DM_STAT_MAX_ENTRIES            8388608
+#define DM_STAT_MAX_HISTOGRAM_ENTRIES  134217728
+
 /*
  * A typo on the command line could possibly make the kernel run out of memory
  * and crash. To prevent the crash we account all used memory. We fail if we
@@ -285,6 +288,9 @@ static int dm_stats_create(struct dm_stats *stats, sector_t start, sector_t end,
        if (n_entries != (size_t)n_entries || !(size_t)(n_entries + 1))
                return -EOVERFLOW;
 
+       if (n_entries > DM_STAT_MAX_ENTRIES)
+               return -EOVERFLOW;
+
        shared_alloc_size = struct_size(s, stat_shared, n_entries);
        if ((shared_alloc_size - sizeof(struct dm_stat)) / sizeof(struct dm_stat_shared) != n_entries)
                return -EOVERFLOW;
@@ -297,6 +303,9 @@ static int dm_stats_create(struct dm_stats *stats, sector_t start, sector_t end,
        if (histogram_alloc_size / (n_histogram_entries + 1) != (size_t)n_entries * sizeof(unsigned long long))
                return -EOVERFLOW;
 
+       if ((n_histogram_entries + 1) * (size_t)n_entries > DM_STAT_MAX_HISTOGRAM_ENTRIES)
+               return -EOVERFLOW;
+
        if (!check_shared_memory(shared_alloc_size + histogram_alloc_size +
                                 num_possible_cpus() * (percpu_alloc_size + histogram_alloc_size)))
                return -ENOMEM;
index 260b5b8f2b0d7e9352ed9ed9376a91504ee10c9d..41f1d731ae5ac275d90fbc334666438187da02b4 100644 (file)
@@ -129,7 +129,12 @@ static int alloc_targets(struct dm_table *t, unsigned int num)
 int dm_table_create(struct dm_table **result, blk_mode_t mode,
                    unsigned int num_targets, struct mapped_device *md)
 {
-       struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL);
+       struct dm_table *t;
+
+       if (num_targets > DM_MAX_TARGETS)
+               return -EOVERFLOW;
+
+       t = kzalloc(sizeof(*t), GFP_KERNEL);
 
        if (!t)
                return -ENOMEM;
@@ -144,7 +149,7 @@ int dm_table_create(struct dm_table **result, blk_mode_t mode,
 
        if (!num_targets) {
                kfree(t);
-               return -ENOMEM;
+               return -EOVERFLOW;
        }
 
        if (alloc_targets(t, num_targets)) {
index 14e58ae705218f71923b99bdfc1d195e6a45e658..82662f5769c4af7f5456fc97e044c63574162060 100644 (file)
@@ -645,23 +645,6 @@ static void verity_work(struct work_struct *w)
        verity_finish_io(io, errno_to_blk_status(verity_verify_io(io)));
 }
 
-static void verity_tasklet(unsigned long data)
-{
-       struct dm_verity_io *io = (struct dm_verity_io *)data;
-       int err;
-
-       io->in_tasklet = true;
-       err = verity_verify_io(io);
-       if (err == -EAGAIN || err == -ENOMEM) {
-               /* fallback to retrying with work-queue */
-               INIT_WORK(&io->work, verity_work);
-               queue_work(io->v->verify_wq, &io->work);
-               return;
-       }
-
-       verity_finish_io(io, errno_to_blk_status(err));
-}
-
 static void verity_end_io(struct bio *bio)
 {
        struct dm_verity_io *io = bio->bi_private;
@@ -674,13 +657,8 @@ static void verity_end_io(struct bio *bio)
                return;
        }
 
-       if (static_branch_unlikely(&use_tasklet_enabled) && io->v->use_tasklet) {
-               tasklet_init(&io->tasklet, verity_tasklet, (unsigned long)io);
-               tasklet_schedule(&io->tasklet);
-       } else {
-               INIT_WORK(&io->work, verity_work);
-               queue_work(io->v->verify_wq, &io->work);
-       }
+       INIT_WORK(&io->work, verity_work);
+       queue_work(io->v->verify_wq, &io->work);
 }
 
 /*
index f9d522c870e61665d87271f66c690138db42108f..f3f6070084196825f21dcc17947f67974a90cbde 100644 (file)
@@ -83,7 +83,6 @@ struct dm_verity_io {
        struct bvec_iter iter;
 
        struct work_struct work;
-       struct tasklet_struct tasklet;
 
        /*
         * Three variably-size fields follow this struct:
index 074cb785eafc19172b9ebf4b6a6f2ae4591563d6..b463c28c39ad34ca23b3d2433811384901171d80 100644 (file)
@@ -299,7 +299,7 @@ static int persistent_memory_claim(struct dm_writecache *wc)
                long i;
 
                wc->memory_map = NULL;
-               pages = kvmalloc_array(p, sizeof(struct page *), GFP_KERNEL);
+               pages = vmalloc_array(p, sizeof(struct page *));
                if (!pages) {
                        r = -ENOMEM;
                        goto err2;
@@ -330,7 +330,7 @@ static int persistent_memory_claim(struct dm_writecache *wc)
                        r = -ENOMEM;
                        goto err3;
                }
-               kvfree(pages);
+               vfree(pages);
                wc->memory_vmapped = true;
        }
 
@@ -341,7 +341,7 @@ static int persistent_memory_claim(struct dm_writecache *wc)
 
        return 0;
 err3:
-       kvfree(pages);
+       vfree(pages);
 err2:
        dax_read_unlock(id);
 err1:
@@ -962,7 +962,7 @@ static int writecache_alloc_entries(struct dm_writecache *wc)
 
        if (wc->entries)
                return 0;
-       wc->entries = vmalloc(array_size(sizeof(struct wc_entry), wc->n_blocks));
+       wc->entries = vmalloc_array(wc->n_blocks, sizeof(struct wc_entry));
        if (!wc->entries)
                return -ENOMEM;
        for (b = 0; b < wc->n_blocks; b++) {
index 24f0d799fd98ed318f2f1d2fc7b682d5ebf77e4c..286f8b16c7bde7fbc0bca0705d470748d9f5eeb5 100644 (file)
@@ -2262,7 +2262,7 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
        int sectors = r1_bio->sectors;
        int read_disk = r1_bio->read_disk;
        struct mddev *mddev = conf->mddev;
-       struct md_rdev *rdev = rcu_dereference(conf->mirrors[read_disk].rdev);
+       struct md_rdev *rdev = conf->mirrors[read_disk].rdev;
 
        if (exceed_read_errors(mddev, rdev)) {
                r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
index 41a832dd1426bae695dc90b385976b2bf4b7a304..b6bf8f232f4880ffcd1f7ff0bd00ddb0bbebccb9 100644 (file)
@@ -989,7 +989,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
        bool no_previous_buffers = !q_num_bufs;
        int ret = 0;
 
-       if (q->num_buffers == q->max_num_buffers) {
+       if (q_num_bufs == q->max_num_buffers) {
                dprintk(q, 1, "maximum number of buffers already allocated\n");
                return -ENOBUFS;
        }
index 54d572c3b515d67722c4dbe7490437bc83c30b96..c575198e83547ab99719eca7e81dc6e7c0e601d4 100644 (file)
@@ -671,8 +671,20 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
 }
 EXPORT_SYMBOL(vb2_querybuf);
 
-static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
+static void vb2_set_flags_and_caps(struct vb2_queue *q, u32 memory,
+                                  u32 *flags, u32 *caps, u32 *max_num_bufs)
 {
+       if (!q->allow_cache_hints || memory != V4L2_MEMORY_MMAP) {
+               /*
+                * This needs to clear V4L2_MEMORY_FLAG_NON_COHERENT only,
+                * but in order to avoid bugs we zero out all bits.
+                */
+               *flags = 0;
+       } else {
+               /* Clear all unknown flags. */
+               *flags &= V4L2_MEMORY_FLAG_NON_COHERENT;
+       }
+
        *caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;
        if (q->io_modes & VB2_MMAP)
                *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
@@ -686,21 +698,9 @@ static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
                *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS;
        if (q->supports_requests)
                *caps |= V4L2_BUF_CAP_SUPPORTS_REQUESTS;
-}
-
-static void validate_memory_flags(struct vb2_queue *q,
-                                 int memory,
-                                 u32 *flags)
-{
-       if (!q->allow_cache_hints || memory != V4L2_MEMORY_MMAP) {
-               /*
-                * This needs to clear V4L2_MEMORY_FLAG_NON_COHERENT only,
-                * but in order to avoid bugs we zero out all bits.
-                */
-               *flags = 0;
-       } else {
-               /* Clear all unknown flags. */
-               *flags &= V4L2_MEMORY_FLAG_NON_COHERENT;
+       if (max_num_bufs) {
+               *max_num_bufs = q->max_num_buffers;
+               *caps |= V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS;
        }
 }
 
@@ -709,8 +709,8 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
        int ret = vb2_verify_memory_type(q, req->memory, req->type);
        u32 flags = req->flags;
 
-       fill_buf_caps(q, &req->capabilities);
-       validate_memory_flags(q, req->memory, &flags);
+       vb2_set_flags_and_caps(q, req->memory, &flags,
+                              &req->capabilities, NULL);
        req->flags = flags;
        return ret ? ret : vb2_core_reqbufs(q, req->memory,
                                            req->flags, &req->count);
@@ -751,11 +751,9 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
        int ret = vb2_verify_memory_type(q, create->memory, f->type);
        unsigned i;
 
-       fill_buf_caps(q, &create->capabilities);
-       validate_memory_flags(q, create->memory, &create->flags);
        create->index = vb2_get_num_buffers(q);
-       create->max_num_buffers = q->max_num_buffers;
-       create->capabilities |= V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS;
+       vb2_set_flags_and_caps(q, create->memory, &create->flags,
+                              &create->capabilities, &create->max_num_buffers);
        if (create->count == 0)
                return ret != -EBUSY ? ret : 0;
 
@@ -1006,8 +1004,8 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv,
        int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type);
        u32 flags = p->flags;
 
-       fill_buf_caps(vdev->queue, &p->capabilities);
-       validate_memory_flags(vdev->queue, p->memory, &flags);
+       vb2_set_flags_and_caps(vdev->queue, p->memory, &flags,
+                              &p->capabilities, NULL);
        p->flags = flags;
        if (res)
                return res;
@@ -1026,12 +1024,11 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv,
                          struct v4l2_create_buffers *p)
 {
        struct video_device *vdev = video_devdata(file);
-       int res = vb2_verify_memory_type(vdev->queue, p->memory,
-                       p->format.type);
+       int res = vb2_verify_memory_type(vdev->queue, p->memory, p->format.type);
 
-       p->index = vdev->queue->num_buffers;
-       fill_buf_caps(vdev->queue, &p->capabilities);
-       validate_memory_flags(vdev->queue, p->memory, &p->flags);
+       p->index = vb2_get_num_buffers(vdev->queue);
+       vb2_set_flags_and_caps(vdev->queue, p->memory, &p->flags,
+                              &p->capabilities, &p->max_num_buffers);
        /*
         * If count == 0, then just check if memory and type are valid.
         * Any -EBUSY result from vb2_verify_memory_type can be mapped to 0.
index bfe4caa79cc9800f7b01839fbbb768c73010a72e..0d90b5820bef7286694129ec0c4ed4f436d399b2 100644 (file)
@@ -272,7 +272,7 @@ static const struct wave5_match_data ti_wave521c_data = {
 };
 
 static const struct of_device_id wave5_dt_ids[] = {
-       { .compatible = "ti,k3-j721s2-wave521c", .data = &ti_wave521c_data },
+       { .compatible = "ti,j721s2-wave521c", .data = &ti_wave521c_data },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, wave5_dt_ids);
index 391c4dbdff4283d0b077608a59e4c95758eb24cf..3c1f657593a8f364e5db9500d06257f34373af8a 100644 (file)
@@ -2838,8 +2838,7 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
        /* MT753x MAC works in 1G full duplex mode for all up-clocked
         * variants.
         */
-       if (interface == PHY_INTERFACE_MODE_INTERNAL ||
-           interface == PHY_INTERFACE_MODE_TRGMII ||
+       if (interface == PHY_INTERFACE_MODE_TRGMII ||
            (phy_interface_mode_is_8023z(interface))) {
                speed = SPEED_1000;
                duplex = DUPLEX_FULL;
index 383b3c4d6f599c57358d8970c9c26941231e9898..614cabb5c1b039d8d6df6789589455fe00f09e70 100644 (file)
@@ -3659,7 +3659,7 @@ static int mv88e6xxx_mdio_read_c45(struct mii_bus *bus, int phy, int devad,
        int err;
 
        if (!chip->info->ops->phy_read_c45)
-               return -EOPNOTSUPP;
+               return 0xffff;
 
        mv88e6xxx_reg_lock(chip);
        err = chip->info->ops->phy_read_c45(chip, bus, phy, devad, reg, &val);
index c51f40960961f2b10a2f4191e4b8f5a50af9fc86..7a864329cb7267a9431a181a183c94b6f791f91e 100644 (file)
@@ -2051,12 +2051,11 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
        priv->info = of_device_get_match_data(priv->dev);
 
        priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset",
-                                                  GPIOD_ASIS);
+                                                  GPIOD_OUT_HIGH);
        if (IS_ERR(priv->reset_gpio))
                return PTR_ERR(priv->reset_gpio);
 
        if (priv->reset_gpio) {
-               gpiod_set_value_cansleep(priv->reset_gpio, 1);
                /* The active low duration must be greater than 10 ms
                 * and checkpatch.pl wants 20 ms.
                 */
index 5beadabc213618314ad42da120da259415eaa7b3..ea773cfa0af67bd06d86037bc8208b4111b3bbc5 100644 (file)
@@ -63,6 +63,15 @@ static int pdsc_process_notifyq(struct pdsc_qcq *qcq)
        return nq_work;
 }
 
+static bool pdsc_adminq_inc_if_up(struct pdsc *pdsc)
+{
+       if (pdsc->state & BIT_ULL(PDSC_S_STOPPING_DRIVER) ||
+           pdsc->state & BIT_ULL(PDSC_S_FW_DEAD))
+               return false;
+
+       return refcount_inc_not_zero(&pdsc->adminq_refcnt);
+}
+
 void pdsc_process_adminq(struct pdsc_qcq *qcq)
 {
        union pds_core_adminq_comp *comp;
@@ -75,9 +84,9 @@ void pdsc_process_adminq(struct pdsc_qcq *qcq)
        int aq_work = 0;
        int credits;
 
-       /* Don't process AdminQ when shutting down */
-       if (pdsc->state & BIT_ULL(PDSC_S_STOPPING_DRIVER)) {
-               dev_err(pdsc->dev, "%s: called while PDSC_S_STOPPING_DRIVER\n",
+       /* Don't process AdminQ when it's not up */
+       if (!pdsc_adminq_inc_if_up(pdsc)) {
+               dev_err(pdsc->dev, "%s: called while adminq is unavailable\n",
                        __func__);
                return;
        }
@@ -124,6 +133,7 @@ credits:
                pds_core_intr_credits(&pdsc->intr_ctrl[qcq->intx],
                                      credits,
                                      PDS_CORE_INTR_CRED_REARM);
+       refcount_dec(&pdsc->adminq_refcnt);
 }
 
 void pdsc_work_thread(struct work_struct *work)
@@ -135,18 +145,20 @@ void pdsc_work_thread(struct work_struct *work)
 
 irqreturn_t pdsc_adminq_isr(int irq, void *data)
 {
-       struct pdsc_qcq *qcq = data;
-       struct pdsc *pdsc = qcq->pdsc;
+       struct pdsc *pdsc = data;
+       struct pdsc_qcq *qcq;
 
-       /* Don't process AdminQ when shutting down */
-       if (pdsc->state & BIT_ULL(PDSC_S_STOPPING_DRIVER)) {
-               dev_err(pdsc->dev, "%s: called while PDSC_S_STOPPING_DRIVER\n",
+       /* Don't process AdminQ when it's not up */
+       if (!pdsc_adminq_inc_if_up(pdsc)) {
+               dev_err(pdsc->dev, "%s: called while adminq is unavailable\n",
                        __func__);
                return IRQ_HANDLED;
        }
 
+       qcq = &pdsc->adminqcq;
        queue_work(pdsc->wq, &qcq->work);
        pds_core_intr_mask(&pdsc->intr_ctrl[qcq->intx], PDS_CORE_INTR_MASK_CLEAR);
+       refcount_dec(&pdsc->adminq_refcnt);
 
        return IRQ_HANDLED;
 }
@@ -179,10 +191,16 @@ static int __pdsc_adminq_post(struct pdsc *pdsc,
 
        /* Check that the FW is running */
        if (!pdsc_is_fw_running(pdsc)) {
-               u8 fw_status = ioread8(&pdsc->info_regs->fw_status);
-
-               dev_info(pdsc->dev, "%s: post failed - fw not running %#02x:\n",
-                        __func__, fw_status);
+               if (pdsc->info_regs) {
+                       u8 fw_status =
+                               ioread8(&pdsc->info_regs->fw_status);
+
+                       dev_info(pdsc->dev, "%s: post failed - fw not running %#02x:\n",
+                                __func__, fw_status);
+               } else {
+                       dev_info(pdsc->dev, "%s: post failed - BARs not setup\n",
+                                __func__);
+               }
                ret = -ENXIO;
 
                goto err_out_unlock;
@@ -230,6 +248,12 @@ int pdsc_adminq_post(struct pdsc *pdsc,
        int err = 0;
        int index;
 
+       if (!pdsc_adminq_inc_if_up(pdsc)) {
+               dev_dbg(pdsc->dev, "%s: preventing adminq cmd %u\n",
+                       __func__, cmd->opcode);
+               return -ENXIO;
+       }
+
        wc.qcq = &pdsc->adminqcq;
        index = __pdsc_adminq_post(pdsc, &pdsc->adminqcq, cmd, comp, &wc);
        if (index < 0) {
@@ -248,10 +272,16 @@ int pdsc_adminq_post(struct pdsc *pdsc,
                        break;
 
                if (!pdsc_is_fw_running(pdsc)) {
-                       u8 fw_status = ioread8(&pdsc->info_regs->fw_status);
-
-                       dev_dbg(pdsc->dev, "%s: post wait failed - fw not running %#02x:\n",
-                               __func__, fw_status);
+                       if (pdsc->info_regs) {
+                               u8 fw_status =
+                                       ioread8(&pdsc->info_regs->fw_status);
+
+                               dev_dbg(pdsc->dev, "%s: post wait failed - fw not running %#02x:\n",
+                                       __func__, fw_status);
+                       } else {
+                               dev_dbg(pdsc->dev, "%s: post wait failed - BARs not setup\n",
+                                       __func__);
+                       }
                        err = -ENXIO;
                        break;
                }
@@ -285,6 +315,8 @@ err_out:
                        queue_work(pdsc->wq, &pdsc->health_work);
        }
 
+       refcount_dec(&pdsc->adminq_refcnt);
+
        return err;
 }
 EXPORT_SYMBOL_GPL(pdsc_adminq_post);
index 0d2091e9eb283a375617828c00552cceb82768ca..7658a72867675aad5287c15989155386d3ab9de7 100644 (file)
@@ -125,7 +125,7 @@ static int pdsc_qcq_intr_alloc(struct pdsc *pdsc, struct pdsc_qcq *qcq)
 
        snprintf(name, sizeof(name), "%s-%d-%s",
                 PDS_CORE_DRV_NAME, pdsc->pdev->bus->number, qcq->q.name);
-       index = pdsc_intr_alloc(pdsc, name, pdsc_adminq_isr, qcq);
+       index = pdsc_intr_alloc(pdsc, name, pdsc_adminq_isr, pdsc);
        if (index < 0)
                return index;
        qcq->intx = index;
@@ -404,10 +404,7 @@ int pdsc_setup(struct pdsc *pdsc, bool init)
        int numdescs;
        int err;
 
-       if (init)
-               err = pdsc_dev_init(pdsc);
-       else
-               err = pdsc_dev_reinit(pdsc);
+       err = pdsc_dev_init(pdsc);
        if (err)
                return err;
 
@@ -450,6 +447,7 @@ int pdsc_setup(struct pdsc *pdsc, bool init)
                pdsc_debugfs_add_viftype(pdsc);
        }
 
+       refcount_set(&pdsc->adminq_refcnt, 1);
        clear_bit(PDSC_S_FW_DEAD, &pdsc->state);
        return 0;
 
@@ -464,6 +462,8 @@ void pdsc_teardown(struct pdsc *pdsc, bool removing)
 
        if (!pdsc->pdev->is_virtfn)
                pdsc_devcmd_reset(pdsc);
+       if (pdsc->adminqcq.work.func)
+               cancel_work_sync(&pdsc->adminqcq.work);
        pdsc_qcq_free(pdsc, &pdsc->notifyqcq);
        pdsc_qcq_free(pdsc, &pdsc->adminqcq);
 
@@ -476,10 +476,9 @@ void pdsc_teardown(struct pdsc *pdsc, bool removing)
                for (i = 0; i < pdsc->nintrs; i++)
                        pdsc_intr_free(pdsc, i);
 
-               if (removing) {
-                       kfree(pdsc->intr_info);
-                       pdsc->intr_info = NULL;
-               }
+               kfree(pdsc->intr_info);
+               pdsc->intr_info = NULL;
+               pdsc->nintrs = 0;
        }
 
        if (pdsc->kern_dbpage) {
@@ -487,6 +486,7 @@ void pdsc_teardown(struct pdsc *pdsc, bool removing)
                pdsc->kern_dbpage = NULL;
        }
 
+       pci_free_irq_vectors(pdsc->pdev);
        set_bit(PDSC_S_FW_DEAD, &pdsc->state);
 }
 
@@ -512,6 +512,24 @@ void pdsc_stop(struct pdsc *pdsc)
                                           PDS_CORE_INTR_MASK_SET);
 }
 
+static void pdsc_adminq_wait_and_dec_once_unused(struct pdsc *pdsc)
+{
+       /* The driver initializes the adminq_refcnt to 1 when the adminq is
+        * allocated and ready for use. Other users/requesters will increment
+        * the refcnt while in use. If the refcnt is down to 1 then the adminq
+        * is not in use and the refcnt can be cleared and adminq freed. Before
+        * calling this function the driver will set PDSC_S_FW_DEAD, which
+        * prevent subsequent attempts to use the adminq and increment the
+        * refcnt to fail. This guarantees that this function will eventually
+        * exit.
+        */
+       while (!refcount_dec_if_one(&pdsc->adminq_refcnt)) {
+               dev_dbg_ratelimited(pdsc->dev, "%s: adminq in use\n",
+                                   __func__);
+               cpu_relax();
+       }
+}
+
 void pdsc_fw_down(struct pdsc *pdsc)
 {
        union pds_core_notifyq_comp reset_event = {
@@ -527,6 +545,8 @@ void pdsc_fw_down(struct pdsc *pdsc)
        if (pdsc->pdev->is_virtfn)
                return;
 
+       pdsc_adminq_wait_and_dec_once_unused(pdsc);
+
        /* Notify clients of fw_down */
        if (pdsc->fw_reporter)
                devlink_health_report(pdsc->fw_reporter, "FW down reported", pdsc);
@@ -577,7 +597,13 @@ err_out:
 
 static void pdsc_check_pci_health(struct pdsc *pdsc)
 {
-       u8 fw_status = ioread8(&pdsc->info_regs->fw_status);
+       u8 fw_status;
+
+       /* some sort of teardown already in progress */
+       if (!pdsc->info_regs)
+               return;
+
+       fw_status = ioread8(&pdsc->info_regs->fw_status);
 
        /* is PCI broken? */
        if (fw_status != PDS_RC_BAD_PCI)
index e35d3e7006bfc1891a0343643910b915f31ba56a..110c4b826b22d588b33ca5cd2f0f1d38c76cf4b5 100644 (file)
@@ -184,6 +184,7 @@ struct pdsc {
        struct mutex devcmd_lock;       /* lock for dev_cmd operations */
        struct mutex config_lock;       /* lock for configuration operations */
        spinlock_t adminq_lock;         /* lock for adminq operations */
+       refcount_t adminq_refcnt;
        struct pds_core_dev_info_regs __iomem *info_regs;
        struct pds_core_dev_cmd_regs __iomem *cmd_regs;
        struct pds_core_intr __iomem *intr_ctrl;
@@ -280,7 +281,6 @@ int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd,
                       union pds_core_dev_comp *comp, int max_seconds);
 int pdsc_devcmd_init(struct pdsc *pdsc);
 int pdsc_devcmd_reset(struct pdsc *pdsc);
-int pdsc_dev_reinit(struct pdsc *pdsc);
 int pdsc_dev_init(struct pdsc *pdsc);
 
 void pdsc_reset_prepare(struct pci_dev *pdev);
index 8ec392299b7dcff9b74a0b08f45a5ccd25986cf1..4e8579ca1c8c71bd89659f041f3613113af16141 100644 (file)
@@ -64,6 +64,10 @@ DEFINE_SHOW_ATTRIBUTE(identity);
 
 void pdsc_debugfs_add_ident(struct pdsc *pdsc)
 {
+       /* This file will already exist in the reset flow */
+       if (debugfs_lookup("identity", pdsc->dentry))
+               return;
+
        debugfs_create_file("identity", 0400, pdsc->dentry,
                            pdsc, &identity_fops);
 }
index 31940b857e0e501d2d4d220a0ed6a0cfd03098c7..e65a1632df505d55de687ba781166299d865eaae 100644 (file)
@@ -57,6 +57,9 @@ int pdsc_err_to_errno(enum pds_core_status_code code)
 
 bool pdsc_is_fw_running(struct pdsc *pdsc)
 {
+       if (!pdsc->info_regs)
+               return false;
+
        pdsc->fw_status = ioread8(&pdsc->info_regs->fw_status);
        pdsc->last_fw_time = jiffies;
        pdsc->last_hb = ioread32(&pdsc->info_regs->fw_heartbeat);
@@ -182,13 +185,17 @@ int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd,
 {
        int err;
 
+       if (!pdsc->cmd_regs)
+               return -ENXIO;
+
        memcpy_toio(&pdsc->cmd_regs->cmd, cmd, sizeof(*cmd));
        pdsc_devcmd_dbell(pdsc);
        err = pdsc_devcmd_wait(pdsc, cmd->opcode, max_seconds);
-       memcpy_fromio(comp, &pdsc->cmd_regs->comp, sizeof(*comp));
 
        if ((err == -ENXIO || err == -ETIMEDOUT) && pdsc->wq)
                queue_work(pdsc->wq, &pdsc->health_work);
+       else
+               memcpy_fromio(comp, &pdsc->cmd_regs->comp, sizeof(*comp));
 
        return err;
 }
@@ -309,13 +316,6 @@ static int pdsc_identify(struct pdsc *pdsc)
        return 0;
 }
 
-int pdsc_dev_reinit(struct pdsc *pdsc)
-{
-       pdsc_init_devinfo(pdsc);
-
-       return pdsc_identify(pdsc);
-}
-
 int pdsc_dev_init(struct pdsc *pdsc)
 {
        unsigned int nintrs;
index e9948ea5bbcdbaae713390cca46280e55b548956..54864f27c87a9e526524a023e444e318cc2bc0f7 100644 (file)
@@ -111,7 +111,8 @@ int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
 
        mutex_lock(&pdsc->devcmd_lock);
        err = pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout * 2);
-       memcpy_fromio(&fw_list, pdsc->cmd_regs->data, sizeof(fw_list));
+       if (!err)
+               memcpy_fromio(&fw_list, pdsc->cmd_regs->data, sizeof(fw_list));
        mutex_unlock(&pdsc->devcmd_lock);
        if (err && err != -EIO)
                return err;
index 90a811f3878ae974679bc5caba97e18aae04bdfb..fa626719e68d1b206fc9bbe1d038daf51984f19b 100644 (file)
@@ -107,6 +107,9 @@ int pdsc_firmware_update(struct pdsc *pdsc, const struct firmware *fw,
 
        dev_info(pdsc->dev, "Installing firmware\n");
 
+       if (!pdsc->cmd_regs)
+               return -ENXIO;
+
        dl = priv_to_devlink(pdsc);
        devlink_flash_update_status_notify(dl, "Preparing to flash",
                                           NULL, 0, 0);
index 3080898d7b95b0122701cacb8a15796ed2cc2dcb..cdbf053b5376c51c91deadb0d9ce6ab752b90745 100644 (file)
@@ -37,6 +37,11 @@ static void pdsc_unmap_bars(struct pdsc *pdsc)
        struct pdsc_dev_bar *bars = pdsc->bars;
        unsigned int i;
 
+       pdsc->info_regs = NULL;
+       pdsc->cmd_regs = NULL;
+       pdsc->intr_status = NULL;
+       pdsc->intr_ctrl = NULL;
+
        for (i = 0; i < PDS_CORE_BARS_MAX; i++) {
                if (bars[i].vaddr)
                        pci_iounmap(pdsc->pdev, bars[i].vaddr);
@@ -293,7 +298,7 @@ err_out_stop:
 err_out_teardown:
        pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING);
 err_out_unmap_bars:
-       del_timer_sync(&pdsc->wdtimer);
+       timer_shutdown_sync(&pdsc->wdtimer);
        if (pdsc->wq)
                destroy_workqueue(pdsc->wq);
        mutex_destroy(&pdsc->config_lock);
@@ -420,7 +425,7 @@ static void pdsc_remove(struct pci_dev *pdev)
                 */
                pdsc_sriov_configure(pdev, 0);
 
-               del_timer_sync(&pdsc->wdtimer);
+               timer_shutdown_sync(&pdsc->wdtimer);
                if (pdsc->wq)
                        destroy_workqueue(pdsc->wq);
 
@@ -433,7 +438,6 @@ static void pdsc_remove(struct pci_dev *pdev)
                mutex_destroy(&pdsc->config_lock);
                mutex_destroy(&pdsc->devcmd_lock);
 
-               pci_free_irq_vectors(pdev);
                pdsc_unmap_bars(pdsc);
                pci_release_regions(pdev);
        }
@@ -445,13 +449,26 @@ static void pdsc_remove(struct pci_dev *pdev)
        devlink_free(dl);
 }
 
+static void pdsc_stop_health_thread(struct pdsc *pdsc)
+{
+       timer_shutdown_sync(&pdsc->wdtimer);
+       if (pdsc->health_work.func)
+               cancel_work_sync(&pdsc->health_work);
+}
+
+static void pdsc_restart_health_thread(struct pdsc *pdsc)
+{
+       timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0);
+       mod_timer(&pdsc->wdtimer, jiffies + 1);
+}
+
 void pdsc_reset_prepare(struct pci_dev *pdev)
 {
        struct pdsc *pdsc = pci_get_drvdata(pdev);
 
+       pdsc_stop_health_thread(pdsc);
        pdsc_fw_down(pdsc);
 
-       pci_free_irq_vectors(pdev);
        pdsc_unmap_bars(pdsc);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
@@ -486,6 +503,7 @@ void pdsc_reset_done(struct pci_dev *pdev)
        }
 
        pdsc_fw_up(pdsc);
+       pdsc_restart_health_thread(pdsc);
 }
 
 static const struct pci_error_handlers pdsc_err_handler = {
index adad188e38b8256ef5a1e051310abae2d5bd9b34..cc07660330f533b5e39efcb0f5dff6f865821315 100644 (file)
@@ -684,7 +684,7 @@ static void bnxt_stamp_tx_skb(struct bnxt *bp, struct sk_buff *skb)
                timestamp.hwtstamp = ns_to_ktime(ns);
                skb_tstamp_tx(ptp->tx_skb, &timestamp);
        } else {
-               netdev_WARN_ONCE(bp->dev,
+               netdev_warn_once(bp->dev,
                                 "TS query for TX timer failed rc = %x\n", rc);
        }
 
index 7a8dc5386ffff9bd99d94eced337cf276551a88f..76615d47e055aebc9fcea0d365b28b4389337c07 100644 (file)
@@ -356,7 +356,7 @@ static enum pkt_hash_types gve_rss_type(__be16 pkt_flags)
 
 static struct sk_buff *gve_rx_add_frags(struct napi_struct *napi,
                                        struct gve_rx_slot_page_info *page_info,
-                                       u16 packet_buffer_size, u16 len,
+                                       unsigned int truesize, u16 len,
                                        struct gve_rx_ctx *ctx)
 {
        u32 offset = page_info->page_offset + page_info->pad;
@@ -389,10 +389,10 @@ static struct sk_buff *gve_rx_add_frags(struct napi_struct *napi,
        if (skb != ctx->skb_head) {
                ctx->skb_head->len += len;
                ctx->skb_head->data_len += len;
-               ctx->skb_head->truesize += packet_buffer_size;
+               ctx->skb_head->truesize += truesize;
        }
        skb_add_rx_frag(skb, num_frags, page_info->page,
-                       offset, len, packet_buffer_size);
+                       offset, len, truesize);
 
        return ctx->skb_head;
 }
@@ -486,7 +486,7 @@ static struct sk_buff *gve_rx_copy_to_pool(struct gve_rx_ring *rx,
 
                memcpy(alloc_page_info.page_address, src, page_info->pad + len);
                skb = gve_rx_add_frags(napi, &alloc_page_info,
-                                      rx->packet_buffer_size,
+                                      PAGE_SIZE,
                                       len, ctx);
 
                u64_stats_update_begin(&rx->statss);
index a187582d22994c607915f1fe26f5374031444976..ba9c19e6994c9defdf06eada37091e09d10881fa 100644 (file)
@@ -360,23 +360,43 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca);
  * As a result, a shift of INCVALUE_SHIFT_n is used to fit a value of
  * INCVALUE_n into the TIMINCA register allowing 32+8+(24-INCVALUE_SHIFT_n)
  * bits to count nanoseconds leaving the rest for fractional nonseconds.
+ *
+ * Any given INCVALUE also has an associated maximum adjustment value. This
+ * maximum adjustment value is the largest increase (or decrease) which can be
+ * safely applied without overflowing the INCVALUE. Since INCVALUE has
+ * a maximum range of 24 bits, its largest value is 0xFFFFFF.
+ *
+ * To understand where the maximum value comes from, consider the following
+ * equation:
+ *
+ *   new_incval = base_incval + (base_incval * adjustment) / 1billion
+ *
+ * To avoid overflow that means:
+ *   max_incval = base_incval + (base_incval * max_adj) / billion
+ *
+ * Re-arranging:
+ *   max_adj = floor(((max_incval - base_incval) * 1billion) / 1billion)
  */
 #define INCVALUE_96MHZ         125
 #define INCVALUE_SHIFT_96MHZ   17
 #define INCPERIOD_SHIFT_96MHZ  2
 #define INCPERIOD_96MHZ                (12 >> INCPERIOD_SHIFT_96MHZ)
+#define MAX_PPB_96MHZ          23999900 /* 23,999,900 ppb */
 
 #define INCVALUE_25MHZ         40
 #define INCVALUE_SHIFT_25MHZ   18
 #define INCPERIOD_25MHZ                1
+#define MAX_PPB_25MHZ          599999900 /* 599,999,900 ppb */
 
 #define INCVALUE_24MHZ         125
 #define INCVALUE_SHIFT_24MHZ   14
 #define INCPERIOD_24MHZ                3
+#define MAX_PPB_24MHZ          999999999 /* 999,999,999 ppb */
 
 #define INCVALUE_38400KHZ      26
 #define INCVALUE_SHIFT_38400KHZ        19
 #define INCPERIOD_38400KHZ     1
+#define MAX_PPB_38400KHZ       230769100 /* 230,769,100 ppb */
 
 /* Another drawback of scaling the incvalue by a large factor is the
  * 64-bit SYSTIM register overflows more quickly.  This is dealt with
index 02d871bc112a739cec1baffba5b63abaf14f4a7d..bbcfd529399b0fa938037858b1e2f7912f8e5a58 100644 (file)
@@ -280,8 +280,17 @@ void e1000e_ptp_init(struct e1000_adapter *adapter)
 
        switch (hw->mac.type) {
        case e1000_pch2lan:
+               adapter->ptp_clock_info.max_adj = MAX_PPB_96MHZ;
+               break;
        case e1000_pch_lpt:
+               if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)
+                       adapter->ptp_clock_info.max_adj = MAX_PPB_96MHZ;
+               else
+                       adapter->ptp_clock_info.max_adj = MAX_PPB_25MHZ;
+               break;
        case e1000_pch_spt:
+               adapter->ptp_clock_info.max_adj = MAX_PPB_24MHZ;
+               break;
        case e1000_pch_cnp:
        case e1000_pch_tgp:
        case e1000_pch_adp:
@@ -289,15 +298,14 @@ void e1000e_ptp_init(struct e1000_adapter *adapter)
        case e1000_pch_lnp:
        case e1000_pch_ptp:
        case e1000_pch_nvp:
-               if ((hw->mac.type < e1000_pch_lpt) ||
-                   (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) {
-                       adapter->ptp_clock_info.max_adj = 24000000 - 1;
-                       break;
-               }
-               fallthrough;
+               if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)
+                       adapter->ptp_clock_info.max_adj = MAX_PPB_24MHZ;
+               else
+                       adapter->ptp_clock_info.max_adj = MAX_PPB_38400KHZ;
+               break;
        case e1000_82574:
        case e1000_82583:
-               adapter->ptp_clock_info.max_adj = 600000000 - 1;
+               adapter->ptp_clock_info.max_adj = MAX_PPB_25MHZ;
                break;
        default:
                break;
index 8dc837889723c8a8976fd537e79e7d6acd49c4a8..4a3c4454d25abad18582ea7b93c74b616ef5cf75 100644 (file)
@@ -978,7 +978,7 @@ struct virtchnl2_ptype {
        u8 proto_id_count;
        __le16 pad;
        __le16 proto_id[];
-};
+} __packed __aligned(2);
 VIRTCHNL2_CHECK_STRUCT_LEN(6, virtchnl2_ptype);
 
 /**
index 6208923e29a2b861363317b983b577b383bbeeb1..c1adc94a5a657a6ac432a52016436479020673f3 100644 (file)
@@ -716,7 +716,8 @@ static s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
        if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
                error = FIELD_GET(IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK, command);
                hw_dbg(hw, "Failed to read, error %x\n", error);
-               return -EIO;
+               ret = -EIO;
+               goto out;
        }
 
        if (!ret)
index 2928898c7f8df89c45092c209f9a3dd25b43ee21..7f786de6101483a775c8aa4f12789631040fdd95 100644 (file)
@@ -314,7 +314,6 @@ static int otx2_set_channels(struct net_device *dev,
        pfvf->hw.tx_queues = channel->tx_count;
        if (pfvf->xdp_prog)
                pfvf->hw.xdp_queues = channel->rx_count;
-       pfvf->hw.non_qos_queues =  pfvf->hw.tx_queues + pfvf->hw.xdp_queues;
 
        if (if_up)
                err = dev->netdev_ops->ndo_open(dev);
index a57455aebff6fc58e24c4a4da2d60d78e59f439f..e5fe67e7386551e321949dc3b42074067eb4b3a9 100644 (file)
@@ -1744,6 +1744,7 @@ int otx2_open(struct net_device *netdev)
        /* RQ and SQs are mapped to different CQs,
         * so find out max CQ IRQs (i.e CINTs) needed.
         */
+       pf->hw.non_qos_queues =  pf->hw.tx_queues + pf->hw.xdp_queues;
        pf->hw.cint_cnt = max3(pf->hw.rx_queues, pf->hw.tx_queues,
                               pf->hw.tc_tx_queues);
 
@@ -2643,8 +2644,6 @@ static int otx2_xdp_setup(struct otx2_nic *pf, struct bpf_prog *prog)
                xdp_features_clear_redirect_target(dev);
        }
 
-       pf->hw.non_qos_queues += pf->hw.xdp_queues;
-
        if (if_up)
                otx2_open(pf->netdev);
 
index 4d519ea833b2c7c4fa439ee56fdd07962221030c..f828d32737af02f6a1492e015a1a3d77a732e732 100644 (file)
@@ -1403,7 +1403,7 @@ static bool otx2_xdp_rcv_pkt_handler(struct otx2_nic *pfvf,
                                     struct otx2_cq_queue *cq,
                                     bool *need_xdp_flush)
 {
-       unsigned char *hard_start, *data;
+       unsigned char *hard_start;
        int qidx = cq->cq_idx;
        struct xdp_buff xdp;
        struct page *page;
@@ -1417,9 +1417,8 @@ static bool otx2_xdp_rcv_pkt_handler(struct otx2_nic *pfvf,
 
        xdp_init_buff(&xdp, pfvf->rbsize, &cq->xdp_rxq);
 
-       data = (unsigned char *)phys_to_virt(pa);
-       hard_start = page_address(page);
-       xdp_prepare_buff(&xdp, hard_start, data - hard_start,
+       hard_start = (unsigned char *)phys_to_virt(pa);
+       xdp_prepare_buff(&xdp, hard_start, OTX2_HEAD_ROOM,
                         cqe->sg.seg_size, false);
 
        act = bpf_prog_run_xdp(prog, &xdp);
index a6e91573f8dae8368f7667f5f5caa5636d881a60..de123350bd46b6e55ee5ea83737f79a4bceb6867 100644 (file)
@@ -4761,7 +4761,10 @@ static int mtk_probe(struct platform_device *pdev)
        }
 
        if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA)) {
-               err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36));
+               err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(36));
+               if (!err)
+                       err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+
                if (err) {
                        dev_err(&pdev->dev, "Wrong DMA config\n");
                        return -EINVAL;
index 92108d354051c31c44c64b207fb11411d0b4295b..2e83bbb9477e0693f236e83be30277d3e92df235 100644 (file)
@@ -168,9 +168,10 @@ static void lan966x_port_link_up(struct lan966x_port *port)
        lan966x_taprio_speed_set(port, config->speed);
 
        /* Also the GIGA_MODE_ENA(1) needs to be set regardless of the
-        * port speed for QSGMII ports.
+        * port speed for QSGMII or SGMII ports.
         */
-       if (phy_interface_num_ports(config->portmode) == 4)
+       if (phy_interface_num_ports(config->portmode) == 4 ||
+           config->portmode == PHY_INTERFACE_MODE_SGMII)
                mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA_SET(1);
 
        lan_wr(config->duplex | mode,
index 2967bab72505617abcf59f0b16f5a1d5bb9d127c..15180538b80a1535a8646b407bcc1b06b632b43c 100644 (file)
@@ -1424,10 +1424,30 @@ static void nfp_nft_ct_translate_mangle_action(struct flow_action_entry *mangle_
                mangle_action->mangle.mask = (__force u32)cpu_to_be32(mangle_action->mangle.mask);
                return;
 
+       /* Both struct tcphdr and struct udphdr start with
+        *      __be16 source;
+        *      __be16 dest;
+        * so we can use the same code for both.
+        */
        case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
        case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
-               mangle_action->mangle.val = (__force u16)cpu_to_be16(mangle_action->mangle.val);
-               mangle_action->mangle.mask = (__force u16)cpu_to_be16(mangle_action->mangle.mask);
+               if (mangle_action->mangle.offset == offsetof(struct tcphdr, source)) {
+                       mangle_action->mangle.val =
+                               (__force u32)cpu_to_be32(mangle_action->mangle.val << 16);
+                       /* The mask of mangle action is inverse mask,
+                        * so clear the dest tp port with 0xFFFF to
+                        * instead of rotate-left operation.
+                        */
+                       mangle_action->mangle.mask =
+                               (__force u32)cpu_to_be32(mangle_action->mangle.mask << 16 | 0xFFFF);
+               }
+               if (mangle_action->mangle.offset == offsetof(struct tcphdr, dest)) {
+                       mangle_action->mangle.offset = 0;
+                       mangle_action->mangle.val =
+                               (__force u32)cpu_to_be32(mangle_action->mangle.val);
+                       mangle_action->mangle.mask =
+                               (__force u32)cpu_to_be32(mangle_action->mangle.mask);
+               }
                return;
 
        default:
@@ -1864,10 +1884,30 @@ int nfp_fl_ct_handle_post_ct(struct nfp_flower_priv *priv,
 {
        struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
        struct nfp_fl_ct_flow_entry *ct_entry;
+       struct flow_action_entry *ct_goto;
        struct nfp_fl_ct_zone_entry *zt;
+       struct flow_action_entry *act;
        bool wildcarded = false;
        struct flow_match_ct ct;
-       struct flow_action_entry *ct_goto;
+       int i;
+
+       flow_action_for_each(i, act, &rule->action) {
+               switch (act->id) {
+               case FLOW_ACTION_REDIRECT:
+               case FLOW_ACTION_REDIRECT_INGRESS:
+               case FLOW_ACTION_MIRRED:
+               case FLOW_ACTION_MIRRED_INGRESS:
+                       if (act->dev->rtnl_link_ops &&
+                           !strcmp(act->dev->rtnl_link_ops->kind, "openvswitch")) {
+                               NL_SET_ERR_MSG_MOD(extack,
+                                                  "unsupported offload: out port is openvswitch internal port");
+                               return -EOPNOTSUPP;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
 
        flow_rule_match_ct(rule, &ct);
        if (!ct.mask->ct_zone) {
index 8f730ada71f91d70b5c1d2707601b927f20aeb79..6b65420e11b5c518251565ca94bfb4a849068436 100644 (file)
@@ -353,6 +353,10 @@ static int imx_dwmac_probe(struct platform_device *pdev)
        if (data->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY)
                plat_dat->flags |= STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY;
 
+       /* Default TX Q0 to use TSO and rest TXQ for TBS */
+       for (int i = 1; i < plat_dat->tx_queues_to_use; i++)
+               plat_dat->tx_queues_cfg[i].tbs_en = 1;
+
        plat_dat->host_dma_width = dwmac->ops->addr_width;
        plat_dat->init = imx_dwmac_init;
        plat_dat->exit = imx_dwmac_exit;
index b334eb16da23aa49af2a0849dc86127a0a69494a..25519952f754ca0e03b39baa0bb6ab06aebd4209 100644 (file)
@@ -3932,6 +3932,9 @@ static int __stmmac_open(struct net_device *dev,
        priv->rx_copybreak = STMMAC_RX_COPYBREAK;
 
        buf_sz = dma_conf->dma_buf_sz;
+       for (int i = 0; i < MTL_MAX_TX_QUEUES; i++)
+               if (priv->dma_conf.tx_queue[i].tbs & STMMAC_TBS_EN)
+                       dma_conf->tx_queue[i].tbs = priv->dma_conf.tx_queue[i].tbs;
        memcpy(&priv->dma_conf, dma_conf, sizeof(*dma_conf));
 
        stmmac_reset_queues_param(priv);
index 1dafa44155d0eb31dfaea9cacdc3954ebee75f4b..a6fcbda64ecc60e5beccf20f2043ab00870cbd5d 100644 (file)
@@ -708,7 +708,10 @@ void netvsc_device_remove(struct hv_device *device)
        /* Disable NAPI and disassociate its context from the device. */
        for (i = 0; i < net_device->num_chn; i++) {
                /* See also vmbus_reset_channel_cb(). */
-               napi_disable(&net_device->chan_table[i].napi);
+               /* only disable enabled NAPI channel */
+               if (i < ndev->real_num_rx_queues)
+                       napi_disable(&net_device->chan_table[i].napi);
+
                netif_napi_del(&net_device->chan_table[i].napi);
        }
 
index 8a20d9889f105bc609f56a2632132e0ef2c08504..0f3a1538a8b8ee045953a3c5ff308dc824ea7c0a 100644 (file)
@@ -489,7 +489,7 @@ static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
        u16 reg, val;
 
        if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
-               bias = -2;
+               bias = -1;
 
        val = clamp_val(bias + tx_r50_cal_val, 0, 63);
 
@@ -705,6 +705,11 @@ restore:
 static void mt798x_phy_common_finetune(struct phy_device *phydev)
 {
        phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+       /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
+       __phy_write(phydev, 0x11, 0xc71);
+       __phy_write(phydev, 0x12, 0xc);
+       __phy_write(phydev, 0x10, 0x8fae);
+
        /* EnabRandUpdTrig = 1 */
        __phy_write(phydev, 0x11, 0x2f00);
        __phy_write(phydev, 0x12, 0xe);
@@ -715,15 +720,56 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev)
        __phy_write(phydev, 0x12, 0x0);
        __phy_write(phydev, 0x10, 0x83aa);
 
-       /* TrFreeze = 0 */
+       /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
+       __phy_write(phydev, 0x11, 0x240);
+       __phy_write(phydev, 0x12, 0x0);
+       __phy_write(phydev, 0x10, 0x9680);
+
+       /* TrFreeze = 0 (mt7988 default) */
        __phy_write(phydev, 0x11, 0x0);
        __phy_write(phydev, 0x12, 0x0);
        __phy_write(phydev, 0x10, 0x9686);
 
+       /* SSTrKp100 = 5 */
+       /* SSTrKf100 = 6 */
+       /* SSTrKp1000Mas = 5 */
+       /* SSTrKf1000Mas = 6 */
        /* SSTrKp1000Slv = 5 */
+       /* SSTrKf1000Slv = 6 */
        __phy_write(phydev, 0x11, 0xbaef);
        __phy_write(phydev, 0x12, 0x2e);
        __phy_write(phydev, 0x10, 0x968c);
+       phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+}
+
+static void mt7981_phy_finetune(struct phy_device *phydev)
+{
+       u16 val[8] = { 0x01ce, 0x01c1,
+                      0x020f, 0x0202,
+                      0x03d0, 0x03c0,
+                      0x0013, 0x0005 };
+       int i, k;
+
+       /* 100M eye finetune:
+        * Keep middle level of TX MLT3 shapper as default.
+        * Only change TX MLT3 overshoot level here.
+        */
+       for (k = 0, i = 1; i < 12; i++) {
+               if (i % 3 == 0)
+                       continue;
+               phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
+       }
+
+       phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+       /* ResetSyncOffset = 6 */
+       __phy_write(phydev, 0x11, 0x600);
+       __phy_write(phydev, 0x12, 0x0);
+       __phy_write(phydev, 0x10, 0x8fc0);
+
+       /* VgaDecRate = 1 */
+       __phy_write(phydev, 0x11, 0x4c2a);
+       __phy_write(phydev, 0x12, 0x3e);
+       __phy_write(phydev, 0x10, 0x8fa4);
 
        /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
         * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
@@ -738,7 +784,7 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev)
        __phy_write(phydev, 0x10, 0x8ec0);
        phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
 
-       /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9*/
+       /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
        phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
                       MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
                       BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
@@ -771,48 +817,6 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev)
        phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
 }
 
-static void mt7981_phy_finetune(struct phy_device *phydev)
-{
-       u16 val[8] = { 0x01ce, 0x01c1,
-                      0x020f, 0x0202,
-                      0x03d0, 0x03c0,
-                      0x0013, 0x0005 };
-       int i, k;
-
-       /* 100M eye finetune:
-        * Keep middle level of TX MLT3 shapper as default.
-        * Only change TX MLT3 overshoot level here.
-        */
-       for (k = 0, i = 1; i < 12; i++) {
-               if (i % 3 == 0)
-                       continue;
-               phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
-       }
-
-       phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-       /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
-       __phy_write(phydev, 0x11, 0xc71);
-       __phy_write(phydev, 0x12, 0xc);
-       __phy_write(phydev, 0x10, 0x8fae);
-
-       /* ResetSyncOffset = 6 */
-       __phy_write(phydev, 0x11, 0x600);
-       __phy_write(phydev, 0x12, 0x0);
-       __phy_write(phydev, 0x10, 0x8fc0);
-
-       /* VgaDecRate = 1 */
-       __phy_write(phydev, 0x11, 0x4c2a);
-       __phy_write(phydev, 0x12, 0x3e);
-       __phy_write(phydev, 0x10, 0x8fa4);
-
-       /* FfeUpdGainForce = 4 */
-       __phy_write(phydev, 0x11, 0x240);
-       __phy_write(phydev, 0x12, 0x0);
-       __phy_write(phydev, 0x10, 0x9680);
-
-       phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-}
-
 static void mt7988_phy_finetune(struct phy_device *phydev)
 {
        u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
@@ -827,17 +831,7 @@ static void mt7988_phy_finetune(struct phy_device *phydev)
        /* TCT finetune */
        phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
 
-       /* Disable TX power saving */
-       phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
-                      MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
-
        phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-
-       /* SlvDSPreadyTime = 24, MasDSPreadyTime = 12 */
-       __phy_write(phydev, 0x11, 0x671);
-       __phy_write(phydev, 0x12, 0xc);
-       __phy_write(phydev, 0x10, 0x8fae);
-
        /* ResetSyncOffset = 5 */
        __phy_write(phydev, 0x11, 0x500);
        __phy_write(phydev, 0x12, 0x0);
@@ -845,13 +839,27 @@ static void mt7988_phy_finetune(struct phy_device *phydev)
 
        /* VgaDecRate is 1 at default on mt7988 */
 
-       phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+       /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
+        * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
+        */
+       __phy_write(phydev, 0x11, 0xb90a);
+       __phy_write(phydev, 0x12, 0x6f);
+       __phy_write(phydev, 0x10, 0x8f82);
+
+       /* RemAckCntLimitCtrl = 1 */
+       __phy_write(phydev, 0x11, 0xfbba);
+       __phy_write(phydev, 0x12, 0xc3);
+       __phy_write(phydev, 0x10, 0x87f8);
 
-       phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_2A30);
-       /* TxClkOffset = 2 */
-       __phy_modify(phydev, MTK_PHY_ANARG_RG, MTK_PHY_TCLKOFFSET_MASK,
-                    FIELD_PREP(MTK_PHY_TCLKOFFSET_MASK, 0x2));
        phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+       /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
+       phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
+                      MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
+                      BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
+
+       /* rg_tr_lpf_cnt_val = 1023 */
+       phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
 }
 
 static void mt798x_phy_eee(struct phy_device *phydev)
@@ -884,11 +892,11 @@ static void mt798x_phy_eee(struct phy_device *phydev)
                       MTK_PHY_LPI_SLV_SEND_TX_EN,
                       FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
 
-       phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
-                      MTK_PHY_LPI_SEND_LOC_TIMER_MASK |
-                      MTK_PHY_LPI_TXPCS_LOC_RCV,
-                      FIELD_PREP(MTK_PHY_LPI_SEND_LOC_TIMER_MASK, 0x117));
+       /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
+       phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
+                          MTK_PHY_LPI_TXPCS_LOC_RCV);
 
+       /* This also fixes some IoT issues, such as CH340 */
        phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
                       MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
                       FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
@@ -922,7 +930,7 @@ static void mt798x_phy_eee(struct phy_device *phydev)
        __phy_write(phydev, 0x12, 0x0);
        __phy_write(phydev, 0x10, 0x9690);
 
-       /* REG_EEE_st2TrKf1000 = 3 */
+       /* REG_EEE_st2TrKf1000 = 2 */
        __phy_write(phydev, 0x11, 0x114f);
        __phy_write(phydev, 0x12, 0x2);
        __phy_write(phydev, 0x10, 0x969a);
@@ -947,7 +955,7 @@ static void mt798x_phy_eee(struct phy_device *phydev)
        __phy_write(phydev, 0x12, 0x0);
        __phy_write(phydev, 0x10, 0x96b8);
 
-       /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 1 */
+       /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
        __phy_write(phydev, 0x11, 0x1463);
        __phy_write(phydev, 0x12, 0x0);
        __phy_write(phydev, 0x10, 0x96ca);
@@ -1459,6 +1467,13 @@ static int mt7988_phy_probe(struct phy_device *phydev)
        if (err)
                return err;
 
+       /* Disable TX power saving at probing to:
+        * 1. Meet common mode compliance test criteria
+        * 2. Make sure that TX-VCM calibration works fine
+        */
+       phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
+                      MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
+
        return mt798x_phy_calibration(phydev);
 }
 
index d7503aef599f04bec326900fe918a974e55bc5cc..fab361a250d6054e03a40e451efda2eb3678fda6 100644 (file)
@@ -104,13 +104,12 @@ bool provides_xdp_headroom = true;
 module_param(provides_xdp_headroom, bool, 0644);
 
 static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
-                              u8 status);
+                              s8 status);
 
 static void make_tx_response(struct xenvif_queue *queue,
-                            struct xen_netif_tx_request *txp,
+                            const struct xen_netif_tx_request *txp,
                             unsigned int extra_count,
-                            s8       st);
-static void push_tx_responses(struct xenvif_queue *queue);
+                            s8 status);
 
 static void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx);
 
@@ -208,13 +207,9 @@ static void xenvif_tx_err(struct xenvif_queue *queue,
                          unsigned int extra_count, RING_IDX end)
 {
        RING_IDX cons = queue->tx.req_cons;
-       unsigned long flags;
 
        do {
-               spin_lock_irqsave(&queue->response_lock, flags);
                make_tx_response(queue, txp, extra_count, XEN_NETIF_RSP_ERROR);
-               push_tx_responses(queue);
-               spin_unlock_irqrestore(&queue->response_lock, flags);
                if (cons == end)
                        break;
                RING_COPY_REQUEST(&queue->tx, cons++, txp);
@@ -465,12 +460,7 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
        for (shinfo->nr_frags = 0; nr_slots > 0 && shinfo->nr_frags < MAX_SKB_FRAGS;
             nr_slots--) {
                if (unlikely(!txp->size)) {
-                       unsigned long flags;
-
-                       spin_lock_irqsave(&queue->response_lock, flags);
                        make_tx_response(queue, txp, 0, XEN_NETIF_RSP_OKAY);
-                       push_tx_responses(queue);
-                       spin_unlock_irqrestore(&queue->response_lock, flags);
                        ++txp;
                        continue;
                }
@@ -496,14 +486,8 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
 
                for (shinfo->nr_frags = 0; shinfo->nr_frags < nr_slots; ++txp) {
                        if (unlikely(!txp->size)) {
-                               unsigned long flags;
-
-                               spin_lock_irqsave(&queue->response_lock, flags);
                                make_tx_response(queue, txp, 0,
                                                 XEN_NETIF_RSP_OKAY);
-                               push_tx_responses(queue);
-                               spin_unlock_irqrestore(&queue->response_lock,
-                                                      flags);
                                continue;
                        }
 
@@ -995,7 +979,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                                         (ret == 0) ?
                                         XEN_NETIF_RSP_OKAY :
                                         XEN_NETIF_RSP_ERROR);
-                       push_tx_responses(queue);
                        continue;
                }
 
@@ -1007,7 +990,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
 
                        make_tx_response(queue, &txreq, extra_count,
                                         XEN_NETIF_RSP_OKAY);
-                       push_tx_responses(queue);
                        continue;
                }
 
@@ -1433,8 +1415,35 @@ int xenvif_tx_action(struct xenvif_queue *queue, int budget)
        return work_done;
 }
 
+static void _make_tx_response(struct xenvif_queue *queue,
+                            const struct xen_netif_tx_request *txp,
+                            unsigned int extra_count,
+                            s8 status)
+{
+       RING_IDX i = queue->tx.rsp_prod_pvt;
+       struct xen_netif_tx_response *resp;
+
+       resp = RING_GET_RESPONSE(&queue->tx, i);
+       resp->id     = txp->id;
+       resp->status = status;
+
+       while (extra_count-- != 0)
+               RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL;
+
+       queue->tx.rsp_prod_pvt = ++i;
+}
+
+static void push_tx_responses(struct xenvif_queue *queue)
+{
+       int notify;
+
+       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify);
+       if (notify)
+               notify_remote_via_irq(queue->tx_irq);
+}
+
 static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
-                              u8 status)
+                              s8 status)
 {
        struct pending_tx_info *pending_tx_info;
        pending_ring_idx_t index;
@@ -1444,8 +1453,8 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
 
        spin_lock_irqsave(&queue->response_lock, flags);
 
-       make_tx_response(queue, &pending_tx_info->req,
-                        pending_tx_info->extra_count, status);
+       _make_tx_response(queue, &pending_tx_info->req,
+                         pending_tx_info->extra_count, status);
 
        /* Release the pending index before pusing the Tx response so
         * its available before a new Tx request is pushed by the
@@ -1459,32 +1468,19 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
        spin_unlock_irqrestore(&queue->response_lock, flags);
 }
 
-
 static void make_tx_response(struct xenvif_queue *queue,
-                            struct xen_netif_tx_request *txp,
+                            const struct xen_netif_tx_request *txp,
                             unsigned int extra_count,
-                            s8       st)
+                            s8 status)
 {
-       RING_IDX i = queue->tx.rsp_prod_pvt;
-       struct xen_netif_tx_response *resp;
-
-       resp = RING_GET_RESPONSE(&queue->tx, i);
-       resp->id     = txp->id;
-       resp->status = st;
-
-       while (extra_count-- != 0)
-               RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL;
+       unsigned long flags;
 
-       queue->tx.rsp_prod_pvt = ++i;
-}
+       spin_lock_irqsave(&queue->response_lock, flags);
 
-static void push_tx_responses(struct xenvif_queue *queue)
-{
-       int notify;
+       _make_tx_response(queue, txp, extra_count, status);
+       push_tx_responses(queue);
 
-       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify);
-       if (notify)
-               notify_remote_via_irq(queue->tx_irq);
+       spin_unlock_irqrestore(&queue->response_lock, flags);
 }
 
 static void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx)
index a23ab5c968b9457bee89f14cc1f158e377ffa084..a3455f1d67fae20268a0e9e02a4c5c34ff054afe 100644 (file)
@@ -471,4 +471,5 @@ int nvme_auth_generate_key(u8 *secret, struct nvme_dhchap_key **ret_key)
 }
 EXPORT_SYMBOL_GPL(nvme_auth_generate_key);
 
+MODULE_DESCRIPTION("NVMe Authentication framework");
 MODULE_LICENSE("GPL v2");
index a5c0431c101cf3775509145e3bc7f12c6b64ccd0..6f7e7a8fa5ae470c463586fb0c638b5dc6f7313e 100644 (file)
@@ -181,5 +181,6 @@ static void __exit nvme_keyring_exit(void)
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Hannes Reinecke <hare@suse.de>");
+MODULE_DESCRIPTION("NVMe Keyring implementation");
 module_init(nvme_keyring_init);
 module_exit(nvme_keyring_exit);
index 596bb11eeba5a9d0a4d1637f2c061775956bb84e..c727cd1f264bf6221d2043d1f65bb70a51f00c1d 100644 (file)
@@ -797,6 +797,7 @@ static int apple_nvme_init_request(struct blk_mq_tag_set *set,
 
 static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown)
 {
+       enum nvme_ctrl_state state = nvme_ctrl_state(&anv->ctrl);
        u32 csts = readl(anv->mmio_nvme + NVME_REG_CSTS);
        bool dead = false, freeze = false;
        unsigned long flags;
@@ -808,8 +809,8 @@ static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown)
        if (csts & NVME_CSTS_CFS)
                dead = true;
 
-       if (anv->ctrl.state == NVME_CTRL_LIVE ||
-           anv->ctrl.state == NVME_CTRL_RESETTING) {
+       if (state == NVME_CTRL_LIVE ||
+           state == NVME_CTRL_RESETTING) {
                freeze = true;
                nvme_start_freeze(&anv->ctrl);
        }
@@ -881,7 +882,7 @@ static enum blk_eh_timer_return apple_nvme_timeout(struct request *req)
        unsigned long flags;
        u32 csts = readl(anv->mmio_nvme + NVME_REG_CSTS);
 
-       if (anv->ctrl.state != NVME_CTRL_LIVE) {
+       if (nvme_ctrl_state(&anv->ctrl) != NVME_CTRL_LIVE) {
                /*
                 * From rdma.c:
                 * If we are resetting, connecting or deleting we should
@@ -985,10 +986,10 @@ static void apple_nvme_reset_work(struct work_struct *work)
        u32 boot_status, aqa;
        struct apple_nvme *anv =
                container_of(work, struct apple_nvme, ctrl.reset_work);
+       enum nvme_ctrl_state state = nvme_ctrl_state(&anv->ctrl);
 
-       if (anv->ctrl.state != NVME_CTRL_RESETTING) {
-               dev_warn(anv->dev, "ctrl state %d is not RESETTING\n",
-                        anv->ctrl.state);
+       if (state != NVME_CTRL_RESETTING) {
+               dev_warn(anv->dev, "ctrl state %d is not RESETTING\n", state);
                ret = -ENODEV;
                goto out;
        }
index 72c0525c75f503bb56c7c246c733f9eea57e44ab..a264b3ae078b8c4c28382c7d8f8757c7e3eec594 100644 (file)
@@ -48,11 +48,6 @@ struct nvme_dhchap_queue_context {
 
 static struct workqueue_struct *nvme_auth_wq;
 
-#define nvme_auth_flags_from_qid(qid) \
-       (qid == 0) ? 0 : BLK_MQ_REQ_NOWAIT | BLK_MQ_REQ_RESERVED
-#define nvme_auth_queue_from_qid(ctrl, qid) \
-       (qid == 0) ? (ctrl)->fabrics_q : (ctrl)->connect_q
-
 static inline int ctrl_max_dhchaps(struct nvme_ctrl *ctrl)
 {
        return ctrl->opts->nr_io_queues + ctrl->opts->nr_write_queues +
@@ -63,10 +58,15 @@ static int nvme_auth_submit(struct nvme_ctrl *ctrl, int qid,
                            void *data, size_t data_len, bool auth_send)
 {
        struct nvme_command cmd = {};
-       blk_mq_req_flags_t flags = nvme_auth_flags_from_qid(qid);
-       struct request_queue *q = nvme_auth_queue_from_qid(ctrl, qid);
+       nvme_submit_flags_t flags = NVME_SUBMIT_RETRY;
+       struct request_queue *q = ctrl->fabrics_q;
        int ret;
 
+       if (qid != 0) {
+               flags |= NVME_SUBMIT_NOWAIT | NVME_SUBMIT_RESERVED;
+               q = ctrl->connect_q;
+       }
+
        cmd.auth_common.opcode = nvme_fabrics_command;
        cmd.auth_common.secp = NVME_AUTH_DHCHAP_PROTOCOL_IDENTIFIER;
        cmd.auth_common.spsp0 = 0x01;
@@ -80,8 +80,7 @@ static int nvme_auth_submit(struct nvme_ctrl *ctrl, int qid,
        }
 
        ret = __nvme_submit_sync_cmd(q, &cmd, NULL, data, data_len,
-                                    qid == 0 ? NVME_QID_ANY : qid,
-                                    0, flags);
+                                    qid == 0 ? NVME_QID_ANY : qid, flags);
        if (ret > 0)
                dev_warn(ctrl->device,
                        "qid %d auth_send failed with status %d\n", qid, ret);
@@ -897,7 +896,7 @@ static void nvme_ctrl_auth_work(struct work_struct *work)
         * If the ctrl is no connected, bail as reconnect will handle
         * authentication.
         */
-       if (ctrl->state != NVME_CTRL_LIVE)
+       if (nvme_ctrl_state(ctrl) != NVME_CTRL_LIVE)
                return;
 
        /* Authenticate admin queue first */
index 20f46c230885c10f2a82bc87f7091645e2d02db5..6f2ebb5fcdb05e1e65971643c9aff2c3f2271c19 100644 (file)
@@ -171,15 +171,15 @@ static const char * const nvme_statuses[] = {
        [NVME_SC_HOST_ABORTED_CMD] = "Host Aborted Command",
 };
 
-const unsigned char *nvme_get_error_status_str(u16 status)
+const char *nvme_get_error_status_str(u16 status)
 {
        status &= 0x7ff;
        if (status < ARRAY_SIZE(nvme_statuses) && nvme_statuses[status])
-               return nvme_statuses[status & 0x7ff];
+               return nvme_statuses[status];
        return "Unknown";
 }
 
-const unsigned char *nvme_get_opcode_str(u8 opcode)
+const char *nvme_get_opcode_str(u8 opcode)
 {
        if (opcode < ARRAY_SIZE(nvme_ops) && nvme_ops[opcode])
                return nvme_ops[opcode];
@@ -187,7 +187,7 @@ const unsigned char *nvme_get_opcode_str(u8 opcode)
 }
 EXPORT_SYMBOL_GPL(nvme_get_opcode_str);
 
-const unsigned char *nvme_get_admin_opcode_str(u8 opcode)
+const char *nvme_get_admin_opcode_str(u8 opcode)
 {
        if (opcode < ARRAY_SIZE(nvme_admin_ops) && nvme_admin_ops[opcode])
                return nvme_admin_ops[opcode];
@@ -195,7 +195,7 @@ const unsigned char *nvme_get_admin_opcode_str(u8 opcode)
 }
 EXPORT_SYMBOL_GPL(nvme_get_admin_opcode_str);
 
-const unsigned char *nvme_get_fabrics_opcode_str(u8 opcode) {
+const char *nvme_get_fabrics_opcode_str(u8 opcode) {
        if (opcode < ARRAY_SIZE(nvme_fabrics_ops) && nvme_fabrics_ops[opcode])
                return nvme_fabrics_ops[opcode];
        return "Unknown";
index 85ab0fcf9e886451fb070b75dcd53be4a4f88f62..0d124a8ca9c321700844bbb8ccc176a6c3081189 100644 (file)
@@ -338,6 +338,30 @@ static void nvme_log_error(struct request *req)
                           nr->status & NVME_SC_DNR  ? "DNR "  : "");
 }
 
+static void nvme_log_err_passthru(struct request *req)
+{
+       struct nvme_ns *ns = req->q->queuedata;
+       struct nvme_request *nr = nvme_req(req);
+
+       pr_err_ratelimited("%s: %s(0x%x), %s (sct 0x%x / sc 0x%x) %s%s"
+               "cdw10=0x%x cdw11=0x%x cdw12=0x%x cdw13=0x%x cdw14=0x%x cdw15=0x%x\n",
+               ns ? ns->disk->disk_name : dev_name(nr->ctrl->device),
+               ns ? nvme_get_opcode_str(nr->cmd->common.opcode) :
+                    nvme_get_admin_opcode_str(nr->cmd->common.opcode),
+               nr->cmd->common.opcode,
+               nvme_get_error_status_str(nr->status),
+               nr->status >> 8 & 7,    /* Status Code Type */
+               nr->status & 0xff,      /* Status Code */
+               nr->status & NVME_SC_MORE ? "MORE " : "",
+               nr->status & NVME_SC_DNR  ? "DNR "  : "",
+               nr->cmd->common.cdw10,
+               nr->cmd->common.cdw11,
+               nr->cmd->common.cdw12,
+               nr->cmd->common.cdw13,
+               nr->cmd->common.cdw14,
+               nr->cmd->common.cdw14);
+}
+
 enum nvme_disposition {
        COMPLETE,
        RETRY,
@@ -385,8 +409,12 @@ static inline void nvme_end_req(struct request *req)
 {
        blk_status_t status = nvme_error_status(nvme_req(req)->status);
 
-       if (unlikely(nvme_req(req)->status && !(req->rq_flags & RQF_QUIET)))
-               nvme_log_error(req);
+       if (unlikely(nvme_req(req)->status && !(req->rq_flags & RQF_QUIET))) {
+               if (blk_rq_is_passthrough(req))
+                       nvme_log_err_passthru(req);
+               else
+                       nvme_log_error(req);
+       }
        nvme_end_req_zoned(req);
        nvme_trace_bio_complete(req);
        if (req->cmd_flags & REQ_NVME_MPATH)
@@ -679,10 +707,21 @@ static inline void nvme_clear_nvme_request(struct request *req)
 /* initialize a passthrough request */
 void nvme_init_request(struct request *req, struct nvme_command *cmd)
 {
-       if (req->q->queuedata)
+       struct nvme_request *nr = nvme_req(req);
+       bool logging_enabled;
+
+       if (req->q->queuedata) {
+               struct nvme_ns *ns = req->q->disk->private_data;
+
+               logging_enabled = ns->passthru_err_log_enabled;
                req->timeout = NVME_IO_TIMEOUT;
-       else /* no queuedata implies admin queue */
+       } else { /* no queuedata implies admin queue */
+               logging_enabled = nr->ctrl->passthru_err_log_enabled;
                req->timeout = NVME_ADMIN_TIMEOUT;
+       }
+
+       if (!logging_enabled)
+               req->rq_flags |= RQF_QUIET;
 
        /* passthru commands should let the driver set the SGL flags */
        cmd->common.flags &= ~NVME_CMD_SGL_ALL;
@@ -691,8 +730,7 @@ void nvme_init_request(struct request *req, struct nvme_command *cmd)
        if (req->mq_hctx->type == HCTX_TYPE_POLL)
                req->cmd_flags |= REQ_POLLED;
        nvme_clear_nvme_request(req);
-       req->rq_flags |= RQF_QUIET;
-       memcpy(nvme_req(req)->cmd, cmd, sizeof(*cmd));
+       memcpy(nr->cmd, cmd, sizeof(*cmd));
 }
 EXPORT_SYMBOL_GPL(nvme_init_request);
 
@@ -721,7 +759,7 @@ blk_status_t nvme_fail_nonready_command(struct nvme_ctrl *ctrl,
 EXPORT_SYMBOL_GPL(nvme_fail_nonready_command);
 
 bool __nvme_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
-               bool queue_live)
+               bool queue_live, enum nvme_ctrl_state state)
 {
        struct nvme_request *req = nvme_req(rq);
 
@@ -742,7 +780,7 @@ bool __nvme_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
                 * command, which is require to set the queue live in the
                 * appropinquate states.
                 */
-               switch (nvme_ctrl_state(ctrl)) {
+               switch (state) {
                case NVME_CTRL_CONNECTING:
                        if (blk_rq_is_passthrough(rq) && nvme_is_fabrics(req->cmd) &&
                            (req->cmd->fabrics.fctype == nvme_fabrics_type_connect ||
@@ -1051,20 +1089,27 @@ EXPORT_SYMBOL_NS_GPL(nvme_execute_rq, NVME_TARGET_PASSTHRU);
  */
 int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
                union nvme_result *result, void *buffer, unsigned bufflen,
-               int qid, int at_head, blk_mq_req_flags_t flags)
+               int qid, nvme_submit_flags_t flags)
 {
        struct request *req;
        int ret;
+       blk_mq_req_flags_t blk_flags = 0;
 
+       if (flags & NVME_SUBMIT_NOWAIT)
+               blk_flags |= BLK_MQ_REQ_NOWAIT;
+       if (flags & NVME_SUBMIT_RESERVED)
+               blk_flags |= BLK_MQ_REQ_RESERVED;
        if (qid == NVME_QID_ANY)
-               req = blk_mq_alloc_request(q, nvme_req_op(cmd), flags);
+               req = blk_mq_alloc_request(q, nvme_req_op(cmd), blk_flags);
        else
-               req = blk_mq_alloc_request_hctx(q, nvme_req_op(cmd), flags,
+               req = blk_mq_alloc_request_hctx(q, nvme_req_op(cmd), blk_flags,
                                                qid - 1);
 
        if (IS_ERR(req))
                return PTR_ERR(req);
        nvme_init_request(req, cmd);
+       if (flags & NVME_SUBMIT_RETRY)
+               req->cmd_flags &= ~REQ_FAILFAST_DRIVER;
 
        if (buffer && bufflen) {
                ret = blk_rq_map_kern(q, req, buffer, bufflen, GFP_KERNEL);
@@ -1072,7 +1117,7 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
                        goto out;
        }
 
-       ret = nvme_execute_rq(req, at_head);
+       ret = nvme_execute_rq(req, flags & NVME_SUBMIT_AT_HEAD);
        if (result && ret >= 0)
                *result = nvme_req(req)->result;
  out:
@@ -1085,7 +1130,7 @@ int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
                void *buffer, unsigned bufflen)
 {
        return __nvme_submit_sync_cmd(q, cmd, NULL, buffer, bufflen,
-                       NVME_QID_ANY, 0, 0);
+                       NVME_QID_ANY, 0);
 }
 EXPORT_SYMBOL_GPL(nvme_submit_sync_cmd);
 
@@ -1560,7 +1605,7 @@ static int nvme_features(struct nvme_ctrl *dev, u8 op, unsigned int fid,
        c.features.dword11 = cpu_to_le32(dword11);
 
        ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &res,
-                       buffer, buflen, NVME_QID_ANY, 0, 0);
+                       buffer, buflen, NVME_QID_ANY, 0);
        if (ret >= 0 && result)
                *result = le32_to_cpu(res.u32);
        return ret;
@@ -2172,7 +2217,7 @@ static int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t l
        cmd.common.cdw11 = cpu_to_le32(len);
 
        return __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, NULL, buffer, len,
-                       NVME_QID_ANY, 1, 0);
+                       NVME_QID_ANY, NVME_SUBMIT_AT_HEAD);
 }
 
 static void nvme_configure_opal(struct nvme_ctrl *ctrl, bool was_suspended)
@@ -3651,6 +3696,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, struct nvme_ns_info *info)
 
        ns->disk = disk;
        ns->queue = disk->queue;
+       ns->passthru_err_log_enabled = false;
 
        if (ctrl->opts && ctrl->opts->data_digest)
                blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, ns->queue);
@@ -3714,6 +3760,13 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, struct nvme_ns_info *info)
        nvme_mpath_add_disk(ns, info->anagrpid);
        nvme_fault_inject_init(&ns->fault_inject, ns->disk->disk_name);
 
+       /*
+        * Set ns->disk->device->driver_data to ns so we can access
+        * ns->logging_enabled in nvme_passthru_err_log_enabled_store() and
+        * nvme_passthru_err_log_enabled_show().
+        */
+       dev_set_drvdata(disk_to_dev(ns->disk), ns);
+
        return;
 
  out_cleanup_ns_from_list:
@@ -4514,6 +4567,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
        int ret;
 
        WRITE_ONCE(ctrl->state, NVME_CTRL_NEW);
+       ctrl->passthru_err_log_enabled = false;
        clear_bit(NVME_CTRL_FAILFAST_EXPIRED, &ctrl->flags);
        spin_lock_init(&ctrl->lock);
        mutex_init(&ctrl->scan_lock);
@@ -4851,5 +4905,6 @@ static void __exit nvme_core_exit(void)
 
 MODULE_LICENSE("GPL");
 MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("NVMe host core framework");
 module_init(nvme_core_init);
 module_exit(nvme_core_exit);
index b5752a77ad989f04a14ef9416f6244cf5255441d..3499acbf6a822fc1a45d93894f4870a9a5f7857c 100644 (file)
@@ -180,7 +180,7 @@ int nvmf_reg_read32(struct nvme_ctrl *ctrl, u32 off, u32 *val)
        cmd.prop_get.offset = cpu_to_le32(off);
 
        ret = __nvme_submit_sync_cmd(ctrl->fabrics_q, &cmd, &res, NULL, 0,
-                       NVME_QID_ANY, 0, 0);
+                       NVME_QID_ANY, 0);
 
        if (ret >= 0)
                *val = le64_to_cpu(res.u64);
@@ -226,7 +226,7 @@ int nvmf_reg_read64(struct nvme_ctrl *ctrl, u32 off, u64 *val)
        cmd.prop_get.offset = cpu_to_le32(off);
 
        ret = __nvme_submit_sync_cmd(ctrl->fabrics_q, &cmd, &res, NULL, 0,
-                       NVME_QID_ANY, 0, 0);
+                       NVME_QID_ANY, 0);
 
        if (ret >= 0)
                *val = le64_to_cpu(res.u64);
@@ -271,7 +271,7 @@ int nvmf_reg_write32(struct nvme_ctrl *ctrl, u32 off, u32 val)
        cmd.prop_set.value = cpu_to_le64(val);
 
        ret = __nvme_submit_sync_cmd(ctrl->fabrics_q, &cmd, NULL, NULL, 0,
-                       NVME_QID_ANY, 0, 0);
+                       NVME_QID_ANY, 0);
        if (unlikely(ret))
                dev_err(ctrl->device,
                        "Property Set error: %d, offset %#x\n",
@@ -450,8 +450,10 @@ int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl)
                return -ENOMEM;
 
        ret = __nvme_submit_sync_cmd(ctrl->fabrics_q, &cmd, &res,
-                       data, sizeof(*data), NVME_QID_ANY, 1,
-                       BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
+                       data, sizeof(*data), NVME_QID_ANY,
+                       NVME_SUBMIT_AT_HEAD |
+                       NVME_SUBMIT_NOWAIT |
+                       NVME_SUBMIT_RESERVED);
        if (ret) {
                nvmf_log_connect_error(ctrl, ret, le32_to_cpu(res.u32),
                                       &cmd, data);
@@ -525,8 +527,10 @@ int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid)
                return -ENOMEM;
 
        ret = __nvme_submit_sync_cmd(ctrl->connect_q, &cmd, &res,
-                       data, sizeof(*data), qid, 1,
-                       BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
+                       data, sizeof(*data), qid,
+                       NVME_SUBMIT_AT_HEAD |
+                       NVME_SUBMIT_RESERVED |
+                       NVME_SUBMIT_NOWAIT);
        if (ret) {
                nvmf_log_connect_error(ctrl, ret, le32_to_cpu(res.u32),
                                       &cmd, data);
@@ -1488,6 +1492,7 @@ static void __exit nvmf_exit(void)
 }
 
 MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("NVMe host fabrics library");
 
 module_init(nvmf_init);
 module_exit(nvmf_exit);
index fbaee5a7be196c08483a41b6673f00e5032bec10..06cc54851b1be39615cdfa6eed1a935dec472f82 100644 (file)
@@ -185,9 +185,11 @@ static inline bool
 nvmf_ctlr_matches_baseopts(struct nvme_ctrl *ctrl,
                        struct nvmf_ctrl_options *opts)
 {
-       if (ctrl->state == NVME_CTRL_DELETING ||
-           ctrl->state == NVME_CTRL_DELETING_NOIO ||
-           ctrl->state == NVME_CTRL_DEAD ||
+       enum nvme_ctrl_state state = nvme_ctrl_state(ctrl);
+
+       if (state == NVME_CTRL_DELETING ||
+           state == NVME_CTRL_DELETING_NOIO ||
+           state == NVME_CTRL_DEAD ||
            strcmp(opts->subsysnqn, ctrl->opts->subsysnqn) ||
            strcmp(opts->host->nqn, ctrl->opts->host->nqn) ||
            !uuid_equal(&opts->host->id, &ctrl->opts->host->id))
index 16847a316421f393cfbf410f083cd97c657f062e..68a5d971657bb5080f717f5ae1ec5645830aadd5 100644 (file)
@@ -221,11 +221,6 @@ static LIST_HEAD(nvme_fc_lport_list);
 static DEFINE_IDA(nvme_fc_local_port_cnt);
 static DEFINE_IDA(nvme_fc_ctrl_cnt);
 
-static struct workqueue_struct *nvme_fc_wq;
-
-static bool nvme_fc_waiting_to_unload;
-static DECLARE_COMPLETION(nvme_fc_unload_proceed);
-
 /*
  * These items are short-term. They will eventually be moved into
  * a generic FC class. See comments in module init.
@@ -255,8 +250,6 @@ nvme_fc_free_lport(struct kref *ref)
        /* remove from transport list */
        spin_lock_irqsave(&nvme_fc_lock, flags);
        list_del(&lport->port_list);
-       if (nvme_fc_waiting_to_unload && list_empty(&nvme_fc_lport_list))
-               complete(&nvme_fc_unload_proceed);
        spin_unlock_irqrestore(&nvme_fc_lock, flags);
 
        ida_free(&nvme_fc_local_port_cnt, lport->localport.port_num);
@@ -2574,6 +2567,7 @@ static enum blk_eh_timer_return nvme_fc_timeout(struct request *rq)
 {
        struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq);
        struct nvme_fc_ctrl *ctrl = op->ctrl;
+       u16 qnum = op->queue->qnum;
        struct nvme_fc_cmd_iu *cmdiu = &op->cmd_iu;
        struct nvme_command *sqe = &cmdiu->sqe;
 
@@ -2582,10 +2576,11 @@ static enum blk_eh_timer_return nvme_fc_timeout(struct request *rq)
         * will detect the aborted io and will fail the connection.
         */
        dev_info(ctrl->ctrl.device,
-               "NVME-FC{%d.%d}: io timeout: opcode %d fctype %d w10/11: "
+               "NVME-FC{%d.%d}: io timeout: opcode %d fctype %d (%s) w10/11: "
                "x%08x/x%08x\n",
-               ctrl->cnum, op->queue->qnum, sqe->common.opcode,
-               sqe->connect.fctype, sqe->common.cdw10, sqe->common.cdw11);
+               ctrl->cnum, qnum, sqe->common.opcode, sqe->fabrics.fctype,
+               nvme_fabrics_opcode_str(qnum, sqe),
+               sqe->common.cdw10, sqe->common.cdw11);
        if (__nvme_fc_abort_op(ctrl, op))
                nvme_fc_error_recovery(ctrl, "io timeout abort failed");
 
@@ -3575,8 +3570,8 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
        flush_delayed_work(&ctrl->connect_work);
 
        dev_info(ctrl->ctrl.device,
-               "NVME-FC{%d}: new ctrl: NQN \"%s\"\n",
-               ctrl->cnum, nvmf_ctrl_subsysnqn(&ctrl->ctrl));
+               "NVME-FC{%d}: new ctrl: NQN \"%s\", hostnqn: %s\n",
+               ctrl->cnum, nvmf_ctrl_subsysnqn(&ctrl->ctrl), opts->host->nqn);
 
        return &ctrl->ctrl;
 
@@ -3894,10 +3889,6 @@ static int __init nvme_fc_init_module(void)
 {
        int ret;
 
-       nvme_fc_wq = alloc_workqueue("nvme_fc_wq", WQ_MEM_RECLAIM, 0);
-       if (!nvme_fc_wq)
-               return -ENOMEM;
-
        /*
         * NOTE:
         * It is expected that in the future the kernel will combine
@@ -3915,7 +3906,7 @@ static int __init nvme_fc_init_module(void)
        ret = class_register(&fc_class);
        if (ret) {
                pr_err("couldn't register class fc\n");
-               goto out_destroy_wq;
+               return ret;
        }
 
        /*
@@ -3939,8 +3930,6 @@ out_destroy_device:
        device_destroy(&fc_class, MKDEV(0, 0));
 out_destroy_class:
        class_unregister(&fc_class);
-out_destroy_wq:
-       destroy_workqueue(nvme_fc_wq);
 
        return ret;
 }
@@ -3960,48 +3949,27 @@ nvme_fc_delete_controllers(struct nvme_fc_rport *rport)
        spin_unlock(&rport->lock);
 }
 
-static void
-nvme_fc_cleanup_for_unload(void)
+static void __exit nvme_fc_exit_module(void)
 {
        struct nvme_fc_lport *lport;
        struct nvme_fc_rport *rport;
-
-       list_for_each_entry(lport, &nvme_fc_lport_list, port_list) {
-               list_for_each_entry(rport, &lport->endp_list, endp_list) {
-                       nvme_fc_delete_controllers(rport);
-               }
-       }
-}
-
-static void __exit nvme_fc_exit_module(void)
-{
        unsigned long flags;
-       bool need_cleanup = false;
 
        spin_lock_irqsave(&nvme_fc_lock, flags);
-       nvme_fc_waiting_to_unload = true;
-       if (!list_empty(&nvme_fc_lport_list)) {
-               need_cleanup = true;
-               nvme_fc_cleanup_for_unload();
-       }
+       list_for_each_entry(lport, &nvme_fc_lport_list, port_list)
+               list_for_each_entry(rport, &lport->endp_list, endp_list)
+                       nvme_fc_delete_controllers(rport);
        spin_unlock_irqrestore(&nvme_fc_lock, flags);
-       if (need_cleanup) {
-               pr_info("%s: waiting for ctlr deletes\n", __func__);
-               wait_for_completion(&nvme_fc_unload_proceed);
-               pr_info("%s: ctrl deletes complete\n", __func__);
-       }
+       flush_workqueue(nvme_delete_wq);
 
        nvmf_unregister_transport(&nvme_fc_transport);
 
-       ida_destroy(&nvme_fc_local_port_cnt);
-       ida_destroy(&nvme_fc_ctrl_cnt);
-
        device_destroy(&fc_class, MKDEV(0, 0));
        class_unregister(&fc_class);
-       destroy_workqueue(nvme_fc_wq);
 }
 
 module_init(nvme_fc_init_module);
 module_exit(nvme_fc_exit_module);
 
+MODULE_DESCRIPTION("NVMe host FC transport driver");
 MODULE_LICENSE("GPL v2");
index 2dd4137a08b284df64788972a067d4282fa92ac7..74de1e64aeead77c604ec31e30bac179a0de245b 100644 (file)
@@ -156,7 +156,7 @@ void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl)
                if (!ns->head->disk)
                        continue;
                kblockd_schedule_work(&ns->head->requeue_work);
-               if (ctrl->state == NVME_CTRL_LIVE)
+               if (nvme_ctrl_state(ns->ctrl) == NVME_CTRL_LIVE)
                        disk_uevent(ns->head->disk, KOBJ_CHANGE);
        }
        up_read(&ctrl->namespaces_rwsem);
@@ -223,13 +223,14 @@ void nvme_mpath_revalidate_paths(struct nvme_ns *ns)
 
 static bool nvme_path_is_disabled(struct nvme_ns *ns)
 {
+       enum nvme_ctrl_state state = nvme_ctrl_state(ns->ctrl);
+
        /*
         * We don't treat NVME_CTRL_DELETING as a disabled path as I/O should
         * still be able to complete assuming that the controller is connected.
         * Otherwise it will fail immediately and return to the requeue list.
         */
-       if (ns->ctrl->state != NVME_CTRL_LIVE &&
-           ns->ctrl->state != NVME_CTRL_DELETING)
+       if (state != NVME_CTRL_LIVE && state != NVME_CTRL_DELETING)
                return true;
        if (test_bit(NVME_NS_ANA_PENDING, &ns->flags) ||
            !test_bit(NVME_NS_READY, &ns->flags))
@@ -331,7 +332,7 @@ out:
 
 static inline bool nvme_path_is_optimized(struct nvme_ns *ns)
 {
-       return ns->ctrl->state == NVME_CTRL_LIVE &&
+       return nvme_ctrl_state(ns->ctrl) == NVME_CTRL_LIVE &&
                ns->ana_state == NVME_ANA_OPTIMIZED;
 }
 
@@ -358,7 +359,7 @@ static bool nvme_available_path(struct nvme_ns_head *head)
        list_for_each_entry_rcu(ns, &head->list, siblings) {
                if (test_bit(NVME_CTRL_FAILFAST_EXPIRED, &ns->ctrl->flags))
                        continue;
-               switch (ns->ctrl->state) {
+               switch (nvme_ctrl_state(ns->ctrl)) {
                case NVME_CTRL_LIVE:
                case NVME_CTRL_RESETTING:
                case NVME_CTRL_CONNECTING:
@@ -667,7 +668,7 @@ static void nvme_update_ns_ana_state(struct nvme_ana_group_desc *desc,
         * controller is ready.
         */
        if (nvme_state_is_live(ns->ana_state) &&
-           ns->ctrl->state == NVME_CTRL_LIVE)
+           nvme_ctrl_state(ns->ctrl) == NVME_CTRL_LIVE)
                nvme_mpath_set_live(ns);
 }
 
@@ -748,7 +749,7 @@ static void nvme_ana_work(struct work_struct *work)
 {
        struct nvme_ctrl *ctrl = container_of(work, struct nvme_ctrl, ana_work);
 
-       if (ctrl->state != NVME_CTRL_LIVE)
+       if (nvme_ctrl_state(ctrl) != NVME_CTRL_LIVE)
                return;
 
        nvme_read_ana_log(ctrl);
index 030c8081824065e7fa3d14e1a4918f1c94080565..3897334e3950d5f2de1451961a159708cf4b8077 100644 (file)
@@ -263,6 +263,7 @@ enum nvme_ctrl_flags {
 struct nvme_ctrl {
        bool comp_seen;
        bool identified;
+       bool passthru_err_log_enabled;
        enum nvme_ctrl_state state;
        spinlock_t lock;
        struct mutex scan_lock;
@@ -522,7 +523,7 @@ struct nvme_ns {
        struct device           cdev_device;
 
        struct nvme_fault_inject fault_inject;
-
+       bool                    passthru_err_log_enabled;
 };
 
 /* NVMe ns supports metadata actions by the controller (generate/strip) */
@@ -805,17 +806,18 @@ blk_status_t nvme_setup_cmd(struct nvme_ns *ns, struct request *req);
 blk_status_t nvme_fail_nonready_command(struct nvme_ctrl *ctrl,
                struct request *req);
 bool __nvme_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
-               bool queue_live);
+               bool queue_live, enum nvme_ctrl_state state);
 
 static inline bool nvme_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
                bool queue_live)
 {
-       if (likely(ctrl->state == NVME_CTRL_LIVE))
+       enum nvme_ctrl_state state = nvme_ctrl_state(ctrl);
+
+       if (likely(state == NVME_CTRL_LIVE))
                return true;
-       if (ctrl->ops->flags & NVME_F_FABRICS &&
-           ctrl->state == NVME_CTRL_DELETING)
+       if (ctrl->ops->flags & NVME_F_FABRICS && state == NVME_CTRL_DELETING)
                return queue_live;
-       return __nvme_check_ready(ctrl, rq, queue_live);
+       return __nvme_check_ready(ctrl, rq, queue_live, state);
 }
 
 /*
@@ -836,12 +838,27 @@ static inline bool nvme_is_unique_nsid(struct nvme_ctrl *ctrl,
                (ctrl->ctratt & NVME_CTRL_CTRATT_NVM_SETS);
 }
 
+/*
+ * Flags for __nvme_submit_sync_cmd()
+ */
+typedef __u32 __bitwise nvme_submit_flags_t;
+
+enum {
+       /* Insert request at the head of the queue */
+       NVME_SUBMIT_AT_HEAD  = (__force nvme_submit_flags_t)(1 << 0),
+       /* Set BLK_MQ_REQ_NOWAIT when allocating request */
+       NVME_SUBMIT_NOWAIT = (__force nvme_submit_flags_t)(1 << 1),
+       /* Set BLK_MQ_REQ_RESERVED when allocating request */
+       NVME_SUBMIT_RESERVED = (__force nvme_submit_flags_t)(1 << 2),
+       /* Retry command when NVME_SC_DNR is not set in the result */
+       NVME_SUBMIT_RETRY = (__force nvme_submit_flags_t)(1 << 3),
+};
+
 int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
                void *buf, unsigned bufflen);
 int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
                union nvme_result *result, void *buffer, unsigned bufflen,
-               int qid, int at_head,
-               blk_mq_req_flags_t flags);
+               int qid, nvme_submit_flags_t flags);
 int nvme_set_features(struct nvme_ctrl *dev, unsigned int fid,
                      unsigned int dword11, void *buffer, size_t buflen,
                      u32 *result);
@@ -1124,35 +1141,42 @@ static inline bool nvme_multi_css(struct nvme_ctrl *ctrl)
 }
 
 #ifdef CONFIG_NVME_VERBOSE_ERRORS
-const unsigned char *nvme_get_error_status_str(u16 status);
-const unsigned char *nvme_get_opcode_str(u8 opcode);
-const unsigned char *nvme_get_admin_opcode_str(u8 opcode);
-const unsigned char *nvme_get_fabrics_opcode_str(u8 opcode);
+const char *nvme_get_error_status_str(u16 status);
+const char *nvme_get_opcode_str(u8 opcode);
+const char *nvme_get_admin_opcode_str(u8 opcode);
+const char *nvme_get_fabrics_opcode_str(u8 opcode);
 #else /* CONFIG_NVME_VERBOSE_ERRORS */
-static inline const unsigned char *nvme_get_error_status_str(u16 status)
+static inline const char *nvme_get_error_status_str(u16 status)
 {
        return "I/O Error";
 }
-static inline const unsigned char *nvme_get_opcode_str(u8 opcode)
+static inline const char *nvme_get_opcode_str(u8 opcode)
 {
        return "I/O Cmd";
 }
-static inline const unsigned char *nvme_get_admin_opcode_str(u8 opcode)
+static inline const char *nvme_get_admin_opcode_str(u8 opcode)
 {
        return "Admin Cmd";
 }
 
-static inline const unsigned char *nvme_get_fabrics_opcode_str(u8 opcode)
+static inline const char *nvme_get_fabrics_opcode_str(u8 opcode)
 {
        return "Fabrics Cmd";
 }
 #endif /* CONFIG_NVME_VERBOSE_ERRORS */
 
-static inline const unsigned char *nvme_opcode_str(int qid, u8 opcode, u8 fctype)
+static inline const char *nvme_opcode_str(int qid, u8 opcode)
 {
-       if (opcode == nvme_fabrics_command)
-               return nvme_get_fabrics_opcode_str(fctype);
        return qid ? nvme_get_opcode_str(opcode) :
                nvme_get_admin_opcode_str(opcode);
 }
+
+static inline const char *nvme_fabrics_opcode_str(
+               int qid, const struct nvme_command *cmd)
+{
+       if (nvme_is_fabrics(cmd))
+               return nvme_get_fabrics_opcode_str(cmd->fabrics.fctype);
+
+       return nvme_opcode_str(qid, cmd->common.opcode);
+}
 #endif /* _NVME_H */
index c1d6357ec98a0107acacdae47024c3110b3cfb9f..e6267a6aa3801e5d76e7d1dc4a509ba0e9fc0159 100644 (file)
@@ -1349,7 +1349,7 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req)
                dev_warn(dev->ctrl.device,
                         "I/O tag %d (%04x) opcode %#x (%s) QID %d timeout, reset controller\n",
                         req->tag, nvme_cid(req), opcode,
-                        nvme_opcode_str(nvmeq->qid, opcode, 0), nvmeq->qid);
+                        nvme_opcode_str(nvmeq->qid, opcode), nvmeq->qid);
                nvme_req(req)->flags |= NVME_REQ_CANCELLED;
                goto disable;
        }
@@ -3543,5 +3543,6 @@ static void __exit nvme_exit(void)
 MODULE_AUTHOR("Matthew Wilcox <willy@linux.intel.com>");
 MODULE_LICENSE("GPL");
 MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("NVMe host PCIe transport driver");
 module_init(nvme_init);
 module_exit(nvme_exit);
index 11dde0d830442df31c74499655e86566ab995a66..20fdd40b1879f5796ab768acade2096eefde9e93 100644 (file)
@@ -1410,6 +1410,8 @@ static int nvme_rdma_map_sg_pi(struct nvme_rdma_queue *queue,
        struct nvme_ns *ns = rq->q->queuedata;
        struct bio *bio = rq->bio;
        struct nvme_keyed_sgl_desc *sg = &c->common.dptr.ksgl;
+       struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
+       u32 xfer_len;
        int nr;
 
        req->mr = ib_mr_pool_get(queue->qp, &queue->qp->sig_mrs);
@@ -1422,8 +1424,7 @@ static int nvme_rdma_map_sg_pi(struct nvme_rdma_queue *queue,
        if (unlikely(nr))
                goto mr_put;
 
-       nvme_rdma_set_sig_attrs(blk_get_integrity(bio->bi_bdev->bd_disk), c,
-                               req->mr->sig_attrs, ns->head->pi_type);
+       nvme_rdma_set_sig_attrs(bi, c, req->mr->sig_attrs, ns->head->pi_type);
        nvme_rdma_set_prot_checks(c, &req->mr->sig_attrs->check_mask);
 
        ib_update_fast_reg_key(req->mr, ib_inc_rkey(req->mr->rkey));
@@ -1441,7 +1442,11 @@ static int nvme_rdma_map_sg_pi(struct nvme_rdma_queue *queue,
                     IB_ACCESS_REMOTE_WRITE;
 
        sg->addr = cpu_to_le64(req->mr->iova);
-       put_unaligned_le24(req->mr->length, sg->length);
+       xfer_len = req->mr->length;
+       /* Check if PI is added by the HW */
+       if (!pi_count)
+               xfer_len += (xfer_len >> bi->interval_exp) * ns->head->pi_size;
+       put_unaligned_le24(xfer_len, sg->length);
        put_unaligned_le32(req->mr->rkey, sg->key);
        sg->type = NVME_KEY_SGL_FMT_DATA_DESC << 4;
 
@@ -1946,14 +1951,13 @@ static enum blk_eh_timer_return nvme_rdma_timeout(struct request *rq)
        struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
        struct nvme_rdma_queue *queue = req->queue;
        struct nvme_rdma_ctrl *ctrl = queue->ctrl;
-       u8 opcode = req->req.cmd->common.opcode;
-       u8 fctype = req->req.cmd->fabrics.fctype;
+       struct nvme_command *cmd = req->req.cmd;
        int qid = nvme_rdma_queue_idx(queue);
 
        dev_warn(ctrl->ctrl.device,
                 "I/O tag %d (%04x) opcode %#x (%s) QID %d timeout\n",
-                rq->tag, nvme_cid(rq), opcode,
-                nvme_opcode_str(qid, opcode, fctype), qid);
+                rq->tag, nvme_cid(rq), cmd->common.opcode,
+                nvme_fabrics_opcode_str(qid, cmd), qid);
 
        if (nvme_ctrl_state(&ctrl->ctrl) != NVME_CTRL_LIVE) {
                /*
@@ -2296,8 +2300,8 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev,
        if (ret)
                goto out_uninit_ctrl;
 
-       dev_info(ctrl->ctrl.device, "new ctrl: NQN \"%s\", addr %pISpcs\n",
-               nvmf_ctrl_subsysnqn(&ctrl->ctrl), &ctrl->addr);
+       dev_info(ctrl->ctrl.device, "new ctrl: NQN \"%s\", addr %pISpcs, hostnqn: %s\n",
+               nvmf_ctrl_subsysnqn(&ctrl->ctrl), &ctrl->addr, opts->host->nqn);
 
        mutex_lock(&nvme_rdma_ctrl_mutex);
        list_add_tail(&ctrl->list, &nvme_rdma_ctrl_list);
@@ -2400,4 +2404,5 @@ static void __exit nvme_rdma_cleanup_module(void)
 module_init(nvme_rdma_init_module);
 module_exit(nvme_rdma_cleanup_module);
 
+MODULE_DESCRIPTION("NVMe host RDMA transport driver");
 MODULE_LICENSE("GPL v2");
index 754e911110420f5f30074762c7787a88b183830a..d099218e494a8457d546ee0e330b2095e7b9d9fc 100644 (file)
@@ -35,6 +35,62 @@ static ssize_t nvme_sysfs_rescan(struct device *dev,
 }
 static DEVICE_ATTR(rescan_controller, S_IWUSR, NULL, nvme_sysfs_rescan);
 
+static ssize_t nvme_adm_passthru_err_log_enabled_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+       return sysfs_emit(buf,
+                         ctrl->passthru_err_log_enabled ? "on\n" : "off\n");
+}
+
+static ssize_t nvme_adm_passthru_err_log_enabled_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+       int err;
+       bool passthru_err_log_enabled;
+
+       err = kstrtobool(buf, &passthru_err_log_enabled);
+       if (err)
+               return -EINVAL;
+
+       ctrl->passthru_err_log_enabled = passthru_err_log_enabled;
+
+       return count;
+}
+
+static ssize_t nvme_io_passthru_err_log_enabled_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct nvme_ns *n = dev_get_drvdata(dev);
+
+       return sysfs_emit(buf, n->passthru_err_log_enabled ? "on\n" : "off\n");
+}
+
+static ssize_t nvme_io_passthru_err_log_enabled_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct nvme_ns *ns = dev_get_drvdata(dev);
+       int err;
+       bool passthru_err_log_enabled;
+
+       err = kstrtobool(buf, &passthru_err_log_enabled);
+       if (err)
+               return -EINVAL;
+       ns->passthru_err_log_enabled = passthru_err_log_enabled;
+
+       return count;
+}
+
+static struct device_attribute dev_attr_adm_passthru_err_log_enabled = \
+       __ATTR(passthru_err_log_enabled, S_IRUGO | S_IWUSR, \
+       nvme_adm_passthru_err_log_enabled_show, nvme_adm_passthru_err_log_enabled_store);
+
+static struct device_attribute dev_attr_io_passthru_err_log_enabled = \
+       __ATTR(passthru_err_log_enabled, S_IRUGO | S_IWUSR, \
+       nvme_io_passthru_err_log_enabled_show, nvme_io_passthru_err_log_enabled_store);
+
 static inline struct nvme_ns_head *dev_to_ns_head(struct device *dev)
 {
        struct gendisk *disk = dev_to_disk(dev);
@@ -208,6 +264,7 @@ static struct attribute *nvme_ns_attrs[] = {
        &dev_attr_ana_grpid.attr,
        &dev_attr_ana_state.attr,
 #endif
+       &dev_attr_io_passthru_err_log_enabled.attr,
        NULL,
 };
 
@@ -311,6 +368,7 @@ static ssize_t nvme_sysfs_show_state(struct device *dev,
                                     char *buf)
 {
        struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+       unsigned state = (unsigned)nvme_ctrl_state(ctrl);
        static const char *const state_name[] = {
                [NVME_CTRL_NEW]         = "new",
                [NVME_CTRL_LIVE]        = "live",
@@ -321,9 +379,8 @@ static ssize_t nvme_sysfs_show_state(struct device *dev,
                [NVME_CTRL_DEAD]        = "dead",
        };
 
-       if ((unsigned)ctrl->state < ARRAY_SIZE(state_name) &&
-           state_name[ctrl->state])
-               return sysfs_emit(buf, "%s\n", state_name[ctrl->state]);
+       if (state < ARRAY_SIZE(state_name) && state_name[state])
+               return sysfs_emit(buf, "%s\n", state_name[state]);
 
        return sysfs_emit(buf, "unknown state\n");
 }
@@ -655,6 +712,7 @@ static struct attribute *nvme_dev_attrs[] = {
 #ifdef CONFIG_NVME_TCP_TLS
        &dev_attr_tls_key.attr,
 #endif
+       &dev_attr_adm_passthru_err_log_enabled.attr,
        NULL
 };
 
index d058d990532bfcf6dd521cfa51f411f60f5913fd..a6d596e05602117ff9c38fbcb86645bda4016c59 100644 (file)
@@ -2428,13 +2428,13 @@ static enum blk_eh_timer_return nvme_tcp_timeout(struct request *rq)
        struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
        struct nvme_ctrl *ctrl = &req->queue->ctrl->ctrl;
        struct nvme_tcp_cmd_pdu *pdu = nvme_tcp_req_cmd_pdu(req);
-       u8 opc = pdu->cmd.common.opcode, fctype = pdu->cmd.fabrics.fctype;
+       struct nvme_command *cmd = &pdu->cmd;
        int qid = nvme_tcp_queue_id(req->queue);
 
        dev_warn(ctrl->device,
                 "I/O tag %d (%04x) type %d opcode %#x (%s) QID %d timeout\n",
-                rq->tag, nvme_cid(rq), pdu->hdr.type, opc,
-                nvme_opcode_str(qid, opc, fctype), qid);
+                rq->tag, nvme_cid(rq), pdu->hdr.type, cmd->common.opcode,
+                nvme_fabrics_opcode_str(qid, cmd), qid);
 
        if (nvme_ctrl_state(ctrl) != NVME_CTRL_LIVE) {
                /*
@@ -2753,8 +2753,8 @@ static struct nvme_ctrl *nvme_tcp_create_ctrl(struct device *dev,
        if (ret)
                goto out_uninit_ctrl;
 
-       dev_info(ctrl->ctrl.device, "new ctrl: NQN \"%s\", addr %pISp\n",
-               nvmf_ctrl_subsysnqn(&ctrl->ctrl), &ctrl->addr);
+       dev_info(ctrl->ctrl.device, "new ctrl: NQN \"%s\", addr %pISp, hostnqn: %s\n",
+               nvmf_ctrl_subsysnqn(&ctrl->ctrl), &ctrl->addr, opts->host->nqn);
 
        mutex_lock(&nvme_tcp_ctrl_mutex);
        list_add_tail(&ctrl->list, &nvme_tcp_ctrl_list);
@@ -2826,4 +2826,5 @@ static void __exit nvme_tcp_cleanup_module(void)
 module_init(nvme_tcp_init_module);
 module_exit(nvme_tcp_cleanup_module);
 
+MODULE_DESCRIPTION("NVMe host TCP transport driver");
 MODULE_LICENSE("GPL v2");
index d26aa30f87026058fb23a1df97d10c1fe7fafbda..8658e9c08534df50c466314c6c70d18d79525324 100644 (file)
@@ -248,7 +248,7 @@ void nvmet_ns_changed(struct nvmet_subsys *subsys, u32 nsid)
                nvmet_add_to_changed_ns_log(ctrl, cpu_to_le32(nsid));
                if (nvmet_aen_bit_disabled(ctrl, NVME_AEN_BIT_NS_ATTR))
                        continue;
-               nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE,
+               nvmet_add_async_event(ctrl, NVME_AER_NOTICE,
                                NVME_AER_NOTICE_NS_CHANGED,
                                NVME_LOG_CHANGED_NS);
        }
@@ -265,7 +265,7 @@ void nvmet_send_ana_event(struct nvmet_subsys *subsys,
                        continue;
                if (nvmet_aen_bit_disabled(ctrl, NVME_AEN_BIT_ANA_CHANGE))
                        continue;
-               nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE,
+               nvmet_add_async_event(ctrl, NVME_AER_NOTICE,
                                NVME_AER_NOTICE_ANA, NVME_LOG_ANA);
        }
        mutex_unlock(&subsys->lock);
@@ -1705,4 +1705,5 @@ static void __exit nvmet_exit(void)
 module_init(nvmet_init);
 module_exit(nvmet_exit);
 
+MODULE_DESCRIPTION("NVMe target core framework");
 MODULE_LICENSE("GPL v2");
index 668d257fa98636dc1785e7b5f6bb6b35e8188ab9..68e82ccc0e4e38ffcb2018cce0080741a5984925 100644 (file)
@@ -21,7 +21,7 @@ static void __nvmet_disc_changed(struct nvmet_port *port,
        if (nvmet_aen_bit_disabled(ctrl, NVME_AEN_BIT_DISC_CHANGE))
                return;
 
-       nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE,
+       nvmet_add_async_event(ctrl, NVME_AER_NOTICE,
                              NVME_AER_NOTICE_DISC_CHANGED, NVME_LOG_DISC);
 }
 
index bda7a3009e85127ca27f99e107d61fbf1f3995f2..fd229f310c931fbfd6c3132185f2b73c135cd633 100644 (file)
@@ -111,6 +111,8 @@ struct nvmet_fc_tgtport {
        struct nvmet_fc_port_entry      *pe;
        struct kref                     ref;
        u32                             max_sg_cnt;
+
+       struct work_struct              put_work;
 };
 
 struct nvmet_fc_port_entry {
@@ -145,7 +147,6 @@ struct nvmet_fc_tgt_queue {
        struct list_head                avail_defer_list;
        struct workqueue_struct         *work_q;
        struct kref                     ref;
-       struct rcu_head                 rcu;
        /* array of fcp_iods */
        struct nvmet_fc_fcp_iod         fod[] __counted_by(sqsize);
 } __aligned(sizeof(unsigned long long));
@@ -166,10 +167,9 @@ struct nvmet_fc_tgt_assoc {
        struct nvmet_fc_hostport        *hostport;
        struct nvmet_fc_ls_iod          *rcv_disconn;
        struct list_head                a_list;
-       struct nvmet_fc_tgt_queue __rcu *queues[NVMET_NR_QUEUES + 1];
+       struct nvmet_fc_tgt_queue       *queues[NVMET_NR_QUEUES + 1];
        struct kref                     ref;
        struct work_struct              del_work;
-       struct rcu_head                 rcu;
 };
 
 
@@ -249,6 +249,13 @@ static int nvmet_fc_tgt_a_get(struct nvmet_fc_tgt_assoc *assoc);
 static void nvmet_fc_tgt_q_put(struct nvmet_fc_tgt_queue *queue);
 static int nvmet_fc_tgt_q_get(struct nvmet_fc_tgt_queue *queue);
 static void nvmet_fc_tgtport_put(struct nvmet_fc_tgtport *tgtport);
+static void nvmet_fc_put_tgtport_work(struct work_struct *work)
+{
+       struct nvmet_fc_tgtport *tgtport =
+               container_of(work, struct nvmet_fc_tgtport, put_work);
+
+       nvmet_fc_tgtport_put(tgtport);
+}
 static int nvmet_fc_tgtport_get(struct nvmet_fc_tgtport *tgtport);
 static void nvmet_fc_handle_fcp_rqst(struct nvmet_fc_tgtport *tgtport,
                                        struct nvmet_fc_fcp_iod *fod);
@@ -360,7 +367,7 @@ __nvmet_fc_finish_ls_req(struct nvmet_fc_ls_req_op *lsop)
 
        if (!lsop->req_queued) {
                spin_unlock_irqrestore(&tgtport->lock, flags);
-               return;
+               goto out_putwork;
        }
 
        list_del(&lsop->lsreq_list);
@@ -373,7 +380,8 @@ __nvmet_fc_finish_ls_req(struct nvmet_fc_ls_req_op *lsop)
                                  (lsreq->rqstlen + lsreq->rsplen),
                                  DMA_BIDIRECTIONAL);
 
-       nvmet_fc_tgtport_put(tgtport);
+out_putwork:
+       queue_work(nvmet_wq, &tgtport->put_work);
 }
 
 static int
@@ -489,8 +497,7 @@ nvmet_fc_xmt_disconnect_assoc(struct nvmet_fc_tgt_assoc *assoc)
         * message is normal. Otherwise, send unless the hostport has
         * already been invalidated by the lldd.
         */
-       if (!tgtport->ops->ls_req || !assoc->hostport ||
-           assoc->hostport->invalid)
+       if (!tgtport->ops->ls_req || assoc->hostport->invalid)
                return;
 
        lsop = kzalloc((sizeof(*lsop) +
@@ -802,14 +809,11 @@ nvmet_fc_alloc_target_queue(struct nvmet_fc_tgt_assoc *assoc,
        if (!queue)
                return NULL;
 
-       if (!nvmet_fc_tgt_a_get(assoc))
-               goto out_free_queue;
-
        queue->work_q = alloc_workqueue("ntfc%d.%d.%d", 0, 0,
                                assoc->tgtport->fc_target_port.port_num,
                                assoc->a_id, qid);
        if (!queue->work_q)
-               goto out_a_put;
+               goto out_free_queue;
 
        queue->qid = qid;
        queue->sqsize = sqsize;
@@ -831,15 +835,13 @@ nvmet_fc_alloc_target_queue(struct nvmet_fc_tgt_assoc *assoc,
                goto out_fail_iodlist;
 
        WARN_ON(assoc->queues[qid]);
-       rcu_assign_pointer(assoc->queues[qid], queue);
+       assoc->queues[qid] = queue;
 
        return queue;
 
 out_fail_iodlist:
        nvmet_fc_destroy_fcp_iodlist(assoc->tgtport, queue);
        destroy_workqueue(queue->work_q);
-out_a_put:
-       nvmet_fc_tgt_a_put(assoc);
 out_free_queue:
        kfree(queue);
        return NULL;
@@ -852,15 +854,11 @@ nvmet_fc_tgt_queue_free(struct kref *ref)
        struct nvmet_fc_tgt_queue *queue =
                container_of(ref, struct nvmet_fc_tgt_queue, ref);
 
-       rcu_assign_pointer(queue->assoc->queues[queue->qid], NULL);
-
        nvmet_fc_destroy_fcp_iodlist(queue->assoc->tgtport, queue);
 
-       nvmet_fc_tgt_a_put(queue->assoc);
-
        destroy_workqueue(queue->work_q);
 
-       kfree_rcu(queue, rcu);
+       kfree(queue);
 }
 
 static void
@@ -969,7 +967,7 @@ nvmet_fc_find_target_queue(struct nvmet_fc_tgtport *tgtport,
        rcu_read_lock();
        list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
                if (association_id == assoc->association_id) {
-                       queue = rcu_dereference(assoc->queues[qid]);
+                       queue = assoc->queues[qid];
                        if (queue &&
                            (!atomic_read(&queue->connected) ||
                             !nvmet_fc_tgt_q_get(queue)))
@@ -1078,8 +1076,6 @@ nvmet_fc_alloc_hostport(struct nvmet_fc_tgtport *tgtport, void *hosthandle)
                /* new allocation not needed */
                kfree(newhost);
                newhost = match;
-               /* no new allocation - release reference */
-               nvmet_fc_tgtport_put(tgtport);
        } else {
                newhost->tgtport = tgtport;
                newhost->hosthandle = hosthandle;
@@ -1094,23 +1090,54 @@ nvmet_fc_alloc_hostport(struct nvmet_fc_tgtport *tgtport, void *hosthandle)
 }
 
 static void
-nvmet_fc_delete_assoc(struct work_struct *work)
+nvmet_fc_delete_assoc(struct nvmet_fc_tgt_assoc *assoc)
+{
+       nvmet_fc_delete_target_assoc(assoc);
+       nvmet_fc_tgt_a_put(assoc);
+}
+
+static void
+nvmet_fc_delete_assoc_work(struct work_struct *work)
 {
        struct nvmet_fc_tgt_assoc *assoc =
                container_of(work, struct nvmet_fc_tgt_assoc, del_work);
+       struct nvmet_fc_tgtport *tgtport = assoc->tgtport;
 
-       nvmet_fc_delete_target_assoc(assoc);
-       nvmet_fc_tgt_a_put(assoc);
+       nvmet_fc_delete_assoc(assoc);
+       nvmet_fc_tgtport_put(tgtport);
+}
+
+static void
+nvmet_fc_schedule_delete_assoc(struct nvmet_fc_tgt_assoc *assoc)
+{
+       nvmet_fc_tgtport_get(assoc->tgtport);
+       queue_work(nvmet_wq, &assoc->del_work);
+}
+
+static bool
+nvmet_fc_assoc_exits(struct nvmet_fc_tgtport *tgtport, u64 association_id)
+{
+       struct nvmet_fc_tgt_assoc *a;
+
+       list_for_each_entry_rcu(a, &tgtport->assoc_list, a_list) {
+               if (association_id == a->association_id)
+                       return true;
+       }
+
+       return false;
 }
 
 static struct nvmet_fc_tgt_assoc *
 nvmet_fc_alloc_target_assoc(struct nvmet_fc_tgtport *tgtport, void *hosthandle)
 {
-       struct nvmet_fc_tgt_assoc *assoc, *tmpassoc;
+       struct nvmet_fc_tgt_assoc *assoc;
        unsigned long flags;
+       bool done;
        u64 ran;
        int idx;
-       bool needrandom = true;
+
+       if (!tgtport->pe)
+               return NULL;
 
        assoc = kzalloc(sizeof(*assoc), GFP_KERNEL);
        if (!assoc)
@@ -1120,43 +1147,35 @@ nvmet_fc_alloc_target_assoc(struct nvmet_fc_tgtport *tgtport, void *hosthandle)
        if (idx < 0)
                goto out_free_assoc;
 
-       if (!nvmet_fc_tgtport_get(tgtport))
-               goto out_ida;
-
        assoc->hostport = nvmet_fc_alloc_hostport(tgtport, hosthandle);
        if (IS_ERR(assoc->hostport))
-               goto out_put;
+               goto out_ida;
 
        assoc->tgtport = tgtport;
        assoc->a_id = idx;
        INIT_LIST_HEAD(&assoc->a_list);
        kref_init(&assoc->ref);
-       INIT_WORK(&assoc->del_work, nvmet_fc_delete_assoc);
+       INIT_WORK(&assoc->del_work, nvmet_fc_delete_assoc_work);
        atomic_set(&assoc->terminating, 0);
 
-       while (needrandom) {
+       done = false;
+       do {
                get_random_bytes(&ran, sizeof(ran) - BYTES_FOR_QID);
                ran = ran << BYTES_FOR_QID_SHIFT;
 
                spin_lock_irqsave(&tgtport->lock, flags);
-               needrandom = false;
-               list_for_each_entry(tmpassoc, &tgtport->assoc_list, a_list) {
-                       if (ran == tmpassoc->association_id) {
-                               needrandom = true;
-                               break;
-                       }
-               }
-               if (!needrandom) {
+               rcu_read_lock();
+               if (!nvmet_fc_assoc_exits(tgtport, ran)) {
                        assoc->association_id = ran;
                        list_add_tail_rcu(&assoc->a_list, &tgtport->assoc_list);
+                       done = true;
                }
+               rcu_read_unlock();
                spin_unlock_irqrestore(&tgtport->lock, flags);
-       }
+       } while (!done);
 
        return assoc;
 
-out_put:
-       nvmet_fc_tgtport_put(tgtport);
 out_ida:
        ida_free(&tgtport->assoc_cnt, idx);
 out_free_assoc:
@@ -1172,13 +1191,18 @@ nvmet_fc_target_assoc_free(struct kref *ref)
        struct nvmet_fc_tgtport *tgtport = assoc->tgtport;
        struct nvmet_fc_ls_iod  *oldls;
        unsigned long flags;
+       int i;
+
+       for (i = NVMET_NR_QUEUES; i >= 0; i--) {
+               if (assoc->queues[i])
+                       nvmet_fc_delete_target_queue(assoc->queues[i]);
+       }
 
        /* Send Disconnect now that all i/o has completed */
        nvmet_fc_xmt_disconnect_assoc(assoc);
 
        nvmet_fc_free_hostport(assoc->hostport);
        spin_lock_irqsave(&tgtport->lock, flags);
-       list_del_rcu(&assoc->a_list);
        oldls = assoc->rcv_disconn;
        spin_unlock_irqrestore(&tgtport->lock, flags);
        /* if pending Rcv Disconnect Association LS, send rsp now */
@@ -1188,8 +1212,7 @@ nvmet_fc_target_assoc_free(struct kref *ref)
        dev_info(tgtport->dev,
                "{%d:%d} Association freed\n",
                tgtport->fc_target_port.port_num, assoc->a_id);
-       kfree_rcu(assoc, rcu);
-       nvmet_fc_tgtport_put(tgtport);
+       kfree(assoc);
 }
 
 static void
@@ -1208,7 +1231,7 @@ static void
 nvmet_fc_delete_target_assoc(struct nvmet_fc_tgt_assoc *assoc)
 {
        struct nvmet_fc_tgtport *tgtport = assoc->tgtport;
-       struct nvmet_fc_tgt_queue *queue;
+       unsigned long flags;
        int i, terminating;
 
        terminating = atomic_xchg(&assoc->terminating, 1);
@@ -1217,29 +1240,21 @@ nvmet_fc_delete_target_assoc(struct nvmet_fc_tgt_assoc *assoc)
        if (terminating)
                return;
 
+       spin_lock_irqsave(&tgtport->lock, flags);
+       list_del_rcu(&assoc->a_list);
+       spin_unlock_irqrestore(&tgtport->lock, flags);
 
-       for (i = NVMET_NR_QUEUES; i >= 0; i--) {
-               rcu_read_lock();
-               queue = rcu_dereference(assoc->queues[i]);
-               if (!queue) {
-                       rcu_read_unlock();
-                       continue;
-               }
+       synchronize_rcu();
 
-               if (!nvmet_fc_tgt_q_get(queue)) {
-                       rcu_read_unlock();
-                       continue;
-               }
-               rcu_read_unlock();
-               nvmet_fc_delete_target_queue(queue);
-               nvmet_fc_tgt_q_put(queue);
+       /* ensure all in-flight I/Os have been processed */
+       for (i = NVMET_NR_QUEUES; i >= 0; i--) {
+               if (assoc->queues[i])
+                       flush_workqueue(assoc->queues[i]->work_q);
        }
 
        dev_info(tgtport->dev,
                "{%d:%d} Association deleted\n",
                tgtport->fc_target_port.port_num, assoc->a_id);
-
-       nvmet_fc_tgt_a_put(assoc);
 }
 
 static struct nvmet_fc_tgt_assoc *
@@ -1415,6 +1430,7 @@ nvmet_fc_register_targetport(struct nvmet_fc_port_info *pinfo,
        kref_init(&newrec->ref);
        ida_init(&newrec->assoc_cnt);
        newrec->max_sg_cnt = template->max_sgl_segments;
+       INIT_WORK(&newrec->put_work, nvmet_fc_put_tgtport_work);
 
        ret = nvmet_fc_alloc_ls_iodlist(newrec);
        if (ret) {
@@ -1492,9 +1508,8 @@ __nvmet_fc_free_assocs(struct nvmet_fc_tgtport *tgtport)
        list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
                if (!nvmet_fc_tgt_a_get(assoc))
                        continue;
-               if (!queue_work(nvmet_wq, &assoc->del_work))
-                       /* already deleting - release local reference */
-                       nvmet_fc_tgt_a_put(assoc);
+               nvmet_fc_schedule_delete_assoc(assoc);
+               nvmet_fc_tgt_a_put(assoc);
        }
        rcu_read_unlock();
 }
@@ -1540,16 +1555,14 @@ nvmet_fc_invalidate_host(struct nvmet_fc_target_port *target_port,
        spin_lock_irqsave(&tgtport->lock, flags);
        list_for_each_entry_safe(assoc, next,
                                &tgtport->assoc_list, a_list) {
-               if (!assoc->hostport ||
-                   assoc->hostport->hosthandle != hosthandle)
+               if (assoc->hostport->hosthandle != hosthandle)
                        continue;
                if (!nvmet_fc_tgt_a_get(assoc))
                        continue;
                assoc->hostport->invalid = 1;
                noassoc = false;
-               if (!queue_work(nvmet_wq, &assoc->del_work))
-                       /* already deleting - release local reference */
-                       nvmet_fc_tgt_a_put(assoc);
+               nvmet_fc_schedule_delete_assoc(assoc);
+               nvmet_fc_tgt_a_put(assoc);
        }
        spin_unlock_irqrestore(&tgtport->lock, flags);
 
@@ -1581,7 +1594,7 @@ nvmet_fc_delete_ctrl(struct nvmet_ctrl *ctrl)
 
                rcu_read_lock();
                list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
-                       queue = rcu_dereference(assoc->queues[0]);
+                       queue = assoc->queues[0];
                        if (queue && queue->nvme_sq.ctrl == ctrl) {
                                if (nvmet_fc_tgt_a_get(assoc))
                                        found_ctrl = true;
@@ -1593,9 +1606,8 @@ nvmet_fc_delete_ctrl(struct nvmet_ctrl *ctrl)
                nvmet_fc_tgtport_put(tgtport);
 
                if (found_ctrl) {
-                       if (!queue_work(nvmet_wq, &assoc->del_work))
-                               /* already deleting - release local reference */
-                               nvmet_fc_tgt_a_put(assoc);
+                       nvmet_fc_schedule_delete_assoc(assoc);
+                       nvmet_fc_tgt_a_put(assoc);
                        return;
                }
 
@@ -1625,6 +1637,8 @@ nvmet_fc_unregister_targetport(struct nvmet_fc_target_port *target_port)
        /* terminate any outstanding associations */
        __nvmet_fc_free_assocs(tgtport);
 
+       flush_workqueue(nvmet_wq);
+
        /*
         * should terminate LS's as well. However, LS's will be generated
         * at the tail end of association termination, so they likely don't
@@ -1870,9 +1884,6 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport,
                                sizeof(struct fcnvme_ls_disconnect_assoc_acc)),
                        FCNVME_LS_DISCONNECT_ASSOC);
 
-       /* release get taken in nvmet_fc_find_target_assoc */
-       nvmet_fc_tgt_a_put(assoc);
-
        /*
         * The rules for LS response says the response cannot
         * go back until ABTS's have been sent for all outstanding
@@ -1887,8 +1898,6 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport,
        assoc->rcv_disconn = iod;
        spin_unlock_irqrestore(&tgtport->lock, flags);
 
-       nvmet_fc_delete_target_assoc(assoc);
-
        if (oldls) {
                dev_info(tgtport->dev,
                        "{%d:%d} Multiple Disconnect Association LS's "
@@ -1904,6 +1913,9 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport,
                nvmet_fc_xmt_ls_rsp(tgtport, oldls);
        }
 
+       nvmet_fc_schedule_delete_assoc(assoc);
+       nvmet_fc_tgt_a_put(assoc);
+
        return false;
 }
 
@@ -2540,8 +2552,9 @@ nvmet_fc_handle_fcp_rqst(struct nvmet_fc_tgtport *tgtport,
 
        fod->req.cmd = &fod->cmdiubuf.sqe;
        fod->req.cqe = &fod->rspiubuf.cqe;
-       if (tgtport->pe)
-               fod->req.port = tgtport->pe->port;
+       if (!tgtport->pe)
+               goto transport_error;
+       fod->req.port = tgtport->pe->port;
 
        /* clear any response payload */
        memset(&fod->rspiubuf, 0, sizeof(fod->rspiubuf));
@@ -2902,6 +2915,9 @@ nvmet_fc_remove_port(struct nvmet_port *port)
 
        nvmet_fc_portentry_unbind(pe);
 
+       /* terminate any outstanding associations */
+       __nvmet_fc_free_assocs(pe->tgtport);
+
        kfree(pe);
 }
 
@@ -2933,6 +2949,9 @@ static int __init nvmet_fc_init_module(void)
 
 static void __exit nvmet_fc_exit_module(void)
 {
+       /* ensure any shutdown operation, e.g. delete ctrls have finished */
+       flush_workqueue(nvmet_wq);
+
        /* sanity check - all lports should be removed */
        if (!list_empty(&nvmet_fc_target_list))
                pr_warn("%s: targetport list not empty\n", __func__);
@@ -2945,4 +2964,5 @@ static void __exit nvmet_fc_exit_module(void)
 module_init(nvmet_fc_init_module);
 module_exit(nvmet_fc_exit_module);
 
+MODULE_DESCRIPTION("NVMe target FC transport driver");
 MODULE_LICENSE("GPL v2");
index ead349af30f1e0c87ee0adde980aa98b5fdb0e8a..1471af250ea62267a812bdb402b05ff9099cfcb6 100644 (file)
@@ -358,7 +358,7 @@ fcloop_h2t_ls_req(struct nvme_fc_local_port *localport,
        if (!rport->targetport) {
                tls_req->status = -ECONNREFUSED;
                spin_lock(&rport->lock);
-               list_add_tail(&rport->ls_list, &tls_req->ls_list);
+               list_add_tail(&tls_req->ls_list, &rport->ls_list);
                spin_unlock(&rport->lock);
                queue_work(nvmet_wq, &rport->ls_work);
                return ret;
@@ -391,7 +391,7 @@ fcloop_h2t_xmt_ls_rsp(struct nvmet_fc_target_port *targetport,
        if (remoteport) {
                rport = remoteport->private;
                spin_lock(&rport->lock);
-               list_add_tail(&rport->ls_list, &tls_req->ls_list);
+               list_add_tail(&tls_req->ls_list, &rport->ls_list);
                spin_unlock(&rport->lock);
                queue_work(nvmet_wq, &rport->ls_work);
        }
@@ -446,7 +446,7 @@ fcloop_t2h_ls_req(struct nvmet_fc_target_port *targetport, void *hosthandle,
        if (!tport->remoteport) {
                tls_req->status = -ECONNREFUSED;
                spin_lock(&tport->lock);
-               list_add_tail(&tport->ls_list, &tls_req->ls_list);
+               list_add_tail(&tls_req->ls_list, &tport->ls_list);
                spin_unlock(&tport->lock);
                queue_work(nvmet_wq, &tport->ls_work);
                return ret;
@@ -1650,4 +1650,5 @@ static void __exit fcloop_exit(void)
 module_init(fcloop_init);
 module_exit(fcloop_exit);
 
+MODULE_DESCRIPTION("NVMe target FC loop transport driver");
 MODULE_LICENSE("GPL v2");
index 9cb434c5807514813afe91eada69c0a925daf83a..e589915ddef85cf5f67fcba50deed724b37616d3 100644 (file)
@@ -400,7 +400,7 @@ static void nvme_loop_shutdown_ctrl(struct nvme_loop_ctrl *ctrl)
        }
 
        nvme_quiesce_admin_queue(&ctrl->ctrl);
-       if (ctrl->ctrl.state == NVME_CTRL_LIVE)
+       if (nvme_ctrl_state(&ctrl->ctrl) == NVME_CTRL_LIVE)
                nvme_disable_ctrl(&ctrl->ctrl, true);
 
        nvme_cancel_admin_tagset(&ctrl->ctrl);
@@ -434,8 +434,10 @@ static void nvme_loop_reset_ctrl_work(struct work_struct *work)
        nvme_loop_shutdown_ctrl(ctrl);
 
        if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) {
-               if (ctrl->ctrl.state != NVME_CTRL_DELETING &&
-                   ctrl->ctrl.state != NVME_CTRL_DELETING_NOIO)
+               enum nvme_ctrl_state state = nvme_ctrl_state(&ctrl->ctrl);
+
+               if (state != NVME_CTRL_DELETING &&
+                   state != NVME_CTRL_DELETING_NOIO)
                        /* state change failure for non-deleted ctrl? */
                        WARN_ON_ONCE(1);
                return;
@@ -688,5 +690,6 @@ static void __exit nvme_loop_cleanup_module(void)
 module_init(nvme_loop_init_module);
 module_exit(nvme_loop_cleanup_module);
 
+MODULE_DESCRIPTION("NVMe target loop transport driver");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("nvmet-transport-254"); /* 254 == NVMF_TRTYPE_LOOP */
index 667f9c04f35d538bb361f733e50c62bb7c52d9c3..3a0f2c170f4c16f6c1fa6f09c2cac948403550fb 100644 (file)
@@ -2104,5 +2104,6 @@ static void __exit nvmet_rdma_exit(void)
 module_init(nvmet_rdma_init);
 module_exit(nvmet_rdma_exit);
 
+MODULE_DESCRIPTION("NVMe target RDMA transport driver");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("nvmet-transport-1"); /* 1 == NVMF_TRTYPE_RDMA */
index 6a1e6bb80062d4753501e07cbcba43870fc00eeb..c8655fc5aa5b8aac838cb4c2e4c0a76c8ebbc174 100644 (file)
@@ -2216,10 +2216,12 @@ static void __exit nvmet_tcp_exit(void)
        flush_workqueue(nvmet_wq);
 
        destroy_workqueue(nvmet_tcp_wq);
+       ida_destroy(&nvmet_tcp_queue_ida);
 }
 
 module_init(nvmet_tcp_init);
 module_exit(nvmet_tcp_exit);
 
+MODULE_DESCRIPTION("NVMe target TCP transport driver");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("nvmet-transport-3"); /* 3 == NVMF_TRTYPE_TCP */
index 9c2137dae429aa26cd69bfaadb9706193946b2b8..826b5016a101022b990045fa7b68afe85be80c7a 100644 (file)
@@ -386,21 +386,8 @@ void pci_bus_add_devices(const struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pci_bus_add_devices);
 
-/** pci_walk_bus - walk devices on/under bus, calling callback.
- *  @top      bus whose devices should be walked
- *  @cb       callback to be called for each device found
- *  @userdata arbitrary pointer to be passed to callback.
- *
- *  Walk the given bus, including any bridged devices
- *  on buses under this bus.  Call the provided callback
- *  on each device found.
- *
- *  We check the return of @cb each time. If it returns anything
- *  other than 0, we break out.
- *
- */
-void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
-                 void *userdata)
+static void __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
+                          void *userdata, bool locked)
 {
        struct pci_dev *dev;
        struct pci_bus *bus;
@@ -408,7 +395,8 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
        int retval;
 
        bus = top;
-       down_read(&pci_bus_sem);
+       if (!locked)
+               down_read(&pci_bus_sem);
        next = top->devices.next;
        for (;;) {
                if (next == &bus->devices) {
@@ -431,10 +419,37 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
                if (retval)
                        break;
        }
-       up_read(&pci_bus_sem);
+       if (!locked)
+               up_read(&pci_bus_sem);
+}
+
+/**
+ *  pci_walk_bus - walk devices on/under bus, calling callback.
+ *  @top: bus whose devices should be walked
+ *  @cb: callback to be called for each device found
+ *  @userdata: arbitrary pointer to be passed to callback
+ *
+ *  Walk the given bus, including any bridged devices
+ *  on buses under this bus.  Call the provided callback
+ *  on each device found.
+ *
+ *  We check the return of @cb each time. If it returns anything
+ *  other than 0, we break out.
+ */
+void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata)
+{
+       __pci_walk_bus(top, cb, userdata, false);
 }
 EXPORT_SYMBOL_GPL(pci_walk_bus);
 
+void pci_walk_bus_locked(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata)
+{
+       lockdep_assert_held(&pci_bus_sem);
+
+       __pci_walk_bus(top, cb, userdata, true);
+}
+EXPORT_SYMBOL_GPL(pci_walk_bus_locked);
+
 struct pci_bus *pci_bus_get(struct pci_bus *bus)
 {
        if (bus)
index 10f2d0bb86bec008e82e6a86211161c693ae568e..2ce2a3bd932bd7e3824b69cc9450135895b7a89e 100644 (file)
@@ -972,7 +972,7 @@ static int qcom_pcie_enable_aspm(struct pci_dev *pdev, void *userdata)
         * Downstream devices need to be in D0 state before enabling PCI PM
         * substates.
         */
-       pci_set_power_state(pdev, PCI_D0);
+       pci_set_power_state_locked(pdev, PCI_D0);
        pci_enable_link_state_locked(pdev, PCIE_LINK_STATE_ALL);
 
        return 0;
index d8f11a078924c1336326456b0e3f37f7b0e66df9..9ab9b1008d8b9de897f1a1372f128e849b8a73a2 100644 (file)
@@ -1354,6 +1354,7 @@ end:
 /**
  * pci_set_full_power_state - Put a PCI device into D0 and update its state
  * @dev: PCI device to power up
+ * @locked: whether pci_bus_sem is held
  *
  * Call pci_power_up() to put @dev into D0, read from its PCI_PM_CTRL register
  * to confirm the state change, restore its BARs if they might be lost and
@@ -1363,7 +1364,7 @@ end:
  * to D0, it is more efficient to use pci_power_up() directly instead of this
  * function.
  */
-static int pci_set_full_power_state(struct pci_dev *dev)
+static int pci_set_full_power_state(struct pci_dev *dev, bool locked)
 {
        u16 pmcsr;
        int ret;
@@ -1399,7 +1400,7 @@ static int pci_set_full_power_state(struct pci_dev *dev)
        }
 
        if (dev->bus->self)
-               pcie_aspm_pm_state_change(dev->bus->self);
+               pcie_aspm_pm_state_change(dev->bus->self, locked);
 
        return 0;
 }
@@ -1428,10 +1429,22 @@ void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
                pci_walk_bus(bus, __pci_dev_set_current_state, &state);
 }
 
+static void __pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state, bool locked)
+{
+       if (!bus)
+               return;
+
+       if (locked)
+               pci_walk_bus_locked(bus, __pci_dev_set_current_state, &state);
+       else
+               pci_walk_bus(bus, __pci_dev_set_current_state, &state);
+}
+
 /**
  * pci_set_low_power_state - Put a PCI device into a low-power state.
  * @dev: PCI device to handle.
  * @state: PCI power state (D1, D2, D3hot) to put the device into.
+ * @locked: whether pci_bus_sem is held
  *
  * Use the device's PCI_PM_CTRL register to put it into a low-power state.
  *
@@ -1442,7 +1455,7 @@ void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
  * 0 if device already is in the requested state.
  * 0 if device's power state has been successfully changed.
  */
-static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state)
+static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state, bool locked)
 {
        u16 pmcsr;
 
@@ -1496,29 +1509,12 @@ static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state)
                                     pci_power_name(state));
 
        if (dev->bus->self)
-               pcie_aspm_pm_state_change(dev->bus->self);
+               pcie_aspm_pm_state_change(dev->bus->self, locked);
 
        return 0;
 }
 
-/**
- * pci_set_power_state - Set the power state of a PCI device
- * @dev: PCI device to handle.
- * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
- *
- * Transition a device to a new power state, using the platform firmware and/or
- * the device's PCI PM registers.
- *
- * RETURN VALUE:
- * -EINVAL if the requested state is invalid.
- * -EIO if device does not support PCI PM or its PM capabilities register has a
- * wrong version, or device doesn't support the requested state.
- * 0 if the transition is to D1 or D2 but D1 and D2 are not supported.
- * 0 if device already is in the requested state.
- * 0 if the transition is to D3 but D3 is not supported.
- * 0 if device's power state has been successfully changed.
- */
-int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
+static int __pci_set_power_state(struct pci_dev *dev, pci_power_t state, bool locked)
 {
        int error;
 
@@ -1542,7 +1538,7 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
                return 0;
 
        if (state == PCI_D0)
-               return pci_set_full_power_state(dev);
+               return pci_set_full_power_state(dev, locked);
 
        /*
         * This device is quirked not to be put into D3, so don't put it in
@@ -1556,16 +1552,16 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
                 * To put the device in D3cold, put it into D3hot in the native
                 * way, then put it into D3cold using platform ops.
                 */
-               error = pci_set_low_power_state(dev, PCI_D3hot);
+               error = pci_set_low_power_state(dev, PCI_D3hot, locked);
 
                if (pci_platform_power_transition(dev, PCI_D3cold))
                        return error;
 
                /* Powering off a bridge may power off the whole hierarchy */
                if (dev->current_state == PCI_D3cold)
-                       pci_bus_set_current_state(dev->subordinate, PCI_D3cold);
+                       __pci_bus_set_current_state(dev->subordinate, PCI_D3cold, locked);
        } else {
-               error = pci_set_low_power_state(dev, state);
+               error = pci_set_low_power_state(dev, state, locked);
 
                if (pci_platform_power_transition(dev, state))
                        return error;
@@ -1573,8 +1569,38 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 
        return 0;
 }
+
+/**
+ * pci_set_power_state - Set the power state of a PCI device
+ * @dev: PCI device to handle.
+ * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
+ *
+ * Transition a device to a new power state, using the platform firmware and/or
+ * the device's PCI PM registers.
+ *
+ * RETURN VALUE:
+ * -EINVAL if the requested state is invalid.
+ * -EIO if device does not support PCI PM or its PM capabilities register has a
+ * wrong version, or device doesn't support the requested state.
+ * 0 if the transition is to D1 or D2 but D1 and D2 are not supported.
+ * 0 if device already is in the requested state.
+ * 0 if the transition is to D3 but D3 is not supported.
+ * 0 if device's power state has been successfully changed.
+ */
+int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
+{
+       return __pci_set_power_state(dev, state, false);
+}
 EXPORT_SYMBOL(pci_set_power_state);
 
+int pci_set_power_state_locked(struct pci_dev *dev, pci_power_t state)
+{
+       lockdep_assert_held(&pci_bus_sem);
+
+       return __pci_set_power_state(dev, state, true);
+}
+EXPORT_SYMBOL(pci_set_power_state_locked);
+
 #define PCI_EXP_SAVE_REGS      7
 
 static struct pci_cap_saved_state *_pci_find_saved_cap(struct pci_dev *pci_dev,
index 2336a8d1edab27646220794a3a4cdd085ba7b3e9..e9750b1b19bad5bfc500909f390f1d890f5eab73 100644 (file)
@@ -571,12 +571,12 @@ int pcie_retrain_link(struct pci_dev *pdev, bool use_lt);
 #ifdef CONFIG_PCIEASPM
 void pcie_aspm_init_link_state(struct pci_dev *pdev);
 void pcie_aspm_exit_link_state(struct pci_dev *pdev);
-void pcie_aspm_pm_state_change(struct pci_dev *pdev);
+void pcie_aspm_pm_state_change(struct pci_dev *pdev, bool locked);
 void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
 #else
 static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { }
 static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { }
-static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { }
+static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev, bool locked) { }
 static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
 #endif
 
index 5a0066ecc3c5adcc97e14f08f166c783f254f6e9..bc0bd86695ec62a2d43428b69eb562f771334bb3 100644 (file)
@@ -1003,8 +1003,11 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
        up_read(&pci_bus_sem);
 }
 
-/* @pdev: the root port or switch downstream port */
-void pcie_aspm_pm_state_change(struct pci_dev *pdev)
+/*
+ * @pdev: the root port or switch downstream port
+ * @locked: whether pci_bus_sem is held
+ */
+void pcie_aspm_pm_state_change(struct pci_dev *pdev, bool locked)
 {
        struct pcie_link_state *link = pdev->link_state;
 
@@ -1014,12 +1017,14 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev)
         * Devices changed PM state, we should recheck if latency
         * meets all functions' requirement
         */
-       down_read(&pci_bus_sem);
+       if (!locked)
+               down_read(&pci_bus_sem);
        mutex_lock(&aspm_lock);
        pcie_update_aspm_capable(link->root);
        pcie_config_aspm_path(link);
        mutex_unlock(&aspm_lock);
-       up_read(&pci_bus_sem);
+       if (!locked)
+               up_read(&pci_bus_sem);
 }
 
 void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
index 1dd84c7a79de97f44b25c48fd241db068492b4f9..b1995ac268d77a9c56c81ce6e65048e2c465c449 100644 (file)
@@ -1170,7 +1170,7 @@ static int mlxbf_pmc_program_crspace_counter(int blk_num, uint32_t cnt_num,
        int ret;
 
        addr = pmc->block[blk_num].mmio_base +
-               (rounddown(cnt_num, 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ);
+               ((cnt_num / 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ);
        ret = mlxbf_pmc_readl(addr, &word);
        if (ret)
                return ret;
@@ -1413,7 +1413,7 @@ static int mlxbf_pmc_read_crspace_event(int blk_num, uint32_t cnt_num,
        int ret;
 
        addr = pmc->block[blk_num].mmio_base +
-               (rounddown(cnt_num, 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ);
+               ((cnt_num / 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ);
        ret = mlxbf_pmc_readl(addr, &word);
        if (ret)
                return ret;
index ed16ec422a7b33e9b529bfe1912d0ff687e4db5d..b8d1e32e97ebafaa1d0091d32d110b9854022ff9 100644 (file)
@@ -47,6 +47,9 @@
 /* Message with data needs at least two words (for header & data). */
 #define MLXBF_TMFIFO_DATA_MIN_WORDS            2
 
+/* Tx timeout in milliseconds. */
+#define TMFIFO_TX_TIMEOUT                      2000
+
 /* ACPI UID for BlueField-3. */
 #define TMFIFO_BF3_UID                         1
 
@@ -62,12 +65,14 @@ struct mlxbf_tmfifo;
  * @drop_desc: dummy desc for packet dropping
  * @cur_len: processed length of the current descriptor
  * @rem_len: remaining length of the pending packet
+ * @rem_padding: remaining bytes to send as paddings
  * @pkt_len: total length of the pending packet
  * @next_avail: next avail descriptor id
  * @num: vring size (number of descriptors)
  * @align: vring alignment size
  * @index: vring index
  * @vdev_id: vring virtio id (VIRTIO_ID_xxx)
+ * @tx_timeout: expire time of last tx packet
  * @fifo: pointer to the tmfifo structure
  */
 struct mlxbf_tmfifo_vring {
@@ -79,12 +84,14 @@ struct mlxbf_tmfifo_vring {
        struct vring_desc drop_desc;
        int cur_len;
        int rem_len;
+       int rem_padding;
        u32 pkt_len;
        u16 next_avail;
        int num;
        int align;
        int index;
        int vdev_id;
+       unsigned long tx_timeout;
        struct mlxbf_tmfifo *fifo;
 };
 
@@ -819,6 +826,50 @@ mlxbf_tmfifo_desc_done:
        return true;
 }
 
+static void mlxbf_tmfifo_check_tx_timeout(struct mlxbf_tmfifo_vring *vring)
+{
+       unsigned long flags;
+
+       /* Only handle Tx timeout for network vdev. */
+       if (vring->vdev_id != VIRTIO_ID_NET)
+               return;
+
+       /* Initialize the timeout or return if not expired. */
+       if (!vring->tx_timeout) {
+               /* Initialize the timeout. */
+               vring->tx_timeout = jiffies +
+                       msecs_to_jiffies(TMFIFO_TX_TIMEOUT);
+               return;
+       } else if (time_before(jiffies, vring->tx_timeout)) {
+               /* Return if not timeout yet. */
+               return;
+       }
+
+       /*
+        * Drop the packet after timeout. The outstanding packet is
+        * released and the remaining bytes will be sent with padding byte 0x00
+        * as a recovery. On the peer(host) side, the padding bytes 0x00 will be
+        * either dropped directly, or appended into existing outstanding packet
+        * thus dropped as corrupted network packet.
+        */
+       vring->rem_padding = round_up(vring->rem_len, sizeof(u64));
+       mlxbf_tmfifo_release_pkt(vring);
+       vring->cur_len = 0;
+       vring->rem_len = 0;
+       vring->fifo->vring[0] = NULL;
+
+       /*
+        * Make sure the load/store are in order before
+        * returning back to virtio.
+        */
+       virtio_mb(false);
+
+       /* Notify upper layer. */
+       spin_lock_irqsave(&vring->fifo->spin_lock[0], flags);
+       vring_interrupt(0, vring->vq);
+       spin_unlock_irqrestore(&vring->fifo->spin_lock[0], flags);
+}
+
 /* Rx & Tx processing of a queue. */
 static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
 {
@@ -841,6 +892,7 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
                return;
 
        do {
+retry:
                /* Get available FIFO space. */
                if (avail == 0) {
                        if (is_rx)
@@ -851,6 +903,17 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
                                break;
                }
 
+               /* Insert paddings for discarded Tx packet. */
+               if (!is_rx) {
+                       vring->tx_timeout = 0;
+                       while (vring->rem_padding >= sizeof(u64)) {
+                               writeq(0, vring->fifo->tx.data);
+                               vring->rem_padding -= sizeof(u64);
+                               if (--avail == 0)
+                                       goto retry;
+                       }
+               }
+
                /* Console output always comes from the Tx buffer. */
                if (!is_rx && devid == VIRTIO_ID_CONSOLE) {
                        mlxbf_tmfifo_console_tx(fifo, avail);
@@ -860,6 +923,10 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx)
                /* Handle one descriptor. */
                more = mlxbf_tmfifo_rxtx_one_desc(vring, is_rx, &avail);
        } while (more);
+
+       /* Check Tx timeout. */
+       if (avail <= 0 && !is_rx)
+               mlxbf_tmfifo_check_tx_timeout(vring);
 }
 
 /* Handle Rx or Tx queues. */
index f246252bddd85d97f3232617a53cb437b75a92c0..f4fa8bd8bda832a622078d84e2a7181d5f65cb88 100644 (file)
@@ -10,6 +10,7 @@ config AMD_PMF
        depends on AMD_NB
        select ACPI_PLATFORM_PROFILE
        depends on TEE && AMDTEE
+       depends on AMD_SFH_HID
        help
          This driver provides support for the AMD Platform Management Framework.
          The goal is to enhance end user experience by making AMD PCs smarter,
index a0423942f771e457457cc88cb604913eeb5b2657..a3dec14c30043ecc9c1d109247452d6d19949976 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <acpi/button.h>
+#include <linux/amd-pmf-io.h>
 #include <linux/power_supply.h>
 #include <linux/units.h>
 #include "pmf.h"
@@ -44,6 +45,8 @@ void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *
        dev_dbg(dev->dev, "Max C0 Residency: %u\n", in->ev_info.max_c0residency);
        dev_dbg(dev->dev, "GFX Busy: %u\n", in->ev_info.gfx_busy);
        dev_dbg(dev->dev, "LID State: %s\n", in->ev_info.lid_state ? "close" : "open");
+       dev_dbg(dev->dev, "User Presence: %s\n", in->ev_info.user_present ? "Present" : "Away");
+       dev_dbg(dev->dev, "Ambient Light: %d\n", in->ev_info.ambient_light);
        dev_dbg(dev->dev, "==== TA inputs END ====\n");
 }
 #else
@@ -147,6 +150,38 @@ static int amd_pmf_get_slider_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_
        return 0;
 }
 
+static int amd_pmf_get_sensor_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
+{
+       struct amd_sfh_info sfh_info;
+       int ret;
+
+       /* Get ALS data */
+       ret = amd_get_sfh_info(&sfh_info, MT_ALS);
+       if (!ret)
+               in->ev_info.ambient_light = sfh_info.ambient_light;
+       else
+               return ret;
+
+       /* get HPD data */
+       ret = amd_get_sfh_info(&sfh_info, MT_HPD);
+       if (ret)
+               return ret;
+
+       switch (sfh_info.user_present) {
+       case SFH_NOT_DETECTED:
+               in->ev_info.user_present = 0xff; /* assume no sensors connected */
+               break;
+       case SFH_USER_PRESENT:
+               in->ev_info.user_present = 1;
+               break;
+       case SFH_USER_AWAY:
+               in->ev_info.user_present = 0;
+               break;
+       }
+
+       return 0;
+}
+
 void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
 {
        /* TA side lid open is 1 and close is 0, hence the ! here */
@@ -155,4 +190,5 @@ void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_tab
        amd_pmf_get_smu_info(dev, in);
        amd_pmf_get_battery_info(dev, in);
        amd_pmf_get_slider_info(dev, in);
+       amd_pmf_get_sensor_info(dev, in);
 }
index 502ce93d5cddac57f2f482080ea8a0800ea5123f..f8c0177afb0dae60d4f67f2876ba98c6100d1ceb 100644 (file)
@@ -298,8 +298,10 @@ static ssize_t amd_pmf_get_pb_data(struct file *filp, const char __user *buf,
        if (!new_policy_buf)
                return -ENOMEM;
 
-       if (copy_from_user(new_policy_buf, buf, length))
+       if (copy_from_user(new_policy_buf, buf, length)) {
+               kfree(new_policy_buf);
                return -EFAULT;
+       }
 
        kfree(dev->policy_buf);
        dev->policy_buf = new_policy_buf;
index a1ee1a74fc3c4cb7e7bc62cda0297acdbe942d54..2cf3b4a8813f9b30cb5a79aaf2ee6acee2474c68 100644 (file)
@@ -399,7 +399,8 @@ int ifs_load_firmware(struct device *dev)
        if (fw->size != expected_size) {
                dev_err(dev, "File size mismatch (expected %u, actual %zu). Corrupted IFS image.\n",
                        expected_size, fw->size);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto release;
        }
 
        ret = image_sanity_check(dev, (struct microcode_header_intel *)fw->data);
index 33ab207493e3e62946dc5d76c2eda98805725888..33bb58dc3f78c30a304a7a35595666152c34e908 100644 (file)
@@ -23,23 +23,23 @@ static int (*uncore_read)(struct uncore_data *data, unsigned int *min, unsigned
 static int (*uncore_write)(struct uncore_data *data, unsigned int input, unsigned int min_max);
 static int (*uncore_read_freq)(struct uncore_data *data, unsigned int *freq);
 
-static ssize_t show_domain_id(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_domain_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
-       struct uncore_data *data = container_of(attr, struct uncore_data, domain_id_dev_attr);
+       struct uncore_data *data = container_of(attr, struct uncore_data, domain_id_kobj_attr);
 
        return sprintf(buf, "%u\n", data->domain_id);
 }
 
-static ssize_t show_fabric_cluster_id(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_fabric_cluster_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
-       struct uncore_data *data = container_of(attr, struct uncore_data, fabric_cluster_id_dev_attr);
+       struct uncore_data *data = container_of(attr, struct uncore_data, fabric_cluster_id_kobj_attr);
 
        return sprintf(buf, "%u\n", data->cluster_id);
 }
 
-static ssize_t show_package_id(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_package_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
-       struct uncore_data *data = container_of(attr, struct uncore_data, package_id_dev_attr);
+       struct uncore_data *data = container_of(attr, struct uncore_data, package_id_kobj_attr);
 
        return sprintf(buf, "%u\n", data->package_id);
 }
@@ -97,30 +97,30 @@ static ssize_t show_perf_status_freq_khz(struct uncore_data *data, char *buf)
 }
 
 #define store_uncore_min_max(name, min_max)                            \
-       static ssize_t store_##name(struct device *dev,         \
-                                    struct device_attribute *attr,     \
+       static ssize_t store_##name(struct kobject *kobj,               \
+                                    struct kobj_attribute *attr,       \
                                     const char *buf, size_t count)     \
        {                                                               \
-               struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\
+               struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\
                                                                        \
                return store_min_max_freq_khz(data, buf, count, \
                                              min_max);         \
        }
 
 #define show_uncore_min_max(name, min_max)                             \
-       static ssize_t show_##name(struct device *dev,          \
-                                   struct device_attribute *attr, char *buf)\
+       static ssize_t show_##name(struct kobject *kobj,                \
+                                   struct kobj_attribute *attr, char *buf)\
        {                                                               \
-               struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\
+               struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\
                                                                        \
                return show_min_max_freq_khz(data, buf, min_max);       \
        }
 
 #define show_uncore_perf_status(name)                                  \
-       static ssize_t show_##name(struct device *dev,          \
-                                  struct device_attribute *attr, char *buf)\
+       static ssize_t show_##name(struct kobject *kobj,                \
+                                  struct kobj_attribute *attr, char *buf)\
        {                                                               \
-               struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\
+               struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\
                                                                        \
                return show_perf_status_freq_khz(data, buf); \
        }
@@ -134,11 +134,11 @@ show_uncore_min_max(max_freq_khz, 1);
 show_uncore_perf_status(current_freq_khz);
 
 #define show_uncore_data(member_name)                                  \
-       static ssize_t show_##member_name(struct device *dev,   \
-                                          struct device_attribute *attr, char *buf)\
+       static ssize_t show_##member_name(struct kobject *kobj, \
+                                          struct kobj_attribute *attr, char *buf)\
        {                                                               \
                struct uncore_data *data = container_of(attr, struct uncore_data,\
-                                                         member_name##_dev_attr);\
+                                                         member_name##_kobj_attr);\
                                                                        \
                return sysfs_emit(buf, "%u\n",                          \
                                 data->member_name);                    \
@@ -149,29 +149,29 @@ show_uncore_data(initial_max_freq_khz);
 
 #define init_attribute_rw(_name)                                       \
        do {                                                            \
-               sysfs_attr_init(&data->_name##_dev_attr.attr);  \
-               data->_name##_dev_attr.show = show_##_name;             \
-               data->_name##_dev_attr.store = store_##_name;           \
-               data->_name##_dev_attr.attr.name = #_name;              \
-               data->_name##_dev_attr.attr.mode = 0644;                \
+               sysfs_attr_init(&data->_name##_kobj_attr.attr); \
+               data->_name##_kobj_attr.show = show_##_name;            \
+               data->_name##_kobj_attr.store = store_##_name;          \
+               data->_name##_kobj_attr.attr.name = #_name;             \
+               data->_name##_kobj_attr.attr.mode = 0644;               \
        } while (0)
 
 #define init_attribute_ro(_name)                                       \
        do {                                                            \
-               sysfs_attr_init(&data->_name##_dev_attr.attr);  \
-               data->_name##_dev_attr.show = show_##_name;             \
-               data->_name##_dev_attr.store = NULL;                    \
-               data->_name##_dev_attr.attr.name = #_name;              \
-               data->_name##_dev_attr.attr.mode = 0444;                \
+               sysfs_attr_init(&data->_name##_kobj_attr.attr); \
+               data->_name##_kobj_attr.show = show_##_name;            \
+               data->_name##_kobj_attr.store = NULL;                   \
+               data->_name##_kobj_attr.attr.name = #_name;             \
+               data->_name##_kobj_attr.attr.mode = 0444;               \
        } while (0)
 
 #define init_attribute_root_ro(_name)                                  \
        do {                                                            \
-               sysfs_attr_init(&data->_name##_dev_attr.attr);  \
-               data->_name##_dev_attr.show = show_##_name;             \
-               data->_name##_dev_attr.store = NULL;                    \
-               data->_name##_dev_attr.attr.name = #_name;              \
-               data->_name##_dev_attr.attr.mode = 0400;                \
+               sysfs_attr_init(&data->_name##_kobj_attr.attr); \
+               data->_name##_kobj_attr.show = show_##_name;            \
+               data->_name##_kobj_attr.store = NULL;                   \
+               data->_name##_kobj_attr.attr.name = #_name;             \
+               data->_name##_kobj_attr.attr.mode = 0400;               \
        } while (0)
 
 static int create_attr_group(struct uncore_data *data, char *name)
@@ -186,21 +186,21 @@ static int create_attr_group(struct uncore_data *data, char *name)
 
        if (data->domain_id != UNCORE_DOMAIN_ID_INVALID) {
                init_attribute_root_ro(domain_id);
-               data->uncore_attrs[index++] = &data->domain_id_dev_attr.attr;
+               data->uncore_attrs[index++] = &data->domain_id_kobj_attr.attr;
                init_attribute_root_ro(fabric_cluster_id);
-               data->uncore_attrs[index++] = &data->fabric_cluster_id_dev_attr.attr;
+               data->uncore_attrs[index++] = &data->fabric_cluster_id_kobj_attr.attr;
                init_attribute_root_ro(package_id);
-               data->uncore_attrs[index++] = &data->package_id_dev_attr.attr;
+               data->uncore_attrs[index++] = &data->package_id_kobj_attr.attr;
        }
 
-       data->uncore_attrs[index++] = &data->max_freq_khz_dev_attr.attr;
-       data->uncore_attrs[index++] = &data->min_freq_khz_dev_attr.attr;
-       data->uncore_attrs[index++] = &data->initial_min_freq_khz_dev_attr.attr;
-       data->uncore_attrs[index++] = &data->initial_max_freq_khz_dev_attr.attr;
+       data->uncore_attrs[index++] = &data->max_freq_khz_kobj_attr.attr;
+       data->uncore_attrs[index++] = &data->min_freq_khz_kobj_attr.attr;
+       data->uncore_attrs[index++] = &data->initial_min_freq_khz_kobj_attr.attr;
+       data->uncore_attrs[index++] = &data->initial_max_freq_khz_kobj_attr.attr;
 
        ret = uncore_read_freq(data, &freq);
        if (!ret)
-               data->uncore_attrs[index++] = &data->current_freq_khz_dev_attr.attr;
+               data->uncore_attrs[index++] = &data->current_freq_khz_kobj_attr.attr;
 
        data->uncore_attrs[index] = NULL;
 
index 7afb69977c7e8c80b0db3ba819799434e41ff60a..0e5bf507e555209a69ba61e8e8eaaf7392209bfa 100644 (file)
  * @instance_id:       Unique instance id to append to directory name
  * @name:              Sysfs entry name for this instance
  * @uncore_attr_group: Attribute group storage
- * @max_freq_khz_dev_attr: Storage for device attribute max_freq_khz
- * @mix_freq_khz_dev_attr: Storage for device attribute min_freq_khz
- * @initial_max_freq_khz_dev_attr: Storage for device attribute initial_max_freq_khz
- * @initial_min_freq_khz_dev_attr: Storage for device attribute initial_min_freq_khz
- * @current_freq_khz_dev_attr: Storage for device attribute current_freq_khz
- * @domain_id_dev_attr: Storage for device attribute domain_id
- * @fabric_cluster_id_dev_attr: Storage for device attribute fabric_cluster_id
- * @package_id_dev_attr: Storage for device attribute package_id
+ * @max_freq_khz_kobj_attr: Storage for kobject attribute max_freq_khz
+ * @mix_freq_khz_kobj_attr: Storage for kobject attribute min_freq_khz
+ * @initial_max_freq_khz_kobj_attr: Storage for kobject attribute initial_max_freq_khz
+ * @initial_min_freq_khz_kobj_attr: Storage for kobject attribute initial_min_freq_khz
+ * @current_freq_khz_kobj_attr: Storage for kobject attribute current_freq_khz
+ * @domain_id_kobj_attr: Storage for kobject attribute domain_id
+ * @fabric_cluster_id_kobj_attr: Storage for kobject attribute fabric_cluster_id
+ * @package_id_kobj_attr: Storage for kobject attribute package_id
  * @uncore_attrs:      Attribute storage for group creation
  *
  * This structure is used to encapsulate all data related to uncore sysfs
@@ -53,14 +53,14 @@ struct uncore_data {
        char name[32];
 
        struct attribute_group uncore_attr_group;
-       struct device_attribute max_freq_khz_dev_attr;
-       struct device_attribute min_freq_khz_dev_attr;
-       struct device_attribute initial_max_freq_khz_dev_attr;
-       struct device_attribute initial_min_freq_khz_dev_attr;
-       struct device_attribute current_freq_khz_dev_attr;
-       struct device_attribute domain_id_dev_attr;
-       struct device_attribute fabric_cluster_id_dev_attr;
-       struct device_attribute package_id_dev_attr;
+       struct kobj_attribute max_freq_khz_kobj_attr;
+       struct kobj_attribute min_freq_khz_kobj_attr;
+       struct kobj_attribute initial_max_freq_khz_kobj_attr;
+       struct kobj_attribute initial_min_freq_khz_kobj_attr;
+       struct kobj_attribute current_freq_khz_kobj_attr;
+       struct kobj_attribute domain_id_kobj_attr;
+       struct kobj_attribute fabric_cluster_id_kobj_attr;
+       struct kobj_attribute package_id_kobj_attr;
        struct attribute *uncore_attrs[9];
 };
 
index 9cf5ed0f8dc2848b9f85f59dafd3cd43373bf960..040153ad67c1cb7c36fe85616cb97d10f7f99c46 100644 (file)
@@ -32,7 +32,7 @@ static int get_fwu_request(struct device *dev, u32 *out)
                return -ENODEV;
 
        if (obj->type != ACPI_TYPE_INTEGER) {
-               dev_warn(dev, "wmi_query_block returned invalid value\n");
+               dev_warn(dev, "wmidev_block_query returned invalid value\n");
                kfree(obj);
                return -EINVAL;
        }
@@ -55,7 +55,7 @@ static int set_fwu_request(struct device *dev, u32 in)
 
        status = wmidev_block_set(to_wmi_device(dev), 0, &input);
        if (ACPI_FAILURE(status)) {
-               dev_err(dev, "wmi_set_block failed\n");
+               dev_err(dev, "wmidev_block_set failed\n");
                return -ENODEV;
        }
 
index 1cf2471d54ddef765b017fd079864b3ffb868fdc..6bd14d0132dbd73b1ea497679d4dd8297671859e 100644 (file)
@@ -26,6 +26,21 @@ static const struct x86_cpu_id p2sb_cpu_ids[] = {
        {}
 };
 
+/*
+ * Cache BAR0 of P2SB device functions 0 to 7.
+ * TODO: The constant 8 is the number of functions that PCI specification
+ *       defines. Same definitions exist tree-wide. Unify this definition and
+ *       the other definitions then move to include/uapi/linux/pci.h.
+ */
+#define NR_P2SB_RES_CACHE 8
+
+struct p2sb_res_cache {
+       u32 bus_dev_id;
+       struct resource res;
+};
+
+static struct p2sb_res_cache p2sb_resources[NR_P2SB_RES_CACHE];
+
 static int p2sb_get_devfn(unsigned int *devfn)
 {
        unsigned int fn = P2SB_DEVFN_DEFAULT;
@@ -39,10 +54,18 @@ static int p2sb_get_devfn(unsigned int *devfn)
        return 0;
 }
 
+static bool p2sb_valid_resource(struct resource *res)
+{
+       if (res->flags)
+               return true;
+
+       return false;
+}
+
 /* Copy resource from the first BAR of the device in question */
-static int p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem)
+static void p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem)
 {
-       struct resource *bar0 = &pdev->resource[0];
+       struct resource *bar0 = pci_resource_n(pdev, 0);
 
        /* Make sure we have no dangling pointers in the output */
        memset(mem, 0, sizeof(*mem));
@@ -56,49 +79,66 @@ static int p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem)
        mem->end = bar0->end;
        mem->flags = bar0->flags;
        mem->desc = bar0->desc;
-
-       return 0;
 }
 
-static int p2sb_scan_and_read(struct pci_bus *bus, unsigned int devfn, struct resource *mem)
+static void p2sb_scan_and_cache_devfn(struct pci_bus *bus, unsigned int devfn)
 {
+       struct p2sb_res_cache *cache = &p2sb_resources[PCI_FUNC(devfn)];
        struct pci_dev *pdev;
-       int ret;
 
        pdev = pci_scan_single_device(bus, devfn);
        if (!pdev)
-               return -ENODEV;
+               return;
 
-       ret = p2sb_read_bar0(pdev, mem);
+       p2sb_read_bar0(pdev, &cache->res);
+       cache->bus_dev_id = bus->dev.id;
 
        pci_stop_and_remove_bus_device(pdev);
-       return ret;
 }
 
-/**
- * p2sb_bar - Get Primary to Sideband (P2SB) bridge device BAR
- * @bus: PCI bus to communicate with
- * @devfn: PCI slot and function to communicate with
- * @mem: memory resource to be filled in
- *
- * The BIOS prevents the P2SB device from being enumerated by the PCI
- * subsystem, so we need to unhide and hide it back to lookup the BAR.
- *
- * if @bus is NULL, the bus 0 in domain 0 will be used.
- * If @devfn is 0, it will be replaced by devfn of the P2SB device.
- *
- * Caller must provide a valid pointer to @mem.
- *
- * Locking is handled by pci_rescan_remove_lock mutex.
- *
- * Return:
- * 0 on success or appropriate errno value on error.
- */
-int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem)
+static int p2sb_scan_and_cache(struct pci_bus *bus, unsigned int devfn)
+{
+       unsigned int slot, fn;
+
+       if (PCI_FUNC(devfn) == 0) {
+               /*
+                * When function number of the P2SB device is zero, scan it and
+                * other function numbers, and if devices are available, cache
+                * their BAR0s.
+                */
+               slot = PCI_SLOT(devfn);
+               for (fn = 0; fn < NR_P2SB_RES_CACHE; fn++)
+                       p2sb_scan_and_cache_devfn(bus, PCI_DEVFN(slot, fn));
+       } else {
+               /* Scan the P2SB device and cache its BAR0 */
+               p2sb_scan_and_cache_devfn(bus, devfn);
+       }
+
+       if (!p2sb_valid_resource(&p2sb_resources[PCI_FUNC(devfn)].res))
+               return -ENOENT;
+
+       return 0;
+}
+
+static struct pci_bus *p2sb_get_bus(struct pci_bus *bus)
+{
+       static struct pci_bus *p2sb_bus;
+
+       bus = bus ?: p2sb_bus;
+       if (bus)
+               return bus;
+
+       /* Assume P2SB is on the bus 0 in domain 0 */
+       p2sb_bus = pci_find_bus(0, 0);
+       return p2sb_bus;
+}
+
+static int p2sb_cache_resources(void)
 {
-       struct pci_dev *pdev_p2sb;
        unsigned int devfn_p2sb;
        u32 value = P2SBC_HIDE;
+       struct pci_bus *bus;
+       u16 class;
        int ret;
 
        /* Get devfn for P2SB device itself */
@@ -106,8 +146,17 @@ int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem)
        if (ret)
                return ret;
 
-       /* if @bus is NULL, use bus 0 in domain 0 */
-       bus = bus ?: pci_find_bus(0, 0);
+       bus = p2sb_get_bus(NULL);
+       if (!bus)
+               return -ENODEV;
+
+       /*
+        * When a device with same devfn exists and its device class is not
+        * PCI_CLASS_MEMORY_OTHER for P2SB, do not touch it.
+        */
+       pci_bus_read_config_word(bus, devfn_p2sb, PCI_CLASS_DEVICE, &class);
+       if (!PCI_POSSIBLE_ERROR(class) && class != PCI_CLASS_MEMORY_OTHER)
+               return -ENODEV;
 
        /*
         * Prevent concurrent PCI bus scan from seeing the P2SB device and
@@ -115,17 +164,16 @@ int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem)
         */
        pci_lock_rescan_remove();
 
-       /* Unhide the P2SB device, if needed */
+       /*
+        * The BIOS prevents the P2SB device from being enumerated by the PCI
+        * subsystem, so we need to unhide and hide it back to lookup the BAR.
+        * Unhide the P2SB device here, if needed.
+        */
        pci_bus_read_config_dword(bus, devfn_p2sb, P2SBC, &value);
        if (value & P2SBC_HIDE)
                pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, 0);
 
-       pdev_p2sb = pci_scan_single_device(bus, devfn_p2sb);
-       if (devfn)
-               ret = p2sb_scan_and_read(bus, devfn, mem);
-       else
-               ret = p2sb_read_bar0(pdev_p2sb, mem);
-       pci_stop_and_remove_bus_device(pdev_p2sb);
+       ret = p2sb_scan_and_cache(bus, devfn_p2sb);
 
        /* Hide the P2SB device, if it was hidden */
        if (value & P2SBC_HIDE)
@@ -133,12 +181,62 @@ int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem)
 
        pci_unlock_rescan_remove();
 
-       if (ret)
-               return ret;
+       return ret;
+}
+
+/**
+ * p2sb_bar - Get Primary to Sideband (P2SB) bridge device BAR
+ * @bus: PCI bus to communicate with
+ * @devfn: PCI slot and function to communicate with
+ * @mem: memory resource to be filled in
+ *
+ * If @bus is NULL, the bus 0 in domain 0 will be used.
+ * If @devfn is 0, it will be replaced by devfn of the P2SB device.
+ *
+ * Caller must provide a valid pointer to @mem.
+ *
+ * Return:
+ * 0 on success or appropriate errno value on error.
+ */
+int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem)
+{
+       struct p2sb_res_cache *cache;
+       int ret;
+
+       bus = p2sb_get_bus(bus);
+       if (!bus)
+               return -ENODEV;
+
+       if (!devfn) {
+               ret = p2sb_get_devfn(&devfn);
+               if (ret)
+                       return ret;
+       }
 
-       if (mem->flags == 0)
+       cache = &p2sb_resources[PCI_FUNC(devfn)];
+       if (cache->bus_dev_id != bus->dev.id)
                return -ENODEV;
 
+       if (!p2sb_valid_resource(&cache->res))
+               return -ENOENT;
+
+       memcpy(mem, &cache->res, sizeof(*mem));
        return 0;
 }
 EXPORT_SYMBOL_GPL(p2sb_bar);
+
+static int __init p2sb_fs_init(void)
+{
+       p2sb_cache_resources();
+       return 0;
+}
+
+/*
+ * pci_rescan_remove_lock to avoid access to unhidden P2SB devices can
+ * not be locked in sysfs pci bus rescan path because of deadlock. To
+ * avoid the deadlock, access to P2SB devices with the lock at an early
+ * step in kernel initialization and cache required resources. This
+ * should happen after subsys_initcall which initializes PCI subsystem
+ * and before device_initcall which requires P2SB resources.
+ */
+fs_initcall(p2sb_fs_init);
index 0c6733772698408ef1a23b977d1a0698a19347d5..7aee5e9ff2b8dd5810f83cc0317ed329b4361d2e 100644 (file)
@@ -944,6 +944,32 @@ static const struct ts_dmi_data teclast_tbook11_data = {
        .properties     = teclast_tbook11_props,
 };
 
+static const struct property_entry teclast_x16_plus_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-min-x", 8),
+       PROPERTY_ENTRY_U32("touchscreen-min-y", 14),
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1916),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1264),
+       PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+       PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-teclast-x16-plus.fw"),
+       PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       PROPERTY_ENTRY_BOOL("silead,home-button"),
+       { }
+};
+
+static const struct ts_dmi_data teclast_x16_plus_data = {
+       .embedded_fw = {
+               .name   = "silead/gsl3692-teclast-x16-plus.fw",
+               .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 },
+               .length = 43560,
+               .sha256 = { 0x9d, 0xb0, 0x3d, 0xf1, 0x00, 0x3c, 0xb5, 0x25,
+                           0x62, 0x8a, 0xa0, 0x93, 0x4b, 0xe0, 0x4e, 0x75,
+                           0xd1, 0x27, 0xb1, 0x65, 0x3c, 0xba, 0xa5, 0x0f,
+                           0xcd, 0xb4, 0xbe, 0x00, 0xbb, 0xf6, 0x43, 0x29 },
+       },
+       .acpi_name      = "MSSL1680:00",
+       .properties     = teclast_x16_plus_props,
+};
+
 static const struct property_entry teclast_x3_plus_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-size-x", 1980),
        PROPERTY_ENTRY_U32("touchscreen-size-y", 1500),
@@ -1612,6 +1638,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_SKU, "E5A6_A1"),
                },
        },
+       {
+               /* Teclast X16 Plus */
+               .driver_data = (void *)&teclast_x16_plus_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
+                       DMI_MATCH(DMI_PRODUCT_SKU, "D3A5_A1"),
+               },
+       },
        {
                /* Teclast X3 Plus */
                .driver_data = (void *)&teclast_x3_plus_data,
index bd271a5730aa51f1c1e6286e2b481e865799b79a..3c288e8f404beb5d4887235c85654e9ac77cd425 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/rwsem.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
 #include <linux/types.h>
@@ -56,7 +57,6 @@ static_assert(__alignof__(struct guid_block) == 1);
 
 enum { /* wmi_block flags */
        WMI_READ_TAKES_NO_ARGS,
-       WMI_PROBED,
 };
 
 struct wmi_block {
@@ -64,8 +64,10 @@ struct wmi_block {
        struct list_head list;
        struct guid_block gblock;
        struct acpi_device *acpi_device;
+       struct rw_semaphore notify_lock;        /* Protects notify callback add/remove */
        wmi_notify_handler handler;
        void *handler_data;
+       bool driver_ready;
        unsigned long flags;
 };
 
@@ -219,6 +221,17 @@ static int wmidev_match_guid(struct device *dev, const void *data)
        return 0;
 }
 
+static int wmidev_match_notify_id(struct device *dev, const void *data)
+{
+       struct wmi_block *wblock = dev_to_wblock(dev);
+       const u32 *notify_id = data;
+
+       if (wblock->gblock.flags & ACPI_WMI_EVENT && wblock->gblock.notify_id == *notify_id)
+               return 1;
+
+       return 0;
+}
+
 static struct bus_type wmi_bus_type;
 
 static struct wmi_device *wmi_find_device_by_guid(const char *guid_string)
@@ -238,6 +251,17 @@ static struct wmi_device *wmi_find_device_by_guid(const char *guid_string)
        return dev_to_wdev(dev);
 }
 
+static struct wmi_device *wmi_find_event_by_notify_id(const u32 notify_id)
+{
+       struct device *dev;
+
+       dev = bus_find_device(&wmi_bus_type, NULL, &notify_id, wmidev_match_notify_id);
+       if (!dev)
+               return ERR_PTR(-ENODEV);
+
+       return to_wmi_device(dev);
+}
+
 static void wmi_device_put(struct wmi_device *wdev)
 {
        put_device(&wdev->dev);
@@ -572,32 +596,31 @@ acpi_status wmi_install_notify_handler(const char *guid,
                                       wmi_notify_handler handler,
                                       void *data)
 {
-       struct wmi_block *block;
-       acpi_status status = AE_NOT_EXIST;
-       guid_t guid_input;
-
-       if (!guid || !handler)
-               return AE_BAD_PARAMETER;
+       struct wmi_block *wblock;
+       struct wmi_device *wdev;
+       acpi_status status;
 
-       if (guid_parse(guid, &guid_input))
-               return AE_BAD_PARAMETER;
+       wdev = wmi_find_device_by_guid(guid);
+       if (IS_ERR(wdev))
+               return AE_ERROR;
 
-       list_for_each_entry(block, &wmi_block_list, list) {
-               acpi_status wmi_status;
+       wblock = container_of(wdev, struct wmi_block, dev);
 
-               if (guid_equal(&block->gblock.guid, &guid_input)) {
-                       if (block->handler)
-                               return AE_ALREADY_ACQUIRED;
+       down_write(&wblock->notify_lock);
+       if (wblock->handler) {
+               status = AE_ALREADY_ACQUIRED;
+       } else {
+               wblock->handler = handler;
+               wblock->handler_data = data;
 
-                       block->handler = handler;
-                       block->handler_data = data;
+               if (ACPI_FAILURE(wmi_method_enable(wblock, true)))
+                       dev_warn(&wblock->dev.dev, "Failed to enable device\n");
 
-                       wmi_status = wmi_method_enable(block, true);
-                       if ((wmi_status != AE_OK) ||
-                           ((wmi_status == AE_OK) && (status == AE_NOT_EXIST)))
-                               status = wmi_status;
-               }
+               status = AE_OK;
        }
+       up_write(&wblock->notify_lock);
+
+       wmi_device_put(wdev);
 
        return status;
 }
@@ -613,30 +636,31 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
  */
 acpi_status wmi_remove_notify_handler(const char *guid)
 {
-       struct wmi_block *block;
-       acpi_status status = AE_NOT_EXIST;
-       guid_t guid_input;
+       struct wmi_block *wblock;
+       struct wmi_device *wdev;
+       acpi_status status;
 
-       if (!guid)
-               return AE_BAD_PARAMETER;
+       wdev = wmi_find_device_by_guid(guid);
+       if (IS_ERR(wdev))
+               return AE_ERROR;
 
-       if (guid_parse(guid, &guid_input))
-               return AE_BAD_PARAMETER;
+       wblock = container_of(wdev, struct wmi_block, dev);
 
-       list_for_each_entry(block, &wmi_block_list, list) {
-               acpi_status wmi_status;
+       down_write(&wblock->notify_lock);
+       if (!wblock->handler) {
+               status = AE_NULL_ENTRY;
+       } else {
+               if (ACPI_FAILURE(wmi_method_enable(wblock, false)))
+                       dev_warn(&wblock->dev.dev, "Failed to disable device\n");
 
-               if (guid_equal(&block->gblock.guid, &guid_input)) {
-                       if (!block->handler)
-                               return AE_NULL_ENTRY;
+               wblock->handler = NULL;
+               wblock->handler_data = NULL;
 
-                       wmi_status = wmi_method_enable(block, false);
-                       block->handler = NULL;
-                       block->handler_data = NULL;
-                       if (wmi_status != AE_OK || (wmi_status == AE_OK && status == AE_NOT_EXIST))
-                               status = wmi_status;
-               }
+               status = AE_OK;
        }
+       up_write(&wblock->notify_lock);
+
+       wmi_device_put(wdev);
 
        return status;
 }
@@ -655,15 +679,19 @@ EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
 acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
 {
        struct wmi_block *wblock;
+       struct wmi_device *wdev;
+       acpi_status status;
 
-       list_for_each_entry(wblock, &wmi_block_list, list) {
-               struct guid_block *gblock = &wblock->gblock;
+       wdev = wmi_find_event_by_notify_id(event);
+       if (IS_ERR(wdev))
+               return AE_NOT_FOUND;
 
-               if ((gblock->flags & ACPI_WMI_EVENT) && gblock->notify_id == event)
-                       return get_event_data(wblock, out);
-       }
+       wblock = container_of(wdev, struct wmi_block, dev);
+       status = get_event_data(wblock, out);
 
-       return AE_NOT_FOUND;
+       wmi_device_put(wdev);
+
+       return status;
 }
 EXPORT_SYMBOL_GPL(wmi_get_event_data);
 
@@ -868,7 +896,7 @@ static int wmi_dev_probe(struct device *dev)
        if (wdriver->probe) {
                ret = wdriver->probe(dev_to_wdev(dev),
                                find_guid_context(wblock, wdriver));
-               if (!ret) {
+               if (ret) {
                        if (ACPI_FAILURE(wmi_method_enable(wblock, false)))
                                dev_warn(dev, "Failed to disable device\n");
 
@@ -876,7 +904,9 @@ static int wmi_dev_probe(struct device *dev)
                }
        }
 
-       set_bit(WMI_PROBED, &wblock->flags);
+       down_write(&wblock->notify_lock);
+       wblock->driver_ready = true;
+       up_write(&wblock->notify_lock);
 
        return 0;
 }
@@ -886,7 +916,9 @@ static void wmi_dev_remove(struct device *dev)
        struct wmi_block *wblock = dev_to_wblock(dev);
        struct wmi_driver *wdriver = drv_to_wdrv(dev->driver);
 
-       clear_bit(WMI_PROBED, &wblock->flags);
+       down_write(&wblock->notify_lock);
+       wblock->driver_ready = false;
+       up_write(&wblock->notify_lock);
 
        if (wdriver->remove)
                wdriver->remove(dev_to_wdev(dev));
@@ -999,6 +1031,8 @@ static int wmi_create_device(struct device *wmi_bus_dev,
                wblock->dev.setable = true;
 
  out_init:
+       init_rwsem(&wblock->notify_lock);
+       wblock->driver_ready = false;
        wblock->dev.dev.bus = &wmi_bus_type;
        wblock->dev.dev.parent = wmi_bus_dev;
 
@@ -1171,6 +1205,26 @@ acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
        }
 }
 
+static void wmi_notify_driver(struct wmi_block *wblock)
+{
+       struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver);
+       struct acpi_buffer data = { ACPI_ALLOCATE_BUFFER, NULL };
+       acpi_status status;
+
+       if (!driver->no_notify_data) {
+               status = get_event_data(wblock, &data);
+               if (ACPI_FAILURE(status)) {
+                       dev_warn(&wblock->dev.dev, "Failed to get event data\n");
+                       return;
+               }
+       }
+
+       if (driver->notify)
+               driver->notify(&wblock->dev, data.pointer);
+
+       kfree(data.pointer);
+}
+
 static int wmi_notify_device(struct device *dev, void *data)
 {
        struct wmi_block *wblock = dev_to_wblock(dev);
@@ -1179,28 +1233,17 @@ static int wmi_notify_device(struct device *dev, void *data)
        if (!(wblock->gblock.flags & ACPI_WMI_EVENT && wblock->gblock.notify_id == *event))
                return 0;
 
-       /* If a driver is bound, then notify the driver. */
-       if (test_bit(WMI_PROBED, &wblock->flags) && wblock->dev.dev.driver) {
-               struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver);
-               struct acpi_buffer evdata = { ACPI_ALLOCATE_BUFFER, NULL };
-               acpi_status status;
-
-               if (!driver->no_notify_data) {
-                       status = get_event_data(wblock, &evdata);
-                       if (ACPI_FAILURE(status)) {
-                               dev_warn(&wblock->dev.dev, "failed to get event data\n");
-                               return -EIO;
-                       }
-               }
-
-               if (driver->notify)
-                       driver->notify(&wblock->dev, evdata.pointer);
-
-               kfree(evdata.pointer);
-       } else if (wblock->handler) {
-               /* Legacy handler */
-               wblock->handler(*event, wblock->handler_data);
+       down_read(&wblock->notify_lock);
+       /* The WMI driver notify handler conflicts with the legacy WMI handler.
+        * Because of this the WMI driver notify handler takes precedence.
+        */
+       if (wblock->dev.dev.driver && wblock->driver_ready) {
+               wmi_notify_driver(wblock);
+       } else {
+               if (wblock->handler)
+                       wblock->handler(*event, wblock->handler_data);
        }
+       up_read(&wblock->notify_lock);
 
        acpi_bus_generate_netlink_event(wblock->acpi_device->pnp.device_class,
                                        dev_name(&wblock->dev.dev), *event, 0);
index a12e2a66d516f9de6e4b7ccc3f8048861322624a..ec163d1bcd189192abcecbcb4e29e0e4251b2e38 100644 (file)
@@ -282,7 +282,6 @@ struct qcom_battmgr_wireless {
 
 struct qcom_battmgr {
        struct device *dev;
-       struct auxiliary_device *adev;
        struct pmic_glink_client *client;
 
        enum qcom_battmgr_variant variant;
@@ -1294,69 +1293,11 @@ static void qcom_battmgr_enable_worker(struct work_struct *work)
                dev_err(battmgr->dev, "failed to request power notifications\n");
 }
 
-static char *qcom_battmgr_battery[] = { "battery" };
-
-static void qcom_battmgr_register_psy(struct qcom_battmgr *battmgr)
-{
-       struct power_supply_config psy_cfg_supply = {};
-       struct auxiliary_device *adev = battmgr->adev;
-       struct power_supply_config psy_cfg = {};
-       struct device *dev = &adev->dev;
-
-       psy_cfg.drv_data = battmgr;
-       psy_cfg.of_node = adev->dev.of_node;
-
-       psy_cfg_supply.drv_data = battmgr;
-       psy_cfg_supply.of_node = adev->dev.of_node;
-       psy_cfg_supply.supplied_to = qcom_battmgr_battery;
-       psy_cfg_supply.num_supplicants = 1;
-
-       if (battmgr->variant == QCOM_BATTMGR_SC8280XP) {
-               battmgr->bat_psy = devm_power_supply_register(dev, &sc8280xp_bat_psy_desc, &psy_cfg);
-               if (IS_ERR(battmgr->bat_psy))
-                       dev_err(dev, "failed to register battery power supply (%ld)\n",
-                               PTR_ERR(battmgr->bat_psy));
-
-               battmgr->ac_psy = devm_power_supply_register(dev, &sc8280xp_ac_psy_desc, &psy_cfg_supply);
-               if (IS_ERR(battmgr->ac_psy))
-                       dev_err(dev, "failed to register AC power supply (%ld)\n",
-                               PTR_ERR(battmgr->ac_psy));
-
-               battmgr->usb_psy = devm_power_supply_register(dev, &sc8280xp_usb_psy_desc, &psy_cfg_supply);
-               if (IS_ERR(battmgr->usb_psy))
-                       dev_err(dev, "failed to register USB power supply (%ld)\n",
-                               PTR_ERR(battmgr->usb_psy));
-
-               battmgr->wls_psy = devm_power_supply_register(dev, &sc8280xp_wls_psy_desc, &psy_cfg_supply);
-               if (IS_ERR(battmgr->wls_psy))
-                       dev_err(dev, "failed to register wireless charing power supply (%ld)\n",
-                               PTR_ERR(battmgr->wls_psy));
-       } else {
-               battmgr->bat_psy = devm_power_supply_register(dev, &sm8350_bat_psy_desc, &psy_cfg);
-               if (IS_ERR(battmgr->bat_psy))
-                       dev_err(dev, "failed to register battery power supply (%ld)\n",
-                               PTR_ERR(battmgr->bat_psy));
-
-               battmgr->usb_psy = devm_power_supply_register(dev, &sm8350_usb_psy_desc, &psy_cfg_supply);
-               if (IS_ERR(battmgr->usb_psy))
-                       dev_err(dev, "failed to register USB power supply (%ld)\n",
-                               PTR_ERR(battmgr->usb_psy));
-
-               battmgr->wls_psy = devm_power_supply_register(dev, &sm8350_wls_psy_desc, &psy_cfg_supply);
-               if (IS_ERR(battmgr->wls_psy))
-                       dev_err(dev, "failed to register wireless charing power supply (%ld)\n",
-                               PTR_ERR(battmgr->wls_psy));
-       }
-}
-
 static void qcom_battmgr_pdr_notify(void *priv, int state)
 {
        struct qcom_battmgr *battmgr = priv;
 
        if (state == SERVREG_SERVICE_STATE_UP) {
-               if (!battmgr->bat_psy)
-                       qcom_battmgr_register_psy(battmgr);
-
                battmgr->service_up = true;
                schedule_work(&battmgr->enable_work);
        } else {
@@ -1371,9 +1312,13 @@ static const struct of_device_id qcom_battmgr_of_variants[] = {
        {}
 };
 
+static char *qcom_battmgr_battery[] = { "battery" };
+
 static int qcom_battmgr_probe(struct auxiliary_device *adev,
                              const struct auxiliary_device_id *id)
 {
+       struct power_supply_config psy_cfg_supply = {};
+       struct power_supply_config psy_cfg = {};
        const struct of_device_id *match;
        struct qcom_battmgr *battmgr;
        struct device *dev = &adev->dev;
@@ -1383,7 +1328,14 @@ static int qcom_battmgr_probe(struct auxiliary_device *adev,
                return -ENOMEM;
 
        battmgr->dev = dev;
-       battmgr->adev = adev;
+
+       psy_cfg.drv_data = battmgr;
+       psy_cfg.of_node = adev->dev.of_node;
+
+       psy_cfg_supply.drv_data = battmgr;
+       psy_cfg_supply.of_node = adev->dev.of_node;
+       psy_cfg_supply.supplied_to = qcom_battmgr_battery;
+       psy_cfg_supply.num_supplicants = 1;
 
        INIT_WORK(&battmgr->enable_work, qcom_battmgr_enable_worker);
        mutex_init(&battmgr->lock);
@@ -1395,6 +1347,43 @@ static int qcom_battmgr_probe(struct auxiliary_device *adev,
        else
                battmgr->variant = QCOM_BATTMGR_SM8350;
 
+       if (battmgr->variant == QCOM_BATTMGR_SC8280XP) {
+               battmgr->bat_psy = devm_power_supply_register(dev, &sc8280xp_bat_psy_desc, &psy_cfg);
+               if (IS_ERR(battmgr->bat_psy))
+                       return dev_err_probe(dev, PTR_ERR(battmgr->bat_psy),
+                                            "failed to register battery power supply\n");
+
+               battmgr->ac_psy = devm_power_supply_register(dev, &sc8280xp_ac_psy_desc, &psy_cfg_supply);
+               if (IS_ERR(battmgr->ac_psy))
+                       return dev_err_probe(dev, PTR_ERR(battmgr->ac_psy),
+                                            "failed to register AC power supply\n");
+
+               battmgr->usb_psy = devm_power_supply_register(dev, &sc8280xp_usb_psy_desc, &psy_cfg_supply);
+               if (IS_ERR(battmgr->usb_psy))
+                       return dev_err_probe(dev, PTR_ERR(battmgr->usb_psy),
+                                            "failed to register USB power supply\n");
+
+               battmgr->wls_psy = devm_power_supply_register(dev, &sc8280xp_wls_psy_desc, &psy_cfg_supply);
+               if (IS_ERR(battmgr->wls_psy))
+                       return dev_err_probe(dev, PTR_ERR(battmgr->wls_psy),
+                                            "failed to register wireless charing power supply\n");
+       } else {
+               battmgr->bat_psy = devm_power_supply_register(dev, &sm8350_bat_psy_desc, &psy_cfg);
+               if (IS_ERR(battmgr->bat_psy))
+                       return dev_err_probe(dev, PTR_ERR(battmgr->bat_psy),
+                                            "failed to register battery power supply\n");
+
+               battmgr->usb_psy = devm_power_supply_register(dev, &sm8350_usb_psy_desc, &psy_cfg_supply);
+               if (IS_ERR(battmgr->usb_psy))
+                       return dev_err_probe(dev, PTR_ERR(battmgr->usb_psy),
+                                            "failed to register USB power supply\n");
+
+               battmgr->wls_psy = devm_power_supply_register(dev, &sm8350_wls_psy_desc, &psy_cfg_supply);
+               if (IS_ERR(battmgr->wls_psy))
+                       return dev_err_probe(dev, PTR_ERR(battmgr->wls_psy),
+                                            "failed to register wireless charing power supply\n");
+       }
+
        battmgr->client = devm_pmic_glink_register_client(dev,
                                                          PMIC_GLINK_OWNER_BATTMGR,
                                                          qcom_battmgr_callback,
index bc88a40a88d4cac0bbe61efc4725703b1136654e..830a1c4cd705784687fb424f3bfd23fdc7743fcf 100644 (file)
@@ -392,7 +392,7 @@ static int max597x_regmap_read_clear(struct regmap *map, unsigned int reg,
                return ret;
 
        if (*val)
-               return regmap_write(map, reg, *val);
+               return regmap_write(map, reg, 0);
 
        return 0;
 }
index 698c420e0869bd464f1368305b16d26a18360fa4..60cfcd741c2af31ce7e351cdf8cfb35f996264cf 100644 (file)
@@ -157,7 +157,17 @@ static int pwm_regulator_get_voltage(struct regulator_dev *rdev)
 
        pwm_get_state(drvdata->pwm, &pstate);
 
+       if (!pstate.enabled) {
+               if (pstate.polarity == PWM_POLARITY_INVERSED)
+                       pstate.duty_cycle = pstate.period;
+               else
+                       pstate.duty_cycle = 0;
+       }
+
        voltage = pwm_get_relative_duty_cycle(&pstate, duty_unit);
+       if (voltage < min(max_uV_duty, min_uV_duty) ||
+           voltage > max(max_uV_duty, min_uV_duty))
+               return -ENOTRECOVERABLE;
 
        /*
         * The dutycycle for min_uV might be greater than the one for max_uV.
@@ -313,6 +323,32 @@ static int pwm_regulator_init_continuous(struct platform_device *pdev,
        return 0;
 }
 
+static int pwm_regulator_init_boot_on(struct platform_device *pdev,
+                                     struct pwm_regulator_data *drvdata,
+                                     const struct regulator_init_data *init_data)
+{
+       struct pwm_state pstate;
+
+       if (!init_data->constraints.boot_on || drvdata->enb_gpio)
+               return 0;
+
+       pwm_get_state(drvdata->pwm, &pstate);
+       if (pstate.enabled)
+               return 0;
+
+       /*
+        * Update the duty cycle so the output does not change
+        * when the regulator core enables the regulator (and
+        * thus the PWM channel).
+        */
+       if (pstate.polarity == PWM_POLARITY_INVERSED)
+               pstate.duty_cycle = pstate.period;
+       else
+               pstate.duty_cycle = 0;
+
+       return pwm_apply_might_sleep(drvdata->pwm, &pstate);
+}
+
 static int pwm_regulator_probe(struct platform_device *pdev)
 {
        const struct regulator_init_data *init_data;
@@ -372,6 +408,13 @@ static int pwm_regulator_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       ret = pwm_regulator_init_boot_on(pdev, drvdata, init_data);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to apply boot_on settings: %d\n",
+                       ret);
+               return ret;
+       }
+
        regulator = devm_regulator_register(&pdev->dev,
                                            &drvdata->desc, &config);
        if (IS_ERR(regulator)) {
index f48214e2c3b46000eb2e833b422be4474a08f920..04133510e5af7dee68f7d4cb8f10f7af02ff44ab 100644 (file)
@@ -726,9 +726,25 @@ static int ti_abb_probe(struct platform_device *pdev)
                        return PTR_ERR(abb->setup_reg);
        }
 
-       abb->int_base = devm_platform_ioremap_resource_byname(pdev, "int-address");
-       if (IS_ERR(abb->int_base))
-               return PTR_ERR(abb->int_base);
+       pname = "int-address";
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+       if (!res) {
+               dev_err(dev, "Missing '%s' IO resource\n", pname);
+               return -ENODEV;
+       }
+       /*
+        * The MPU interrupt status register (PRM_IRQSTATUS_MPU) is
+        * shared between regulator-abb-{ivahd,dspeve,gpu} driver
+        * instances. Therefore use devm_ioremap() rather than
+        * devm_platform_ioremap_resource_byname() to avoid busy
+        * resource region conflicts.
+        */
+       abb->int_base = devm_ioremap(dev, res->start,
+                                            resource_size(res));
+       if (!abb->int_base) {
+               dev_err(dev, "Unable to map '%s'\n", pname);
+               return -ENOMEM;
+       }
 
        /* Map Optional resources */
        pname = "efuse-address";
index 2a50fda3a628c3fdc9daa79d73437de565bc5891..625fd547ee60a79c3a8bae9e985cb74d06b9073f 100644 (file)
@@ -371,7 +371,6 @@ static u16 initio_se2_rd(unsigned long base, u8 addr)
  */
 static void initio_se2_wr(unsigned long base, u8 addr, u16 val)
 {
-       u8 rb;
        u8 instr;
        int i;
 
@@ -400,7 +399,7 @@ static void initio_se2_wr(unsigned long base, u8 addr, u16 val)
                udelay(30);
                outb(SE2CS, base + TUL_NVRAM);                  /* -CLK */
                udelay(30);
-               if ((rb = inb(base + TUL_NVRAM)) & SE2DI)
+               if (inb(base + TUL_NVRAM) & SE2DI)
                        break;  /* write complete */
        }
        outb(0, base + TUL_NVRAM);                              /* -CS */
index 71f711cb0628a70d40efc99520ef2dc807494e75..355a0bc0828e749a45513309b942cfdae4878a7c 100644 (file)
@@ -3387,7 +3387,7 @@ static enum sci_status isci_io_request_build(struct isci_host *ihost,
                return SCI_FAILURE;
        }
 
-       return SCI_SUCCESS;
+       return status;
 }
 
 static struct isci_request *isci_request_from_tag(struct isci_host *ihost, u16 tag)
index 79da4b1c1df0adc649954a45f2d630989f12a6d6..4f455884fdc440188124d845ef0535f4da418d22 100644 (file)
@@ -61,11 +61,11 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd);
 static enum scsi_disposition scsi_try_to_abort_cmd(const struct scsi_host_template *,
                                                   struct scsi_cmnd *);
 
-void scsi_eh_wakeup(struct Scsi_Host *shost)
+void scsi_eh_wakeup(struct Scsi_Host *shost, unsigned int busy)
 {
        lockdep_assert_held(shost->host_lock);
 
-       if (scsi_host_busy(shost) == shost->host_failed) {
+       if (busy == shost->host_failed) {
                trace_scsi_eh_wakeup(shost);
                wake_up_process(shost->ehandler);
                SCSI_LOG_ERROR_RECOVERY(5, shost_printk(KERN_INFO, shost,
@@ -88,7 +88,7 @@ void scsi_schedule_eh(struct Scsi_Host *shost)
        if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 ||
            scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) {
                shost->host_eh_scheduled++;
-               scsi_eh_wakeup(shost);
+               scsi_eh_wakeup(shost, scsi_host_busy(shost));
        }
 
        spin_unlock_irqrestore(shost->host_lock, flags);
@@ -286,7 +286,7 @@ static void scsi_eh_inc_host_failed(struct rcu_head *head)
 
        spin_lock_irqsave(shost->host_lock, flags);
        shost->host_failed++;
-       scsi_eh_wakeup(shost);
+       scsi_eh_wakeup(shost, scsi_host_busy(shost));
        spin_unlock_irqrestore(shost->host_lock, flags);
 }
 
index cf3864f720930988fbadc77b3c91c77fe2d3bb62..1fb80eae9a63a30787dee6583e2a0cfe5c96f0ce 100644 (file)
@@ -280,7 +280,7 @@ static void scsi_dec_host_busy(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
        if (unlikely(scsi_host_in_recovery(shost))) {
                spin_lock_irqsave(shost->host_lock, flags);
                if (shost->host_failed || shost->host_eh_scheduled)
-                       scsi_eh_wakeup(shost);
+                       scsi_eh_wakeup(shost, scsi_host_busy(shost));
                spin_unlock_irqrestore(shost->host_lock, flags);
        }
        rcu_read_unlock();
index 3f0dfb97db6bd1b88755db1fb50dd6e968e385c6..1fbfe1b52c9f1a906ea6b0da7a6b273e2972a903 100644 (file)
@@ -92,7 +92,7 @@ extern void scmd_eh_abort_handler(struct work_struct *work);
 extern enum blk_eh_timer_return scsi_timeout(struct request *req);
 extern int scsi_error_handler(void *host);
 extern enum scsi_disposition scsi_decide_disposition(struct scsi_cmnd *cmd);
-extern void scsi_eh_wakeup(struct Scsi_Host *shost);
+extern void scsi_eh_wakeup(struct Scsi_Host *shost, unsigned int busy);
 extern void scsi_eh_scmd_add(struct scsi_cmnd *);
 void scsi_eh_ready_devs(struct Scsi_Host *shost,
                        struct list_head *work_q,
index a95936b18f695e3ef796098866ea07101e9e346d..7ceb982040a5dfe5d490f9a4bd306e99e5140a53 100644 (file)
@@ -330,6 +330,7 @@ enum storvsc_request_type {
  */
 
 static int storvsc_ringbuffer_size = (128 * 1024);
+static int aligned_ringbuffer_size;
 static u32 max_outstanding_req_per_channel;
 static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth);
 
@@ -687,8 +688,8 @@ static void handle_sc_creation(struct vmbus_channel *new_sc)
        new_sc->next_request_id_callback = storvsc_next_request_id;
 
        ret = vmbus_open(new_sc,
-                        storvsc_ringbuffer_size,
-                        storvsc_ringbuffer_size,
+                        aligned_ringbuffer_size,
+                        aligned_ringbuffer_size,
                         (void *)&props,
                         sizeof(struct vmstorage_channel_properties),
                         storvsc_on_channel_callback, new_sc);
@@ -1973,7 +1974,7 @@ static int storvsc_probe(struct hv_device *device,
        dma_set_min_align_mask(&device->device, HV_HYP_PAGE_SIZE - 1);
 
        stor_device->port_number = host->host_no;
-       ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size, is_fc);
+       ret = storvsc_connect_to_vsp(device, aligned_ringbuffer_size, is_fc);
        if (ret)
                goto err_out1;
 
@@ -2164,7 +2165,7 @@ static int storvsc_resume(struct hv_device *hv_dev)
 {
        int ret;
 
-       ret = storvsc_connect_to_vsp(hv_dev, storvsc_ringbuffer_size,
+       ret = storvsc_connect_to_vsp(hv_dev, aligned_ringbuffer_size,
                                     hv_dev_is_fc(hv_dev));
        return ret;
 }
@@ -2198,8 +2199,9 @@ static int __init storvsc_drv_init(void)
         * the ring buffer indices) by the max request size (which is
         * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64)
         */
+       aligned_ringbuffer_size = VMBUS_RING_SIZE(storvsc_ringbuffer_size);
        max_outstanding_req_per_channel =
-               ((storvsc_ringbuffer_size - PAGE_SIZE) /
+               ((aligned_ringbuffer_size - PAGE_SIZE) /
                ALIGN(MAX_MULTIPAGE_BUFFER_PACKET +
                sizeof(struct vstor_packet) + sizeof(u64),
                sizeof(u64)));
index 4cf20be668a6021c6acfae56c19f0914586a7bf6..617eb892f4ad457feb5d4de3d9c1ceb88a010c61 100644 (file)
@@ -188,8 +188,6 @@ static void virtscsi_vq_done(struct virtio_scsi *vscsi,
                while ((buf = virtqueue_get_buf(vq, &len)) != NULL)
                        fn(vscsi, buf);
 
-               if (unlikely(virtqueue_is_broken(vq)))
-                       break;
        } while (!virtqueue_enable_cb(vq));
        spin_unlock_irqrestore(&virtscsi_vq->vq_lock, flags);
 }
index 780199bf351efbfb24422880ef39510c77def68f..49a0955e82d6cf5eef83e5f63ba8d31194c65324 100644 (file)
@@ -296,14 +296,14 @@ struct apple_mbox *apple_mbox_get(struct device *dev, int index)
        of_node_put(args.np);
 
        if (!pdev)
-               return ERR_PTR(EPROBE_DEFER);
+               return ERR_PTR(-EPROBE_DEFER);
 
        mbox = platform_get_drvdata(pdev);
        if (!mbox)
-               return ERR_PTR(EPROBE_DEFER);
+               return ERR_PTR(-EPROBE_DEFER);
 
        if (!device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_CONSUMER))
-               return ERR_PTR(ENODEV);
+               return ERR_PTR(-ENODEV);
 
        return mbox;
 }
index d96222e6d7d2d4022753d3120b4c36ea759dad75..cfdaa5eaec76db9b322272b54d4fdfdcff3db697 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
-#include <linux/spi/spi-mem.h>
+#include <linux/mtd/spi-nor.h>
 #include <linux/sysfs.h>
 #include <linux/types.h>
 #include "spi-bcm-qspi.h"
@@ -1221,7 +1221,7 @@ static int bcm_qspi_exec_mem_op(struct spi_mem *mem,
 
        /* non-aligned and very short transfers are handled by MSPI */
        if (!IS_ALIGNED((uintptr_t)addr, 4) || !IS_ALIGNED((uintptr_t)buf, 4) ||
-           len < 4)
+           len < 4 || op->cmd.opcode == SPINOR_OP_RDSFDP)
                mspi_read = true;
 
        if (!has_bspi(qspi) || mspi_read)
index a50eb4db79de8e93cb61a9ea50bc8913ed3e4f1f..e5140532071d2b647ab77fa561f27630a334971a 100644 (file)
@@ -317,6 +317,15 @@ static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx)
        xspi->rx_bytes -= nrx;
 
        while (ntx || nrx) {
+               if (nrx) {
+                       u8 data = cdns_spi_read(xspi, CDNS_SPI_RXD);
+
+                       if (xspi->rxbuf)
+                               *xspi->rxbuf++ = data;
+
+                       nrx--;
+               }
+
                if (ntx) {
                        if (xspi->txbuf)
                                cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++);
@@ -326,14 +335,6 @@ static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx)
                        ntx--;
                }
 
-               if (nrx) {
-                       u8 data = cdns_spi_read(xspi, CDNS_SPI_RXD);
-
-                       if (xspi->rxbuf)
-                               *xspi->rxbuf++ = data;
-
-                       nrx--;
-               }
        }
 }
 
index f13073e1259364640b16b57323e5d027c10bdb0f..b24190526ce96420fe885e585b00fb820502bacd 100644 (file)
@@ -244,7 +244,10 @@ static int cs42l43_spi_probe(struct platform_device *pdev)
        priv->ctlr->use_gpio_descriptors = true;
        priv->ctlr->auto_runtime_pm = true;
 
-       devm_pm_runtime_enable(priv->dev);
+       ret = devm_pm_runtime_enable(priv->dev);
+       if (ret)
+               return ret;
+
        pm_runtime_idle(priv->dev);
 
        regmap_write(priv->regmap, CS42L43_TRAN_CONFIG6, CS42L43_FIFO_SIZE - 1);
index 9d22018f7985f11956fae5e06ffb0dbd180914f9..1301d14483d482dcaf05250a563a414db73c9dd4 100644 (file)
@@ -377,6 +377,11 @@ static const struct spi_controller_mem_ops hisi_sfc_v3xx_mem_ops = {
 static irqreturn_t hisi_sfc_v3xx_isr(int irq, void *data)
 {
        struct hisi_sfc_v3xx_host *host = data;
+       u32 reg;
+
+       reg = readl(host->regbase + HISI_SFC_V3XX_INT_STAT);
+       if (!reg)
+               return IRQ_NONE;
 
        hisi_sfc_v3xx_disable_int(host);
 
index 272bc871a848b833e6e673740f4be5f8f3a16294..546cdce525fc5b1b49b305b872e81d2b0aed0cb5 100644 (file)
@@ -1344,7 +1344,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
        controller->dma_tx = dma_request_chan(dev, "tx");
        if (IS_ERR(controller->dma_tx)) {
                ret = PTR_ERR(controller->dma_tx);
-               dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret);
+               dev_err_probe(dev, ret, "can't get the TX DMA channel!\n");
                controller->dma_tx = NULL;
                goto err;
        }
@@ -1353,7 +1353,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
        controller->dma_rx = dma_request_chan(dev, "rx");
        if (IS_ERR(controller->dma_rx)) {
                ret = PTR_ERR(controller->dma_rx);
-               dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
+               dev_err_probe(dev, ret, "can't get the RX DMA channel!\n");
                controller->dma_rx = NULL;
                goto err;
        }
index 57d767a68e7b2766dcea5510809cf2f09e0bef63..07d20ca1164c357813e075b7a1a6763da735ab0a 100644 (file)
@@ -76,6 +76,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0x7a24), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0x7e23), (unsigned long)&cnl_info },
+       { PCI_VDEVICE(INTEL, 0x7f24), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0x9d24), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0x9da4), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&cnl_info },
@@ -84,7 +85,6 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0xa2a4), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info },
        { PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&cnl_info },
-       { PCI_VDEVICE(INTEL, 0xae23), (unsigned long)&cnl_info },
        { },
 };
 MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids);
index cfc3b1ddbd229f04885db1b610298e63b623132f..6f12e4fb2e2e184f1bb4cf9fe12e5437384fc4ac 100644 (file)
@@ -136,14 +136,14 @@ struct sh_msiof_spi_priv {
 
 /* SIFCTR */
 #define SIFCTR_TFWM_MASK       GENMASK(31, 29) /* Transmit FIFO Watermark */
-#define SIFCTR_TFWM_64         (0 << 29)       /*  Transfer Request when 64 empty stages */
-#define SIFCTR_TFWM_32         (1 << 29)       /*  Transfer Request when 32 empty stages */
-#define SIFCTR_TFWM_24         (2 << 29)       /*  Transfer Request when 24 empty stages */
-#define SIFCTR_TFWM_16         (3 << 29)       /*  Transfer Request when 16 empty stages */
-#define SIFCTR_TFWM_12         (4 << 29)       /*  Transfer Request when 12 empty stages */
-#define SIFCTR_TFWM_8          (5 << 29)       /*  Transfer Request when 8 empty stages */
-#define SIFCTR_TFWM_4          (6 << 29)       /*  Transfer Request when 4 empty stages */
-#define SIFCTR_TFWM_1          (7 << 29)       /*  Transfer Request when 1 empty stage */
+#define SIFCTR_TFWM_64         (0UL << 29)     /*  Transfer Request when 64 empty stages */
+#define SIFCTR_TFWM_32         (1UL << 29)     /*  Transfer Request when 32 empty stages */
+#define SIFCTR_TFWM_24         (2UL << 29)     /*  Transfer Request when 24 empty stages */
+#define SIFCTR_TFWM_16         (3UL << 29)     /*  Transfer Request when 16 empty stages */
+#define SIFCTR_TFWM_12         (4UL << 29)     /*  Transfer Request when 12 empty stages */
+#define SIFCTR_TFWM_8          (5UL << 29)     /*  Transfer Request when 8 empty stages */
+#define SIFCTR_TFWM_4          (6UL << 29)     /*  Transfer Request when 4 empty stages */
+#define SIFCTR_TFWM_1          (7UL << 29)     /*  Transfer Request when 1 empty stage */
 #define SIFCTR_TFUA_MASK       GENMASK(26, 20) /* Transmit FIFO Usable Area */
 #define SIFCTR_TFUA_SHIFT      20
 #define SIFCTR_TFUA(i)         ((i) << SIFCTR_TFUA_SHIFT)
index 7477a11e12be0e2bf47006ce9e579fdd9f1fda30..f2170f4b50775ea175c3d0c1e4a7ef0f809e6a52 100644 (file)
@@ -1717,6 +1717,10 @@ static int __spi_pump_transfer_message(struct spi_controller *ctlr,
                        pm_runtime_put_noidle(ctlr->dev.parent);
                        dev_err(&ctlr->dev, "Failed to power device: %d\n",
                                ret);
+
+                       msg->status = ret;
+                       spi_finalize_current_message(ctlr);
+
                        return ret;
                }
        }
index 5ac5cb60bae67b8caa54d47e0ebb740d6a4505ab..bc6eb0dd66a495f04ae5d0c398611895351c9b2f 100644 (file)
@@ -49,7 +49,6 @@
  */
 #define DEFAULT_DURATION_JIFFIES (6)
 
-static unsigned int target_mwait;
 static struct dentry *debug_dir;
 static bool poll_pkg_cstate_enable;
 
@@ -312,34 +311,6 @@ MODULE_PARM_DESC(window_size, "sliding window in number of clamping cycles\n"
        "\twindow size results in slower response time but more smooth\n"
        "\tclamping results. default to 2.");
 
-static void find_target_mwait(void)
-{
-       unsigned int eax, ebx, ecx, edx;
-       unsigned int highest_cstate = 0;
-       unsigned int highest_subcstate = 0;
-       int i;
-
-       if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
-               return;
-
-       cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
-
-       if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
-           !(ecx & CPUID5_ECX_INTERRUPT_BREAK))
-               return;
-
-       edx >>= MWAIT_SUBSTATE_SIZE;
-       for (i = 0; i < 7 && edx; i++, edx >>= MWAIT_SUBSTATE_SIZE) {
-               if (edx & MWAIT_SUBSTATE_MASK) {
-                       highest_cstate = i;
-                       highest_subcstate = edx & MWAIT_SUBSTATE_MASK;
-               }
-       }
-       target_mwait = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
-               (highest_subcstate - 1);
-
-}
-
 struct pkg_cstate_info {
        bool skip;
        int msr_index;
@@ -759,9 +730,6 @@ static int __init powerclamp_probe(void)
                return -ENODEV;
        }
 
-       /* find the deepest mwait value */
-       find_target_mwait();
-
        return 0;
 }
 
index 10704f2d3af5302f71a931e13bd0ba5432d46fe2..fd3e175d83423261d68124cd26fc0351488ad05e 100644 (file)
@@ -1715,7 +1715,7 @@ static int bch2_discard_one_bucket(struct btree_trans *trans,
                 * This works without any other locks because this is the only
                 * thread that removes items from the need_discard tree
                 */
-               bch2_trans_unlock(trans);
+               bch2_trans_unlock_long(trans);
                blkdev_issue_discard(ca->disk_sb.bdev,
                                     k.k->p.offset * ca->mi.bucket_size,
                                     ca->mi.bucket_size,
index bed75c93c06904e06f70e3afa92cc507a68b81c9..6843974423381029e7a8cf24fd4cd5c6c33627cd 100644 (file)
@@ -92,7 +92,7 @@ static noinline void print_cycle(struct printbuf *out, struct lock_graph *g)
                        continue;
 
                bch2_btree_trans_to_text(out, i->trans);
-               bch2_prt_task_backtrace(out, task, i == g->g ? 5 : 1);
+               bch2_prt_task_backtrace(out, task, i == g->g ? 5 : 1, GFP_NOWAIT);
        }
 }
 
@@ -227,7 +227,7 @@ static noinline int break_cycle(struct lock_graph *g, struct printbuf *cycle)
                        prt_printf(&buf, "backtrace:");
                        prt_newline(&buf);
                        printbuf_indent_add(&buf, 2);
-                       bch2_prt_task_backtrace(&buf, trans->locking_wait.task, 2);
+                       bch2_prt_task_backtrace(&buf, trans->locking_wait.task, 2, GFP_NOWAIT);
                        printbuf_indent_sub(&buf, 2);
                        prt_newline(&buf);
                }
index cadda9bbe4a4cd67fe3b6f6f7aa5a5d93e496307..7bdba8507fc93cdfdecc29de3e70e5589cf8177b 100644 (file)
@@ -627,7 +627,7 @@ restart:
                prt_printf(&i->buf, "backtrace:");
                prt_newline(&i->buf);
                printbuf_indent_add(&i->buf, 2);
-               bch2_prt_task_backtrace(&i->buf, task, 0);
+               bch2_prt_task_backtrace(&i->buf, task, 0, GFP_KERNEL);
                printbuf_indent_sub(&i->buf, 2);
                prt_newline(&i->buf);
 
index dc52918d06ef3f91c30484822a5a170b08543f9c..8c70123b6a0c809b6d50040593281c2e9c115828 100644 (file)
@@ -79,7 +79,7 @@ void bch2_inode_flush_nocow_writes_async(struct bch_fs *c,
                        continue;
 
                bio = container_of(bio_alloc_bioset(ca->disk_sb.bdev, 0,
-                                                   REQ_OP_FLUSH,
+                                                   REQ_OP_WRITE|REQ_PREFLUSH,
                                                    GFP_KERNEL,
                                                    &c->nocow_flush_bioset),
                                   struct nocow_flush, bio);
index 4f0ecd60567570b7364cef517225ea0e3dfa5575..6a760777bafb06d08b449ee0db4308a77b54b11e 100644 (file)
@@ -119,22 +119,19 @@ static int lookup_inode(struct btree_trans *trans, u64 inode_nr,
        if (!ret)
                *snapshot = iter.pos.snapshot;
 err:
-       bch_err_msg(trans->c, ret, "fetching inode %llu:%u", inode_nr, *snapshot);
        bch2_trans_iter_exit(trans, &iter);
        return ret;
 }
 
-static int __lookup_dirent(struct btree_trans *trans,
+static int lookup_dirent_in_snapshot(struct btree_trans *trans,
                           struct bch_hash_info hash_info,
                           subvol_inum dir, struct qstr *name,
-                          u64 *target, unsigned *type)
+                          u64 *target, unsigned *type, u32 snapshot)
 {
        struct btree_iter iter;
        struct bkey_s_c_dirent d;
-       int ret;
-
-       ret = bch2_hash_lookup(trans, &iter, bch2_dirent_hash_desc,
-                              &hash_info, dir, name, 0);
+       int ret = bch2_hash_lookup_in_snapshot(trans, &iter, bch2_dirent_hash_desc,
+                              &hash_info, dir, name, 0, snapshot);
        if (ret)
                return ret;
 
@@ -225,15 +222,16 @@ static int lookup_lostfound(struct btree_trans *trans, u32 snapshot,
 
        struct bch_inode_unpacked root_inode;
        struct bch_hash_info root_hash_info;
-       ret = lookup_inode(trans, root_inum.inum, &root_inode, &snapshot);
+       u32 root_inode_snapshot = snapshot;
+       ret = lookup_inode(trans, root_inum.inum, &root_inode, &root_inode_snapshot);
        bch_err_msg(c, ret, "looking up root inode");
        if (ret)
                return ret;
 
        root_hash_info = bch2_hash_info_init(c, &root_inode);
 
-       ret = __lookup_dirent(trans, root_hash_info, root_inum,
-                             &lostfound_str, &inum, &d_type);
+       ret = lookup_dirent_in_snapshot(trans, root_hash_info, root_inum,
+                             &lostfound_str, &inum, &d_type, snapshot);
        if (bch2_err_matches(ret, ENOENT))
                goto create_lostfound;
 
@@ -250,7 +248,10 @@ static int lookup_lostfound(struct btree_trans *trans, u32 snapshot,
         * The bch2_check_dirents pass has already run, dangling dirents
         * shouldn't exist here:
         */
-       return lookup_inode(trans, inum, lostfound, &snapshot);
+       ret = lookup_inode(trans, inum, lostfound, &snapshot);
+       bch_err_msg(c, ret, "looking up lost+found %llu:%u in (root inode %llu, snapshot root %u)",
+                   inum, snapshot, root_inum.inum, bch2_snapshot_root(c, snapshot));
+       return ret;
 
 create_lostfound:
        /*
index d71d26e39521e4410a90cb6bf3e21df360e6c201..bc890776eb57933a5931edd2a2f07570f52b7ab3 100644 (file)
@@ -233,7 +233,7 @@ static void __journal_entry_close(struct journal *j, unsigned closed_val, bool t
                prt_str(&pbuf, "entry size: ");
                prt_human_readable_u64(&pbuf, vstruct_bytes(buf->data));
                prt_newline(&pbuf);
-               bch2_prt_task_backtrace(&pbuf, current, 1);
+               bch2_prt_task_backtrace(&pbuf, current, 1, GFP_NOWAIT);
                trace_journal_entry_close(c, pbuf.buf);
                printbuf_exit(&pbuf);
        }
index 04a1e79a5ed392cd8ebaac922a2516b374a6d094..bfd6585e746da45880da9b5ad8fb502586cbf933 100644 (file)
@@ -1988,7 +1988,8 @@ CLOSURE_CALLBACK(bch2_journal_write)
                        percpu_ref_get(&ca->io_ref);
 
                        bio = ca->journal.bio;
-                       bio_reset(bio, ca->disk_sb.bdev, REQ_OP_FLUSH);
+                       bio_reset(bio, ca->disk_sb.bdev,
+                                 REQ_OP_WRITE|REQ_PREFLUSH);
                        bio->bi_end_io          = journal_write_endio;
                        bio->bi_private         = ca;
                        closure_bio_submit(bio, cl);
index 89fdb7c21134ebbb6c145a88ed5b1943ab54588a..fcaa5a888744881a4f6c37dd77fbd8cf73b2f4d0 100644 (file)
@@ -160,21 +160,16 @@ static inline bool is_visible_key(struct bch_hash_desc desc, subvol_inum inum, s
 }
 
 static __always_inline int
-bch2_hash_lookup(struct btree_trans *trans,
+bch2_hash_lookup_in_snapshot(struct btree_trans *trans,
                 struct btree_iter *iter,
                 const struct bch_hash_desc desc,
                 const struct bch_hash_info *info,
                 subvol_inum inum, const void *key,
-                unsigned flags)
+                unsigned flags, u32 snapshot)
 {
        struct bkey_s_c k;
-       u32 snapshot;
        int ret;
 
-       ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
-       if (ret)
-               return ret;
-
        for_each_btree_key_upto_norestart(trans, *iter, desc.btree_id,
                           SPOS(inum.inum, desc.hash_key(info, key), snapshot),
                           POS(inum.inum, U64_MAX),
@@ -194,6 +189,19 @@ bch2_hash_lookup(struct btree_trans *trans,
        return ret ?: -BCH_ERR_ENOENT_str_hash_lookup;
 }
 
+static __always_inline int
+bch2_hash_lookup(struct btree_trans *trans,
+                struct btree_iter *iter,
+                const struct bch_hash_desc desc,
+                const struct bch_hash_info *info,
+                subvol_inum inum, const void *key,
+                unsigned flags)
+{
+       u32 snapshot;
+       return  bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot) ?:
+               bch2_hash_lookup_in_snapshot(trans, iter, desc, info, inum, key, flags, snapshot);
+}
+
 static __always_inline int
 bch2_hash_hole(struct btree_trans *trans,
               struct btree_iter *iter,
index a135136adeee355cb8854482e85b0c85e6c1b8f8..56b815fd9fc6ee5a541aa8e7007f3c00025c493d 100644 (file)
@@ -272,14 +272,14 @@ void bch2_print_string_as_lines(const char *prefix, const char *lines)
        console_unlock();
 }
 
-int bch2_save_backtrace(bch_stacktrace *stack, struct task_struct *task, unsigned skipnr)
+int bch2_save_backtrace(bch_stacktrace *stack, struct task_struct *task, unsigned skipnr,
+                       gfp_t gfp)
 {
 #ifdef CONFIG_STACKTRACE
        unsigned nr_entries = 0;
-       int ret = 0;
 
        stack->nr = 0;
-       ret = darray_make_room(stack, 32);
+       int ret = darray_make_room_gfp(stack, 32, gfp);
        if (ret)
                return ret;
 
@@ -308,10 +308,10 @@ void bch2_prt_backtrace(struct printbuf *out, bch_stacktrace *stack)
        }
 }
 
-int bch2_prt_task_backtrace(struct printbuf *out, struct task_struct *task, unsigned skipnr)
+int bch2_prt_task_backtrace(struct printbuf *out, struct task_struct *task, unsigned skipnr, gfp_t gfp)
 {
        bch_stacktrace stack = { 0 };
-       int ret = bch2_save_backtrace(&stack, task, skipnr + 1);
+       int ret = bch2_save_backtrace(&stack, task, skipnr + 1, gfp);
 
        bch2_prt_backtrace(out, &stack);
        darray_exit(&stack);
index df67bf55fe2bc2d74265eb8a52fe6d22fca2fd2f..b414736d59a5b36d1344657eaeb6de6113ec5a09 100644 (file)
@@ -348,9 +348,9 @@ void bch2_prt_u64_base2(struct printbuf *, u64);
 void bch2_print_string_as_lines(const char *prefix, const char *lines);
 
 typedef DARRAY(unsigned long) bch_stacktrace;
-int bch2_save_backtrace(bch_stacktrace *stack, struct task_struct *, unsigned);
+int bch2_save_backtrace(bch_stacktrace *stack, struct task_struct *, unsigned, gfp_t);
 void bch2_prt_backtrace(struct printbuf *, bch_stacktrace *);
-int bch2_prt_task_backtrace(struct printbuf *, struct task_struct *, unsigned);
+int bch2_prt_task_backtrace(struct printbuf *, struct task_struct *, unsigned, gfp_t);
 
 static inline void prt_bdevname(struct printbuf *out, struct block_device *bdev)
 {
index 279933e007d21798549df035b4aa595597f225b6..7cc5841577b240f90f9a623e64adc87c3fb24982 100644 (file)
 struct z_erofs_decompress_req {
        struct super_block *sb;
        struct page **in, **out;
-
        unsigned short pageofs_in, pageofs_out;
        unsigned int inputsize, outputsize;
 
-       /* indicate the algorithm will be used for decompression */
-       unsigned int alg;
+       unsigned int alg;       /* the algorithm for decompression */
        bool inplace_io, partial_decoding, fillgaps;
+       gfp_t gfp;      /* allocation flags for extra temporary buffers */
 };
 
 struct z_erofs_decompressor {
index 072ef6a66823ef351923f2c0514c9ddec50e5d8f..d4cee95af14c7490e85706589853059b99b7e688 100644 (file)
@@ -111,8 +111,9 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_lz4_decompress_ctx *ctx,
                        victim = availables[--top];
                        get_page(victim);
                } else {
-                       victim = erofs_allocpage(pagepool,
-                                                GFP_KERNEL | __GFP_NOFAIL);
+                       victim = erofs_allocpage(pagepool, rq->gfp);
+                       if (!victim)
+                               return -ENOMEM;
                        set_page_private(victim, Z_EROFS_SHORTLIVED_PAGE);
                }
                rq->out[i] = victim;
index 4a64a9c91dd322379d2c4be2268f6c4c24f995ee..b98872058abe82d4034b84c1c93c46645b50968b 100644 (file)
@@ -95,7 +95,7 @@ int z_erofs_load_deflate_config(struct super_block *sb,
 }
 
 int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
-                              struct page **pagepool)
+                              struct page **pgpl)
 {
        const unsigned int nrpages_out =
                PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
@@ -158,8 +158,12 @@ again:
                        strm->z.avail_out = min_t(u32, outsz, PAGE_SIZE - pofs);
                        outsz -= strm->z.avail_out;
                        if (!rq->out[no]) {
-                               rq->out[no] = erofs_allocpage(pagepool,
-                                               GFP_KERNEL | __GFP_NOFAIL);
+                               rq->out[no] = erofs_allocpage(pgpl, rq->gfp);
+                               if (!rq->out[no]) {
+                                       kout = NULL;
+                                       err = -ENOMEM;
+                                       break;
+                               }
                                set_page_private(rq->out[no],
                                                 Z_EROFS_SHORTLIVED_PAGE);
                        }
@@ -211,8 +215,11 @@ again:
 
                        DBG_BUGON(erofs_page_is_managed(EROFS_SB(sb),
                                                        rq->in[j]));
-                       tmppage = erofs_allocpage(pagepool,
-                                                 GFP_KERNEL | __GFP_NOFAIL);
+                       tmppage = erofs_allocpage(pgpl, rq->gfp);
+                       if (!tmppage) {
+                               err = -ENOMEM;
+                               goto failed;
+                       }
                        set_page_private(tmppage, Z_EROFS_SHORTLIVED_PAGE);
                        copy_highpage(tmppage, rq->in[j]);
                        rq->in[j] = tmppage;
@@ -230,7 +237,7 @@ again:
                        break;
                }
        }
-
+failed:
        if (zlib_inflateEnd(&strm->z) != Z_OK && !err)
                err = -EIO;
        if (kout)
index 2dd14f99c1dc10eeea57eedfccbb649bf184828f..6ca357d83cfa458225f20e2d6f6a45307fef2194 100644 (file)
@@ -148,7 +148,7 @@ again:
 }
 
 int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
-                           struct page **pagepool)
+                           struct page **pgpl)
 {
        const unsigned int nrpages_out =
                PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
@@ -215,8 +215,11 @@ again:
                                                   PAGE_SIZE - pageofs);
                        outlen -= strm->buf.out_size;
                        if (!rq->out[no] && rq->fillgaps) {     /* deduped */
-                               rq->out[no] = erofs_allocpage(pagepool,
-                                               GFP_KERNEL | __GFP_NOFAIL);
+                               rq->out[no] = erofs_allocpage(pgpl, rq->gfp);
+                               if (!rq->out[no]) {
+                                       err = -ENOMEM;
+                                       break;
+                               }
                                set_page_private(rq->out[no],
                                                 Z_EROFS_SHORTLIVED_PAGE);
                        }
@@ -258,8 +261,11 @@ again:
 
                        DBG_BUGON(erofs_page_is_managed(EROFS_SB(rq->sb),
                                                        rq->in[j]));
-                       tmppage = erofs_allocpage(pagepool,
-                                                 GFP_KERNEL | __GFP_NOFAIL);
+                       tmppage = erofs_allocpage(pgpl, rq->gfp);
+                       if (!tmppage) {
+                               err = -ENOMEM;
+                               goto failed;
+                       }
                        set_page_private(tmppage, Z_EROFS_SHORTLIVED_PAGE);
                        copy_highpage(tmppage, rq->in[j]);
                        rq->in[j] = tmppage;
@@ -277,6 +283,7 @@ again:
                        break;
                }
        }
+failed:
        if (no < nrpages_out && strm->buf.out)
                kunmap(rq->out[no]);
        if (ni < nrpages_in)
index bc12030393b24f26231fb363ac07e3150cd6babb..5ff90026fd43fe116e3a34178bf00b9f3303b411 100644 (file)
@@ -459,7 +459,7 @@ static struct erofs_fscache *erofs_fscache_acquire_cookie(struct super_block *sb
 
        inode->i_size = OFFSET_MAX;
        inode->i_mapping->a_ops = &erofs_fscache_meta_aops;
-       mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
+       mapping_set_gfp_mask(inode->i_mapping, GFP_KERNEL);
        inode->i_blkbits = EROFS_SB(sb)->blkszbits;
        inode->i_private = ctx;
 
index 3d616dea55dc3dbccbac495988f865947b0d2a96..36e638e8b53a3d290fcb7ade23a40dc4805be9e6 100644 (file)
@@ -60,7 +60,7 @@ static void *erofs_read_inode(struct erofs_buf *buf,
                } else {
                        const unsigned int gotten = sb->s_blocksize - *ofs;
 
-                       copied = kmalloc(vi->inode_isize, GFP_NOFS);
+                       copied = kmalloc(vi->inode_isize, GFP_KERNEL);
                        if (!copied) {
                                err = -ENOMEM;
                                goto err_out;
index 5dea308764b45038f8236bf31b004067f0f297a6..e146d09151af4188efe4cb7bf2ad4a938b8596af 100644 (file)
@@ -81,7 +81,7 @@ struct erofs_workgroup *erofs_insert_workgroup(struct super_block *sb,
 repeat:
        xa_lock(&sbi->managed_pslots);
        pre = __xa_cmpxchg(&sbi->managed_pslots, grp->index,
-                          NULL, grp, GFP_NOFS);
+                          NULL, grp, GFP_KERNEL);
        if (pre) {
                if (xa_is_err(pre)) {
                        pre = ERR_PTR(xa_err(pre));
index 692c0c39be638dc4b2454b63968a0467043ddc7a..ff0aa72b0db342f10ed7c1b565d2cc7bd6a540ff 100644 (file)
@@ -82,6 +82,9 @@ struct z_erofs_pcluster {
        /* L: indicate several pageofs_outs or not */
        bool multibases;
 
+       /* L: whether extra buffer allocations are best-effort */
+       bool besteffort;
+
        /* A: compressed bvecs (can be cached or inplaced pages) */
        struct z_erofs_bvec compressed_bvecs[];
 };
@@ -230,7 +233,7 @@ static int z_erofs_bvec_enqueue(struct z_erofs_bvec_iter *iter,
                struct page *nextpage = *candidate_bvpage;
 
                if (!nextpage) {
-                       nextpage = erofs_allocpage(pagepool, GFP_NOFS);
+                       nextpage = erofs_allocpage(pagepool, GFP_KERNEL);
                        if (!nextpage)
                                return -ENOMEM;
                        set_page_private(nextpage, Z_EROFS_SHORTLIVED_PAGE);
@@ -302,7 +305,7 @@ static struct z_erofs_pcluster *z_erofs_alloc_pcluster(unsigned int size)
                if (nrpages > pcs->maxpages)
                        continue;
 
-               pcl = kmem_cache_zalloc(pcs->slab, GFP_NOFS);
+               pcl = kmem_cache_zalloc(pcs->slab, GFP_KERNEL);
                if (!pcl)
                        return ERR_PTR(-ENOMEM);
                pcl->pclustersize = size;
@@ -563,21 +566,19 @@ static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe)
                        __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN;
        unsigned int i;
 
-       if (i_blocksize(fe->inode) != PAGE_SIZE)
-               return;
-       if (fe->mode < Z_EROFS_PCLUSTER_FOLLOWED)
+       if (i_blocksize(fe->inode) != PAGE_SIZE ||
+           fe->mode < Z_EROFS_PCLUSTER_FOLLOWED)
                return;
 
        for (i = 0; i < pclusterpages; ++i) {
                struct page *page, *newpage;
                void *t;        /* mark pages just found for debugging */
 
-               /* the compressed page was loaded before */
+               /* Inaccurate check w/o locking to avoid unneeded lookups */
                if (READ_ONCE(pcl->compressed_bvecs[i].page))
                        continue;
 
                page = find_get_page(mc, pcl->obj.index + i);
-
                if (page) {
                        t = (void *)((unsigned long)page | 1);
                        newpage = NULL;
@@ -597,9 +598,13 @@ static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe)
                        set_page_private(newpage, Z_EROFS_PREALLOCATED_PAGE);
                        t = (void *)((unsigned long)newpage | 1);
                }
-
-               if (!cmpxchg_relaxed(&pcl->compressed_bvecs[i].page, NULL, t))
+               spin_lock(&pcl->obj.lockref.lock);
+               if (!pcl->compressed_bvecs[i].page) {
+                       pcl->compressed_bvecs[i].page = t;
+                       spin_unlock(&pcl->obj.lockref.lock);
                        continue;
+               }
+               spin_unlock(&pcl->obj.lockref.lock);
 
                if (page)
                        put_page(page);
@@ -694,7 +699,7 @@ static void z_erofs_cache_invalidate_folio(struct folio *folio,
        DBG_BUGON(stop > folio_size(folio) || stop < length);
 
        if (offset == 0 && stop == folio_size(folio))
-               while (!z_erofs_cache_release_folio(folio, GFP_NOFS))
+               while (!z_erofs_cache_release_folio(folio, 0))
                        cond_resched();
 }
 
@@ -713,36 +718,30 @@ int erofs_init_managed_cache(struct super_block *sb)
        set_nlink(inode, 1);
        inode->i_size = OFFSET_MAX;
        inode->i_mapping->a_ops = &z_erofs_cache_aops;
-       mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
+       mapping_set_gfp_mask(inode->i_mapping, GFP_KERNEL);
        EROFS_SB(sb)->managed_cache = inode;
        return 0;
 }
 
-static bool z_erofs_try_inplace_io(struct z_erofs_decompress_frontend *fe,
-                                  struct z_erofs_bvec *bvec)
-{
-       struct z_erofs_pcluster *const pcl = fe->pcl;
-
-       while (fe->icur > 0) {
-               if (!cmpxchg(&pcl->compressed_bvecs[--fe->icur].page,
-                            NULL, bvec->page)) {
-                       pcl->compressed_bvecs[fe->icur] = *bvec;
-                       return true;
-               }
-       }
-       return false;
-}
-
 /* callers must be with pcluster lock held */
 static int z_erofs_attach_page(struct z_erofs_decompress_frontend *fe,
                               struct z_erofs_bvec *bvec, bool exclusive)
 {
+       struct z_erofs_pcluster *pcl = fe->pcl;
        int ret;
 
        if (exclusive) {
                /* give priority for inplaceio to use file pages first */
-               if (z_erofs_try_inplace_io(fe, bvec))
+               spin_lock(&pcl->obj.lockref.lock);
+               while (fe->icur > 0) {
+                       if (pcl->compressed_bvecs[--fe->icur].page)
+                               continue;
+                       pcl->compressed_bvecs[fe->icur] = *bvec;
+                       spin_unlock(&pcl->obj.lockref.lock);
                        return 0;
+               }
+               spin_unlock(&pcl->obj.lockref.lock);
+
                /* otherwise, check if it can be used as a bvpage */
                if (fe->mode >= Z_EROFS_PCLUSTER_FOLLOWED &&
                    !fe->candidate_bvpage)
@@ -964,7 +963,7 @@ static int z_erofs_read_fragment(struct super_block *sb, struct page *page,
 }
 
 static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe,
-                               struct page *page)
+                               struct page *page, bool ra)
 {
        struct inode *const inode = fe->inode;
        struct erofs_map_blocks *const map = &fe->map;
@@ -1014,6 +1013,7 @@ repeat:
                err = z_erofs_pcluster_begin(fe);
                if (err)
                        goto out;
+               fe->pcl->besteffort |= !ra;
        }
 
        /*
@@ -1280,6 +1280,9 @@ static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be,
                                        .inplace_io = overlapped,
                                        .partial_decoding = pcl->partial,
                                        .fillgaps = pcl->multibases,
+                                       .gfp = pcl->besteffort ?
+                                               GFP_KERNEL | __GFP_NOFAIL :
+                                               GFP_NOWAIT | __GFP_NORETRY
                                 }, be->pagepool);
 
        /* must handle all compressed pages before actual file pages */
@@ -1322,6 +1325,7 @@ static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be,
        pcl->length = 0;
        pcl->partial = true;
        pcl->multibases = false;
+       pcl->besteffort = false;
        pcl->bvset.nextpage = NULL;
        pcl->vcnt = 0;
 
@@ -1423,23 +1427,26 @@ static void z_erofs_fill_bio_vec(struct bio_vec *bvec,
 {
        gfp_t gfp = mapping_gfp_mask(mc);
        bool tocache = false;
-       struct z_erofs_bvec *zbv = pcl->compressed_bvecs + nr;
+       struct z_erofs_bvec zbv;
        struct address_space *mapping;
-       struct page *page, *oldpage;
+       struct page *page;
        int justfound, bs = i_blocksize(f->inode);
 
        /* Except for inplace pages, the entire page can be used for I/Os */
        bvec->bv_offset = 0;
        bvec->bv_len = PAGE_SIZE;
 repeat:
-       oldpage = READ_ONCE(zbv->page);
-       if (!oldpage)
+       spin_lock(&pcl->obj.lockref.lock);
+       zbv = pcl->compressed_bvecs[nr];
+       page = zbv.page;
+       justfound = (unsigned long)page & 1UL;
+       page = (struct page *)((unsigned long)page & ~1UL);
+       pcl->compressed_bvecs[nr].page = page;
+       spin_unlock(&pcl->obj.lockref.lock);
+       if (!page)
                goto out_allocpage;
 
-       justfound = (unsigned long)oldpage & 1UL;
-       page = (struct page *)((unsigned long)oldpage & ~1UL);
        bvec->bv_page = page;
-
        DBG_BUGON(z_erofs_is_shortlived_page(page));
        /*
         * Handle preallocated cached pages.  We tried to allocate such pages
@@ -1448,7 +1455,6 @@ repeat:
         */
        if (page->private == Z_EROFS_PREALLOCATED_PAGE) {
                set_page_private(page, 0);
-               WRITE_ONCE(zbv->page, page);
                tocache = true;
                goto out_tocache;
        }
@@ -1459,9 +1465,9 @@ repeat:
         * therefore it is impossible for `mapping` to be NULL.
         */
        if (mapping && mapping != mc) {
-               if (zbv->offset < 0)
-                       bvec->bv_offset = round_up(-zbv->offset, bs);
-               bvec->bv_len = round_up(zbv->end, bs) - bvec->bv_offset;
+               if (zbv.offset < 0)
+                       bvec->bv_offset = round_up(-zbv.offset, bs);
+               bvec->bv_len = round_up(zbv.end, bs) - bvec->bv_offset;
                return;
        }
 
@@ -1471,7 +1477,6 @@ repeat:
 
        /* the cached page is still in managed cache */
        if (page->mapping == mc) {
-               WRITE_ONCE(zbv->page, page);
                /*
                 * The cached page is still available but without a valid
                 * `->private` pcluster hint.  Let's reconnect them.
@@ -1503,11 +1508,15 @@ repeat:
        put_page(page);
 out_allocpage:
        page = erofs_allocpage(&f->pagepool, gfp | __GFP_NOFAIL);
-       if (oldpage != cmpxchg(&zbv->page, oldpage, page)) {
+       spin_lock(&pcl->obj.lockref.lock);
+       if (pcl->compressed_bvecs[nr].page) {
                erofs_pagepool_add(&f->pagepool, page);
+               spin_unlock(&pcl->obj.lockref.lock);
                cond_resched();
                goto repeat;
        }
+       pcl->compressed_bvecs[nr].page = page;
+       spin_unlock(&pcl->obj.lockref.lock);
        bvec->bv_page = page;
 out_tocache:
        if (!tocache || bs != PAGE_SIZE ||
@@ -1685,6 +1694,7 @@ submit_bio_retry:
 
                        if (cur + bvec.bv_len > end)
                                bvec.bv_len = end - cur;
+                       DBG_BUGON(bvec.bv_len < sb->s_blocksize);
                        if (!bio_add_page(bio, bvec.bv_page, bvec.bv_len,
                                          bvec.bv_offset))
                                goto submit_bio_retry;
@@ -1785,7 +1795,7 @@ static void z_erofs_pcluster_readmore(struct z_erofs_decompress_frontend *f,
                        if (PageUptodate(page))
                                unlock_page(page);
                        else
-                               (void)z_erofs_do_read_page(f, page);
+                               (void)z_erofs_do_read_page(f, page, !!rac);
                        put_page(page);
                }
 
@@ -1806,7 +1816,7 @@ static int z_erofs_read_folio(struct file *file, struct folio *folio)
        f.headoffset = (erofs_off_t)folio->index << PAGE_SHIFT;
 
        z_erofs_pcluster_readmore(&f, NULL, true);
-       err = z_erofs_do_read_page(&f, &folio->page);
+       err = z_erofs_do_read_page(&f, &folio->page, false);
        z_erofs_pcluster_readmore(&f, NULL, false);
        z_erofs_pcluster_end(&f);
 
@@ -1847,7 +1857,7 @@ static void z_erofs_readahead(struct readahead_control *rac)
                folio = head;
                head = folio_get_private(folio);
 
-               err = z_erofs_do_read_page(&f, &folio->page);
+               err = z_erofs_do_read_page(&f, &folio->page, true);
                if (err && err != -EINTR)
                        erofs_err(inode->i_sb, "readahead error at folio %lu @ nid %llu",
                                  folio->index, EROFS_I(inode)->nid);
index 522edcbb2ce4d17a7f219e6016bff31f5d466fdd..0687f952956c34b6d85e785ee13f231d49679e64 100644 (file)
@@ -501,7 +501,7 @@ static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
        struct inode *inode = mapping->host;
        struct exfat_inode_info *ei = EXFAT_I(inode);
        loff_t pos = iocb->ki_pos;
-       loff_t size = iocb->ki_pos + iov_iter_count(iter);
+       loff_t size = pos + iov_iter_count(iter);
        int rw = iov_iter_rw(iter);
        ssize_t ret;
 
@@ -525,11 +525,10 @@ static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
         */
        ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block);
        if (ret < 0) {
-               if (rw == WRITE)
+               if (rw == WRITE && ret != -EIOCBQUEUED)
                        exfat_write_failed(mapping, size);
 
-               if (ret != -EIOCBQUEUED)
-                       return ret;
+               return ret;
        } else
                size = pos + ret;
 
index 177f1f41f225458344cd000147d71079c19689ab..2e215e8c3c88e57d6ed17ba6cc5cb22420e99af6 100644 (file)
 
 static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags)
 {
-       struct dentry *parent = NULL;
+       struct dentry *parent;
        struct gfs2_sbd *sdp;
        struct gfs2_inode *dip;
-       struct inode *dinode, *inode;
+       struct inode *inode;
        struct gfs2_holder d_gh;
        struct gfs2_inode *ip = NULL;
        int error, valid = 0;
        int had_lock = 0;
 
-       if (flags & LOOKUP_RCU) {
-               dinode = d_inode_rcu(READ_ONCE(dentry->d_parent));
-               if (!dinode)
-                       return -ECHILD;
-       } else {
-               parent = dget_parent(dentry);
-               dinode = d_inode(parent);
-       }
-       sdp = GFS2_SB(dinode);
-       dip = GFS2_I(dinode);
+       if (flags & LOOKUP_RCU)
+               return -ECHILD;
+
+       parent = dget_parent(dentry);
+       sdp = GFS2_SB(d_inode(parent));
+       dip = GFS2_I(d_inode(parent));
        inode = d_inode(dentry);
 
        if (inode) {
@@ -66,8 +62,7 @@ static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags)
 
        had_lock = (gfs2_glock_is_locked_by_me(dip->i_gl) != NULL);
        if (!had_lock) {
-               error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED,
-                                          flags & LOOKUP_RCU ? GL_NOBLOCK : 0, &d_gh);
+               error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
                if (error)
                        goto out;
        }
index 6bfc9383b7b8eca60aad0d88c341904b572681bb..1b95db2c3aac3c9a9d5d881985e70622342b52ab 100644 (file)
@@ -1882,10 +1882,10 @@ int gfs2_permission(struct mnt_idmap *idmap, struct inode *inode,
                WARN_ON_ONCE(!may_not_block);
                return -ECHILD;
         }
-       if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
-               int noblock = may_not_block ? GL_NOBLOCK : 0;
-               error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
-                                          LM_FLAG_ANY | noblock, &i_gh);
+       if (gfs2_glock_is_locked_by_me(gl) == NULL) {
+               if (may_not_block)
+                       return -ECHILD;
+               error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
                if (error)
                        return error;
        }
index ea5b8e57d904e20b964fb5e627c4bae894370401..671664fed3077f794de3a5707bd69b90cb328e78 100644 (file)
@@ -340,7 +340,7 @@ static ssize_t hugetlbfs_read_iter(struct kiocb *iocb, struct iov_iter *to)
                } else {
                        folio_unlock(folio);
 
-                       if (!folio_test_has_hwpoisoned(folio))
+                       if (!folio_test_hwpoison(folio))
                                want = nr;
                        else {
                                /*
index 8eec84c651bfba2da05af6a834c4ad3fe7a60f2b..cb3cda1390adb16e1ad8031783849ba59022db87 100644 (file)
@@ -2763,9 +2763,7 @@ static int dbBackSplit(dmtree_t *tp, int leafno, bool is_ctl)
  *     leafno  - the number of the leaf to be updated.
  *     newval  - the new value for the leaf.
  *
- * RETURN VALUES:
- *  0          - success
- *     -EIO    - i/o error
+ * RETURN VALUES: none
  */
 static int dbJoin(dmtree_t *tp, int leafno, int newval, bool is_ctl)
 {
@@ -2792,10 +2790,6 @@ static int dbJoin(dmtree_t *tp, int leafno, int newval, bool is_ctl)
                 * get the buddy size (number of words covered) of
                 * the new value.
                 */
-
-               if ((newval - tp->dmt_budmin) > BUDMIN)
-                       return -EIO;
-
                budsz = BUDSIZE(newval, tp->dmt_budmin);
 
                /* try to join.
index 971892620504730e6e2265f50c54874f3d676eac..1daeb5714faad14c24c49a5efd5d118aaf04b54c 100644 (file)
@@ -145,21 +145,27 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
        struct cached_fid *cfid;
        struct cached_fids *cfids;
        const char *npath;
+       int retries = 0, cur_sleep = 1;
 
        if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache ||
            is_smb1_server(tcon->ses->server) || (dir_cache_timeout == 0))
                return -EOPNOTSUPP;
 
        ses = tcon->ses;
-       server = cifs_pick_channel(ses);
        cfids = tcon->cfids;
 
-       if (!server->ops->new_lease_key)
-               return -EIO;
-
        if (cifs_sb->root == NULL)
                return -ENOENT;
 
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
+       oplock = SMB2_OPLOCK_LEVEL_II;
+       server = cifs_pick_channel(ses);
+
+       if (!server->ops->new_lease_key)
+               return -EIO;
+
        utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
        if (!utf16_path)
                return -ENOMEM;
@@ -268,6 +274,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
         */
        cfid->has_lease = true;
 
+       if (retries) {
+               smb2_set_replay(server, &rqst[0]);
+               smb2_set_replay(server, &rqst[1]);
+       }
+
        rc = compound_send_recv(xid, ses, server,
                                flags, 2, rqst,
                                resp_buftype, rsp_iov);
@@ -367,6 +378,11 @@ out:
                atomic_inc(&tcon->num_remote_opens);
        }
        kfree(utf16_path);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
index ef4c2e3c9fa6130b129be94d4a15c4724b952ed9..6322f0f68a176b177c943b074fe414c4905bf9bb 100644 (file)
@@ -572,7 +572,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
                len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
                UniStrupr(user);
        } else {
-               memset(user, '\0', 2);
+               *(u16 *)user = 0;
        }
 
        rc = crypto_shash_update(ses->server->secmech.hmacmd5,
index e902de4e475af9cc3483fba922a1b11cbb068cd9..2a4a4e3a8751f2ce8f0409ce79dc5024e02bb883 100644 (file)
@@ -396,7 +396,7 @@ cifs_alloc_inode(struct super_block *sb)
        spin_lock_init(&cifs_inode->writers_lock);
        cifs_inode->writers = 0;
        cifs_inode->netfs.inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */
-       cifs_inode->server_eof = 0;
+       cifs_inode->netfs.remote_i_size = 0;
        cifs_inode->uniqueid = 0;
        cifs_inode->createtime = 0;
        cifs_inode->epoch = 0;
@@ -1380,6 +1380,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
        struct inode *src_inode = file_inode(src_file);
        struct inode *target_inode = file_inode(dst_file);
        struct cifsInodeInfo *src_cifsi = CIFS_I(src_inode);
+       struct cifsInodeInfo *target_cifsi = CIFS_I(target_inode);
        struct cifsFileInfo *smb_file_src;
        struct cifsFileInfo *smb_file_target;
        struct cifs_tcon *src_tcon;
@@ -1428,7 +1429,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
         * Advance the EOF marker after the flush above to the end of the range
         * if it's short of that.
         */
-       if (src_cifsi->server_eof < off + len) {
+       if (src_cifsi->netfs.remote_i_size < off + len) {
                rc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len);
                if (rc < 0)
                        goto unlock;
@@ -1452,12 +1453,22 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
        /* Discard all the folios that overlap the destination region. */
        truncate_inode_pages_range(&target_inode->i_data, fstart, fend);
 
+       fscache_invalidate(cifs_inode_cookie(target_inode), NULL,
+                          i_size_read(target_inode), 0);
+
        rc = file_modified(dst_file);
        if (!rc) {
                rc = target_tcon->ses->server->ops->copychunk_range(xid,
                        smb_file_src, smb_file_target, off, len, destoff);
-               if (rc > 0 && destoff + rc > i_size_read(target_inode))
+               if (rc > 0 && destoff + rc > i_size_read(target_inode)) {
                        truncate_setsize(target_inode, destoff + rc);
+                       netfs_resize_file(&target_cifsi->netfs,
+                                         i_size_read(target_inode), true);
+                       fscache_resize_cookie(cifs_inode_cookie(target_inode),
+                                             i_size_read(target_inode));
+               }
+               if (rc > 0 && destoff + rc > target_cifsi->netfs.zero_point)
+                       target_cifsi->netfs.zero_point = destoff + rc;
        }
 
        file_accessed(src_file);
index 20036fb16cececeaa3acffb78d81691ac86b1ec3..16befff4cbb47c9ac104b052401a490398d0fac9 100644 (file)
  */
 #define CIFS_DEF_ACTIMEO (1 * HZ)
 
+/*
+ * max sleep time before retry to server
+ */
+#define CIFS_MAX_SLEEP 2000
+
 /*
  * max attribute cache timeout (jiffies) - 2^30
  */
@@ -1501,6 +1506,7 @@ struct cifs_writedata {
        struct smbd_mr                  *mr;
 #endif
        struct cifs_credits             credits;
+       bool                            replay;
 };
 
 /*
@@ -1561,7 +1567,6 @@ struct cifsInodeInfo {
        spinlock_t writers_lock;
        unsigned int writers;           /* Number of writers on this inode */
        unsigned long time;             /* jiffies of last update of inode */
-       u64  server_eof;                /* current file size on server -- protected by i_lock */
        u64  uniqueid;                  /* server inode number */
        u64  createtime;                /* creation time on server */
        __u8 lease_key[SMB2_LEASE_KEY_SIZE];    /* lease key for this inode */
@@ -1831,6 +1836,13 @@ static inline bool is_retryable_error(int error)
        return false;
 }
 
+static inline bool is_replayable_error(int error)
+{
+       if (error == -EAGAIN || error == -ECONNABORTED)
+               return true;
+       return false;
+}
+
 
 /* cifs_get_writable_file() flags */
 #define FIND_WR_ANY         0
index 90da81d0372a09224e87abc257dc9adb8509a6f8..b75282c204dadff986f9711d38e775834c30ddd2 100644 (file)
@@ -2120,8 +2120,8 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
 {
        loff_t end_of_write = offset + bytes_written;
 
-       if (end_of_write > cifsi->server_eof)
-               cifsi->server_eof = end_of_write;
+       if (end_of_write > cifsi->netfs.remote_i_size)
+               netfs_resize_file(&cifsi->netfs, end_of_write, true);
 }
 
 static ssize_t
@@ -3247,8 +3247,8 @@ cifs_uncached_writev_complete(struct work_struct *work)
 
        spin_lock(&inode->i_lock);
        cifs_update_eof(cifsi, wdata->offset, wdata->bytes);
-       if (cifsi->server_eof > inode->i_size)
-               i_size_write(inode, cifsi->server_eof);
+       if (cifsi->netfs.remote_i_size > inode->i_size)
+               i_size_write(inode, cifsi->netfs.remote_i_size);
        spin_unlock(&inode->i_lock);
 
        complete(&wdata->done);
@@ -3300,6 +3300,7 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list,
                        if (wdata->cfile->invalidHandle)
                                rc = -EAGAIN;
                        else {
+                               wdata->replay = true;
 #ifdef CONFIG_CIFS_SMB_DIRECT
                                if (wdata->mr) {
                                        wdata->mr->need_invalidate = true;
index f0989484f2c648796d923fcd3f998b150b1f92cf..d02f8ba29cb5bf22f1dcdcc3932f20afc3094f22 100644 (file)
@@ -104,7 +104,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
        fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode);
        mtime = inode_get_mtime(inode);
        if (timespec64_equal(&mtime, &fattr->cf_mtime) &&
-           cifs_i->server_eof == fattr->cf_eof) {
+           cifs_i->netfs.remote_i_size == fattr->cf_eof) {
                cifs_dbg(FYI, "%s: inode %llu is unchanged\n",
                         __func__, cifs_i->uniqueid);
                return;
@@ -194,7 +194,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
        else
                clear_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags);
 
-       cifs_i->server_eof = fattr->cf_eof;
+       cifs_i->netfs.remote_i_size = fattr->cf_eof;
        /*
         * Can't safely change the file size here if the client is writing to
         * it due to potential races.
@@ -2858,7 +2858,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
 
 set_size_out:
        if (rc == 0) {
-               cifsInode->server_eof = attrs->ia_size;
+               netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
                cifs_setsize(inode, attrs->ia_size);
                /*
                 * i_blocks is not related to (i_size / i_blksize), but instead
@@ -3011,6 +3011,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
        if ((attrs->ia_valid & ATTR_SIZE) &&
            attrs->ia_size != i_size_read(inode)) {
                truncate_setsize(inode, attrs->ia_size);
+               netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
                fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
        }
 
@@ -3210,6 +3211,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
        if ((attrs->ia_valid & ATTR_SIZE) &&
            attrs->ia_size != i_size_read(inode)) {
                truncate_setsize(inode, attrs->ia_size);
+               netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
                fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
        }
 
index 94255401b38dcb24c705f255731db2791e171c8d..3b1b01d10f7d7a2f1d12b158ded96d58203f80d0 100644 (file)
@@ -141,7 +141,7 @@ retry:
                                        if (likely(reparse_inode_match(inode, fattr))) {
                                                fattr->cf_mode = inode->i_mode;
                                                fattr->cf_rdev = inode->i_rdev;
-                                               fattr->cf_eof = CIFS_I(inode)->server_eof;
+                                               fattr->cf_eof = CIFS_I(inode)->netfs.remote_i_size;
                                                fattr->cf_symlink_target = NULL;
                                        } else {
                                                CIFS_I(inode)->time = 0;
index a652200540c8aa5d2aa0ecd68ed50cc66f587d05..05818cd6d932e91792ecc65d764eba0a942cb28d 100644 (file)
@@ -120,6 +120,14 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
        unsigned int size[2];
        void *data[2];
        int len;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
+       oplock = SMB2_OPLOCK_LEVEL_NONE;
+       num_rqst = 0;
+       server = cifs_pick_channel(ses);
 
        vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
        if (vars == NULL)
@@ -127,8 +135,6 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
        rqst = &vars->rqst[0];
        rsp_iov = &vars->rsp_iov[0];
 
-       server = cifs_pick_channel(ses);
-
        if (smb3_encryption_required(tcon))
                flags |= CIFS_TRANSFORM_REQ;
 
@@ -463,15 +469,24 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
        num_rqst++;
 
        if (cfile) {
+               if (retries)
+                       for (i = 1; i < num_rqst - 2; i++)
+                               smb2_set_replay(server, &rqst[i]);
+
                rc = compound_send_recv(xid, ses, server,
                                        flags, num_rqst - 2,
                                        &rqst[1], &resp_buftype[1],
                                        &rsp_iov[1]);
-       } else
+       } else {
+               if (retries)
+                       for (i = 0; i < num_rqst; i++)
+                               smb2_set_replay(server, &rqst[i]);
+
                rc = compound_send_recv(xid, ses, server,
                                        flags, num_rqst,
                                        rqst, resp_buftype,
                                        rsp_iov);
+       }
 
 finished:
        num_rqst = 0;
@@ -620,9 +635,6 @@ finished:
        }
        SMB2_close_free(&rqst[num_rqst]);
 
-       if (cfile)
-               cifsFileInfo_put(cfile);
-
        num_cmds += 2;
        if (out_iov && out_buftype) {
                memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov));
@@ -632,7 +644,16 @@ finished:
                for (i = 0; i < num_cmds; i++)
                        free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base);
        }
+       num_cmds -= 2; /* correct num_cmds as there could be a retry */
        kfree(vars);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
+       if (cfile)
+               cifsFileInfo_put(cfile);
+
        return rc;
 }
 
index d9553c2556a290dcea14434e00df9d854e713aa3..83c898afc8354bf04c7a86ee57e4343ad3618319 100644 (file)
@@ -1108,7 +1108,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
 {
        struct smb2_compound_vars *vars;
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = cifs_pick_channel(ses);
+       struct TCP_Server_Info *server;
        struct smb_rqst *rqst;
        struct kvec *rsp_iov;
        __le16 *utf16_path = NULL;
@@ -1124,6 +1124,13 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
        struct smb2_file_full_ea_info *ea = NULL;
        struct smb2_query_info_rsp *rsp;
        int rc, used_len = 0;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = CIFS_CP_CREATE_CLOSE_OP;
+       oplock = SMB2_OPLOCK_LEVEL_NONE;
+       server = cifs_pick_channel(ses);
 
        if (smb3_encryption_required(tcon))
                flags |= CIFS_TRANSFORM_REQ;
@@ -1244,6 +1251,12 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
                goto sea_exit;
        smb2_set_related(&rqst[2]);
 
+       if (retries) {
+               smb2_set_replay(server, &rqst[0]);
+               smb2_set_replay(server, &rqst[1]);
+               smb2_set_replay(server, &rqst[2]);
+       }
+
        rc = compound_send_recv(xid, ses, server,
                                flags, 3, rqst,
                                resp_buftype, rsp_iov);
@@ -1260,6 +1273,11 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
        kfree(vars);
 out_free_path:
        kfree(utf16_path);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 #endif
@@ -1484,7 +1502,7 @@ smb2_ioctl_query_info(const unsigned int xid,
        struct smb_rqst *rqst;
        struct kvec *rsp_iov;
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = cifs_pick_channel(ses);
+       struct TCP_Server_Info *server;
        char __user *arg = (char __user *)p;
        struct smb_query_info qi;
        struct smb_query_info __user *pqi;
@@ -1501,6 +1519,13 @@ smb2_ioctl_query_info(const unsigned int xid,
        void *data[2];
        int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR;
        void (*free_req1_func)(struct smb_rqst *r);
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = CIFS_CP_CREATE_CLOSE_OP;
+       oplock = SMB2_OPLOCK_LEVEL_NONE;
+       server = cifs_pick_channel(ses);
 
        vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
        if (vars == NULL)
@@ -1641,6 +1666,12 @@ smb2_ioctl_query_info(const unsigned int xid,
                goto free_req_1;
        smb2_set_related(&rqst[2]);
 
+       if (retries) {
+               smb2_set_replay(server, &rqst[0]);
+               smb2_set_replay(server, &rqst[1]);
+               smb2_set_replay(server, &rqst[2]);
+       }
+
        rc = compound_send_recv(xid, ses, server,
                                flags, 3, rqst,
                                resp_buftype, rsp_iov);
@@ -1701,6 +1732,11 @@ free_output_buffer:
        kfree(buffer);
 free_vars:
        kfree(vars);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -2227,8 +2263,14 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
        struct cifs_open_parms oparms;
        struct smb2_query_directory_rsp *qd_rsp = NULL;
        struct smb2_create_rsp *op_rsp = NULL;
-       struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
-       int retry_count = 0;
+       struct TCP_Server_Info *server;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
+       oplock = SMB2_OPLOCK_LEVEL_NONE;
+       server = cifs_pick_channel(tcon->ses);
 
        utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
        if (!utf16_path)
@@ -2278,14 +2320,15 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
 
        smb2_set_related(&rqst[1]);
 
-again:
+       if (retries) {
+               smb2_set_replay(server, &rqst[0]);
+               smb2_set_replay(server, &rqst[1]);
+       }
+
        rc = compound_send_recv(xid, tcon->ses, server,
                                flags, 2, rqst,
                                resp_buftype, rsp_iov);
 
-       if (rc == -EAGAIN && retry_count++ < 10)
-               goto again;
-
        /* If the open failed there is nothing to do */
        op_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;
        if (op_rsp == NULL || op_rsp->hdr.Status != STATUS_SUCCESS) {
@@ -2333,6 +2376,11 @@ again:
        SMB2_query_directory_free(&rqst[1]);
        free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
        free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -2457,6 +2505,22 @@ smb2_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid,
                                 CIFS_CACHE_READ(cinode) ? 1 : 0);
 }
 
+void
+smb2_set_replay(struct TCP_Server_Info *server, struct smb_rqst *rqst)
+{
+       struct smb2_hdr *shdr;
+
+       if (server->dialect < SMB30_PROT_ID)
+               return;
+
+       shdr = (struct smb2_hdr *)(rqst->rq_iov[0].iov_base);
+       if (shdr == NULL) {
+               cifs_dbg(FYI, "shdr NULL in smb2_set_related\n");
+               return;
+       }
+       shdr->Flags |= SMB2_FLAGS_REPLAY_OPERATION;
+}
+
 void
 smb2_set_related(struct smb_rqst *rqst)
 {
@@ -2529,6 +2593,27 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
        shdr->NextCommand = cpu_to_le32(len);
 }
 
+/*
+ * helper function for exponential backoff and check if replayable
+ */
+bool smb2_should_replay(struct cifs_tcon *tcon,
+                               int *pretries,
+                               int *pcur_sleep)
+{
+       if (!pretries || !pcur_sleep)
+               return false;
+
+       if (tcon->retry || (*pretries)++ < tcon->ses->server->retrans) {
+               msleep(*pcur_sleep);
+               (*pcur_sleep) = ((*pcur_sleep) << 1);
+               if ((*pcur_sleep) > CIFS_MAX_SLEEP)
+                       (*pcur_sleep) = CIFS_MAX_SLEEP;
+               return true;
+       }
+
+       return false;
+}
+
 /*
  * Passes the query info response back to the caller on success.
  * Caller need to free this with free_rsp_buf().
@@ -2542,7 +2627,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
 {
        struct smb2_compound_vars *vars;
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = cifs_pick_channel(ses);
+       struct TCP_Server_Info *server;
        int flags = CIFS_CP_CREATE_CLOSE_OP;
        struct smb_rqst *rqst;
        int resp_buftype[3];
@@ -2553,6 +2638,13 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
        int rc;
        __le16 *utf16_path;
        struct cached_fid *cfid = NULL;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = CIFS_CP_CREATE_CLOSE_OP;
+       oplock = SMB2_OPLOCK_LEVEL_NONE;
+       server = cifs_pick_channel(ses);
 
        if (!path)
                path = "";
@@ -2633,6 +2725,14 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
                goto qic_exit;
        smb2_set_related(&rqst[2]);
 
+       if (retries) {
+               if (!cfid) {
+                       smb2_set_replay(server, &rqst[0]);
+                       smb2_set_replay(server, &rqst[2]);
+               }
+               smb2_set_replay(server, &rqst[1]);
+       }
+
        if (cfid) {
                rc = compound_send_recv(xid, ses, server,
                                        flags, 1, &rqst[1],
@@ -2665,6 +2765,11 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
        kfree(vars);
 out_free_path:
        kfree(utf16_path);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -3213,6 +3318,9 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
                                  cfile->fid.volatile_fid, cfile->pid, new_size);
                if (rc >= 0) {
                        truncate_setsize(inode, new_size);
+                       netfs_resize_file(&cifsi->netfs, new_size, true);
+                       if (offset < cifsi->netfs.zero_point)
+                               cifsi->netfs.zero_point = offset;
                        fscache_resize_cookie(cifs_inode_cookie(inode), new_size);
                }
        }
@@ -3436,7 +3544,7 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
                rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
                                  cfile->fid.volatile_fid, cfile->pid, new_eof);
                if (rc == 0) {
-                       cifsi->server_eof = new_eof;
+                       netfs_resize_file(&cifsi->netfs, new_eof, true);
                        cifs_setsize(inode, new_eof);
                        cifs_truncate_page(inode->i_mapping, inode->i_size);
                        truncate_setsize(inode, new_eof);
@@ -3528,8 +3636,9 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
        int rc;
        unsigned int xid;
        struct inode *inode = file_inode(file);
-       struct cifsFileInfo *cfile = file->private_data;
        struct cifsInodeInfo *cifsi = CIFS_I(inode);
+       struct cifsFileInfo *cfile = file->private_data;
+       struct netfs_inode *ictx = &cifsi->netfs;
        loff_t old_eof, new_eof;
 
        xid = get_xid();
@@ -3549,6 +3658,7 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
                goto out_2;
 
        truncate_pagecache_range(inode, off, old_eof);
+       ictx->zero_point = old_eof;
 
        rc = smb2_copychunk_range(xid, cfile, cfile, off + len,
                                  old_eof - off - len, off);
@@ -3563,9 +3673,10 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
 
        rc = 0;
 
-       cifsi->server_eof = i_size_read(inode) - len;
-       truncate_setsize(inode, cifsi->server_eof);
-       fscache_resize_cookie(cifs_inode_cookie(inode), cifsi->server_eof);
+       truncate_setsize(inode, new_eof);
+       netfs_resize_file(&cifsi->netfs, new_eof, true);
+       ictx->zero_point = new_eof;
+       fscache_resize_cookie(cifs_inode_cookie(inode), new_eof);
 out_2:
        filemap_invalidate_unlock(inode->i_mapping);
  out:
@@ -3581,6 +3692,7 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
        unsigned int xid;
        struct cifsFileInfo *cfile = file->private_data;
        struct inode *inode = file_inode(file);
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
        __u64 count, old_eof, new_eof;
 
        xid = get_xid();
@@ -3608,6 +3720,7 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
                goto out_2;
 
        truncate_setsize(inode, new_eof);
+       netfs_resize_file(&cifsi->netfs, i_size_read(inode), true);
        fscache_resize_cookie(cifs_inode_cookie(inode), i_size_read(inode));
 
        rc = smb2_copychunk_range(xid, cfile, cfile, off, count, off + len);
index 288199f0b987df98ba3fab9320523bc16e73092d..86f6f35b7f32e8498e2628350abf43daa0d97f96 100644 (file)
@@ -195,7 +195,6 @@ cifs_chan_skip_or_disable(struct cifs_ses *ses,
                pserver = server->primary_server;
                cifs_signal_cifsd_for_reconnect(pserver, false);
 skip_terminate:
-               mutex_unlock(&ses->session_mutex);
                return -EHOSTDOWN;
        }
 
@@ -2765,7 +2764,14 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
        int flags = 0;
        unsigned int total_len;
        __le16 *utf16_path = NULL;
-       struct TCP_Server_Info *server = cifs_pick_channel(ses);
+       struct TCP_Server_Info *server;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
+       n_iov = 2;
+       server = cifs_pick_channel(ses);
 
        cifs_dbg(FYI, "mkdir\n");
 
@@ -2869,6 +2875,10 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
        /* no need to inc num_remote_opens because we close it just below */
        trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, full_path, CREATE_NOT_FILE,
                                    FILE_WRITE_ATTRIBUTES);
+
+       if (retries)
+               smb2_set_replay(server, &rqst);
+
        /* resource #4: response buffer */
        rc = cifs_send_recv(xid, ses, server,
                            &rqst, &resp_buftype, flags, &rsp_iov);
@@ -2906,6 +2916,11 @@ err_free_req:
        cifs_small_buf_release(req);
 err_free_path:
        kfree(utf16_path);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -3101,12 +3116,18 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        struct smb2_create_rsp *rsp = NULL;
        struct cifs_tcon *tcon = oparms->tcon;
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = cifs_pick_channel(ses);
+       struct TCP_Server_Info *server;
        struct kvec iov[SMB2_CREATE_IOV_SIZE];
        struct kvec rsp_iov = {NULL, 0};
        int resp_buftype = CIFS_NO_BUFFER;
        int rc = 0;
        int flags = 0;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
+       server = cifs_pick_channel(ses);
 
        cifs_dbg(FYI, "create/open\n");
        if (!ses || !server)
@@ -3128,6 +3149,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, oparms->path,
                oparms->create_options, oparms->desired_access);
 
+       if (retries)
+               smb2_set_replay(server, &rqst);
+
        rc = cifs_send_recv(xid, ses, server,
                            &rqst, &resp_buftype, flags,
                            &rsp_iov);
@@ -3181,6 +3205,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
 creat_exit:
        SMB2_open_free(&rqst);
        free_rsp_buf(resp_buftype, rsp);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -3305,15 +3334,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        int resp_buftype = CIFS_NO_BUFFER;
        int rc = 0;
        int flags = 0;
-
-       cifs_dbg(FYI, "SMB2 IOCTL\n");
-
-       if (out_data != NULL)
-               *out_data = NULL;
-
-       /* zero out returned data len, in case of error */
-       if (plen)
-               *plen = 0;
+       int retries = 0, cur_sleep = 1;
 
        if (!tcon)
                return -EIO;
@@ -3322,10 +3343,23 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        if (!ses)
                return -EIO;
 
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
        server = cifs_pick_channel(ses);
+
        if (!server)
                return -EIO;
 
+       cifs_dbg(FYI, "SMB2 IOCTL\n");
+
+       if (out_data != NULL)
+               *out_data = NULL;
+
+       /* zero out returned data len, in case of error */
+       if (plen)
+               *plen = 0;
+
        if (smb3_encryption_required(tcon))
                flags |= CIFS_TRANSFORM_REQ;
 
@@ -3340,6 +3374,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        if (rc)
                goto ioctl_exit;
 
+       if (retries)
+               smb2_set_replay(server, &rqst);
+
        rc = cifs_send_recv(xid, ses, server,
                            &rqst, &resp_buftype, flags,
                            &rsp_iov);
@@ -3409,6 +3446,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
 ioctl_exit:
        SMB2_ioctl_free(&rqst);
        free_rsp_buf(resp_buftype, rsp);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -3480,13 +3522,20 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
        struct smb_rqst rqst;
        struct smb2_close_rsp *rsp = NULL;
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = cifs_pick_channel(ses);
+       struct TCP_Server_Info *server;
        struct kvec iov[1];
        struct kvec rsp_iov;
        int resp_buftype = CIFS_NO_BUFFER;
        int rc = 0;
        int flags = 0;
        bool query_attrs = false;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
+       query_attrs = false;
+       server = cifs_pick_channel(ses);
 
        cifs_dbg(FYI, "Close\n");
 
@@ -3512,6 +3561,9 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
        if (rc)
                goto close_exit;
 
+       if (retries)
+               smb2_set_replay(server, &rqst);
+
        rc = cifs_send_recv(xid, ses, server,
                            &rqst, &resp_buftype, flags, &rsp_iov);
        rsp = (struct smb2_close_rsp *)rsp_iov.iov_base;
@@ -3545,6 +3597,11 @@ close_exit:
                        cifs_dbg(VFS, "handle cancelled close fid 0x%llx returned error %d\n",
                                 persistent_fid, tmp_rc);
        }
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -3675,12 +3732,19 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
        struct TCP_Server_Info *server;
        int flags = 0;
        bool allocated = false;
+       int retries = 0, cur_sleep = 1;
 
        cifs_dbg(FYI, "Query Info\n");
 
        if (!ses)
                return -EIO;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
+       allocated = false;
        server = cifs_pick_channel(ses);
+
        if (!server)
                return -EIO;
 
@@ -3702,6 +3766,9 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
        trace_smb3_query_info_enter(xid, persistent_fid, tcon->tid,
                                    ses->Suid, info_class, (__u32)info_type);
 
+       if (retries)
+               smb2_set_replay(server, &rqst);
+
        rc = cifs_send_recv(xid, ses, server,
                            &rqst, &resp_buftype, flags, &rsp_iov);
        rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
@@ -3744,6 +3811,11 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
 qinf_exit:
        SMB2_query_info_free(&rqst);
        free_rsp_buf(resp_buftype, rsp);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -3844,7 +3916,7 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
                u32 *plen /* returned data len */)
 {
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = cifs_pick_channel(ses);
+       struct TCP_Server_Info *server;
        struct smb_rqst rqst;
        struct smb2_change_notify_rsp *smb_rsp;
        struct kvec iov[1];
@@ -3852,6 +3924,12 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
        int resp_buftype = CIFS_NO_BUFFER;
        int flags = 0;
        int rc = 0;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
+       server = cifs_pick_channel(ses);
 
        cifs_dbg(FYI, "change notify\n");
        if (!ses || !server)
@@ -3876,6 +3954,10 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
 
        trace_smb3_notify_enter(xid, persistent_fid, tcon->tid, ses->Suid,
                                (u8)watch_tree, completion_filter);
+
+       if (retries)
+               smb2_set_replay(server, &rqst);
+
        rc = cifs_send_recv(xid, ses, server,
                            &rqst, &resp_buftype, flags, &rsp_iov);
 
@@ -3910,6 +3992,11 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
        if (rqst.rq_iov)
                cifs_small_buf_release(rqst.rq_iov[0].iov_base); /* request */
        free_rsp_buf(resp_buftype, rsp_iov.iov_base);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -4152,10 +4239,16 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        struct smb_rqst rqst;
        struct kvec iov[1];
        struct kvec rsp_iov = {NULL, 0};
-       struct TCP_Server_Info *server = cifs_pick_channel(ses);
+       struct TCP_Server_Info *server;
        int resp_buftype = CIFS_NO_BUFFER;
        int flags = 0;
        int rc = 0;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
+       server = cifs_pick_channel(ses);
 
        cifs_dbg(FYI, "flush\n");
        if (!ses || !(ses->server))
@@ -4175,6 +4268,10 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
                goto flush_exit;
 
        trace_smb3_flush_enter(xid, persistent_fid, tcon->tid, ses->Suid);
+
+       if (retries)
+               smb2_set_replay(server, &rqst);
+
        rc = cifs_send_recv(xid, ses, server,
                            &rqst, &resp_buftype, flags, &rsp_iov);
 
@@ -4189,6 +4286,11 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
  flush_exit:
        SMB2_flush_free(&rqst);
        free_rsp_buf(resp_buftype, rsp_iov.iov_base);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -4668,7 +4770,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
        struct cifs_io_parms *io_parms = NULL;
        int credit_request;
 
-       if (!wdata->server)
+       if (!wdata->server || wdata->replay)
                server = wdata->server = cifs_pick_channel(tcon->ses);
 
        /*
@@ -4753,6 +4855,8 @@ smb2_async_writev(struct cifs_writedata *wdata,
        rqst.rq_nvec = 1;
        rqst.rq_iter = wdata->iter;
        rqst.rq_iter_size = iov_iter_count(&rqst.rq_iter);
+       if (wdata->replay)
+               smb2_set_replay(server, &rqst);
 #ifdef CONFIG_CIFS_SMB_DIRECT
        if (wdata->mr)
                iov[0].iov_len += sizeof(struct smbd_buffer_descriptor_v1);
@@ -4826,18 +4930,21 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
        int flags = 0;
        unsigned int total_len;
        struct TCP_Server_Info *server;
+       int retries = 0, cur_sleep = 1;
 
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
        *nbytes = 0;
-
-       if (n_vec < 1)
-               return rc;
-
        if (!io_parms->server)
                io_parms->server = cifs_pick_channel(io_parms->tcon->ses);
        server = io_parms->server;
        if (server == NULL)
                return -ECONNABORTED;
 
+       if (n_vec < 1)
+               return rc;
+
        rc = smb2_plain_req_init(SMB2_WRITE, io_parms->tcon, server,
                                 (void **) &req, &total_len);
        if (rc)
@@ -4871,6 +4978,9 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
        rqst.rq_iov = iov;
        rqst.rq_nvec = n_vec + 1;
 
+       if (retries)
+               smb2_set_replay(server, &rqst);
+
        rc = cifs_send_recv(xid, io_parms->tcon->ses, server,
                            &rqst,
                            &resp_buftype, flags, &rsp_iov);
@@ -4895,6 +5005,11 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
 
        cifs_small_buf_release(req);
        free_rsp_buf(resp_buftype, rsp);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(io_parms->tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -5206,8 +5321,14 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        struct kvec rsp_iov;
        int rc = 0;
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = cifs_pick_channel(ses);
+       struct TCP_Server_Info *server;
        int flags = 0;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
+       server = cifs_pick_channel(ses);
 
        if (!ses || !(ses->server))
                return -EIO;
@@ -5227,6 +5348,9 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        if (rc)
                goto qdir_exit;
 
+       if (retries)
+               smb2_set_replay(server, &rqst);
+
        rc = cifs_send_recv(xid, ses, server,
                            &rqst, &resp_buftype, flags, &rsp_iov);
        rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base;
@@ -5261,6 +5385,11 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
 qdir_exit:
        SMB2_query_directory_free(&rqst);
        free_rsp_buf(resp_buftype, rsp);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -5327,8 +5456,14 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
        int rc = 0;
        int resp_buftype;
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = cifs_pick_channel(ses);
+       struct TCP_Server_Info *server;
        int flags = 0;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
+       server = cifs_pick_channel(ses);
 
        if (!ses || !server)
                return -EIO;
@@ -5356,6 +5491,8 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
                return rc;
        }
 
+       if (retries)
+               smb2_set_replay(server, &rqst);
 
        rc = cifs_send_recv(xid, ses, server,
                            &rqst, &resp_buftype, flags,
@@ -5371,6 +5508,11 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
 
        free_rsp_buf(resp_buftype, rsp);
        kfree(iov);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -5423,12 +5565,18 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
        int rc;
        struct smb2_oplock_break *req = NULL;
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = cifs_pick_channel(ses);
+       struct TCP_Server_Info *server;
        int flags = CIFS_OBREAK_OP;
        unsigned int total_len;
        struct kvec iov[1];
        struct kvec rsp_iov;
        int resp_buf_type;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = CIFS_OBREAK_OP;
+       server = cifs_pick_channel(ses);
 
        cifs_dbg(FYI, "SMB2_oplock_break\n");
        rc = smb2_plain_req_init(SMB2_OPLOCK_BREAK, tcon, server,
@@ -5453,15 +5601,21 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
        rqst.rq_iov = iov;
        rqst.rq_nvec = 1;
 
+       if (retries)
+               smb2_set_replay(server, &rqst);
+
        rc = cifs_send_recv(xid, ses, server,
                            &rqst, &resp_buf_type, flags, &rsp_iov);
        cifs_small_buf_release(req);
-
        if (rc) {
                cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
                cifs_dbg(FYI, "Send error in Oplock Break = %d\n", rc);
        }
 
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -5547,9 +5701,15 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
        int rc = 0;
        int resp_buftype;
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = cifs_pick_channel(ses);
+       struct TCP_Server_Info *server;
        FILE_SYSTEM_POSIX_INFO *info = NULL;
        int flags = 0;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
+       server = cifs_pick_channel(ses);
 
        rc = build_qfs_info_req(&iov, tcon, server,
                                FS_POSIX_INFORMATION,
@@ -5565,6 +5725,9 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
        rqst.rq_iov = &iov;
        rqst.rq_nvec = 1;
 
+       if (retries)
+               smb2_set_replay(server, &rqst);
+
        rc = cifs_send_recv(xid, ses, server,
                            &rqst, &resp_buftype, flags, &rsp_iov);
        free_qfs_info_req(&iov);
@@ -5584,6 +5747,11 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
 
 posix_qfsinf_exit:
        free_rsp_buf(resp_buftype, rsp_iov.iov_base);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -5598,9 +5766,15 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
        int rc = 0;
        int resp_buftype;
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = cifs_pick_channel(ses);
+       struct TCP_Server_Info *server;
        struct smb2_fs_full_size_info *info = NULL;
        int flags = 0;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
+       server = cifs_pick_channel(ses);
 
        rc = build_qfs_info_req(&iov, tcon, server,
                                FS_FULL_SIZE_INFORMATION,
@@ -5616,6 +5790,9 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
        rqst.rq_iov = &iov;
        rqst.rq_nvec = 1;
 
+       if (retries)
+               smb2_set_replay(server, &rqst);
+
        rc = cifs_send_recv(xid, ses, server,
                            &rqst, &resp_buftype, flags, &rsp_iov);
        free_qfs_info_req(&iov);
@@ -5635,6 +5812,11 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
 
 qfsinf_exit:
        free_rsp_buf(resp_buftype, rsp_iov.iov_base);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -5649,9 +5831,15 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
        int rc = 0;
        int resp_buftype, max_len, min_len;
        struct cifs_ses *ses = tcon->ses;
-       struct TCP_Server_Info *server = cifs_pick_channel(ses);
+       struct TCP_Server_Info *server;
        unsigned int rsp_len, offset;
        int flags = 0;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = 0;
+       server = cifs_pick_channel(ses);
 
        if (level == FS_DEVICE_INFORMATION) {
                max_len = sizeof(FILE_SYSTEM_DEVICE_INFO);
@@ -5683,6 +5871,9 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
        rqst.rq_iov = &iov;
        rqst.rq_nvec = 1;
 
+       if (retries)
+               smb2_set_replay(server, &rqst);
+
        rc = cifs_send_recv(xid, ses, server,
                            &rqst, &resp_buftype, flags, &rsp_iov);
        free_qfs_info_req(&iov);
@@ -5720,6 +5911,11 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
 
 qfsattr_exit:
        free_rsp_buf(resp_buftype, rsp_iov.iov_base);
+
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
@@ -5737,7 +5933,13 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
        unsigned int count;
        int flags = CIFS_NO_RSP_BUF;
        unsigned int total_len;
-       struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
+       struct TCP_Server_Info *server;
+       int retries = 0, cur_sleep = 1;
+
+replay_again:
+       /* reinitialize for possible replay */
+       flags = CIFS_NO_RSP_BUF;
+       server = cifs_pick_channel(tcon->ses);
 
        cifs_dbg(FYI, "smb2_lockv num lock %d\n", num_lock);
 
@@ -5768,6 +5970,9 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
        rqst.rq_iov = iov;
        rqst.rq_nvec = 2;
 
+       if (retries)
+               smb2_set_replay(server, &rqst);
+
        rc = cifs_send_recv(xid, tcon->ses, server,
                            &rqst, &resp_buf_type, flags,
                            &rsp_iov);
@@ -5779,6 +5984,10 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
                                    tcon->ses->Suid, rc);
        }
 
+       if (is_replayable_error(rc) &&
+           smb2_should_replay(tcon, &retries, &cur_sleep))
+               goto replay_again;
+
        return rc;
 }
 
index 0034b537b0b3f9dd057ce5183f05b6fedb147f77..b3069911e9dd8f51ea38ea54da740049696d18e6 100644 (file)
@@ -122,6 +122,11 @@ extern unsigned long smb_rqst_len(struct TCP_Server_Info *server,
 extern void smb2_set_next_command(struct cifs_tcon *tcon,
                                  struct smb_rqst *rqst);
 extern void smb2_set_related(struct smb_rqst *rqst);
+extern void smb2_set_replay(struct TCP_Server_Info *server,
+                           struct smb_rqst *rqst);
+extern bool smb2_should_replay(struct cifs_tcon *tcon,
+                         int *pretries,
+                         int *pcur_sleep);
 
 /*
  * SMB2 Worker functions - most of protocol specific implementation details
index f0ce26414f17377365ed0201f21dd4e9cdf06b59..1d1ee9f18f373501f781447f82b494857dd8e9f3 100644 (file)
 #include "cifsproto.h"
 #include "../common/md4.h"
 
-#ifndef false
-#define false 0
-#endif
-#ifndef true
-#define true 1
-#endif
-
 /* following came from the other byteorder.h to avoid include conflicts */
 #define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
 #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
index 4f717ad7c21b424d45f785fdbb94be941c1d7f14..e00278fcfa4fa65f063430001c5506e3a2906358 100644 (file)
@@ -400,10 +400,17 @@ unmask:
                                                  server->conn_id, server->hostname);
        }
 smbd_done:
-       if (rc < 0 && rc != -EINTR)
+       /*
+        * there's hardly any use for the layers above to know the
+        * actual error code here. All they should do at this point is
+        * to retry the connection and hope it goes away.
+        */
+       if (rc < 0 && rc != -EINTR && rc != -EAGAIN) {
                cifs_server_dbg(VFS, "Error %d sending data on socket to server\n",
                         rc);
-       else if (rc > 0)
+               rc = -ECONNABORTED;
+               cifs_signal_cifsd_for_reconnect(server, false);
+       } else if (rc > 0)
                rc = 0;
 out:
        cifs_in_send_dec(server);
@@ -1026,6 +1033,9 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
                if (!server || server->terminate)
                        continue;
 
+               if (CIFS_CHAN_NEEDS_RECONNECT(ses, i))
+                       continue;
+
                /*
                 * strictly speaking, we should pick up req_lock to read
                 * server->in_flight. But it shouldn't matter much here if we
index b7521e41402e003a3fd7e121c6003cf7edf23539..0ebf91ffa2361c0940aba0fc301d1a65bf1612e5 100644 (file)
@@ -304,7 +304,8 @@ enum ksmbd_event {
        KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST,
        KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE      = 15,
 
-       KSMBD_EVENT_MAX
+       __KSMBD_EVENT_MAX,
+       KSMBD_EVENT_MAX = __KSMBD_EVENT_MAX - 1
 };
 
 /*
index b49d47bdafc945e31bdfa8d7b9f9931752c4d17c..f29bb03f0dc47bfcb0fe3fc5c5acff16d5a314a8 100644 (file)
@@ -74,7 +74,7 @@ static int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info)
 static int handle_generic_event(struct sk_buff *skb, struct genl_info *info);
 static int ksmbd_ipc_heartbeat_request(void);
 
-static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX] = {
+static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX + 1] = {
        [KSMBD_EVENT_UNSPEC] = {
                .len = 0,
        },
@@ -403,7 +403,7 @@ static int handle_generic_event(struct sk_buff *skb, struct genl_info *info)
                return -EPERM;
 #endif
 
-       if (type >= KSMBD_EVENT_MAX) {
+       if (type > KSMBD_EVENT_MAX) {
                WARN_ON(1);
                return -EINVAL;
        }
index 9d4222154dcc0c92201a0d7a6e4dac77e0eea37b..002a3f0dc7c5880b61045cf7f10f7e078b85d6a9 100644 (file)
@@ -365,6 +365,7 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig,
  * @t:         TCP transport instance
  * @buf:       buffer to store read data from socket
  * @to_read:   number of bytes to read from socket
+ * @max_retries: number of retries if reading from socket fails
  *
  * Return:     on success return number of bytes read from socket,
  *             otherwise return error number
@@ -416,6 +417,7 @@ static void tcp_destroy_socket(struct socket *ksmbd_socket)
 
 /**
  * create_socket - create socket for ksmbd/0
+ * @iface:      interface to bind the created socket to
  *
  * Return:     0 on success, error number otherwise
  */
index 6b211522a13ec100a0af815798d36536b7239c4a..110e8a27218900756f3af6cd515d6e8cf33e9514 100644 (file)
@@ -62,6 +62,46 @@ enum {
 
 #define EVENTFS_MODE_MASK      (EVENTFS_SAVE_MODE - 1)
 
+/*
+ * eventfs_inode reference count management.
+ *
+ * NOTE! We count only references from dentries, in the
+ * form 'dentry->d_fsdata'. There are also references from
+ * directory inodes ('ti->private'), but the dentry reference
+ * count is always a superset of the inode reference count.
+ */
+static void release_ei(struct kref *ref)
+{
+       struct eventfs_inode *ei = container_of(ref, struct eventfs_inode, kref);
+
+       WARN_ON_ONCE(!ei->is_freed);
+
+       kfree(ei->entry_attrs);
+       kfree_const(ei->name);
+       kfree_rcu(ei, rcu);
+}
+
+static inline void put_ei(struct eventfs_inode *ei)
+{
+       if (ei)
+               kref_put(&ei->kref, release_ei);
+}
+
+static inline void free_ei(struct eventfs_inode *ei)
+{
+       if (ei) {
+               ei->is_freed = 1;
+               put_ei(ei);
+       }
+}
+
+static inline struct eventfs_inode *get_ei(struct eventfs_inode *ei)
+{
+       if (ei)
+               kref_get(&ei->kref);
+       return ei;
+}
+
 static struct dentry *eventfs_root_lookup(struct inode *dir,
                                          struct dentry *dentry,
                                          unsigned int flags);
@@ -156,33 +196,30 @@ static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry,
        return ret;
 }
 
-static void update_top_events_attr(struct eventfs_inode *ei, struct dentry *dentry)
+static void update_top_events_attr(struct eventfs_inode *ei, struct super_block *sb)
 {
-       struct inode *inode;
+       struct inode *root;
 
        /* Only update if the "events" was on the top level */
        if (!ei || !(ei->attr.mode & EVENTFS_TOPLEVEL))
                return;
 
        /* Get the tracefs root inode. */
-       inode = d_inode(dentry->d_sb->s_root);
-       ei->attr.uid = inode->i_uid;
-       ei->attr.gid = inode->i_gid;
+       root = d_inode(sb->s_root);
+       ei->attr.uid = root->i_uid;
+       ei->attr.gid = root->i_gid;
 }
 
 static void set_top_events_ownership(struct inode *inode)
 {
        struct tracefs_inode *ti = get_tracefs(inode);
        struct eventfs_inode *ei = ti->private;
-       struct dentry *dentry;
 
        /* The top events directory doesn't get automatically updated */
        if (!ei || !ei->is_events || !(ei->attr.mode & EVENTFS_TOPLEVEL))
                return;
 
-       dentry = ei->dentry;
-
-       update_top_events_attr(ei, dentry);
+       update_top_events_attr(ei, inode->i_sb);
 
        if (!(ei->attr.mode & EVENTFS_SAVE_UID))
                inode->i_uid = ei->attr.uid;
@@ -233,10 +270,11 @@ static struct eventfs_inode *eventfs_find_events(struct dentry *dentry)
 {
        struct eventfs_inode *ei;
 
-       mutex_lock(&eventfs_mutex);
        do {
-               /* The parent always has an ei, except for events itself */
-               ei = dentry->d_parent->d_fsdata;
+               // The parent is stable because we do not do renames
+               dentry = dentry->d_parent;
+               // ... and directories always have d_fsdata
+               ei = dentry->d_fsdata;
 
                /*
                 * If the ei is being freed, the ownership of the children
@@ -246,12 +284,10 @@ static struct eventfs_inode *eventfs_find_events(struct dentry *dentry)
                        ei = NULL;
                        break;
                }
-
-               dentry = ei->dentry;
+               // Walk upwards until you find the events inode
        } while (!ei->is_events);
-       mutex_unlock(&eventfs_mutex);
 
-       update_top_events_attr(ei, dentry);
+       update_top_events_attr(ei, dentry->d_sb);
 
        return ei;
 }
@@ -281,50 +317,11 @@ static void update_inode_attr(struct dentry *dentry, struct inode *inode,
                inode->i_gid = attr->gid;
 }
 
-static void update_gid(struct eventfs_inode *ei, kgid_t gid, int level)
-{
-       struct eventfs_inode *ei_child;
-
-       /* at most we have events/system/event */
-       if (WARN_ON_ONCE(level > 3))
-               return;
-
-       ei->attr.gid = gid;
-
-       if (ei->entry_attrs) {
-               for (int i = 0; i < ei->nr_entries; i++) {
-                       ei->entry_attrs[i].gid = gid;
-               }
-       }
-
-       /*
-        * Only eventfs_inode with dentries are updated, make sure
-        * all eventfs_inodes are updated. If one of the children
-        * do not have a dentry, this function must traverse it.
-        */
-       list_for_each_entry_srcu(ei_child, &ei->children, list,
-                                srcu_read_lock_held(&eventfs_srcu)) {
-               if (!ei_child->dentry)
-                       update_gid(ei_child, gid, level + 1);
-       }
-}
-
-void eventfs_update_gid(struct dentry *dentry, kgid_t gid)
-{
-       struct eventfs_inode *ei = dentry->d_fsdata;
-       int idx;
-
-       idx = srcu_read_lock(&eventfs_srcu);
-       update_gid(ei, gid, 0);
-       srcu_read_unlock(&eventfs_srcu, idx);
-}
-
 /**
- * create_file - create a file in the tracefs filesystem
- * @name: the name of the file to create.
+ * lookup_file - look up a file in the tracefs filesystem
+ * @dentry: the dentry to look up
  * @mode: the permission that the file should have.
  * @attr: saved attributes changed by user
- * @parent: parent dentry for this file.
  * @data: something that the caller will want to get to later on.
  * @fop: struct file_operations that should be used for this file.
  *
@@ -332,30 +329,25 @@ void eventfs_update_gid(struct dentry *dentry, kgid_t gid)
  * directory. The inode.i_private pointer will point to @data in the open()
  * call.
  */
-static struct dentry *create_file(const char *name, umode_t mode,
+static struct dentry *lookup_file(struct eventfs_inode *parent_ei,
+                                 struct dentry *dentry,
+                                 umode_t mode,
                                  struct eventfs_attr *attr,
-                                 struct dentry *parent, void *data,
+                                 void *data,
                                  const struct file_operations *fop)
 {
        struct tracefs_inode *ti;
-       struct dentry *dentry;
        struct inode *inode;
 
        if (!(mode & S_IFMT))
                mode |= S_IFREG;
 
        if (WARN_ON_ONCE(!S_ISREG(mode)))
-               return NULL;
-
-       WARN_ON_ONCE(!parent);
-       dentry = eventfs_start_creating(name, parent);
-
-       if (IS_ERR(dentry))
-               return dentry;
+               return ERR_PTR(-EIO);
 
        inode = tracefs_get_inode(dentry->d_sb);
        if (unlikely(!inode))
-               return eventfs_failed_creating(dentry);
+               return ERR_PTR(-ENOMEM);
 
        /* If the user updated the directory's attributes, use them */
        update_inode_attr(dentry, inode, attr, mode);
@@ -369,32 +361,31 @@ static struct dentry *create_file(const char *name, umode_t mode,
 
        ti = get_tracefs(inode);
        ti->flags |= TRACEFS_EVENT_INODE;
-       d_instantiate(dentry, inode);
-       fsnotify_create(dentry->d_parent->d_inode, dentry);
-       return eventfs_end_creating(dentry);
+
+       // Files have their parent's ei as their fsdata
+       dentry->d_fsdata = get_ei(parent_ei);
+
+       d_add(dentry, inode);
+       return NULL;
 };
 
 /**
- * create_dir - create a dir in the tracefs filesystem
+ * lookup_dir_entry - look up a dir in the tracefs filesystem
+ * @dentry: the directory to look up
  * @ei: the eventfs_inode that represents the directory to create
- * @parent: parent dentry for this file.
  *
- * This function will create a dentry for a directory represented by
+ * This function will look up a dentry for a directory represented by
  * a eventfs_inode.
  */
-static struct dentry *create_dir(struct eventfs_inode *ei, struct dentry *parent)
+static struct dentry *lookup_dir_entry(struct dentry *dentry,
+       struct eventfs_inode *pei, struct eventfs_inode *ei)
 {
        struct tracefs_inode *ti;
-       struct dentry *dentry;
        struct inode *inode;
 
-       dentry = eventfs_start_creating(ei->name, parent);
-       if (IS_ERR(dentry))
-               return dentry;
-
        inode = tracefs_get_inode(dentry->d_sb);
        if (unlikely(!inode))
-               return eventfs_failed_creating(dentry);
+               return ERR_PTR(-ENOMEM);
 
        /* If the user updated the directory's attributes, use them */
        update_inode_attr(dentry, inode, &ei->attr,
@@ -408,64 +399,46 @@ static struct dentry *create_dir(struct eventfs_inode *ei, struct dentry *parent
 
        ti = get_tracefs(inode);
        ti->flags |= TRACEFS_EVENT_INODE;
+       /* Only directories have ti->private set to an ei, not files */
+       ti->private = ei;
 
-       inc_nlink(inode);
-       d_instantiate(dentry, inode);
-       inc_nlink(dentry->d_parent->d_inode);
-       fsnotify_mkdir(dentry->d_parent->d_inode, dentry);
-       return eventfs_end_creating(dentry);
+       dentry->d_fsdata = get_ei(ei);
+
+       d_add(dentry, inode);
+       return NULL;
 }
 
-static void free_ei(struct eventfs_inode *ei)
+static inline struct eventfs_inode *alloc_ei(const char *name)
 {
-       kfree_const(ei->name);
-       kfree(ei->d_children);
-       kfree(ei->entry_attrs);
-       kfree(ei);
+       struct eventfs_inode *ei = kzalloc(sizeof(*ei), GFP_KERNEL);
+
+       if (!ei)
+               return NULL;
+
+       ei->name = kstrdup_const(name, GFP_KERNEL);
+       if (!ei->name) {
+               kfree(ei);
+               return NULL;
+       }
+       kref_init(&ei->kref);
+       return ei;
 }
 
 /**
- * eventfs_set_ei_status_free - remove the dentry reference from an eventfs_inode
- * @ti: the tracefs_inode of the dentry
+ * eventfs_d_release - dentry is going away
  * @dentry: dentry which has the reference to remove.
  *
  * Remove the association between a dentry from an eventfs_inode.
  */
-void eventfs_set_ei_status_free(struct tracefs_inode *ti, struct dentry *dentry)
+void eventfs_d_release(struct dentry *dentry)
 {
-       struct eventfs_inode *ei;
-       int i;
-
-       mutex_lock(&eventfs_mutex);
-
-       ei = dentry->d_fsdata;
-       if (!ei)
-               goto out;
-
-       /* This could belong to one of the files of the ei */
-       if (ei->dentry != dentry) {
-               for (i = 0; i < ei->nr_entries; i++) {
-                       if (ei->d_children[i] == dentry)
-                               break;
-               }
-               if (WARN_ON_ONCE(i == ei->nr_entries))
-                       goto out;
-               ei->d_children[i] = NULL;
-       } else if (ei->is_freed) {
-               free_ei(ei);
-       } else {
-               ei->dentry = NULL;
-       }
-
-       dentry->d_fsdata = NULL;
- out:
-       mutex_unlock(&eventfs_mutex);
+       put_ei(dentry->d_fsdata);
 }
 
 /**
- * create_file_dentry - create a dentry for a file of an eventfs_inode
+ * lookup_file_dentry - create a dentry for a file of an eventfs_inode
  * @ei: the eventfs_inode that the file will be created under
- * @idx: the index into the d_children[] of the @ei
+ * @idx: the index into the entry_attrs[] of the @ei
  * @parent: The parent dentry of the created file.
  * @name: The name of the file to create
  * @mode: The mode of the file.
@@ -476,163 +449,17 @@ void eventfs_set_ei_status_free(struct tracefs_inode *ti, struct dentry *dentry)
  * address located at @e_dentry.
  */
 static struct dentry *
-create_file_dentry(struct eventfs_inode *ei, int idx,
-                  struct dentry *parent, const char *name, umode_t mode, void *data,
+lookup_file_dentry(struct dentry *dentry,
+                  struct eventfs_inode *ei, int idx,
+                  umode_t mode, void *data,
                   const struct file_operations *fops)
 {
        struct eventfs_attr *attr = NULL;
-       struct dentry **e_dentry = &ei->d_children[idx];
-       struct dentry *dentry;
-
-       WARN_ON_ONCE(!inode_is_locked(parent->d_inode));
 
-       mutex_lock(&eventfs_mutex);
-       if (ei->is_freed) {
-               mutex_unlock(&eventfs_mutex);
-               return NULL;
-       }
-       /* If the e_dentry already has a dentry, use it */
-       if (*e_dentry) {
-               dget(*e_dentry);
-               mutex_unlock(&eventfs_mutex);
-               return *e_dentry;
-       }
-
-       /* ei->entry_attrs are protected by SRCU */
        if (ei->entry_attrs)
                attr = &ei->entry_attrs[idx];
 
-       mutex_unlock(&eventfs_mutex);
-
-       dentry = create_file(name, mode, attr, parent, data, fops);
-
-       mutex_lock(&eventfs_mutex);
-
-       if (IS_ERR_OR_NULL(dentry)) {
-               /*
-                * When the mutex was released, something else could have
-                * created the dentry for this e_dentry. In which case
-                * use that one.
-                *
-                * If ei->is_freed is set, the e_dentry is currently on its
-                * way to being freed, don't return it. If e_dentry is NULL
-                * it means it was already freed.
-                */
-               if (ei->is_freed) {
-                       dentry = NULL;
-               } else {
-                       dentry = *e_dentry;
-                       dget(dentry);
-               }
-               mutex_unlock(&eventfs_mutex);
-               return dentry;
-       }
-
-       if (!*e_dentry && !ei->is_freed) {
-               *e_dentry = dentry;
-               dentry->d_fsdata = ei;
-       } else {
-               /*
-                * Should never happen unless we get here due to being freed.
-                * Otherwise it means two dentries exist with the same name.
-                */
-               WARN_ON_ONCE(!ei->is_freed);
-               dentry = NULL;
-       }
-       mutex_unlock(&eventfs_mutex);
-
-       return dentry;
-}
-
-/**
- * eventfs_post_create_dir - post create dir routine
- * @ei: eventfs_inode of recently created dir
- *
- * Map the meta-data of files within an eventfs dir to their parent dentry
- */
-static void eventfs_post_create_dir(struct eventfs_inode *ei)
-{
-       struct eventfs_inode *ei_child;
-       struct tracefs_inode *ti;
-
-       lockdep_assert_held(&eventfs_mutex);
-
-       /* srcu lock already held */
-       /* fill parent-child relation */
-       list_for_each_entry_srcu(ei_child, &ei->children, list,
-                                srcu_read_lock_held(&eventfs_srcu)) {
-               ei_child->d_parent = ei->dentry;
-       }
-
-       ti = get_tracefs(ei->dentry->d_inode);
-       ti->private = ei;
-}
-
-/**
- * create_dir_dentry - Create a directory dentry for the eventfs_inode
- * @pei: The eventfs_inode parent of ei.
- * @ei: The eventfs_inode to create the directory for
- * @parent: The dentry of the parent of this directory
- *
- * This creates and attaches a directory dentry to the eventfs_inode @ei.
- */
-static struct dentry *
-create_dir_dentry(struct eventfs_inode *pei, struct eventfs_inode *ei,
-                 struct dentry *parent)
-{
-       struct dentry *dentry = NULL;
-
-       WARN_ON_ONCE(!inode_is_locked(parent->d_inode));
-
-       mutex_lock(&eventfs_mutex);
-       if (pei->is_freed || ei->is_freed) {
-               mutex_unlock(&eventfs_mutex);
-               return NULL;
-       }
-       if (ei->dentry) {
-               /* If the eventfs_inode already has a dentry, use it */
-               dentry = ei->dentry;
-               dget(dentry);
-               mutex_unlock(&eventfs_mutex);
-               return dentry;
-       }
-       mutex_unlock(&eventfs_mutex);
-
-       dentry = create_dir(ei, parent);
-
-       mutex_lock(&eventfs_mutex);
-
-       if (IS_ERR_OR_NULL(dentry) && !ei->is_freed) {
-               /*
-                * When the mutex was released, something else could have
-                * created the dentry for this e_dentry. In which case
-                * use that one.
-                *
-                * If ei->is_freed is set, the e_dentry is currently on its
-                * way to being freed.
-                */
-               dentry = ei->dentry;
-               if (dentry)
-                       dget(dentry);
-               mutex_unlock(&eventfs_mutex);
-               return dentry;
-       }
-
-       if (!ei->dentry && !ei->is_freed) {
-               ei->dentry = dentry;
-               eventfs_post_create_dir(ei);
-               dentry->d_fsdata = ei;
-       } else {
-               /*
-                * Should never happen unless we get here due to being freed.
-                * Otherwise it means two dentries exist with the same name.
-                */
-               WARN_ON_ONCE(!ei->is_freed);
-               dentry = NULL;
-       }
-       mutex_unlock(&eventfs_mutex);
-
-       return dentry;
+       return lookup_file(ei, dentry, mode, attr, data, fops);
 }
 
 /**
@@ -649,79 +476,50 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
                                          struct dentry *dentry,
                                          unsigned int flags)
 {
-       const struct file_operations *fops;
-       const struct eventfs_entry *entry;
        struct eventfs_inode *ei_child;
        struct tracefs_inode *ti;
        struct eventfs_inode *ei;
-       struct dentry *ei_dentry = NULL;
-       struct dentry *ret = NULL;
-       struct dentry *d;
        const char *name = dentry->d_name.name;
-       umode_t mode;
-       void *data;
-       int idx;
-       int i;
-       int r;
+       struct dentry *result = NULL;
 
        ti = get_tracefs(dir);
        if (!(ti->flags & TRACEFS_EVENT_INODE))
-               return NULL;
-
-       /* Grab srcu to prevent the ei from going away */
-       idx = srcu_read_lock(&eventfs_srcu);
+               return ERR_PTR(-EIO);
 
-       /*
-        * Grab the eventfs_mutex to consistent value from ti->private.
-        * This s
-        */
        mutex_lock(&eventfs_mutex);
-       ei = READ_ONCE(ti->private);
-       if (ei && !ei->is_freed)
-               ei_dentry = READ_ONCE(ei->dentry);
-       mutex_unlock(&eventfs_mutex);
 
-       if (!ei || !ei_dentry)
+       ei = ti->private;
+       if (!ei || ei->is_freed)
                goto out;
 
-       data = ei->data;
-
-       list_for_each_entry_srcu(ei_child, &ei->children, list,
-                                srcu_read_lock_held(&eventfs_srcu)) {
+       list_for_each_entry(ei_child, &ei->children, list) {
                if (strcmp(ei_child->name, name) != 0)
                        continue;
-               ret = simple_lookup(dir, dentry, flags);
-               if (IS_ERR(ret))
+               if (ei_child->is_freed)
                        goto out;
-               d = create_dir_dentry(ei, ei_child, ei_dentry);
-               dput(d);
+               result = lookup_dir_entry(dentry, ei, ei_child);
                goto out;
        }
 
-       for (i = 0; i < ei->nr_entries; i++) {
-               entry = &ei->entries[i];
-               if (strcmp(name, entry->name) == 0) {
-                       void *cdata = data;
-                       mutex_lock(&eventfs_mutex);
-                       /* If ei->is_freed, then the event itself may be too */
-                       if (!ei->is_freed)
-                               r = entry->callback(name, &mode, &cdata, &fops);
-                       else
-                               r = -1;
-                       mutex_unlock(&eventfs_mutex);
-                       if (r <= 0)
-                               continue;
-                       ret = simple_lookup(dir, dentry, flags);
-                       if (IS_ERR(ret))
-                               goto out;
-                       d = create_file_dentry(ei, i, ei_dentry, name, mode, cdata, fops);
-                       dput(d);
-                       break;
-               }
+       for (int i = 0; i < ei->nr_entries; i++) {
+               void *data;
+               umode_t mode;
+               const struct file_operations *fops;
+               const struct eventfs_entry *entry = &ei->entries[i];
+
+               if (strcmp(name, entry->name) != 0)
+                       continue;
+
+               data = ei->data;
+               if (entry->callback(name, &mode, &data, &fops) <= 0)
+                       goto out;
+
+               result = lookup_file_dentry(dentry, ei, i, mode, data, fops);
+               goto out;
        }
  out:
-       srcu_read_unlock(&eventfs_srcu, idx);
-       return ret;
+       mutex_unlock(&eventfs_mutex);
+       return result;
 }
 
 /*
@@ -871,25 +669,10 @@ struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode
        if (!parent)
                return ERR_PTR(-EINVAL);
 
-       ei = kzalloc(sizeof(*ei), GFP_KERNEL);
+       ei = alloc_ei(name);
        if (!ei)
                return ERR_PTR(-ENOMEM);
 
-       ei->name = kstrdup_const(name, GFP_KERNEL);
-       if (!ei->name) {
-               kfree(ei);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       if (size) {
-               ei->d_children = kcalloc(size, sizeof(*ei->d_children), GFP_KERNEL);
-               if (!ei->d_children) {
-                       kfree_const(ei->name);
-                       kfree(ei);
-                       return ERR_PTR(-ENOMEM);
-               }
-       }
-
        ei->entries = entries;
        ei->nr_entries = size;
        ei->data = data;
@@ -897,10 +680,8 @@ struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode
        INIT_LIST_HEAD(&ei->list);
 
        mutex_lock(&eventfs_mutex);
-       if (!parent->is_freed) {
+       if (!parent->is_freed)
                list_add_tail(&ei->list, &parent->children);
-               ei->d_parent = parent->dentry;
-       }
        mutex_unlock(&eventfs_mutex);
 
        /* Was the parent freed? */
@@ -940,28 +721,20 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
        if (IS_ERR(dentry))
                return ERR_CAST(dentry);
 
-       ei = kzalloc(sizeof(*ei), GFP_KERNEL);
+       ei = alloc_ei(name);
        if (!ei)
-               goto fail_ei;
+               goto fail;
 
        inode = tracefs_get_inode(dentry->d_sb);
        if (unlikely(!inode))
                goto fail;
 
-       if (size) {
-               ei->d_children = kcalloc(size, sizeof(*ei->d_children), GFP_KERNEL);
-               if (!ei->d_children)
-                       goto fail;
-       }
-
-       ei->dentry = dentry;
+       // Note: we have a ref to the dentry from tracefs_start_creating()
+       ei->events_dir = dentry;
        ei->entries = entries;
        ei->nr_entries = size;
        ei->is_events = 1;
        ei->data = data;
-       ei->name = kstrdup_const(name, GFP_KERNEL);
-       if (!ei->name)
-               goto fail;
 
        /* Save the ownership of this directory */
        uid = d_inode(dentry->d_parent)->i_uid;
@@ -992,11 +765,19 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
        inode->i_op = &eventfs_root_dir_inode_operations;
        inode->i_fop = &eventfs_file_operations;
 
-       dentry->d_fsdata = ei;
+       dentry->d_fsdata = get_ei(ei);
 
-       /* directory inodes start off with i_nlink == 2 (for "." entry) */
-       inc_nlink(inode);
+       /*
+        * Keep all eventfs directories with i_nlink == 1.
+        * Due to the dynamic nature of the dentry creations and not
+        * wanting to add a pointer to the parent eventfs_inode in the
+        * eventfs_inode structure, keeping the i_nlink in sync with the
+        * number of directories would cause too much complexity for
+        * something not worth much. Keeping directory links at 1
+        * tells userspace not to trust the link number.
+        */
        d_instantiate(dentry, inode);
+       /* The dentry of the "events" parent does keep track though */
        inc_nlink(dentry->d_parent->d_inode);
        fsnotify_mkdir(dentry->d_parent->d_inode, dentry);
        tracefs_end_creating(dentry);
@@ -1004,72 +785,11 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
        return ei;
 
  fail:
-       kfree(ei->d_children);
-       kfree(ei);
- fail_ei:
+       free_ei(ei);
        tracefs_failed_creating(dentry);
        return ERR_PTR(-ENOMEM);
 }
 
-static LLIST_HEAD(free_list);
-
-static void eventfs_workfn(struct work_struct *work)
-{
-        struct eventfs_inode *ei, *tmp;
-        struct llist_node *llnode;
-
-       llnode = llist_del_all(&free_list);
-        llist_for_each_entry_safe(ei, tmp, llnode, llist) {
-               /* This dput() matches the dget() from unhook_dentry() */
-               for (int i = 0; i < ei->nr_entries; i++) {
-                       if (ei->d_children[i])
-                               dput(ei->d_children[i]);
-               }
-               /* This should only get here if it had a dentry */
-               if (!WARN_ON_ONCE(!ei->dentry))
-                       dput(ei->dentry);
-        }
-}
-
-static DECLARE_WORK(eventfs_work, eventfs_workfn);
-
-static void free_rcu_ei(struct rcu_head *head)
-{
-       struct eventfs_inode *ei = container_of(head, struct eventfs_inode, rcu);
-
-       if (ei->dentry) {
-               /* Do not free the ei until all references of dentry are gone */
-               if (llist_add(&ei->llist, &free_list))
-                       queue_work(system_unbound_wq, &eventfs_work);
-               return;
-       }
-
-       /* If the ei doesn't have a dentry, neither should its children */
-       for (int i = 0; i < ei->nr_entries; i++) {
-               WARN_ON_ONCE(ei->d_children[i]);
-       }
-
-       free_ei(ei);
-}
-
-static void unhook_dentry(struct dentry *dentry)
-{
-       if (!dentry)
-               return;
-       /*
-        * Need to add a reference to the dentry that is expected by
-        * simple_recursive_removal(), which will include a dput().
-        */
-       dget(dentry);
-
-       /*
-        * Also add a reference for the dput() in eventfs_workfn().
-        * That is required as that dput() will free the ei after
-        * the SRCU grace period is over.
-        */
-       dget(dentry);
-}
-
 /**
  * eventfs_remove_rec - remove eventfs dir or file from list
  * @ei: eventfs_inode to be removed.
@@ -1082,8 +802,6 @@ static void eventfs_remove_rec(struct eventfs_inode *ei, int level)
 {
        struct eventfs_inode *ei_child;
 
-       if (!ei)
-               return;
        /*
         * Check recursion depth. It should never be greater than 3:
         * 0 - events/
@@ -1095,28 +813,11 @@ static void eventfs_remove_rec(struct eventfs_inode *ei, int level)
                return;
 
        /* search for nested folders or files */
-       list_for_each_entry_srcu(ei_child, &ei->children, list,
-                                lockdep_is_held(&eventfs_mutex)) {
-               /* Children only have dentry if parent does */
-               WARN_ON_ONCE(ei_child->dentry && !ei->dentry);
+       list_for_each_entry(ei_child, &ei->children, list)
                eventfs_remove_rec(ei_child, level + 1);
-       }
-
-
-       ei->is_freed = 1;
 
-       for (int i = 0; i < ei->nr_entries; i++) {
-               if (ei->d_children[i]) {
-                       /* Children only have dentry if parent does */
-                       WARN_ON_ONCE(!ei->dentry);
-                       unhook_dentry(ei->d_children[i]);
-               }
-       }
-
-       unhook_dentry(ei->dentry);
-
-       list_del_rcu(&ei->list);
-       call_srcu(&eventfs_srcu, &ei->rcu, free_rcu_ei);
+       list_del(&ei->list);
+       free_ei(ei);
 }
 
 /**
@@ -1127,22 +828,12 @@ static void eventfs_remove_rec(struct eventfs_inode *ei, int level)
  */
 void eventfs_remove_dir(struct eventfs_inode *ei)
 {
-       struct dentry *dentry;
-
        if (!ei)
                return;
 
        mutex_lock(&eventfs_mutex);
-       dentry = ei->dentry;
        eventfs_remove_rec(ei, 0);
        mutex_unlock(&eventfs_mutex);
-
-       /*
-        * If any of the ei children has a dentry, then the ei itself
-        * must have a dentry.
-        */
-       if (dentry)
-               simple_recursive_removal(dentry, NULL);
 }
 
 /**
@@ -1155,7 +846,11 @@ void eventfs_remove_events_dir(struct eventfs_inode *ei)
 {
        struct dentry *dentry;
 
-       dentry = ei->dentry;
+       dentry = ei->events_dir;
+       if (!dentry)
+               return;
+
+       ei->events_dir = NULL;
        eventfs_remove_dir(ei);
 
        /*
@@ -1165,5 +860,6 @@ void eventfs_remove_events_dir(struct eventfs_inode *ei)
         * sticks around while the other ei->dentry are created
         * and destroyed dynamically.
         */
+       d_invalidate(dentry);
        dput(dentry);
 }
index e1b172c0e091a8d55fcc80951fa4ed5202b1539e..d65ffad4c327ca11a98a8d2073d8e5c77ac138c3 100644 (file)
@@ -38,8 +38,6 @@ static struct inode *tracefs_alloc_inode(struct super_block *sb)
        if (!ti)
                return NULL;
 
-       ti->flags = 0;
-
        return &ti->vfs_inode;
 }
 
@@ -379,21 +377,30 @@ static const struct super_operations tracefs_super_operations = {
        .show_options   = tracefs_show_options,
 };
 
-static void tracefs_dentry_iput(struct dentry *dentry, struct inode *inode)
+/*
+ * It would be cleaner if eventfs had its own dentry ops.
+ *
+ * Note that d_revalidate is called potentially under RCU,
+ * so it can't take the eventfs mutex etc. It's fine - if
+ * we open a file just as it's marked dead, things will
+ * still work just fine, and just see the old stale case.
+ */
+static void tracefs_d_release(struct dentry *dentry)
 {
-       struct tracefs_inode *ti;
+       if (dentry->d_fsdata)
+               eventfs_d_release(dentry);
+}
 
-       if (!dentry || !inode)
-               return;
+static int tracefs_d_revalidate(struct dentry *dentry, unsigned int flags)
+{
+       struct eventfs_inode *ei = dentry->d_fsdata;
 
-       ti = get_tracefs(inode);
-       if (ti && ti->flags & TRACEFS_EVENT_INODE)
-               eventfs_set_ei_status_free(ti, dentry);
-       iput(inode);
+       return !(ei && ei->is_freed);
 }
 
 static const struct dentry_operations tracefs_dentry_operations = {
-       .d_iput = tracefs_dentry_iput,
+       .d_revalidate = tracefs_d_revalidate,
+       .d_release = tracefs_d_release,
 };
 
 static int trace_fill_super(struct super_block *sb, void *data, int silent)
@@ -497,75 +504,6 @@ struct dentry *tracefs_end_creating(struct dentry *dentry)
        return dentry;
 }
 
-/**
- * eventfs_start_creating - start the process of creating a dentry
- * @name: Name of the file created for the dentry
- * @parent: The parent dentry where this dentry will be created
- *
- * This is a simple helper function for the dynamically created eventfs
- * files. When the directory of the eventfs files are accessed, their
- * dentries are created on the fly. This function is used to start that
- * process.
- */
-struct dentry *eventfs_start_creating(const char *name, struct dentry *parent)
-{
-       struct dentry *dentry;
-       int error;
-
-       /* Must always have a parent. */
-       if (WARN_ON_ONCE(!parent))
-               return ERR_PTR(-EINVAL);
-
-       error = simple_pin_fs(&trace_fs_type, &tracefs_mount,
-                             &tracefs_mount_count);
-       if (error)
-               return ERR_PTR(error);
-
-       if (unlikely(IS_DEADDIR(parent->d_inode)))
-               dentry = ERR_PTR(-ENOENT);
-       else
-               dentry = lookup_one_len(name, parent, strlen(name));
-
-       if (!IS_ERR(dentry) && dentry->d_inode) {
-               dput(dentry);
-               dentry = ERR_PTR(-EEXIST);
-       }
-
-       if (IS_ERR(dentry))
-               simple_release_fs(&tracefs_mount, &tracefs_mount_count);
-
-       return dentry;
-}
-
-/**
- * eventfs_failed_creating - clean up a failed eventfs dentry creation
- * @dentry: The dentry to clean up
- *
- * If after calling eventfs_start_creating(), a failure is detected, the
- * resources created by eventfs_start_creating() needs to be cleaned up. In
- * that case, this function should be called to perform that clean up.
- */
-struct dentry *eventfs_failed_creating(struct dentry *dentry)
-{
-       dput(dentry);
-       simple_release_fs(&tracefs_mount, &tracefs_mount_count);
-       return NULL;
-}
-
-/**
- * eventfs_end_creating - Finish the process of creating a eventfs dentry
- * @dentry: The dentry that has successfully been created.
- *
- * This function is currently just a place holder to match
- * eventfs_start_creating(). In case any synchronization needs to be added,
- * this function will be used to implement that without having to modify
- * the callers of eventfs_start_creating().
- */
-struct dentry *eventfs_end_creating(struct dentry *dentry)
-{
-       return dentry;
-}
-
 /* Find the inode that this will use for default */
 static struct inode *instance_inode(struct dentry *parent, struct inode *inode)
 {
@@ -779,7 +717,11 @@ static void init_once(void *foo)
 {
        struct tracefs_inode *ti = (struct tracefs_inode *) foo;
 
+       /* inode_init_once() calls memset() on the vfs_inode portion */
        inode_init_once(&ti->vfs_inode);
+
+       /* Zero out the rest */
+       memset_after(ti, 0, vfs_inode);
 }
 
 static int __init tracefs_init(void)
index 45397df9bb65bffb783329c156e03a2fdb01ebea..beb3dcd0e434207c882bcfe6ec027b6ca3e43526 100644 (file)
@@ -11,9 +11,10 @@ enum {
 };
 
 struct tracefs_inode {
+       struct inode            vfs_inode;
+       /* The below gets initialized with memset_after(ti, 0, vfs_inode) */
        unsigned long           flags;
        void                    *private;
-       struct inode            vfs_inode;
 };
 
 /*
@@ -31,43 +32,37 @@ struct eventfs_attr {
 /*
  * struct eventfs_inode - hold the properties of the eventfs directories.
  * @list:      link list into the parent directory
+ * @rcu:       Union with @list for freeing
+ * @children:  link list into the child eventfs_inode
  * @entries:   the array of entries representing the files in the directory
  * @name:      the name of the directory to create
- * @children:  link list into the child eventfs_inode
- * @dentry:     the dentry of the directory
- * @d_parent:   pointer to the parent's dentry
- * @d_children: The array of dentries to represent the files when created
+ * @events_dir: the dentry of the events directory
  * @entry_attrs: Saved mode and ownership of the @d_children
- * @attr:      Saved mode and ownership of eventfs_inode itself
  * @data:      The private data to pass to the callbacks
+ * @attr:      Saved mode and ownership of eventfs_inode itself
  * @is_freed:  Flag set if the eventfs is on its way to be freed
  *                Note if is_freed is set, then dentry is corrupted.
+ * @is_events: Flag set for only the top level "events" directory
  * @nr_entries: The number of items in @entries
+ * @ino:       The saved inode number
  */
 struct eventfs_inode {
-       struct list_head                list;
+       union {
+               struct list_head        list;
+               struct rcu_head         rcu;
+       };
+       struct list_head                children;
        const struct eventfs_entry      *entries;
        const char                      *name;
-       struct list_head                children;
-       struct dentry                   *dentry; /* Check is_freed to access */
-       struct dentry                   *d_parent;
-       struct dentry                   **d_children;
+       struct dentry                   *events_dir;
        struct eventfs_attr             *entry_attrs;
-       struct eventfs_attr             attr;
        void                            *data;
+       struct eventfs_attr             attr;
+       struct kref                     kref;
        unsigned int                    is_freed:1;
        unsigned int                    is_events:1;
        unsigned int                    nr_entries:30;
        unsigned int                    ino;
-       /*
-        * Union - used for deletion
-        * @llist:      for calling dput() if needed after RCU
-        * @rcu:        eventfs_inode to delete in RCU
-        */
-       union {
-               struct llist_node       llist;
-               struct rcu_head         rcu;
-       };
 };
 
 static inline struct tracefs_inode *get_tracefs(const struct inode *inode)
@@ -79,10 +74,7 @@ struct dentry *tracefs_start_creating(const char *name, struct dentry *parent);
 struct dentry *tracefs_end_creating(struct dentry *dentry);
 struct dentry *tracefs_failed_creating(struct dentry *dentry);
 struct inode *tracefs_get_inode(struct super_block *sb);
-struct dentry *eventfs_start_creating(const char *name, struct dentry *parent);
-struct dentry *eventfs_failed_creating(struct dentry *dentry);
-struct dentry *eventfs_end_creating(struct dentry *dentry);
-void eventfs_update_gid(struct dentry *dentry, kgid_t gid);
-void eventfs_set_ei_status_free(struct tracefs_inode *ti, struct dentry *dentry);
+
+void eventfs_d_release(struct dentry *dentry);
 
 #endif /* _TRACEFS_INTERNAL_H */
index aff20ddd4a9f9cdeeeca1f54f210d19462773a5b..5a2512d20bd07473a872592911ede7246b8c11b7 100644 (file)
@@ -1496,6 +1496,18 @@ xfs_fs_fill_super(
 
        mp->m_super = sb;
 
+       /*
+        * Copy VFS mount flags from the context now that all parameter parsing
+        * is guaranteed to have been completed by either the old mount API or
+        * the newer fsopen/fsconfig API.
+        */
+       if (fc->sb_flags & SB_RDONLY)
+               set_bit(XFS_OPSTATE_READONLY, &mp->m_opstate);
+       if (fc->sb_flags & SB_DIRSYNC)
+               mp->m_features |= XFS_FEAT_DIRSYNC;
+       if (fc->sb_flags & SB_SYNCHRONOUS)
+               mp->m_features |= XFS_FEAT_WSYNC;
+
        error = xfs_fs_validate_params(mp);
        if (error)
                return error;
@@ -1965,6 +1977,11 @@ static const struct fs_context_operations xfs_context_ops = {
        .free        = xfs_fs_free,
 };
 
+/*
+ * WARNING: do not initialise any parameters in this function that depend on
+ * mount option parsing having already been performed as this can be called from
+ * fsopen() before any parameters have been set.
+ */
 static int xfs_init_fs_context(
        struct fs_context       *fc)
 {
@@ -1996,16 +2013,6 @@ static int xfs_init_fs_context(
        mp->m_logbsize = -1;
        mp->m_allocsize_log = 16; /* 64k */
 
-       /*
-        * Copy binary VFS mount flags we are interested in.
-        */
-       if (fc->sb_flags & SB_RDONLY)
-               set_bit(XFS_OPSTATE_READONLY, &mp->m_opstate);
-       if (fc->sb_flags & SB_DIRSYNC)
-               mp->m_features |= XFS_FEAT_DIRSYNC;
-       if (fc->sb_flags & SB_SYNCHRONOUS)
-               mp->m_features |= XFS_FEAT_WSYNC;
-
        fc->s_fs_info = mp;
        fc->ops = &xfs_context_ops;
 
index 840cd254172d061ec445bdc845a7f1e8cbf20463..7118ac28d46879b615de35a6e3702208de4001e9 100644 (file)
@@ -77,17 +77,6 @@ enum hid_bpf_attach_flags {
 int hid_bpf_device_event(struct hid_bpf_ctx *ctx);
 int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx);
 
-/* Following functions are kfunc that we export to BPF programs */
-/* available everywhere in HID-BPF */
-__u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t __sz);
-
-/* only available in syscall */
-int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags);
-int hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
-                      enum hid_report_type rtype, enum hid_class_request reqtype);
-struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id);
-void hid_bpf_release_context(struct hid_bpf_ctx *ctx);
-
 /*
  * Below is HID internal
  */
index 1dbb14daccfaf326af0c54c89ff61afb50e07982..26d68115afb826b65a9fd11ce329635161e39cca 100644 (file)
@@ -471,7 +471,7 @@ enum ata_completion_errors {
 
 /*
  * Link power management policy: If you alter this, you also need to
- * alter libata-scsi.c (for the ascii descriptions)
+ * alter libata-sata.c (for the ascii descriptions)
  */
 enum ata_lpm_policy {
        ATA_LPM_UNKNOWN,
index 185924c5637876a153957a3a206fe907dcc784a5..76458b6d53da7667b31fc3a80007bb1a609ec1d8 100644 (file)
@@ -315,9 +315,9 @@ LSM_HOOK(int, 0, socket_getsockopt, struct socket *sock, int level, int optname)
 LSM_HOOK(int, 0, socket_setsockopt, struct socket *sock, int level, int optname)
 LSM_HOOK(int, 0, socket_shutdown, struct socket *sock, int how)
 LSM_HOOK(int, 0, socket_sock_rcv_skb, struct sock *sk, struct sk_buff *skb)
-LSM_HOOK(int, 0, socket_getpeersec_stream, struct socket *sock,
+LSM_HOOK(int, -ENOPROTOOPT, socket_getpeersec_stream, struct socket *sock,
         sockptr_t optval, sockptr_t optlen, unsigned int len)
-LSM_HOOK(int, 0, socket_getpeersec_dgram, struct socket *sock,
+LSM_HOOK(int, -ENOPROTOOPT, socket_getpeersec_dgram, struct socket *sock,
         struct sk_buff *skb, u32 *secid)
 LSM_HOOK(int, 0, sk_alloc_security, struct sock *sk, int family, gfp_t priority)
 LSM_HOOK(void, LSM_RET_VOID, sk_free_security, struct sock *sk)
index 40d94411d49204e7276a6ad9554eb17335fd4577..dc7048824be81d628ca12f0874c1a7508da0d5c1 100644 (file)
@@ -156,6 +156,7 @@ calc_vm_flag_bits(unsigned long flags)
        return _calc_vm_trans(flags, MAP_GROWSDOWN,  VM_GROWSDOWN ) |
               _calc_vm_trans(flags, MAP_LOCKED,     VM_LOCKED    ) |
               _calc_vm_trans(flags, MAP_SYNC,       VM_SYNC      ) |
+              _calc_vm_trans(flags, MAP_STACK,      VM_NOHUGEPAGE) |
               arch_calc_vm_flag_bits(flags);
 }
 
index 4ed33b12782151632e36aa114039cb4a0916fe06..a497f189d98818bcda37458746ebb2bded7826e4 100644 (file)
@@ -2013,9 +2013,9 @@ static inline int pfn_valid(unsigned long pfn)
        if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
                return 0;
        ms = __pfn_to_section(pfn);
-       rcu_read_lock();
+       rcu_read_lock_sched();
        if (!valid_section(ms)) {
-               rcu_read_unlock();
+               rcu_read_unlock_sched();
                return 0;
        }
        /*
@@ -2023,7 +2023,7 @@ static inline int pfn_valid(unsigned long pfn)
         * the entire section-sized span.
         */
        ret = early_section(ms) || pfn_section_valid(ms, pfn);
-       rcu_read_unlock();
+       rcu_read_unlock_sched();
 
        return ret;
 }
index e8c350a3ade153d852bec011dbd3c72a352d319d..e9f4f845d760afafbfb6e45b220dfb6919a29779 100644 (file)
@@ -186,6 +186,8 @@ struct ip_set_type_variant {
        /* Return true if "b" set is the same as "a"
         * according to the create set parameters */
        bool (*same_set)(const struct ip_set *a, const struct ip_set *b);
+       /* Cancel ongoing garbage collectors before destroying the set*/
+       void (*cancel_gc)(struct ip_set *set);
        /* Region-locking is used */
        bool region_lock;
 };
@@ -242,6 +244,8 @@ extern void ip_set_type_unregister(struct ip_set_type *set_type);
 
 /* A generic IP set */
 struct ip_set {
+       /* For call_cru in destroy */
+       struct rcu_head rcu;
        /* The name of the set */
        char name[IPSET_MAXNAMELEN];
        /* Lock protecting the set data */
index 462c21e0e417654e56edf314ebcb62d8c6f4ad16..bc605ec4a3fd06f9145242827fe310a760f00122 100644 (file)
@@ -816,12 +816,6 @@ struct nvme_reservation_status_ext {
        struct nvme_registered_ctrl_ext regctl_eds[];
 };
 
-enum nvme_async_event_type {
-       NVME_AER_TYPE_ERROR     = 0,
-       NVME_AER_TYPE_SMART     = 1,
-       NVME_AER_TYPE_NOTICE    = 2,
-};
-
 /* I/O commands */
 
 enum nvme_opcode {
@@ -1818,7 +1812,7 @@ struct nvme_command {
        };
 };
 
-static inline bool nvme_is_fabrics(struct nvme_command *cmd)
+static inline bool nvme_is_fabrics(const struct nvme_command *cmd)
 {
        return cmd->common.opcode == nvme_fabrics_command;
 }
@@ -1837,7 +1831,7 @@ struct nvme_error_slot {
        __u8            resv2[24];
 };
 
-static inline bool nvme_is_write(struct nvme_command *cmd)
+static inline bool nvme_is_write(const struct nvme_command *cmd)
 {
        /*
         * What a mess...
index add9368e6314b9d7038a651af3f8e1b9e08d7ffa..7ab0d13672dafa0faaeaf4cf02e7bab6fcc3130b 100644 (file)
@@ -1422,6 +1422,7 @@ int pci_load_and_free_saved_state(struct pci_dev *dev,
                                  struct pci_saved_state **state);
 int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state);
 int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
+int pci_set_power_state_locked(struct pci_dev *dev, pci_power_t state);
 pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
 bool pci_pme_capable(struct pci_dev *dev, pci_power_t state);
 void pci_pme_active(struct pci_dev *dev, bool enable);
@@ -1625,6 +1626,8 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
 
 void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
                  void *userdata);
+void pci_walk_bus_locked(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
+                        void *userdata);
 int pci_cfg_space_size(struct pci_dev *dev);
 unsigned char pci_bus_max_busnr(struct pci_bus *bus);
 void pci_setup_bridge(struct pci_bus *bus);
@@ -2025,6 +2028,8 @@ static inline int pci_save_state(struct pci_dev *dev) { return 0; }
 static inline void pci_restore_state(struct pci_dev *dev) { }
 static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 { return 0; }
+static inline int pci_set_power_state_locked(struct pci_dev *dev, pci_power_t state)
+{ return 0; }
 static inline int pci_wake_from_d3(struct pci_dev *dev, bool enable)
 { return 0; }
 static inline pci_power_t pci_choose_state(struct pci_dev *dev,
index 471fe2ff9066b75e82795b92972905bbae3cc48c..600fbd5daf683d4d93536a569ef5e52248d7a851 100644 (file)
@@ -21,7 +21,7 @@
 #include <uapi/linux/spi/spi.h>
 
 /* Max no. of CS supported per spi device */
-#define SPI_CS_CNT_MAX 4
+#define SPI_CS_CNT_MAX 16
 
 struct dma_chan;
 struct software_node;
index cdba4d0c6d4a88dd19db34faa425addb8cd3f744..77eb9b0e768504daa57af63b2eb7c8debd00dfda 100644 (file)
@@ -128,6 +128,7 @@ struct mnt_id_req;
 #define __TYPE_IS_LL(t) (__TYPE_AS(t, 0LL) || __TYPE_AS(t, 0ULL))
 #define __SC_LONG(t, a) __typeof(__builtin_choose_expr(__TYPE_IS_LL(t), 0LL, 0L)) a
 #define __SC_CAST(t, a)        (__force t) a
+#define __SC_TYPE(t, a)        t
 #define __SC_ARGS(t, a)        a
 #define __SC_TEST(t, a) (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(t) && sizeof(t) > sizeof(long))
 
index 49c4640027d8a6b93e903a6238d21e8541e31da4..afd40dce40f3d593f6fa0a11828aee9fd1582de3 100644 (file)
@@ -46,12 +46,6 @@ struct scm_stat {
 
 #define UNIXCB(skb)    (*(struct unix_skb_parms *)&((skb)->cb))
 
-#define unix_state_lock(s)     spin_lock(&unix_sk(s)->lock)
-#define unix_state_unlock(s)   spin_unlock(&unix_sk(s)->lock)
-#define unix_state_lock_nested(s) \
-                               spin_lock_nested(&unix_sk(s)->lock, \
-                               SINGLE_DEPTH_NESTING)
-
 /* The AF_UNIX socket */
 struct unix_sock {
        /* WARNING: sk has to be the first member */
@@ -77,6 +71,20 @@ struct unix_sock {
 #define unix_sk(ptr) container_of_const(ptr, struct unix_sock, sk)
 #define unix_peer(sk) (unix_sk(sk)->peer)
 
+#define unix_state_lock(s)     spin_lock(&unix_sk(s)->lock)
+#define unix_state_unlock(s)   spin_unlock(&unix_sk(s)->lock)
+enum unix_socket_lock_class {
+       U_LOCK_NORMAL,
+       U_LOCK_SECOND,  /* for double locking, see unix_state_double_lock(). */
+       U_LOCK_DIAG, /* used while dumping icons, see sk_diag_dump_icons(). */
+};
+
+static inline void unix_state_lock_nested(struct sock *sk,
+                                  enum unix_socket_lock_class subclass)
+{
+       spin_lock_nested(&unix_sk(sk)->lock, subclass);
+}
+
 #define peer_wait peer_wq.wait
 
 long unix_inq_len(struct sock *sk);
index de0c69c57e3cb7485e3d8473bc0b109e4280d2f6..25cb688bdc62360292e25b0d676f135101a2118c 100644 (file)
@@ -767,7 +767,7 @@ int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev);
  *     Functions provided by ip_sockglue.c
  */
 
-void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb);
+void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb, bool drop_dst);
 void ip_cmsg_recv_offset(struct msghdr *msg, struct sock *sk,
                         struct sk_buff *skb, int tlen, int offset);
 int ip_cmsg_send(struct sock *sk, struct msghdr *msg,
index 4e1ea18eb5f05f763429ed2f75c0c1c9aee20d44..001226c34621560a49cffc85046df85f1c1fa4fe 100644 (file)
@@ -1351,6 +1351,7 @@ void nft_obj_notify(struct net *net, const struct nft_table *table,
  *     @type: stateful object numeric type
  *     @owner: module owner
  *     @maxattr: maximum netlink attribute
+ *     @family: address family for AF-specific object types
  *     @policy: netlink attribute policy
  */
 struct nft_object_type {
@@ -1360,6 +1361,7 @@ struct nft_object_type {
        struct list_head                list;
        u32                             type;
        unsigned int                    maxattr;
+       u8                              family;
        struct module                   *owner;
        const struct nla_policy         *policy;
 };
index 8c18e8b6d27d21b34962cc392dfeaffe48070847..b24716ab27504bdfa17f221a39053dd21dd961d9 100644 (file)
@@ -75,6 +75,7 @@
 #define CS35L56_DSP1_AHBM_WINDOW_DEBUG_0               0x25E2040
 #define CS35L56_DSP1_AHBM_WINDOW_DEBUG_1               0x25E2044
 #define CS35L56_DSP1_XMEM_UNPACKED24_0                 0x2800000
+#define CS35L56_DSP1_FW_VER                            0x2800010
 #define CS35L56_DSP1_HALO_STATE_A1                     0x2801E58
 #define CS35L56_DSP1_HALO_STATE                                0x28021E0
 #define CS35L56_DSP1_PM_CUR_STATE_A1                   0x2804000
 
 #define CS35L56_CONTROL_PORT_READY_US                  2200
 #define CS35L56_HALO_STATE_POLL_US                     1000
-#define CS35L56_HALO_STATE_TIMEOUT_US                  50000
+#define CS35L56_HALO_STATE_TIMEOUT_US                  250000
 #define CS35L56_RESET_PULSE_MIN_US                     1100
 #define CS35L56_WAKE_HOLD_TIME_US                      1000
 
@@ -272,6 +273,7 @@ extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
 extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];
 
 int cs35l56_set_patch(struct cs35l56_base *cs35l56_base);
+int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base);
 int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command);
 int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base);
 int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base);
@@ -284,7 +286,10 @@ int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base);
 int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base);
 int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire);
 void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp);
+int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base,
+                            bool *fw_missing, unsigned int *fw_version);
 int cs35l56_hw_init(struct cs35l56_base *cs35l56_base);
+int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base);
 int cs35l56_get_bclk_freq_id(unsigned int freq);
 void cs35l56_fill_supply_names(struct regulator_bulk_data *data);
 
index de1944e42c6556a46a8a87855189f34b86859e99..63c49318a863076b0861b945c1511d98f9ffffe3 100644 (file)
@@ -53,7 +53,7 @@ extern "C" {
 #define DRM_IVPU_PARAM_CORE_CLOCK_RATE     3
 #define DRM_IVPU_PARAM_NUM_CONTEXTS        4
 #define DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS 5
-#define DRM_IVPU_PARAM_CONTEXT_PRIORITY            6
+#define DRM_IVPU_PARAM_CONTEXT_PRIORITY            6 /* Deprecated */
 #define DRM_IVPU_PARAM_CONTEXT_ID          7
 #define DRM_IVPU_PARAM_FW_API_VERSION      8
 #define DRM_IVPU_PARAM_ENGINE_HEARTBEAT            9
@@ -64,11 +64,18 @@ extern "C" {
 
 #define DRM_IVPU_PLATFORM_TYPE_SILICON     0
 
+/* Deprecated, use DRM_IVPU_JOB_PRIORITY */
 #define DRM_IVPU_CONTEXT_PRIORITY_IDLE     0
 #define DRM_IVPU_CONTEXT_PRIORITY_NORMAL    1
 #define DRM_IVPU_CONTEXT_PRIORITY_FOCUS            2
 #define DRM_IVPU_CONTEXT_PRIORITY_REALTIME  3
 
+#define DRM_IVPU_JOB_PRIORITY_DEFAULT  0
+#define DRM_IVPU_JOB_PRIORITY_IDLE     1
+#define DRM_IVPU_JOB_PRIORITY_NORMAL   2
+#define DRM_IVPU_JOB_PRIORITY_FOCUS    3
+#define DRM_IVPU_JOB_PRIORITY_REALTIME 4
+
 /**
  * DRM_IVPU_CAP_METRIC_STREAMER
  *
@@ -112,10 +119,6 @@ struct drm_ivpu_param {
         * %DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS:
         * Lowest VPU virtual address available in the current context (read-only)
         *
-        * %DRM_IVPU_PARAM_CONTEXT_PRIORITY:
-        * Value of current context scheduling priority (read-write).
-        * See DRM_IVPU_CONTEXT_PRIORITY_* for possible values.
-        *
         * %DRM_IVPU_PARAM_CONTEXT_ID:
         * Current context ID, always greater than 0 (read-only)
         *
@@ -286,6 +289,18 @@ struct drm_ivpu_submit {
         * to be executed. The offset has to be 8-byte aligned.
         */
        __u32 commands_offset;
+
+       /**
+        * @priority:
+        *
+        * Priority to be set for related job command queue, can be one of the following:
+        * %DRM_IVPU_JOB_PRIORITY_DEFAULT
+        * %DRM_IVPU_JOB_PRIORITY_IDLE
+        * %DRM_IVPU_JOB_PRIORITY_NORMAL
+        * %DRM_IVPU_JOB_PRIORITY_FOCUS
+        * %DRM_IVPU_JOB_PRIORITY_REALTIME
+        */
+       __u32 priority;
 };
 
 /* drm_ivpu_bo_wait job status codes */
index 8d4e836e1b6b15c1846fa2f6148111e63f4b4aa9..deda3d14135bb9ed54469353e44f1c1e86e8a0f2 100644 (file)
@@ -876,13 +876,13 @@ config CC_NO_ARRAY_BOUNDS
        bool
        default y if CC_IS_GCC && GCC_VERSION >= 110000 && GCC11_NO_ARRAY_BOUNDS
 
-# Currently, disable -Wstringop-overflow for GCC 11, globally.
-config GCC11_NO_STRINGOP_OVERFLOW
+# Currently, disable -Wstringop-overflow for GCC globally.
+config GCC_NO_STRINGOP_OVERFLOW
        def_bool y
 
 config CC_NO_STRINGOP_OVERFLOW
        bool
-       default y if CC_IS_GCC && GCC_VERSION >= 110000 && GCC_VERSION < 120000 && GCC11_NO_STRINGOP_OVERFLOW
+       default y if CC_IS_GCC && GCC_NO_STRINGOP_OVERFLOW
 
 config CC_STRINGOP_OVERFLOW
        bool
index 04e33f25919ca78332fc3429b8c98d427b768688..d5495710c17877624c75d8fa36b71af9535336a3 100644 (file)
 #include <trace/events/io_uring.h>
 #endif
 
-
 enum {
        IOU_OK                  = 0,
        IOU_ISSUE_SKIP_COMPLETE = -EIOCBQUEUED,
 
+       /*
+        * Requeue the task_work to restart operations on this request. The
+        * actual value isn't important, should just be not an otherwise
+        * valid error code, yet less than -MAX_ERRNO and valid internally.
+        */
+       IOU_REQUEUE             = -3072,
+
        /*
         * Intended only when both IO_URING_F_MULTISHOT is passed
         * to indicate to the poll runner that multishot should be
index 75d494dad7e2c7b22a53f50fc422d807a0559000..43bc9a5f96f9d1ce48f2d6e2a5cf850c675aee0d 100644 (file)
@@ -60,6 +60,7 @@ struct io_sr_msg {
        unsigned                        len;
        unsigned                        done_io;
        unsigned                        msg_flags;
+       unsigned                        nr_multishot_loops;
        u16                             flags;
        /* initialised and used only by !msg send variants */
        u16                             addr_len;
@@ -70,6 +71,13 @@ struct io_sr_msg {
        struct io_kiocb                 *notif;
 };
 
+/*
+ * Number of times we'll try and do receives if there's more data. If we
+ * exceed this limit, then add us to the back of the queue and retry from
+ * there. This helps fairness between flooding clients.
+ */
+#define MULTISHOT_MAX_RETRY    32
+
 static inline bool io_check_multishot(struct io_kiocb *req,
                                      unsigned int issue_flags)
 {
@@ -611,6 +619,7 @@ int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
                sr->msg_flags |= MSG_CMSG_COMPAT;
 #endif
        sr->done_io = 0;
+       sr->nr_multishot_loops = 0;
        return 0;
 }
 
@@ -645,23 +654,35 @@ static inline bool io_recv_finish(struct io_kiocb *req, int *ret,
                return true;
        }
 
-       if (!mshot_finished) {
-               if (io_fill_cqe_req_aux(req, issue_flags & IO_URING_F_COMPLETE_DEFER,
-                                       *ret, cflags | IORING_CQE_F_MORE)) {
-                       io_recv_prep_retry(req);
-                       /* Known not-empty or unknown state, retry */
-                       if (cflags & IORING_CQE_F_SOCK_NONEMPTY ||
-                           msg->msg_inq == -1)
+       if (mshot_finished)
+               goto finish;
+
+       /*
+        * Fill CQE for this receive and see if we should keep trying to
+        * receive from this socket.
+        */
+       if (io_fill_cqe_req_aux(req, issue_flags & IO_URING_F_COMPLETE_DEFER,
+                               *ret, cflags | IORING_CQE_F_MORE)) {
+               struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
+               int mshot_retry_ret = IOU_ISSUE_SKIP_COMPLETE;
+
+               io_recv_prep_retry(req);
+               /* Known not-empty or unknown state, retry */
+               if (cflags & IORING_CQE_F_SOCK_NONEMPTY || msg->msg_inq == -1) {
+                       if (sr->nr_multishot_loops++ < MULTISHOT_MAX_RETRY)
                                return false;
-                       if (issue_flags & IO_URING_F_MULTISHOT)
-                               *ret = IOU_ISSUE_SKIP_COMPLETE;
-                       else
-                               *ret = -EAGAIN;
-                       return true;
+                       /* mshot retries exceeded, force a requeue */
+                       sr->nr_multishot_loops = 0;
+                       mshot_retry_ret = IOU_REQUEUE;
                }
-               /* Otherwise stop multishot but use the current result. */
+               if (issue_flags & IO_URING_F_MULTISHOT)
+                       *ret = mshot_retry_ret;
+               else
+                       *ret = -EAGAIN;
+               return true;
        }
-
+       /* Otherwise stop multishot but use the current result. */
+finish:
        io_req_set_res(req, *ret, cflags);
 
        if (issue_flags & IO_URING_F_MULTISHOT)
@@ -902,6 +923,7 @@ retry_multishot:
                if (!buf)
                        return -ENOBUFS;
                sr->buf = buf;
+               sr->len = len;
        }
 
        ret = import_ubuf(ITER_DEST, sr->buf, len, &msg.msg_iter);
index 6705634e5f52aa625b797f3c7931903c55130359..b1ee3a9c38072933dd020848b7f3586af257d912 100644 (file)
@@ -471,7 +471,6 @@ const struct io_issue_def io_issue_defs[] = {
        },
        [IORING_OP_FIXED_FD_INSTALL] = {
                .needs_file             = 1,
-               .audit_skip             = 1,
                .prep                   = io_install_fixed_fd_prep,
                .issue                  = io_install_fixed_fd,
        },
index 0fe0dd30554623edb87cd159b4ffe0c52288211a..e3357dfa14ca42dd5b25e6cf9ce4a4be8b7ee0f4 100644 (file)
@@ -277,6 +277,10 @@ int io_install_fixed_fd_prep(struct io_kiocb *req, const struct io_uring_sqe *sq
        if (flags & ~IORING_FIXED_FD_NO_CLOEXEC)
                return -EINVAL;
 
+       /* ensure the task's creds are used when installing/receiving fds */
+       if (req->flags & REQ_F_CREDS)
+               return -EPERM;
+
        /* default to O_CLOEXEC, disable if IORING_FIXED_FD_NO_CLOEXEC is set */
        ifi = io_kiocb_to_cmd(req, struct io_fixed_install);
        ifi->o_flags = O_CLOEXEC;
index d59b74a99d4e4b444dcb2f86dc9d3594d838e1cf..7513afc7b702e4cbc727717fc59aa8eb758465df 100644 (file)
@@ -226,8 +226,29 @@ enum {
        IOU_POLL_NO_ACTION = 1,
        IOU_POLL_REMOVE_POLL_USE_RES = 2,
        IOU_POLL_REISSUE = 3,
+       IOU_POLL_REQUEUE = 4,
 };
 
+static void __io_poll_execute(struct io_kiocb *req, int mask)
+{
+       unsigned flags = 0;
+
+       io_req_set_res(req, mask, 0);
+       req->io_task_work.func = io_poll_task_func;
+
+       trace_io_uring_task_add(req, mask);
+
+       if (!(req->flags & REQ_F_POLL_NO_LAZY))
+               flags = IOU_F_TWQ_LAZY_WAKE;
+       __io_req_task_work_add(req, flags);
+}
+
+static inline void io_poll_execute(struct io_kiocb *req, int res)
+{
+       if (io_poll_get_ownership(req))
+               __io_poll_execute(req, res);
+}
+
 /*
  * All poll tw should go through this. Checks for poll events, manages
  * references, does rewait, etc.
@@ -309,6 +330,8 @@ static int io_poll_check_events(struct io_kiocb *req, struct io_tw_state *ts)
                        int ret = io_poll_issue(req, ts);
                        if (ret == IOU_STOP_MULTISHOT)
                                return IOU_POLL_REMOVE_POLL_USE_RES;
+                       else if (ret == IOU_REQUEUE)
+                               return IOU_POLL_REQUEUE;
                        if (ret < 0)
                                return ret;
                }
@@ -331,8 +354,12 @@ void io_poll_task_func(struct io_kiocb *req, struct io_tw_state *ts)
        int ret;
 
        ret = io_poll_check_events(req, ts);
-       if (ret == IOU_POLL_NO_ACTION)
+       if (ret == IOU_POLL_NO_ACTION) {
+               return;
+       } else if (ret == IOU_POLL_REQUEUE) {
+               __io_poll_execute(req, 0);
                return;
+       }
        io_poll_remove_entries(req);
        io_poll_tw_hash_eject(req, ts);
 
@@ -364,26 +391,6 @@ void io_poll_task_func(struct io_kiocb *req, struct io_tw_state *ts)
        }
 }
 
-static void __io_poll_execute(struct io_kiocb *req, int mask)
-{
-       unsigned flags = 0;
-
-       io_req_set_res(req, mask, 0);
-       req->io_task_work.func = io_poll_task_func;
-
-       trace_io_uring_task_add(req, mask);
-
-       if (!(req->flags & REQ_F_POLL_NO_LAZY))
-               flags = IOU_F_TWQ_LAZY_WAKE;
-       __io_req_task_work_add(req, flags);
-}
-
-static inline void io_poll_execute(struct io_kiocb *req, int res)
-{
-       if (io_poll_get_ownership(req))
-               __io_poll_execute(req, res);
-}
-
 static void io_poll_cancel_req(struct io_kiocb *req)
 {
        io_poll_mark_cancelled(req);
index ff4d5d753387e80568ccc90734732d6cb999b39e..1dacae9e816c9269e8a1ae5bfab4d12fa9aaa9ac 100644 (file)
@@ -24,6 +24,15 @@ struct async_poll {
        struct io_poll          *double_poll;
 };
 
+/*
+ * Must only be called inside issue_flags & IO_URING_F_MULTISHOT, or
+ * potentially other cases where we already "own" this poll request.
+ */
+static inline void io_poll_multishot_retry(struct io_kiocb *req)
+{
+       atomic_inc(&req->poll_refs);
+}
+
 int io_poll_add_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
 int io_poll_add(struct io_kiocb *req, unsigned int issue_flags);
 
index 118cc9f1cf1602a4859eb3359c8b2e64cf6db620..d5e79d9bdc717b8cb917d6e06b2cbbe6840dd762 100644 (file)
@@ -18,6 +18,7 @@
 #include "opdef.h"
 #include "kbuf.h"
 #include "rsrc.h"
+#include "poll.h"
 #include "rw.h"
 
 struct io_rw {
@@ -962,8 +963,15 @@ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
                if (io_fill_cqe_req_aux(req,
                                        issue_flags & IO_URING_F_COMPLETE_DEFER,
                                        ret, cflags | IORING_CQE_F_MORE)) {
-                       if (issue_flags & IO_URING_F_MULTISHOT)
+                       if (issue_flags & IO_URING_F_MULTISHOT) {
+                               /*
+                                * Force retry, as we might have more data to
+                                * be read and otherwise it won't get retried
+                                * until (if ever) another poll is triggered.
+                                */
+                               io_poll_multishot_retry(req);
                                return IOU_ISSUE_SKIP_COMPLETE;
+                       }
                        return -EAGAIN;
                }
        }
index 485bb0389b488d28a4efb23901b514d93b3834f6..929e98c629652a0fef1b71e6c002cca41936c4b4 100644 (file)
@@ -537,7 +537,7 @@ retry:
                }
        }
 
-       ret = __replace_page(vma, vaddr, old_page, new_page);
+       ret = __replace_page(vma, vaddr & PAGE_MASK, old_page, new_page);
        if (new_page)
                put_page(new_page);
 put_old:
index e0e853412c158e1277ea4c63a40576093b0bc673..1e78ef24321e82dbfaf0c07941a0c41ad3438aaa 100644 (file)
@@ -627,12 +627,21 @@ retry:
 }
 
 /*
- * PI futexes can not be requeued and must remove themselves from the
- * hash bucket. The hash bucket lock (i.e. lock_ptr) is held.
+ * PI futexes can not be requeued and must remove themselves from the hash
+ * bucket. The hash bucket lock (i.e. lock_ptr) is held.
  */
 void futex_unqueue_pi(struct futex_q *q)
 {
-       __futex_unqueue(q);
+       /*
+        * If the lock was not acquired (due to timeout or signal) then the
+        * rt_waiter is removed before futex_q is. If this is observed by
+        * an unlocker after dropping the rtmutex wait lock and before
+        * acquiring the hash bucket lock, then the unlocker dequeues the
+        * futex_q from the hash bucket list to guarantee consistent state
+        * vs. userspace. Therefore the dequeue here must be conditional.
+        */
+       if (!plist_node_empty(&q->list))
+               __futex_unqueue(q);
 
        BUG_ON(!q->pi_state);
        put_pi_state(q->pi_state);
index 90e5197f4e5696dbd5a79fd0033ed95e4bd32fac..5722467f273794ec314870fc76d0ba04a8617f7e 100644 (file)
@@ -1135,6 +1135,7 @@ retry:
 
        hb = futex_hash(&key);
        spin_lock(&hb->lock);
+retry_hb:
 
        /*
         * Check waiters first. We do not trust user space values at
@@ -1177,12 +1178,17 @@ retry:
                /*
                 * Futex vs rt_mutex waiter state -- if there are no rt_mutex
                 * waiters even though futex thinks there are, then the waiter
-                * is leaving and the uncontended path is safe to take.
+                * is leaving. The entry needs to be removed from the list so a
+                * new futex_lock_pi() is not using this stale PI-state while
+                * the futex is available in user space again.
+                * There can be more than one task on its way out so it needs
+                * to retry.
                 */
                rt_waiter = rt_mutex_top_waiter(&pi_state->pi_mutex);
                if (!rt_waiter) {
+                       __futex_unqueue(top_waiter);
                        raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
-                       goto do_uncontended;
+                       goto retry_hb;
                }
 
                get_pi_state(pi_state);
@@ -1217,7 +1223,6 @@ retry:
                return ret;
        }
 
-do_uncontended:
        /*
         * We have no kernel internal state, i.e. no waiters in the
         * kernel. Waiters which are about to queue themselves are stuck
index 27ca1c866f298bf9d8876bce68e418881702aabf..371eb1711d3467baf596c477411c1d3ac554cedd 100644 (file)
@@ -600,7 +600,7 @@ int __init early_irq_init(void)
                mutex_init(&desc[i].request_mutex);
                init_waitqueue_head(&desc[i].wait_for_threads);
                desc_set_defaults(i, &desc[i], node, NULL, NULL);
-               irq_resend_init(desc);
+               irq_resend_init(&desc[i]);
        }
        return arch_early_irq_init();
 }
index c108ed8a9804ada919575c97b42dd663e33c1a16..3052b1f1168e29c4432ba3b068488af11029018d 100644 (file)
@@ -99,6 +99,7 @@ static u64 suspend_start;
  * Interval: 0.5sec.
  */
 #define WATCHDOG_INTERVAL (HZ >> 1)
+#define WATCHDOG_INTERVAL_MAX_NS ((2 * WATCHDOG_INTERVAL) * (NSEC_PER_SEC / HZ))
 
 /*
  * Threshold: 0.0312s, when doubled: 0.0625s.
@@ -134,6 +135,7 @@ static DECLARE_WORK(watchdog_work, clocksource_watchdog_work);
 static DEFINE_SPINLOCK(watchdog_lock);
 static int watchdog_running;
 static atomic_t watchdog_reset_pending;
+static int64_t watchdog_max_interval;
 
 static inline void clocksource_watchdog_lock(unsigned long *flags)
 {
@@ -399,8 +401,8 @@ static inline void clocksource_reset_watchdog(void)
 static void clocksource_watchdog(struct timer_list *unused)
 {
        u64 csnow, wdnow, cslast, wdlast, delta;
+       int64_t wd_nsec, cs_nsec, interval;
        int next_cpu, reset_pending;
-       int64_t wd_nsec, cs_nsec;
        struct clocksource *cs;
        enum wd_read_status read_ret;
        unsigned long extra_wait = 0;
@@ -470,6 +472,27 @@ static void clocksource_watchdog(struct timer_list *unused)
                if (atomic_read(&watchdog_reset_pending))
                        continue;
 
+               /*
+                * The processing of timer softirqs can get delayed (usually
+                * on account of ksoftirqd not getting to run in a timely
+                * manner), which causes the watchdog interval to stretch.
+                * Skew detection may fail for longer watchdog intervals
+                * on account of fixed margins being used.
+                * Some clocksources, e.g. acpi_pm, cannot tolerate
+                * watchdog intervals longer than a few seconds.
+                */
+               interval = max(cs_nsec, wd_nsec);
+               if (unlikely(interval > WATCHDOG_INTERVAL_MAX_NS)) {
+                       if (system_state > SYSTEM_SCHEDULING &&
+                           interval > 2 * watchdog_max_interval) {
+                               watchdog_max_interval = interval;
+                               pr_warn("Long readout interval, skipping watchdog check: cs_nsec: %lld wd_nsec: %lld\n",
+                                       cs_nsec, wd_nsec);
+                       }
+                       watchdog_timer.expires = jiffies;
+                       continue;
+               }
+
                /* Check the deviation from the watchdog clocksource. */
                md = cs->uncertainty_margin + watchdog->uncertainty_margin;
                if (abs(cs_nsec - wd_nsec) > md) {
index d2501673028da5e627aa08b51a103c181295cad3..01fb50c1b17e4f1b33285ae2ce2690f0747f8ee8 100644 (file)
@@ -1577,6 +1577,7 @@ void tick_cancel_sched_timer(int cpu)
 {
        struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
        ktime_t idle_sleeptime, iowait_sleeptime;
+       unsigned long idle_calls, idle_sleeps;
 
 # ifdef CONFIG_HIGH_RES_TIMERS
        if (ts->sched_timer.base)
@@ -1585,9 +1586,13 @@ void tick_cancel_sched_timer(int cpu)
 
        idle_sleeptime = ts->idle_sleeptime;
        iowait_sleeptime = ts->iowait_sleeptime;
+       idle_calls = ts->idle_calls;
+       idle_sleeps = ts->idle_sleeps;
        memset(ts, 0, sizeof(*ts));
        ts->idle_sleeptime = idle_sleeptime;
        ts->iowait_sleeptime = iowait_sleeptime;
+       ts->idle_calls = idle_calls;
+       ts->idle_sleeps = idle_sleeps;
 }
 #endif
 
index 13aaf5e85b811b72f60b355f833a680342a41c7f..fd4bfe3ecf014f6b3c83f9a7fa043b7df44dac32 100644 (file)
@@ -944,7 +944,7 @@ __poll_t ring_buffer_poll_wait(struct trace_buffer *buffer, int cpu,
                full = 0;
        } else {
                if (!cpumask_test_cpu(cpu, buffer->cpumask))
-                       return -EINVAL;
+                       return EPOLLERR;
 
                cpu_buffer = buffer->buffers[cpu];
                work = &cpu_buffer->irq_work;
index 46439e3bcec4d20b45ae8202d7a68888778fa208..b33c3861fbbbf303e78f740a0fcc41caa2a77d77 100644 (file)
@@ -1470,8 +1470,10 @@ register_snapshot_trigger(char *glob,
                          struct event_trigger_data *data,
                          struct trace_event_file *file)
 {
-       if (tracing_alloc_snapshot_instance(file->tr) != 0)
-               return 0;
+       int ret = tracing_alloc_snapshot_instance(file->tr);
+
+       if (ret < 0)
+               return ret;
 
        return register_trigger(glob, data, file);
 }
index bd0d01d00fb9d52d0736524c3274f1382fee8462..a8e28f9b9271cf6545351f7d4f7ece1fbd9d8989 100644 (file)
@@ -2444,6 +2444,9 @@ static int timerlat_fd_open(struct inode *inode, struct file *file)
        tlat = this_cpu_tmr_var();
        tlat->count = 0;
 
+       hrtimer_init(&tlat->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED_HARD);
+       tlat->timer.function = timerlat_irq;
+
        migrate_enable();
        return 0;
 };
@@ -2526,9 +2529,6 @@ timerlat_fd_read(struct file *file, char __user *ubuf, size_t count,
                tlat->tracing_thread = false;
                tlat->kthread = current;
 
-               hrtimer_init(&tlat->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED_HARD);
-               tlat->timer.function = timerlat_irq;
-
                /* Annotate now to drift new period */
                tlat->abs_period = hrtimer_cb_get_time(&tlat->timer);
 
index f5371287b3750f0cefdc423748846b4257d8d14a..074c6dd2e36a7d9e8154a604db7c2a8e4f669921 100644 (file)
@@ -45,8 +45,8 @@ int kunit_bus_init(void)
        int error;
 
        kunit_bus_device = root_device_register("kunit");
-       if (!kunit_bus_device)
-               return -ENOMEM;
+       if (IS_ERR(kunit_bus_device))
+               return PTR_ERR(kunit_bus_device);
 
        error = bus_register(&kunit_bus_type);
        if (error)
index 717b9599036ba0bccf1ffe846b7b051c591109f2..689fff2b2b106a597bbf9b2e473d37e193537b03 100644 (file)
@@ -146,6 +146,10 @@ void kunit_free_suite_set(struct kunit_suite_set suite_set)
        kfree(suite_set.start);
 }
 
+/*
+ * Filter and reallocate test suites. Must return the filtered test suites set
+ * allocated at a valid virtual address or NULL in case of error.
+ */
 struct kunit_suite_set
 kunit_filter_suites(const struct kunit_suite_set *suite_set,
                    const char *filter_glob,
index c4259d910356ba7e8f24847cd347eb5861071cb4..f7980ef236a38bdefd8e0e7b53915f6057348617 100644 (file)
@@ -720,7 +720,7 @@ static void kunit_device_cleanup_test(struct kunit *test)
        long action_was_run = 0;
 
        test_device = kunit_device_register(test, "my_device");
-       KUNIT_ASSERT_NOT_NULL(test, test_device);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_device);
 
        /* Add an action to verify cleanup. */
        devm_add_action(test_device, test_dev_action, &action_was_run);
index f95d2093a0aa3359c0cb08462ea62e76ab0f2ecf..31a5a992e64670f35a9717659f99ca1b385d5f2e 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/panic.h>
 #include <linux/sched/debug.h>
 #include <linux/sched.h>
+#include <linux/mm.h>
 
 #include "debugfs.h"
 #include "device-impl.h"
@@ -801,12 +802,19 @@ static void kunit_module_exit(struct module *mod)
        };
        const char *action = kunit_action();
 
+       /*
+        * Check if the start address is a valid virtual address to detect
+        * if the module load sequence has failed and the suite set has not
+        * been initialized and filtered.
+        */
+       if (!suite_set.start || !virt_addr_valid(suite_set.start))
+               return;
+
        if (!action)
                __kunit_test_suites_exit(mod->kunit_suites,
                                         mod->num_kunit_suites);
 
-       if (suite_set.start)
-               kunit_free_suite_set(suite_set);
+       kunit_free_suite_set(suite_set);
 }
 
 static int kunit_module_notify(struct notifier_block *nb, unsigned long val,
@@ -816,12 +824,12 @@ static int kunit_module_notify(struct notifier_block *nb, unsigned long val,
 
        switch (val) {
        case MODULE_STATE_LIVE:
+               kunit_module_init(mod);
                break;
        case MODULE_STATE_GOING:
                kunit_module_exit(mod);
                break;
        case MODULE_STATE_COMING:
-               kunit_module_init(mod);
                break;
        case MODULE_STATE_UNFORMED:
                break;
index a0be5d05c7f08187667c91c7d0886843df52225c..5caa1f566553843911ffdf2edafd32ee70277ea8 100644 (file)
@@ -14,6 +14,7 @@
 
 #define pr_fmt(fmt) "stackdepot: " fmt
 
+#include <linux/debugfs.h>
 #include <linux/gfp.h>
 #include <linux/jhash.h>
 #include <linux/kernel.h>
@@ -21,8 +22,9 @@
 #include <linux/list.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
-#include <linux/percpu.h>
 #include <linux/printk.h>
+#include <linux/rculist.h>
+#include <linux/rcupdate.h>
 #include <linux/refcount.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
@@ -67,12 +69,28 @@ union handle_parts {
 };
 
 struct stack_record {
-       struct list_head list;          /* Links in hash table or freelist */
+       struct list_head hash_list;     /* Links in the hash table */
        u32 hash;                       /* Hash in hash table */
        u32 size;                       /* Number of stored frames */
-       union handle_parts handle;
+       union handle_parts handle;      /* Constant after initialization */
        refcount_t count;
-       unsigned long entries[CONFIG_STACKDEPOT_MAX_FRAMES];    /* Frames */
+       union {
+               unsigned long entries[CONFIG_STACKDEPOT_MAX_FRAMES];    /* Frames */
+               struct {
+                       /*
+                        * An important invariant of the implementation is to
+                        * only place a stack record onto the freelist iff its
+                        * refcount is zero. Because stack records with a zero
+                        * refcount are never considered as valid, it is safe to
+                        * union @entries and freelist management state below.
+                        * Conversely, as soon as an entry is off the freelist
+                        * and its refcount becomes non-zero, the below must not
+                        * be accessed until being placed back on the freelist.
+                        */
+                       struct list_head free_list;     /* Links in the freelist */
+                       unsigned long rcu_state;        /* RCU cookie */
+               };
+       };
 };
 
 #define DEPOT_STACK_RECORD_SIZE \
@@ -112,8 +130,25 @@ static LIST_HEAD(free_stacks);
  * yet allocated or if the limit on the number of pools is reached.
  */
 static bool new_pool_required = true;
-/* Lock that protects the variables above. */
-static DEFINE_RWLOCK(pool_rwlock);
+/* The lock must be held when performing pool or freelist modifications. */
+static DEFINE_RAW_SPINLOCK(pool_lock);
+
+/* Statistics counters for debugfs. */
+enum depot_counter_id {
+       DEPOT_COUNTER_ALLOCS,
+       DEPOT_COUNTER_FREES,
+       DEPOT_COUNTER_INUSE,
+       DEPOT_COUNTER_FREELIST_SIZE,
+       DEPOT_COUNTER_COUNT,
+};
+static long counters[DEPOT_COUNTER_COUNT];
+static const char *const counter_names[] = {
+       [DEPOT_COUNTER_ALLOCS]          = "allocations",
+       [DEPOT_COUNTER_FREES]           = "frees",
+       [DEPOT_COUNTER_INUSE]           = "in_use",
+       [DEPOT_COUNTER_FREELIST_SIZE]   = "freelist_size",
+};
+static_assert(ARRAY_SIZE(counter_names) == DEPOT_COUNTER_COUNT);
 
 static int __init disable_stack_depot(char *str)
 {
@@ -258,14 +293,15 @@ out_unlock:
 }
 EXPORT_SYMBOL_GPL(stack_depot_init);
 
-/* Initializes a stack depol pool. */
+/*
+ * Initializes new stack depot @pool, release all its entries to the freelist,
+ * and update the list of pools.
+ */
 static void depot_init_pool(void *pool)
 {
        int offset;
 
-       lockdep_assert_held_write(&pool_rwlock);
-
-       WARN_ON(!list_empty(&free_stacks));
+       lockdep_assert_held(&pool_lock);
 
        /* Initialize handles and link stack records into the freelist. */
        for (offset = 0; offset <= DEPOT_POOL_SIZE - DEPOT_STACK_RECORD_SIZE;
@@ -276,18 +312,36 @@ static void depot_init_pool(void *pool)
                stack->handle.offset = offset >> DEPOT_STACK_ALIGN;
                stack->handle.extra = 0;
 
-               list_add(&stack->list, &free_stacks);
+               /*
+                * Stack traces of size 0 are never saved, and we can simply use
+                * the size field as an indicator if this is a new unused stack
+                * record in the freelist.
+                */
+               stack->size = 0;
+
+               INIT_LIST_HEAD(&stack->hash_list);
+               /*
+                * Add to the freelist front to prioritize never-used entries:
+                * required in case there are entries in the freelist, but their
+                * RCU cookie still belongs to the current RCU grace period
+                * (there can still be concurrent readers).
+                */
+               list_add(&stack->free_list, &free_stacks);
+               counters[DEPOT_COUNTER_FREELIST_SIZE]++;
        }
 
        /* Save reference to the pool to be used by depot_fetch_stack(). */
        stack_pools[pools_num] = pool;
-       pools_num++;
+
+       /* Pairs with concurrent READ_ONCE() in depot_fetch_stack(). */
+       WRITE_ONCE(pools_num, pools_num + 1);
+       ASSERT_EXCLUSIVE_WRITER(pools_num);
 }
 
 /* Keeps the preallocated memory to be used for a new stack depot pool. */
 static void depot_keep_new_pool(void **prealloc)
 {
-       lockdep_assert_held_write(&pool_rwlock);
+       lockdep_assert_held(&pool_lock);
 
        /*
         * If a new pool is already saved or the maximum number of
@@ -310,17 +364,16 @@ static void depot_keep_new_pool(void **prealloc)
         * number of pools is reached. In either case, take note that
         * keeping another pool is not required.
         */
-       new_pool_required = false;
+       WRITE_ONCE(new_pool_required, false);
 }
 
-/* Updates references to the current and the next stack depot pools. */
-static bool depot_update_pools(void **prealloc)
+/*
+ * Try to initialize a new stack depot pool from either a previous or the
+ * current pre-allocation, and release all its entries to the freelist.
+ */
+static bool depot_try_init_pool(void **prealloc)
 {
-       lockdep_assert_held_write(&pool_rwlock);
-
-       /* Check if we still have objects in the freelist. */
-       if (!list_empty(&free_stacks))
-               goto out_keep_prealloc;
+       lockdep_assert_held(&pool_lock);
 
        /* Check if we have a new pool saved and use it. */
        if (new_pool) {
@@ -329,10 +382,9 @@ static bool depot_update_pools(void **prealloc)
 
                /* Take note that we might need a new new_pool. */
                if (pools_num < DEPOT_MAX_POOLS)
-                       new_pool_required = true;
+                       WRITE_ONCE(new_pool_required, true);
 
-               /* Try keeping the preallocated memory for new_pool. */
-               goto out_keep_prealloc;
+               return true;
        }
 
        /* Bail out if we reached the pool limit. */
@@ -349,12 +401,32 @@ static bool depot_update_pools(void **prealloc)
        }
 
        return false;
+}
+
+/* Try to find next free usable entry. */
+static struct stack_record *depot_pop_free(void)
+{
+       struct stack_record *stack;
+
+       lockdep_assert_held(&pool_lock);
+
+       if (list_empty(&free_stacks))
+               return NULL;
+
+       /*
+        * We maintain the invariant that the elements in front are least
+        * recently used, and are therefore more likely to be associated with an
+        * RCU grace period in the past. Consequently it is sufficient to only
+        * check the first entry.
+        */
+       stack = list_first_entry(&free_stacks, struct stack_record, free_list);
+       if (stack->size && !poll_state_synchronize_rcu(stack->rcu_state))
+               return NULL;
+
+       list_del(&stack->free_list);
+       counters[DEPOT_COUNTER_FREELIST_SIZE]--;
 
-out_keep_prealloc:
-       /* Keep the preallocated memory for a new pool if required. */
-       if (*prealloc)
-               depot_keep_new_pool(prealloc);
-       return true;
+       return stack;
 }
 
 /* Allocates a new stack in a stack depot pool. */
@@ -363,19 +435,22 @@ depot_alloc_stack(unsigned long *entries, int size, u32 hash, void **prealloc)
 {
        struct stack_record *stack;
 
-       lockdep_assert_held_write(&pool_rwlock);
+       lockdep_assert_held(&pool_lock);
 
-       /* Update current and new pools if required and possible. */
-       if (!depot_update_pools(prealloc))
+       /* This should already be checked by public API entry points. */
+       if (WARN_ON_ONCE(!size))
                return NULL;
 
        /* Check if we have a stack record to save the stack trace. */
-       if (list_empty(&free_stacks))
-               return NULL;
-
-       /* Get and unlink the first entry from the freelist. */
-       stack = list_first_entry(&free_stacks, struct stack_record, list);
-       list_del(&stack->list);
+       stack = depot_pop_free();
+       if (!stack) {
+               /* No usable entries on the freelist - try to refill the freelist. */
+               if (!depot_try_init_pool(prealloc))
+                       return NULL;
+               stack = depot_pop_free();
+               if (WARN_ON(!stack))
+                       return NULL;
+       }
 
        /* Limit number of saved frames to CONFIG_STACKDEPOT_MAX_FRAMES. */
        if (size > CONFIG_STACKDEPOT_MAX_FRAMES)
@@ -394,38 +469,80 @@ depot_alloc_stack(unsigned long *entries, int size, u32 hash, void **prealloc)
         */
        kmsan_unpoison_memory(stack, DEPOT_STACK_RECORD_SIZE);
 
+       counters[DEPOT_COUNTER_ALLOCS]++;
+       counters[DEPOT_COUNTER_INUSE]++;
        return stack;
 }
 
 static struct stack_record *depot_fetch_stack(depot_stack_handle_t handle)
 {
+       const int pools_num_cached = READ_ONCE(pools_num);
        union handle_parts parts = { .handle = handle };
        void *pool;
        size_t offset = parts.offset << DEPOT_STACK_ALIGN;
        struct stack_record *stack;
 
-       lockdep_assert_held(&pool_rwlock);
+       lockdep_assert_not_held(&pool_lock);
 
-       if (parts.pool_index > pools_num) {
+       if (parts.pool_index > pools_num_cached) {
                WARN(1, "pool index %d out of bounds (%d) for stack id %08x\n",
-                    parts.pool_index, pools_num, handle);
+                    parts.pool_index, pools_num_cached, handle);
                return NULL;
        }
 
        pool = stack_pools[parts.pool_index];
-       if (!pool)
+       if (WARN_ON(!pool))
                return NULL;
 
        stack = pool + offset;
+       if (WARN_ON(!refcount_read(&stack->count)))
+               return NULL;
+
        return stack;
 }
 
 /* Links stack into the freelist. */
 static void depot_free_stack(struct stack_record *stack)
 {
-       lockdep_assert_held_write(&pool_rwlock);
+       unsigned long flags;
+
+       lockdep_assert_not_held(&pool_lock);
 
-       list_add(&stack->list, &free_stacks);
+       raw_spin_lock_irqsave(&pool_lock, flags);
+       printk_deferred_enter();
+
+       /*
+        * Remove the entry from the hash list. Concurrent list traversal may
+        * still observe the entry, but since the refcount is zero, this entry
+        * will no longer be considered as valid.
+        */
+       list_del_rcu(&stack->hash_list);
+
+       /*
+        * Due to being used from constrained contexts such as the allocators,
+        * NMI, or even RCU itself, stack depot cannot rely on primitives that
+        * would sleep (such as synchronize_rcu()) or recursively call into
+        * stack depot again (such as call_rcu()).
+        *
+        * Instead, get an RCU cookie, so that we can ensure this entry isn't
+        * moved onto another list until the next grace period, and concurrent
+        * RCU list traversal remains safe.
+        */
+       stack->rcu_state = get_state_synchronize_rcu();
+
+       /*
+        * Add the entry to the freelist tail, so that older entries are
+        * considered first - their RCU cookie is more likely to no longer be
+        * associated with the current grace period.
+        */
+       list_add_tail(&stack->free_list, &free_stacks);
+
+       counters[DEPOT_COUNTER_FREELIST_SIZE]++;
+       counters[DEPOT_COUNTER_FREES]++;
+       counters[DEPOT_COUNTER_INUSE]--;
+
+       printk_deferred_exit();
+       raw_spin_unlock_irqrestore(&pool_lock, flags);
 }
 
 /* Calculates the hash for a stack. */
@@ -453,22 +570,52 @@ int stackdepot_memcmp(const unsigned long *u1, const unsigned long *u2,
 
 /* Finds a stack in a bucket of the hash table. */
 static inline struct stack_record *find_stack(struct list_head *bucket,
-                                            unsigned long *entries, int size,
-                                            u32 hash)
+                                             unsigned long *entries, int size,
+                                             u32 hash, depot_flags_t flags)
 {
-       struct list_head *pos;
-       struct stack_record *found;
+       struct stack_record *stack, *ret = NULL;
+
+       /*
+        * Stack depot may be used from instrumentation that instruments RCU or
+        * tracing itself; use variant that does not call into RCU and cannot be
+        * traced.
+        *
+        * Note: Such use cases must take care when using refcounting to evict
+        * unused entries, because the stack record free-then-reuse code paths
+        * do call into RCU.
+        */
+       rcu_read_lock_sched_notrace();
 
-       lockdep_assert_held(&pool_rwlock);
+       list_for_each_entry_rcu(stack, bucket, hash_list) {
+               if (stack->hash != hash || stack->size != size)
+                       continue;
+
+               /*
+                * This may race with depot_free_stack() accessing the freelist
+                * management state unioned with @entries. The refcount is zero
+                * in that case and the below refcount_inc_not_zero() will fail.
+                */
+               if (data_race(stackdepot_memcmp(entries, stack->entries, size)))
+                       continue;
+
+               /*
+                * Try to increment refcount. If this succeeds, the stack record
+                * is valid and has not yet been freed.
+                *
+                * If STACK_DEPOT_FLAG_GET is not used, it is undefined behavior
+                * to then call stack_depot_put() later, and we can assume that
+                * a stack record is never placed back on the freelist.
+                */
+               if ((flags & STACK_DEPOT_FLAG_GET) && !refcount_inc_not_zero(&stack->count))
+                       continue;
 
-       list_for_each(pos, bucket) {
-               found = list_entry(pos, struct stack_record, list);
-               if (found->hash == hash &&
-                   found->size == size &&
-                   !stackdepot_memcmp(entries, found->entries, size))
-                       return found;
+               ret = stack;
+               break;
        }
-       return NULL;
+
+       rcu_read_unlock_sched_notrace();
+
+       return ret;
 }
 
 depot_stack_handle_t stack_depot_save_flags(unsigned long *entries,
@@ -482,7 +629,6 @@ depot_stack_handle_t stack_depot_save_flags(unsigned long *entries,
        struct page *page = NULL;
        void *prealloc = NULL;
        bool can_alloc = depot_flags & STACK_DEPOT_FLAG_CAN_ALLOC;
-       bool need_alloc = false;
        unsigned long flags;
        u32 hash;
 
@@ -505,31 +651,16 @@ depot_stack_handle_t stack_depot_save_flags(unsigned long *entries,
        hash = hash_stack(entries, nr_entries);
        bucket = &stack_table[hash & stack_hash_mask];
 
-       read_lock_irqsave(&pool_rwlock, flags);
-       printk_deferred_enter();
-
-       /* Fast path: look the stack trace up without full locking. */
-       found = find_stack(bucket, entries, nr_entries, hash);
-       if (found) {
-               if (depot_flags & STACK_DEPOT_FLAG_GET)
-                       refcount_inc(&found->count);
-               printk_deferred_exit();
-               read_unlock_irqrestore(&pool_rwlock, flags);
+       /* Fast path: look the stack trace up without locking. */
+       found = find_stack(bucket, entries, nr_entries, hash, depot_flags);
+       if (found)
                goto exit;
-       }
-
-       /* Take note if another stack pool needs to be allocated. */
-       if (new_pool_required)
-               need_alloc = true;
-
-       printk_deferred_exit();
-       read_unlock_irqrestore(&pool_rwlock, flags);
 
        /*
         * Allocate memory for a new pool if required now:
         * we won't be able to do that under the lock.
         */
-       if (unlikely(can_alloc && need_alloc)) {
+       if (unlikely(can_alloc && READ_ONCE(new_pool_required))) {
                /*
                 * Zero out zone modifiers, as we don't have specific zone
                 * requirements. Keep the flags related to allocation in atomic
@@ -543,31 +674,36 @@ depot_stack_handle_t stack_depot_save_flags(unsigned long *entries,
                        prealloc = page_address(page);
        }
 
-       write_lock_irqsave(&pool_rwlock, flags);
+       raw_spin_lock_irqsave(&pool_lock, flags);
        printk_deferred_enter();
 
-       found = find_stack(bucket, entries, nr_entries, hash);
+       /* Try to find again, to avoid concurrently inserting duplicates. */
+       found = find_stack(bucket, entries, nr_entries, hash, depot_flags);
        if (!found) {
                struct stack_record *new =
                        depot_alloc_stack(entries, nr_entries, hash, &prealloc);
 
                if (new) {
-                       list_add(&new->list, bucket);
+                       /*
+                        * This releases the stack record into the bucket and
+                        * makes it visible to readers in find_stack().
+                        */
+                       list_add_rcu(&new->hash_list, bucket);
                        found = new;
                }
-       } else {
-               if (depot_flags & STACK_DEPOT_FLAG_GET)
-                       refcount_inc(&found->count);
+       }
+
+       if (prealloc) {
                /*
-                * Stack depot already contains this stack trace, but let's
-                * keep the preallocated memory for future.
+                * Either stack depot already contains this stack trace, or
+                * depot_alloc_stack() did not consume the preallocated memory.
+                * Try to keep the preallocated memory for future.
                 */
-               if (prealloc)
-                       depot_keep_new_pool(&prealloc);
+               depot_keep_new_pool(&prealloc);
        }
 
        printk_deferred_exit();
-       write_unlock_irqrestore(&pool_rwlock, flags);
+       raw_spin_unlock_irqrestore(&pool_lock, flags);
 exit:
        if (prealloc) {
                /* Stack depot didn't use this memory, free it. */
@@ -592,7 +728,6 @@ unsigned int stack_depot_fetch(depot_stack_handle_t handle,
                               unsigned long **entries)
 {
        struct stack_record *stack;
-       unsigned long flags;
 
        *entries = NULL;
        /*
@@ -604,13 +739,13 @@ unsigned int stack_depot_fetch(depot_stack_handle_t handle,
        if (!handle || stack_depot_disabled)
                return 0;
 
-       read_lock_irqsave(&pool_rwlock, flags);
-       printk_deferred_enter();
-
        stack = depot_fetch_stack(handle);
-
-       printk_deferred_exit();
-       read_unlock_irqrestore(&pool_rwlock, flags);
+       /*
+        * Should never be NULL, otherwise this is a use-after-put (or just a
+        * corrupt handle).
+        */
+       if (WARN(!stack, "corrupt handle or use after stack_depot_put()"))
+               return 0;
 
        *entries = stack->entries;
        return stack->size;
@@ -620,29 +755,20 @@ EXPORT_SYMBOL_GPL(stack_depot_fetch);
 void stack_depot_put(depot_stack_handle_t handle)
 {
        struct stack_record *stack;
-       unsigned long flags;
 
        if (!handle || stack_depot_disabled)
                return;
 
-       write_lock_irqsave(&pool_rwlock, flags);
-       printk_deferred_enter();
-
        stack = depot_fetch_stack(handle);
-       if (WARN_ON(!stack))
-               goto out;
-
-       if (refcount_dec_and_test(&stack->count)) {
-               /* Unlink stack from the hash table. */
-               list_del(&stack->list);
+       /*
+        * Should always be able to find the stack record, otherwise this is an
+        * unbalanced put attempt (or corrupt handle).
+        */
+       if (WARN(!stack, "corrupt handle or unbalanced stack_depot_put()"))
+               return;
 
-               /* Free stack. */
+       if (refcount_dec_and_test(&stack->count))
                depot_free_stack(stack);
-       }
-
-out:
-       printk_deferred_exit();
-       write_unlock_irqrestore(&pool_rwlock, flags);
 }
 EXPORT_SYMBOL_GPL(stack_depot_put);
 
@@ -690,3 +816,30 @@ unsigned int stack_depot_get_extra_bits(depot_stack_handle_t handle)
        return parts.extra;
 }
 EXPORT_SYMBOL(stack_depot_get_extra_bits);
+
+static int stats_show(struct seq_file *seq, void *v)
+{
+       /*
+        * data race ok: These are just statistics counters, and approximate
+        * statistics are ok for debugging.
+        */
+       seq_printf(seq, "pools: %d\n", data_race(pools_num));
+       for (int i = 0; i < DEPOT_COUNTER_COUNT; i++)
+               seq_printf(seq, "%s: %ld\n", counter_names[i], data_race(counters[i]));
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(stats);
+
+static int depot_debugfs_init(void)
+{
+       struct dentry *dir;
+
+       if (stack_depot_disabled)
+               return 0;
+
+       dir = debugfs_create_dir("stackdepot", NULL);
+       debugfs_create_file("stats", 0444, dir, NULL, &stats_fops);
+       return 0;
+}
+late_initcall(depot_debugfs_init);
index 94ef5c02b459642f2625775bc66ca147cb2ac992..94c958f7ebb50dd925070157c0d0b2432dfc0483 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/page_owner.h>
 #include <linux/sched/sysctl.h>
 #include <linux/memory-tiers.h>
+#include <linux/compat.h>
 
 #include <asm/tlb.h>
 #include <asm/pgalloc.h>
@@ -809,7 +810,10 @@ static unsigned long __thp_get_unmapped_area(struct file *filp,
 {
        loff_t off_end = off + len;
        loff_t off_align = round_up(off, size);
-       unsigned long len_pad, ret;
+       unsigned long len_pad, ret, off_sub;
+
+       if (IS_ENABLED(CONFIG_32BIT) || in_compat_syscall())
+               return 0;
 
        if (off_end <= off_align || (off_end - off_align) < size)
                return 0;
@@ -835,7 +839,13 @@ static unsigned long __thp_get_unmapped_area(struct file *filp,
        if (ret == addr)
                return addr;
 
-       ret += (off - ret) & (size - 1);
+       off_sub = (off - ret) & (size - 1);
+
+       if (current->mm->get_unmapped_area == arch_get_unmapped_area_topdown &&
+           !off_sub)
+               return ret + size;
+
+       ret += off_sub;
        return ret;
 }
 
@@ -2437,7 +2447,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
                        page = pmd_page(old_pmd);
                        folio = page_folio(page);
                        if (!folio_test_dirty(folio) && pmd_dirty(old_pmd))
-                               folio_set_dirty(folio);
+                               folio_mark_dirty(folio);
                        if (!folio_test_referenced(folio) && pmd_young(old_pmd))
                                folio_set_referenced(folio);
                        folio_remove_rmap_pmd(folio, page, vma);
@@ -3563,7 +3573,7 @@ int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
        }
 
        if (pmd_dirty(pmdval))
-               folio_set_dirty(folio);
+               folio_mark_dirty(folio);
        if (pmd_write(pmdval))
                entry = make_writable_migration_entry(page_to_pfn(page));
        else if (anon_exclusive)
index abd92869874d75f62cd303475ba2b44c67db38ac..4dcb2ee35eca856a43694f4402dea0c1c9bf6d8a 100644 (file)
@@ -2176,6 +2176,9 @@ static void __init memmap_init_reserved_pages(void)
                        start = region->base;
                        end = start + region->size;
 
+                       if (nid == NUMA_NO_NODE || nid >= MAX_NUMNODES)
+                               nid = early_pfn_to_nid(PFN_DOWN(start));
+
                        reserve_bootmem_region(start, end, nid);
                }
        }
index e4c8735e7c85cf061a2ab31c9be250934c680879..46d8d02114cfeeda78049fa986d29ac1b324d7f3 100644 (file)
@@ -2623,8 +2623,9 @@ static unsigned long calculate_high_delay(struct mem_cgroup *memcg,
 }
 
 /*
- * Scheduled by try_charge() to be executed from the userland return path
- * and reclaims memory over the high limit.
+ * Reclaims memory over the high limit. Called directly from
+ * try_charge() (context permitting), as well as from the userland
+ * return path where reclaim is always able to block.
  */
 void mem_cgroup_handle_over_high(gfp_t gfp_mask)
 {
@@ -2643,6 +2644,17 @@ void mem_cgroup_handle_over_high(gfp_t gfp_mask)
        current->memcg_nr_pages_over_high = 0;
 
 retry_reclaim:
+       /*
+        * Bail if the task is already exiting. Unlike memory.max,
+        * memory.high enforcement isn't as strict, and there is no
+        * OOM killer involved, which means the excess could already
+        * be much bigger (and still growing) than it could for
+        * memory.max; the dying task could get stuck in fruitless
+        * reclaim for a long time, which isn't desirable.
+        */
+       if (task_is_dying())
+               goto out;
+
        /*
         * The allocating task should reclaim at least the batch size, but for
         * subsequent retries we only want to do what's necessary to prevent oom
@@ -2693,6 +2705,9 @@ retry_reclaim:
        }
 
        /*
+        * Reclaim didn't manage to push usage below the limit, slow
+        * this allocating task down.
+        *
         * If we exit early, we're guaranteed to die (since
         * schedule_timeout_killable sets TASK_KILLABLE). This means we don't
         * need to account for any ill-begotten jiffies to pay them off later.
@@ -2887,11 +2902,17 @@ done_restock:
                }
        } while ((memcg = parent_mem_cgroup(memcg)));
 
+       /*
+        * Reclaim is set up above to be called from the userland
+        * return path. But also attempt synchronous reclaim to avoid
+        * excessive overrun while the task is still inside the
+        * kernel. If this is successful, the return path will see it
+        * when it rechecks the overage and simply bail out.
+        */
        if (current->memcg_nr_pages_over_high > MEMCG_CHARGE_BATCH &&
            !(current->flags & PF_MEMALLOC) &&
-           gfpflags_allow_blocking(gfp_mask)) {
+           gfpflags_allow_blocking(gfp_mask))
                mem_cgroup_handle_over_high(gfp_mask);
-       }
        return 0;
 }
 
index 4f9b61f4a6682a530a202d02a6998c0b687906dd..636280d04008d8550dda8f9aa12acf6da5d92848 100644 (file)
@@ -982,7 +982,7 @@ static bool has_extra_refcount(struct page_state *ps, struct page *p,
        int count = page_count(p) - 1;
 
        if (extra_pins)
-               count -= 1;
+               count -= folio_nr_pages(page_folio(p));
 
        if (count > 0) {
                pr_err("%#lx: %s still referenced by %d users\n",
index 7e1f4849463aa3645a0eead97f40a90caf5e6d5f..89bcae0b224d6d43b4720c5c71a6c528e683bafb 100644 (file)
@@ -1464,7 +1464,7 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
                        delay_rmap = 0;
                        if (!folio_test_anon(folio)) {
                                if (pte_dirty(ptent)) {
-                                       folio_set_dirty(folio);
+                                       folio_mark_dirty(folio);
                                        if (tlb_delay_rmap(tlb)) {
                                                delay_rmap = 1;
                                                force_flush = 1;
index b78e83d351d2864a6a339059ac734b6602eb5824..d89770eaab6b6111117783ca7ff532871c1d71a5 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1825,15 +1825,17 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
                /*
                 * mmap_region() will call shmem_zero_setup() to create a file,
                 * so use shmem's get_unmapped_area in case it can be huge.
-                * do_mmap() will clear pgoff, so match alignment.
                 */
-               pgoff = 0;
                get_area = shmem_get_unmapped_area;
        } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
                /* Ensures that larger anonymous mappings are THP aligned. */
                get_area = thp_get_unmapped_area;
        }
 
+       /* Always treat pgoff as zero for anonymous memory. */
+       if (!file)
+               pgoff = 0;
+
        addr = get_area(file, addr, len, pgoff, flags);
        if (IS_ERR_VALUE(addr))
                return addr;
index cd4e4ae77c40ae0497efeaa8fb391f6550e51a4b..02147b61712bc9e3536061bb33d3f54f2e5db463 100644 (file)
@@ -1638,7 +1638,7 @@ static inline void wb_dirty_limits(struct dirty_throttle_control *dtc)
         */
        dtc->wb_thresh = __wb_calc_thresh(dtc);
        dtc->wb_bg_thresh = dtc->thresh ?
-               div_u64((u64)dtc->wb_thresh * dtc->bg_thresh, dtc->thresh) : 0;
+               div64_u64(dtc->wb_thresh * dtc->bg_thresh, dtc->thresh) : 0;
 
        /*
         * In order to avoid the stacked BDI deadlock we need
index 23620c57c1225bef9e3e1193a7163c36a916951f..2648ec4f04947b2e837377da68d7b8ae1fd48f7a 100644 (file)
@@ -469,7 +469,7 @@ static inline int ra_alloc_folio(struct readahead_control *ractl, pgoff_t index,
 
        if (!folio)
                return -ENOMEM;
-       mark = round_up(mark, 1UL << order);
+       mark = round_down(mark, 1UL << order);
        if (index == mark)
                folio_set_readahead(folio);
        err = filemap_add_folio(ractl->mapping, folio, index, gfp);
@@ -575,7 +575,7 @@ static void ondemand_readahead(struct readahead_control *ractl,
         * It's the expected callback index, assume sequential access.
         * Ramp up sizes, and push forward the readahead window.
         */
-       expected = round_up(ra->start + ra->size - ra->async_size,
+       expected = round_down(ra->start + ra->size - ra->async_size,
                        1UL << order);
        if (index == expected || index == (ra->start + ra->size)) {
                ra->start += ra->size;
index 20e3b0d9cf7ed0d59d86a11b2472f0e138160692..75fcf1f783bc567d1a916c85fb7abddc169f7fb5 100644 (file)
@@ -357,6 +357,7 @@ static __always_inline ssize_t mfill_atomic_hugetlb(
                                              unsigned long dst_start,
                                              unsigned long src_start,
                                              unsigned long len,
+                                             atomic_t *mmap_changing,
                                              uffd_flags_t flags)
 {
        struct mm_struct *dst_mm = dst_vma->vm_mm;
@@ -472,6 +473,15 @@ retry:
                                goto out;
                        }
                        mmap_read_lock(dst_mm);
+                       /*
+                        * If memory mappings are changing because of non-cooperative
+                        * operation (e.g. mremap) running in parallel, bail out and
+                        * request the user to retry later
+                        */
+                       if (mmap_changing && atomic_read(mmap_changing)) {
+                               err = -EAGAIN;
+                               break;
+                       }
 
                        dst_vma = NULL;
                        goto retry;
@@ -506,6 +516,7 @@ extern ssize_t mfill_atomic_hugetlb(struct vm_area_struct *dst_vma,
                                    unsigned long dst_start,
                                    unsigned long src_start,
                                    unsigned long len,
+                                   atomic_t *mmap_changing,
                                    uffd_flags_t flags);
 #endif /* CONFIG_HUGETLB_PAGE */
 
@@ -622,8 +633,8 @@ retry:
         * If this is a HUGETLB vma, pass off to appropriate routine
         */
        if (is_vm_hugetlb_page(dst_vma))
-               return  mfill_atomic_hugetlb(dst_vma, dst_start,
-                                            src_start, len, flags);
+               return  mfill_atomic_hugetlb(dst_vma, dst_start, src_start,
+                                            len, mmap_changing, flags);
 
        if (!vma_is_anonymous(dst_vma) && !vma_is_shmem(dst_vma))
                goto out_unlock;
index d982daea832927d38474f8d46764a82f87a09659..14088c4ff2f66f9049858598f30dc0069c27fb70 100644 (file)
@@ -2175,6 +2175,7 @@ void batadv_mcast_free(struct batadv_priv *bat_priv)
        cancel_delayed_work_sync(&bat_priv->mcast.work);
 
        batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
+       batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST_TRACKER, 1);
        batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
 
        /* safely calling outside of worker, as worker was canceled above */
@@ -2198,6 +2199,8 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig)
                                      BATADV_MCAST_WANT_NO_RTR4);
        batadv_mcast_want_rtr6_update(bat_priv, orig,
                                      BATADV_MCAST_WANT_NO_RTR6);
+       batadv_mcast_have_mc_ptype_update(bat_priv, orig,
+                                         BATADV_MCAST_HAVE_MC_PTYPE_CAPA);
 
        spin_unlock_bh(&orig->mcast_handler_lock);
 }
index d7d021af102981255ba284d396826feb71ae20be..2d7b7324295885e7a5ee70dd63b5dffd9a9a8968 100644 (file)
@@ -1762,6 +1762,10 @@ static void br_ip6_multicast_querier_expired(struct timer_list *t)
 }
 #endif
 
+static void br_multicast_query_delay_expired(struct timer_list *t)
+{
+}
+
 static void br_multicast_select_own_querier(struct net_bridge_mcast *brmctx,
                                            struct br_ip *ip,
                                            struct sk_buff *skb)
@@ -3198,7 +3202,7 @@ br_multicast_update_query_timer(struct net_bridge_mcast *brmctx,
                                unsigned long max_delay)
 {
        if (!timer_pending(&query->timer))
-               query->delay_time = jiffies + max_delay;
+               mod_timer(&query->delay_timer, jiffies + max_delay);
 
        mod_timer(&query->timer, jiffies + brmctx->multicast_querier_interval);
 }
@@ -4041,13 +4045,11 @@ void br_multicast_ctx_init(struct net_bridge *br,
        brmctx->multicast_querier_interval = 255 * HZ;
        brmctx->multicast_membership_interval = 260 * HZ;
 
-       brmctx->ip4_other_query.delay_time = 0;
        brmctx->ip4_querier.port_ifidx = 0;
        seqcount_spinlock_init(&brmctx->ip4_querier.seq, &br->multicast_lock);
        brmctx->multicast_igmp_version = 2;
 #if IS_ENABLED(CONFIG_IPV6)
        brmctx->multicast_mld_version = 1;
-       brmctx->ip6_other_query.delay_time = 0;
        brmctx->ip6_querier.port_ifidx = 0;
        seqcount_spinlock_init(&brmctx->ip6_querier.seq, &br->multicast_lock);
 #endif
@@ -4056,6 +4058,8 @@ void br_multicast_ctx_init(struct net_bridge *br,
                    br_ip4_multicast_local_router_expired, 0);
        timer_setup(&brmctx->ip4_other_query.timer,
                    br_ip4_multicast_querier_expired, 0);
+       timer_setup(&brmctx->ip4_other_query.delay_timer,
+                   br_multicast_query_delay_expired, 0);
        timer_setup(&brmctx->ip4_own_query.timer,
                    br_ip4_multicast_query_expired, 0);
 #if IS_ENABLED(CONFIG_IPV6)
@@ -4063,6 +4067,8 @@ void br_multicast_ctx_init(struct net_bridge *br,
                    br_ip6_multicast_local_router_expired, 0);
        timer_setup(&brmctx->ip6_other_query.timer,
                    br_ip6_multicast_querier_expired, 0);
+       timer_setup(&brmctx->ip6_other_query.delay_timer,
+                   br_multicast_query_delay_expired, 0);
        timer_setup(&brmctx->ip6_own_query.timer,
                    br_ip6_multicast_query_expired, 0);
 #endif
@@ -4197,10 +4203,12 @@ static void __br_multicast_stop(struct net_bridge_mcast *brmctx)
 {
        del_timer_sync(&brmctx->ip4_mc_router_timer);
        del_timer_sync(&brmctx->ip4_other_query.timer);
+       del_timer_sync(&brmctx->ip4_other_query.delay_timer);
        del_timer_sync(&brmctx->ip4_own_query.timer);
 #if IS_ENABLED(CONFIG_IPV6)
        del_timer_sync(&brmctx->ip6_mc_router_timer);
        del_timer_sync(&brmctx->ip6_other_query.timer);
+       del_timer_sync(&brmctx->ip6_other_query.delay_timer);
        del_timer_sync(&brmctx->ip6_own_query.timer);
 #endif
 }
@@ -4643,13 +4651,15 @@ int br_multicast_set_querier(struct net_bridge_mcast *brmctx, unsigned long val)
        max_delay = brmctx->multicast_query_response_interval;
 
        if (!timer_pending(&brmctx->ip4_other_query.timer))
-               brmctx->ip4_other_query.delay_time = jiffies + max_delay;
+               mod_timer(&brmctx->ip4_other_query.delay_timer,
+                         jiffies + max_delay);
 
        br_multicast_start_querier(brmctx, &brmctx->ip4_own_query);
 
 #if IS_ENABLED(CONFIG_IPV6)
        if (!timer_pending(&brmctx->ip6_other_query.timer))
-               brmctx->ip6_other_query.delay_time = jiffies + max_delay;
+               mod_timer(&brmctx->ip6_other_query.delay_timer,
+                         jiffies + max_delay);
 
        br_multicast_start_querier(brmctx, &brmctx->ip6_own_query);
 #endif
index b0a92c344722be6bf195d571bf1a26daf759dfca..86ea5e6689b5ce49a4b71b383893d2ef5b53d110 100644 (file)
@@ -78,7 +78,7 @@ struct bridge_mcast_own_query {
 /* other querier */
 struct bridge_mcast_other_query {
        struct timer_list               timer;
-       unsigned long                   delay_time;
+       struct timer_list               delay_timer;
 };
 
 /* selected querier */
@@ -1159,7 +1159,7 @@ __br_multicast_querier_exists(struct net_bridge_mcast *brmctx,
                own_querier_enabled = false;
        }
 
-       return time_is_before_jiffies(querier->delay_time) &&
+       return !timer_pending(&querier->delay_timer) &&
               (own_querier_enabled || timer_pending(&querier->timer));
 }
 
index 62e54e152ecf1fa601cb2cd755988c9ff97670af..78592912f657c934885077c900ef95b9d79aed4c 100644 (file)
@@ -674,7 +674,7 @@ static int devlink_port_function_validate(struct devlink_port *devlink_port,
                return -EOPNOTSUPP;
        }
        if (tb[DEVLINK_PORT_FN_ATTR_STATE] && !ops->port_fn_state_set) {
-               NL_SET_ERR_MSG_ATTR(extack, tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR],
+               NL_SET_ERR_MSG_ATTR(extack, tb[DEVLINK_PORT_FN_ATTR_STATE],
                                    "Function does not support state setting");
                return -EOPNOTSUPP;
        }
index 7ceb9ac6e7309372a5931f92c9b8adcc390af5f4..9d71b66183daf94e19945d75cfb5c33df6ce346c 100644 (file)
@@ -308,7 +308,7 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
 
        skb = hsr_init_skb(master);
        if (!skb) {
-               WARN_ONCE(1, "HSR: Could not send supervision frame\n");
+               netdev_warn_once(master->dev, "HSR: Could not send supervision frame\n");
                return;
        }
 
@@ -355,7 +355,7 @@ static void send_prp_supervision_frame(struct hsr_port *master,
 
        skb = hsr_init_skb(master);
        if (!skb) {
-               WARN_ONCE(1, "PRP: Could not send supervision frame\n");
+               netdev_warn_once(master->dev, "PRP: Could not send supervision frame\n");
                return;
        }
 
index b06f678b03a19b806fd14764a4caad60caf02919..41537d18eecfd6e1163aacc35e047c22468e04e6 100644 (file)
@@ -1287,6 +1287,12 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork,
        if (unlikely(!rt))
                return -EFAULT;
 
+       cork->fragsize = ip_sk_use_pmtu(sk) ?
+                        dst_mtu(&rt->dst) : READ_ONCE(rt->dst.dev->mtu);
+
+       if (!inetdev_valid_mtu(cork->fragsize))
+               return -ENETUNREACH;
+
        /*
         * setup for corking.
         */
@@ -1303,12 +1309,6 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork,
                cork->addr = ipc->addr;
        }
 
-       cork->fragsize = ip_sk_use_pmtu(sk) ?
-                        dst_mtu(&rt->dst) : READ_ONCE(rt->dst.dev->mtu);
-
-       if (!inetdev_valid_mtu(cork->fragsize))
-               return -ENETUNREACH;
-
        cork->gso_size = ipc->gso_size;
 
        cork->dst = &rt->dst;
index 7aa9dc0e6760df6c9980252854014ab6fdd1c3f7..21d2ffa919e98b41ed325f978ae573b9f25f4d71 100644 (file)
@@ -1363,12 +1363,13 @@ e_inval:
  * ipv4_pktinfo_prepare - transfer some info from rtable to skb
  * @sk: socket
  * @skb: buffer
+ * @drop_dst: if true, drops skb dst
  *
  * To support IP_CMSG_PKTINFO option, we store rt_iif and specific
  * destination in skb->cb[] before dst drop.
  * This way, receiver doesn't make cache line misses to read rtable.
  */
-void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb)
+void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb, bool drop_dst)
 {
        struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb);
        bool prepare = inet_test_bit(PKTINFO, sk) ||
@@ -1397,7 +1398,8 @@ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb)
                pktinfo->ipi_ifindex = 0;
                pktinfo->ipi_spec_dst.s_addr = 0;
        }
-       skb_dst_drop(skb);
+       if (drop_dst)
+               skb_dst_drop(skb);
 }
 
 int ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
index 9d6f59531b3a0b0bc082e1f1febf4568368580b9..3622298365105d99c0277f1c1616fb5fc63cdc2d 100644 (file)
@@ -1073,7 +1073,7 @@ static int ipmr_cache_report(const struct mr_table *mrt,
                msg = (struct igmpmsg *)skb_network_header(skb);
                msg->im_vif = vifi;
                msg->im_vif_hi = vifi >> 8;
-               ipv4_pktinfo_prepare(mroute_sk, pkt);
+               ipv4_pktinfo_prepare(mroute_sk, pkt, false);
                memcpy(skb->cb, pkt->cb, sizeof(skb->cb));
                /* Add our header */
                igmp = skb_put(skb, sizeof(struct igmphdr));
index 27da9d7294c0b4fb9027bb7feb704063dc6302db..aea89326c69793f94bb8489cdf0c93b7524ba3fc 100644 (file)
@@ -292,7 +292,7 @@ static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
        /* Charge it to the socket. */
 
-       ipv4_pktinfo_prepare(sk, skb);
+       ipv4_pktinfo_prepare(sk, skb, true);
        if (sock_queue_rcv_skb_reason(sk, skb, &reason) < 0) {
                kfree_skb_reason(skb, reason);
                return NET_RX_DROP;
index a1c6de385ccef91fe3c3e072ac5d2a20f0394a2b..7e2481b9eae1b791e1ec65f39efa41837a9fcbd3 100644 (file)
@@ -1786,7 +1786,17 @@ static skb_frag_t *skb_advance_to_frag(struct sk_buff *skb, u32 offset_skb,
 
 static bool can_map_frag(const skb_frag_t *frag)
 {
-       return skb_frag_size(frag) == PAGE_SIZE && !skb_frag_off(frag);
+       struct page *page;
+
+       if (skb_frag_size(frag) != PAGE_SIZE || skb_frag_off(frag))
+               return false;
+
+       page = skb_frag_page(frag);
+
+       if (PageCompound(page) || page->mapping)
+               return false;
+
+       return true;
 }
 
 static int find_next_mappable_frag(const skb_frag_t *frag,
index 148ffb007969f57edc4be8ec1c235062ad49b503..f631b0a21af4c7a520212c94ed0580f86d269ed2 100644 (file)
@@ -2169,7 +2169,7 @@ static int udp_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)
 
        udp_csum_pull_header(skb);
 
-       ipv4_pktinfo_prepare(sk, skb);
+       ipv4_pktinfo_prepare(sk, skb, true);
        return __udp_queue_rcv_skb(sk, skb);
 
 csum_error:
index 507a8353a6bdb94cd5e83aad6efd877d84cfdc85..c008d21925d7f4afa31cc55deec0ccc321cdab04 100644 (file)
@@ -220,19 +220,26 @@ const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) {
 EXPORT_SYMBOL_GPL(ipv6_stub);
 
 /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
-const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+const struct in6_addr in6addr_loopback __aligned(BITS_PER_LONG/8)
+       = IN6ADDR_LOOPBACK_INIT;
 EXPORT_SYMBOL(in6addr_loopback);
-const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr in6addr_any __aligned(BITS_PER_LONG/8)
+       = IN6ADDR_ANY_INIT;
 EXPORT_SYMBOL(in6addr_any);
-const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
+const struct in6_addr in6addr_linklocal_allnodes __aligned(BITS_PER_LONG/8)
+       = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
 EXPORT_SYMBOL(in6addr_linklocal_allnodes);
-const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
+const struct in6_addr in6addr_linklocal_allrouters __aligned(BITS_PER_LONG/8)
+       = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
 EXPORT_SYMBOL(in6addr_linklocal_allrouters);
-const struct in6_addr in6addr_interfacelocal_allnodes = IN6ADDR_INTERFACELOCAL_ALLNODES_INIT;
+const struct in6_addr in6addr_interfacelocal_allnodes __aligned(BITS_PER_LONG/8)
+       = IN6ADDR_INTERFACELOCAL_ALLNODES_INIT;
 EXPORT_SYMBOL(in6addr_interfacelocal_allnodes);
-const struct in6_addr in6addr_interfacelocal_allrouters = IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT;
+const struct in6_addr in6addr_interfacelocal_allrouters __aligned(BITS_PER_LONG/8)
+       = IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT;
 EXPORT_SYMBOL(in6addr_interfacelocal_allrouters);
-const struct in6_addr in6addr_sitelocal_allrouters = IN6ADDR_SITELOCAL_ALLROUTERS_INIT;
+const struct in6_addr in6addr_sitelocal_allrouters __aligned(BITS_PER_LONG/8)
+       = IN6ADDR_SITELOCAL_ALLROUTERS_INIT;
 EXPORT_SYMBOL(in6addr_sitelocal_allrouters);
 
 static void snmp6_free_dev(struct inet6_dev *idev)
index 46c19bd4899011d53b4feb84e25013c01ddce701..9bbabf750a21e251d4e8f9e3059c707505f5ce32 100644 (file)
@@ -796,8 +796,8 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
                                                struct sk_buff *skb),
                         bool log_ecn_err)
 {
-       const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
-       int err;
+       const struct ipv6hdr *ipv6h;
+       int nh, err;
 
        if ((!(tpi->flags & TUNNEL_CSUM) &&
             (tunnel->parms.i_flags & TUNNEL_CSUM)) ||
@@ -829,7 +829,6 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
                        goto drop;
                }
 
-               ipv6h = ipv6_hdr(skb);
                skb->protocol = eth_type_trans(skb, tunnel->dev);
                skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
        } else {
@@ -837,7 +836,23 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
                skb_reset_mac_header(skb);
        }
 
+       /* Save offset of outer header relative to skb->head,
+        * because we are going to reset the network header to the inner header
+        * and might change skb->head.
+        */
+       nh = skb_network_header(skb) - skb->head;
+
        skb_reset_network_header(skb);
+
+       if (!pskb_inet_may_pull(skb)) {
+               DEV_STATS_INC(tunnel->dev, rx_length_errors);
+               DEV_STATS_INC(tunnel->dev, rx_errors);
+               goto drop;
+       }
+
+       /* Get the outer header. */
+       ipv6h = (struct ipv6hdr *)(skb->head + nh);
+
        memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
 
        __skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
index 20551cfb7da6d8dd098c906477895e26c080fe32..fde1140d899efc7ba02e6bc3998cb857ef30df14 100644 (file)
@@ -226,6 +226,8 @@ static int llc_ui_release(struct socket *sock)
        }
        netdev_put(llc->dev, &llc->dev_tracker);
        sock_put(sk);
+       sock_orphan(sk);
+       sock->sk = NULL;
        llc_sk_free(sk);
 out:
        return 0;
index 3ed4709a75096025683149b2d4af0a1d5f24141c..028e8b473626f122db6e3e664414b2f0447fae69 100644 (file)
@@ -2314,9 +2314,6 @@ bool __mptcp_retransmit_pending_data(struct sock *sk)
        if (__mptcp_check_fallback(msk))
                return false;
 
-       if (tcp_rtx_and_write_queues_empty(sk))
-               return false;
-
        /* the closing socket has some data untransmitted and/or unacked:
         * some data in the mptcp rtx queue has not really xmitted yet.
         * keep it simple and re-inject the whole mptcp level rtx queue
index 21f7860e8fa1fd4f1f46c9ad278bfeb261090152..cb48a2b9cb9fd708c2f99adadfd4b21671b44a4a 100644 (file)
@@ -30,6 +30,7 @@
 #define mtype_del              IPSET_TOKEN(MTYPE, _del)
 #define mtype_list             IPSET_TOKEN(MTYPE, _list)
 #define mtype_gc               IPSET_TOKEN(MTYPE, _gc)
+#define mtype_cancel_gc                IPSET_TOKEN(MTYPE, _cancel_gc)
 #define mtype                  MTYPE
 
 #define get_ext(set, map, id)  ((map)->extensions + ((set)->dsize * (id)))
@@ -59,9 +60,6 @@ mtype_destroy(struct ip_set *set)
 {
        struct mtype *map = set->data;
 
-       if (SET_WITH_TIMEOUT(set))
-               del_timer_sync(&map->gc);
-
        if (set->dsize && set->extensions & IPSET_EXT_DESTROY)
                mtype_ext_cleanup(set);
        ip_set_free(map->members);
@@ -290,6 +288,15 @@ mtype_gc(struct timer_list *t)
        add_timer(&map->gc);
 }
 
+static void
+mtype_cancel_gc(struct ip_set *set)
+{
+       struct mtype *map = set->data;
+
+       if (SET_WITH_TIMEOUT(set))
+               del_timer_sync(&map->gc);
+}
+
 static const struct ip_set_type_variant mtype = {
        .kadt   = mtype_kadt,
        .uadt   = mtype_uadt,
@@ -303,6 +310,7 @@ static const struct ip_set_type_variant mtype = {
        .head   = mtype_head,
        .list   = mtype_list,
        .same_set = mtype_same_set,
+       .cancel_gc = mtype_cancel_gc,
 };
 
 #endif /* __IP_SET_BITMAP_IP_GEN_H */
index 4c133e06be1de2f8972b50ac87e6b0b7bfc9ac6d..bcaad9c009fe04dea51bbb30c8270b0953862877 100644 (file)
@@ -1182,6 +1182,14 @@ ip_set_destroy_set(struct ip_set *set)
        kfree(set);
 }
 
+static void
+ip_set_destroy_set_rcu(struct rcu_head *head)
+{
+       struct ip_set *set = container_of(head, struct ip_set, rcu);
+
+       ip_set_destroy_set(set);
+}
+
 static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info,
                          const struct nlattr * const attr[])
 {
@@ -1193,8 +1201,6 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info,
        if (unlikely(protocol_min_failed(attr)))
                return -IPSET_ERR_PROTOCOL;
 
-       /* Must wait for flush to be really finished in list:set */
-       rcu_barrier();
 
        /* Commands are serialized and references are
         * protected by the ip_set_ref_lock.
@@ -1206,8 +1212,10 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info,
         * counter, so if it's already zero, we can proceed
         * without holding the lock.
         */
-       read_lock_bh(&ip_set_ref_lock);
        if (!attr[IPSET_ATTR_SETNAME]) {
+               /* Must wait for flush to be really finished in list:set */
+               rcu_barrier();
+               read_lock_bh(&ip_set_ref_lock);
                for (i = 0; i < inst->ip_set_max; i++) {
                        s = ip_set(inst, i);
                        if (s && (s->ref || s->ref_netlink)) {
@@ -1221,6 +1229,8 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info,
                        s = ip_set(inst, i);
                        if (s) {
                                ip_set(inst, i) = NULL;
+                               /* Must cancel garbage collectors */
+                               s->variant->cancel_gc(s);
                                ip_set_destroy_set(s);
                        }
                }
@@ -1228,6 +1238,9 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info,
                inst->is_destroyed = false;
        } else {
                u32 flags = flag_exist(info->nlh);
+               u16 features = 0;
+
+               read_lock_bh(&ip_set_ref_lock);
                s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]),
                                    &i);
                if (!s) {
@@ -1238,10 +1251,16 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info,
                        ret = -IPSET_ERR_BUSY;
                        goto out;
                }
+               features = s->type->features;
                ip_set(inst, i) = NULL;
                read_unlock_bh(&ip_set_ref_lock);
-
-               ip_set_destroy_set(s);
+               if (features & IPSET_TYPE_NAME) {
+                       /* Must wait for flush to be really finished  */
+                       rcu_barrier();
+               }
+               /* Must cancel garbage collectors */
+               s->variant->cancel_gc(s);
+               call_rcu(&s->rcu, ip_set_destroy_set_rcu);
        }
        return 0;
 out:
@@ -1394,9 +1413,6 @@ static int ip_set_swap(struct sk_buff *skb, const struct nfnl_info *info,
        ip_set(inst, to_id) = from;
        write_unlock_bh(&ip_set_ref_lock);
 
-       /* Make sure all readers of the old set pointers are completed. */
-       synchronize_rcu();
-
        return 0;
 }
 
@@ -2409,8 +2425,11 @@ ip_set_fini(void)
 {
        nf_unregister_sockopt(&so_set);
        nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
-
        unregister_pernet_subsys(&ip_set_net_ops);
+
+       /* Wait for call_rcu() in destroy */
+       rcu_barrier();
+
        pr_debug("these are the famous last words\n");
 }
 
index cbf80da9a01caf0616d7d77d5be16521b6c0d47e..1136510521a80b9ac8fdb78edd6f8395a6eb3e76 100644 (file)
@@ -222,6 +222,7 @@ static const union nf_inet_addr zeromask = {};
 #undef mtype_gc_do
 #undef mtype_gc
 #undef mtype_gc_init
+#undef mtype_cancel_gc
 #undef mtype_variant
 #undef mtype_data_match
 
@@ -266,6 +267,7 @@ static const union nf_inet_addr zeromask = {};
 #define mtype_gc_do            IPSET_TOKEN(MTYPE, _gc_do)
 #define mtype_gc               IPSET_TOKEN(MTYPE, _gc)
 #define mtype_gc_init          IPSET_TOKEN(MTYPE, _gc_init)
+#define mtype_cancel_gc                IPSET_TOKEN(MTYPE, _cancel_gc)
 #define mtype_variant          IPSET_TOKEN(MTYPE, _variant)
 #define mtype_data_match       IPSET_TOKEN(MTYPE, _data_match)
 
@@ -450,9 +452,6 @@ mtype_destroy(struct ip_set *set)
        struct htype *h = set->data;
        struct list_head *l, *lt;
 
-       if (SET_WITH_TIMEOUT(set))
-               cancel_delayed_work_sync(&h->gc.dwork);
-
        mtype_ahash_destroy(set, ipset_dereference_nfnl(h->table), true);
        list_for_each_safe(l, lt, &h->ad) {
                list_del(l);
@@ -599,6 +598,15 @@ mtype_gc_init(struct htable_gc *gc)
        queue_delayed_work(system_power_efficient_wq, &gc->dwork, HZ);
 }
 
+static void
+mtype_cancel_gc(struct ip_set *set)
+{
+       struct htype *h = set->data;
+
+       if (SET_WITH_TIMEOUT(set))
+               cancel_delayed_work_sync(&h->gc.dwork);
+}
+
 static int
 mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
          struct ip_set_ext *mext, u32 flags);
@@ -1441,6 +1449,7 @@ static const struct ip_set_type_variant mtype_variant = {
        .uref   = mtype_uref,
        .resize = mtype_resize,
        .same_set = mtype_same_set,
+       .cancel_gc = mtype_cancel_gc,
        .region_lock = true,
 };
 
index e162636525cfb4ad02de58982382a289e5bcbc45..6c3f28bc59b3259f0033cd4adc0ba5711db08c26 100644 (file)
@@ -426,9 +426,6 @@ list_set_destroy(struct ip_set *set)
        struct list_set *map = set->data;
        struct set_elem *e, *n;
 
-       if (SET_WITH_TIMEOUT(set))
-               timer_shutdown_sync(&map->gc);
-
        list_for_each_entry_safe(e, n, &map->members, list) {
                list_del(&e->list);
                ip_set_put_byindex(map->net, e->id);
@@ -545,6 +542,15 @@ list_set_same_set(const struct ip_set *a, const struct ip_set *b)
               a->extensions == b->extensions;
 }
 
+static void
+list_set_cancel_gc(struct ip_set *set)
+{
+       struct list_set *map = set->data;
+
+       if (SET_WITH_TIMEOUT(set))
+               timer_shutdown_sync(&map->gc);
+}
+
 static const struct ip_set_type_variant set_variant = {
        .kadt   = list_set_kadt,
        .uadt   = list_set_uadt,
@@ -558,6 +564,7 @@ static const struct ip_set_type_variant set_variant = {
        .head   = list_set_head,
        .list   = list_set_list,
        .same_set = list_set_same_set,
+       .cancel_gc = list_set_cancel_gc,
 };
 
 static void
index c6bd533983c1ff275796b789cdb973c09f646984..4cc97f971264ed779434ab4597dd0162586b3736 100644 (file)
@@ -283,7 +283,7 @@ sctp_new(struct nf_conn *ct, const struct sk_buff *skb,
                        pr_debug("Setting vtag %x for secondary conntrack\n",
                                 sh->vtag);
                        ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = sh->vtag;
-               } else {
+               } else if (sch->type == SCTP_CID_SHUTDOWN_ACK) {
                /* If it is a shutdown ack OOTB packet, we expect a return
                   shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */
                        pr_debug("Setting vtag %x for new conn OOTB\n",
index e573be5afde7a591e00e799aadeadcf455b31f05..ae493599a3ef03415f6c40e942cdab700acb84c6 100644 (file)
@@ -457,7 +457,8 @@ static void tcp_init_sender(struct ip_ct_tcp_state *sender,
                            const struct sk_buff *skb,
                            unsigned int dataoff,
                            const struct tcphdr *tcph,
-                           u32 end, u32 win)
+                           u32 end, u32 win,
+                           enum ip_conntrack_dir dir)
 {
        /* SYN-ACK in reply to a SYN
         * or SYN from reply direction in simultaneous open.
@@ -471,7 +472,8 @@ static void tcp_init_sender(struct ip_ct_tcp_state *sender,
         * Both sides must send the Window Scale option
         * to enable window scaling in either direction.
         */
-       if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE &&
+       if (dir == IP_CT_DIR_REPLY &&
+           !(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE &&
              receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE)) {
                sender->td_scale = 0;
                receiver->td_scale = 0;
@@ -542,7 +544,7 @@ tcp_in_window(struct nf_conn *ct, enum ip_conntrack_dir dir,
                if (tcph->syn) {
                        tcp_init_sender(sender, receiver,
                                        skb, dataoff, tcph,
-                                       end, win);
+                                       end, win, dir);
                        if (!tcph->ack)
                                /* Simultaneous open */
                                return NFCT_TCP_ACCEPT;
@@ -585,7 +587,7 @@ tcp_in_window(struct nf_conn *ct, enum ip_conntrack_dir dir,
                 */
                tcp_init_sender(sender, receiver,
                                skb, dataoff, tcph,
-                               end, win);
+                               end, win, dir);
 
                if (dir == IP_CT_DIR_REPLY && !tcph->ack)
                        return NFCT_TCP_ACCEPT;
index 8cc52d2bd31be518df778bbe2cfaad6172d90dbc..e16f158388bbe568cddc1be5a0a6d16069897822 100644 (file)
@@ -193,11 +193,12 @@ void nf_logger_put(int pf, enum nf_log_type type)
                return;
        }
 
-       BUG_ON(loggers[pf][type] == NULL);
-
        rcu_read_lock();
        logger = rcu_dereference(loggers[pf][type]);
-       module_put(logger->me);
+       if (!logger)
+               WARN_ON_ONCE(1);
+       else
+               module_put(logger->me);
        rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(nf_logger_put);
index c537104411e7d1b1c1b449b55c7a3c43fb7e2ac3..fc016befb46ffb2562a10897d8837814e7327377 100644 (file)
@@ -7551,11 +7551,15 @@ nla_put_failure:
        return -1;
 }
 
-static const struct nft_object_type *__nft_obj_type_get(u32 objtype)
+static const struct nft_object_type *__nft_obj_type_get(u32 objtype, u8 family)
 {
        const struct nft_object_type *type;
 
        list_for_each_entry(type, &nf_tables_objects, list) {
+               if (type->family != NFPROTO_UNSPEC &&
+                   type->family != family)
+                       continue;
+
                if (objtype == type->type)
                        return type;
        }
@@ -7563,11 +7567,11 @@ static const struct nft_object_type *__nft_obj_type_get(u32 objtype)
 }
 
 static const struct nft_object_type *
-nft_obj_type_get(struct net *net, u32 objtype)
+nft_obj_type_get(struct net *net, u32 objtype, u8 family)
 {
        const struct nft_object_type *type;
 
-       type = __nft_obj_type_get(objtype);
+       type = __nft_obj_type_get(objtype, family);
        if (type != NULL && try_module_get(type->owner))
                return type;
 
@@ -7660,7 +7664,7 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info,
                if (info->nlh->nlmsg_flags & NLM_F_REPLACE)
                        return -EOPNOTSUPP;
 
-               type = __nft_obj_type_get(objtype);
+               type = __nft_obj_type_get(objtype, family);
                if (WARN_ON_ONCE(!type))
                        return -ENOENT;
 
@@ -7674,7 +7678,7 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info,
        if (!nft_use_inc(&table->use))
                return -EMFILE;
 
-       type = nft_obj_type_get(net, objtype);
+       type = nft_obj_type_get(net, objtype, family);
        if (IS_ERR(type)) {
                err = PTR_ERR(type);
                goto err_type;
index 86bb9d7797d9eeaea730e463c389a958e0b6ec85..aac98a3c966e90e76824dfe5dfa362a857128efa 100644 (file)
@@ -1250,7 +1250,31 @@ static int nft_ct_expect_obj_init(const struct nft_ctx *ctx,
        if (tb[NFTA_CT_EXPECT_L3PROTO])
                priv->l3num = ntohs(nla_get_be16(tb[NFTA_CT_EXPECT_L3PROTO]));
 
+       switch (priv->l3num) {
+       case NFPROTO_IPV4:
+       case NFPROTO_IPV6:
+               if (priv->l3num != ctx->family)
+                       return -EINVAL;
+
+               fallthrough;
+       case NFPROTO_INET:
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
        priv->l4proto = nla_get_u8(tb[NFTA_CT_EXPECT_L4PROTO]);
+       switch (priv->l4proto) {
+       case IPPROTO_TCP:
+       case IPPROTO_UDP:
+       case IPPROTO_UDPLITE:
+       case IPPROTO_DCCP:
+       case IPPROTO_SCTP:
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
        priv->dport = nla_get_be16(tb[NFTA_CT_EXPECT_DPORT]);
        priv->timeout = nla_get_u32(tb[NFTA_CT_EXPECT_TIMEOUT]);
        priv->size = nla_get_u8(tb[NFTA_CT_EXPECT_SIZE]);
index 9f21953c7433ff942caba909a8c8673baa3e003c..f735d79d8be5778a008485e893a2be78584318fe 100644 (file)
@@ -713,6 +713,7 @@ static const struct nft_object_ops nft_tunnel_obj_ops = {
 
 static struct nft_object_type nft_tunnel_obj_type __read_mostly = {
        .type           = NFT_OBJECT_TUNNEL,
+       .family         = NFPROTO_NETDEV,
        .ops            = &nft_tunnel_obj_ops,
        .maxattr        = NFTA_TUNNEL_KEY_MAX,
        .policy         = nft_tunnel_key_policy,
index 97348cedb16b30d9a60cb8096a8408f6a8890e6d..cdad47b140fa4bd54ac0571457ab16ab505a3a11 100644 (file)
@@ -1208,6 +1208,10 @@ void nci_free_device(struct nci_dev *ndev)
 {
        nfc_free_device(ndev->nfc_dev);
        nci_hci_deallocate(ndev);
+
+       /* drop partial rx data packet if present */
+       if (ndev->rx_data_reassembly)
+               kfree_skb(ndev->rx_data_reassembly);
        kfree(ndev);
 }
 EXPORT_SYMBOL(nci_free_device);
index 95cc95458e2d8d2c2c3578088544ee1abe0ea8a6..e4c858411207a51d043aef96a47c48ac63f5dd8a 100644 (file)
@@ -1877,9 +1877,15 @@ static bool smcd_lgr_match(struct smc_link_group *lgr,
                           struct smcd_dev *smcismdev,
                           struct smcd_gid *peer_gid)
 {
-       return lgr->peer_gid.gid == peer_gid->gid && lgr->smcd == smcismdev &&
-               smc_ism_is_virtual(smcismdev) ?
-               (lgr->peer_gid.gid_ext == peer_gid->gid_ext) : 1;
+       if (lgr->peer_gid.gid != peer_gid->gid ||
+           lgr->smcd != smcismdev)
+               return false;
+
+       if (smc_ism_is_virtual(smcismdev) &&
+           lgr->peer_gid.gid_ext != peer_gid->gid_ext)
+               return false;
+
+       return true;
 }
 
 /* create a new SMC connection (and a new link group if necessary) */
index f60c93e5a25d69f6c918ab43a9c48a973cbf90b4..b969e505c7b77002e17936c7ee4fa6e6c79ad223 100644 (file)
@@ -1598,10 +1598,10 @@ void svc_process_bc(struct rpc_rqst *req, struct svc_rqst *rqstp)
        /* Finally, send the reply synchronously */
        if (rqstp->bc_to_initval > 0) {
                timeout.to_initval = rqstp->bc_to_initval;
-               timeout.to_retries = rqstp->bc_to_initval;
+               timeout.to_retries = rqstp->bc_to_retries;
        } else {
                timeout.to_initval = req->rq_xprt->timeout->to_initval;
-               timeout.to_initval = req->rq_xprt->timeout->to_retries;
+               timeout.to_retries = req->rq_xprt->timeout->to_retries;
        }
        memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf));
        task = rpc_run_bc_task(req, &timeout);
index ac1f2bc18fc9685652c26ac3b68f19bfd82f8332..30b178ebba60aa810e8442a326a14edcee071061 100644 (file)
@@ -1344,13 +1344,11 @@ static void unix_state_double_lock(struct sock *sk1, struct sock *sk2)
                unix_state_lock(sk1);
                return;
        }
-       if (sk1 < sk2) {
-               unix_state_lock(sk1);
-               unix_state_lock_nested(sk2);
-       } else {
-               unix_state_lock(sk2);
-               unix_state_lock_nested(sk1);
-       }
+       if (sk1 > sk2)
+               swap(sk1, sk2);
+
+       unix_state_lock(sk1);
+       unix_state_lock_nested(sk2, U_LOCK_SECOND);
 }
 
 static void unix_state_double_unlock(struct sock *sk1, struct sock *sk2)
@@ -1591,7 +1589,7 @@ restart:
                goto out_unlock;
        }
 
-       unix_state_lock_nested(sk);
+       unix_state_lock_nested(sk, U_LOCK_SECOND);
 
        if (sk->sk_state != st) {
                unix_state_unlock(sk);
index bec09a3a1d44ce56d43e16583fdf3b417cce4033..be19827eca36dbb68ec97b2e9b3c80e22b4fa4be 100644 (file)
@@ -84,7 +84,7 @@ static int sk_diag_dump_icons(struct sock *sk, struct sk_buff *nlskb)
                         * queue lock. With the other's queue locked it's
                         * OK to lock the state.
                         */
-                       unix_state_lock_nested(req);
+                       unix_state_lock_nested(req, U_LOCK_DIAG);
                        peer = unix_sk(req)->peer;
                        buf[i++] = (peer ? sock_i_ino(peer) : 0);
                        unix_state_unlock(req);
index ab271b2051a2459cc83d05111ba1be0558cdc954..226ea3df3b4b4caf70a8b7cc1c7ead71def9af7c 100644 (file)
@@ -9,8 +9,8 @@
 # Input config fragments without '.config' suffix
 define merge_into_defconfig
        $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh \
-               -m -O $(objtree) $(srctree)/arch/$(ARCH)/configs/$(1) \
-               $(foreach config,$(2),$(srctree)/arch/$(ARCH)/configs/$(config).config)
+               -m -O $(objtree) $(srctree)/arch/$(SRCARCH)/configs/$(1) \
+               $(foreach config,$(2),$(srctree)/arch/$(SRCARCH)/configs/$(config).config)
        +$(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig
 endef
 
@@ -23,7 +23,7 @@ endef
 # Input config fragments without '.config' suffix
 define merge_into_defconfig_override
        $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh \
-               -Q -m -O $(objtree) $(srctree)/arch/$(ARCH)/configs/$(1) \
-               $(foreach config,$(2),$(srctree)/arch/$(ARCH)/configs/$(config).config)
+               -Q -m -O $(objtree) $(srctree)/arch/$(SRCARCH)/configs/$(1) \
+               $(foreach config,$(2),$(srctree)/arch/$(SRCARCH)/configs/$(config).config)
        +$(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig
 endef
index 3e808528aaeab2625424b56247eed97fa107232d..e9e9fb8d86746460c893a51a2989ca4061fc8e52 100644 (file)
@@ -345,6 +345,8 @@ void sym_calc_value(struct symbol *sym)
 
        oldval = sym->curr;
 
+       newval.tri = no;
+
        switch (sym->type) {
        case S_INT:
                newval.val = "0";
@@ -357,7 +359,7 @@ void sym_calc_value(struct symbol *sym)
                break;
        case S_BOOLEAN:
        case S_TRISTATE:
-               newval = symbol_no.curr;
+               newval.val = "n";
                break;
        default:
                sym->curr.val = sym->name;
index 795b21154446df9d6cd37920e4b5183e0cbddeef..267b9a0a3abcd849fe4f0bae4cddd8a287d26184 100644 (file)
@@ -70,9 +70,7 @@ void modpost_log(enum loglevel loglevel, const char *fmt, ...)
                break;
        case LOG_ERROR:
                fprintf(stderr, "ERROR: ");
-               break;
-       case LOG_FATAL:
-               fprintf(stderr, "FATAL: ");
+               error_occurred = true;
                break;
        default: /* invalid loglevel, ignore */
                break;
@@ -83,16 +81,8 @@ void modpost_log(enum loglevel loglevel, const char *fmt, ...)
        va_start(arglist, fmt);
        vfprintf(stderr, fmt, arglist);
        va_end(arglist);
-
-       if (loglevel == LOG_FATAL)
-               exit(1);
-       if (loglevel == LOG_ERROR)
-               error_occurred = true;
 }
 
-void __attribute__((alias("modpost_log")))
-modpost_log_noret(enum loglevel loglevel, const char *fmt, ...);
-
 static inline bool strends(const char *str, const char *postfix)
 {
        if (strlen(str) < strlen(postfix))
@@ -806,7 +796,8 @@ static void check_section(const char *modname, struct elf_info *elf,
 
 #define DATA_SECTIONS ".data", ".data.rel"
 #define TEXT_SECTIONS ".text", ".text.*", ".sched.text", \
-               ".kprobes.text", ".cpuidle.text", ".noinstr.text"
+               ".kprobes.text", ".cpuidle.text", ".noinstr.text", \
+               ".ltext", ".ltext.*"
 #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
                ".fixup", ".entry.text", ".exception.text", \
                ".coldtext", ".softirqentry.text"
index 835cababf1b09eb2353f8777f934dfabf3731454..ee43c795063682b440818cd3a81ba5355afba456 100644 (file)
@@ -194,15 +194,11 @@ void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym);
 enum loglevel {
        LOG_WARN,
        LOG_ERROR,
-       LOG_FATAL
 };
 
 void __attribute__((format(printf, 2, 3)))
 modpost_log(enum loglevel loglevel, const char *fmt, ...);
 
-void __attribute__((format(printf, 2, 3), noreturn))
-modpost_log_noret(enum loglevel loglevel, const char *fmt, ...);
-
 /*
  * warn - show the given message, then let modpost continue running, still
  *        allowing modpost to exit successfully. This should be used when
@@ -218,4 +214,4 @@ modpost_log_noret(enum loglevel loglevel, const char *fmt, ...);
  */
 #define warn(fmt, args...)     modpost_log(LOG_WARN, fmt, ##args)
 #define error(fmt, args...)    modpost_log(LOG_ERROR, fmt, ##args)
-#define fatal(fmt, args...)    modpost_log_noret(LOG_FATAL, fmt, ##args)
+#define fatal(fmt, args...)    do { error(fmt, ##args); exit(1); } while (1)
index 89298983a16941a20ccbd72330af1e168652c3f4..f58726671fb37424308c678126e5edd4a22dc5f3 100644 (file)
@@ -55,12 +55,12 @@ patch -p1 < %{SOURCE2}
 %{make} %{makeflags} KERNELRELEASE=%{KERNELRELEASE} KBUILD_BUILD_VERSION=%{release}
 
 %install
-mkdir -p %{buildroot}/boot
-cp $(%{make} %{makeflags} -s image_name) %{buildroot}/boot/vmlinuz-%{KERNELRELEASE}
+mkdir -p %{buildroot}/lib/modules/%{KERNELRELEASE}
+cp $(%{make} %{makeflags} -s image_name) %{buildroot}/lib/modules/%{KERNELRELEASE}/vmlinuz
 %{make} %{makeflags} INSTALL_MOD_PATH=%{buildroot} modules_install
 %{make} %{makeflags} INSTALL_HDR_PATH=%{buildroot}/usr headers_install
-cp System.map %{buildroot}/boot/System.map-%{KERNELRELEASE}
-cp .config %{buildroot}/boot/config-%{KERNELRELEASE}
+cp System.map %{buildroot}/lib/modules/%{KERNELRELEASE}
+cp .config %{buildroot}/lib/modules/%{KERNELRELEASE}/config
 ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEASE}/build
 %if %{with_devel}
 %{make} %{makeflags} run-command KBUILD_RUN_COMMAND='${srctree}/scripts/package/install-extmod-build %{buildroot}/usr/src/kernels/%{KERNELRELEASE}'
@@ -70,13 +70,14 @@ ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEA
 rm -rf %{buildroot}
 
 %post
-if [ -x /sbin/installkernel -a -r /boot/vmlinuz-%{KERNELRELEASE} -a -r /boot/System.map-%{KERNELRELEASE} ]; then
-cp /boot/vmlinuz-%{KERNELRELEASE} /boot/.vmlinuz-%{KERNELRELEASE}-rpm
-cp /boot/System.map-%{KERNELRELEASE} /boot/.System.map-%{KERNELRELEASE}-rpm
-rm -f /boot/vmlinuz-%{KERNELRELEASE} /boot/System.map-%{KERNELRELEASE}
-/sbin/installkernel %{KERNELRELEASE} /boot/.vmlinuz-%{KERNELRELEASE}-rpm /boot/.System.map-%{KERNELRELEASE}-rpm
-rm -f /boot/.vmlinuz-%{KERNELRELEASE}-rpm /boot/.System.map-%{KERNELRELEASE}-rpm
+if [ -x /usr/bin/kernel-install ]; then
+       /usr/bin/kernel-install add %{KERNELRELEASE} /lib/modules/%{KERNELRELEASE}/vmlinuz
 fi
+for file in vmlinuz System.map config; do
+       if ! cmp --silent "/lib/modules/%{KERNELRELEASE}/${file}" "/boot/${file}-%{KERNELRELEASE}"; then
+               cp "/lib/modules/%{KERNELRELEASE}/${file}" "/boot/${file}-%{KERNELRELEASE}"
+       fi
+done
 
 %preun
 if [ -x /sbin/new-kernel-pkg ]; then
@@ -94,7 +95,6 @@ fi
 %defattr (-, root, root)
 /lib/modules/%{KERNELRELEASE}
 %exclude /lib/modules/%{KERNELRELEASE}/build
-/boot/*
 
 %files headers
 %defattr (-, root, root)
index 0144a98d3712e66733462a37a47518beb2eab743..3aaad75c9ce8531b6f214ad8bd469d1c571908c7 100644 (file)
@@ -4255,7 +4255,19 @@ EXPORT_SYMBOL(security_inode_setsecctx);
  */
 int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
 {
-       return call_int_hook(inode_getsecctx, -EOPNOTSUPP, inode, ctx, ctxlen);
+       struct security_hook_list *hp;
+       int rc;
+
+       /*
+        * Only one module will provide a security context.
+        */
+       hlist_for_each_entry(hp, &security_hook_heads.inode_getsecctx, list) {
+               rc = hp->hook.inode_getsecctx(inode, ctx, ctxlen);
+               if (rc != LSM_RET_DEFAULT(inode_getsecctx))
+                       return rc;
+       }
+
+       return LSM_RET_DEFAULT(inode_getsecctx);
 }
 EXPORT_SYMBOL(security_inode_getsecctx);
 
@@ -4612,8 +4624,20 @@ EXPORT_SYMBOL(security_sock_rcv_skb);
 int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval,
                                      sockptr_t optlen, unsigned int len)
 {
-       return call_int_hook(socket_getpeersec_stream, -ENOPROTOOPT, sock,
-                            optval, optlen, len);
+       struct security_hook_list *hp;
+       int rc;
+
+       /*
+        * Only one module will provide a security context.
+        */
+       hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_stream,
+                            list) {
+               rc = hp->hook.socket_getpeersec_stream(sock, optval, optlen,
+                                                      len);
+               if (rc != LSM_RET_DEFAULT(socket_getpeersec_stream))
+                       return rc;
+       }
+       return LSM_RET_DEFAULT(socket_getpeersec_stream);
 }
 
 /**
@@ -4633,8 +4657,19 @@ int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval,
 int security_socket_getpeersec_dgram(struct socket *sock,
                                     struct sk_buff *skb, u32 *secid)
 {
-       return call_int_hook(socket_getpeersec_dgram, -ENOPROTOOPT, sock,
-                            skb, secid);
+       struct security_hook_list *hp;
+       int rc;
+
+       /*
+        * Only one module will provide a security context.
+        */
+       hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_dgram,
+                            list) {
+               rc = hp->hook.socket_getpeersec_dgram(sock, skb, secid);
+               if (rc != LSM_RET_DEFAULT(socket_getpeersec_dgram))
+                       return rc;
+       }
+       return LSM_RET_DEFAULT(socket_getpeersec_dgram);
 }
 EXPORT_SYMBOL(security_socket_getpeersec_dgram);
 
index a09f0154e6a7029c72fb3f0d6d8bd36f202b72c8..d0788126cbab10a2ef8daaab9201f366f27d8c63 100644 (file)
@@ -211,6 +211,10 @@ static const char * const snd_pcm_format_names[] = {
        FORMAT(DSD_U32_LE),
        FORMAT(DSD_U16_BE),
        FORMAT(DSD_U32_BE),
+       FORMAT(S20_LE),
+       FORMAT(S20_BE),
+       FORMAT(U20_LE),
+       FORMAT(U20_BE),
 };
 
 /**
index 35277ce890a46fb9204cc80a55e812cb64c842d5..d74cf11eef1ea6fcb1bae71b9c00aad87203de40 100644 (file)
@@ -76,6 +76,8 @@ static const struct cs35l41_config cs35l41_config_table[] = {
        { "10431533", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
        { "10431573", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
        { "10431663", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },
+       { "10431683", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+       { "104316A3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
        { "104316D3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
        { "104316F3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
        { "104317F3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
@@ -410,6 +412,8 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
        { "CSC3551", "10431533", generic_dsd_config },
        { "CSC3551", "10431573", generic_dsd_config },
        { "CSC3551", "10431663", generic_dsd_config },
+       { "CSC3551", "10431683", generic_dsd_config },
+       { "CSC3551", "104316A3", generic_dsd_config },
        { "CSC3551", "104316D3", generic_dsd_config },
        { "CSC3551", "104316F3", generic_dsd_config },
        { "CSC3551", "104317F3", generic_dsd_config },
index b61e1de8c4bf905a6bddd8bc859da2dc9b8cd408..75a14ba54fcd1c270459b47be66ecb6aa799aa33 100644 (file)
   *  ASP1_RX_WL = 24 bits per sample
   *  ASP1_TX_WL = 24 bits per sample
   *  ASP1_RXn_EN 1..3 and ASP1_TXn_EN 1..4 disabled
+  *
+  * Override any Windows-specific mixer settings applied by the firmware.
   */
 static const struct reg_sequence cs35l56_hda_dai_config[] = {
        { CS35L56_ASP1_CONTROL1,        0x00000021 },
        { CS35L56_ASP1_CONTROL2,        0x20200200 },
        { CS35L56_ASP1_CONTROL3,        0x00000003 },
+       { CS35L56_ASP1_FRAME_CONTROL1,  0x03020100 },
+       { CS35L56_ASP1_FRAME_CONTROL5,  0x00020100 },
        { CS35L56_ASP1_DATA_CONTROL5,   0x00000018 },
        { CS35L56_ASP1_DATA_CONTROL1,   0x00000018 },
        { CS35L56_ASP1_ENABLES1,        0x00000000 },
+       { CS35L56_ASP1TX1_INPUT,        0x00000018 },
+       { CS35L56_ASP1TX2_INPUT,        0x00000019 },
+       { CS35L56_ASP1TX3_INPUT,        0x00000020 },
+       { CS35L56_ASP1TX4_INPUT,        0x00000028 },
+
 };
 
 static void cs35l56_hda_play(struct cs35l56_hda *cs35l56)
@@ -133,6 +142,10 @@ static int cs35l56_hda_runtime_resume(struct device *dev)
                }
        }
 
+       ret = cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base);
+       if (ret)
+               goto err;
+
        return 0;
 
 err:
@@ -384,7 +397,7 @@ static const struct cs_dsp_client_ops cs35l56_hda_client_ops = {
 
 static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56,
                                             const struct firmware **firmware, char **filename,
-                                            const char *dir, const char *system_name,
+                                            const char *base_name, const char *system_name,
                                             const char *amp_name,
                                             const char *filetype)
 {
@@ -392,17 +405,13 @@ static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56,
        int ret = 0;
 
        if (system_name && amp_name)
-               *filename = kasprintf(GFP_KERNEL, "%scs35l56%s-%02x-dsp1-misc-%s-%s.%s", dir,
-                                     cs35l56->base.secured ? "s" : "", cs35l56->base.rev,
+               *filename = kasprintf(GFP_KERNEL, "%s-%s-%s.%s", base_name,
                                      system_name, amp_name, filetype);
        else if (system_name)
-               *filename = kasprintf(GFP_KERNEL, "%scs35l56%s-%02x-dsp1-misc-%s.%s", dir,
-                                     cs35l56->base.secured ? "s" : "", cs35l56->base.rev,
+               *filename = kasprintf(GFP_KERNEL, "%s-%s.%s", base_name,
                                      system_name, filetype);
        else
-               *filename = kasprintf(GFP_KERNEL, "%scs35l56%s-%02x-dsp1-misc.%s", dir,
-                                     cs35l56->base.secured ? "s" : "", cs35l56->base.rev,
-                                     filetype);
+               *filename = kasprintf(GFP_KERNEL, "%s.%s", base_name, filetype);
 
        if (!*filename)
                return -ENOMEM;
@@ -435,8 +444,8 @@ static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56,
        return 0;
 }
 
-static const char cirrus_dir[] = "cirrus/";
 static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56,
+                                              unsigned int preloaded_fw_ver,
                                               const struct firmware **wmfw_firmware,
                                               char **wmfw_filename,
                                               const struct firmware **coeff_firmware,
@@ -444,55 +453,73 @@ static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56,
 {
        const char *system_name = cs35l56->system_name;
        const char *amp_name = cs35l56->amp_name;
+       char base_name[37];
        int ret;
 
+       if (preloaded_fw_ver) {
+               snprintf(base_name, sizeof(base_name),
+                        "cirrus/cs35l56-%02x%s-%06x-dsp1-misc",
+                        cs35l56->base.rev,
+                        cs35l56->base.secured ? "-s" : "",
+                        preloaded_fw_ver & 0xffffff);
+       } else {
+               snprintf(base_name, sizeof(base_name),
+                        "cirrus/cs35l56-%02x%s-dsp1-misc",
+                        cs35l56->base.rev,
+                        cs35l56->base.secured ? "-s" : "");
+       }
+
        if (system_name && amp_name) {
                if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
-                                                      cirrus_dir, system_name, amp_name, "wmfw")) {
+                                                      base_name, system_name, amp_name, "wmfw")) {
                        cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
-                                                         cirrus_dir, system_name, amp_name, "bin");
+                                                         base_name, system_name, amp_name, "bin");
                        return;
                }
        }
 
        if (system_name) {
                if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
-                                                      cirrus_dir, system_name, NULL, "wmfw")) {
+                                                      base_name, system_name, NULL, "wmfw")) {
                        if (amp_name)
                                cs35l56_hda_request_firmware_file(cs35l56,
                                                                  coeff_firmware, coeff_filename,
-                                                                 cirrus_dir, system_name,
+                                                                 base_name, system_name,
                                                                  amp_name, "bin");
                        if (!*coeff_firmware)
                                cs35l56_hda_request_firmware_file(cs35l56,
                                                                  coeff_firmware, coeff_filename,
-                                                                 cirrus_dir, system_name,
+                                                                 base_name, system_name,
                                                                  NULL, "bin");
                        return;
                }
+
+               /*
+                * Check for system-specific bin files without wmfw before
+                * falling back to generic firmware
+                */
+               if (amp_name)
+                       cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+                                                         base_name, system_name, amp_name, "bin");
+               if (!*coeff_firmware)
+                       cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+                                                         base_name, system_name, NULL, "bin");
+
+               if (*coeff_firmware)
+                       return;
        }
 
        ret = cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
-                                               cirrus_dir, NULL, NULL, "wmfw");
+                                               base_name, NULL, NULL, "wmfw");
        if (!ret) {
                cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
-                                                 cirrus_dir, NULL, NULL, "bin");
+                                                 base_name, NULL, NULL, "bin");
                return;
        }
 
-       /* When a firmware file is not found must still search for the coeff files */
-       if (system_name) {
-               if (amp_name)
-                       cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
-                                                         cirrus_dir, system_name, amp_name, "bin");
-               if (!*coeff_firmware)
-                       cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
-                                                         cirrus_dir, system_name, NULL, "bin");
-       }
-
        if (!*coeff_firmware)
                cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
-                                                 cirrus_dir, NULL, NULL, "bin");
+                                                 base_name, NULL, NULL, "bin");
 }
 
 static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmware,
@@ -526,7 +553,8 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
        const struct firmware *wmfw_firmware = NULL;
        char *coeff_filename = NULL;
        char *wmfw_filename = NULL;
-       unsigned int firmware_missing;
+       unsigned int preloaded_fw_ver;
+       bool firmware_missing;
        int ret = 0;
 
        /* Prepare for a new DSP power-up */
@@ -537,24 +565,21 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
 
        pm_runtime_get_sync(cs35l56->base.dev);
 
-       ret = regmap_read(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, &firmware_missing);
-       if (ret) {
-               dev_err(cs35l56->base.dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
+       /*
+        * The firmware can only be upgraded if it is currently running
+        * from the built-in ROM. If not, the wmfw/bin must be for the
+        * version of firmware that is running on the chip.
+        */
+       ret = cs35l56_read_prot_status(&cs35l56->base, &firmware_missing, &preloaded_fw_ver);
+       if (ret)
                goto err_pm_put;
-       }
 
-       firmware_missing &= CS35L56_FIRMWARE_MISSING;
+       if (firmware_missing)
+               preloaded_fw_ver = 0;
 
-       /*
-        * Firmware can only be downloaded if the CS35L56 is secured or is
-        * running from the built-in ROM. If it is secured the BIOS will have
-        * downloaded firmware, and the wmfw/bin files will only contain
-        * tunings that are safe to download with the firmware running.
-        */
-       if (cs35l56->base.secured || firmware_missing) {
-               cs35l56_hda_request_firmware_files(cs35l56, &wmfw_firmware, &wmfw_filename,
-                                                  &coeff_firmware, &coeff_filename);
-       }
+       cs35l56_hda_request_firmware_files(cs35l56, preloaded_fw_ver,
+                                          &wmfw_firmware, &wmfw_filename,
+                                          &coeff_firmware, &coeff_filename);
 
        /*
         * If the BIOS didn't patch the firmware a bin file is mandatory to
@@ -569,12 +594,12 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
        mutex_lock(&cs35l56->base.irq_lock);
 
        /*
-        * When the device is running in secure mode the firmware files can
-        * only contain insecure tunings and therefore we do not need to
-        * shutdown the firmware to apply them and can use the lower cost
-        * reinit sequence instead.
+        * If the firmware hasn't been patched it must be shutdown before
+        * doing a full patch and reset afterwards. If it is already
+        * running a patched version the firmware files only contain
+        * tunings and we can use the lower cost reinit sequence instead.
         */
-       if (!cs35l56->base.secured && (wmfw_firmware || coeff_firmware)) {
+       if (firmware_missing && (wmfw_firmware || coeff_firmware)) {
                ret = cs35l56_firmware_shutdown(&cs35l56->base);
                if (ret)
                        goto err;
@@ -593,7 +618,7 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
        if (coeff_filename)
                dev_dbg(cs35l56->base.dev, "Loaded Coefficients: %s\n", coeff_filename);
 
-       if (cs35l56->base.secured) {
+       if (!firmware_missing) {
                ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
                if (ret)
                        goto err_powered_up;
@@ -976,6 +1001,9 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id)
 
        regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config,
                               ARRAY_SIZE(cs35l56_hda_dai_config));
+       ret = cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base);
+       if (ret)
+               goto err;
 
        /*
         * By default only enable one ASP1TXn, where n=amplifier index,
@@ -1035,16 +1063,6 @@ const struct dev_pm_ops cs35l56_hda_pm_ops = {
 };
 EXPORT_SYMBOL_NS_GPL(cs35l56_hda_pm_ops, SND_HDA_SCODEC_CS35L56);
 
-#if IS_ENABLED(CONFIG_SND_HDA_SCODEC_CS35L56_KUNIT_TEST)
-/* Hooks to export static function to KUnit test */
-
-int cs35l56_hda_test_hook_get_speaker_id(struct device *dev, int amp_index, int num_amps)
-{
-       return cs35l56_hda_get_speaker_id(dev, amp_index, num_amps);
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_hda_test_hook_get_speaker_id, SND_HDA_SCODEC_CS35L56);
-#endif
-
 MODULE_DESCRIPTION("CS35L56 HDA Driver");
 MODULE_IMPORT_NS(SND_HDA_CIRRUS_SCODEC);
 MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS);
index 2276adc8447840a232eb493e5bac54af0cb35682..1b550c42db092739135e5917a74914894e254454 100644 (file)
@@ -1729,9 +1729,11 @@ static int default_bdl_pos_adj(struct azx *chip)
        /* some exceptions: Atoms seem problematic with value 1 */
        if (chip->pci->vendor == PCI_VENDOR_ID_INTEL) {
                switch (chip->pci->device) {
-               case 0x0f04: /* Baytrail */
-               case 0x2284: /* Braswell */
+               case PCI_DEVICE_ID_INTEL_HDA_BYT:
+               case PCI_DEVICE_ID_INTEL_HDA_BSW:
                        return 32;
+               case PCI_DEVICE_ID_INTEL_HDA_APL:
+                       return 64;
                }
        }
 
index 627899959ffe8c34c76211d51824e1d1e93d33a8..e41316e2e98338a5d69245ed9e9db1b979a2fdf2 100644 (file)
@@ -1371,6 +1371,7 @@ void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int ac
                spec->scodecs[CS8409_CODEC1] = &dolphin_cs42l42_1;
                spec->scodecs[CS8409_CODEC1]->codec = codec;
                spec->num_scodecs = 2;
+               spec->gen.suppress_vmaster = 1;
 
                codec->patch_ops = cs8409_dolphin_patch_ops;
 
index f6f16622f9cc78a1ac8ca0de8b82e915f580f7fd..6994c4c5073cbb6fd5ad932186db35970c7cbd0f 100644 (file)
@@ -439,6 +439,10 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
                alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
                fallthrough;
        case 0x10ec0215:
+       case 0x10ec0285:
+       case 0x10ec0289:
+               alc_update_coef_idx(codec, 0x36, 1<<13, 0);
+               fallthrough;
        case 0x10ec0230:
        case 0x10ec0233:
        case 0x10ec0235:
@@ -452,9 +456,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
        case 0x10ec0283:
        case 0x10ec0286:
        case 0x10ec0288:
-       case 0x10ec0285:
        case 0x10ec0298:
-       case 0x10ec0289:
        case 0x10ec0300:
                alc_update_coef_idx(codec, 0x10, 1<<9, 0);
                break;
@@ -9577,7 +9579,7 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = cs35l41_fixup_i2c_two,
                .chained = true,
-               .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
+               .chain_id = ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK,
        },
        [ALC287_FIXUP_TAS2781_I2C] = {
                .type = HDA_FIXUP_FUNC,
@@ -9604,6 +9606,8 @@ static const struct hda_fixup alc269_fixups[] = {
        [ALC287_FIXUP_THINKPAD_I2S_SPK] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc287_fixup_bind_dacs,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK,
        },
        [ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD] = {
                .type = HDA_FIXUP_FUNC,
@@ -9653,6 +9657,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x1247, "Acer vCopperbox", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS),
        SND_PCI_QUIRK(0x1025, 0x1248, "Acer Veriton N4660G", ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1025, 0x1269, "Acer SWIFT SF314-54", ALC256_FIXUP_ACER_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x126a, "Acer Swift SF114-32", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1025, 0x128f, "Acer Veriton Z6860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
        SND_PCI_QUIRK(0x1025, 0x1290, "Acer Veriton Z4860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
        SND_PCI_QUIRK(0x1025, 0x1291, "Acer Veriton Z4660G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
@@ -9732,6 +9737,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
        SND_PCI_QUIRK(0x1028, 0x0beb, "Dell XPS 15 9530 (2023)", ALC289_FIXUP_DELL_CS35L41_SPI_2),
        SND_PCI_QUIRK(0x1028, 0x0c03, "Dell Precision 5340", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0c0d, "Dell Oasis", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
        SND_PCI_QUIRK(0x1028, 0x0c19, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
        SND_PCI_QUIRK(0x1028, 0x0c1a, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
        SND_PCI_QUIRK(0x1028, 0x0c1b, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS),
@@ -9852,6 +9858,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8786, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED),
        SND_PCI_QUIRK(0x103c, 0x8787, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED),
        SND_PCI_QUIRK(0x103c, 0x8788, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x87b7, "HP Laptop 14-fq0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
        SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x87e7, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
@@ -9957,6 +9964,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8c72, "HP EliteBook 865 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8c96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8c97, "HP ZBook", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8ca1, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ca2, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
@@ -10322,6 +10331,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC),
        SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
        SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO),
+       SND_PCI_QUIRK(0x2782, 0x1707, "Vaio VJFE-ADL", ALC298_FIXUP_SPK_VOLUME),
        SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC),
        SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED),
        SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10),
index c90ec3419247797a0628bfa5207eaf3afcb8d012..504d1b8c4cbb4f104a8b8e70adf10894f211ce6c 100644 (file)
@@ -505,6 +505,13 @@ static int acp_card_rt5682s_hw_params(struct snd_pcm_substream *substream,
 
        clk_set_rate(drvdata->wclk, srate);
        clk_set_rate(drvdata->bclk, srate * ch * format);
+       if (!drvdata->soc_mclk) {
+               ret = acp_clk_enable(drvdata, srate, ch * format);
+               if (ret < 0) {
+                       dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
+                       return ret;
+               }
+       }
 
        return 0;
 }
@@ -1464,8 +1471,13 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
        if (drv_data->amp_cpu_id == I2S_SP) {
                links[i].name = "acp-amp-codec";
                links[i].id = AMP_BE_ID;
-               links[i].cpus = sof_sp_virtual;
-               links[i].num_cpus = ARRAY_SIZE(sof_sp_virtual);
+               if (drv_data->platform == RENOIR) {
+                       links[i].cpus = sof_sp;
+                       links[i].num_cpus = ARRAY_SIZE(sof_sp);
+               } else {
+                       links[i].cpus = sof_sp_virtual;
+                       links[i].num_cpus = ARRAY_SIZE(sof_sp_virtual);
+               }
                links[i].platforms = sof_component;
                links[i].num_platforms = ARRAY_SIZE(sof_component);
                links[i].dpcm_playback = 1;
index 2a9fd3275e42f5fa1086d10baf4a8cc4cc2b69b1..20b94814a0462147258fe94cd4219b772afa45f0 100644 (file)
@@ -48,6 +48,7 @@ static struct acp_card_drvdata sof_rt5682s_rt1019_data = {
        .hs_codec_id = RT5682S,
        .amp_codec_id = RT1019,
        .dmic_codec_id = DMIC,
+       .platform = RENOIR,
        .tdm_mode = false,
 };
 
@@ -58,6 +59,7 @@ static struct acp_card_drvdata sof_rt5682s_max_data = {
        .hs_codec_id = RT5682S,
        .amp_codec_id = MAX98360A,
        .dmic_codec_id = DMIC,
+       .platform = RENOIR,
        .tdm_mode = false,
 };
 
@@ -68,6 +70,7 @@ static struct acp_card_drvdata sof_nau8825_data = {
        .hs_codec_id = NAU8825,
        .amp_codec_id = MAX98360A,
        .dmic_codec_id = DMIC,
+       .platform = REMBRANDT,
        .soc_mclk = true,
        .tdm_mode = false,
 };
@@ -79,6 +82,7 @@ static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = {
        .hs_codec_id = RT5682S,
        .amp_codec_id = RT1019,
        .dmic_codec_id = DMIC,
+       .platform = REMBRANDT,
        .soc_mclk = true,
        .tdm_mode = false,
 };
index f85b85ea4be9c28cf6ba1f29b4c7290908bc842d..2b0aa270a3e9d75c8ebd47aaf12e6fc0b73c75b3 100644 (file)
@@ -354,6 +354,14 @@ static const struct dmi_system_id acp3x_es83xx_dmi_table[] = {
                },
                .driver_data = (void *)(ES83XX_ENABLE_DMIC|ES83XX_48_MHZ_MCLK),
        },
+       {
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+               },
+               .driver_data = (void *)(ES83XX_ENABLE_DMIC),
+       },
        {
                .matches = {
                        DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
index d83cb6e4c62aecc6e54a700e5d22f136253e42fb..23d44a50d8157212aa5bbaa49ecd1e9acbe9aa00 100644 (file)
@@ -297,6 +297,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 B7ED"),
                }
        },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 C7VF"),
+               }
+       },
        {
                .driver_data = &acp6x_card,
                .matches = {
index 953ba066bab1e30dfc22ea94bead73ce2f91c0fe..02fba4bc0a14f4cc44690ffed69bd5217409b6e9 100644 (file)
@@ -5,6 +5,7 @@
 // Copyright (C) 2023 Cirrus Logic, Inc. and
 //                    Cirrus Logic International Semiconductor Ltd.
 
+#include <linux/gpio/consumer.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/types.h>
 #include "cs35l56.h"
 
 static const struct reg_sequence cs35l56_patch[] = {
+       /*
+        * Firmware can change these to non-defaults to satisfy SDCA.
+        * Ensure that they are at known defaults.
+        */
+       { CS35L56_SWIRE_DP3_CH1_INPUT,          0x00000018 },
+       { CS35L56_SWIRE_DP3_CH2_INPUT,          0x00000019 },
+       { CS35L56_SWIRE_DP3_CH3_INPUT,          0x00000029 },
+       { CS35L56_SWIRE_DP3_CH4_INPUT,          0x00000028 },
+
        /* These are not reset by a soft-reset, so patch to defaults. */
        { CS35L56_MAIN_RENDER_USER_MUTE,        0x00000000 },
        { CS35L56_MAIN_RENDER_USER_VOLUME,      0x00000000 },
@@ -34,10 +44,9 @@ static const struct reg_default cs35l56_reg_defaults[] = {
        { CS35L56_ASP1_FRAME_CONTROL5,          0x00020100 },
        { CS35L56_ASP1_DATA_CONTROL1,           0x00000018 },
        { CS35L56_ASP1_DATA_CONTROL5,           0x00000018 },
-       { CS35L56_ASP1TX1_INPUT,                0x00000018 },
-       { CS35L56_ASP1TX2_INPUT,                0x00000019 },
-       { CS35L56_ASP1TX3_INPUT,                0x00000020 },
-       { CS35L56_ASP1TX4_INPUT,                0x00000028 },
+
+       /* no defaults for ASP1TX mixer */
+
        { CS35L56_SWIRE_DP3_CH1_INPUT,          0x00000018 },
        { CS35L56_SWIRE_DP3_CH2_INPUT,          0x00000019 },
        { CS35L56_SWIRE_DP3_CH3_INPUT,          0x00000029 },
@@ -195,6 +204,47 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
        }
 }
 
+/*
+ * The firmware boot sequence can overwrite the ASP1 config registers so that
+ * they don't match regmap's view of their values. Rewrite the values from the
+ * regmap cache into the hardware registers.
+ */
+int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base)
+{
+       struct reg_sequence asp1_regs[] = {
+               { .reg = CS35L56_ASP1_ENABLES1 },
+               { .reg = CS35L56_ASP1_CONTROL1 },
+               { .reg = CS35L56_ASP1_CONTROL2 },
+               { .reg = CS35L56_ASP1_CONTROL3 },
+               { .reg = CS35L56_ASP1_FRAME_CONTROL1 },
+               { .reg = CS35L56_ASP1_FRAME_CONTROL5 },
+               { .reg = CS35L56_ASP1_DATA_CONTROL1 },
+               { .reg = CS35L56_ASP1_DATA_CONTROL5 },
+       };
+       int i, ret;
+
+       /* Read values from regmap cache into a write sequence */
+       for (i = 0; i < ARRAY_SIZE(asp1_regs); ++i) {
+               ret = regmap_read(cs35l56_base->regmap, asp1_regs[i].reg, &asp1_regs[i].def);
+               if (ret)
+                       goto err;
+       }
+
+       /* Write the values cache-bypassed so that they will be written to silicon */
+       ret = regmap_multi_reg_write_bypassed(cs35l56_base->regmap, asp1_regs,
+                                             ARRAY_SIZE(asp1_regs));
+       if (ret)
+               goto err;
+
+       return 0;
+
+err:
+       dev_err(cs35l56_base->dev, "Failed to sync ASP1 registers: %d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_force_sync_asp1_registers_from_cache, SND_SOC_CS35L56_SHARED);
+
 int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command)
 {
        unsigned int val;
@@ -400,17 +450,6 @@ int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base)
        unsigned int val;
        int ret;
 
-       /* Nothing to re-patch if we haven't done any patching yet. */
-       if (!cs35l56_base->fw_patched)
-               return false;
-
-       /*
-        * If we have control of RESET we will have asserted it so the firmware
-        * will need re-patching.
-        */
-       if (cs35l56_base->reset_gpio)
-               return true;
-
        /*
         * In secure mode FIRMWARE_MISSING is cleared by the BIOS loader so
         * can't be used here to test for memory retention.
@@ -590,10 +629,35 @@ void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_ds
 }
 EXPORT_SYMBOL_NS_GPL(cs35l56_init_cs_dsp, SND_SOC_CS35L56_SHARED);
 
+int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base,
+                            bool *fw_missing, unsigned int *fw_version)
+{
+       unsigned int prot_status;
+       int ret;
+
+       ret = regmap_read(cs35l56_base->regmap, CS35L56_PROTECTION_STATUS, &prot_status);
+       if (ret) {
+               dev_err(cs35l56_base->dev, "Get PROTECTION_STATUS failed: %d\n", ret);
+               return ret;
+       }
+
+       *fw_missing = !!(prot_status & CS35L56_FIRMWARE_MISSING);
+
+       ret = regmap_read(cs35l56_base->regmap, CS35L56_DSP1_FW_VER, fw_version);
+       if (ret) {
+               dev_err(cs35l56_base->dev, "Get FW VER failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_read_prot_status, SND_SOC_CS35L56_SHARED);
+
 int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
 {
        int ret;
-       unsigned int devid, revid, otpid, secured;
+       unsigned int devid, revid, otpid, secured, fw_ver;
+       bool fw_missing;
 
        /*
         * When the system is not using a reset_gpio ensure the device is
@@ -652,8 +716,13 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
                return ret;
        }
 
-       dev_info(cs35l56_base->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n",
-                cs35l56_base->secured ? "s" : "", cs35l56_base->rev, otpid);
+       ret = cs35l56_read_prot_status(cs35l56_base, &fw_missing, &fw_ver);
+       if (ret)
+               return ret;
+
+       dev_info(cs35l56_base->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d fw:%d.%d.%d (patched=%u)\n",
+                cs35l56_base->secured ? "s" : "", cs35l56_base->rev, otpid,
+                fw_ver >> 16, (fw_ver >> 8) & 0xff, fw_ver & 0xff, !fw_missing);
 
        /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */
        regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
@@ -668,6 +737,41 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
 }
 EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, SND_SOC_CS35L56_SHARED);
 
+int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base)
+{
+       struct gpio_descs *descs;
+       int speaker_id;
+       int i, ret;
+
+       /* Read the speaker type qualifier from the motherboard GPIOs */
+       descs = gpiod_get_array_optional(cs35l56_base->dev, "spk-id", GPIOD_IN);
+       if (!descs) {
+               return -ENOENT;
+       } else if (IS_ERR(descs)) {
+               ret = PTR_ERR(descs);
+               return dev_err_probe(cs35l56_base->dev, ret, "Failed to get spk-id-gpios\n");
+       }
+
+       speaker_id = 0;
+       for (i = 0; i < descs->ndescs; i++) {
+               ret = gpiod_get_value_cansleep(descs->desc[i]);
+               if (ret < 0) {
+                       dev_err_probe(cs35l56_base->dev, ret, "Failed to read spk-id[%d]\n", i);
+                       goto err;
+               }
+
+               speaker_id |= (ret << i);
+       }
+
+       dev_dbg(cs35l56_base->dev, "Speaker ID = %d\n", speaker_id);
+       ret = speaker_id;
+err:
+       gpiod_put_array(descs);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_get_speaker_id, SND_SOC_CS35L56_SHARED);
+
 static const u32 cs35l56_bclk_valid_for_pll_freq_table[] = {
        [0x0C] = 128000,
        [0x0F] = 256000,
index 45b4de3eff94ffef7ba6ef8ffcccf11747f74415..c23e29da4cfb9f43fa52611fdeea96adad4a0b30 100644 (file)
@@ -59,6 +59,135 @@ static int cs35l56_dspwait_put_volsw(struct snd_kcontrol *kcontrol,
        return snd_soc_put_volsw(kcontrol, ucontrol);
 }
 
+static const unsigned short cs35l56_asp1_mixer_regs[] = {
+       CS35L56_ASP1TX1_INPUT, CS35L56_ASP1TX2_INPUT,
+       CS35L56_ASP1TX3_INPUT, CS35L56_ASP1TX4_INPUT,
+};
+
+static const char * const cs35l56_asp1_mux_control_names[] = {
+       "ASP1 TX1 Source", "ASP1 TX2 Source", "ASP1 TX3 Source", "ASP1 TX4 Source"
+};
+
+static int cs35l56_dspwait_asp1tx_get(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+       struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       int index = e->shift_l;
+       unsigned int addr, val;
+       int ret;
+
+       /* Wait for mux to be initialized */
+       cs35l56_wait_dsp_ready(cs35l56);
+       flush_work(&cs35l56->mux_init_work);
+
+       addr = cs35l56_asp1_mixer_regs[index];
+       ret = regmap_read(cs35l56->base.regmap, addr, &val);
+       if (ret)
+               return ret;
+
+       val &= CS35L56_ASP_TXn_SRC_MASK;
+       ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
+
+       return 0;
+}
+
+static int cs35l56_dspwait_asp1tx_put(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+       struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       int item = ucontrol->value.enumerated.item[0];
+       int index = e->shift_l;
+       unsigned int addr, val;
+       bool changed;
+       int ret;
+
+       /* Wait for mux to be initialized */
+       cs35l56_wait_dsp_ready(cs35l56);
+       flush_work(&cs35l56->mux_init_work);
+
+       addr = cs35l56_asp1_mixer_regs[index];
+       val = snd_soc_enum_item_to_val(e, item);
+
+       ret = regmap_update_bits_check(cs35l56->base.regmap, addr,
+                                      CS35L56_ASP_TXn_SRC_MASK, val, &changed);
+       if (!ret)
+               return ret;
+
+       if (changed)
+               snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
+
+       return changed;
+}
+
+static void cs35l56_mark_asp1_mixer_widgets_dirty(struct cs35l56_private *cs35l56)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cs35l56->component);
+       const char *prefix = cs35l56->component->name_prefix;
+       char full_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       const char *name;
+       struct snd_kcontrol *kcontrol;
+       struct soc_enum *e;
+       unsigned int val[4];
+       int i, item, ret;
+
+       /*
+        * Resume so we can read the registers from silicon if the regmap
+        * cache has not yet been populated.
+        */
+       ret = pm_runtime_resume_and_get(cs35l56->base.dev);
+       if (ret < 0)
+               return;
+
+       ret = regmap_bulk_read(cs35l56->base.regmap, CS35L56_ASP1TX1_INPUT,
+                              val, ARRAY_SIZE(val));
+
+       pm_runtime_mark_last_busy(cs35l56->base.dev);
+       pm_runtime_put_autosuspend(cs35l56->base.dev);
+
+       if (ret) {
+               dev_err(cs35l56->base.dev, "Failed to read ASP1 mixer regs: %d\n", ret);
+               return;
+       }
+
+       snd_soc_card_mutex_lock(dapm->card);
+       WARN_ON(!dapm->card->instantiated);
+
+       for (i = 0; i < ARRAY_SIZE(cs35l56_asp1_mux_control_names); ++i) {
+               name = cs35l56_asp1_mux_control_names[i];
+
+               if (prefix) {
+                       snprintf(full_name, sizeof(full_name), "%s %s", prefix, name);
+                       name = full_name;
+               }
+
+               kcontrol = snd_soc_card_get_kcontrol(dapm->card, name);
+               if (!kcontrol) {
+                       dev_warn(cs35l56->base.dev, "Could not find control %s\n", name);
+                       continue;
+               }
+
+               e = (struct soc_enum *)kcontrol->private_value;
+               item = snd_soc_enum_val_to_item(e, val[i] & CS35L56_ASP_TXn_SRC_MASK);
+               snd_soc_dapm_mux_update_power(dapm, kcontrol, item, e, NULL);
+       }
+
+       snd_soc_card_mutex_unlock(dapm->card);
+}
+
+static void cs35l56_mux_init_work(struct work_struct *work)
+{
+       struct cs35l56_private *cs35l56 = container_of(work,
+                                                      struct cs35l56_private,
+                                                      mux_init_work);
+
+       cs35l56_mark_asp1_mixer_widgets_dirty(cs35l56);
+}
+
 static DECLARE_TLV_DB_SCALE(vol_tlv, -10000, 25, 0);
 
 static const struct snd_kcontrol_new cs35l56_controls[] = {
@@ -77,40 +206,44 @@ static const struct snd_kcontrol_new cs35l56_controls[] = {
 };
 
 static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx1_enum,
-                                 CS35L56_ASP1TX1_INPUT,
-                                 0, CS35L56_ASP_TXn_SRC_MASK,
+                                 SND_SOC_NOPM,
+                                 0, 0,
                                  cs35l56_tx_input_texts,
                                  cs35l56_tx_input_values);
 
 static const struct snd_kcontrol_new asp1_tx1_mux =
-       SOC_DAPM_ENUM("ASP1TX1 SRC", cs35l56_asp1tx1_enum);
+       SOC_DAPM_ENUM_EXT("ASP1TX1 SRC", cs35l56_asp1tx1_enum,
+                         cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put);
 
 static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx2_enum,
-                                 CS35L56_ASP1TX2_INPUT,
-                                 0, CS35L56_ASP_TXn_SRC_MASK,
+                                 SND_SOC_NOPM,
+                                 1, 0,
                                  cs35l56_tx_input_texts,
                                  cs35l56_tx_input_values);
 
 static const struct snd_kcontrol_new asp1_tx2_mux =
-       SOC_DAPM_ENUM("ASP1TX2 SRC", cs35l56_asp1tx2_enum);
+       SOC_DAPM_ENUM_EXT("ASP1TX2 SRC", cs35l56_asp1tx2_enum,
+                         cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put);
 
 static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx3_enum,
-                                 CS35L56_ASP1TX3_INPUT,
-                                 0, CS35L56_ASP_TXn_SRC_MASK,
+                                 SND_SOC_NOPM,
+                                 2, 0,
                                  cs35l56_tx_input_texts,
                                  cs35l56_tx_input_values);
 
 static const struct snd_kcontrol_new asp1_tx3_mux =
-       SOC_DAPM_ENUM("ASP1TX3 SRC", cs35l56_asp1tx3_enum);
+       SOC_DAPM_ENUM_EXT("ASP1TX3 SRC", cs35l56_asp1tx3_enum,
+                         cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put);
 
 static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_asp1tx4_enum,
-                                 CS35L56_ASP1TX4_INPUT,
-                                 0, CS35L56_ASP_TXn_SRC_MASK,
+                                 SND_SOC_NOPM,
+                                 3, 0,
                                  cs35l56_tx_input_texts,
                                  cs35l56_tx_input_values);
 
 static const struct snd_kcontrol_new asp1_tx4_mux =
-       SOC_DAPM_ENUM("ASP1TX4 SRC", cs35l56_asp1tx4_enum);
+       SOC_DAPM_ENUM_EXT("ASP1TX4 SRC", cs35l56_asp1tx4_enum,
+                         cs35l56_dspwait_asp1tx_get, cs35l56_dspwait_asp1tx_put);
 
 static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx1_enum,
                                CS35L56_SWIRE_DP3_CH1_INPUT,
@@ -148,6 +281,21 @@ static SOC_VALUE_ENUM_SINGLE_DECL(cs35l56_sdw1tx4_enum,
 static const struct snd_kcontrol_new sdw1_tx4_mux =
        SOC_DAPM_ENUM("SDW1TX4 SRC", cs35l56_sdw1tx4_enum);
 
+static int cs35l56_asp1_cfg_event(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 cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               /* Override register values set by firmware boot */
+               return cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base);
+       default:
+               return 0;
+       }
+}
+
 static int cs35l56_play_event(struct snd_soc_dapm_widget *w,
                              struct snd_kcontrol *kcontrol, int event)
 {
@@ -184,6 +332,9 @@ static const struct snd_soc_dapm_widget cs35l56_dapm_widgets[] = {
        SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_B", 0, 0),
        SND_SOC_DAPM_REGULATOR_SUPPLY("VDD_AMP", 0, 0),
 
+       SND_SOC_DAPM_SUPPLY("ASP1 CFG", SND_SOC_NOPM, 0, 0, cs35l56_asp1_cfg_event,
+                           SND_SOC_DAPM_PRE_PMU),
+
        SND_SOC_DAPM_SUPPLY("PLAY", SND_SOC_NOPM, 0, 0, cs35l56_play_event,
                            SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
@@ -251,6 +402,9 @@ static const struct snd_soc_dapm_route cs35l56_audio_map[] = {
        { "AMP", NULL, "VDD_B" },
        { "AMP", NULL, "VDD_AMP" },
 
+       { "ASP1 Playback", NULL, "ASP1 CFG" },
+       { "ASP1 Capture", NULL, "ASP1 CFG" },
+
        { "ASP1 Playback", NULL, "PLAY" },
        { "SDW1 Playback", NULL, "PLAY" },
 
@@ -650,7 +804,7 @@ static struct snd_soc_dai_driver cs35l56_dai[] = {
        }
 };
 
-static void cs35l56_secure_patch(struct cs35l56_private *cs35l56)
+static void cs35l56_reinit_patch(struct cs35l56_private *cs35l56)
 {
        int ret;
 
@@ -662,19 +816,10 @@ static void cs35l56_secure_patch(struct cs35l56_private *cs35l56)
                cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
 }
 
-static void cs35l56_patch(struct cs35l56_private *cs35l56)
+static void cs35l56_patch(struct cs35l56_private *cs35l56, bool firmware_missing)
 {
-       unsigned int firmware_missing;
        int ret;
 
-       ret = regmap_read(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, &firmware_missing);
-       if (ret) {
-               dev_err(cs35l56->base.dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
-               return;
-       }
-
-       firmware_missing &= CS35L56_FIRMWARE_MISSING;
-
        /*
         * Disable SoundWire interrupts to prevent race with IRQ work.
         * Setting sdw_irq_no_unmask prevents the handler re-enabling
@@ -747,23 +892,59 @@ static void cs35l56_dsp_work(struct work_struct *work)
        struct cs35l56_private *cs35l56 = container_of(work,
                                                       struct cs35l56_private,
                                                       dsp_work);
+       unsigned int firmware_version;
+       bool firmware_missing;
+       int ret;
 
        if (!cs35l56->base.init_done)
                return;
 
        pm_runtime_get_sync(cs35l56->base.dev);
 
+       ret = cs35l56_read_prot_status(&cs35l56->base, &firmware_missing, &firmware_version);
+       if (ret)
+               goto err;
+
+       /* Populate fw file qualifier with the revision and security state */
+       kfree(cs35l56->dsp.fwf_name);
+       if (firmware_missing) {
+               cs35l56->dsp.fwf_name = kasprintf(GFP_KERNEL, "%02x-dsp1", cs35l56->base.rev);
+       } else {
+               /* Firmware files must match the running firmware version */
+               cs35l56->dsp.fwf_name = kasprintf(GFP_KERNEL,
+                                                 "%02x%s-%06x-dsp1",
+                                                 cs35l56->base.rev,
+                                                 cs35l56->base.secured ? "-s" : "",
+                                                 firmware_version);
+       }
+
+       if (!cs35l56->dsp.fwf_name)
+               goto err;
+
+       dev_dbg(cs35l56->base.dev, "DSP fwf name: '%s' system name: '%s'\n",
+               cs35l56->dsp.fwf_name, cs35l56->dsp.system_name);
+
        /*
-        * When the device is running in secure mode the firmware files can
-        * only contain insecure tunings and therefore we do not need to
-        * shutdown the firmware to apply them and can use the lower cost
-        * reinit sequence instead.
+        * The firmware cannot be patched if it is already running from
+        * patch RAM. In this case the firmware files are versioned to
+        * match the running firmware version and will only contain
+        * tunings. We do not need to shutdown the firmware to apply
+        * tunings so can use the lower cost reinit sequence instead.
         */
-       if (cs35l56->base.secured)
-               cs35l56_secure_patch(cs35l56);
+       if (!firmware_missing)
+               cs35l56_reinit_patch(cs35l56);
        else
-               cs35l56_patch(cs35l56);
+               cs35l56_patch(cs35l56, firmware_missing);
 
+
+       /*
+        * Set starting value of ASP1 mux widgets. Updating a mux takes
+        * the DAPM mutex. Post this to a separate job so that DAPM
+        * power-up can wait for dsp_work to complete without deadlocking
+        * on the DAPM mutex.
+        */
+       queue_work(cs35l56->dsp_wq, &cs35l56->mux_init_work);
+err:
        pm_runtime_mark_last_busy(cs35l56->base.dev);
        pm_runtime_put_autosuspend(cs35l56->base.dev);
 }
@@ -778,10 +959,19 @@ static int cs35l56_component_probe(struct snd_soc_component *component)
 
        if (!cs35l56->dsp.system_name &&
            (snd_soc_card_get_pci_ssid(component->card, &vendor, &device) == 0)) {
-               cs35l56->dsp.system_name = devm_kasprintf(cs35l56->base.dev,
-                                                         GFP_KERNEL,
-                                                         "%04x%04x",
-                                                         vendor, device);
+               /* Append a speaker qualifier if there is a speaker ID */
+               if (cs35l56->speaker_id >= 0) {
+                       cs35l56->dsp.system_name = devm_kasprintf(cs35l56->base.dev,
+                                                                 GFP_KERNEL,
+                                                                 "%04x%04x-spkid%d",
+                                                                 vendor, device,
+                                                                 cs35l56->speaker_id);
+               } else {
+                       cs35l56->dsp.system_name = devm_kasprintf(cs35l56->base.dev,
+                                                                 GFP_KERNEL,
+                                                                 "%04x%04x",
+                                                                 vendor, device);
+               }
                if (!cs35l56->dsp.system_name)
                        return -ENOMEM;
        }
@@ -809,6 +999,17 @@ static void cs35l56_component_remove(struct snd_soc_component *component)
        struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
 
        cancel_work_sync(&cs35l56->dsp_work);
+       cancel_work_sync(&cs35l56->mux_init_work);
+
+       if (cs35l56->dsp.cs_dsp.booted)
+               wm_adsp_power_down(&cs35l56->dsp);
+
+       wm_adsp2_component_remove(&cs35l56->dsp, component);
+
+       kfree(cs35l56->dsp.fwf_name);
+       cs35l56->dsp.fwf_name = NULL;
+
+       cs35l56->component = NULL;
 }
 
 static int cs35l56_set_bias_level(struct snd_soc_component *component,
@@ -869,8 +1070,10 @@ int cs35l56_system_suspend(struct device *dev)
 
        dev_dbg(dev, "system_suspend\n");
 
-       if (cs35l56->component)
+       if (cs35l56->component) {
                flush_work(&cs35l56->dsp_work);
+               cancel_work_sync(&cs35l56->mux_init_work);
+       }
 
        /*
         * The interrupt line is normally shared, but after we start suspending
@@ -1021,6 +1224,7 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56)
                return -ENOMEM;
 
        INIT_WORK(&cs35l56->dsp_work, cs35l56_dsp_work);
+       INIT_WORK(&cs35l56->mux_init_work, cs35l56_mux_init_work);
 
        dsp = &cs35l56->dsp;
        cs35l56_init_cs_dsp(&cs35l56->base, &dsp->cs_dsp);
@@ -1050,7 +1254,13 @@ static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56)
        if (ret < 0)
                return 0;
 
-       cs35l56->dsp.system_name = devm_kstrdup(dev, prop, GFP_KERNEL);
+       /* Append a speaker qualifier if there is a speaker ID */
+       if (cs35l56->speaker_id >= 0)
+               cs35l56->dsp.system_name = devm_kasprintf(dev, GFP_KERNEL, "%s-spkid%d",
+                                                         prop, cs35l56->speaker_id);
+       else
+               cs35l56->dsp.system_name = devm_kstrdup(dev, prop, GFP_KERNEL);
+
        if (cs35l56->dsp.system_name == NULL)
                return -ENOMEM;
 
@@ -1065,6 +1275,7 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
 
        init_completion(&cs35l56->init_completion);
        mutex_init(&cs35l56->base.irq_lock);
+       cs35l56->speaker_id = -ENOENT;
 
        dev_set_drvdata(cs35l56->base.dev, cs35l56);
 
@@ -1101,6 +1312,12 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
                gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
        }
 
+       ret = cs35l56_get_speaker_id(&cs35l56->base);
+       if ((ret < 0) && (ret != -ENOENT))
+               goto err;
+
+       cs35l56->speaker_id = ret;
+
        ret = cs35l56_get_firmware_uid(cs35l56);
        if (ret != 0)
                goto err;
@@ -1152,11 +1369,9 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
        if (ret < 0)
                return ret;
 
-       /* Populate the DSP information with the revision and security state */
-       cs35l56->dsp.part = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "cs35l56%s-%02x",
-                                          cs35l56->base.secured ? "s" : "", cs35l56->base.rev);
-       if (!cs35l56->dsp.part)
-               return -ENOMEM;
+       ret = cs35l56_set_patch(&cs35l56->base);
+       if (ret)
+               return ret;
 
        if (!cs35l56->base.reset_gpio) {
                dev_dbg(cs35l56->base.dev, "No reset gpio: using soft reset\n");
@@ -1190,10 +1405,6 @@ post_soft_reset:
        if (ret)
                return ret;
 
-       ret = cs35l56_set_patch(&cs35l56->base);
-       if (ret)
-               return ret;
-
        /* Registers could be dirty after soft reset or SoundWire enumeration */
        regcache_sync(cs35l56->base.regmap);
 
index 8159c3e217d936c02baf88c5659a99e4f3159ddd..596b141e3f9612389cae4c6b80eab20f4f90fd69 100644 (file)
@@ -34,6 +34,7 @@ struct cs35l56_private {
        struct wm_adsp dsp; /* must be first member */
        struct cs35l56_base base;
        struct work_struct dsp_work;
+       struct work_struct mux_init_work;
        struct workqueue_struct *dsp_wq;
        struct snd_soc_component *component;
        struct regulator_bulk_data supplies[CS35L56_NUM_BULK_SUPPLIES];
@@ -44,6 +45,7 @@ struct cs35l56_private {
        bool sdw_attached;
        struct completion init_completion;
 
+       int speaker_id;
        u32 rx_mask;
        u32 tx_mask;
        u8 asp_slot_width;
old mode 100755 (executable)
new mode 100644 (file)
index fa890f6..cbcd02e
@@ -45,6 +45,82 @@ struct es8326_priv {
        int jack_remove_retry;
 };
 
+static int es8326_crosstalk1_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+       unsigned int crosstalk_h, crosstalk_l;
+       unsigned int crosstalk;
+
+       regmap_read(es8326->regmap, ES8326_DAC_RAMPRATE, &crosstalk_h);
+       regmap_read(es8326->regmap, ES8326_DAC_CROSSTALK, &crosstalk_l);
+       crosstalk_h &= 0x20;
+       crosstalk_l &= 0xf0;
+       crosstalk = crosstalk_h >> 1 | crosstalk_l >> 4;
+       ucontrol->value.integer.value[0] = crosstalk;
+
+       return 0;
+}
+
+static int es8326_crosstalk1_set(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+       unsigned int crosstalk_h, crosstalk_l;
+       unsigned int crosstalk;
+
+       crosstalk = ucontrol->value.integer.value[0];
+       regmap_read(es8326->regmap, ES8326_DAC_CROSSTALK, &crosstalk_l);
+       crosstalk_h = (crosstalk & 0x10) << 1;
+       crosstalk_l &= 0x0f;
+       crosstalk_l |= (crosstalk & 0x0f) << 4;
+       regmap_update_bits(es8326->regmap, ES8326_DAC_RAMPRATE,
+                       0x20, crosstalk_h);
+       regmap_write(es8326->regmap, ES8326_DAC_CROSSTALK, crosstalk_l);
+
+       return 0;
+}
+
+static int es8326_crosstalk2_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+       unsigned int crosstalk_h, crosstalk_l;
+       unsigned int crosstalk;
+
+       regmap_read(es8326->regmap, ES8326_DAC_RAMPRATE, &crosstalk_h);
+       regmap_read(es8326->regmap, ES8326_DAC_CROSSTALK, &crosstalk_l);
+       crosstalk_h &= 0x10;
+       crosstalk_l &= 0x0f;
+       crosstalk = crosstalk_h  | crosstalk_l;
+       ucontrol->value.integer.value[0] = crosstalk;
+
+       return 0;
+}
+
+static int es8326_crosstalk2_set(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+       unsigned int crosstalk_h, crosstalk_l;
+       unsigned int crosstalk;
+
+       crosstalk = ucontrol->value.integer.value[0];
+       regmap_read(es8326->regmap, ES8326_DAC_CROSSTALK, &crosstalk_l);
+       crosstalk_h = crosstalk & 0x10;
+       crosstalk_l &= 0xf0;
+       crosstalk_l |= crosstalk & 0x0f;
+       regmap_update_bits(es8326->regmap, ES8326_DAC_RAMPRATE,
+                       0x10, crosstalk_h);
+       regmap_write(es8326->regmap, ES8326_DAC_CROSSTALK, crosstalk_l);
+
+       return 0;
+}
+
 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9550, 50, 0);
 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_analog_pga_tlv, 0, 300, 0);
@@ -102,6 +178,10 @@ static const struct snd_kcontrol_new es8326_snd_controls[] = {
        SOC_SINGLE_TLV("ALC Capture Target Level", ES8326_ALC_LEVEL,
                        0, 0x0f, 0, drc_target_tlv),
 
+       SOC_SINGLE_EXT("CROSSTALK1", SND_SOC_NOPM, 0, 31, 0,
+                       es8326_crosstalk1_get, es8326_crosstalk1_set),
+       SOC_SINGLE_EXT("CROSSTALK2", SND_SOC_NOPM, 0, 31, 0,
+                       es8326_crosstalk2_get, es8326_crosstalk2_set),
 };
 
 static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = {
@@ -117,12 +197,6 @@ static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = {
        SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture", 0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0, SND_SOC_NOPM, 0, 0),
 
-       /* ADC Digital Mute */
-       SND_SOC_DAPM_PGA("ADC L1", ES8326_ADC_MUTE, 0, 1, NULL, 0),
-       SND_SOC_DAPM_PGA("ADC R1", ES8326_ADC_MUTE, 1, 1, NULL, 0),
-       SND_SOC_DAPM_PGA("ADC L2", ES8326_ADC_MUTE, 2, 1, NULL, 0),
-       SND_SOC_DAPM_PGA("ADC R2", ES8326_ADC_MUTE, 3, 1, NULL, 0),
-
        /* Analog Power Supply*/
        SND_SOC_DAPM_DAC("Right DAC", NULL, ES8326_ANA_PDN, 0, 1),
        SND_SOC_DAPM_DAC("Left DAC", NULL, ES8326_ANA_PDN, 1, 1),
@@ -142,15 +216,10 @@ static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route es8326_dapm_routes[] = {
-       {"ADC L1", NULL, "MIC1"},
-       {"ADC R1", NULL, "MIC2"},
-       {"ADC L2", NULL, "MIC3"},
-       {"ADC R2", NULL, "MIC4"},
-
-       {"ADC L", NULL, "ADC L1"},
-       {"ADC R", NULL, "ADC R1"},
-       {"ADC L", NULL, "ADC L2"},
-       {"ADC R", NULL, "ADC R2"},
+       {"ADC L", NULL, "MIC1"},
+       {"ADC R", NULL, "MIC2"},
+       {"ADC L", NULL, "MIC3"},
+       {"ADC R", NULL, "MIC4"},
 
        {"I2S OUT", NULL, "ADC L"},
        {"I2S OUT", NULL, "ADC R"},
@@ -440,10 +509,16 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction)
        unsigned int offset_l, offset_r;
 
        if (mute) {
-               regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF);
-               regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE,
-                               ES8326_MUTE_MASK, ES8326_MUTE);
-               regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xf0);
+               if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+                       regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF);
+                       regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE,
+                                       ES8326_MUTE_MASK, ES8326_MUTE);
+                       regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF,
+                                       0x30, 0x00);
+               } else {
+                       regmap_update_bits(es8326->regmap,  ES8326_ADC_MUTE,
+                                       0x0F, 0x0F);
+               }
        } else {
                if (!es8326->calibrated) {
                        regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_FORCE_CAL);
@@ -456,11 +531,22 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction)
                        regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r);
                        es8326->calibrated = true;
                }
-               regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa1);
-               regmap_write(es8326->regmap, ES8326_HP_VOL, 0x91);
-               regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_ON);
-               regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE,
-                               ES8326_MUTE_MASK, ~(ES8326_MUTE));
+               if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+                       regmap_update_bits(es8326->regmap, ES8326_DAC_DSM, 0x01, 0x01);
+                       usleep_range(1000, 5000);
+                       regmap_update_bits(es8326->regmap, ES8326_DAC_DSM, 0x01, 0x00);
+                       usleep_range(1000, 5000);
+                       regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF, 0x30, 0x20);
+                       regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF, 0x30, 0x30);
+                       regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa1);
+                       regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_ON);
+                       regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE,
+                                       ES8326_MUTE_MASK, ~(ES8326_MUTE));
+               } else {
+                       msleep(300);
+                       regmap_update_bits(es8326->regmap,  ES8326_ADC_MUTE,
+                                       0x0F, 0x00);
+               }
        }
        return 0;
 }
@@ -477,23 +563,20 @@ static int es8326_set_bias_level(struct snd_soc_component *codec,
                if (ret)
                        return ret;
 
-               regmap_update_bits(es8326->regmap, ES8326_DAC_DSM, 0x01, 0x00);
+               regmap_update_bits(es8326->regmap, ES8326_RESET, 0x02, 0x02);
+               usleep_range(5000, 10000);
                regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk);
                regmap_write(es8326->regmap, ES8326_SDINOUT1_IO,
                            (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT));
-               regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E);
                regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x40);
                regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x00);
                regmap_update_bits(es8326->regmap,  ES8326_CLK_CTL, 0x20, 0x20);
-
-               regmap_update_bits(es8326->regmap, ES8326_RESET,
-                               ES8326_CSM_ON, ES8326_CSM_ON);
+               regmap_update_bits(es8326->regmap, ES8326_RESET, 0x02, 0x00);
                break;
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
                regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b);
-               regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x00);
                regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x00);
                regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT);
                break;
@@ -513,7 +596,7 @@ static const struct snd_soc_dai_ops es8326_ops = {
        .set_fmt = es8326_set_dai_fmt,
        .set_sysclk = es8326_set_dai_sysclk,
        .mute_stream = es8326_mute,
-       .no_capture_mute = 1,
+       .no_capture_mute = 0,
 };
 
 static struct snd_soc_dai_driver es8326_dai = {
@@ -672,6 +755,8 @@ static void es8326_jack_detect_handler(struct work_struct *work)
                        es8326->hp = 0;
                }
                regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01);
+               regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x0a);
+               regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF, 0x0f, 0x03);
                /*
                 * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event
                 */
@@ -695,8 +780,11 @@ static void es8326_jack_detect_handler(struct work_struct *work)
                         * Don't report jack status.
                         */
                        regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01);
+                       es8326_enable_micbias(es8326->component);
                        usleep_range(50000, 70000);
                        regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00);
+                       regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x1f);
+                       regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF, 0x0f, 0x08);
                        queue_delayed_work(system_wq, &es8326->jack_detect_work,
                                        msecs_to_jiffies(400));
                        es8326->hp = 1;
@@ -736,13 +824,10 @@ exit:
 static irqreturn_t es8326_irq(int irq, void *dev_id)
 {
        struct es8326_priv *es8326 = dev_id;
-       struct snd_soc_component *comp = es8326->component;
 
        if (!es8326->jack)
                goto out;
 
-       es8326_enable_micbias(comp);
-
        if (es8326->jack->status & SND_JACK_HEADSET)
                queue_delayed_work(system_wq, &es8326->jack_detect_work,
                                   msecs_to_jiffies(10));
@@ -766,14 +851,14 @@ static int es8326_calibrate(struct snd_soc_component *component)
        if ((es8326->version == ES8326_VERSION_B) && (es8326->calibrated == false)) {
                dev_dbg(component->dev, "ES8326_VERSION_B, calibrating\n");
                regmap_write(es8326->regmap, ES8326_CLK_INV, 0xc0);
-               regmap_write(es8326->regmap, ES8326_CLK_DIV1, 0x01);
+               regmap_write(es8326->regmap, ES8326_CLK_DIV1, 0x03);
                regmap_write(es8326->regmap, ES8326_CLK_DLL, 0x30);
                regmap_write(es8326->regmap, ES8326_CLK_MUX, 0xed);
                regmap_write(es8326->regmap, ES8326_CLK_DAC_SEL, 0x08);
                regmap_write(es8326->regmap, ES8326_CLK_TRI, 0xc1);
                regmap_write(es8326->regmap, ES8326_DAC_MUTE, 0x03);
                regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7f);
-               regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x03);
+               regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x23);
                regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x88);
                usleep_range(15000, 20000);
                regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c);
@@ -814,13 +899,13 @@ static int es8326_resume(struct snd_soc_component *component)
        /* reset internal clock state */
        regmap_write(es8326->regmap, ES8326_RESET, 0x1f);
        regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E);
+       regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0);
        usleep_range(10000, 15000);
        regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0xe9);
-       regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0x4b);
+       regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0xcb);
        /* set headphone default type and detect pin */
        regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x83);
        regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05);
-       regmap_write(es8326->regmap, ES8326_HP_MISC, 0x30);
 
        /* set internal oscillator as clock source of headpone cp */
        regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x89);
@@ -828,14 +913,15 @@ static int es8326_resume(struct snd_soc_component *component)
        /* clock manager reset release */
        regmap_write(es8326->regmap, ES8326_RESET, 0x17);
        /* set headphone detection as half scan mode */
-       regmap_write(es8326->regmap, ES8326_HP_MISC, 0x30);
+       regmap_write(es8326->regmap, ES8326_HP_MISC, 0x3d);
        regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x00);
 
        /* enable headphone driver */
+       regmap_write(es8326->regmap, ES8326_HP_VOL, 0xc4);
        regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa7);
        usleep_range(2000, 5000);
-       regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xa3);
-       regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xb3);
+       regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0x23);
+       regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0x33);
        regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa1);
 
        regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00);
@@ -844,6 +930,8 @@ static int es8326_resume(struct snd_soc_component *component)
        regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x00);
        /* calibrate for B version */
        es8326_calibrate(component);
+       regmap_write(es8326->regmap, ES8326_DAC_CROSSTALK, 0xaa);
+       regmap_write(es8326->regmap, ES8326_DAC_RAMPRATE, 0x00);
        /* turn off headphone out */
        regmap_write(es8326->regmap, ES8326_HP_CAL, 0x00);
        /* set ADC and DAC in low power mode */
@@ -856,6 +944,14 @@ static int es8326_resume(struct snd_soc_component *component)
        regmap_write(es8326->regmap, ES8326_DAC_DSM, 0x08);
        regmap_write(es8326->regmap, ES8326_DAC_VPPSCALE, 0x15);
 
+       regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x80 |
+                       ((es8326->version == ES8326_VERSION_B) ?
+                       (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) :
+                       (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04)));
+       usleep_range(5000, 10000);
+       es8326_enable_micbias(es8326->component);
+       usleep_range(50000, 70000);
+       regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00);
        regmap_write(es8326->regmap, ES8326_INT_SOURCE,
                    (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON));
        regmap_write(es8326->regmap, ES8326_INTOUT_IO,
@@ -864,7 +960,7 @@ static int es8326_resume(struct snd_soc_component *component)
                    (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT));
        regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
 
-       regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b);
+       regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x00);
        regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON);
        regmap_update_bits(es8326->regmap, ES8326_PGAGAIN, ES8326_MIC_SEL_MASK,
                           ES8326_MIC1_SEL);
@@ -872,11 +968,7 @@ static int es8326_resume(struct snd_soc_component *component)
        regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, ES8326_MUTE_MASK,
                           ES8326_MUTE);
 
-       regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x80 |
-                       ((es8326->version == ES8326_VERSION_B) ?
-                       (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) :
-                       (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04)));
-       regmap_write(es8326->regmap, ES8326_HP_VOL, 0x11);
+       regmap_write(es8326->regmap, ES8326_ADC_MUTE, 0x0f);
 
        es8326->jack_remove_retry = 0;
        es8326->hp = 0;
index 90a08351d6acd043b42a6ebed574591a3defc6a0..4234bbb900c4530c6746fab5f75fcb0b049e4fdb 100644 (file)
@@ -72,6 +72,7 @@
 #define ES8326_DAC_VOL         0x50
 #define ES8326_DRC_RECOVERY    0x53
 #define ES8326_DRC_WINSIZE     0x54
+#define ES8326_DAC_CROSSTALK   0x55
 #define ES8326_HPJACK_TIMER    0x56
 #define ES8326_HPDET_TYPE      0x57
 #define ES8326_INT_SOURCE      0x58
 #define ES8326_MUTE (3 << 0)
 
 /* ES8326_CLK_CTL */
-#define ES8326_CLK_ON (0x7f << 0)
+#define ES8326_CLK_ON (0x7e << 0)
 #define ES8326_CLK_OFF (0 << 0)
 
 /* ES8326_CLK_INV */
index 7e21cec3c2fb97a9be518b4316cdeafae2cf0776..6ce309980cd10e200dc62a1941b07f6f7728d3cd 100644 (file)
@@ -1584,7 +1584,6 @@ static int wsa_macro_enable_interpolator(struct snd_soc_dapm_widget *w,
        u16 gain_reg;
        u16 reg;
        int val;
-       int offset_val = 0;
        struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);
 
        if (w->shift == WSA_MACRO_COMP1) {
@@ -1623,10 +1622,8 @@ static int wsa_macro_enable_interpolator(struct snd_soc_dapm_widget *w,
                                        CDC_WSA_RX1_RX_PATH_MIX_SEC0,
                                        CDC_WSA_RX_PGA_HALF_DB_MASK,
                                        CDC_WSA_RX_PGA_HALF_DB_ENABLE);
-                       offset_val = -2;
                }
                val = snd_soc_component_read(component, gain_reg);
-               val += offset_val;
                snd_soc_component_write(component, gain_reg, val);
                wsa_macro_config_ear_spkr_gain(component, wsa,
                                                event, gain_reg);
@@ -1654,10 +1651,6 @@ static int wsa_macro_enable_interpolator(struct snd_soc_dapm_widget *w,
                                        CDC_WSA_RX1_RX_PATH_MIX_SEC0,
                                        CDC_WSA_RX_PGA_HALF_DB_MASK,
                                        CDC_WSA_RX_PGA_HALF_DB_DISABLE);
-                       offset_val = 2;
-                       val = snd_soc_component_read(component, gain_reg);
-                       val += offset_val;
-                       snd_soc_component_write(component, gain_reg, val);
                }
                wsa_macro_config_ear_spkr_gain(component, wsa,
                                                event, gain_reg);
index 43c648efd0d938db5e0cb470a625617b8dc1860f..deb15b95992d5cc494562a91f13adbc348e2dd31 100644 (file)
@@ -3033,7 +3033,6 @@ static int wcd9335_codec_enable_mix_path(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
        u16 gain_reg;
-       int offset_val = 0;
        int val = 0;
 
        switch (w->reg) {
@@ -3073,7 +3072,6 @@ static int wcd9335_codec_enable_mix_path(struct snd_soc_dapm_widget *w,
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                val = snd_soc_component_read(comp, gain_reg);
-               val += offset_val;
                snd_soc_component_write(comp, gain_reg, val);
                break;
        case SND_SOC_DAPM_POST_PMD:
@@ -3294,7 +3292,6 @@ static int wcd9335_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
        u16 gain_reg;
        u16 reg;
        int val;
-       int offset_val = 0;
 
        if (!(snd_soc_dapm_widget_name_cmp(w, "RX INT0 INTERP"))) {
                reg = WCD9335_CDC_RX0_RX_PATH_CTL;
@@ -3337,7 +3334,6 @@ static int wcd9335_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
        case SND_SOC_DAPM_POST_PMU:
                wcd9335_config_compander(comp, w->shift, event);
                val = snd_soc_component_read(comp, gain_reg);
-               val += offset_val;
                snd_soc_component_write(comp, gain_reg, val);
                break;
        case SND_SOC_DAPM_POST_PMD:
index 1b6e376f3833cbc5f59034e88f90a4ee3845632a..6813268e6a19f3048877c5ae0ee55ae227543c04 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
-#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/slimbus.h>
 #include <sound/pcm_params.h>
index faf8d3f9b3c5d929d935ad4c5c63fe45371e4edc..6021aa5a56891969b04db64ac019bafb0766c701 100644 (file)
@@ -210,7 +210,7 @@ struct wcd938x_priv {
 };
 
 static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800);
-static const DECLARE_TLV_DB_SCALE(line_gain, -3000, 150, -3000);
+static const DECLARE_TLV_DB_SCALE(line_gain, -3000, 150, 0);
 static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(analog_gain, 0, 3000);
 
 struct wcd938x_mbhc_zdet_param {
@@ -3587,10 +3587,8 @@ static int wcd938x_probe(struct platform_device *pdev)
        mutex_init(&wcd938x->micb_lock);
 
        ret = wcd938x_populate_dt_data(wcd938x, dev);
-       if (ret) {
-               dev_err(dev, "%s: Fail to obtain platform data\n", __func__);
-               return -EINVAL;
-       }
+       if (ret)
+               return ret;
 
        ret = wcd938x_add_slave_components(wcd938x, dev, &match);
        if (ret)
index c01e31175015cc2f354175dec019fac591a98b4b..36ea0dcdc7ab0033eb48e393d783e4f7d4df9854 100644 (file)
@@ -739,19 +739,25 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp,
                                         const char *filetype)
 {
        struct cs_dsp *cs_dsp = &dsp->cs_dsp;
+       const char *fwf;
        char *s, c;
        int ret = 0;
 
+       if (dsp->fwf_name)
+               fwf = dsp->fwf_name;
+       else
+               fwf = dsp->cs_dsp.name;
+
        if (system_name && asoc_component_prefix)
                *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, dsp->part,
-                                     dsp->fwf_name, wm_adsp_fw[dsp->fw].file, system_name,
+                                     fwf, wm_adsp_fw[dsp->fw].file, system_name,
                                      asoc_component_prefix, filetype);
        else if (system_name)
                *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, dsp->part,
-                                     dsp->fwf_name, wm_adsp_fw[dsp->fw].file, system_name,
+                                     fwf, wm_adsp_fw[dsp->fw].file, system_name,
                                      filetype);
        else
-               *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, dsp->part, dsp->fwf_name,
+               *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, dsp->part, fwf,
                                      wm_adsp_fw[dsp->fw].file, filetype);
 
        if (*filename == NULL)
@@ -823,6 +829,23 @@ static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
                }
        }
 
+       /* Check system-specific bin without wmfw before falling back to generic */
+       if (dsp->wmfw_optional && system_name) {
+               if (asoc_component_prefix)
+                       wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
+                                                     cirrus_dir, system_name,
+                                                     asoc_component_prefix, "bin");
+
+               if (!*coeff_firmware)
+                       wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
+                                                     cirrus_dir, system_name,
+                                                     NULL, "bin");
+
+               if (*coeff_firmware)
+                       return 0;
+       }
+
+       /* Check legacy location */
        if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
                                           "", NULL, NULL, "wmfw")) {
                wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
@@ -830,62 +853,28 @@ static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
                return 0;
        }
 
+       /* Fall back to generic wmfw and optional matching bin */
        ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
                                            cirrus_dir, NULL, NULL, "wmfw");
-       if (!ret) {
+       if (!ret || dsp->wmfw_optional) {
                wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
                                              cirrus_dir, NULL, NULL, "bin");
                return 0;
        }
 
-       if (dsp->wmfw_optional) {
-               if (system_name) {
-                       if (asoc_component_prefix)
-                               wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
-                                                             cirrus_dir, system_name,
-                                                             asoc_component_prefix, "bin");
-
-                       if (!*coeff_firmware)
-                               wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
-                                                             cirrus_dir, system_name,
-                                                             NULL, "bin");
-               }
-
-               if (!*coeff_firmware)
-                       wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
-                                                     "", NULL, NULL, "bin");
-
-               if (!*coeff_firmware)
-                       wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
-                                                     cirrus_dir, NULL, NULL, "bin");
-
-               return 0;
-       }
-
        adsp_err(dsp, "Failed to request firmware <%s>%s-%s-%s<-%s<%s>>.wmfw\n",
-                cirrus_dir, dsp->part, dsp->fwf_name, wm_adsp_fw[dsp->fw].file,
-                system_name, asoc_component_prefix);
+                cirrus_dir, dsp->part,
+                dsp->fwf_name ? dsp->fwf_name : dsp->cs_dsp.name,
+                wm_adsp_fw[dsp->fw].file, system_name, asoc_component_prefix);
 
        return -ENOENT;
 }
 
 static int wm_adsp_common_init(struct wm_adsp *dsp)
 {
-       char *p;
-
        INIT_LIST_HEAD(&dsp->compr_list);
        INIT_LIST_HEAD(&dsp->buffer_list);
 
-       if (!dsp->fwf_name) {
-               p = devm_kstrdup(dsp->cs_dsp.dev, dsp->cs_dsp.name, GFP_KERNEL);
-               if (!p)
-                       return -ENOMEM;
-
-               dsp->fwf_name = p;
-               for (; *p != 0; ++p)
-                       *p = tolower(*p);
-       }
-
        return 0;
 }
 
index cb83c569e18d6aef70b23a56198dbf5ccd5ef2d8..a2e86ef7d18f5981b4604372e4b20930695aa5c4 100644 (file)
@@ -1098,7 +1098,11 @@ static int wsa_dev_mode_put(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
-static const DECLARE_TLV_DB_SCALE(pa_gain, -300, 150, -300);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(pa_gain,
+       0, 14, TLV_DB_SCALE_ITEM(-300, 0, 0),
+       15, 29, TLV_DB_SCALE_ITEM(-300, 150, 0),
+       30, 31, TLV_DB_SCALE_ITEM(1800, 0, 0),
+);
 
 static int wsa883x_get_swr_port(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
index ed4bb551bfbb92c965eba25c048ce4fa12648283..b7fd503a166668d3fe41500bf52e58de129c92de 100644 (file)
@@ -32,12 +32,14 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
        case WSA_CODEC_DMA_RX_0:
        case WSA_CODEC_DMA_RX_1:
                /*
-                * set limit of 0dB on Digital Volume for Speakers,
-                * this can prevent damage of speakers to some extent without
-                * active speaker protection
+                * Set limit of -3 dB on Digital Volume and 0 dB on PA Volume
+                * to reduce the risk of speaker damage until we have active
+                * speaker protection in place.
                 */
-               snd_soc_limit_volume(card, "WSA_RX0 Digital Volume", 84);
-               snd_soc_limit_volume(card, "WSA_RX1 Digital Volume", 84);
+               snd_soc_limit_volume(card, "WSA_RX0 Digital Volume", 81);
+               snd_soc_limit_volume(card, "WSA_RX1 Digital Volume", 81);
+               snd_soc_limit_volume(card, "SpkrLeft PA Volume", 17);
+               snd_soc_limit_volume(card, "SpkrRight PA Volume", 17);
                break;
        default:
                break;
index f8524b5bfb330652afb48091b7afab12b1a70d6e..516350533e73f8ee1084164e44068f825eb7fafe 100644 (file)
@@ -1037,7 +1037,7 @@ component_dai_empty:
        return -EINVAL;
 }
 
-#define MAX_DEFAULT_CH_MAP_SIZE 7
+#define MAX_DEFAULT_CH_MAP_SIZE 8
 static struct snd_soc_dai_link_ch_map default_ch_map_sync[MAX_DEFAULT_CH_MAP_SIZE] = {
        { .cpu = 0, .codec = 0 },
        { .cpu = 1, .codec = 1 },
@@ -1046,6 +1046,7 @@ static struct snd_soc_dai_link_ch_map default_ch_map_sync[MAX_DEFAULT_CH_MAP_SIZ
        { .cpu = 4, .codec = 4 },
        { .cpu = 5, .codec = 5 },
        { .cpu = 6, .codec = 6 },
+       { .cpu = 7, .codec = 7 },
 };
 static struct snd_soc_dai_link_ch_map default_ch_map_1cpu[MAX_DEFAULT_CH_MAP_SIZE] = {
        { .cpu = 0, .codec = 0 },
@@ -1055,6 +1056,7 @@ static struct snd_soc_dai_link_ch_map default_ch_map_1cpu[MAX_DEFAULT_CH_MAP_SIZ
        { .cpu = 0, .codec = 4 },
        { .cpu = 0, .codec = 5 },
        { .cpu = 0, .codec = 6 },
+       { .cpu = 0, .codec = 7 },
 };
 static struct snd_soc_dai_link_ch_map default_ch_map_1codec[MAX_DEFAULT_CH_MAP_SIZE] = {
        { .cpu = 0, .codec = 0 },
@@ -1064,6 +1066,7 @@ static struct snd_soc_dai_link_ch_map default_ch_map_1codec[MAX_DEFAULT_CH_MAP_S
        { .cpu = 4, .codec = 0 },
        { .cpu = 5, .codec = 0 },
        { .cpu = 6, .codec = 0 },
+       { .cpu = 7, .codec = 0 },
 };
 static int snd_soc_compensate_channel_connection_map(struct snd_soc_card *card,
                                                     struct snd_soc_dai_link *dai_link)
index 702386823d17263ffa6acacb6d0bd71adb7c83d9..f41c309558579f1c3c4b1d0e7bcca1b2e64d8747 100644 (file)
@@ -577,6 +577,11 @@ static const struct of_device_id sun4i_spdif_of_match[] = {
                .compatible = "allwinner,sun50i-h6-spdif",
                .data = &sun50i_h6_spdif_quirks,
        },
+       {
+               .compatible = "allwinner,sun50i-h616-spdif",
+               /* Essentially the same as the H6, but without RX */
+               .data = &sun50i_h6_spdif_quirks,
+       },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
index 33db334e6556674414047b1a1d660ec3e8083100..60fcb872a80b6c1f79afcec88e959df33a04a4da 100644 (file)
@@ -261,6 +261,8 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
        int ret, i, cur, err, pins, clock_id;
        const u8 *sources;
        int proto = fmt->protocol;
+       bool readable, writeable;
+       u32 bmControls;
 
        entity_id &= 0xff;
 
@@ -292,11 +294,27 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
                sources = GET_VAL(selector, proto, baCSourceID);
                cur = 0;
 
+               if (proto == UAC_VERSION_3)
+                       bmControls = le32_to_cpu(*(__le32 *)(&selector->v3.baCSourceID[0] + pins));
+               else
+                       bmControls = *(__u8 *)(&selector->v2.baCSourceID[0] + pins);
+
+               readable = uac_v2v3_control_is_readable(bmControls,
+                                                       UAC2_CX_CLOCK_SELECTOR);
+               writeable = uac_v2v3_control_is_writeable(bmControls,
+                                                         UAC2_CX_CLOCK_SELECTOR);
+
                if (pins == 1) {
                        ret = 1;
                        goto find_source;
                }
 
+               /* for now just warn about buggy device */
+               if (!readable)
+                       usb_audio_warn(chip,
+                               "%s(): clock selector control is not readable, id %d\n",
+                               __func__, clock_id);
+
                /* the entity ID we are looking at is a selector.
                 * find out what it currently selects */
                ret = uac_clock_selector_get_val(chip, clock_id);
@@ -325,17 +343,29 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
                                              visited, validate);
                if (ret > 0) {
                        /* Skip setting clock selector again for some devices */
-                       if (chip->quirk_flags & QUIRK_FLAG_SKIP_CLOCK_SELECTOR)
+                       if (chip->quirk_flags & QUIRK_FLAG_SKIP_CLOCK_SELECTOR ||
+                           !writeable)
                                return ret;
                        err = uac_clock_selector_set_val(chip, entity_id, cur);
-                       if (err < 0)
+                       if (err < 0) {
+                               if (pins == 1) {
+                                       usb_audio_dbg(chip,
+                                                     "%s(): selector returned an error, "
+                                                     "assuming a firmware bug, id %d, ret %d\n",
+                                                     __func__, clock_id, err);
+                                       return ret;
+                               }
                                return err;
+                       }
                }
 
                if (!validate || ret > 0 || !chip->autoclock)
                        return ret;
 
        find_others:
+               if (!writeable)
+                       return -ENXIO;
+
                /* The current clock source is invalid, try others. */
                for (i = 1; i <= pins; i++) {
                        if (i == cur)
index ab5fed9f55b60ec8b255448a9cbb435f9e04d96b..3b45d0ee769389aafb3e752cec5b96223c52077b 100644 (file)
@@ -470,9 +470,11 @@ static int validate_sample_rate_table_v2v3(struct snd_usb_audio *chip,
                                           int clock)
 {
        struct usb_device *dev = chip->dev;
+       struct usb_host_interface *alts;
        unsigned int *table;
        unsigned int nr_rates;
        int i, err;
+       u32 bmControls;
 
        /* performing the rate verification may lead to unexpected USB bus
         * behavior afterwards by some unknown reason.  Do this only for the
@@ -481,6 +483,24 @@ static int validate_sample_rate_table_v2v3(struct snd_usb_audio *chip,
        if (!(chip->quirk_flags & QUIRK_FLAG_VALIDATE_RATES))
                return 0; /* don't perform the validation as default */
 
+       alts = snd_usb_get_host_interface(chip, fp->iface, fp->altsetting);
+       if (!alts)
+               return 0;
+
+       if (fp->protocol == UAC_VERSION_3) {
+               struct uac3_as_header_descriptor *as = snd_usb_find_csint_desc(
+                               alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
+               bmControls = le32_to_cpu(as->bmControls);
+       } else {
+               struct uac2_as_header_descriptor *as = snd_usb_find_csint_desc(
+                               alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
+               bmControls = as->bmControls;
+       }
+
+       if (!uac_v2v3_control_is_readable(bmControls,
+                               UAC2_AS_VAL_ALT_SETTINGS))
+               return 0;
+
        table = kcalloc(fp->nr_rates, sizeof(*table), GFP_KERNEL);
        if (!table)
                return -ENOMEM;
index 1ec177fe284eddd7eb431d56083e82886c858550..820d3e4b672ab603b6f2cb91ba95d12b60d519f5 100644 (file)
@@ -1085,7 +1085,7 @@ int snd_usb_midi_v2_create(struct snd_usb_audio *chip,
        }
        if ((quirk && quirk->type != QUIRK_MIDI_STANDARD_INTERFACE) ||
            iface->num_altsetting < 2) {
-               usb_audio_info(chip, "Quirk or no altest; falling back to MIDI 1.0\n");
+               usb_audio_info(chip, "Quirk or no altset; falling back to MIDI 1.0\n");
                goto fallback_to_midi1;
        }
        hostif = &iface->altsetting[1];
index 07cc6a201579aa864f6ebd113d638cf4a36153d8..09712e61c606ef21c2b39bb80b8906a70f6ed4ff 100644 (file)
@@ -2031,10 +2031,14 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_IGNORE_CTL_ERROR),
        DEVICE_FLG(0x0499, 0x1509, /* Steinberg UR22 */
                   QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+       DEVICE_FLG(0x0499, 0x3108, /* Yamaha YIT-W12TX */
+                  QUIRK_FLAG_GET_SAMPLE_RATE),
        DEVICE_FLG(0x04d8, 0xfeea, /* Benchmark DAC1 Pre */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
        DEVICE_FLG(0x04e8, 0xa051, /* Samsung USBC Headset (AKG) */
                   QUIRK_FLAG_SKIP_CLOCK_SELECTOR | QUIRK_FLAG_CTL_MSG_DELAY_5M),
+       DEVICE_FLG(0x0525, 0xa4ad, /* Hamedal C20 usb camero */
+                  QUIRK_FLAG_IFACE_SKIP_CLOSE),
        DEVICE_FLG(0x054c, 0x0b8c, /* Sony WALKMAN NW-A45 DAC */
                   QUIRK_FLAG_SET_IFACE_FIRST),
        DEVICE_FLG(0x0556, 0x0014, /* Phoenix Audio TMX320VC */
@@ -2073,14 +2077,22 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_GENERIC_IMPLICIT_FB),
        DEVICE_FLG(0x0763, 0x2031, /* M-Audio Fast Track C600 */
                   QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+       DEVICE_FLG(0x07fd, 0x000b, /* MOTU M Series 2nd hardware revision */
+                  QUIRK_FLAG_CTL_MSG_DELAY_1M),
        DEVICE_FLG(0x08bb, 0x2702, /* LineX FM Transmitter */
                   QUIRK_FLAG_IGNORE_CTL_ERROR),
        DEVICE_FLG(0x0951, 0x16ad, /* Kingston HyperX */
                   QUIRK_FLAG_CTL_MSG_DELAY_1M),
        DEVICE_FLG(0x0b0e, 0x0349, /* Jabra 550a */
                   QUIRK_FLAG_CTL_MSG_DELAY_1M),
+       DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */
+                  QUIRK_FLAG_FIXED_RATE),
+       DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */
+                  QUIRK_FLAG_FIXED_RATE),
        DEVICE_FLG(0x0fd9, 0x0008, /* Hauppauge HVR-950Q */
                   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+       DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */
+                  QUIRK_FLAG_GET_SAMPLE_RATE),
        DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
        DEVICE_FLG(0x1397, 0x0507, /* Behringer UMC202HD */
@@ -2113,6 +2125,10 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY),
        DEVICE_FLG(0x1901, 0x0191, /* GE B850V3 CP2114 audio interface */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
+       DEVICE_FLG(0x19f7, 0x0035, /* RODE NT-USB+ */
+                  QUIRK_FLAG_GET_SAMPLE_RATE),
+       DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */
+                  QUIRK_FLAG_GET_SAMPLE_RATE),
        DEVICE_FLG(0x2040, 0x7200, /* Hauppauge HVR-950Q */
                   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
        DEVICE_FLG(0x2040, 0x7201, /* Hauppauge HVR-950Q-MXL */
@@ -2155,6 +2171,12 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_IGNORE_CTL_ERROR),
        DEVICE_FLG(0x2912, 0x30c8, /* Audioengine D1 */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
+       DEVICE_FLG(0x2b53, 0x0023, /* Fiero SC-01 (firmware v1.0.0 @ 48 kHz) */
+                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+       DEVICE_FLG(0x2b53, 0x0024, /* Fiero SC-01 (firmware v1.0.0 @ 96 kHz) */
+                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+       DEVICE_FLG(0x2b53, 0x0031, /* Fiero SC-01 (firmware v1.1.0) */
+                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
        DEVICE_FLG(0x30be, 0x0101, /* Schiit Hel */
                   QUIRK_FLAG_IGNORE_CTL_ERROR),
        DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */
@@ -2163,22 +2185,6 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_ALIGN_TRANSFER),
        DEVICE_FLG(0x534d, 0x2109, /* MacroSilicon MS2109 */
                   QUIRK_FLAG_ALIGN_TRANSFER),
-       DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */
-                  QUIRK_FLAG_GET_SAMPLE_RATE),
-       DEVICE_FLG(0x2b53, 0x0023, /* Fiero SC-01 (firmware v1.0.0 @ 48 kHz) */
-                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
-       DEVICE_FLG(0x2b53, 0x0024, /* Fiero SC-01 (firmware v1.0.0 @ 96 kHz) */
-                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
-       DEVICE_FLG(0x2b53, 0x0031, /* Fiero SC-01 (firmware v1.1.0) */
-                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
-       DEVICE_FLG(0x0525, 0xa4ad, /* Hamedal C20 usb camero */
-                  QUIRK_FLAG_IFACE_SKIP_CLOSE),
-       DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */
-                  QUIRK_FLAG_FIXED_RATE),
-       DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */
-                  QUIRK_FLAG_FIXED_RATE),
-       DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */
-                  QUIRK_FLAG_GET_SAMPLE_RATE),
 
        /* Vendor matches */
        VENDOR_FLG(0x045e, /* MS Lifecam */
index e2847c040f750f98a77cb0bfe4ec2a548f5eb691..b158c3cb8e5f5fce75e22306c7707935465bc57f 100644 (file)
@@ -91,8 +91,6 @@ static void virtsnd_event_notify_cb(struct virtqueue *vqueue)
                        virtsnd_event_dispatch(snd, event);
                        virtsnd_event_send(vqueue, event, true, GFP_ATOMIC);
                }
-               if (unlikely(virtqueue_is_broken(vqueue)))
-                       break;
        } while (!virtqueue_enable_cb(vqueue));
        spin_unlock_irqrestore(&queue->lock, flags);
 }
index 18dc5aca2e0c5b2a1e6c0d4391b34865b797995e..9dabea01277f845726ee2a908b9288c9f0e5e918 100644 (file)
@@ -303,8 +303,6 @@ void virtsnd_ctl_notify_cb(struct virtqueue *vqueue)
                virtqueue_disable_cb(vqueue);
                while ((msg = virtqueue_get_buf(vqueue, &length)))
                        virtsnd_ctl_msg_complete(msg);
-               if (unlikely(virtqueue_is_broken(vqueue)))
-                       break;
        } while (!virtqueue_enable_cb(vqueue));
        spin_unlock_irqrestore(&queue->lock, flags);
 }
index 542446c4c7ba8e4da2d7dd5b701c829e45c24084..8c32efaf4c5294e6aba0adcfb8a40a22d3a0d261 100644 (file)
@@ -358,8 +358,6 @@ static inline void virtsnd_pcm_notify_cb(struct virtio_snd_queue *queue)
                virtqueue_disable_cb(queue->vqueue);
                while ((msg = virtqueue_get_buf(queue->vqueue, &written_bytes)))
                        virtsnd_pcm_msg_complete(msg, written_bytes);
-               if (unlikely(virtqueue_is_broken(queue->vqueue)))
-                       break;
        } while (!virtqueue_enable_cb(queue->vqueue));
        spin_unlock_irqrestore(&queue->lock, flags);
 }
index d9d9923af85c2e60ca9b2161fd93867df3346d1b..a4b902f9e1c486801a7c14072e796a1b1f8e92ad 100644 (file)
@@ -15,7 +15,7 @@ LIBS = -L../ -L$(OUTPUT) -lm -lcpupower
 OBJS = $(OUTPUT)main.o $(OUTPUT)parse.o $(OUTPUT)system.o $(OUTPUT)benchmark.o
 endif
 
-CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\"
+override CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\"
 
 $(OUTPUT)%.o : %.c
        $(ECHO) "  CC      " $@
index 0b12c36902d82ddf23d8d71ac5067e282f1b1564..caff3834671f9dfb7d261d5b6633532f71ecd9f5 100644 (file)
@@ -65,4 +65,6 @@ cxl_core-y += config_check.o
 cxl_core-y += cxl_core_test.o
 cxl_core-y += cxl_core_exports.o
 
+KBUILD_CFLAGS := $(filter-out -Wmissing-prototypes -Wmissing-declarations, $(KBUILD_CFLAGS))
+
 obj-m += test/
index 61d5f7bcddf9a6ef9d5df5d0c4346bd93f7181f9..6b192789785612d810c6ff577b1ac47aadd9e9b3 100644 (file)
@@ -8,3 +8,5 @@ obj-m += cxl_mock_mem.o
 cxl_test-y := cxl.o
 cxl_mock-y := mock.o
 cxl_mock_mem-y := mem.o
+
+KBUILD_CFLAGS := $(filter-out -Wmissing-prototypes -Wmissing-declarations, $(KBUILD_CFLAGS))
index 8153251ea389a7dcff59d13f258cee0b066c7dbf..91a3627f301a79b90036c2cfd82217819b9bb757 100644 (file)
@@ -82,4 +82,6 @@ libnvdimm-$(CONFIG_NVDIMM_KEYS) += $(NVDIMM_SRC)/security.o
 libnvdimm-y += libnvdimm_test.o
 libnvdimm-y += config_check.o
 
+KBUILD_CFLAGS := $(filter-out -Wmissing-prototypes -Wmissing-declarations, $(KBUILD_CFLAGS))
+
 obj-m += test/
index 2a268b17b61f515b5c50a1fdbe3d7ae21af00578..dbdd736a41d394c9a6e2897d971eb31e728eae34 100644 (file)
@@ -48,6 +48,17 @@ test_LAG_cleanup()
        ip link add mv0 link "$name" up address "$ucaddr" type macvlan
        # Used to test dev->mc handling
        ip address add "$addr6" dev "$name"
+
+       # Check that addresses were added as expected
+       (grep_bridge_fdb "$ucaddr" bridge fdb show dev dummy1 ||
+               grep_bridge_fdb "$ucaddr" bridge fdb show dev dummy2) >/dev/null
+       check_err $? "macvlan unicast address not found on a slave"
+
+       # mcaddr is added asynchronously by addrconf_dad_work(), use busywait
+       (busywait 10000 grep_bridge_fdb "$mcaddr" bridge fdb show dev dummy1 ||
+               grep_bridge_fdb "$mcaddr" bridge fdb show dev dummy2) >/dev/null
+       check_err $? "IPv6 solicited-node multicast mac address not found on a slave"
+
        ip link set dev "$name" down
        ip link del "$name"
 
index 265b6882cc21ed0c285ae9f37f9282bfb2e440d1..b5e3a3aad4bfbb5f1d77b4fd1bd4ae566f6394a1 100644 (file)
@@ -1,3 +1,5 @@
+CONFIG_DUMMY=y
+CONFIG_IPV6=y
+CONFIG_MACVLAN=y
 CONFIG_NET_TEAM=y
 CONFIG_NET_TEAM_MODE_LOADBALANCE=y
-CONFIG_MACVLAN=y
index 352fc39f3c6c160bfdcd2b3c655bfe319f00892c..b62c7dba6777f975dd9158f6788a6177307bc9e4 100644 (file)
@@ -880,8 +880,8 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
         does not overlap with other contacts. The value of `t` may be
         incremented over time to move the point along a linear path.
         """
-        x = 50 + 10 * contact_id + t
-        y = 100 + 100 * contact_id + t
+        x = 50 + 10 * contact_id + t * 11
+        y = 100 + 100 * contact_id + t * 11
         return test_multitouch.Touch(contact_id, x, y)
 
     def make_contacts(self, n, t=0):
@@ -902,8 +902,8 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
         tracking_id = contact_ids.tracking_id
         slot_num = contact_ids.slot_num
 
-        x = 50 + 10 * contact_id + t
-        y = 100 + 100 * contact_id + t
+        x = 50 + 10 * contact_id + t * 11
+        y = 100 + 100 * contact_id + t * 11
 
         # If the data isn't supposed to be stored in any slots, there is
         # nothing we can check for in the evdev stream.
index c8416c54b4637b1380810f0c9f71bc99e1710b8e..b1fd7362c2feec339228036dace5d28fe1b1719b 100644 (file)
@@ -42,17 +42,6 @@ function die() {
        exit 1
 }
 
-# save existing dmesg so we can detect new content
-function save_dmesg() {
-       SAVED_DMESG=$(mktemp --tmpdir -t klp-dmesg-XXXXXX)
-       dmesg > "$SAVED_DMESG"
-}
-
-# cleanup temporary dmesg file from save_dmesg()
-function cleanup_dmesg_file() {
-       rm -f "$SAVED_DMESG"
-}
-
 function push_config() {
        DYNAMIC_DEBUG=$(grep '^kernel/livepatch' /sys/kernel/debug/dynamic_debug/control | \
                        awk -F'[: ]' '{print "file " $1 " line " $2 " " $4}')
@@ -99,7 +88,6 @@ function set_ftrace_enabled() {
 
 function cleanup() {
        pop_config
-       cleanup_dmesg_file
 }
 
 # setup_config - save the current config and set a script exit trap that
@@ -280,7 +268,15 @@ function set_pre_patch_ret {
 function start_test {
        local test="$1"
 
-       save_dmesg
+       # Dump something unique into the dmesg log, then stash the entry
+       # in LAST_DMESG.  The check_result() function will use it to
+       # find new kernel messages since the test started.
+       local last_dmesg_msg="livepatch kselftest timestamp: $(date --rfc-3339=ns)"
+       log "$last_dmesg_msg"
+       loop_until 'dmesg | grep -q "$last_dmesg_msg"' ||
+               die "buffer busy? can't find canary dmesg message: $last_dmesg_msg"
+       LAST_DMESG=$(dmesg | grep "$last_dmesg_msg")
+
        echo -n "TEST: $test ... "
        log "===== TEST: $test ====="
 }
@@ -291,23 +287,24 @@ function check_result {
        local expect="$*"
        local result
 
-       # Note: when comparing dmesg output, the kernel log timestamps
-       # help differentiate repeated testing runs.  Remove them with a
-       # post-comparison sed filter.
-
-       result=$(dmesg | comm --nocheck-order -13 "$SAVED_DMESG" - | \
+       # Test results include any new dmesg entry since LAST_DMESG, then:
+       # - include lines matching keywords
+       # - exclude lines matching keywords
+       # - filter out dmesg timestamp prefixes
+       result=$(dmesg | awk -v last_dmesg="$LAST_DMESG" 'p; $0 == last_dmesg { p=1 }' | \
                 grep -e 'livepatch:' -e 'test_klp' | \
                 grep -v '\(tainting\|taints\) kernel' | \
                 sed 's/^\[[ 0-9.]*\] //')
 
        if [[ "$expect" == "$result" ]] ; then
                echo "ok"
+       elif [[ "$result" == "" ]] ; then
+               echo -e "not ok\n\nbuffer overrun? can't find canary dmesg entry: $LAST_DMESG\n"
+               die "livepatch kselftest(s) failed"
        else
                echo -e "not ok\n\n$(diff -upr --label expected --label result <(echo "$expect") <(echo "$result"))\n"
                die "livepatch kselftest(s) failed"
        fi
-
-       cleanup_dmesg_file
 }
 
 # check_sysfs_rights(modname, rel_path, expected_rights) - check sysfs
index 0899019a7fcb4b04bcedca44227f2c2dd5a83597..e14bdd4455f2d2798077b8a701790bcee0732e90 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 # SPDX-License-Identifier: GPL-2.0
 
 # Kselftest framework requirement - SKIP code is 4.
index 380b691d3eb9fbe9c1070937d9561b732343aec0..b748c48908d9d4af9ba31fe7d2443329c13c3dc2 100644 (file)
@@ -566,7 +566,7 @@ static int ksm_merge_hugepages_time(int merge_type, int mapping, int prot,
        if (map_ptr_orig == MAP_FAILED)
                err(2, "initial mmap");
 
-       if (madvise(map_ptr, len + HPAGE_SIZE, MADV_HUGEPAGE))
+       if (madvise(map_ptr, len, MADV_HUGEPAGE))
                err(2, "MADV_HUGEPAGE");
 
        pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
index 193281560b61be23d3b55857030ea07b4ad3f95d..86e8f2048a409028b28ece3f755d06f535726c47 100644 (file)
@@ -15,6 +15,7 @@
 #include <unistd.h>
 #include <sys/mman.h>
 #include <fcntl.h>
+#include "vm_util.h"
 
 #define LENGTH (256UL*1024*1024)
 #define PROTECTION (PROT_READ | PROT_WRITE)
@@ -58,10 +59,16 @@ int main(int argc, char **argv)
 {
        void *addr;
        int ret;
+       size_t hugepage_size;
        size_t length = LENGTH;
        int flags = FLAGS;
        int shift = 0;
 
+       hugepage_size = default_huge_page_size();
+       /* munmap with fail if the length is not page aligned */
+       if (hugepage_size > length)
+               length = hugepage_size;
+
        if (argc > 1)
                length = atol(argv[1]) << 20;
        if (argc > 2) {
index 1d4c1589c3055d3bb22eebe2c02fa7b015e4a665..2f8b991f78cb4cade90dc05f502a647a955fb582 100644 (file)
@@ -360,7 +360,8 @@ static long long remap_region(struct config c, unsigned int threshold_mb,
                              char pattern_seed)
 {
        void *addr, *src_addr, *dest_addr, *dest_preamble_addr;
-       unsigned long long i;
+       int d;
+       unsigned long long t;
        struct timespec t_start = {0, 0}, t_end = {0, 0};
        long long  start_ns, end_ns, align_mask, ret, offset;
        unsigned long long threshold;
@@ -378,8 +379,8 @@ static long long remap_region(struct config c, unsigned int threshold_mb,
 
        /* Set byte pattern for source block. */
        srand(pattern_seed);
-       for (i = 0; i < threshold; i++)
-               memset((char *) src_addr + i, (char) rand(), 1);
+       for (t = 0; t < threshold; t++)
+               memset((char *) src_addr + t, (char) rand(), 1);
 
        /* Mask to zero out lower bits of address for alignment */
        align_mask = ~(c.dest_alignment - 1);
@@ -420,8 +421,8 @@ static long long remap_region(struct config c, unsigned int threshold_mb,
 
                /* Set byte pattern for the dest preamble block. */
                srand(pattern_seed);
-               for (i = 0; i < c.dest_preamble_size; i++)
-                       memset((char *) dest_preamble_addr + i, (char) rand(), 1);
+               for (d = 0; d < c.dest_preamble_size; d++)
+                       memset((char *) dest_preamble_addr + d, (char) rand(), 1);
        }
 
        clock_gettime(CLOCK_MONOTONIC, &t_start);
@@ -437,14 +438,14 @@ static long long remap_region(struct config c, unsigned int threshold_mb,
 
        /* Verify byte pattern after remapping */
        srand(pattern_seed);
-       for (i = 0; i < threshold; i++) {
+       for (t = 0; t < threshold; t++) {
                char c = (char) rand();
 
-               if (((char *) dest_addr)[i] != c) {
+               if (((char *) dest_addr)[t] != c) {
                        ksft_print_msg("Data after remap doesn't match at offset %llu\n",
-                                      i);
+                                      t);
                        ksft_print_msg("Expected: %#x\t Got: %#x\n", c & 0xff,
-                                       ((char *) dest_addr)[i] & 0xff);
+                                       ((char *) dest_addr)[t] & 0xff);
                        ret = -1;
                        goto clean_up_dest;
                }
@@ -453,14 +454,14 @@ static long long remap_region(struct config c, unsigned int threshold_mb,
        /* Verify the dest preamble byte pattern after remapping */
        if (c.dest_preamble_size) {
                srand(pattern_seed);
-               for (i = 0; i < c.dest_preamble_size; i++) {
+               for (d = 0; d < c.dest_preamble_size; d++) {
                        char c = (char) rand();
 
-                       if (((char *) dest_preamble_addr)[i] != c) {
+                       if (((char *) dest_preamble_addr)[d] != c) {
                                ksft_print_msg("Preamble data after remap doesn't match at offset %d\n",
-                                              i);
+                                              d);
                                ksft_print_msg("Expected: %#x\t Got: %#x\n", c & 0xff,
-                                              ((char *) dest_preamble_addr)[i] & 0xff);
+                                              ((char *) dest_preamble_addr)[d] & 0xff);
                                ret = -1;
                                goto clean_up_dest;
                        }
index 45cae7cab27e12705c59cc56f6fdf5e675805f92..a0a75f3029043727b96bdb59728ed80d4d5cd9c0 100755 (executable)
@@ -29,9 +29,15 @@ check_supported_x86_64()
        # See man 1 gzip under '-f'.
        local pg_table_levels=$(gzip -dcfq "${config}" | grep PGTABLE_LEVELS | cut -d'=' -f 2)
 
+       local cpu_supports_pl5=$(awk '/^flags/ {if (/la57/) {print 0;}
+               else {print 1}; exit}' /proc/cpuinfo 2>/dev/null)
+
        if [[ "${pg_table_levels}" -lt 5 ]]; then
                echo "$0: PGTABLE_LEVELS=${pg_table_levels}, must be >= 5 to run this test"
                exit $ksft_skip
+       elif [[ "${cpu_supports_pl5}" -ne 0 ]]; then
+               echo "$0: CPU does not have the necessary la57 flag to support page table level 5"
+               exit $ksft_skip
        fi
 }
 
index 70a02301f4c276ba6313c3baa1ab3b5058a68b0c..3d2d2eb9d6fff077cca24fd82a2a4990c34706d1 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 # SPDX-License-Identifier: GPL-2.0
 
 set -e
index 50818075e566e1abf1f2f9e587951e5abed238fc..211753756bdee87daf7ebb1af06dbb4c1f6ee383 100644 (file)
@@ -53,8 +53,7 @@ TEST_PROGS += bind_bhash.sh
 TEST_PROGS += ip_local_port_range.sh
 TEST_PROGS += rps_default_mask.sh
 TEST_PROGS += big_tcp.sh
-TEST_PROGS_EXTENDED := in_netns.sh setup_loopback.sh setup_veth.sh
-TEST_PROGS_EXTENDED += toeplitz_client.sh toeplitz.sh lib.sh
+TEST_PROGS_EXTENDED := toeplitz_client.sh toeplitz.sh
 TEST_GEN_FILES =  socket nettest
 TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy reuseport_addr_any
 TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd txring_overwrite
@@ -84,6 +83,7 @@ TEST_PROGS += sctp_vrf.sh
 TEST_GEN_FILES += sctp_hello
 TEST_GEN_FILES += csum
 TEST_GEN_FILES += nat6to4.o
+TEST_GEN_FILES += xdp_dummy.o
 TEST_GEN_FILES += ip_local_port_range
 TEST_GEN_FILES += bind_wildcard
 TEST_PROGS += test_vxlan_mdb.sh
@@ -95,6 +95,7 @@ TEST_PROGS += fq_band_pktlimit.sh
 TEST_PROGS += vlan_hw_filter.sh
 
 TEST_FILES := settings
+TEST_FILES += in_netns.sh lib.sh net_helper.sh setup_loopback.sh setup_veth.sh
 
 include ../lib.mk
 
@@ -104,7 +105,7 @@ $(OUTPUT)/tcp_inq: LDLIBS += -lpthread
 $(OUTPUT)/bind_bhash: LDLIBS += -lpthread
 $(OUTPUT)/io_uring_zerocopy_tx: CFLAGS += -I../../../include/
 
-# Rules to generate bpf obj nat6to4.o
+# Rules to generate bpf objs
 CLANG ?= clang
 SCRATCH_DIR := $(OUTPUT)/tools
 BUILD_DIR := $(SCRATCH_DIR)/build
@@ -139,7 +140,7 @@ endif
 
 CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG),$(CLANG_TARGET_ARCH))
 
-$(OUTPUT)/nat6to4.o: nat6to4.c $(BPFOBJ) | $(MAKE_DIRS)
+$(OUTPUT)/nat6to4.o $(OUTPUT)/xdp_dummy.o: $(OUTPUT)/%.o : %.c $(BPFOBJ) | $(MAKE_DIRS)
        $(CLANG) -O2 --target=bpf -c $< $(CCINCLUDE) $(CLANG_SYS_INCLUDES) -o $@
 
 $(BPFOBJ): $(wildcard $(BPFDIR)/*.[ch] $(BPFDIR)/Makefile)                    \
index 19ff7505166096483d79709676c03eb8a9135fc5..3b749addd364040491010ab9d4b50a19c4e3b643 100644 (file)
@@ -19,8 +19,11 @@ CONFIG_BRIDGE_VLAN_FILTERING=y
 CONFIG_BRIDGE=y
 CONFIG_CRYPTO_CHACHA20POLY1305=m
 CONFIG_VLAN_8021Q=y
+CONFIG_GENEVE=m
 CONFIG_IFB=y
 CONFIG_INET_DIAG=y
+CONFIG_INET_ESP=y
+CONFIG_INET_ESP_OFFLOAD=y
 CONFIG_IP_GRE=m
 CONFIG_NETFILTER=y
 CONFIG_NETFILTER_ADVANCED=y
@@ -29,7 +32,10 @@ CONFIG_NF_NAT=m
 CONFIG_IP6_NF_IPTABLES=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP6_NF_NAT=m
+CONFIG_IP6_NF_RAW=m
 CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_TTL=m
 CONFIG_IPV6_GRE=m
 CONFIG_IPV6_SEG6_LWTUNNEL=y
 CONFIG_L2TP_ETH=m
@@ -45,8 +51,14 @@ CONFIG_NF_TABLES=m
 CONFIG_NF_TABLES_IPV6=y
 CONFIG_NF_TABLES_IPV4=y
 CONFIG_NFT_NAT=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NET_ACT_CSUM=m
+CONFIG_NET_ACT_CT=m
 CONFIG_NET_ACT_GACT=m
+CONFIG_NET_ACT_PEDIT=m
 CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_BPF=m
+CONFIG_NET_CLS_MATCHALL=m
 CONFIG_NET_CLS_U32=m
 CONFIG_NET_IPGRE_DEMUX=m
 CONFIG_NET_IPGRE=m
@@ -55,6 +67,9 @@ CONFIG_NET_SCH_HTB=m
 CONFIG_NET_SCH_FQ=m
 CONFIG_NET_SCH_ETF=m
 CONFIG_NET_SCH_NETEM=y
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NFT_COMPAT=m
+CONFIG_NF_FLOW_TABLE=m
 CONFIG_PSAMPLE=m
 CONFIG_TCP_MD5SIG=y
 CONFIG_TEST_BLACKHOLE_DEV=m
@@ -80,3 +95,4 @@ CONFIG_IP_SCTP=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
 CONFIG_CRYPTO_ARIA=y
 CONFIG_XFRM_INTERFACE=m
+CONFIG_XFRM_USER=m
index 452693514be4b06842dbe32088c5495c2c933f0b..4de92632f48360c0002900260af9b35d34186f4b 100644 (file)
@@ -112,7 +112,7 @@ TEST_PROGS = bridge_fdb_learning_limit.sh \
        vxlan_symmetric_ipv6.sh \
        vxlan_symmetric.sh
 
-TEST_PROGS_EXTENDED := devlink_lib.sh \
+TEST_FILES := devlink_lib.sh \
        ethtool_lib.sh \
        fib_offload_lib.sh \
        forwarding.config.sample \
index dca549443801135cf8db35f9545885a6ab772504..f9fe182dfbd44e9de0f0caa27b409281c0584081 100644 (file)
@@ -4,6 +4,9 @@
 ##############################################################################
 # Defines
 
+WAIT_TIMEOUT=${WAIT_TIMEOUT:=20}
+BUSYWAIT_TIMEOUT=$((WAIT_TIMEOUT * 1000)) # ms
+
 # Kselftest framework requirement - SKIP code is 4.
 ksft_skip=4
 # namespace list created by setup_ns
@@ -48,7 +51,7 @@ cleanup_ns()
 
        for ns in "$@"; do
                ip netns delete "${ns}" &> /dev/null
-               if ! busywait 2 ip netns list \| grep -vq "^$ns$" &> /dev/null; then
+               if ! busywait $BUSYWAIT_TIMEOUT ip netns list \| grep -vq "^$ns$" &> /dev/null; then
                        echo "Warn: Failed to remove namespace $ns"
                        ret=1
                fi
index e317c2e44dae840149fad7fe14a3a41d699b063e..4f80014cae4940a3f56ebb313349baa8540c0a0a 100644 (file)
@@ -22,8 +22,11 @@ CONFIG_NFT_TPROXY=m
 CONFIG_NFT_SOCKET=m
 CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IP6_NF_FILTER=m
 CONFIG_NET_ACT_CSUM=m
 CONFIG_NET_ACT_PEDIT=m
 CONFIG_NET_CLS_ACT=y
index 3a5b630261910b1cfdd001e05c97c07335b61827..c07386e21e0a4aa10b004cb820488f15ff18dd7a 100755 (executable)
@@ -643,13 +643,6 @@ kill_events_pids()
        mptcp_lib_kill_wait $evts_ns2_pid
 }
 
-kill_tests_wait()
-{
-       #shellcheck disable=SC2046
-       kill -SIGUSR1 $(ip netns pids $ns2) $(ip netns pids $ns1)
-       wait
-}
-
 pm_nl_set_limits()
 {
        local ns=$1
@@ -3453,7 +3446,7 @@ userspace_tests()
                chk_mptcp_info subflows 0 subflows 0
                chk_subflows_total 1 1
                kill_events_pids
-               wait $tests_pid
+               mptcp_lib_kill_wait $tests_pid
        fi
 
        # userspace pm create destroy subflow
@@ -3475,7 +3468,7 @@ userspace_tests()
                chk_mptcp_info subflows 0 subflows 0
                chk_subflows_total 1 1
                kill_events_pids
-               wait $tests_pid
+               mptcp_lib_kill_wait $tests_pid
        fi
 
        # userspace pm create id 0 subflow
@@ -3494,7 +3487,7 @@ userspace_tests()
                chk_mptcp_info subflows 1 subflows 1
                chk_subflows_total 2 2
                kill_events_pids
-               wait $tests_pid
+               mptcp_lib_kill_wait $tests_pid
        fi
 
        # userspace pm remove initial subflow
@@ -3518,7 +3511,7 @@ userspace_tests()
                chk_mptcp_info subflows 1 subflows 1
                chk_subflows_total 1 1
                kill_events_pids
-               wait $tests_pid
+               mptcp_lib_kill_wait $tests_pid
        fi
 
        # userspace pm send RM_ADDR for ID 0
@@ -3544,7 +3537,7 @@ userspace_tests()
                chk_mptcp_info subflows 1 subflows 1
                chk_subflows_total 1 1
                kill_events_pids
-               wait $tests_pid
+               mptcp_lib_kill_wait $tests_pid
        fi
 }
 
@@ -3558,7 +3551,8 @@ endpoint_tests()
                pm_nl_set_limits $ns2 2 2
                pm_nl_add_endpoint $ns1 10.0.2.1 flags signal
                speed=slow \
-                       run_tests $ns1 $ns2 10.0.1.1 2>/dev/null &
+                       run_tests $ns1 $ns2 10.0.1.1 &
+               local tests_pid=$!
 
                wait_mpj $ns1
                pm_nl_check_endpoint "creation" \
@@ -3573,7 +3567,7 @@ endpoint_tests()
                pm_nl_add_endpoint $ns2 10.0.2.2 flags signal
                pm_nl_check_endpoint "modif is allowed" \
                        $ns2 10.0.2.2 id 1 flags signal
-               kill_tests_wait
+               mptcp_lib_kill_wait $tests_pid
        fi
 
        if reset "delete and re-add" &&
@@ -3582,7 +3576,8 @@ endpoint_tests()
                pm_nl_set_limits $ns2 1 1
                pm_nl_add_endpoint $ns2 10.0.2.2 id 2 dev ns2eth2 flags subflow
                test_linkfail=4 speed=20 \
-                       run_tests $ns1 $ns2 10.0.1.1 2>/dev/null &
+                       run_tests $ns1 $ns2 10.0.1.1 &
+               local tests_pid=$!
 
                wait_mpj $ns2
                chk_subflow_nr "before delete" 2
@@ -3597,7 +3592,7 @@ endpoint_tests()
                wait_mpj $ns2
                chk_subflow_nr "after re-add" 2
                chk_mptcp_info subflows 1 subflows 1
-               kill_tests_wait
+               mptcp_lib_kill_wait $tests_pid
        fi
 }
 
index 022262a2cfe0ee59976d398f665c8057dfaea0d7..3a2abae5993e2b4b32ae810d080dc3d336e41e11 100644 (file)
@@ -6,7 +6,7 @@ readonly KSFT_FAIL=1
 readonly KSFT_SKIP=4
 
 # shellcheck disable=SC2155 # declare and assign separately
-readonly KSFT_TEST=$(basename "${0}" | sed 's/\.sh$//g')
+readonly KSFT_TEST="${MPTCP_LIB_KSFT_TEST:-$(basename "${0}" .sh)}"
 
 MPTCP_LIB_SUBTESTS=()
 
index 79b65bdf05db6586726cc76d3313f12368d21dc5..abc5648b59abde537dca90791404691050c759e2 100644 (file)
@@ -1 +1 @@
-timeout=1200
+timeout=1800
index ae8ad5d6fb9dac680573b4207a67781e18773c09..0cc964e6f2c1768dad6a474cffd1c521580b7741 100755 (executable)
@@ -284,12 +284,12 @@ done
 
 setup
 run_test 10 10 0 0 "balanced bwidth"
-run_test 10 10 1 50 "balanced bwidth with unbalanced delay"
+run_test 10 10 1 25 "balanced bwidth with unbalanced delay"
 
 # we still need some additional infrastructure to pass the following test-cases
-run_test 30 10 0 0 "unbalanced bwidth"
-run_test 30 10 1 50 "unbalanced bwidth with unbalanced delay"
-run_test 30 10 50 1 "unbalanced bwidth with opposed, unbalanced delay"
+run_test 10 3 0 0 "unbalanced bwidth"
+run_test 10 3 1 25 "unbalanced bwidth with unbalanced delay"
+run_test 10 3 25 1 "unbalanced bwidth with opposed, unbalanced delay"
 
 mptcp_lib_result_print_all_tap
 exit $ret
old mode 100755 (executable)
new mode 100644 (file)
index f10879788f61ba4f4c01d6cb60a929048ec56540..3f118e3f1c66d636c6379485da9fcea4fbc6aff8 100755 (executable)
@@ -707,23 +707,23 @@ setup_xfrm6() {
 }
 
 setup_xfrm4udp() {
-       setup_xfrm 4 ${veth4_a_addr} ${veth4_b_addr} "encap espinudp 4500 4500 0.0.0.0"
-       setup_nettest_xfrm 4 4500
+       setup_xfrm 4 ${veth4_a_addr} ${veth4_b_addr} "encap espinudp 4500 4500 0.0.0.0" && \
+               setup_nettest_xfrm 4 4500
 }
 
 setup_xfrm6udp() {
-       setup_xfrm 6 ${veth6_a_addr} ${veth6_b_addr} "encap espinudp 4500 4500 0.0.0.0"
-       setup_nettest_xfrm 6 4500
+       setup_xfrm 6 ${veth6_a_addr} ${veth6_b_addr} "encap espinudp 4500 4500 0.0.0.0" && \
+               setup_nettest_xfrm 6 4500
 }
 
 setup_xfrm4udprouted() {
-       setup_xfrm 4 ${prefix4}.${a_r1}.1 ${prefix4}.${b_r1}.1 "encap espinudp 4500 4500 0.0.0.0"
-       setup_nettest_xfrm 4 4500
+       setup_xfrm 4 ${prefix4}.${a_r1}.1 ${prefix4}.${b_r1}.1 "encap espinudp 4500 4500 0.0.0.0" && \
+               setup_nettest_xfrm 4 4500
 }
 
 setup_xfrm6udprouted() {
-       setup_xfrm 6 ${prefix6}:${a_r1}::1 ${prefix6}:${b_r1}::1 "encap espinudp 4500 4500 0.0.0.0"
-       setup_nettest_xfrm 6 4500
+       setup_xfrm 6 ${prefix6}:${a_r1}::1 ${prefix6}:${b_r1}::1 "encap espinudp 4500 4500 0.0.0.0" && \
+               setup_nettest_xfrm 6 4500
 }
 
 setup_routing_old() {
@@ -1339,7 +1339,7 @@ test_pmtu_ipvX_over_bridged_vxlanY_or_geneveY_exception() {
 
                sleep 1
 
-               dd if=/dev/zero of=/dev/stdout status=none bs=1M count=1 | ${target} socat -T 3 -u STDIN $TCPDST,connect-timeout=3
+               dd if=/dev/zero status=none bs=1M count=1 | ${target} socat -T 3 -u STDIN $TCPDST,connect-timeout=3
 
                size=$(du -sb $tmpoutfile)
                size=${size%%/tmp/*}
old mode 100755 (executable)
new mode 100644 (file)
index a9a1759e035ca875ac22036fa52984b32ada76f8..1f78a87f6f37eaab8dc41850e1a906f9aef6315f 100644 (file)
@@ -11,7 +11,7 @@ setup_veth_ns() {
        local -r ns_mac="$4"
 
        [[ -e /var/run/netns/"${ns_name}" ]] || ip netns add "${ns_name}"
-       echo 100000 > "/sys/class/net/${ns_dev}/gro_flush_timeout"
+       echo 1000000 > "/sys/class/net/${ns_dev}/gro_flush_timeout"
        ip link set dev "${ns_dev}" netns "${ns_name}" mtu 65535
        ip -netns "${ns_name}" link set dev "${ns_dev}" up
 
diff --git a/tools/testing/selftests/net/tcp_ao/config b/tools/testing/selftests/net/tcp_ao/config
new file mode 100644 (file)
index 0000000..d3277a9
--- /dev/null
@@ -0,0 +1,10 @@
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_RMD160=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6=y
+CONFIG_NET_L3_MASTER_DEV=y
+CONFIG_NET_VRF=y
+CONFIG_TCP_AO=y
+CONFIG_TCP_MD5SIG=y
+CONFIG_VETH=m
index c48b4970ca17e07220813192fadbc553cdc89250..24e62120b7924d3a1555a7e42097f9e55338b4db 100644 (file)
@@ -417,9 +417,9 @@ struct test_key {
                matches_vrf             : 1,
                is_current              : 1,
                is_rnext                : 1,
-               used_on_handshake       : 1,
-               used_after_accept       : 1,
-               used_on_client          : 1;
+               used_on_server_tx       : 1,
+               used_on_client_tx       : 1,
+               skip_counters_checks    : 1;
 };
 
 struct key_collection {
@@ -609,16 +609,14 @@ static int key_collection_socket(bool server, unsigned int port)
                                addr = &this_ip_dest;
                        sndid = key->client_keyid;
                        rcvid = key->server_keyid;
-                       set_current = key->is_current;
-                       set_rnext = key->is_rnext;
+                       key->used_on_client_tx = set_current = key->is_current;
+                       key->used_on_server_tx = set_rnext = key->is_rnext;
                }
 
                if (test_add_key_cr(sk, key->password, key->len,
                                    *addr, vrf, sndid, rcvid, key->maclen,
                                    key->alg, set_current, set_rnext))
                        test_key_error("setsockopt(TCP_AO_ADD_KEY)", key);
-               if (set_current || set_rnext)
-                       key->used_on_handshake = 1;
 #ifdef DEBUG
                test_print("%s [%u/%u] key: { %s, %u:%u, %u, %u:%u:%u:%u (%u)}",
                           server ? "server" : "client", i, collection.nr_keys,
@@ -640,22 +638,22 @@ static void verify_counters(const char *tst_name, bool is_listen_sk, bool server
        for (i = 0; i < collection.nr_keys; i++) {
                struct test_key *key = &collection.keys[i];
                uint8_t sndid, rcvid;
-               bool was_used;
+               bool rx_cnt_expected;
 
+               if (key->skip_counters_checks)
+                       continue;
                if (server) {
                        sndid = key->server_keyid;
                        rcvid = key->client_keyid;
-                       if (is_listen_sk)
-                               was_used = key->used_on_handshake;
-                       else
-                               was_used = key->used_after_accept;
+                       rx_cnt_expected = key->used_on_client_tx;
                } else {
                        sndid = key->client_keyid;
                        rcvid = key->server_keyid;
-                       was_used = key->used_on_client;
+                       rx_cnt_expected = key->used_on_server_tx;
                }
 
-               test_tcp_ao_key_counters_cmp(tst_name, a, b, was_used,
+               test_tcp_ao_key_counters_cmp(tst_name, a, b,
+                                            rx_cnt_expected ? TEST_CNT_KEY_GOOD : 0,
                                             sndid, rcvid);
        }
        test_tcp_ao_counters_free(a);
@@ -843,7 +841,7 @@ static void end_server(const char *tst_name, int sk,
        synchronize_threads(); /* 4: verified => closed */
        close(sk);
 
-       verify_counters(tst_name, true, false, begin, &end);
+       verify_counters(tst_name, false, true, begin, &end);
        synchronize_threads(); /* 5: counters */
 }
 
@@ -916,9 +914,8 @@ static int run_client(const char *tst_name, unsigned int port,
                current_index = nr_keys - 1;
        if (rnext_index < 0)
                rnext_index = nr_keys - 1;
-       collection.keys[current_index].used_on_handshake = 1;
-       collection.keys[rnext_index].used_after_accept = 1;
-       collection.keys[rnext_index].used_on_client = 1;
+       collection.keys[current_index].used_on_client_tx = 1;
+       collection.keys[rnext_index].used_on_server_tx = 1;
 
        synchronize_threads(); /* 3: accepted => send data */
        if (test_client_verify(sk, msg_sz, msg_nr, TEST_TIMEOUT_SEC)) {
@@ -1059,7 +1056,16 @@ static void check_current_back(const char *tst_name, unsigned int port,
                test_error("Can't change the current key");
        if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
                test_fail("verify failed");
-       collection.keys[rotate_to_index].used_after_accept = 1;
+       /* There is a race here: between setting the current_key with
+        * setsockopt(TCP_AO_INFO) and starting to send some data - there
+        * might have been a segment received with the desired
+        * RNext_key set. In turn that would mean that the first outgoing
+        * segment will have the desired current_key (flipped back).
+        * Which is what the user/test wants. As it's racy, skip checking
+        * the counters, yet check what are the resulting current/rnext
+        * keys on both sides.
+        */
+       collection.keys[rotate_to_index].skip_counters_checks = 1;
 
        end_client(tst_name, sk, nr_keys, current_index, rnext_index, &tmp);
 }
@@ -1089,7 +1095,7 @@ static void roll_over_keys(const char *tst_name, unsigned int port,
                }
                verify_current_rnext(tst_name, sk, -1,
                                     collection.keys[i].server_keyid);
-               collection.keys[i].used_on_client = 1;
+               collection.keys[i].used_on_server_tx = 1;
                synchronize_threads(); /* verify current/rnext */
        }
        end_client(tst_name, sk, nr_keys, current_index, rnext_index, &tmp);
index c75d82885a2e1aa40f463bbdc65999c05c6a063d..15aeb0963058fdf645451206b3015dd707aa0c13 100644 (file)
@@ -62,7 +62,9 @@ int test_wait_fd(int sk, time_t sec, bool write)
                return -ETIMEDOUT;
        }
 
-       if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &slen) || ret)
+       if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &slen))
+               return -errno;
+       if (ret)
                return -ret;
        return 0;
 }
@@ -584,9 +586,11 @@ int test_client_verify(int sk, const size_t msg_len, const size_t nr,
 {
        size_t buf_sz = msg_len * nr;
        char *buf = alloca(buf_sz);
+       ssize_t ret;
 
        randomize_buffer(buf, buf_sz);
-       if (test_client_loop(sk, buf, buf_sz, msg_len, timeout_sec) != buf_sz)
-               return -1;
-       return 0;
+       ret = test_client_loop(sk, buf, buf_sz, msg_len, timeout_sec);
+       if (ret < 0)
+               return (int)ret;
+       return ret != buf_sz ? -1 : 0;
 }
index ac06009a7f5f65ddf0095aa6d7044e98abf032cf..7df8b8700e39e96292f8eafdf105ee0314a65497 100644 (file)
@@ -1,10 +1,33 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Author: Dmitry Safonov <dima@arista.com> */
+/*
+ * The test checks that both active and passive reset have correct TCP-AO
+ * signature. An "active" reset (abort) here is procured from closing
+ * listen() socket with non-accepted connections in the queue:
+ * inet_csk_listen_stop() => inet_child_forget() =>
+ *                        => tcp_disconnect() => tcp_send_active_reset()
+ *
+ * The passive reset is quite hard to get on established TCP connections.
+ * It could be procured from non-established states, but the synchronization
+ * part from userspace in order to reliably get RST seems uneasy.
+ * So, instead it's procured by corrupting SEQ number on TIMED-WAIT state.
+ *
+ * It's important to test both passive and active RST as they go through
+ * different code-paths:
+ * - tcp_send_active_reset() makes no-data skb, sends it with tcp_transmit_skb()
+ * - tcp_v*_send_reset() create their reply skbs and send them with
+ *   ip_send_unicast_reply()
+ *
+ * In both cases TCP-AO signatures have to be correct, which is verified by
+ * (1) checking that the TCP-AO connection was reset and (2) TCP-AO counters.
+ *
+ * Author: Dmitry Safonov <dima@arista.com>
+ */
 #include <inttypes.h>
 #include "../../../../include/linux/kernel.h"
 #include "aolib.h"
 
 const size_t quota = 1000;
+const size_t packet_sz = 100;
 /*
  * Backlog == 0 means 1 connection in queue, see:
  * commit 64a146513f8f ("[NET]: Revert incorrect accept queue...")
@@ -59,26 +82,6 @@ static void close_forced(int sk)
        close(sk);
 }
 
-static int test_wait_for_exception(int sk, time_t sec)
-{
-       struct timeval tv = { .tv_sec = sec };
-       struct timeval *ptv = NULL;
-       fd_set efds;
-       int ret;
-
-       FD_ZERO(&efds);
-       FD_SET(sk, &efds);
-
-       if (sec)
-               ptv = &tv;
-
-       errno = 0;
-       ret = select(sk + 1, NULL, NULL, &efds, ptv);
-       if (ret < 0)
-               return -errno;
-       return ret ? sk : 0;
-}
-
 static void test_server_active_rst(unsigned int port)
 {
        struct tcp_ao_counters cnt1, cnt2;
@@ -155,17 +158,16 @@ static void test_server_passive_rst(unsigned int port)
                        test_fail("server returned %zd", bytes);
        }
 
-       synchronize_threads(); /* 3: chekpoint/restore the connection */
+       synchronize_threads(); /* 3: checkpoint the client */
+       synchronize_threads(); /* 4: close the server, creating twsk */
        if (test_get_tcp_ao_counters(sk, &ao2))
                test_error("test_get_tcp_ao_counters()");
-
-       synchronize_threads(); /* 4: terminate server + send more on client */
-       bytes = test_server_run(sk, quota, TEST_RETRANSMIT_SEC);
        close(sk);
+
+       synchronize_threads(); /* 5: restore the socket, send more data */
        test_tcp_ao_counters_cmp("passive RST server", &ao1, &ao2, TEST_CNT_GOOD);
 
-       synchronize_threads(); /* 5: verified => closed */
-       close(sk);
+       synchronize_threads(); /* 6: server exits */
 }
 
 static void *server_fn(void *arg)
@@ -284,7 +286,7 @@ static void test_client_active_rst(unsigned int port)
                test_error("test_wait_fds(): %d", err);
 
        synchronize_threads(); /* 3: close listen socket */
-       if (test_client_verify(sk[0], 100, quota / 100, TEST_TIMEOUT_SEC))
+       if (test_client_verify(sk[0], packet_sz, quota / packet_sz, TEST_TIMEOUT_SEC))
                test_fail("Failed to send data on connected socket");
        else
                test_ok("Verified established tcp connection");
@@ -323,7 +325,6 @@ static void test_client_passive_rst(unsigned int port)
        struct tcp_sock_state img;
        sockaddr_af saddr;
        int sk, err;
-       socklen_t slen = sizeof(err);
 
        sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
        if (sk < 0)
@@ -337,18 +338,51 @@ static void test_client_passive_rst(unsigned int port)
                test_error("failed to connect()");
 
        synchronize_threads(); /* 2: accepted => send data */
-       if (test_client_verify(sk, 100, quota / 100, TEST_TIMEOUT_SEC))
+       if (test_client_verify(sk, packet_sz, quota / packet_sz, TEST_TIMEOUT_SEC))
                test_fail("Failed to send data on connected socket");
        else
                test_ok("Verified established tcp connection");
 
-       synchronize_threads(); /* 3: chekpoint/restore the connection */
+       synchronize_threads(); /* 3: checkpoint the client */
        test_enable_repair(sk);
        test_sock_checkpoint(sk, &img, &saddr);
        test_ao_checkpoint(sk, &ao_img);
-       test_kill_sk(sk);
+       test_disable_repair(sk);
 
-       img.out.seq += quota;
+       synchronize_threads(); /* 4: close the server, creating twsk */
+
+       /*
+        * The "corruption" in SEQ has to be small enough to fit into TCP
+        * window, see tcp_timewait_state_process() for out-of-window
+        * segments.
+        */
+       img.out.seq += 5; /* 5 is more noticeable in tcpdump than 1 */
+
+       /*
+        * FIXME: This is kind-of ugly and dirty, but it works.
+        *
+        * At this moment, the server has close'ed(sk).
+        * The passive RST that is being targeted here is new data after
+        * half-duplex close, see tcp_timewait_state_process() => TCP_TW_RST
+        *
+        * What is needed here is:
+        * (1) wait for FIN from the server
+        * (2) make sure that the ACK from the client went out
+        * (3) make sure that the ACK was received and processed by the server
+        *
+        * Otherwise, the data that will be sent from "repaired" socket
+        * post SEQ corruption may get to the server before it's in
+        * TCP_FIN_WAIT2.
+        *
+        * (1) is easy with select()/poll()
+        * (2) is possible by polling tcpi_state from TCP_INFO
+        * (3) is quite complex: as server's socket was already closed,
+        *     probably the way to do it would be tcp-diag.
+        */
+       sleep(TEST_RETRANSMIT_SEC);
+
+       synchronize_threads(); /* 5: restore the socket, send more data */
+       test_kill_sk(sk);
 
        sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
        if (sk < 0)
@@ -366,25 +400,33 @@ static void test_client_passive_rst(unsigned int port)
        test_disable_repair(sk);
        test_sock_state_free(&img);
 
-       synchronize_threads(); /* 4: terminate server + send more on client */
-       if (test_client_verify(sk, 100, quota / 100, 2 * TEST_TIMEOUT_SEC))
-               test_ok("client connection broken post-seq-adjust");
-       else
-               test_fail("client connection still works post-seq-adjust");
-
-       test_wait_for_exception(sk, TEST_TIMEOUT_SEC);
-
-       if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &slen))
-               test_error("getsockopt()");
-       if (err != ECONNRESET && err != EPIPE)
-               test_fail("client connection was not reset: %d", err);
+       /*
+        * This is how "passive reset" is acquired in this test from TCP_TW_RST:
+        *
+        * IP 10.0.254.1.7011 > 10.0.1.1.59772: Flags [P.], seq 901:1001, ack 1001, win 249,
+        *    options [tcp-ao keyid 100 rnextkeyid 100 mac 0x10217d6c36a22379086ef3b1], length 100
+        * IP 10.0.254.1.7011 > 10.0.1.1.59772: Flags [F.], seq 1001, ack 1001, win 249,
+        *    options [tcp-ao keyid 100 rnextkeyid 100 mac 0x104ffc99b98c10a5298cc268], length 0
+        * IP 10.0.1.1.59772 > 10.0.254.1.7011: Flags [.], ack 1002, win 251,
+        *    options [tcp-ao keyid 100 rnextkeyid 100 mac 0xe496dd4f7f5a8a66873c6f93,nop,nop,sack 1 {1001:1002}], length 0
+        * IP 10.0.1.1.59772 > 10.0.254.1.7011: Flags [P.], seq 1006:1106, ack 1001, win 251,
+        *    options [tcp-ao keyid 100 rnextkeyid 100 mac 0x1b5f3330fb23fbcd0c77d0ca], length 100
+        * IP 10.0.254.1.7011 > 10.0.1.1.59772: Flags [R], seq 3215596252, win 0,
+        *    options [tcp-ao keyid 100 rnextkeyid 100 mac 0x0bcfbbf497bce844312304b2], length 0
+        */
+       err = test_client_verify(sk, packet_sz, quota / packet_sz, 2 * TEST_TIMEOUT_SEC);
+       /* Make sure that the connection was reset, not timeouted */
+       if (err && err == -ECONNRESET)
+               test_ok("client sock was passively reset post-seq-adjust");
+       else if (err)
+               test_fail("client sock was not reset post-seq-adjust: %d", err);
        else
-               test_ok("client connection was reset");
+               test_fail("client sock is yet connected post-seq-adjust");
 
        if (test_get_tcp_ao_counters(sk, &ao2))
                test_error("test_get_tcp_ao_counters()");
 
-       synchronize_threads(); /* 5: verified => closed */
+       synchronize_threads(); /* 6: server exits */
        close(sk);
        test_tcp_ao_counters_cmp("client passive RST", &ao1, &ao2, TEST_CNT_GOOD);
 }
@@ -410,6 +452,6 @@ static void *client_fn(void *arg)
 
 int main(int argc, char *argv[])
 {
-       test_init(15, server_fn, client_fn);
+       test_init(14, server_fn, client_fn);
        return 0;
 }
diff --git a/tools/testing/selftests/net/tcp_ao/settings b/tools/testing/selftests/net/tcp_ao/settings
new file mode 100644 (file)
index 0000000..6091b45
--- /dev/null
@@ -0,0 +1 @@
+timeout=120
index af5dc57c8ce935907fd93279077c0d326205415e..8802604148dda1c2565fdb0d5b0aaabb0cad1427 100755 (executable)
@@ -7,7 +7,7 @@ source net_helper.sh
 
 readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)"
 
-BPF_FILE="../bpf/xdp_dummy.bpf.o"
+BPF_FILE="xdp_dummy.o"
 
 # set global exit status, but never reset nonzero one.
 check_err()
@@ -197,7 +197,7 @@ run_all() {
 }
 
 if [ ! -f ${BPF_FILE} ]; then
-       echo "Missing ${BPF_FILE}. Build bpf selftest first"
+       echo "Missing ${BPF_FILE}. Run 'make' first"
        exit -1
 fi
 
index cb664679b4342992a16694a182c7d0b3a7e9d80b..7080eae5312b2f9fa13c41868337fd4433fb0de6 100755 (executable)
@@ -7,7 +7,7 @@ source net_helper.sh
 
 readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)"
 
-BPF_FILE="../bpf/xdp_dummy.bpf.o"
+BPF_FILE="xdp_dummy.o"
 
 cleanup() {
        local -r jobs="$(jobs -p)"
@@ -84,7 +84,7 @@ run_all() {
 }
 
 if [ ! -f ${BPF_FILE} ]; then
-       echo "Missing ${BPF_FILE}. Build bpf selftest first"
+       echo "Missing ${BPF_FILE}. Run 'make' first"
        exit -1
 fi
 
index dd47fa96f6b3e5ea1cf1f750a4fd55d7a0c4592b..e1ff645bd3d1c7b0b8ba177ee73ce595a91f3808 100755 (executable)
@@ -7,7 +7,7 @@ source net_helper.sh
 
 readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)"
 
-BPF_FILE="../bpf/xdp_dummy.bpf.o"
+BPF_FILE="xdp_dummy.o"
 
 cleanup() {
        local -r jobs="$(jobs -p)"
@@ -85,12 +85,12 @@ run_all() {
 }
 
 if [ ! -f ${BPF_FILE} ]; then
-       echo "Missing ${BPF_FILE}. Build bpf selftest first"
+       echo "Missing ${BPF_FILE}. Run 'make' first"
        exit -1
 fi
 
 if [ ! -f nat6to4.o ]; then
-       echo "Missing nat6to4 helper. Build bpf nat6to4.o selftest first"
+       echo "Missing nat6to4 helper. Run 'make' first"
        exit -1
 fi
 
index c079565add39224eb99e011f941b6f0a11c1648c..d6b9c759043ca8219be27ce953b94722ae1492c6 100755 (executable)
@@ -1,7 +1,9 @@
 #!/bin/bash
 # SPDX-License-Identifier: GPL-2.0
 
-BPF_FILE="../bpf/xdp_dummy.bpf.o"
+source net_helper.sh
+
+BPF_FILE="xdp_dummy.o"
 readonly BASE="ns-$(mktemp -u XXXXXX)"
 readonly SRC=2
 readonly DST=1
@@ -119,7 +121,7 @@ run_test() {
        ip netns exec $NS_DST $ipt -A INPUT -p udp --dport 8000
        ip netns exec $NS_DST ./udpgso_bench_rx -C 1000 -R 10 -n 10 -l 1300 $rx_args &
        local spid=$!
-       sleep 0.1
+       wait_local_port_listen "$NS_DST" 8000 udp
        ip netns exec $NS_SRC ./udpgso_bench_tx $family -M 1 -s 13000 -S 1300 -D $dst
        local retc=$?
        wait $spid
@@ -168,7 +170,7 @@ run_bench() {
        ip netns exec $NS_DST bash -c "echo 2 > /sys/class/net/veth$DST/queues/rx-0/rps_cpus"
        ip netns exec $NS_DST taskset 0x2 ./udpgso_bench_rx -C 1000 -R 10  &
        local spid=$!
-       sleep 0.1
+       wait_local_port_listen "$NS_DST" 8000 udp
        ip netns exec $NS_SRC taskset 0x1 ./udpgso_bench_tx $family -l 3 -S 1300 -D $dst
        local retc=$?
        wait $spid
index 2d073595c620210254bc372bc428b05121e9b26b..27574bbf2d6386f770673b82684edf07b586c79a 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 # SPDX-License-Identifier: GPL-2.0
 
-BPF_FILE="../bpf/xdp_dummy.bpf.o"
+BPF_FILE="xdp_dummy.o"
 readonly STATS="$(mktemp -p /tmp ns-XXXXXX)"
 readonly BASE=`basename $STATS`
 readonly SRC=2
@@ -218,7 +218,7 @@ while getopts "hs:" option; do
 done
 
 if [ ! -f ${BPF_FILE} ]; then
-       echo "Missing ${BPF_FILE}. Build bpf selftest first"
+       echo "Missing ${BPF_FILE}. Run 'make' first"
        exit 1
 fi
 
diff --git a/tools/testing/selftests/net/xdp_dummy.c b/tools/testing/selftests/net/xdp_dummy.c
new file mode 100644 (file)
index 0000000..d988b2e
--- /dev/null
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define KBUILD_MODNAME "xdp_dummy"
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+
+SEC("xdp")
+int xdp_dummy_prog(struct xdp_md *ctx)
+{
+       return XDP_PASS;
+}
+
+char _license[] SEC("license") = "GPL";
index 88754296196870a5d0ef3afb52373c8d40cbc598..2348d2c20d0a1aaf3a05a1c7005983f442708b3c 100644 (file)
@@ -24,6 +24,11 @@ bool rseq_validate_cpu_id(void)
 {
        return rseq_mm_cid_available();
 }
+static
+bool rseq_use_cpu_index(void)
+{
+       return false;   /* Use mm_cid */
+}
 #else
 # define RSEQ_PERCPU   RSEQ_PERCPU_CPU_ID
 static
@@ -36,6 +41,11 @@ bool rseq_validate_cpu_id(void)
 {
        return rseq_current_cpu_raw() >= 0;
 }
+static
+bool rseq_use_cpu_index(void)
+{
+       return true;    /* Use cpu_id as index. */
+}
 #endif
 
 struct percpu_lock_entry {
@@ -274,7 +284,7 @@ void test_percpu_list(void)
        /* Generate list entries for every usable cpu. */
        sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus);
        for (i = 0; i < CPU_SETSIZE; i++) {
-               if (!CPU_ISSET(i, &allowed_cpus))
+               if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
                        continue;
                for (j = 1; j <= 100; j++) {
                        struct percpu_list_node *node;
@@ -299,7 +309,7 @@ void test_percpu_list(void)
        for (i = 0; i < CPU_SETSIZE; i++) {
                struct percpu_list_node *node;
 
-               if (!CPU_ISSET(i, &allowed_cpus))
+               if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
                        continue;
 
                while ((node = __percpu_list_pop(&list, i))) {
index 20403d58345cd523186b9423750ea7ad669cdd96..2f37961240caa7cc43f142fac32fd7f9c9c211d4 100644 (file)
@@ -288,6 +288,11 @@ bool rseq_validate_cpu_id(void)
 {
        return rseq_mm_cid_available();
 }
+static
+bool rseq_use_cpu_index(void)
+{
+       return false;   /* Use mm_cid */
+}
 # ifdef TEST_MEMBARRIER
 /*
  * Membarrier does not currently support targeting a mm_cid, so
@@ -312,6 +317,11 @@ bool rseq_validate_cpu_id(void)
 {
        return rseq_current_cpu_raw() >= 0;
 }
+static
+bool rseq_use_cpu_index(void)
+{
+       return true;    /* Use cpu_id as index. */
+}
 # ifdef TEST_MEMBARRIER
 static
 int rseq_membarrier_expedited(int cpu)
@@ -715,7 +725,7 @@ void test_percpu_list(void)
        /* Generate list entries for every usable cpu. */
        sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus);
        for (i = 0; i < CPU_SETSIZE; i++) {
-               if (!CPU_ISSET(i, &allowed_cpus))
+               if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
                        continue;
                for (j = 1; j <= 100; j++) {
                        struct percpu_list_node *node;
@@ -752,7 +762,7 @@ void test_percpu_list(void)
        for (i = 0; i < CPU_SETSIZE; i++) {
                struct percpu_list_node *node;
 
-               if (!CPU_ISSET(i, &allowed_cpus))
+               if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
                        continue;
 
                while ((node = __percpu_list_pop(&list, i))) {
@@ -902,7 +912,7 @@ void test_percpu_buffer(void)
        /* Generate list entries for every usable cpu. */
        sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus);
        for (i = 0; i < CPU_SETSIZE; i++) {
-               if (!CPU_ISSET(i, &allowed_cpus))
+               if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
                        continue;
                /* Worse-case is every item in same CPU. */
                buffer.c[i].array =
@@ -952,7 +962,7 @@ void test_percpu_buffer(void)
        for (i = 0; i < CPU_SETSIZE; i++) {
                struct percpu_buffer_node *node;
 
-               if (!CPU_ISSET(i, &allowed_cpus))
+               if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
                        continue;
 
                while ((node = __percpu_buffer_pop(&buffer, i))) {
@@ -1113,7 +1123,7 @@ void test_percpu_memcpy_buffer(void)
        /* Generate list entries for every usable cpu. */
        sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus);
        for (i = 0; i < CPU_SETSIZE; i++) {
-               if (!CPU_ISSET(i, &allowed_cpus))
+               if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
                        continue;
                /* Worse-case is every item in same CPU. */
                buffer.c[i].array =
@@ -1160,7 +1170,7 @@ void test_percpu_memcpy_buffer(void)
        for (i = 0; i < CPU_SETSIZE; i++) {
                struct percpu_memcpy_buffer_node item;
 
-               if (!CPU_ISSET(i, &allowed_cpus))
+               if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
                        continue;
 
                while (__percpu_memcpy_buffer_pop(&buffer, &item, i)) {
index 5b5c9d558dee07bc1f7afd7df280e1189858451e..97b86980b768f4fa09da58f16d71ba42f42d2c8d 100644 (file)
@@ -38,10 +38,10 @@ unsigned long long timing(clockid_t clk_id, unsigned long long samples)
        i *= 1000000000ULL;
        i += finish.tv_nsec - start.tv_nsec;
 
-       printf("%lu.%09lu - %lu.%09lu = %llu (%.1fs)\n",
-               finish.tv_sec, finish.tv_nsec,
-               start.tv_sec, start.tv_nsec,
-               i, (double)i / 1000000000.0);
+       ksft_print_msg("%lu.%09lu - %lu.%09lu = %llu (%.1fs)\n",
+                      finish.tv_sec, finish.tv_nsec,
+                      start.tv_sec, start.tv_nsec,
+                      i, (double)i / 1000000000.0);
 
        return i;
 }
@@ -53,7 +53,7 @@ unsigned long long calibrate(void)
        pid_t pid, ret;
        int seconds = 15;
 
-       printf("Calibrating sample size for %d seconds worth of syscalls ...\n", seconds);
+       ksft_print_msg("Calibrating sample size for %d seconds worth of syscalls ...\n", seconds);
 
        samples = 0;
        pid = getpid();
@@ -98,24 +98,36 @@ bool le(int i_one, int i_two)
 }
 
 long compare(const char *name_one, const char *name_eval, const char *name_two,
-            unsigned long long one, bool (*eval)(int, int), unsigned long long two)
+            unsigned long long one, bool (*eval)(int, int), unsigned long long two,
+            bool skip)
 {
        bool good;
 
-       printf("\t%s %s %s (%lld %s %lld): ", name_one, name_eval, name_two,
-              (long long)one, name_eval, (long long)two);
+       if (skip) {
+               ksft_test_result_skip("%s %s %s\n", name_one, name_eval,
+                                     name_two);
+               return 0;
+       }
+
+       ksft_print_msg("\t%s %s %s (%lld %s %lld): ", name_one, name_eval, name_two,
+                      (long long)one, name_eval, (long long)two);
        if (one > INT_MAX) {
-               printf("Miscalculation! Measurement went negative: %lld\n", (long long)one);
-               return 1;
+               ksft_print_msg("Miscalculation! Measurement went negative: %lld\n", (long long)one);
+               good = false;
+               goto out;
        }
        if (two > INT_MAX) {
-               printf("Miscalculation! Measurement went negative: %lld\n", (long long)two);
-               return 1;
+               ksft_print_msg("Miscalculation! Measurement went negative: %lld\n", (long long)two);
+               good = false;
+               goto out;
        }
 
        good = eval(one, two);
        printf("%s\n", good ? "✔️" : "❌");
 
+out:
+       ksft_test_result(good, "%s %s %s\n", name_one, name_eval, name_two);
+
        return good ? 0 : 1;
 }
 
@@ -142,15 +154,22 @@ int main(int argc, char *argv[])
        unsigned long long samples, calc;
        unsigned long long native, filter1, filter2, bitmap1, bitmap2;
        unsigned long long entry, per_filter1, per_filter2;
+       bool skip = false;
 
        setbuf(stdout, NULL);
 
-       printf("Running on:\n");
+       ksft_print_header();
+       ksft_set_plan(7);
+
+       ksft_print_msg("Running on:\n");
+       ksft_print_msg("");
        system("uname -a");
 
-       printf("Current BPF sysctl settings:\n");
+       ksft_print_msg("Current BPF sysctl settings:\n");
        /* Avoid using "sysctl" which may not be installed. */
+       ksft_print_msg("");
        system("grep -H . /proc/sys/net/core/bpf_jit_enable");
+       ksft_print_msg("");
        system("grep -H . /proc/sys/net/core/bpf_jit_harden");
 
        if (argc > 1)
@@ -158,11 +177,11 @@ int main(int argc, char *argv[])
        else
                samples = calibrate();
 
-       printf("Benchmarking %llu syscalls...\n", samples);
+       ksft_print_msg("Benchmarking %llu syscalls...\n", samples);
 
        /* Native call */
        native = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples;
-       printf("getpid native: %llu ns\n", native);
+       ksft_print_msg("getpid native: %llu ns\n", native);
 
        ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
        assert(ret == 0);
@@ -172,35 +191,37 @@ int main(int argc, char *argv[])
        assert(ret == 0);
 
        bitmap1 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples;
-       printf("getpid RET_ALLOW 1 filter (bitmap): %llu ns\n", bitmap1);
+       ksft_print_msg("getpid RET_ALLOW 1 filter (bitmap): %llu ns\n", bitmap1);
 
        /* Second filter resulting in a bitmap */
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &bitmap_prog);
        assert(ret == 0);
 
        bitmap2 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples;
-       printf("getpid RET_ALLOW 2 filters (bitmap): %llu ns\n", bitmap2);
+       ksft_print_msg("getpid RET_ALLOW 2 filters (bitmap): %llu ns\n", bitmap2);
 
        /* Third filter, can no longer be converted to bitmap */
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
        assert(ret == 0);
 
        filter1 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples;
-       printf("getpid RET_ALLOW 3 filters (full): %llu ns\n", filter1);
+       ksft_print_msg("getpid RET_ALLOW 3 filters (full): %llu ns\n", filter1);
 
        /* Fourth filter, can not be converted to bitmap because of filter 3 */
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &bitmap_prog);
        assert(ret == 0);
 
        filter2 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples;
-       printf("getpid RET_ALLOW 4 filters (full): %llu ns\n", filter2);
+       ksft_print_msg("getpid RET_ALLOW 4 filters (full): %llu ns\n", filter2);
 
        /* Estimations */
 #define ESTIMATE(fmt, var, what)       do {                    \
                var = (what);                                   \
-               printf("Estimated " fmt ": %llu ns\n", var);    \
-               if (var > INT_MAX)                              \
-                       goto more_samples;                      \
+               ksft_print_msg("Estimated " fmt ": %llu ns\n", var);    \
+               if (var > INT_MAX) {                            \
+                       skip = true;                            \
+                       ret |= 1;                               \
+               }                                               \
        } while (0)
 
        ESTIMATE("total seccomp overhead for 1 bitmapped filter", calc,
@@ -218,31 +239,34 @@ int main(int argc, char *argv[])
        ESTIMATE("seccomp per-filter overhead (filters / 4)", per_filter2,
                 (filter2 - native - entry) / 4);
 
-       printf("Expectations:\n");
-       ret |= compare("native", "≤", "1 bitmap", native, le, bitmap1);
-       bits = compare("native", "≤", "1 filter", native, le, filter1);
+       ksft_print_msg("Expectations:\n");
+       ret |= compare("native", "≤", "1 bitmap", native, le, bitmap1,
+                      skip);
+       bits = compare("native", "≤", "1 filter", native, le, filter1,
+                      skip);
        if (bits)
-               goto more_samples;
+               skip = true;
 
        ret |= compare("per-filter (last 2 diff)", "≈", "per-filter (filters / 4)",
-                       per_filter1, approx, per_filter2);
+                      per_filter1, approx, per_filter2, skip);
 
        bits = compare("1 bitmapped", "≈", "2 bitmapped",
-                       bitmap1 - native, approx, bitmap2 - native);
+                      bitmap1 - native, approx, bitmap2 - native, skip);
        if (bits) {
-               printf("Skipping constant action bitmap expectations: they appear unsupported.\n");
-               goto out;
+               ksft_print_msg("Skipping constant action bitmap expectations: they appear unsupported.\n");
+               skip = true;
        }
 
-       ret |= compare("entry", "≈", "1 bitmapped", entry, approx, bitmap1 - native);
-       ret |= compare("entry", "≈", "2 bitmapped", entry, approx, bitmap2 - native);
+       ret |= compare("entry", "≈", "1 bitmapped", entry, approx,
+                      bitmap1 - native, skip);
+       ret |= compare("entry", "≈", "2 bitmapped", entry, approx,
+                      bitmap2 - native, skip);
        ret |= compare("native + entry + (per filter * 4)", "≈", "4 filters total",
-                       entry + (per_filter1 * 4) + native, approx, filter2);
-       if (ret == 0)
-               goto out;
+                      entry + (per_filter1 * 4) + native, approx, filter2,
+                      skip);
 
-more_samples:
-       printf("Saw unexpected benchmark result. Try running again with more samples?\n");
-out:
-       return 0;
+       if (ret)
+               ksft_print_msg("Saw unexpected benchmark result. Try running again with more samples?\n");
+
+       ksft_finished();
 }